first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:52:23 +03:00
commit 880f412e2c
2662 changed files with 866266 additions and 0 deletions

View File

@@ -0,0 +1,223 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
// Define the shape of our app state
export interface AppState {
// UI State
sidebarCollapsed: boolean;
theme: "light" | "dark" | "system";
// Loading states for global operations
isInitializing: boolean;
isOnline: boolean;
// Current user/session info
currentUser: {
id?: string;
name?: string;
email?: string;
} | null;
// Global notifications/toasts
notifications: {
id: string;
type: "success" | "error" | "warning" | "info";
title: string;
message: string;
timestamp: number;
read: boolean;
}[];
// Application settings
settings: {
autoRefresh: boolean;
refreshInterval: number; // in seconds
maxLogEntries: number;
defaultPageSize: number;
};
// Global error state
globalError: {
message: string;
code?: string;
timestamp: number;
} | null;
// Selected items
selectedItems: {
providers: string[];
virtualKeys: string[];
teams: string[];
customers: string[];
logs: string[];
};
// Feature flags
features: {
enableMCP: boolean;
enableCaching: boolean;
enableLogging: boolean;
};
}
// Define initial state
const initialState: AppState = {
sidebarCollapsed: false,
theme: "system",
isInitializing: true,
isOnline: true,
currentUser: null,
notifications: [],
settings: {
autoRefresh: false,
refreshInterval: 30,
maxLogEntries: 1000,
defaultPageSize: 50,
},
globalError: null,
features: {
enableMCP: false,
enableCaching: false,
enableLogging: false,
},
selectedItems: {
providers: [],
virtualKeys: [],
teams: [],
customers: [],
logs: [],
},
};
// Create the slice
const appSlice = createSlice({
name: "app",
initialState,
reducers: {
// UI Actions
toggleSidebar: (state) => {
state.sidebarCollapsed = !state.sidebarCollapsed;
},
setSidebarCollapsed: (state, action: PayloadAction<boolean>) => {
state.sidebarCollapsed = action.payload;
},
setTheme: (state, action: PayloadAction<"light" | "dark" | "system">) => {
state.theme = action.payload;
},
// App State Actions
setInitializing: (state, action: PayloadAction<boolean>) => {
state.isInitializing = action.payload;
},
setOnlineStatus: (state, action: PayloadAction<boolean>) => {
state.isOnline = action.payload;
},
// Notification Actions
addNotification: (state, action: PayloadAction<Omit<AppState["notifications"][0], "id" | "timestamp" | "read">>) => {
const notification = {
...action.payload,
id: Date.now().toString(),
timestamp: Date.now(),
read: false,
};
state.notifications.unshift(notification);
// Keep only last 50 notifications
if (state.notifications.length > 50) {
state.notifications = state.notifications.slice(0, 50);
}
},
markNotificationRead: (state, action: PayloadAction<string>) => {
const notification = state.notifications.find((n) => n.id === action.payload);
if (notification) {
notification.read = true;
}
},
removeNotification: (state, action: PayloadAction<string>) => {
state.notifications = state.notifications.filter((n) => n.id !== action.payload);
},
clearAllNotifications: (state) => {
state.notifications = [];
},
markAllNotificationsRead: (state) => {
state.notifications.forEach((notification) => {
notification.read = true;
});
},
// Settings Actions
updateSettings: (state, action: PayloadAction<Partial<AppState["settings"]>>) => {
state.settings = { ...state.settings, ...action.payload };
},
// Error Actions
setGlobalError: (state, action: PayloadAction<AppState["globalError"]>) => {
state.globalError = action.payload;
},
clearGlobalError: (state) => {
state.globalError = null;
},
// Feature Flags Actions
updateFeatures: (state, action: PayloadAction<Partial<AppState["features"]>>) => {
state.features = { ...state.features, ...action.payload };
},
// Reset app state (useful for logout)
resetAppState: () => initialState,
},
});
// Export actions
export const {
// UI Actions
toggleSidebar,
setSidebarCollapsed,
setTheme,
// App State Actions
setInitializing,
setOnlineStatus,
// Notification Actions
addNotification,
markNotificationRead,
removeNotification,
clearAllNotifications,
markAllNotificationsRead,
// Settings Actions
updateSettings,
// Error Actions
setGlobalError,
clearGlobalError,
// Feature Flags Actions
updateFeatures,
// Reset
resetAppState,
} = appSlice.actions;
// Export reducer
export default appSlice.reducer;
// Selectors
export const selectSidebarCollapsed = (state: { app: AppState }) => state.app.sidebarCollapsed;
export const selectTheme = (state: { app: AppState }) => state.app.theme;
export const selectIsInitializing = (state: { app: AppState }) => state.app.isInitializing;
export const selectIsOnline = (state: { app: AppState }) => state.app.isOnline;
export const selectCurrentUser = (state: { app: AppState }) => state.app.currentUser;
export const selectNotifications = (state: { app: AppState }) => state.app.notifications;
export const selectUnreadNotificationsCount = (state: { app: AppState }) => state.app.notifications.filter((n) => !n.read).length;
export const selectSettings = (state: { app: AppState }) => state.app.settings;
export const selectGlobalError = (state: { app: AppState }) => state.app.globalError;
export const selectFeatures = (state: { app: AppState }) => state.app.features;

View File

@@ -0,0 +1,14 @@
// App slice exports
export * from "./appSlice";
export { default as appReducer } from "./appSlice";
// Provider slice exports
export * from "./providerSlice";
export { default as providerReducer } from "./providerSlice";
// Plugin slice exports
export * from "./pluginSlice";
export { default as pluginReducer } from "./pluginSlice";
// Enterprise slice exports
export * from "@enterprise/lib/store/slices";

View File

@@ -0,0 +1,70 @@
import { Plugin } from "@/lib/types/plugins";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { pluginsApi } from "../apis";
interface PluginState {
selectedPlugin?: Plugin;
isDirty: boolean;
}
const initialState: PluginState = {
selectedPlugin: undefined,
isDirty: false,
};
const pluginSlice = createSlice({
name: "plugin",
initialState,
reducers: {
setPluginFormDirtyState: (state, action: PayloadAction<boolean>) => {
state.isDirty = action.payload;
},
setSelectedPlugin: (state, action: PayloadAction<Plugin | undefined>) => {
state.selectedPlugin = action.payload;
},
},
extraReducers: (builder) => {
// Listen to getPlugins fulfilled to update selected plugin if it has changed
builder.addMatcher(pluginsApi.endpoints.getPlugins.matchFulfilled, (state, action) => {
const updatedPlugins = action.payload;
// If we have a selected plugin, check if it has been updated
if (state.selectedPlugin && updatedPlugins) {
const updatedSelectedPlugin = updatedPlugins.find((plugin) => plugin.name === state.selectedPlugin!.name);
// If the selected plugin exists in the updated list, update it
if (updatedSelectedPlugin) {
state.selectedPlugin = updatedSelectedPlugin;
}
}
});
// Listen to updatePlugin fulfilled to update selected plugin if it's the same one
builder.addMatcher(pluginsApi.endpoints.updatePlugin.matchFulfilled, (state, action) => {
const updatedPluginName = action.meta.arg.originalArgs.name;
// If the updated plugin is the currently selected one, update it
if (state.selectedPlugin && updatedPluginName === state.selectedPlugin.name) {
// Update the selected plugin with the new data
const updatedPlugin = action.payload;
state.selectedPlugin = updatedPlugin;
}
});
// Listen to deletePlugin fulfilled to remove the plugin from the list
builder.addMatcher(pluginsApi.endpoints.deletePlugin.matchFulfilled, (state, action) => {
const deletedPluginName = action.meta.arg.originalArgs;
// If the deleted plugin was selected, clear the selection
if (state.selectedPlugin && state.selectedPlugin.name === deletedPluginName) {
state.selectedPlugin = undefined;
}
});
},
});
export const { setPluginFormDirtyState, setSelectedPlugin } = pluginSlice.actions;
export default pluginSlice.reducer;
// Selectors
export const selectSelectedPlugin = (state: { plugin: PluginState }) => state.plugin.selectedPlugin;
export const selectPluginFormIsDirty = (state: { plugin: PluginState }) => state.plugin.isDirty;

View File

@@ -0,0 +1,80 @@
import { ModelProvider } from "@/lib/types/config";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { providersApi } from "../apis";
interface ProviderState {
selectedProvider: ModelProvider | null;
isConfigureDialogOpen: boolean;
providers: ModelProvider[];
isDirty: boolean;
}
const initialState: ProviderState = {
selectedProvider: null,
isConfigureDialogOpen: false,
providers: [],
isDirty: false,
};
const providerSlice = createSlice({
name: "provider",
initialState,
reducers: {
setProviderFormDirtyState: (state, action: PayloadAction<boolean>) => {
state.isDirty = action.payload;
},
setSelectedProvider: (state, action: PayloadAction<ModelProvider | null>) => {
state.selectedProvider = action.payload;
},
setIsConfigureDialogOpen: (state, action: PayloadAction<boolean>) => {
state.isConfigureDialogOpen = action.payload;
},
setProviders: (state, action: PayloadAction<ModelProvider[]>) => {
state.providers = action.payload;
},
openConfigureDialog: (state, action: PayloadAction<ModelProvider | null>) => {
state.selectedProvider = action.payload;
state.isConfigureDialogOpen = true;
},
closeConfigureDialog: (state) => {
state.selectedProvider = null;
state.isConfigureDialogOpen = false;
},
},
extraReducers: (builder) => {
// Listen to getProviders fulfilled to update selected provider if it has changed
builder.addMatcher(providersApi.endpoints.getProviders.matchFulfilled, (state, action) => {
const updatedProviders = action.payload;
// If we have a selected provider, check if it has been updated
if (state.selectedProvider && updatedProviders) {
const updatedSelectedProvider = updatedProviders.find((provider) => provider.name === state.selectedProvider!.name);
// If the selected provider exists in the updated list, update it
if (updatedSelectedProvider) {
// Check if the provider has actually changed
state.selectedProvider = updatedSelectedProvider;
}
}
});
// Listen to updateProvider fulfilled to update selected provider if it's the same one
builder.addMatcher(providersApi.endpoints.updateProvider.matchFulfilled, (state, action) => {
const updatedProvider = action.payload;
// If the updated provider is the currently selected one, update it
if (state.selectedProvider && updatedProvider.name === state.selectedProvider.name) {
state.selectedProvider = updatedProvider;
}
});
},
});
export const {
setProviderFormDirtyState,
setSelectedProvider,
setIsConfigureDialogOpen,
setProviders,
openConfigureDialog,
closeConfigureDialog,
} = providerSlice.actions;
export default providerSlice.reducer;