made routes more dynamic (#36004)

fixes: #35639

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
Erik Jan de Wit 2024-12-19 14:11:11 +01:00 committed by GitHub
parent 1fc6d595d9
commit d9f9b982ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 78 additions and 42 deletions

View File

@ -1,11 +1,12 @@
import "@patternfly/react-core/dist/styles/base.css";
import "@patternfly/patternfly/patternfly-addons.css";
import "@patternfly/react-core/dist/styles/base.css";
import { KeycloakProvider } from "@keycloak/keycloak-ui-shared";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { environment } from "./environment";
import { i18n } from "./i18n";
import { routes } from "./routes";
import { Root } from "./root/Root";
// Initialize required components before rendering app.
await i18n.init();
@ -13,10 +14,10 @@ await i18n.init();
const container = document.getElementById("app");
const root = createRoot(container!);
const router = createBrowserRouter(routes);
root.render(
<StrictMode>
<RouterProvider router={router} />
<KeycloakProvider environment={environment}>
<Root />
</KeycloakProvider>
</StrictMode>,
);

View File

@ -29,6 +29,7 @@ import { TFuncKey } from "../i18n";
import { usePromise } from "../utils/usePromise";
type RootMenuItem = {
id?: string;
label: TFuncKey;
path: string;
isVisible?: keyof Feature;

View File

@ -1,20 +1,62 @@
import { KeycloakProvider } from "@keycloak/keycloak-ui-shared";
import { ErrorPage, useEnvironment } from "@keycloak/keycloak-ui-shared";
import { Page, Spinner } from "@patternfly/react-core";
import { Suspense } from "react";
import { Outlet } from "react-router-dom";
import { environment } from "../environment";
import { Suspense, useState } from "react";
import {
createBrowserRouter,
Outlet,
RouteObject,
RouterProvider,
} from "react-router-dom";
import fetchContentJson from "../content/fetchContent";
import { Environment, environment } from "../environment";
import { usePromise } from "../utils/usePromise";
import { Header } from "./Header";
import { PageNav } from "./PageNav";
import { MenuItem, PageNav } from "./PageNav";
import { routes } from "../routes";
function mapRoutes(content: MenuItem[]): RouteObject[] {
return content
.map((item) => {
if ("children" in item) {
return mapRoutes(item.children);
}
return {
...item,
element:
"path" in item
? routes.find((r) => r.path === (item.id ?? item.path))?.element
: undefined,
};
})
.flat();
}
export const Root = () => {
return (
<KeycloakProvider environment={environment}>
<Page header={<Header />} sidebar={<PageNav />} isManagedSidebar>
<Suspense fallback={<Spinner />}>
<Outlet />
</Suspense>
</Page>
</KeycloakProvider>
const context = useEnvironment<Environment>();
const [content, setContent] = useState<RouteObject[]>();
usePromise(
(signal) => fetchContentJson({ signal, context }),
(content) => {
setContent([
{
path: decodeURIComponent(new URL(environment.baseUrl).pathname),
element: (
<Page header={<Header />} sidebar={<PageNav />} isManagedSidebar>
<Suspense fallback={<Spinner />}>
<Outlet />
</Suspense>
</Page>
),
errorElement: <ErrorPage />,
children: mapRoutes(content),
},
]);
},
);
if (!content) {
return <Spinner />;
}
return <RouterProvider router={createBrowserRouter(content)} />;
};

View File

@ -2,8 +2,6 @@ import { lazy } from "react";
import type { IndexRouteObject, RouteObject } from "react-router-dom";
import { environment } from "./environment";
import { Organizations } from "./organizations/Organizations";
import { Root } from "./root/Root";
import { ErrorPage } from "@keycloak/keycloak-ui-shared";
const DeviceActivity = lazy(() => import("./account-security/DeviceActivity"));
const LinkedAccounts = lazy(() => import("./account-security/LinkedAccounts"));
@ -57,6 +55,7 @@ export const ContentRoute: RouteObject = {
export const PersonalInfoRoute: IndexRouteObject = {
index: true,
element: <PersonalInfo />,
path: "",
};
export const OrganizationsRoute: RouteObject = {
@ -69,23 +68,16 @@ export const Oid4VciRoute: RouteObject = {
element: <Oid4Vci />,
};
export const RootRoute: RouteObject = {
path: decodeURIComponent(new URL(environment.baseUrl).pathname),
element: <Root />,
errorElement: <ErrorPage />,
children: [
PersonalInfoRoute,
DeviceActivityRoute,
LinkedAccountsRoute,
SigningInRoute,
ApplicationsRoute,
GroupsRoute,
OrganizationsRoute,
PersonalInfoRoute,
ResourcesRoute,
ContentRoute,
...(environment.features.isOid4VciEnabled ? [Oid4VciRoute] : []),
],
};
export const routes: RouteObject[] = [RootRoute];
export const routes: RouteObject[] = [
PersonalInfoRoute,
DeviceActivityRoute,
LinkedAccountsRoute,
SigningInRoute,
ApplicationsRoute,
GroupsRoute,
OrganizationsRoute,
PersonalInfoRoute,
ResourcesRoute,
ContentRoute,
...(environment.features.isOid4VciEnabled ? [Oid4VciRoute] : []),
];