diff --git a/ui/dashboardApp/index.ts b/ui/dashboardApp/index.ts
index d9adf8eefb..3e521af8fc 100644
--- a/ui/dashboardApp/index.ts
+++ b/ui/dashboardApp/index.ts
@@ -15,6 +15,7 @@ import {
} from '@lib/utils/appOptions'
import * as telemetry from '@lib/utils/telemetry'
+import LayoutRoot from '@dashboard/layout/root'
import LayoutMain from '@dashboard/layout/main'
import LayoutSignIn from '@dashboard/layout/signin'
@@ -43,9 +44,16 @@ async function main(options: AppOptions) {
const registry = new AppRegistry(options)
+ singleSpa.registerApplication(
+ 'root',
+ AppRegistry.newReactSpaApp(() => LayoutRoot, 'root'),
+ () => true,
+ { registry }
+ )
+
singleSpa.registerApplication(
'layout',
- AppRegistry.newReactSpaApp(() => LayoutMain, 'root'),
+ AppRegistry.newReactSpaApp(() => LayoutMain, '__spa__main__'),
() => {
return !routing.isSignInPage()
},
@@ -54,7 +62,7 @@ async function main(options: AppOptions) {
singleSpa.registerApplication(
'signin',
- AppRegistry.newReactSpaApp(() => LayoutSignIn, 'root'),
+ AppRegistry.newReactSpaApp(() => LayoutSignIn, '__spa__main__'),
() => {
return routing.isSignInPage()
},
diff --git a/ui/dashboardApp/layout/root/index.tsx b/ui/dashboardApp/layout/root/index.tsx
new file mode 100644
index 0000000000..49fe281a4e
--- /dev/null
+++ b/ui/dashboardApp/layout/root/index.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import { HashRouter as Router } from 'react-router-dom'
+
+import { Root, TopLoadingBar } from '@lib/components'
+
+function App() {
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default App
diff --git a/ui/lib/components/TopLoadingBar/index.tsx b/ui/lib/components/TopLoadingBar/index.tsx
new file mode 100644
index 0000000000..ee7e5a5a82
--- /dev/null
+++ b/ui/lib/components/TopLoadingBar/index.tsx
@@ -0,0 +1,20 @@
+import React, { useRef } from 'react'
+import { useEventListener } from '@umijs/hooks'
+import LoadingBar from 'react-top-loading-bar'
+
+const useLoadingBar = () => {
+ const loadingBar = useRef()
+ useEventListener('single-spa:before-routing-event', () =>
+ loadingBar.current.continuousStart()
+ )
+ useEventListener('single-spa:routing-event', () =>
+ loadingBar.current.complete()
+ )
+
+ return loadingBar
+}
+
+export default function TopLoadinngBar() {
+ const loadingBar = useLoadingBar()
+ return
+}
diff --git a/ui/lib/components/index.ts b/ui/lib/components/index.ts
index 6faae1b285..13d16ff3a5 100644
--- a/ui/lib/components/index.ts
+++ b/ui/lib/components/index.ts
@@ -51,3 +51,4 @@ export { default as DatePicker } from './DatePicker'
export { default as LanguageDropdown } from './LanguageDropdown'
export { default as ParamsPageWrapper } from './ParamsPageWrapper'
+export { default as TopLoadingBar } from './TopLoadingBar'
diff --git a/ui/package.json b/ui/package.json
index d12ed1ab95..aade17992d 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -36,6 +36,7 @@
"react-router-dom": "^6.0.0-alpha.3",
"react-spring": "^8.0.27",
"react-syntax-highlighter": "^12.2.1",
+ "react-top-loading-bar": "^1.2.0",
"react-use": "^14.2.0",
"single-spa": "^5.3.4",
"single-spa-react": "^2.14.0",
diff --git a/ui/yarn.lock b/ui/yarn.lock
index d3d757783f..9c92773870 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -11442,6 +11442,11 @@ react-syntax-highlighter@^12.2.1:
prismjs "^1.8.4"
refractor "^2.4.1"
+react-top-loading-bar@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/react-top-loading-bar/-/react-top-loading-bar-1.2.0.tgz#fcbca3c2e462bee7b1c0d1850e8b584cd7bd5a26"
+ integrity sha512-5oNdy+DfD5JK06bcc/gsnnXHmml+d8eaBe3C8KQ3eLiH/BD8+FcwsgbAwqgOaRjuSeVQXdYN2JC2G1uVFtCLfA==
+
react-universal-interface@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.0.tgz#b65cbf7d71a2f3f7dd9705d8e4f06748539bd465"