build: sync config
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { GPUStackPluginManager } from './manager';
|
||||
import { AppPlugin } from './types';
|
||||
|
||||
/**
|
||||
* Hook to access the enterprise plugin instance
|
||||
*/
|
||||
export const getGPUStackPlugin = (): AppPlugin | undefined => {
|
||||
return GPUStackPluginManager.get('enterprise');
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to access a plugin by its name
|
||||
*/
|
||||
export const getPlugin = (name: string): AppPlugin | undefined => {
|
||||
return GPUStackPluginManager.get(name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to check if a plugin is registered
|
||||
*/
|
||||
export const hasPlugin = (name: string): boolean => {
|
||||
return GPUStackPluginManager.has(name);
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
import { addLocale } from '@umijs/max';
|
||||
|
||||
const mergedLocales = new Set<string>();
|
||||
|
||||
/**
|
||||
* Merge enterprise plugin locales into the main application
|
||||
*/
|
||||
export function mergeEnterpriseLocales(locales: Record<string, any> = {}) {
|
||||
if (!locales) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Merging enterprise plugin locales:', Object.keys(locales));
|
||||
|
||||
// Iterate over all locale configurations of the enterprise plugin
|
||||
Object.entries(locales).forEach(([locale, messages]) => {
|
||||
try {
|
||||
if (mergedLocales.has(locale)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge the enterprise locale into the main application
|
||||
addLocale(locale, messages, {
|
||||
momentLocale: '',
|
||||
// @ts-ignore
|
||||
antd: locale
|
||||
});
|
||||
mergedLocales.add(locale);
|
||||
console.log(`✓ Merged enterprise locale: ${locale}`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to merge enterprise locale ${locale}:`, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { AppPlugin, IPluginManager } from './types';
|
||||
|
||||
class PluginManager implements IPluginManager {
|
||||
private plugins = new Map<string, AppPlugin>();
|
||||
private initialized = false;
|
||||
|
||||
/**
|
||||
* register a plugin
|
||||
*/
|
||||
register(name: string, plugin: AppPlugin) {
|
||||
if (this.plugins.has(name)) {
|
||||
console.warn(`Plugin "${name}" is already registered. Overwriting...`);
|
||||
}
|
||||
this.plugins.set(name, plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a plugin
|
||||
*/
|
||||
get(name: string): AppPlugin | undefined {
|
||||
return this.plugins.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a plugin exists
|
||||
*/
|
||||
has(name: string): boolean {
|
||||
return this.plugins.has(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* get all plugins
|
||||
*/
|
||||
getAll(): Map<string, AppPlugin> {
|
||||
return this.plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize all plugins
|
||||
*/
|
||||
async initialize(): Promise<Record<string, any>> {
|
||||
if (this.initialized) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const initData: Record<string, any> = {};
|
||||
|
||||
for (const [name, plugin] of this.plugins.entries()) {
|
||||
if (plugin.onAppInit) {
|
||||
try {
|
||||
const data = await plugin.onAppInit();
|
||||
if (data) {
|
||||
initData[name] = data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to initialize plugin "${name}":`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
return initData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知所有插件应用已就绪
|
||||
*/
|
||||
async notifyReady(): Promise<void> {
|
||||
for (const [name, plugin] of this.plugins.entries()) {
|
||||
if (plugin.onAppReady) {
|
||||
try {
|
||||
await plugin.onAppReady();
|
||||
} catch (error) {
|
||||
console.error(`Plugin "${name}" onAppReady failed:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const GPUStackPluginManager = new PluginManager();
|
||||
@@ -0,0 +1,2 @@
|
||||
// If the enterprise plugin is not installed, imports will be redirected to this empty module to prevent errors.
|
||||
export default undefined;
|
||||
@@ -0,0 +1,57 @@
|
||||
import { getGPUStackPlugin } from '@/plugins';
|
||||
import type { RouteConfig } from '@/plugins/types';
|
||||
|
||||
type ClientRoute = RouteConfig & {
|
||||
id?: string;
|
||||
children?: ClientRoute[];
|
||||
routes?: ClientRoute[];
|
||||
};
|
||||
|
||||
function getLayoutChildren(routes: ClientRoute[]): ClientRoute[] | null {
|
||||
const rootRoute = routes.find((route) => route.path === '/');
|
||||
if (!rootRoute) return null;
|
||||
|
||||
const rootChildren = rootRoute.routes || rootRoute.children;
|
||||
if (!Array.isArray(rootChildren)) return null;
|
||||
|
||||
const globalLayout = rootChildren.find((route) =>
|
||||
route.id?.includes('global-layout')
|
||||
);
|
||||
if (!globalLayout) return null;
|
||||
|
||||
const layoutChildren = globalLayout.children || globalLayout.routes;
|
||||
return Array.isArray(layoutChildren) ? layoutChildren : null;
|
||||
}
|
||||
|
||||
function mergeRoute(targetRoutes: ClientRoute[], pluginRoute: ClientRoute) {
|
||||
const existsIndex = targetRoutes.findIndex(
|
||||
(route) =>
|
||||
(pluginRoute.path && route.path === pluginRoute.path) ||
|
||||
(pluginRoute.key && route.key === pluginRoute.key)
|
||||
);
|
||||
|
||||
if (existsIndex === -1) {
|
||||
targetRoutes.push(pluginRoute);
|
||||
return;
|
||||
}
|
||||
|
||||
const currentRoute = targetRoutes[existsIndex];
|
||||
targetRoutes[existsIndex] = {
|
||||
...currentRoute,
|
||||
...pluginRoute,
|
||||
routes: pluginRoute.routes || currentRoute.routes,
|
||||
children: pluginRoute.children || currentRoute.children
|
||||
};
|
||||
}
|
||||
|
||||
export function mergeEnterpriseRoutes(routes: ClientRoute[]) {
|
||||
const enterprisePlugin = getGPUStackPlugin();
|
||||
if (!enterprisePlugin?.routes?.length) return;
|
||||
|
||||
const layoutChildren = getLayoutChildren(routes);
|
||||
if (!layoutChildren) return;
|
||||
|
||||
enterprisePlugin.routes.forEach((route) =>
|
||||
mergeRoute(layoutChildren, route as ClientRoute)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import { ComponentType } from 'react';
|
||||
|
||||
/**
|
||||
* routes
|
||||
*/
|
||||
export interface RouteConfig {
|
||||
path: string;
|
||||
component?: ComponentType;
|
||||
routes?: RouteConfig[];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* login module configuration
|
||||
*/
|
||||
export interface LoginPlugin {
|
||||
shouldUseCustomLogin?: () => boolean;
|
||||
CustomLoginComponent?: ComponentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* branding module configuration
|
||||
*/
|
||||
export interface BrandingPlugin {
|
||||
ConfigPage?: ComponentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* localization configuration
|
||||
*/
|
||||
export interface LocalesConfig {
|
||||
[locale: string]: Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* application plugin interface
|
||||
*/
|
||||
export interface AppPlugin {
|
||||
/**
|
||||
* application initialization hook
|
||||
* called when the application starts, can return initialization data
|
||||
*/
|
||||
onAppInit?: () => Promise<Record<string, any>> | Record<string, any>;
|
||||
|
||||
/**
|
||||
* application ready hook
|
||||
* called when the application is fully loaded
|
||||
*/
|
||||
onAppReady?: () => void | Promise<void>;
|
||||
|
||||
/**
|
||||
* login module
|
||||
*/
|
||||
login?: LoginPlugin;
|
||||
|
||||
/**
|
||||
* branding module
|
||||
*/
|
||||
branding?: BrandingPlugin;
|
||||
|
||||
/**
|
||||
* localization configuration
|
||||
*/
|
||||
locales?: LocalesConfig;
|
||||
|
||||
/**
|
||||
* routes extension
|
||||
*/
|
||||
routes?: RouteConfig[];
|
||||
|
||||
/**
|
||||
* components extension
|
||||
*/
|
||||
components?: Record<string, ComponentType>;
|
||||
|
||||
/**
|
||||
* Hooks extension
|
||||
*/
|
||||
hooks?: Record<string, (...args: unknown[]) => unknown>;
|
||||
|
||||
/**
|
||||
* other custom fields for future extensions
|
||||
*/
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* plugin manager interface
|
||||
*/
|
||||
export interface IPluginManager {
|
||||
register(name: string, plugin: AppPlugin): void;
|
||||
get(name: string): AppPlugin | undefined;
|
||||
has(name: string): boolean;
|
||||
getAll(): Map<string, AppPlugin>;
|
||||
}
|
||||
Reference in New Issue
Block a user