build: sync config

This commit is contained in:
jialin
2026-04-24 14:28:30 +08:00
committed by jialin
parent 48b357b1c6
commit 6c161c6ae7
55 changed files with 731 additions and 90 deletions
+23
View File
@@ -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);
};
+34
View File
@@ -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);
}
});
}
+81
View File
@@ -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();
+2
View File
@@ -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;
+57
View File
@@ -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)
);
}
+95
View File
@@ -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>;
}