Skip to content

Commit 0c5eb64

Browse files
committed
Merge branch 'dev' into test
2 parents 5fd09d8 + 895c1c4 commit 0c5eb64

File tree

6 files changed

+107
-49
lines changed

6 files changed

+107
-49
lines changed

ui/src/App.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@ import { RouterProvider, createBrowserRouter } from 'react-router-dom';
2222
import './i18n/init';
2323

2424
import '@/utils/pluginKit';
25-
import routes from '@/router';
25+
import { useMergeRoutes } from '@/router';
26+
import InitialLoadingPlaceholder from '@/components/InitialLoadingPlaceholder';
2627

2728
function App() {
29+
const routes = useMergeRoutes();
30+
if (routes.length === 0) {
31+
return <InitialLoadingPlaceholder />;
32+
}
2833
const router = createBrowserRouter(routes, {
2934
basename: process.env.REACT_APP_BASE_URL,
3035
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Same as spin in `public/index.html`
2+
3+
@keyframes _initial-loading-spin {
4+
to { transform: rotate(360deg) }
5+
}
6+
7+
.InitialLoadingPlaceholder {
8+
position: fixed;
9+
top: 0;
10+
right: 0;
11+
bottom: 0;
12+
left: 0;
13+
background-color: white;
14+
z-index: 9999;
15+
16+
&-spinnerContainer {
17+
position: absolute;
18+
top: 50%;
19+
left: 50%;
20+
transform: translate(-50%, -50%);
21+
}
22+
23+
&-spinner {
24+
box-sizing: border-box;
25+
display: inline-block;
26+
width: 2rem;
27+
height: 2rem;
28+
vertical-align: -.125em;
29+
border: .25rem solid currentColor;
30+
border-right-color: transparent;
31+
color: rgba(108, 117, 125, .75);
32+
border-radius: 50%;
33+
animation: 0.75s linear infinite _initial-loading-spin;
34+
}
35+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Same as spin in `public/index.html`
2+
3+
import './index.scss';
4+
5+
function InitialLoadingPlaceholder() {
6+
return (
7+
<div className="InitialLoadingPlaceholder">
8+
<div className="InitialLoadingPlaceholder-spinnerContainer">
9+
<div className="InitialLoadingPlaceholder-spinner" />
10+
</div>
11+
</div>
12+
);
13+
}
14+
15+
export default InitialLoadingPlaceholder;

ui/src/components/TagSelector/index.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
*/
1919

2020
/* eslint-disable no-nested-ternary */
21-
import { FC, useState, useEffect, useRef } from 'react';
21+
import { FC, useState, useEffect, useRef, useCallback } from 'react';
2222
import { Dropdown, Button, Form } from 'react-bootstrap';
2323
import { useTranslation } from 'react-i18next';
2424

25+
import debounce from 'lodash/debounce';
2526
import { marked } from 'marked';
2627
import classNames from 'classnames';
2728

@@ -69,7 +70,7 @@ const TagSelector: FC<IProps> = ({
6970
const [currentIndex, setCurrentIndex] = useState<number>(0);
7071
const [repeatIndex, setRepeatIndex] = useState(-1);
7172
const [searchValue, setSearchValue] = useState<string>('');
72-
const [tags, setTags] = useState<Type.Tag[] | null>(null);
73+
const [tags, setTags] = useState<Type.Tag[] | null>([]);
7374
const [requiredTags, setRequiredTags] = useState<Type.Tag[] | null>(null);
7475
const { t } = useTranslation('translation', { keyPrefix: 'tag_selector' });
7576
const { data: userPermission } = useUserPermission('tag.add');
@@ -146,20 +147,23 @@ const TagSelector: FC<IProps> = ({
146147
handleMenuShow(false);
147148
};
148149

149-
const fetchTags = (str) => {
150-
if (!showRequiredTag && !str) {
151-
setTags([]);
152-
return;
153-
}
154-
queryTags(str).then((res) => {
155-
const tagArray: Type.Tag[] = filterTags(res || []);
156-
if (str === '') {
157-
setRequiredTags(res);
150+
const fetchTags = useCallback(
151+
debounce((str) => {
152+
if (!showRequiredTag && !str) {
153+
setTags([]);
154+
return;
158155
}
159-
handleMenuShow(tagArray.length > 0);
160-
setTags(tagArray);
161-
});
162-
};
156+
queryTags(str).then((res) => {
157+
const tagArray: Type.Tag[] = filterTags(res || []);
158+
if (str === '') {
159+
setRequiredTags(res);
160+
}
161+
handleMenuShow(tagArray.length > 0);
162+
setTags(tagArray);
163+
});
164+
}, 400),
165+
[],
166+
);
163167

164168
const resetSearch = () => {
165169
setCurrentIndex(0);

ui/src/router/index.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* under the License.
1818
*/
1919

20-
import { Suspense, lazy } from 'react';
20+
import { Suspense, lazy, useEffect, useState } from 'react';
2121
import { RouteObject } from 'react-router-dom';
2222

2323
import Layout from '@/pages/Layout';
@@ -27,8 +27,6 @@ import baseRoutes, { RouteNode } from './routes';
2727
import RouteGuard from './RouteGuard';
2828
import RouteErrorBoundary from './RouteErrorBoundary';
2929

30-
const routes: RouteNode[] = [];
31-
3230
const routeWrapper = (routeNodes: RouteNode[], root: RouteNode[]) => {
3331
routeNodes.forEach((rn) => {
3432
if (rn.page === 'pages/Layout') {
@@ -76,8 +74,22 @@ const routeWrapper = (routeNodes: RouteNode[], root: RouteNode[]) => {
7674
}
7775
});
7876
};
79-
const mergedRoutes = mergeRoutePlugins(baseRoutes);
8077

81-
routeWrapper(mergedRoutes, routes);
78+
function useMergeRoutes() {
79+
const [routesState, setRoutes] = useState<RouteObject[]>([]);
80+
81+
const init = async () => {
82+
const routes = [];
83+
const mergedRoutes = await mergeRoutePlugins(baseRoutes).catch(() => []);
84+
routeWrapper(mergedRoutes, routes);
85+
setRoutes(routes);
86+
};
87+
88+
useEffect(() => {
89+
init();
90+
}, []);
91+
92+
return routesState;
93+
}
8294

83-
export default routes as RouteObject[];
95+
export { useMergeRoutes };

ui/src/utils/pluginKit/index.ts

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,18 @@ class Plugins {
4747

4848
registeredPlugins: Type.ActivatedPlugin[] = [];
4949

50+
initialization: Promise<void>;
51+
5052
constructor() {
51-
this.init();
53+
this.initialization = this.init();
5254
}
5355

54-
init() {
56+
async init() {
5557
this.registerBuiltin();
5658

57-
getPluginsStatus().then((plugins) => {
58-
this.registeredPlugins = plugins.filter((p) => p.enabled);
59-
this.registerPlugins();
60-
});
59+
const plugins = await getPluginsStatus().catch(() => []);
60+
this.registeredPlugins = plugins.filter((p) => p.enabled);
61+
await this.registerPlugins();
6162
}
6263

6364
refresh() {
@@ -101,12 +102,9 @@ class Plugins {
101102
return func;
102103
})
103104
.filter((p) => p);
104-
return new Promise((resolve) => {
105-
plugins.forEach(async (p) => {
106-
const plugin = await p();
107-
this.register(plugin);
108-
});
109-
resolve(true);
105+
return Promise.all(plugins.map((p) => p())).then((resolvedPlugins) => {
106+
resolvedPlugins.forEach((plugin) => this.register(plugin));
107+
return true;
110108
});
111109
}
112110

@@ -122,18 +120,6 @@ class Plugins {
122120
this.plugins.push(plugin);
123121
}
124122

125-
activatePlugins(activatedPlugins: Type.ActivatedPlugin[]) {
126-
this.plugins.forEach((plugin: any) => {
127-
const { slug_name } = plugin.info;
128-
const activatedPlugin: any = activatedPlugins?.find(
129-
(p) => p.slug_name === slug_name,
130-
);
131-
if (activatedPlugin) {
132-
plugin.activated = activatedPlugin?.enabled;
133-
}
134-
});
135-
}
136-
137123
getPlugin(slug_name: string) {
138124
return this.plugins.find((p) => p.info.slug_name === slug_name);
139125
}
@@ -150,7 +136,8 @@ class Plugins {
150136

151137
const plugins = new Plugins();
152138

153-
const getRoutePlugins = () => {
139+
const getRoutePlugins = async () => {
140+
await plugins.initialization;
154141
return plugins
155142
.getPlugins()
156143
.filter((plugin) => plugin.info.type === PluginType.Route);
@@ -180,8 +167,8 @@ const validateRoutePlugin = async (slugName) => {
180167
return Boolean(registeredPlugin?.enabled);
181168
};
182169

183-
const mergeRoutePlugins = (routes) => {
184-
const routePlugins = getRoutePlugins();
170+
const mergeRoutePlugins = async (routes) => {
171+
const routePlugins = await getRoutePlugins();
185172
if (routePlugins.length === 0) {
186173
return routes;
187174
}

0 commit comments

Comments
 (0)