diff --git a/src/App.tsx b/src/App.tsx index 86c6fb1d9b..e2b7ed473e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,10 +1,6 @@ import { FunctionComponent, Suspense } from "react"; import { Page } from "@patternfly/react-core"; -import { - HashRouter as Router, - Route as LegacyRoute, - Switch, -} from "react-router-dom"; +import { HashRouter as Router, Switch } from "react-router-dom"; import { CompatRouter, CompatRoute } from "react-router-dom-v5-compat"; import { ErrorBoundary } from "react-error-boundary"; import type Keycloak from "keycloak-js"; @@ -101,19 +97,15 @@ export const App = ({ keycloak, adminClient }: AdminClientProps) => { > - {routes.map((route, i) => { - const Route = route.legacy ? LegacyRoute : CompatRoute; - - return ( - - - - ); - })} + {routes.map((route, i) => ( + + + + ))} diff --git a/src/authentication/routes.ts b/src/authentication/routes.ts index b27870c5bd..9d2fb87541 100644 --- a/src/authentication/routes.ts +++ b/src/authentication/routes.ts @@ -1,8 +1,17 @@ import type { RouteDef } from "../route-config"; -import { AuthenticationRoute } from "./routes/Authentication"; +import { + AuthenticationRoute, + AuthenticationRouteWithTab, +} from "./routes/Authentication"; import { CreateFlowRoute } from "./routes/CreateFlow"; -import { FlowRoute } from "./routes/Flow"; +import { FlowRoute, FlowWithBuiltInRoute } from "./routes/Flow"; -const routes: RouteDef[] = [AuthenticationRoute, CreateFlowRoute, FlowRoute]; +const routes: RouteDef[] = [ + AuthenticationRoute, + AuthenticationRouteWithTab, + CreateFlowRoute, + FlowRoute, + FlowWithBuiltInRoute, +]; export default routes; diff --git a/src/authentication/routes/Authentication.ts b/src/authentication/routes/Authentication.ts index ea8410e390..e870f8b988 100644 --- a/src/authentication/routes/Authentication.ts +++ b/src/authentication/routes/Authentication.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type AuthenticationTab = "flows" | "required-actions" | "policies"; @@ -8,15 +8,25 @@ export type AuthenticationTab = "flows" | "required-actions" | "policies"; export type AuthenticationParams = { realm: string; tab?: AuthenticationTab }; export const AuthenticationRoute: RouteDef = { - path: "/:realm/authentication/:tab?", + path: "/:realm/authentication", component: lazy(() => import("../AuthenticationSection")), breadcrumb: (t) => t("authentication"), access: ["view-realm", "view-identity-providers", "view-clients"], - legacy: true, +}; + +export const AuthenticationRouteWithTab: RouteDef = { + ...AuthenticationRoute, + path: "/:realm/authentication/:tab", }; export const toAuthentication = ( params: AuthenticationParams -): Partial => ({ - pathname: generatePath(AuthenticationRoute.path, params), -}); +): Partial => { + const path = params.tab + ? AuthenticationRouteWithTab.path + : AuthenticationRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/authentication/routes/Flow.ts b/src/authentication/routes/Flow.ts index 8d0f9c676e..8084498d0c 100644 --- a/src/authentication/routes/Flow.ts +++ b/src/authentication/routes/Flow.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type FlowParams = { @@ -11,13 +11,21 @@ export type FlowParams = { }; export const FlowRoute: RouteDef = { - path: "/:realm/authentication/:id/:usedBy/:builtIn?", + path: "/:realm/authentication/:id/:usedBy", component: lazy(() => import("../FlowDetails")), breadcrumb: (t) => t("authentication:flowDetails"), access: "view-authorization", - legacy: true, }; -export const toFlow = (params: FlowParams): Partial => ({ - pathname: generatePath(FlowRoute.path, params), -}); +export const FlowWithBuiltInRoute: RouteDef = { + ...FlowRoute, + path: "/:realm/authentication/:id/:usedBy/:builtIn", +}; + +export const toFlow = (params: FlowParams): Partial => { + const path = params.builtIn ? FlowWithBuiltInRoute.path : FlowRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/client-scopes/routes.ts b/src/client-scopes/routes.ts index 45fb2bb46d..a3c0f54a78 100644 --- a/src/client-scopes/routes.ts +++ b/src/client-scopes/routes.ts @@ -1,5 +1,8 @@ import type { RouteDef } from "../route-config"; -import { ClientScopeRoute } from "./routes/ClientScope"; +import { + ClientScopeRoute, + ClientScopeWithTypeRoute, +} from "./routes/ClientScope"; import { ClientScopesRoute } from "./routes/ClientScopes"; import { MapperRoute } from "./routes/Mapper"; import { NewClientScopeRoute } from "./routes/NewClientScope"; @@ -8,6 +11,7 @@ const routes: RouteDef[] = [ NewClientScopeRoute, MapperRoute, ClientScopeRoute, + ClientScopeWithTypeRoute, ClientScopesRoute, ]; diff --git a/src/client-scopes/routes/ClientScope.ts b/src/client-scopes/routes/ClientScope.ts index d4cba46c7a..3d8d5e1542 100644 --- a/src/client-scopes/routes/ClientScope.ts +++ b/src/client-scopes/routes/ClientScope.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type ClientScopeTab = "settings" | "mappers" | "scope"; @@ -13,13 +13,23 @@ export type ClientScopeParams = { }; export const ClientScopeRoute: RouteDef = { - path: "/:realm/client-scopes/:id/:tab/:type?", + path: "/:realm/client-scopes/:id/:tab", component: lazy(() => import("../form/ClientScopeForm")), breadcrumb: (t) => t("client-scopes:clientScopeDetails"), access: "view-clients", - legacy: true, }; -export const toClientScope = (params: ClientScopeParams): Partial => ({ - pathname: generatePath(ClientScopeRoute.path, params), -}); +export const ClientScopeWithTypeRoute: RouteDef = { + ...ClientScopeRoute, + path: "/:realm/client-scopes/:id/:tab/:type", +}; + +export const toClientScope = (params: ClientScopeParams): Partial => { + const path = params.type + ? ClientScopeWithTypeRoute.path + : ClientScopeRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/clients/routes.ts b/src/clients/routes.ts index 4bbda52dde..2995237398 100644 --- a/src/clients/routes.ts +++ b/src/clients/routes.ts @@ -1,39 +1,56 @@ import type { RouteDef } from "../route-config"; import { AddClientRoute } from "./routes/AddClient"; import { ClientRoute } from "./routes/Client"; -import { ClientsRoute } from "./routes/Clients"; +import { ClientsRoute, ClientsRouteWithTab } from "./routes/Clients"; import { CreateInitialAccessTokenRoute } from "./routes/CreateInitialAccessToken"; import { ImportClientRoute } from "./routes/ImportClient"; import { MapperRoute } from "./routes/Mapper"; import { ClientScopesRoute } from "./routes/ClientScopeTab"; import { AuthorizationRoute } from "./routes/AuthenticationTab"; import { NewResourceRoute } from "./routes/NewResource"; -import { ResourceDetailsRoute } from "./routes/Resource"; +import { + ResourceDetailsRoute, + ResourceDetailsWithResourceIdRoute, +} from "./routes/Resource"; import { NewScopeRoute } from "./routes/NewScope"; -import { ScopeDetailsRoute } from "./routes/Scope"; +import { + ScopeDetailsRoute, + ScopeDetailsWithScopeIdRoute, +} from "./routes/Scope"; import { NewPolicyRoute } from "./routes/NewPolicy"; import { PolicyDetailsRoute } from "./routes/PolicyDetails"; -import { NewPermissionRoute } from "./routes/NewPermission"; +import { + NewPermissionRoute, + NewPermissionWithSelectedIdRoute, +} from "./routes/NewPermission"; import { PermissionDetailsRoute } from "./routes/PermissionDetails"; -import { DedicatedScopeDetailsRoute } from "./routes/DedicatedScopeDetails"; +import { + DedicatedScopeDetailsRoute, + DedicatedScopeDetailsWithTabRoute, +} from "./routes/DedicatedScopeDetails"; const routes: RouteDef[] = [ AddClientRoute, ImportClientRoute, ClientsRoute, + ClientsRouteWithTab, CreateInitialAccessTokenRoute, ClientRoute, MapperRoute, DedicatedScopeDetailsRoute, + DedicatedScopeDetailsWithTabRoute, ClientScopesRoute, AuthorizationRoute, NewResourceRoute, ResourceDetailsRoute, + ResourceDetailsWithResourceIdRoute, NewScopeRoute, ScopeDetailsRoute, + ScopeDetailsWithScopeIdRoute, NewPolicyRoute, PolicyDetailsRoute, NewPermissionRoute, + NewPermissionWithSelectedIdRoute, PermissionDetailsRoute, ]; diff --git a/src/clients/routes/Clients.ts b/src/clients/routes/Clients.ts index 8624f827de..3b3066ca25 100644 --- a/src/clients/routes/Clients.ts +++ b/src/clients/routes/Clients.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type ClientsTab = "list" | "initial-access-token"; @@ -11,13 +11,21 @@ export type ClientsParams = { }; export const ClientsRoute: RouteDef = { - path: "/:realm/clients/:tab?", + path: "/:realm/clients", component: lazy(() => import("../ClientsSection")), breadcrumb: (t) => t("clients:clientList"), access: "query-clients", - legacy: true, }; -export const toClients = (params: ClientsParams): Partial => ({ - pathname: generatePath(ClientsRoute.path, params), -}); +export const ClientsRouteWithTab: RouteDef = { + ...ClientsRoute, + path: "/:realm/clients/:tab", +}; + +export const toClients = (params: ClientsParams): Partial => { + const path = params.tab ? ClientsRouteWithTab.path : ClientsRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/clients/routes/DedicatedScopeDetails.ts b/src/clients/routes/DedicatedScopeDetails.ts index 667d0b390b..39a455affe 100644 --- a/src/clients/routes/DedicatedScopeDetails.ts +++ b/src/clients/routes/DedicatedScopeDetails.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type DedicatedScopeTab = "mappers" | "scope"; @@ -12,15 +12,25 @@ export type DedicatedScopeDetailsParams = { }; export const DedicatedScopeDetailsRoute: RouteDef = { - path: "/:realm/clients/:clientId/clientScopes/dedicated/:tab?", + path: "/:realm/clients/:clientId/clientScopes/dedicated", component: lazy(() => import("../scopes/DedicatedScopes")), breadcrumb: (t) => t("clients:dedicatedScopes"), access: "view-clients", - legacy: true, +}; + +export const DedicatedScopeDetailsWithTabRoute: RouteDef = { + ...DedicatedScopeDetailsRoute, + path: "/:realm/clients/:clientId/clientScopes/dedicated/:tab", }; export const toDedicatedScope = ( params: DedicatedScopeDetailsParams -): Partial => ({ - pathname: generatePath(DedicatedScopeDetailsRoute.path, params), -}); +): Partial => { + const path = params.tab + ? DedicatedScopeDetailsWithTabRoute.path + : DedicatedScopeDetailsRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/clients/routes/NewPermission.ts b/src/clients/routes/NewPermission.ts index 4387d1ad42..34d6e74204 100644 --- a/src/clients/routes/NewPermission.ts +++ b/src/clients/routes/NewPermission.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type PermissionType = "resource" | "scope"; @@ -13,15 +13,23 @@ export type NewPermissionParams = { }; export const NewPermissionRoute: RouteDef = { - path: "/:realm/clients/:id/authorization/permission/new/:permissionType/:selectedId?", + path: "/:realm/clients/:id/authorization/permission/new/:permissionType", component: lazy(() => import("../authorization/PermissionDetails")), breadcrumb: (t) => t("clients:createPermission"), access: "view-clients", - legacy: true, }; -export const toNewPermission = ( - params: NewPermissionParams -): Partial => ({ - pathname: generatePath(NewPermissionRoute.path, params), -}); +export const NewPermissionWithSelectedIdRoute: RouteDef = { + ...NewPermissionRoute, + path: "/:realm/clients/:id/authorization/permission/new/:permissionType/:selectedId?", +}; + +export const toNewPermission = (params: NewPermissionParams): Partial => { + const path = params.selectedId + ? NewPermissionWithSelectedIdRoute.path + : NewPermissionRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/clients/routes/Resource.ts b/src/clients/routes/Resource.ts index cb770c2e49..ea3c2601e5 100644 --- a/src/clients/routes/Resource.ts +++ b/src/clients/routes/Resource.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type ResourceDetailsParams = { @@ -10,15 +10,25 @@ export type ResourceDetailsParams = { }; export const ResourceDetailsRoute: RouteDef = { - path: "/:realm/clients/:id/authorization/resource/:resourceId?", + path: "/:realm/clients/:id/authorization/resource", component: lazy(() => import("../authorization/ResourceDetails")), breadcrumb: (t) => t("clients:createResource"), access: "view-clients", - legacy: true, +}; + +export const ResourceDetailsWithResourceIdRoute: RouteDef = { + ...ResourceDetailsRoute, + path: "/:realm/clients/:id/authorization/resource/:resourceId", }; export const toResourceDetails = ( params: ResourceDetailsParams -): Partial => ({ - pathname: generatePath(ResourceDetailsRoute.path, params), -}); +): Partial => { + const path = params.resourceId + ? ResourceDetailsWithResourceIdRoute.path + : ResourceDetailsRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/clients/routes/Scope.ts b/src/clients/routes/Scope.ts index 7549f76204..78c3a974e6 100644 --- a/src/clients/routes/Scope.ts +++ b/src/clients/routes/Scope.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type ScopeDetailsParams = { @@ -10,13 +10,23 @@ export type ScopeDetailsParams = { }; export const ScopeDetailsRoute: RouteDef = { - path: "/:realm/clients/:id/authorization/scope/:scopeId?", + path: "/:realm/clients/:id/authorization/scope", component: lazy(() => import("../authorization/ScopeDetails")), breadcrumb: (t) => t("clients:createAuthorizationScope"), access: "manage-clients", - legacy: true, }; -export const toScopeDetails = (params: ScopeDetailsParams): Partial => ({ - pathname: generatePath(ScopeDetailsRoute.path, params), -}); +export const ScopeDetailsWithScopeIdRoute: RouteDef = { + ...ScopeDetailsRoute, + path: "/:realm/clients/:id/authorization/scope/:scopeId", +}; + +export const toScopeDetails = (params: ScopeDetailsParams): Partial => { + const path = params.scopeId + ? ScopeDetailsWithScopeIdRoute.path + : ScopeDetailsRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/context/realm-context/RealmContext.tsx b/src/context/realm-context/RealmContext.tsx index 90d91f6e2a..e85db5ec97 100644 --- a/src/context/realm-context/RealmContext.tsx +++ b/src/context/realm-context/RealmContext.tsx @@ -3,7 +3,7 @@ import { useRouteMatch } from "react-router-dom"; import { RecentUsed } from "../../components/realm-selector/recent-used"; import { DashboardParams, - DashboardRoute, + DashboardRouteWithRealm, } from "../../dashboard/routes/Dashboard"; import environment from "../../environment"; import { createNamedContext } from "../../utils/createNamedContext"; @@ -22,7 +22,9 @@ export const RealmContext = createNamedContext( export const RealmContextProvider: FunctionComponent = ({ children }) => { const { adminClient } = useAdminClient(); const recentUsed = useMemo(() => new RecentUsed(), []); - const routeMatch = useRouteMatch(DashboardRoute.path); + const routeMatch = useRouteMatch( + DashboardRouteWithRealm.path + ); const realmParam = routeMatch?.params.realm; const realm = useMemo( () => realmParam ?? environment.loginRealm, diff --git a/src/dashboard/routes.ts b/src/dashboard/routes.ts index e3df4a471b..1520e1d4c0 100644 --- a/src/dashboard/routes.ts +++ b/src/dashboard/routes.ts @@ -1,6 +1,14 @@ import type { RouteDef } from "../route-config"; -import { DashboardRoute } from "./routes/Dashboard"; +import { + DashboardRoute, + DashboardRouteWithRealm, + DashboardRouteWithTab, +} from "./routes/Dashboard"; -const routes: RouteDef[] = [DashboardRoute]; +const routes: RouteDef[] = [ + DashboardRoute, + DashboardRouteWithRealm, + DashboardRouteWithTab, +]; export default routes; diff --git a/src/dashboard/routes/Dashboard.ts b/src/dashboard/routes/Dashboard.ts index f2a3cb7e46..6b144e9739 100644 --- a/src/dashboard/routes/Dashboard.ts +++ b/src/dashboard/routes/Dashboard.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type DashboardTab = "info" | "providers"; @@ -8,13 +8,30 @@ export type DashboardTab = "info" | "providers"; export type DashboardParams = { realm?: string; tab?: DashboardTab }; export const DashboardRoute: RouteDef = { - path: "/:realm?/:tab?", + path: "/", component: lazy(() => import("../Dashboard")), breadcrumb: (t) => t("common:home"), access: "anyone", - legacy: true, }; -export const toDashboard = (params: DashboardParams): Partial => ({ - pathname: generatePath(DashboardRoute.path, params), -}); +export const DashboardRouteWithRealm: RouteDef = { + ...DashboardRoute, + path: "/:realm", +}; + +export const DashboardRouteWithTab: RouteDef = { + ...DashboardRoute, + path: "/:realm/:tab", +}; + +export const toDashboard = (params: DashboardParams): Partial => { + const pathname = params.realm + ? params.tab + ? DashboardRouteWithTab.path + : DashboardRouteWithRealm.path + : DashboardRoute.path; + + return { + pathname: generatePath(pathname, params), + }; +}; diff --git a/src/events/routes.ts b/src/events/routes.ts index 3d5f54a971..9640c8d020 100644 --- a/src/events/routes.ts +++ b/src/events/routes.ts @@ -1,6 +1,6 @@ import type { RouteDef } from "../route-config"; -import { EventsRoute } from "./routes/Events"; +import { EventsRoute, EventsRouteWithTab } from "./routes/Events"; -const routes: RouteDef[] = [EventsRoute]; +const routes: RouteDef[] = [EventsRoute, EventsRouteWithTab]; export default routes; diff --git a/src/events/routes/Events.ts b/src/events/routes/Events.ts index 7942107ed1..b7dce87296 100644 --- a/src/events/routes/Events.ts +++ b/src/events/routes/Events.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type EventsTab = "user-events" | "admin-events"; @@ -11,13 +11,21 @@ export type EventsParams = { }; export const EventsRoute: RouteDef = { - path: "/:realm/events/:tab?", + path: "/:realm/events", component: lazy(() => import("../EventsSection")), breadcrumb: (t) => t("events:title"), access: "view-events", - legacy: true, }; -export const toEvents = (params: EventsParams): Partial => ({ - pathname: generatePath(EventsRoute.path, params), -}); +export const EventsRouteWithTab: RouteDef = { + ...EventsRoute, + path: "/:realm/events/:tab", +}; + +export const toEvents = (params: EventsParams): Partial => { + const path = params.tab ? EventsRouteWithTab.path : EventsRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/groups/routes.ts b/src/groups/routes.ts index 233b592f91..9355d645bf 100644 --- a/src/groups/routes.ts +++ b/src/groups/routes.ts @@ -1,7 +1,7 @@ import type { RouteDef } from "../route-config"; -import { GroupsRoute } from "./routes/Groups"; +import { GroupsRoute, GroupsWithIdRoute } from "./routes/Groups"; import { GroupsSearchRoute } from "./routes/GroupsSearch"; -const routes: RouteDef[] = [GroupsSearchRoute, GroupsRoute]; +const routes: RouteDef[] = [GroupsSearchRoute, GroupsRoute, GroupsWithIdRoute]; export default routes; diff --git a/src/groups/routes/Groups.tsx b/src/groups/routes/Groups.tsx index 9ab464b672..37a73f71d3 100644 --- a/src/groups/routes/Groups.tsx +++ b/src/groups/routes/Groups.tsx @@ -1,20 +1,28 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type GroupsParams = { realm: string; id?: string }; export const GroupsRoute: RouteDef = { - path: "/:realm/groups/:id?", + path: "/:realm/groups", component: lazy(() => import("../GroupsSection")), access: "query-groups", matchOptions: { exact: false, }, - legacy: true, }; -export const toGroups = (params: GroupsParams): Partial => ({ - pathname: generatePath(GroupsRoute.path, params), -}); +export const GroupsWithIdRoute: RouteDef = { + ...GroupsRoute, + path: "/:realm/groups/:id", +}; + +export const toGroups = (params: GroupsParams): Partial => { + const path = params.id ? GroupsWithIdRoute.path : GroupsRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/realm-roles/routes.ts b/src/realm-roles/routes.ts index 89ff196c1a..3970fa0910 100644 --- a/src/realm-roles/routes.ts +++ b/src/realm-roles/routes.ts @@ -1,16 +1,18 @@ import type { RouteDef } from "../route-config"; import { AddRoleRoute } from "./routes/AddRole"; import { AddRoleToClientRoute } from "./routes/AddRoleToClient"; -import { ClientRoleRoute } from "./routes/ClientRole"; -import { RealmRoleRoute } from "./routes/RealmRole"; +import { ClientRoleRoute, ClientRoleRouteWithTab } from "./routes/ClientRole"; +import { RealmRoleRoute, RealmRoleRouteWithTab } from "./routes/RealmRole"; import { RealmRolesRoute } from "./routes/RealmRoles"; const routes: RouteDef[] = [ AddRoleToClientRoute, ClientRoleRoute, + ClientRoleRouteWithTab, RealmRolesRoute, AddRoleRoute, RealmRoleRoute, + RealmRoleRouteWithTab, ]; export default routes; diff --git a/src/realm-roles/routes/ClientRole.ts b/src/realm-roles/routes/ClientRole.ts index f8c211ffa6..b2861d94a4 100644 --- a/src/realm-roles/routes/ClientRole.ts +++ b/src/realm-roles/routes/ClientRole.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type ClientRoleTab = @@ -17,13 +17,21 @@ export type ClientRoleParams = { }; export const ClientRoleRoute: RouteDef = { - path: "/:realm/clients/:clientId/roles/:id/:tab?", + path: "/:realm/clients/:clientId/roles/:id", component: lazy(() => import("../RealmRoleTabs")), breadcrumb: (t) => t("roles:roleDetails"), access: "view-realm", - legacy: true, }; -export const toClientRole = (params: ClientRoleParams): Partial => ({ - pathname: generatePath(ClientRoleRoute.path, params), -}); +export const ClientRoleRouteWithTab: RouteDef = { + ...ClientRoleRoute, + path: "/:realm/clients/:clientId/roles/:id/:tab", +}; + +export const toClientRole = (params: ClientRoleParams): Partial => { + const path = params.tab ? ClientRoleRouteWithTab.path : ClientRoleRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/realm-roles/routes/RealmRole.ts b/src/realm-roles/routes/RealmRole.ts index f986fb5174..c81dc3b363 100644 --- a/src/realm-roles/routes/RealmRole.ts +++ b/src/realm-roles/routes/RealmRole.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type RealmRoleTab = @@ -16,13 +16,21 @@ export type RealmRoleParams = { }; export const RealmRoleRoute: RouteDef = { - path: "/:realm/roles/:id/:tab?", + path: "/:realm/roles/:id", component: lazy(() => import("../RealmRoleTabs")), breadcrumb: (t) => t("roles:roleDetails"), access: ["view-realm", "view-users"], - legacy: true, }; -export const toRealmRole = (params: RealmRoleParams): Partial => ({ - pathname: generatePath(RealmRoleRoute.path, params), -}); +export const RealmRoleRouteWithTab: RouteDef = { + ...RealmRoleRoute, + path: "/:realm/roles/:id/:tab", +}; + +export const toRealmRole = (params: RealmRoleParams): Partial => { + const path = params.tab ? RealmRoleRouteWithTab.path : RealmRoleRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/realm-settings/routes.ts b/src/realm-settings/routes.ts index 6343049300..e3e3cf2323 100644 --- a/src/realm-settings/routes.ts +++ b/src/realm-settings/routes.ts @@ -1,6 +1,9 @@ import type { RouteDef } from "../route-config"; import { KeyProviderFormRoute } from "./routes/KeyProvider"; -import { RealmSettingsRoute } from "./routes/RealmSettings"; +import { + RealmSettingsRoute, + RealmSettingsRouteWithTab, +} from "./routes/RealmSettings"; import { ClientPoliciesRoute } from "./routes/ClientPolicies"; import { AddClientProfileRoute } from "./routes/AddClientProfile"; import { ClientProfileRoute } from "./routes/ClientProfile"; @@ -8,8 +11,14 @@ import { AddExecutorRoute } from "./routes/AddExecutor"; import { ExecutorRoute } from "./routes/Executor"; import { AddClientPolicyRoute } from "./routes/AddClientPolicy"; import { EditClientPolicyRoute } from "./routes/EditClientPolicy"; -import { NewClientPolicyConditionRoute } from "./routes/AddCondition"; -import { EditClientPolicyConditionRoute } from "./routes/EditCondition"; +import { + NewClientPolicyConditionRoute, + NewClientPolicyConditionWithPolicyNameRoute, +} from "./routes/AddCondition"; +import { + EditClientPolicyConditionRoute, + EditClientPolicyConditionWithPolicyNameRoute, +} from "./routes/EditCondition"; import { UserProfileRoute } from "./routes/UserProfile"; import { AddAttributeRoute } from "./routes/AddAttribute"; import { KeysRoute } from "./routes/KeysTab"; @@ -19,6 +28,7 @@ import { EditAttributesGroupRoute } from "./routes/EditAttributesGroup"; const routes: RouteDef[] = [ RealmSettingsRoute, + RealmSettingsRouteWithTab, KeysRoute, KeyProviderFormRoute, ClientPoliciesRoute, @@ -29,7 +39,9 @@ const routes: RouteDef[] = [ AddClientPolicyRoute, EditClientPolicyRoute, NewClientPolicyConditionRoute, + NewClientPolicyConditionWithPolicyNameRoute, EditClientPolicyConditionRoute, + EditClientPolicyConditionWithPolicyNameRoute, UserProfileRoute, AddAttributeRoute, AttributeRoute, diff --git a/src/realm-settings/routes/AddCondition.ts b/src/realm-settings/routes/AddCondition.ts index 36b918d618..083e30dc06 100644 --- a/src/realm-settings/routes/AddCondition.ts +++ b/src/realm-settings/routes/AddCondition.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type NewClientPolicyConditionParams = { @@ -9,15 +9,25 @@ export type NewClientPolicyConditionParams = { }; export const NewClientPolicyConditionRoute: RouteDef = { - path: "/:realm/realm-settings/client-policies/:policyName?/edit-policy/create-condition", + path: "/:realm/realm-settings/client-policies", component: lazy(() => import("../NewClientPolicyCondition")), breadcrumb: (t) => t("realm-settings:addCondition"), access: "manage-clients", - legacy: true, +}; + +export const NewClientPolicyConditionWithPolicyNameRoute: RouteDef = { + ...NewClientPolicyConditionRoute, + path: "/:realm/realm-settings/client-policies/:policyName/edit-policy/create-condition", }; export const toNewClientPolicyCondition = ( params: NewClientPolicyConditionParams -): Partial => ({ - pathname: generatePath(NewClientPolicyConditionRoute.path, params), -}); +): Partial => { + const path = params.policyName + ? NewClientPolicyConditionWithPolicyNameRoute.path + : NewClientPolicyConditionRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/realm-settings/routes/EditCondition.ts b/src/realm-settings/routes/EditCondition.ts index a1ca4c967f..5731203a69 100644 --- a/src/realm-settings/routes/EditCondition.ts +++ b/src/realm-settings/routes/EditCondition.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type EditClientPolicyConditionParams = { @@ -10,15 +10,25 @@ export type EditClientPolicyConditionParams = { }; export const EditClientPolicyConditionRoute: RouteDef = { - path: "/:realm/realm-settings/client-policies/:policyName?/edit-policy/:conditionName/edit-condition", + path: "/:realm/realm-settings/client-policies", component: lazy(() => import("../NewClientPolicyCondition")), breadcrumb: (t) => t("realm-settings:editCondition"), access: "manage-clients", - legacy: true, +}; + +export const EditClientPolicyConditionWithPolicyNameRoute: RouteDef = { + ...EditClientPolicyConditionRoute, + path: "/:realm/realm-settings/client-policies/:policyName/edit-policy/:conditionName/edit-condition", }; export const toEditClientPolicyCondition = ( params: EditClientPolicyConditionParams -): Partial => ({ - pathname: generatePath(EditClientPolicyConditionRoute.path, params), -}); +): Partial => { + const path = params.policyName + ? EditClientPolicyConditionWithPolicyNameRoute.path + : EditClientPolicyConditionRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/realm-settings/routes/RealmSettings.ts b/src/realm-settings/routes/RealmSettings.ts index 807eed1423..8b19495d40 100644 --- a/src/realm-settings/routes/RealmSettings.ts +++ b/src/realm-settings/routes/RealmSettings.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; export type RealmSettingsTab = @@ -24,15 +24,23 @@ export type RealmSettingsParams = { }; export const RealmSettingsRoute: RouteDef = { - path: "/:realm/realm-settings/:tab?", + path: "/:realm/realm-settings", component: lazy(() => import("../RealmSettingsSection")), breadcrumb: (t) => t("realmSettings"), access: "view-realm", - legacy: true, }; -export const toRealmSettings = ( - params: RealmSettingsParams -): Partial => ({ - pathname: generatePath(RealmSettingsRoute.path, params), -}); +export const RealmSettingsRouteWithTab: RouteDef = { + ...RealmSettingsRoute, + path: "/:realm/realm-settings/:tab", +}; + +export const toRealmSettings = (params: RealmSettingsParams): Partial => { + const path = params.tab + ? RealmSettingsRouteWithTab.path + : RealmSettingsRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/route-config.ts b/src/route-config.ts index c99b33b018..82b31075e6 100644 --- a/src/route-config.ts +++ b/src/route-config.ts @@ -23,7 +23,6 @@ export type RouteDef = { breadcrumb?: (t: TFunction) => string | ComponentType; access: AccessType | AccessType[]; matchOptions?: MatchOptions; - legacy?: boolean; }; const NotFoundRoute: RouteDef = { diff --git a/src/user-federation/UserFederationLdapSettings.tsx b/src/user-federation/UserFederationLdapSettings.tsx index 1c6f775548..ad48670d48 100644 --- a/src/user-federation/UserFederationLdapSettings.tsx +++ b/src/user-federation/UserFederationLdapSettings.tsx @@ -24,14 +24,18 @@ import { FormProvider, useForm, useFormContext } from "react-hook-form"; import { useAdminClient, useFetch } from "../context/auth/AdminClient"; import { useAlerts } from "../components/alert/Alerts"; import { useTranslation } from "react-i18next"; -import { useParams } from "react-router-dom"; +import { useHistory, useParams } from "react-router-dom"; import { useNavigate } from "react-router-dom-v5-compat"; import { ScrollForm } from "../components/scroll-form/ScrollForm"; -import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs"; import { LdapMapperList } from "./ldap/mappers/LdapMapperList"; import { toUserFederation } from "./routes/UserFederation"; import { ExtendedHeader } from "./shared/ExtendedHeader"; +import { + routableTab, + RoutableTabs, +} from "../components/routable-tabs/RoutableTabs"; +import { toUserFederationLdap } from "./routes/UserFederationLdap"; type ldapComponentRepresentation = ComponentRepresentation & { config?: { @@ -110,6 +114,7 @@ export default function UserFederationLdapSettings() { const { t } = useTranslation("user-federation"); const form = useForm({ mode: "onChange" }); const navigate = useNavigate(); + const history = useHistory(); const { adminClient } = useAdminClient(); const { realm } = useRealm(); @@ -189,11 +194,21 @@ export default function UserFederationLdapSettings() { /> {id ? ( - + {t("common:settings")}} + {...routableTab({ + to: toUserFederationLdap({ realm, id, tab: "settings" }), + history, + })} > @@ -201,13 +216,16 @@ export default function UserFederationLdapSettings() { {t("common:mappers")}} data-testid="ldap-mappers-tab" + {...routableTab({ + to: toUserFederationLdap({ realm, id, tab: "mappers" }), + history, + })} > - + ) : ( diff --git a/src/user-federation/routes.ts b/src/user-federation/routes.ts index df180b7bf6..ea8ab2a36e 100644 --- a/src/user-federation/routes.ts +++ b/src/user-federation/routes.ts @@ -7,7 +7,10 @@ import { } from "./routes/NewProvider"; import { UserFederationRoute } from "./routes/UserFederation"; import { UserFederationKerberosRoute } from "./routes/UserFederationKerberos"; -import { UserFederationLdapRoute } from "./routes/UserFederationLdap"; +import { + UserFederationLdapRoute, + UserFederationLdapWithTabRoute, +} from "./routes/UserFederationLdap"; import { UserFederationLdapMapperRoute } from "./routes/UserFederationLdapMapper"; import { UserFederationsKerberosRoute } from "./routes/UserFederationsKerberos"; import { UserFederationsLdapRoute } from "./routes/UserFederationsLdap"; @@ -20,6 +23,7 @@ const routes: RouteDef[] = [ UserFederationsLdapRoute, NewLdapUserFederationRoute, UserFederationLdapRoute, + UserFederationLdapWithTabRoute, UserFederationLdapMapperRoute, CustomProviderRoute, CustomEditProviderRoute, diff --git a/src/user-federation/routes/UserFederationLdap.ts b/src/user-federation/routes/UserFederationLdap.ts index 111f18b478..c57b69fe03 100644 --- a/src/user-federation/routes/UserFederationLdap.ts +++ b/src/user-federation/routes/UserFederationLdap.ts @@ -1,6 +1,6 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; import type { Path } from "react-router-dom-v5-compat"; +import { generatePath } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; type UserFederationLdapTab = "settings" | "mappers"; @@ -12,15 +12,25 @@ export type UserFederationLdapParams = { }; export const UserFederationLdapRoute: RouteDef = { - path: "/:realm/user-federation/ldap/:id/:tab?", + path: "/:realm/user-federation/ldap/:id", component: lazy(() => import("../UserFederationLdapSettings")), breadcrumb: (t) => t("common:settings"), access: "view-realm", - legacy: true, +}; + +export const UserFederationLdapWithTabRoute: RouteDef = { + ...UserFederationLdapRoute, + path: "/:realm/user-federation/ldap/:id/:tab", }; export const toUserFederationLdap = ( params: UserFederationLdapParams -): Partial => ({ - pathname: generatePath(UserFederationLdapRoute.path, params), -}); +): Partial => { + const path = params.tab + ? UserFederationLdapWithTabRoute.path + : UserFederationLdapRoute.path; + + return { + pathname: generatePath(path, params), + }; +}; diff --git a/src/user/routes.ts b/src/user/routes.ts index 452e4a13f7..6caf21adbd 100644 --- a/src/user/routes.ts +++ b/src/user/routes.ts @@ -1,8 +1,13 @@ import type { RouteDef } from "../route-config"; import { AddUserRoute } from "./routes/AddUser"; import { UserRoute } from "./routes/User"; -import { UsersRoute } from "./routes/Users"; +import { UsersRoute, UsersRouteWithTab } from "./routes/Users"; -const routes: RouteDef[] = [AddUserRoute, UsersRoute, UserRoute]; +const routes: RouteDef[] = [ + AddUserRoute, + UsersRoute, + UsersRouteWithTab, + UserRoute, +]; export default routes; diff --git a/src/user/routes/Users.ts b/src/user/routes/Users.ts index 6241af1ccb..22e3721194 100644 --- a/src/user/routes/Users.ts +++ b/src/user/routes/Users.ts @@ -1,5 +1,5 @@ import { lazy } from "react"; -import { generatePath } from "react-router-dom"; +import { generatePath } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat"; import type { RouteDef } from "../../route-config"; @@ -8,13 +8,21 @@ export type UserTab = "list" | "permissions"; export type UsersParams = { realm: string; tab?: UserTab }; export const UsersRoute: RouteDef = { - path: "/:realm/users/:tab?", + path: "/:realm/users", component: lazy(() => import("../UsersSection")), breadcrumb: (t) => t("users:title"), access: "query-users", - legacy: true, }; -export const toUsers = (params: UsersParams): Partial => ({ - pathname: generatePath(UsersRoute.path, params), -}); +export const UsersRouteWithTab: RouteDef = { + ...UsersRoute, + path: "/:realm/users/:tab", +}; + +export const toUsers = (params: UsersParams): Partial => { + const path = params.tab ? UsersRouteWithTab.path : UsersRoute.path; + + return { + pathname: generatePath(path, params), + }; +};