This is an automated email from the ASF dual-hosted git repository. robin0716 pushed a commit to branch dev in repository https://gitbox.apache.org/repos/asf/incubator-answer.git
commit c0a1f4e5cd816d739f1eb98ec9ca0294008165b3 Author: Ourai Lin <[email protected]> AuthorDate: Sat Oct 19 20:25:10 2024 +0800 fix(ui): route plugins register failed --- ui/src/App.tsx | 29 +++++++++++++++++++++++--- ui/src/router/index.tsx | 14 ++++++++----- ui/src/utils/pluginKit/index.ts | 46 +++++++++++++++++++++++++++++++++++------ 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/ui/src/App.tsx b/ui/src/App.tsx index affac7a9..1b7d1b82 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -17,14 +17,37 @@ * under the License. */ -import { RouterProvider, createBrowserRouter } from 'react-router-dom'; +import { + type RouteObject, + RouterProvider, + createBrowserRouter, +} from 'react-router-dom'; +import { useState, useEffect } from 'react'; import './i18n/init'; -import '@/utils/pluginKit'; -import routes from '@/router'; +import { subscribe, unsubscribe } from '@/utils/pluginKit'; +import resolveRoutes from '@/router'; function App() { + const [routes, setRoutes] = useState<RouteObject[]>([]); + + useEffect(() => { + const callback = () => { + setRoutes(resolveRoutes()); + }; + + subscribe('registered', callback); + + return () => { + unsubscribe('registered', callback); + }; + }, []); + + if (routes.length === 0) { + return <div>initializing</div>; + } + const router = createBrowserRouter(routes, { basename: process.env.REACT_APP_BASE_URL, }); diff --git a/ui/src/router/index.tsx b/ui/src/router/index.tsx index 432cb581..8c111e0f 100644 --- a/ui/src/router/index.tsx +++ b/ui/src/router/index.tsx @@ -27,8 +27,6 @@ import baseRoutes, { RouteNode } from './routes'; import RouteGuard from './RouteGuard'; import RouteErrorBoundary from './RouteErrorBoundary'; -const routes: RouteNode[] = []; - const routeWrapper = (routeNodes: RouteNode[], root: RouteNode[]) => { routeNodes.forEach((rn) => { if (rn.page === 'pages/Layout') { @@ -76,8 +74,14 @@ const routeWrapper = (routeNodes: RouteNode[], root: RouteNode[]) => { } }); }; -const mergedRoutes = mergeRoutePlugins(baseRoutes); -routeWrapper(mergedRoutes, routes); +function resolveRoutes(): RouteObject[] { + const routes: RouteNode[] = []; + const mergedRoutes = mergeRoutePlugins(baseRoutes); + + routeWrapper(mergedRoutes, routes); + + return routes as RouteObject[]; +} -export default routes as RouteObject[]; +export default resolveRoutes; diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 66d5c376..43b0d691 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -42,15 +42,46 @@ import { Plugin, PluginInfo, PluginType } from './interface'; * @field description: Plugin description, optionally configurable. Usually read from the `i18n` file */ +type EventName = string; +type EventHandler = () => void; + class Plugins { plugins: Plugin[] = []; registeredPlugins: Type.ActivatedPlugin[] = []; + events: Record<EventName, EventHandler[]> = {}; + constructor() { this.init(); } + on(name: EventName, handler: EventHandler) { + if (!this.events[name]) { + this.events[name] = []; + } + + this.events[name].push(handler); + } + + off(name: EventName, handler?: EventHandler) { + const handlers = this.events[name]; + + if (!handlers || handlers.length === 0) { + return; + } + + if (handler) { + this.events[name] = handlers.filter((func) => func !== handler); + } else { + delete this.events[name]; + } + } + + trigger(name: EventName) { + (this.events[name] || []).forEach((handler) => handler()); + } + init() { this.registerBuiltin(); @@ -101,12 +132,10 @@ class Plugins { return func; }) .filter((p) => p); - return new Promise((resolve) => { - plugins.forEach(async (p) => { - const plugin = await p(); - this.register(plugin); - }); - resolve(true); + return Promise.all(plugins.map((p) => p())).then((resolvedPlugins) => { + resolvedPlugins.forEach((plugin) => this.register(plugin)); + this.trigger('registered'); + return true; }); } @@ -150,6 +179,9 @@ class Plugins { const plugins = new Plugins(); +const subscribe = plugins.on.bind(plugins); +const unsubscribe = plugins.off.bind(plugins); + const getRoutePlugins = () => { return plugins .getPlugins() @@ -287,5 +319,7 @@ export { useCaptchaPlugin, useRenderPlugin, PluginType, + subscribe, + unsubscribe, }; export default plugins;
