diff --git a/frontend/src/component/admin/users/AccessOverview/AccessOverview.tsx b/frontend/src/component/admin/users/AccessOverview/AccessOverview.tsx index 3c217348e5..ffc4689e75 100644 --- a/frontend/src/component/admin/users/AccessOverview/AccessOverview.tsx +++ b/frontend/src/component/admin/users/AccessOverview/AccessOverview.tsx @@ -12,6 +12,12 @@ import useProjects from 'hooks/api/getters/useProjects/useProjects'; import { AccessOverviewSelect } from './AccessOverviewSelect'; import { useUserAccessOverview } from 'hooks/api/getters/useUserAccessOverview/useUserAccessOverview'; import { AccessOverviewAccordion } from './AccessOverviewAccordion/AccessOverviewAccordion'; +import { + getCategorizedProjectPermissions, + getCategorizedRootPermissions, +} from 'utils/permissions'; +import type { IAccessOverviewPermissionCategory } from './AccessOverviewAccordion/AccessOverviewList'; +import { createProjectPermissionsStructure } from 'component/admin/roles/RoleForm/RolePermissionCategories/createProjectPermissionsStructure'; const StyledActionsContainer = styled('div')(({ theme }) => ({ display: 'flex', @@ -86,6 +92,21 @@ export const AccessOverview = () => { ); + const rootCategories = getCategorizedRootPermissions( + overview?.root ?? [], + ) as IAccessOverviewPermissionCategory[]; + + const projectCategories = createProjectPermissionsStructure( + overview?.project ?? [], + ).map(({ label, permissions }) => ({ + label, + permissions: permissions.map(([permission]) => permission), + })) as IAccessOverviewPermissionCategory[]; + + const environmentCategories = getCategorizedProjectPermissions( + overview?.environment ?? [], + ) as IAccessOverviewPermissionCategory[]; + return ( { } > - + Root permissions for role {rootRole?.name} - + Project permissions {project ? ` for project ${project}${projectRoles?.length ? ` with project role${projectRoles.length !== 1 ? 's' : ''} ${projectRoles?.map((role: any) => role.name).join(', ')}` : ''}` : ''} {environment && ( - + Environment permissions for {environment} )} diff --git a/frontend/src/component/admin/users/AccessOverview/AccessOverviewAccordion/AccessOverviewAccordion.tsx b/frontend/src/component/admin/users/AccessOverview/AccessOverviewAccordion/AccessOverviewAccordion.tsx index 72d51e9e6a..50f1e31b4b 100644 --- a/frontend/src/component/admin/users/AccessOverview/AccessOverviewAccordion/AccessOverviewAccordion.tsx +++ b/frontend/src/component/admin/users/AccessOverview/AccessOverviewAccordion/AccessOverviewAccordion.tsx @@ -5,8 +5,10 @@ import { AccordionSummary, styled, } from '@mui/material'; -import type { IAccessOverviewPermission } from 'interfaces/permissions'; -import { AccessOverviewList } from './AccessOverviewList'; +import { + AccessOverviewList, + type IAccessOverviewPermissionCategory, +} from './AccessOverviewList'; const StyledAccordion = styled(Accordion)(({ theme }) => ({ border: `1px solid ${theme.palette.divider}`, @@ -50,29 +52,33 @@ const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ })); interface IAccessAccordionProps { - permissions: IAccessOverviewPermission[]; + categories: IAccessOverviewPermissionCategory[]; children: React.ReactNode; } export const AccessOverviewAccordion = ({ - permissions, + categories, children, -}: IAccessAccordionProps) => ( - - }> - - {children} - - - { - permissions.filter(({ hasPermission }) => hasPermission) - .length - } - /{permissions.length} permissions - - - - - - -); +}: IAccessAccordionProps) => { + const permissions = categories.flatMap(({ permissions }) => permissions); + + return ( + + }> + + {children} + + + { + permissions.filter(({ hasPermission }) => hasPermission) + .length + } + /{permissions.length} permissions + + + + + + + ); +}; diff --git a/frontend/src/component/admin/users/AccessOverview/AccessOverviewAccordion/AccessOverviewList.tsx b/frontend/src/component/admin/users/AccessOverview/AccessOverviewAccordion/AccessOverviewList.tsx index 26a63cb4c5..a361fa610f 100644 --- a/frontend/src/component/admin/users/AccessOverview/AccessOverviewAccordion/AccessOverviewList.tsx +++ b/frontend/src/component/admin/users/AccessOverview/AccessOverviewAccordion/AccessOverviewList.tsx @@ -1,20 +1,34 @@ import Check from '@mui/icons-material/Check'; import Close from '@mui/icons-material/Close'; import { Box, styled } from '@mui/material'; -import type { IAccessOverviewPermission } from 'interfaces/permissions'; +import type { + IAccessOverviewPermission, + IPermissionCategory, +} from 'interfaces/permissions'; + +export type IAccessOverviewPermissionCategory = Omit< + IPermissionCategory, + 'permissions' +> & { + permissions: IAccessOverviewPermission[]; +}; const StyledList = styled('ul')(({ theme }) => ({ listStyle: 'none', padding: 0, margin: 0, fontSize: theme.fontSizes.smallBody, - '& li': { + '& > li': { display: 'flex', justifyContent: 'space-between', padding: theme.spacing(2), - '&:not(:last-child)': { - borderBottom: `1px solid ${theme.palette.divider}`, - }, + borderBottom: `1px solid ${theme.palette.divider}`, + }, + '& ul li': { + paddingLeft: theme.spacing(4), + }, + '& ul:last-of-type > li:last-child': { + borderBottom: 'none', }, })); @@ -36,25 +50,32 @@ const StyledPermissionStatus = styled('div', { })); export const AccessOverviewList = ({ - permissions, + categories, }: { - permissions: IAccessOverviewPermission[]; -}) => { - return ( - - - {permissions.map((permission) => ( -
  • -
    {permission.displayName}
    - + categories: IAccessOverviewPermissionCategory[]; +}) => ( + + + {categories.map((category) => ( + <> +
  • + {category.label}
  • - ))} -
    -
    - ); -}; + + {category.permissions.map((permission) => ( +
  • +
    {permission.displayName}
    + +
  • + ))} +
    + + ))} + + +); const PermissionStatus = ({ hasPermission }: { hasPermission: boolean }) => (