src/Routing.tsx
import { Navigate, Route as RouterRoute, Routes as RouterRoutes, matchPath, useLocation } from 'react-router-dom';
import React, { lazy, Suspense, useEffect, useMemo } from 'react';
import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
import { AppPlaceholder } from './presentational-components/shared/loader-placeholders';
import pathnames from './utilities/pathnames';
import QuickstartsTestButtons from './utilities/quickstarts-test-buttons';
import ElementWrapper from './smart-components/common/ElementWrapper';
import { mergeToBasename } from './presentational-components/shared/AppLink';
import { useFlag } from '@unleash/proxy-client-react';
const Overview = lazy(() => import('./smart-components/overview/overview'));
const WorkspacesOverview = lazy(() => import('./smart-components/workspaces/overview/about-access-tab'));
const Workspaces = lazy(() => import('./smart-components/workspaces/workspaces'));
const Users = lazy(() => import('./smart-components/user/users'));
const UserDetail = lazy(() => import('./smart-components/user/user'));
const AddUserToGroup = lazy(() => import('./smart-components/user/add-user-to-group/add-user-to-group'));
const InviteUsersModal = lazy(() => import('./smart-components/user/invite-users/invite-users-modal'));
const Roles = lazy(() => import('./smart-components/role/roles'));
const Role = lazy(() => import('./smart-components/role/role'));
const AddRoleWizard = lazy(() => import('./smart-components/role/add-role/add-role-wizard'));
const EditRole = lazy(() => import('./smart-components/role/edit-role-modal'));
const RemoveRole = lazy(() => import('./smart-components/role/remove-role-modal'));
const AddRolePermissionWizard = lazy(() => import('./smart-components/role/add-role-permissions/add-role-permission-wizard'));
const ResourceDefinitions = lazy(() => import('./smart-components/role/role-resource-definitions'));
const EditResourceDefinitionsModal = lazy(() => import('./smart-components/role/edit-resource-definitions-modal'));
const newRolesTable = lazy(() => import('./smart-components/role/RolesTable'));
const Groups = lazy(() => import('./smart-components/group/groups'));
const Group = lazy(() => import('./smart-components/group/group'));
const AddGroupWizard = lazy(() => import('./smart-components/group/add-group/add-group-wizard'));
const EditGroup = lazy(() => import('./smart-components/group/edit-group-modal'));
const RemoveGroup = lazy(() => import('./smart-components/group/remove-group-modal'));
const GroupMembers = lazy(() => import('./smart-components/group/member/group-members'));
const GroupRoles = lazy(() => import('./smart-components/group/role/group-roles'));
const GroupServiceAccounts = lazy(() => import('./smart-components/group/service-account/group-service-accounts'));
const AddGroupRoles = lazy(() => import('./smart-components/group/role/add-group-roles'));
const AddGroupMembers = lazy(() => import('./smart-components/group/member/add-group-members'));
const AddGroupServiceAccounts = lazy(() => import('./smart-components/group/service-account/add-group-service-accounts'));
const RemoveServiceAccountFromGroup = lazy(() => import('./smart-components/group/service-account/remove-group-service-accounts'));
const QuickstartsTest = lazy(() => import('./smart-components/quickstarts/quickstarts-test'));
const UsersAndUserGroups = lazy(() => import('./smart-components/access-management/users-and-user-groups'));
const getRoutes = ({ enableServiceAccounts, isITLess, isWorkspacesFlag }: Record<string, boolean>) => [
{
path: pathnames['users-and-user-groups'].path,
element: UsersAndUserGroups,
},
{
path: pathnames.overview.path,
element: isWorkspacesFlag ? WorkspacesOverview : Overview,
},
{
path: pathnames.workspaces.path,
element: Workspaces,
},
{
path: pathnames['user-detail'].path,
element: UserDetail,
childRoutes: [
{
path: pathnames['add-user-to-group'].path,
element: AddUserToGroup,
},
{
path: pathnames['user-add-group-roles'].path,
element: AddGroupRoles,
},
],
},
{
path: pathnames.users.path,
element: Users,
childRoutes: [
isITLess && {
path: pathnames['invite-users'].path,
element: InviteUsersModal,
},
],
},
{
path: pathnames['role-detail'].path,
element: Role,
childRoutes: [
{
path: pathnames['role-detail-remove'].path,
element: RemoveRole,
},
{
path: pathnames['role-detail-edit'].path,
element: EditRole,
},
{
path: pathnames['role-add-permission'].path,
element: AddRolePermissionWizard,
},
],
},
{
path: pathnames['role-detail-permission'].path,
element: ResourceDefinitions,
childRoutes: [
{
path: pathnames['role-detail-permission-edit'].path,
element: EditResourceDefinitionsModal,
},
],
},
...(isWorkspacesFlag
? [
{
path: pathnames.roles.path,
element: newRolesTable,
},
]
: [
{
path: pathnames.roles.path,
element: Roles,
childRoutes: [
{
path: pathnames['roles-add-group-roles'].path,
element: AddGroupRoles,
},
{
path: pathnames['add-role'].path,
element: AddRoleWizard,
},
{
path: pathnames['remove-role'].path,
element: RemoveRole,
},
{
path: pathnames['edit-role'].path,
element: EditRole,
},
],
},
]),
{
path: pathnames['group-detail-role-detail'].path,
element: Role,
},
{
path: pathnames['group-detail'].path,
element: Group,
childRoutes: [
{
path: pathnames['group-detail'].path,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
element: (({ groupId }) => <Navigate to={mergeToBasename(pathnames['group-detail-roles'].link).replace(':groupId', groupId)} />) as React.FC,
},
{
path: pathnames['group-detail-roles'].path,
element: GroupRoles,
childRoutes: [
{
path: pathnames['group-roles-edit-group'].path,
element: EditGroup,
},
{
path: pathnames['group-roles-remove-group'].path,
element: RemoveGroup,
},
{
path: pathnames['group-add-roles'].path,
element: AddGroupRoles,
},
],
},
{
path: pathnames['group-detail-members'].path,
element: GroupMembers,
childRoutes: [
{
path: pathnames['group-members-edit-group'].path,
element: EditGroup,
},
{
path: pathnames['group-members-remove-group'].path,
element: RemoveGroup,
},
{
path: pathnames['group-add-members'].path,
element: AddGroupMembers,
},
],
},
...(enableServiceAccounts
? [
{
path: pathnames['group-detail-service-accounts'].path,
element: GroupServiceAccounts,
childRoutes: [
{
path: pathnames['group-service-accounts-edit-group'].path,
element: EditGroup,
},
{
path: pathnames['group-service-accounts-remove-group'].path,
element: RemoveServiceAccountFromGroup,
},
{
path: pathnames['group-add-service-account'].path,
element: AddGroupServiceAccounts,
},
],
},
]
: []),
],
},
{
path: pathnames.groups.path,
element: Groups,
childRoutes: [
{
path: pathnames['add-group'].path,
element: AddGroupWizard,
},
{
path: pathnames['edit-group'].path,
element: EditGroup,
},
{
path: pathnames['remove-group'].path,
element: RemoveGroup,
},
],
},
...(localStorage.getItem('quickstarts:enabled') === 'true' ? [{ path: pathnames['quickstarts-test'].path, element: QuickstartsTest }] : []),
];
interface RouteType {
path?: string;
element: React.ComponentType;
childRoutes?: RouteType[];
elementProps?: Record<string, unknown>;
}
const renderRoutes = (routes: RouteType[] = []) =>
routes.map(({ path, element: Element, childRoutes, elementProps }) => (
<RouterRoute
key={path}
path={path}
element={
<ElementWrapper path={path}>
<Element {...elementProps} />
</ElementWrapper>
}
>
{renderRoutes(childRoutes)}
</RouterRoute>
));
const Routing = () => {
const location = useLocation();
const { updateDocumentTitle, isBeta } = useChrome();
const isITLess = useFlag('platform.rbac.itless');
const enableServiceAccounts =
(isBeta() && useFlag('platform.rbac.group-service-accounts')) || (!isBeta() && useFlag('platform.rbac.group-service-accounts.stable'));
const isWorkspacesFlag = useFlag('platform.rbac.workspaces');
useEffect(() => {
const currPath = Object.values(pathnames).find(
(item) =>
!!matchPath(
{
path: item.path,
end: true,
},
location.pathname
)
);
if (currPath?.title) {
updateDocumentTitle(`${currPath.title} - User Access`);
}
}, [location.pathname, updateDocumentTitle]);
const routes = getRoutes({ enableServiceAccounts, isITLess, isWorkspacesFlag });
const renderedRoutes = useMemo(() => renderRoutes(routes as never), [routes]);
return (
<Suspense fallback={<AppPlaceholder />}>
<QuickstartsTestButtons />
<RouterRoutes>
{renderedRoutes}
{/* Catch all unmatched routes */}
<RouterRoute path="*" element={<Navigate to={mergeToBasename(pathnames.users.link)} />} />
</RouterRoutes>
</Suspense>
);
};
export default Routing;