1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-06 01:15:28 +02:00
Nuno Góis 2025-03-17 08:46:09 +00:00 committed by GitHub
parent 76b3e06fe5
commit 3a59886206
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 105 additions and 50 deletions

View File

@ -3,7 +3,7 @@ import { PageHeader } from 'component/common/PageHeader/PageHeader';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import useUserInfo from 'hooks/api/getters/useUserInfo/useUserInfo'; import useUserInfo from 'hooks/api/getters/useUserInfo/useUserInfo';
import { styled, useMediaQuery } from '@mui/material'; import { styled, useMediaQuery } from '@mui/material';
import { useEffect, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments'; import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import theme from 'themes/theme'; import theme from 'themes/theme';
@ -18,16 +18,21 @@ import {
} from 'utils/permissions'; } from 'utils/permissions';
import type { IAccessOverviewPermissionCategory } from './AccessOverviewAccordion/AccessOverviewList'; import type { IAccessOverviewPermissionCategory } from './AccessOverviewAccordion/AccessOverviewList';
import { createProjectPermissionsStructure } from 'component/admin/roles/RoleForm/RolePermissionCategories/createProjectPermissionsStructure'; import { createProjectPermissionsStructure } from 'component/admin/roles/RoleForm/RolePermissionCategories/createProjectPermissionsStructure';
import { Search } from 'component/common/Search/Search';
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
const StyledActionsContainer = styled('div')(({ theme }) => ({ const StyledActionsContainer = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',
flex: 1, flex: 1,
gap: theme.spacing(1), gap: theme.spacing(1),
maxWidth: 600, maxWidth: 800,
[theme.breakpoints.down('md')]: { [theme.breakpoints.down('md')]: {
flexDirection: 'column', flexDirection: 'column',
maxWidth: '100%', maxWidth: '100%',
}, },
'& > div': {
width: '100%',
},
})); }));
const StyledAccessOverviewContainer = styled('div')(({ theme }) => ({ const StyledAccessOverviewContainer = styled('div')(({ theme }) => ({
@ -36,6 +41,20 @@ const StyledAccessOverviewContainer = styled('div')(({ theme }) => ({
gap: theme.spacing(2), gap: theme.spacing(2),
})); }));
const filterCategory = (
category: IAccessOverviewPermissionCategory,
search: string,
): IAccessOverviewPermissionCategory | undefined => {
const searchLower = search.toLowerCase();
const filteredPermissions = category.permissions.filter(({ displayName }) =>
displayName.toLowerCase().includes(searchLower),
);
if (filteredPermissions.length) {
return { ...category, permissions: filteredPermissions };
}
};
export const AccessOverview = () => { export const AccessOverview = () => {
const id = useRequiredPathParam('id'); const id = useRequiredPathParam('id');
const [query, setQuery] = useQueryParams({ const [query, setQuery] = useQueryParams({
@ -48,6 +67,7 @@ export const AccessOverview = () => {
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
const [searchValue, setSearchValue] = useState('');
const [project, setProject] = useState(query.project ?? ''); const [project, setProject] = useState(query.project ?? '');
const [environment, setEnvironment] = useState( const [environment, setEnvironment] = useState(
query.environment ?? undefined, query.environment ?? undefined,
@ -71,6 +91,7 @@ export const AccessOverview = () => {
const AccessActions = ( const AccessActions = (
<StyledActionsContainer> <StyledActionsContainer>
<Search initialValue={searchValue} onChange={setSearchValue} />
<AccessOverviewSelect <AccessOverviewSelect
label='Project' label='Project'
options={projects} options={projects}
@ -92,21 +113,41 @@ export const AccessOverview = () => {
</StyledActionsContainer> </StyledActionsContainer>
); );
const rootCategories = getCategorizedRootPermissions( const rootCategories = useMemo(() => {
const categories = getCategorizedRootPermissions(
overview?.root ?? [], overview?.root ?? [],
) as IAccessOverviewPermissionCategory[]; ) as IAccessOverviewPermissionCategory[];
const projectCategories = createProjectPermissionsStructure( if (!searchValue) return categories;
return categories
.map((category) => filterCategory(category, searchValue))
.filter(Boolean) as IAccessOverviewPermissionCategory[];
}, [overview?.root, searchValue]);
const projectCategories = useMemo(() => {
const categories = createProjectPermissionsStructure(
overview?.project ?? [], overview?.project ?? [],
).map(({ label, permissions }) => ({ ).map(({ label, permissions }) => ({
label, label,
permissions: permissions.map(([permission]) => permission), permissions: permissions.map(([permission]) => permission),
})) as IAccessOverviewPermissionCategory[]; })) as IAccessOverviewPermissionCategory[];
const environmentCategories = getCategorizedProjectPermissions( return categories
.map((category) => filterCategory(category, searchValue))
.filter(Boolean) as IAccessOverviewPermissionCategory[];
}, [overview?.project, searchValue]);
const environmentCategories = useMemo(() => {
const categories = getCategorizedProjectPermissions(
overview?.environment ?? [], overview?.environment ?? [],
) as IAccessOverviewPermissionCategory[]; ) as IAccessOverviewPermissionCategory[];
return categories
.map((category) => filterCategory(category, searchValue))
.filter(Boolean) as IAccessOverviewPermissionCategory[];
}, [overview?.environment, searchValue]);
return ( return (
<PageContent <PageContent
isLoading={loading} isLoading={loading}
@ -128,6 +169,7 @@ export const AccessOverview = () => {
} }
> >
<StyledAccessOverviewContainer> <StyledAccessOverviewContainer>
<SearchHighlightProvider value={searchValue}>
<AccessOverviewAccordion categories={rootCategories}> <AccessOverviewAccordion categories={rootCategories}>
Root permissions for role {rootRole?.name} Root permissions for role {rootRole?.name}
</AccessOverviewAccordion> </AccessOverviewAccordion>
@ -138,10 +180,13 @@ export const AccessOverview = () => {
: ''} : ''}
</AccessOverviewAccordion> </AccessOverviewAccordion>
{environment && ( {environment && (
<AccessOverviewAccordion categories={environmentCategories}> <AccessOverviewAccordion
categories={environmentCategories}
>
Environment permissions for {environment} Environment permissions for {environment}
</AccessOverviewAccordion> </AccessOverviewAccordion>
)} )}
</SearchHighlightProvider>
</StyledAccessOverviewContainer> </StyledAccessOverviewContainer>
</PageContent> </PageContent>
); );

View File

@ -1,6 +1,8 @@
import Check from '@mui/icons-material/Check'; import Check from '@mui/icons-material/Check';
import Close from '@mui/icons-material/Close'; import Close from '@mui/icons-material/Close';
import { Box, styled } from '@mui/material'; import { Box, styled } from '@mui/material';
import { Highlighter } from 'component/common/Highlighter/Highlighter';
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import type { import type {
IAccessOverviewPermission, IAccessOverviewPermission,
IPermissionCategory, IPermissionCategory,
@ -53,7 +55,10 @@ export const AccessOverviewList = ({
categories, categories,
}: { }: {
categories: IAccessOverviewPermissionCategory[]; categories: IAccessOverviewPermissionCategory[];
}) => ( }) => {
const { searchQuery } = useSearchHighlightContext();
return (
<Box sx={{ maxHeight: 500, overflow: 'auto' }}> <Box sx={{ maxHeight: 500, overflow: 'auto' }}>
<StyledList> <StyledList>
{categories.map((category) => ( {categories.map((category) => (
@ -64,7 +69,11 @@ export const AccessOverviewList = ({
<StyledList> <StyledList>
{category.permissions.map((permission) => ( {category.permissions.map((permission) => (
<li key={permission.name}> <li key={permission.name}>
<div>{permission.displayName}</div> <div>
<Highlighter search={searchQuery}>
{permission.displayName}
</Highlighter>
</div>
<PermissionStatus <PermissionStatus
hasPermission={permission.hasPermission} hasPermission={permission.hasPermission}
/> />
@ -76,6 +85,7 @@ export const AccessOverviewList = ({
</StyledList> </StyledList>
</Box> </Box>
); );
};
const PermissionStatus = ({ hasPermission }: { hasPermission: boolean }) => ( const PermissionStatus = ({ hasPermission }: { hasPermission: boolean }) => (
<StyledPermissionStatus hasPermission={hasPermission}> <StyledPermissionStatus hasPermission={hasPermission}>