mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-11 00:08:30 +01:00
feat: grouping of project level roles in autocomplete (#9046)
This commit is contained in:
parent
18cd0e2cdb
commit
e0b4e258dc
@ -0,0 +1,53 @@
|
||||
import { render } from 'utils/testRenderer';
|
||||
import { MultipleRoleSelect } from './MultipleRoleSelect';
|
||||
import { fireEvent, screen } from '@testing-library/react';
|
||||
|
||||
test('Display grouped project roles with names and descriptions', async () => {
|
||||
render(
|
||||
<MultipleRoleSelect
|
||||
roles={[
|
||||
{
|
||||
id: 0,
|
||||
name: 'Owner',
|
||||
project: null,
|
||||
description: 'Owner description',
|
||||
type: 'project',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: 'B Custom Role',
|
||||
project: null,
|
||||
description: 'Custom role description A',
|
||||
type: 'custom',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'A Custom Role',
|
||||
project: null,
|
||||
description: 'Custom role description B',
|
||||
type: 'custom',
|
||||
},
|
||||
]}
|
||||
value={[]}
|
||||
setValue={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
const multiselect = await screen.findByLabelText('Role');
|
||||
|
||||
fireEvent.click(multiselect);
|
||||
|
||||
expect(screen.getByText('Predefined project roles')).toBeInTheDocument();
|
||||
expect(screen.getByText('Owner')).toBeInTheDocument();
|
||||
expect(screen.getByText('Owner description')).toBeInTheDocument();
|
||||
expect(screen.getByText('Custom project roles')).toBeInTheDocument();
|
||||
const customRoleA = screen.getByText('A Custom Role');
|
||||
const customRoleB = screen.getByText('B Custom Role');
|
||||
expect(customRoleA).toBeInTheDocument();
|
||||
expect(customRoleB).toBeInTheDocument();
|
||||
expect(customRoleA.compareDocumentPosition(customRoleB)).toBe(
|
||||
Node.DOCUMENT_POSITION_FOLLOWING,
|
||||
);
|
||||
expect(screen.getByText('Custom role description A')).toBeInTheDocument();
|
||||
expect(screen.getByText('Custom role description B')).toBeInTheDocument();
|
||||
});
|
@ -3,8 +3,8 @@ import {
|
||||
type AutocompleteProps,
|
||||
type AutocompleteRenderOptionState,
|
||||
Checkbox,
|
||||
TextField,
|
||||
styled,
|
||||
TextField,
|
||||
} from '@mui/material';
|
||||
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
|
||||
import CheckBoxIcon from '@mui/icons-material/CheckBox';
|
||||
@ -13,6 +13,7 @@ import { RoleDescription } from '../RoleDescription/RoleDescription';
|
||||
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
|
||||
|
||||
const StyledRoleOption = styled('div')(({ theme }) => ({
|
||||
paddingTop: theme.spacing(0.75),
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
'& > span:last-of-type': {
|
||||
@ -29,6 +30,25 @@ interface IMultipleRoleSelectProps
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
function sortItems<T extends { name: string; type: string }>(items: T[]): T[] {
|
||||
return items.sort((a, b) => {
|
||||
if (a.type !== b.type) {
|
||||
return a.type === 'project' ? -1 : 1;
|
||||
}
|
||||
|
||||
if (a.type === 'custom') {
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
const StyledListItem = styled('li')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
gap: theme.spacing(0.5),
|
||||
}));
|
||||
|
||||
export const MultipleRoleSelect = ({
|
||||
roles,
|
||||
value,
|
||||
@ -41,30 +61,48 @@ export const MultipleRoleSelect = ({
|
||||
option: IRole,
|
||||
state: AutocompleteRenderOptionState,
|
||||
) => (
|
||||
<li {...props}>
|
||||
<StyledListItem {...props} key={option.id}>
|
||||
<Checkbox
|
||||
icon={<CheckBoxOutlineBlankIcon fontSize='small' />}
|
||||
checkedIcon={<CheckBoxIcon fontSize='small' />}
|
||||
style={{ marginRight: 8 }}
|
||||
checked={state.selected}
|
||||
/>
|
||||
<StyledRoleOption>
|
||||
<span>{option.name}</span>
|
||||
<span>{option.description}</span>
|
||||
</StyledRoleOption>
|
||||
</li>
|
||||
</StyledListItem>
|
||||
);
|
||||
|
||||
const sortedRoles = sortItems(roles);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Autocomplete
|
||||
slotProps={{
|
||||
paper: {
|
||||
sx: {
|
||||
'& .MuiAutocomplete-listbox': {
|
||||
'& .MuiAutocomplete-option': {
|
||||
paddingLeft: (theme) => theme.spacing(0.5),
|
||||
alignItems: 'flex-start',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
multiple
|
||||
disableCloseOnSelect
|
||||
openOnFocus
|
||||
size='small'
|
||||
value={value}
|
||||
groupBy={(option) => {
|
||||
return option.type === 'project'
|
||||
? 'Predefined project roles'
|
||||
: 'Custom project roles';
|
||||
}}
|
||||
onChange={(_, roles) => setValue(roles)}
|
||||
options={roles}
|
||||
options={sortedRoles}
|
||||
renderOption={renderRoleOption}
|
||||
getOptionLabel={(option) => option.name}
|
||||
renderInput={(params) => (
|
||||
|
Loading…
Reference in New Issue
Block a user