From d8d230557e3a53940c810f4c80bc502c0a3e8077 Mon Sep 17 00:00:00 2001 From: Jon Koops Date: Wed, 21 Jul 2021 11:20:32 +0200 Subject: [PATCH] Defer breadcrumbs translations on route definitions (#883) --- src/App.tsx | 8 +- src/PageNav.tsx | 2 +- .../bread-crumb/PageBreadCrumbs.tsx | 12 +- src/route-config.ts | 153 +++++++++--------- 4 files changed, 90 insertions(+), 85 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 9d11fc8582..2f41b3a3c8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -74,13 +74,9 @@ export const App = () => { onReset={() => window.location.reload()} > - {routes(() => {}).map((route, i) => ( + {routes.map((route, i) => ( ( diff --git a/src/PageNav.tsx b/src/PageNav.tsx index 838196d951..21652079d1 100644 --- a/src/PageNav.tsx +++ b/src/PageNav.tsx @@ -35,7 +35,7 @@ export const PageNav: React.FunctionComponent = () => { type LeftNavProps = { title: string; path: string }; const LeftNav = ({ title, path }: LeftNavProps) => { - const route = routes(() => {}).find( + const route = routes.find( (route) => route.path.replace(/\/:.+?(\?|(?:(?!\/).)*|$)/g, "") === path ); if (!route || !hasAccess(route.access)) return <>; diff --git a/src/components/bread-crumb/PageBreadCrumbs.tsx b/src/components/bread-crumb/PageBreadCrumbs.tsx index efe9e2b26d..fe4968c895 100644 --- a/src/components/bread-crumb/PageBreadCrumbs.tsx +++ b/src/components/bread-crumb/PageBreadCrumbs.tsx @@ -1,6 +1,9 @@ import React, { isValidElement } from "react"; import { Link } from "react-router-dom"; -import useBreadcrumbs, { BreadcrumbData } from "use-react-router-breadcrumbs"; +import useBreadcrumbs, { + BreadcrumbData, + BreadcrumbsRoute, +} from "use-react-router-breadcrumbs"; import { useTranslation } from "react-i18next"; import _ from "lodash"; import { Breadcrumb, BreadcrumbItem } from "@patternfly/react-core"; @@ -15,8 +18,13 @@ export const PageBreadCrumbs = () => { const elementText = (crumb: BreadcrumbData) => isValidElement(crumb.breadcrumb) && crumb.breadcrumb.props.children; + const routesWithCrumbs: BreadcrumbsRoute[] = routes.map((route) => ({ + ...route, + breadcrumb: route.breadcrumb?.(t), + })); + const crumbs = _.uniqBy( - useBreadcrumbs(routes(t), { + useBreadcrumbs(routesWithCrumbs, { excludePaths: ["/", `/${realm}`], }), elementText diff --git a/src/route-config.ts b/src/route-config.ts index e54dbd36aa..72cd30ac08 100644 --- a/src/route-config.ts +++ b/src/route-config.ts @@ -1,261 +1,262 @@ import type { TFunction } from "i18next"; -import type { BreadcrumbsRoute } from "use-react-router-breadcrumbs"; import type { AccessType } from "keycloak-admin/lib/defs/whoAmIRepresentation"; - +import type { ComponentType } from "react"; +import type { MatchOptions } from "use-react-router-breadcrumbs"; import { AuthenticationSection } from "./authentication/AuthenticationSection"; -import { ClientScopeForm } from "./client-scopes/form/ClientScopeForm"; +import { RoleMappingForm } from "./client-scopes/add/RoleMappingForm"; import { ClientScopesSection } from "./client-scopes/ClientScopesSection"; -import { DashboardSection } from "./dashboard/Dashboard"; +import { MappingDetails } from "./client-scopes/details/MappingDetails"; +import { ClientScopeForm } from "./client-scopes/form/ClientScopeForm"; import { NewClientForm } from "./clients/add/NewClientForm"; +import { ClientDetails } from "./clients/ClientDetails"; import { ClientsSection } from "./clients/ClientsSection"; import { ImportForm } from "./clients/import/ImportForm"; +import { CreateInitialAccessToken } from "./clients/initial-access/CreateInitialAccessToken"; +import { DashboardSection } from "./dashboard/Dashboard"; import { EventsSection } from "./events/EventsSection"; import { GroupsSection } from "./groups/GroupsSection"; -import { IdentityProvidersSection } from "./identity-providers/IdentityProvidersSection"; -import { PageNotFoundSection } from "./PageNotFoundSection"; -import { RealmRolesSection } from "./realm-roles/RealmRolesSection"; -import { - EditProviderCrumb, - RealmSettingsSection, -} from "./realm-settings/RealmSettingsSection"; -import { NewRealmForm } from "./realm/add/NewRealmForm"; -import { SessionsSection } from "./sessions/SessionsSection"; -import { UserFederationSection } from "./user-federation/UserFederationSection"; -import { UsersSection } from "./user/UsersSection"; -import { MappingDetails } from "./client-scopes/details/MappingDetails"; -import { ClientDetails } from "./clients/ClientDetails"; -import { UsersTabs } from "./user/UsersTabs"; -import { UserGroups } from "./user/UserGroups"; -import { UserFederationKerberosSettings } from "./user-federation/UserFederationKerberosSettings"; -import { UserFederationLdapSettings } from "./user-federation/UserFederationLdapSettings"; -import { RoleMappingForm } from "./client-scopes/add/RoleMappingForm"; -import { RealmRoleTabs } from "./realm-roles/RealmRoleTabs"; import { SearchGroups } from "./groups/SearchGroups"; -import { CreateInitialAccessToken } from "./clients/initial-access/CreateInitialAccessToken"; -import { LdapMapperDetails } from "./user-federation/ldap/mappers/LdapMapperDetails"; import { AddIdentityProvider, IdentityProviderCrumb, } from "./identity-providers/add/AddIdentityProvider"; import { AddOpenIdConnect } from "./identity-providers/add/AddOpenIdConnect"; import { DetailSettings } from "./identity-providers/add/DetailSettings"; +import { IdentityProvidersSection } from "./identity-providers/IdentityProvidersSection"; +import { PageNotFoundSection } from "./PageNotFoundSection"; +import { RealmRolesSection } from "./realm-roles/RealmRolesSection"; +import { RealmRoleTabs } from "./realm-roles/RealmRoleTabs"; import { AESGeneratedSettings } from "./realm-settings/key-providers/aes-generated/AESGeneratedForm"; -import { HMACGeneratedSettings } from "./realm-settings/key-providers/hmac-generated/HMACGeneratedForm"; -import { RSAGeneratedSettings } from "./realm-settings/key-providers/rsa-generated/RSAGeneratedForm"; import { ECDSAGeneratedSettings } from "./realm-settings/key-providers/ecdsa-generated/ECDSAGeneratedForm"; +import { HMACGeneratedSettings } from "./realm-settings/key-providers/hmac-generated/HMACGeneratedForm"; import { JavaKeystoreSettings } from "./realm-settings/key-providers/java-keystore/JavaKeystoreForm"; +import { RSAGeneratedSettings } from "./realm-settings/key-providers/rsa-generated/RSAGeneratedForm"; import { RSASettings } from "./realm-settings/key-providers/rsa/RSAForm"; +import { + EditProviderCrumb, + RealmSettingsSection, +} from "./realm-settings/RealmSettingsSection"; +import { NewRealmForm } from "./realm/add/NewRealmForm"; +import { SessionsSection } from "./sessions/SessionsSection"; +import { LdapMapperDetails } from "./user-federation/ldap/mappers/LdapMapperDetails"; +import { UserFederationKerberosSettings } from "./user-federation/UserFederationKerberosSettings"; +import { UserFederationLdapSettings } from "./user-federation/UserFederationLdapSettings"; +import { UserFederationSection } from "./user-federation/UserFederationSection"; +import { UserGroups } from "./user/UserGroups"; +import { UsersSection } from "./user/UsersSection"; +import { UsersTabs } from "./user/UsersTabs"; -export type RouteDef = BreadcrumbsRoute & { +export type RouteDef = { + path: string; + component: ComponentType; + breadcrumb: ((t: TFunction) => string | ComponentType) | null; access: AccessType; - component: () => JSX.Element; + matchOptions?: MatchOptions; }; -type RoutesFn = (t: TFunction) => RouteDef[]; - -export const routes: RoutesFn = (t: TFunction) => [ +export const routes: RouteDef[] = [ { path: "/:realm/add-realm", component: NewRealmForm, - breadcrumb: t("realm:createRealm"), + breadcrumb: (t) => t("realm:createRealm"), access: "manage-realm", }, { path: "/:realm/clients/add-client", component: NewClientForm, - breadcrumb: t("clients:createClient"), + breadcrumb: (t) => t("clients:createClient"), access: "manage-clients", }, { path: "/:realm/clients/import-client", component: ImportForm, - breadcrumb: t("clients:importClient"), + breadcrumb: (t) => t("clients:importClient"), access: "manage-clients", }, { path: "/:realm/clients/:tab?", component: ClientsSection, - breadcrumb: t("clients:clientList"), + breadcrumb: (t) => t("clients:clientList"), access: "query-clients", }, { path: "/:realm/clients/initialAccessToken/create", component: CreateInitialAccessToken, - breadcrumb: t("clients:createToken"), + breadcrumb: (t) => t("clients:createToken"), access: "manage-clients", }, { path: "/:realm/clients/:clientId/roles/add-role", component: RealmRoleTabs, - breadcrumb: t("roles:createRole"), + breadcrumb: (t) => t("roles:createRole"), access: "manage-realm", }, { path: "/:realm/clients/:clientId/roles/:id/:tab?", component: RealmRoleTabs, - breadcrumb: t("roles:roleDetails"), + breadcrumb: (t) => t("roles:roleDetails"), access: "view-realm", }, { path: "/:realm/clients/:clientId/:tab", component: ClientDetails, - breadcrumb: t("clients:clientSettings"), + breadcrumb: (t) => t("clients:clientSettings"), access: "view-clients", }, { path: "/:realm/client-scopes/new", component: ClientScopeForm, - breadcrumb: t("client-scopes:createClientScope"), + breadcrumb: (t) => t("client-scopes:createClientScope"), access: "manage-clients", }, { path: "/:realm/client-scopes/:id/mappers/oidc-role-name-mapper", component: RoleMappingForm, - breadcrumb: t("common:mappingDetails"), + breadcrumb: (t) => t("common:mappingDetails"), access: "view-clients", }, { path: "/:realm/client-scopes/:id/mappers/:mapperId", component: MappingDetails, - breadcrumb: t("common:mappingDetails"), + breadcrumb: (t) => t("common:mappingDetails"), access: "view-clients", }, { path: "/:realm/client-scopes/:id/:type/:tab", component: ClientScopeForm, - breadcrumb: t("client-scopes:clientScopeDetails"), + breadcrumb: (t) => t("client-scopes:clientScopeDetails"), access: "view-clients", }, { path: "/:realm/client-scopes", component: ClientScopesSection, - breadcrumb: t("client-scopes:clientScopeList"), + breadcrumb: (t) => t("client-scopes:clientScopeList"), access: "view-clients", }, { path: "/:realm/roles", component: RealmRolesSection, - breadcrumb: t("roles:roleList"), + breadcrumb: (t) => t("roles:roleList"), access: "view-realm", }, { path: "/:realm/roles/add-role", component: RealmRoleTabs, - breadcrumb: t("roles:createRole"), + breadcrumb: (t) => t("roles:createRole"), access: "manage-realm", }, { path: "/:realm/roles/:id/:tab?", component: RealmRoleTabs, - breadcrumb: t("roles:roleDetails"), + breadcrumb: (t) => t("roles:roleDetails"), access: "view-realm", }, { path: "/:realm/users", component: UsersSection, - breadcrumb: t("users:title"), + breadcrumb: (t) => t("users:title"), access: "query-users", }, { path: "/:realm/users/add-user", component: UsersTabs, - breadcrumb: t("users:createUser"), + breadcrumb: (t) => t("users:createUser"), access: "manage-users", }, { path: "/:realm/users/:id", component: UserGroups, - breadcrumb: t("users:userDetails"), + breadcrumb: (t) => t("users:userDetails"), access: "manage-users", }, { path: "/:realm/users/:id/:tab", component: UsersTabs, - breadcrumb: t("users:userDetails"), + breadcrumb: (t) => t("users:userDetails"), access: "manage-users", }, { path: "/:realm/sessions", component: SessionsSection, - breadcrumb: t("sessions:title"), + breadcrumb: (t) => t("sessions:title"), access: "view-realm", }, { path: "/:realm/events/:tab?", component: EventsSection, - breadcrumb: t("events:title"), + breadcrumb: (t) => t("events:title"), access: "view-events", }, { path: "/:realm/realm-settings/:tab?", component: RealmSettingsSection, - breadcrumb: t("realmSettings"), + breadcrumb: (t) => t("realmSettings"), access: "view-realm", }, { path: "/:realm/realm-settings/keys/:id?/aes-generated/settings", component: AESGeneratedSettings, - breadcrumb: EditProviderCrumb, + breadcrumb: () => EditProviderCrumb, access: "view-realm", }, { path: "/:realm/realm-settings/keys/:id?/ecdsa-generated/settings", component: ECDSAGeneratedSettings, - breadcrumb: EditProviderCrumb, + breadcrumb: () => EditProviderCrumb, access: "view-realm", }, { path: "/:realm/realm-settings/keys/:id?/hmac-generated/settings", component: HMACGeneratedSettings, - breadcrumb: EditProviderCrumb, + breadcrumb: () => EditProviderCrumb, access: "view-realm", }, { path: "/:realm/realm-settings/keys/:id?/java-keystore/settings", component: JavaKeystoreSettings, - breadcrumb: EditProviderCrumb, + breadcrumb: () => EditProviderCrumb, access: "view-realm", }, { path: "/:realm/realm-settings/keys/:id?/rsa-generated/settings", component: RSAGeneratedSettings, - breadcrumb: EditProviderCrumb, + breadcrumb: () => EditProviderCrumb, access: "view-realm", }, { path: "/:realm/realm-settings/keys/:id?/rsa/settings", component: RSASettings, - breadcrumb: EditProviderCrumb, + breadcrumb: () => EditProviderCrumb, access: "view-realm", }, { path: "/:realm/authentication", component: AuthenticationSection, - breadcrumb: t("authentication"), + breadcrumb: (t) => t("authentication"), access: "view-realm", }, { path: "/:realm/identity-providers", component: IdentityProvidersSection, - breadcrumb: t("identityProviders"), + breadcrumb: (t) => t("identityProviders"), access: "view-identity-providers", }, { path: "/:realm/identity-providers/oidc", component: AddOpenIdConnect, - breadcrumb: t("identity-providers:addOpenIdProvider"), + breadcrumb: (t) => t("identity-providers:addOpenIdProvider"), access: "manage-identity-providers", }, { path: "/:realm/identity-providers/keycloak-oidc", component: AddOpenIdConnect, - breadcrumb: t("identity-providers:addKeycloakOpenIdProvider"), + breadcrumb: (t) => t("identity-providers:addKeycloakOpenIdProvider"), access: "manage-identity-providers", }, { path: "/:realm/identity-providers/:id", component: AddIdentityProvider, - breadcrumb: IdentityProviderCrumb, + breadcrumb: () => IdentityProviderCrumb, access: "manage-identity-providers", }, { @@ -267,7 +268,7 @@ export const routes: RoutesFn = (t: TFunction) => [ { path: "/:realm/user-federation", component: UserFederationSection, - breadcrumb: t("userFederation"), + breadcrumb: (t) => t("userFederation"), access: "view-realm", }, { @@ -279,13 +280,13 @@ export const routes: RoutesFn = (t: TFunction) => [ { path: "/:realm/user-federation/kerberos/:id", component: UserFederationKerberosSettings, - breadcrumb: t("common:settings"), + breadcrumb: (t) => t("common:settings"), access: "view-realm", }, { path: "/:realm/user-federation/kerberos/new", component: UserFederationKerberosSettings, - breadcrumb: t("common:settings"), + breadcrumb: (t) => t("common:settings"), access: "view-realm", }, { @@ -297,46 +298,46 @@ export const routes: RoutesFn = (t: TFunction) => [ { path: "/:realm/user-federation/ldap/new", component: UserFederationLdapSettings, - breadcrumb: t("user-federation:addOneLdap"), + breadcrumb: (t) => t("user-federation:addOneLdap"), access: "view-realm", }, { path: "/:realm/user-federation/ldap/:id/:tab?", component: UserFederationLdapSettings, - breadcrumb: t("common:settings"), + breadcrumb: (t) => t("common:settings"), access: "view-realm", }, { path: "/:realm/user-federation/ldap/:id/:tab/:mapperId", component: LdapMapperDetails, - breadcrumb: t("common:mappingDetails"), + breadcrumb: (t) => t("common:mappingDetails"), access: "view-realm", }, { path: "/:realm/", component: DashboardSection, - breadcrumb: t("common:home"), + breadcrumb: (t) => t("common:home"), access: "anyone", }, { path: "/:realm/groups/search", component: SearchGroups, - breadcrumb: t("groups:searchGroups"), + breadcrumb: (t) => t("groups:searchGroups"), access: "query-groups", }, { path: "/:realm/groups", component: GroupsSection, breadcrumb: null, + access: "query-groups", matchOptions: { exact: false, }, - access: "query-groups", }, { path: "/", component: DashboardSection, - breadcrumb: t("common:home"), + breadcrumb: (t) => t("common:home"), access: "anyone", }, {