Move all legacy routes to new React Router API (#3155)

This commit is contained in:
Jon Koops 2022-08-22 16:29:35 +02:00 committed by GitHub
parent b4204f4778
commit ce140245e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 403 additions and 162 deletions

View file

@ -1,10 +1,6 @@
import { FunctionComponent, Suspense } from "react"; import { FunctionComponent, Suspense } from "react";
import { Page } from "@patternfly/react-core"; import { Page } from "@patternfly/react-core";
import { import { HashRouter as Router, Switch } from "react-router-dom";
HashRouter as Router,
Route as LegacyRoute,
Switch,
} from "react-router-dom";
import { CompatRouter, CompatRoute } from "react-router-dom-v5-compat"; import { CompatRouter, CompatRoute } from "react-router-dom-v5-compat";
import { ErrorBoundary } from "react-error-boundary"; import { ErrorBoundary } from "react-error-boundary";
import type Keycloak from "keycloak-js"; import type Keycloak from "keycloak-js";
@ -101,19 +97,15 @@ export const App = ({ keycloak, adminClient }: AdminClientProps) => {
> >
<ServerInfoProvider> <ServerInfoProvider>
<Switch> <Switch>
{routes.map((route, i) => { {routes.map((route, i) => (
const Route = route.legacy ? LegacyRoute : CompatRoute; <CompatRoute
key={i}
return ( path={route.path}
<Route exact={route.matchOptions?.exact ?? true}
key={i} >
path={route.path} <SecuredRoute route={route} />
exact={route.matchOptions?.exact ?? true} </CompatRoute>
> ))}
<SecuredRoute route={route} />
</Route>
);
})}
</Switch> </Switch>
</ServerInfoProvider> </ServerInfoProvider>
</ErrorBoundary> </ErrorBoundary>

View file

@ -1,8 +1,17 @@
import type { RouteDef } from "../route-config"; import type { RouteDef } from "../route-config";
import { AuthenticationRoute } from "./routes/Authentication"; import {
AuthenticationRoute,
AuthenticationRouteWithTab,
} from "./routes/Authentication";
import { CreateFlowRoute } from "./routes/CreateFlow"; 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; export default routes;

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type AuthenticationTab = "flows" | "required-actions" | "policies"; 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 type AuthenticationParams = { realm: string; tab?: AuthenticationTab };
export const AuthenticationRoute: RouteDef = { export const AuthenticationRoute: RouteDef = {
path: "/:realm/authentication/:tab?", path: "/:realm/authentication",
component: lazy(() => import("../AuthenticationSection")), component: lazy(() => import("../AuthenticationSection")),
breadcrumb: (t) => t("authentication"), breadcrumb: (t) => t("authentication"),
access: ["view-realm", "view-identity-providers", "view-clients"], access: ["view-realm", "view-identity-providers", "view-clients"],
legacy: true, };
export const AuthenticationRouteWithTab: RouteDef = {
...AuthenticationRoute,
path: "/:realm/authentication/:tab",
}; };
export const toAuthentication = ( export const toAuthentication = (
params: AuthenticationParams params: AuthenticationParams
): Partial<Path> => ({ ): Partial<Path> => {
pathname: generatePath(AuthenticationRoute.path, params), const path = params.tab
}); ? AuthenticationRouteWithTab.path
: AuthenticationRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type FlowParams = { export type FlowParams = {
@ -11,13 +11,21 @@ export type FlowParams = {
}; };
export const FlowRoute: RouteDef = { export const FlowRoute: RouteDef = {
path: "/:realm/authentication/:id/:usedBy/:builtIn?", path: "/:realm/authentication/:id/:usedBy",
component: lazy(() => import("../FlowDetails")), component: lazy(() => import("../FlowDetails")),
breadcrumb: (t) => t("authentication:flowDetails"), breadcrumb: (t) => t("authentication:flowDetails"),
access: "view-authorization", access: "view-authorization",
legacy: true,
}; };
export const toFlow = (params: FlowParams): Partial<Path> => ({ export const FlowWithBuiltInRoute: RouteDef = {
pathname: generatePath(FlowRoute.path, params), ...FlowRoute,
}); path: "/:realm/authentication/:id/:usedBy/:builtIn",
};
export const toFlow = (params: FlowParams): Partial<Path> => {
const path = params.builtIn ? FlowWithBuiltInRoute.path : FlowRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,5 +1,8 @@
import type { RouteDef } from "../route-config"; import type { RouteDef } from "../route-config";
import { ClientScopeRoute } from "./routes/ClientScope"; import {
ClientScopeRoute,
ClientScopeWithTypeRoute,
} from "./routes/ClientScope";
import { ClientScopesRoute } from "./routes/ClientScopes"; import { ClientScopesRoute } from "./routes/ClientScopes";
import { MapperRoute } from "./routes/Mapper"; import { MapperRoute } from "./routes/Mapper";
import { NewClientScopeRoute } from "./routes/NewClientScope"; import { NewClientScopeRoute } from "./routes/NewClientScope";
@ -8,6 +11,7 @@ const routes: RouteDef[] = [
NewClientScopeRoute, NewClientScopeRoute,
MapperRoute, MapperRoute,
ClientScopeRoute, ClientScopeRoute,
ClientScopeWithTypeRoute,
ClientScopesRoute, ClientScopesRoute,
]; ];

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type ClientScopeTab = "settings" | "mappers" | "scope"; export type ClientScopeTab = "settings" | "mappers" | "scope";
@ -13,13 +13,23 @@ export type ClientScopeParams = {
}; };
export const ClientScopeRoute: RouteDef = { export const ClientScopeRoute: RouteDef = {
path: "/:realm/client-scopes/:id/:tab/:type?", path: "/:realm/client-scopes/:id/:tab",
component: lazy(() => import("../form/ClientScopeForm")), component: lazy(() => import("../form/ClientScopeForm")),
breadcrumb: (t) => t("client-scopes:clientScopeDetails"), breadcrumb: (t) => t("client-scopes:clientScopeDetails"),
access: "view-clients", access: "view-clients",
legacy: true,
}; };
export const toClientScope = (params: ClientScopeParams): Partial<Path> => ({ export const ClientScopeWithTypeRoute: RouteDef = {
pathname: generatePath(ClientScopeRoute.path, params), ...ClientScopeRoute,
}); path: "/:realm/client-scopes/:id/:tab/:type",
};
export const toClientScope = (params: ClientScopeParams): Partial<Path> => {
const path = params.type
? ClientScopeWithTypeRoute.path
: ClientScopeRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,39 +1,56 @@
import type { RouteDef } from "../route-config"; import type { RouteDef } from "../route-config";
import { AddClientRoute } from "./routes/AddClient"; import { AddClientRoute } from "./routes/AddClient";
import { ClientRoute } from "./routes/Client"; import { ClientRoute } from "./routes/Client";
import { ClientsRoute } from "./routes/Clients"; import { ClientsRoute, ClientsRouteWithTab } from "./routes/Clients";
import { CreateInitialAccessTokenRoute } from "./routes/CreateInitialAccessToken"; import { CreateInitialAccessTokenRoute } from "./routes/CreateInitialAccessToken";
import { ImportClientRoute } from "./routes/ImportClient"; import { ImportClientRoute } from "./routes/ImportClient";
import { MapperRoute } from "./routes/Mapper"; import { MapperRoute } from "./routes/Mapper";
import { ClientScopesRoute } from "./routes/ClientScopeTab"; import { ClientScopesRoute } from "./routes/ClientScopeTab";
import { AuthorizationRoute } from "./routes/AuthenticationTab"; import { AuthorizationRoute } from "./routes/AuthenticationTab";
import { NewResourceRoute } from "./routes/NewResource"; import { NewResourceRoute } from "./routes/NewResource";
import { ResourceDetailsRoute } from "./routes/Resource"; import {
ResourceDetailsRoute,
ResourceDetailsWithResourceIdRoute,
} from "./routes/Resource";
import { NewScopeRoute } from "./routes/NewScope"; import { NewScopeRoute } from "./routes/NewScope";
import { ScopeDetailsRoute } from "./routes/Scope"; import {
ScopeDetailsRoute,
ScopeDetailsWithScopeIdRoute,
} from "./routes/Scope";
import { NewPolicyRoute } from "./routes/NewPolicy"; import { NewPolicyRoute } from "./routes/NewPolicy";
import { PolicyDetailsRoute } from "./routes/PolicyDetails"; import { PolicyDetailsRoute } from "./routes/PolicyDetails";
import { NewPermissionRoute } from "./routes/NewPermission"; import {
NewPermissionRoute,
NewPermissionWithSelectedIdRoute,
} from "./routes/NewPermission";
import { PermissionDetailsRoute } from "./routes/PermissionDetails"; import { PermissionDetailsRoute } from "./routes/PermissionDetails";
import { DedicatedScopeDetailsRoute } from "./routes/DedicatedScopeDetails"; import {
DedicatedScopeDetailsRoute,
DedicatedScopeDetailsWithTabRoute,
} from "./routes/DedicatedScopeDetails";
const routes: RouteDef[] = [ const routes: RouteDef[] = [
AddClientRoute, AddClientRoute,
ImportClientRoute, ImportClientRoute,
ClientsRoute, ClientsRoute,
ClientsRouteWithTab,
CreateInitialAccessTokenRoute, CreateInitialAccessTokenRoute,
ClientRoute, ClientRoute,
MapperRoute, MapperRoute,
DedicatedScopeDetailsRoute, DedicatedScopeDetailsRoute,
DedicatedScopeDetailsWithTabRoute,
ClientScopesRoute, ClientScopesRoute,
AuthorizationRoute, AuthorizationRoute,
NewResourceRoute, NewResourceRoute,
ResourceDetailsRoute, ResourceDetailsRoute,
ResourceDetailsWithResourceIdRoute,
NewScopeRoute, NewScopeRoute,
ScopeDetailsRoute, ScopeDetailsRoute,
ScopeDetailsWithScopeIdRoute,
NewPolicyRoute, NewPolicyRoute,
PolicyDetailsRoute, PolicyDetailsRoute,
NewPermissionRoute, NewPermissionRoute,
NewPermissionWithSelectedIdRoute,
PermissionDetailsRoute, PermissionDetailsRoute,
]; ];

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type ClientsTab = "list" | "initial-access-token"; export type ClientsTab = "list" | "initial-access-token";
@ -11,13 +11,21 @@ export type ClientsParams = {
}; };
export const ClientsRoute: RouteDef = { export const ClientsRoute: RouteDef = {
path: "/:realm/clients/:tab?", path: "/:realm/clients",
component: lazy(() => import("../ClientsSection")), component: lazy(() => import("../ClientsSection")),
breadcrumb: (t) => t("clients:clientList"), breadcrumb: (t) => t("clients:clientList"),
access: "query-clients", access: "query-clients",
legacy: true,
}; };
export const toClients = (params: ClientsParams): Partial<Path> => ({ export const ClientsRouteWithTab: RouteDef = {
pathname: generatePath(ClientsRoute.path, params), ...ClientsRoute,
}); path: "/:realm/clients/:tab",
};
export const toClients = (params: ClientsParams): Partial<Path> => {
const path = params.tab ? ClientsRouteWithTab.path : ClientsRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type DedicatedScopeTab = "mappers" | "scope"; export type DedicatedScopeTab = "mappers" | "scope";
@ -12,15 +12,25 @@ export type DedicatedScopeDetailsParams = {
}; };
export const DedicatedScopeDetailsRoute: RouteDef = { export const DedicatedScopeDetailsRoute: RouteDef = {
path: "/:realm/clients/:clientId/clientScopes/dedicated/:tab?", path: "/:realm/clients/:clientId/clientScopes/dedicated",
component: lazy(() => import("../scopes/DedicatedScopes")), component: lazy(() => import("../scopes/DedicatedScopes")),
breadcrumb: (t) => t("clients:dedicatedScopes"), breadcrumb: (t) => t("clients:dedicatedScopes"),
access: "view-clients", access: "view-clients",
legacy: true, };
export const DedicatedScopeDetailsWithTabRoute: RouteDef = {
...DedicatedScopeDetailsRoute,
path: "/:realm/clients/:clientId/clientScopes/dedicated/:tab",
}; };
export const toDedicatedScope = ( export const toDedicatedScope = (
params: DedicatedScopeDetailsParams params: DedicatedScopeDetailsParams
): Partial<Path> => ({ ): Partial<Path> => {
pathname: generatePath(DedicatedScopeDetailsRoute.path, params), const path = params.tab
}); ? DedicatedScopeDetailsWithTabRoute.path
: DedicatedScopeDetailsRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type PermissionType = "resource" | "scope"; export type PermissionType = "resource" | "scope";
@ -13,15 +13,23 @@ export type NewPermissionParams = {
}; };
export const NewPermissionRoute: RouteDef = { 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")), component: lazy(() => import("../authorization/PermissionDetails")),
breadcrumb: (t) => t("clients:createPermission"), breadcrumb: (t) => t("clients:createPermission"),
access: "view-clients", access: "view-clients",
legacy: true,
}; };
export const toNewPermission = ( export const NewPermissionWithSelectedIdRoute: RouteDef = {
params: NewPermissionParams ...NewPermissionRoute,
): Partial<Path> => ({ path: "/:realm/clients/:id/authorization/permission/new/:permissionType/:selectedId?",
pathname: generatePath(NewPermissionRoute.path, params), };
});
export const toNewPermission = (params: NewPermissionParams): Partial<Path> => {
const path = params.selectedId
? NewPermissionWithSelectedIdRoute.path
: NewPermissionRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type ResourceDetailsParams = { export type ResourceDetailsParams = {
@ -10,15 +10,25 @@ export type ResourceDetailsParams = {
}; };
export const ResourceDetailsRoute: RouteDef = { export const ResourceDetailsRoute: RouteDef = {
path: "/:realm/clients/:id/authorization/resource/:resourceId?", path: "/:realm/clients/:id/authorization/resource",
component: lazy(() => import("../authorization/ResourceDetails")), component: lazy(() => import("../authorization/ResourceDetails")),
breadcrumb: (t) => t("clients:createResource"), breadcrumb: (t) => t("clients:createResource"),
access: "view-clients", access: "view-clients",
legacy: true, };
export const ResourceDetailsWithResourceIdRoute: RouteDef = {
...ResourceDetailsRoute,
path: "/:realm/clients/:id/authorization/resource/:resourceId",
}; };
export const toResourceDetails = ( export const toResourceDetails = (
params: ResourceDetailsParams params: ResourceDetailsParams
): Partial<Path> => ({ ): Partial<Path> => {
pathname: generatePath(ResourceDetailsRoute.path, params), const path = params.resourceId
}); ? ResourceDetailsWithResourceIdRoute.path
: ResourceDetailsRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type ScopeDetailsParams = { export type ScopeDetailsParams = {
@ -10,13 +10,23 @@ export type ScopeDetailsParams = {
}; };
export const ScopeDetailsRoute: RouteDef = { export const ScopeDetailsRoute: RouteDef = {
path: "/:realm/clients/:id/authorization/scope/:scopeId?", path: "/:realm/clients/:id/authorization/scope",
component: lazy(() => import("../authorization/ScopeDetails")), component: lazy(() => import("../authorization/ScopeDetails")),
breadcrumb: (t) => t("clients:createAuthorizationScope"), breadcrumb: (t) => t("clients:createAuthorizationScope"),
access: "manage-clients", access: "manage-clients",
legacy: true,
}; };
export const toScopeDetails = (params: ScopeDetailsParams): Partial<Path> => ({ export const ScopeDetailsWithScopeIdRoute: RouteDef = {
pathname: generatePath(ScopeDetailsRoute.path, params), ...ScopeDetailsRoute,
}); path: "/:realm/clients/:id/authorization/scope/:scopeId",
};
export const toScopeDetails = (params: ScopeDetailsParams): Partial<Path> => {
const path = params.scopeId
? ScopeDetailsWithScopeIdRoute.path
: ScopeDetailsRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -3,7 +3,7 @@ import { useRouteMatch } from "react-router-dom";
import { RecentUsed } from "../../components/realm-selector/recent-used"; import { RecentUsed } from "../../components/realm-selector/recent-used";
import { import {
DashboardParams, DashboardParams,
DashboardRoute, DashboardRouteWithRealm,
} from "../../dashboard/routes/Dashboard"; } from "../../dashboard/routes/Dashboard";
import environment from "../../environment"; import environment from "../../environment";
import { createNamedContext } from "../../utils/createNamedContext"; import { createNamedContext } from "../../utils/createNamedContext";
@ -22,7 +22,9 @@ export const RealmContext = createNamedContext<RealmContextType | undefined>(
export const RealmContextProvider: FunctionComponent = ({ children }) => { export const RealmContextProvider: FunctionComponent = ({ children }) => {
const { adminClient } = useAdminClient(); const { adminClient } = useAdminClient();
const recentUsed = useMemo(() => new RecentUsed(), []); const recentUsed = useMemo(() => new RecentUsed(), []);
const routeMatch = useRouteMatch<DashboardParams>(DashboardRoute.path); const routeMatch = useRouteMatch<DashboardParams>(
DashboardRouteWithRealm.path
);
const realmParam = routeMatch?.params.realm; const realmParam = routeMatch?.params.realm;
const realm = useMemo( const realm = useMemo(
() => realmParam ?? environment.loginRealm, () => realmParam ?? environment.loginRealm,

View file

@ -1,6 +1,14 @@
import type { RouteDef } from "../route-config"; 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; export default routes;

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type DashboardTab = "info" | "providers"; export type DashboardTab = "info" | "providers";
@ -8,13 +8,30 @@ export type DashboardTab = "info" | "providers";
export type DashboardParams = { realm?: string; tab?: DashboardTab }; export type DashboardParams = { realm?: string; tab?: DashboardTab };
export const DashboardRoute: RouteDef = { export const DashboardRoute: RouteDef = {
path: "/:realm?/:tab?", path: "/",
component: lazy(() => import("../Dashboard")), component: lazy(() => import("../Dashboard")),
breadcrumb: (t) => t("common:home"), breadcrumb: (t) => t("common:home"),
access: "anyone", access: "anyone",
legacy: true,
}; };
export const toDashboard = (params: DashboardParams): Partial<Path> => ({ export const DashboardRouteWithRealm: RouteDef = {
pathname: generatePath(DashboardRoute.path, params), ...DashboardRoute,
}); path: "/:realm",
};
export const DashboardRouteWithTab: RouteDef = {
...DashboardRoute,
path: "/:realm/:tab",
};
export const toDashboard = (params: DashboardParams): Partial<Path> => {
const pathname = params.realm
? params.tab
? DashboardRouteWithTab.path
: DashboardRouteWithRealm.path
: DashboardRoute.path;
return {
pathname: generatePath(pathname, params),
};
};

View file

@ -1,6 +1,6 @@
import type { RouteDef } from "../route-config"; 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; export default routes;

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type EventsTab = "user-events" | "admin-events"; export type EventsTab = "user-events" | "admin-events";
@ -11,13 +11,21 @@ export type EventsParams = {
}; };
export const EventsRoute: RouteDef = { export const EventsRoute: RouteDef = {
path: "/:realm/events/:tab?", path: "/:realm/events",
component: lazy(() => import("../EventsSection")), component: lazy(() => import("../EventsSection")),
breadcrumb: (t) => t("events:title"), breadcrumb: (t) => t("events:title"),
access: "view-events", access: "view-events",
legacy: true,
}; };
export const toEvents = (params: EventsParams): Partial<Path> => ({ export const EventsRouteWithTab: RouteDef = {
pathname: generatePath(EventsRoute.path, params), ...EventsRoute,
}); path: "/:realm/events/:tab",
};
export const toEvents = (params: EventsParams): Partial<Path> => {
const path = params.tab ? EventsRouteWithTab.path : EventsRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,7 +1,7 @@
import type { RouteDef } from "../route-config"; import type { RouteDef } from "../route-config";
import { GroupsRoute } from "./routes/Groups"; import { GroupsRoute, GroupsWithIdRoute } from "./routes/Groups";
import { GroupsSearchRoute } from "./routes/GroupsSearch"; import { GroupsSearchRoute } from "./routes/GroupsSearch";
const routes: RouteDef[] = [GroupsSearchRoute, GroupsRoute]; const routes: RouteDef[] = [GroupsSearchRoute, GroupsRoute, GroupsWithIdRoute];
export default routes; export default routes;

View file

@ -1,20 +1,28 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type GroupsParams = { realm: string; id?: string }; export type GroupsParams = { realm: string; id?: string };
export const GroupsRoute: RouteDef = { export const GroupsRoute: RouteDef = {
path: "/:realm/groups/:id?", path: "/:realm/groups",
component: lazy(() => import("../GroupsSection")), component: lazy(() => import("../GroupsSection")),
access: "query-groups", access: "query-groups",
matchOptions: { matchOptions: {
exact: false, exact: false,
}, },
legacy: true,
}; };
export const toGroups = (params: GroupsParams): Partial<Path> => ({ export const GroupsWithIdRoute: RouteDef = {
pathname: generatePath(GroupsRoute.path, params), ...GroupsRoute,
}); path: "/:realm/groups/:id",
};
export const toGroups = (params: GroupsParams): Partial<Path> => {
const path = params.id ? GroupsWithIdRoute.path : GroupsRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,16 +1,18 @@
import type { RouteDef } from "../route-config"; import type { RouteDef } from "../route-config";
import { AddRoleRoute } from "./routes/AddRole"; import { AddRoleRoute } from "./routes/AddRole";
import { AddRoleToClientRoute } from "./routes/AddRoleToClient"; import { AddRoleToClientRoute } from "./routes/AddRoleToClient";
import { ClientRoleRoute } from "./routes/ClientRole"; import { ClientRoleRoute, ClientRoleRouteWithTab } from "./routes/ClientRole";
import { RealmRoleRoute } from "./routes/RealmRole"; import { RealmRoleRoute, RealmRoleRouteWithTab } from "./routes/RealmRole";
import { RealmRolesRoute } from "./routes/RealmRoles"; import { RealmRolesRoute } from "./routes/RealmRoles";
const routes: RouteDef[] = [ const routes: RouteDef[] = [
AddRoleToClientRoute, AddRoleToClientRoute,
ClientRoleRoute, ClientRoleRoute,
ClientRoleRouteWithTab,
RealmRolesRoute, RealmRolesRoute,
AddRoleRoute, AddRoleRoute,
RealmRoleRoute, RealmRoleRoute,
RealmRoleRouteWithTab,
]; ];
export default routes; export default routes;

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type ClientRoleTab = export type ClientRoleTab =
@ -17,13 +17,21 @@ export type ClientRoleParams = {
}; };
export const ClientRoleRoute: RouteDef = { export const ClientRoleRoute: RouteDef = {
path: "/:realm/clients/:clientId/roles/:id/:tab?", path: "/:realm/clients/:clientId/roles/:id",
component: lazy(() => import("../RealmRoleTabs")), component: lazy(() => import("../RealmRoleTabs")),
breadcrumb: (t) => t("roles:roleDetails"), breadcrumb: (t) => t("roles:roleDetails"),
access: "view-realm", access: "view-realm",
legacy: true,
}; };
export const toClientRole = (params: ClientRoleParams): Partial<Path> => ({ export const ClientRoleRouteWithTab: RouteDef = {
pathname: generatePath(ClientRoleRoute.path, params), ...ClientRoleRoute,
}); path: "/:realm/clients/:clientId/roles/:id/:tab",
};
export const toClientRole = (params: ClientRoleParams): Partial<Path> => {
const path = params.tab ? ClientRoleRouteWithTab.path : ClientRoleRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type RealmRoleTab = export type RealmRoleTab =
@ -16,13 +16,21 @@ export type RealmRoleParams = {
}; };
export const RealmRoleRoute: RouteDef = { export const RealmRoleRoute: RouteDef = {
path: "/:realm/roles/:id/:tab?", path: "/:realm/roles/:id",
component: lazy(() => import("../RealmRoleTabs")), component: lazy(() => import("../RealmRoleTabs")),
breadcrumb: (t) => t("roles:roleDetails"), breadcrumb: (t) => t("roles:roleDetails"),
access: ["view-realm", "view-users"], access: ["view-realm", "view-users"],
legacy: true,
}; };
export const toRealmRole = (params: RealmRoleParams): Partial<Path> => ({ export const RealmRoleRouteWithTab: RouteDef = {
pathname: generatePath(RealmRoleRoute.path, params), ...RealmRoleRoute,
}); path: "/:realm/roles/:id/:tab",
};
export const toRealmRole = (params: RealmRoleParams): Partial<Path> => {
const path = params.tab ? RealmRoleRouteWithTab.path : RealmRoleRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,6 +1,9 @@
import type { RouteDef } from "../route-config"; import type { RouteDef } from "../route-config";
import { KeyProviderFormRoute } from "./routes/KeyProvider"; import { KeyProviderFormRoute } from "./routes/KeyProvider";
import { RealmSettingsRoute } from "./routes/RealmSettings"; import {
RealmSettingsRoute,
RealmSettingsRouteWithTab,
} from "./routes/RealmSettings";
import { ClientPoliciesRoute } from "./routes/ClientPolicies"; import { ClientPoliciesRoute } from "./routes/ClientPolicies";
import { AddClientProfileRoute } from "./routes/AddClientProfile"; import { AddClientProfileRoute } from "./routes/AddClientProfile";
import { ClientProfileRoute } from "./routes/ClientProfile"; import { ClientProfileRoute } from "./routes/ClientProfile";
@ -8,8 +11,14 @@ import { AddExecutorRoute } from "./routes/AddExecutor";
import { ExecutorRoute } from "./routes/Executor"; import { ExecutorRoute } from "./routes/Executor";
import { AddClientPolicyRoute } from "./routes/AddClientPolicy"; import { AddClientPolicyRoute } from "./routes/AddClientPolicy";
import { EditClientPolicyRoute } from "./routes/EditClientPolicy"; import { EditClientPolicyRoute } from "./routes/EditClientPolicy";
import { NewClientPolicyConditionRoute } from "./routes/AddCondition"; import {
import { EditClientPolicyConditionRoute } from "./routes/EditCondition"; NewClientPolicyConditionRoute,
NewClientPolicyConditionWithPolicyNameRoute,
} from "./routes/AddCondition";
import {
EditClientPolicyConditionRoute,
EditClientPolicyConditionWithPolicyNameRoute,
} from "./routes/EditCondition";
import { UserProfileRoute } from "./routes/UserProfile"; import { UserProfileRoute } from "./routes/UserProfile";
import { AddAttributeRoute } from "./routes/AddAttribute"; import { AddAttributeRoute } from "./routes/AddAttribute";
import { KeysRoute } from "./routes/KeysTab"; import { KeysRoute } from "./routes/KeysTab";
@ -19,6 +28,7 @@ import { EditAttributesGroupRoute } from "./routes/EditAttributesGroup";
const routes: RouteDef[] = [ const routes: RouteDef[] = [
RealmSettingsRoute, RealmSettingsRoute,
RealmSettingsRouteWithTab,
KeysRoute, KeysRoute,
KeyProviderFormRoute, KeyProviderFormRoute,
ClientPoliciesRoute, ClientPoliciesRoute,
@ -29,7 +39,9 @@ const routes: RouteDef[] = [
AddClientPolicyRoute, AddClientPolicyRoute,
EditClientPolicyRoute, EditClientPolicyRoute,
NewClientPolicyConditionRoute, NewClientPolicyConditionRoute,
NewClientPolicyConditionWithPolicyNameRoute,
EditClientPolicyConditionRoute, EditClientPolicyConditionRoute,
EditClientPolicyConditionWithPolicyNameRoute,
UserProfileRoute, UserProfileRoute,
AddAttributeRoute, AddAttributeRoute,
AttributeRoute, AttributeRoute,

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type NewClientPolicyConditionParams = { export type NewClientPolicyConditionParams = {
@ -9,15 +9,25 @@ export type NewClientPolicyConditionParams = {
}; };
export const NewClientPolicyConditionRoute: RouteDef = { 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")), component: lazy(() => import("../NewClientPolicyCondition")),
breadcrumb: (t) => t("realm-settings:addCondition"), breadcrumb: (t) => t("realm-settings:addCondition"),
access: "manage-clients", access: "manage-clients",
legacy: true, };
export const NewClientPolicyConditionWithPolicyNameRoute: RouteDef = {
...NewClientPolicyConditionRoute,
path: "/:realm/realm-settings/client-policies/:policyName/edit-policy/create-condition",
}; };
export const toNewClientPolicyCondition = ( export const toNewClientPolicyCondition = (
params: NewClientPolicyConditionParams params: NewClientPolicyConditionParams
): Partial<Path> => ({ ): Partial<Path> => {
pathname: generatePath(NewClientPolicyConditionRoute.path, params), const path = params.policyName
}); ? NewClientPolicyConditionWithPolicyNameRoute.path
: NewClientPolicyConditionRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type EditClientPolicyConditionParams = { export type EditClientPolicyConditionParams = {
@ -10,15 +10,25 @@ export type EditClientPolicyConditionParams = {
}; };
export const EditClientPolicyConditionRoute: RouteDef = { 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")), component: lazy(() => import("../NewClientPolicyCondition")),
breadcrumb: (t) => t("realm-settings:editCondition"), breadcrumb: (t) => t("realm-settings:editCondition"),
access: "manage-clients", 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 = ( export const toEditClientPolicyCondition = (
params: EditClientPolicyConditionParams params: EditClientPolicyConditionParams
): Partial<Path> => ({ ): Partial<Path> => {
pathname: generatePath(EditClientPolicyConditionRoute.path, params), const path = params.policyName
}); ? EditClientPolicyConditionWithPolicyNameRoute.path
: EditClientPolicyConditionRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
export type RealmSettingsTab = export type RealmSettingsTab =
@ -24,15 +24,23 @@ export type RealmSettingsParams = {
}; };
export const RealmSettingsRoute: RouteDef = { export const RealmSettingsRoute: RouteDef = {
path: "/:realm/realm-settings/:tab?", path: "/:realm/realm-settings",
component: lazy(() => import("../RealmSettingsSection")), component: lazy(() => import("../RealmSettingsSection")),
breadcrumb: (t) => t("realmSettings"), breadcrumb: (t) => t("realmSettings"),
access: "view-realm", access: "view-realm",
legacy: true,
}; };
export const toRealmSettings = ( export const RealmSettingsRouteWithTab: RouteDef = {
params: RealmSettingsParams ...RealmSettingsRoute,
): Partial<Path> => ({ path: "/:realm/realm-settings/:tab",
pathname: generatePath(RealmSettingsRoute.path, params), };
});
export const toRealmSettings = (params: RealmSettingsParams): Partial<Path> => {
const path = params.tab
? RealmSettingsRouteWithTab.path
: RealmSettingsRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -23,7 +23,6 @@ export type RouteDef = {
breadcrumb?: (t: TFunction) => string | ComponentType<any>; breadcrumb?: (t: TFunction) => string | ComponentType<any>;
access: AccessType | AccessType[]; access: AccessType | AccessType[];
matchOptions?: MatchOptions; matchOptions?: MatchOptions;
legacy?: boolean;
}; };
const NotFoundRoute: RouteDef = { const NotFoundRoute: RouteDef = {

View file

@ -24,14 +24,18 @@ import { FormProvider, useForm, useFormContext } from "react-hook-form";
import { useAdminClient, useFetch } from "../context/auth/AdminClient"; import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import { useAlerts } from "../components/alert/Alerts"; import { useAlerts } from "../components/alert/Alerts";
import { useTranslation } from "react-i18next"; 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 { useNavigate } from "react-router-dom-v5-compat";
import { ScrollForm } from "../components/scroll-form/ScrollForm"; import { ScrollForm } from "../components/scroll-form/ScrollForm";
import { KeycloakTabs } from "../components/keycloak-tabs/KeycloakTabs";
import { LdapMapperList } from "./ldap/mappers/LdapMapperList"; import { LdapMapperList } from "./ldap/mappers/LdapMapperList";
import { toUserFederation } from "./routes/UserFederation"; import { toUserFederation } from "./routes/UserFederation";
import { ExtendedHeader } from "./shared/ExtendedHeader"; import { ExtendedHeader } from "./shared/ExtendedHeader";
import {
routableTab,
RoutableTabs,
} from "../components/routable-tabs/RoutableTabs";
import { toUserFederationLdap } from "./routes/UserFederationLdap";
type ldapComponentRepresentation = ComponentRepresentation & { type ldapComponentRepresentation = ComponentRepresentation & {
config?: { config?: {
@ -110,6 +114,7 @@ export default function UserFederationLdapSettings() {
const { t } = useTranslation("user-federation"); const { t } = useTranslation("user-federation");
const form = useForm<ComponentRepresentation>({ mode: "onChange" }); const form = useForm<ComponentRepresentation>({ mode: "onChange" });
const navigate = useNavigate(); const navigate = useNavigate();
const history = useHistory();
const { adminClient } = useAdminClient(); const { adminClient } = useAdminClient();
const { realm } = useRealm(); const { realm } = useRealm();
@ -189,11 +194,21 @@ export default function UserFederationLdapSettings() {
/> />
<PageSection variant="light" className="pf-u-p-0"> <PageSection variant="light" className="pf-u-p-0">
{id ? ( {id ? (
<KeycloakTabs isBox> <RoutableTabs
defaultLocation={toUserFederationLdap({
realm,
id,
tab: "settings",
})}
isBox
>
<Tab <Tab
id="settings" id="settings"
eventKey="settings"
title={<TabTitleText>{t("common:settings")}</TabTitleText>} title={<TabTitleText>{t("common:settings")}</TabTitleText>}
{...routableTab({
to: toUserFederationLdap({ realm, id, tab: "settings" }),
history,
})}
> >
<PageSection variant="light"> <PageSection variant="light">
<AddLdapFormContent save={save} /> <AddLdapFormContent save={save} />
@ -201,13 +216,16 @@ export default function UserFederationLdapSettings() {
</Tab> </Tab>
<Tab <Tab
id="mappers" id="mappers"
eventKey="mappers"
title={<TabTitleText>{t("common:mappers")}</TabTitleText>} title={<TabTitleText>{t("common:mappers")}</TabTitleText>}
data-testid="ldap-mappers-tab" data-testid="ldap-mappers-tab"
{...routableTab({
to: toUserFederationLdap({ realm, id, tab: "mappers" }),
history,
})}
> >
<LdapMapperList /> <LdapMapperList />
</Tab> </Tab>
</KeycloakTabs> </RoutableTabs>
) : ( ) : (
<PageSection variant="light"> <PageSection variant="light">
<AddLdapFormContent save={save} /> <AddLdapFormContent save={save} />

View file

@ -7,7 +7,10 @@ import {
} from "./routes/NewProvider"; } from "./routes/NewProvider";
import { UserFederationRoute } from "./routes/UserFederation"; import { UserFederationRoute } from "./routes/UserFederation";
import { UserFederationKerberosRoute } from "./routes/UserFederationKerberos"; import { UserFederationKerberosRoute } from "./routes/UserFederationKerberos";
import { UserFederationLdapRoute } from "./routes/UserFederationLdap"; import {
UserFederationLdapRoute,
UserFederationLdapWithTabRoute,
} from "./routes/UserFederationLdap";
import { UserFederationLdapMapperRoute } from "./routes/UserFederationLdapMapper"; import { UserFederationLdapMapperRoute } from "./routes/UserFederationLdapMapper";
import { UserFederationsKerberosRoute } from "./routes/UserFederationsKerberos"; import { UserFederationsKerberosRoute } from "./routes/UserFederationsKerberos";
import { UserFederationsLdapRoute } from "./routes/UserFederationsLdap"; import { UserFederationsLdapRoute } from "./routes/UserFederationsLdap";
@ -20,6 +23,7 @@ const routes: RouteDef[] = [
UserFederationsLdapRoute, UserFederationsLdapRoute,
NewLdapUserFederationRoute, NewLdapUserFederationRoute,
UserFederationLdapRoute, UserFederationLdapRoute,
UserFederationLdapWithTabRoute,
UserFederationLdapMapperRoute, UserFederationLdapMapperRoute,
CustomProviderRoute, CustomProviderRoute,
CustomEditProviderRoute, CustomEditProviderRoute,

View file

@ -1,6 +1,6 @@
import { lazy } from "react"; import { lazy } from "react";
import { generatePath } from "react-router-dom";
import type { Path } from "react-router-dom-v5-compat"; import type { Path } from "react-router-dom-v5-compat";
import { generatePath } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
type UserFederationLdapTab = "settings" | "mappers"; type UserFederationLdapTab = "settings" | "mappers";
@ -12,15 +12,25 @@ export type UserFederationLdapParams = {
}; };
export const UserFederationLdapRoute: RouteDef = { export const UserFederationLdapRoute: RouteDef = {
path: "/:realm/user-federation/ldap/:id/:tab?", path: "/:realm/user-federation/ldap/:id",
component: lazy(() => import("../UserFederationLdapSettings")), component: lazy(() => import("../UserFederationLdapSettings")),
breadcrumb: (t) => t("common:settings"), breadcrumb: (t) => t("common:settings"),
access: "view-realm", access: "view-realm",
legacy: true, };
export const UserFederationLdapWithTabRoute: RouteDef = {
...UserFederationLdapRoute,
path: "/:realm/user-federation/ldap/:id/:tab",
}; };
export const toUserFederationLdap = ( export const toUserFederationLdap = (
params: UserFederationLdapParams params: UserFederationLdapParams
): Partial<Path> => ({ ): Partial<Path> => {
pathname: generatePath(UserFederationLdapRoute.path, params), const path = params.tab
}); ? UserFederationLdapWithTabRoute.path
: UserFederationLdapRoute.path;
return {
pathname: generatePath(path, params),
};
};

View file

@ -1,8 +1,13 @@
import type { RouteDef } from "../route-config"; import type { RouteDef } from "../route-config";
import { AddUserRoute } from "./routes/AddUser"; import { AddUserRoute } from "./routes/AddUser";
import { UserRoute } from "./routes/User"; 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; export default routes;

View file

@ -1,5 +1,5 @@
import { lazy } from "react"; 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 { Path } from "react-router-dom-v5-compat";
import type { RouteDef } from "../../route-config"; import type { RouteDef } from "../../route-config";
@ -8,13 +8,21 @@ export type UserTab = "list" | "permissions";
export type UsersParams = { realm: string; tab?: UserTab }; export type UsersParams = { realm: string; tab?: UserTab };
export const UsersRoute: RouteDef = { export const UsersRoute: RouteDef = {
path: "/:realm/users/:tab?", path: "/:realm/users",
component: lazy(() => import("../UsersSection")), component: lazy(() => import("../UsersSection")),
breadcrumb: (t) => t("users:title"), breadcrumb: (t) => t("users:title"),
access: "query-users", access: "query-users",
legacy: true,
}; };
export const toUsers = (params: UsersParams): Partial<Path> => ({ export const UsersRouteWithTab: RouteDef = {
pathname: generatePath(UsersRoute.path, params), ...UsersRoute,
}); path: "/:realm/users/:tab",
};
export const toUsers = (params: UsersParams): Partial<Path> => {
const path = params.tab ? UsersRouteWithTab.path : UsersRoute.path;
return {
pathname: generatePath(path, params),
};
};