1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-12-09 20:04:11 +01:00

fix: don't spread props + nest li correctly (#10923)

Fixes a few errors appearing on the "assign user/group" on the project
settings pages. Namely:
- spreading "key" into props in two places (option list and selected
chips)
- incorrect HTML nesting ([`li`'s only permitted parents are `ul`, `ol`,
and
`menu`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/li#technical_summary))
- missing key in the list (caused by nesting the `li`)

The renderOption type update is based on a [fix that was added in a more
recent version of
mui](https://github.com/mui/material-ui/pull/42689/files).

For some reason, the default tag rendering spreads the key in somehow,
so I've had to add a manual `renderTags` prop, and as such extracted the
`getOptionLabel` function. If you know a better way of sorting out the
fact that the `key` prop is spread into the default MUI chips, I'd be
very happy to implement that instead.
This commit is contained in:
Thomas Heartman 2025-11-06 13:05:16 +01:00 committed by GitHub
parent 7215e6bdfb
commit 2f25f5fd8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -4,6 +4,7 @@ import {
Button,
capitalize,
Checkbox,
Chip,
styled,
TextField,
Tooltip,
@ -86,6 +87,18 @@ const StyledUserOption = styled('div')(({ theme }) => ({
},
}));
const getOptionLabel = (option: IAccessOption) => {
if (
option.type === ENTITY_TYPE.USER ||
option.type === ENTITY_TYPE.SERVICE_ACCOUNT
) {
const optionUser = option.entity as IUser;
return optionUser.email || optionUser.name || optionUser.username || '';
} else {
return option.entity.name;
}
};
interface IAccessOption {
id: number;
entity: IUser | IGroup;
@ -272,7 +285,7 @@ export const ProjectAccessAssign = ({
};
const renderOption = (
props: React.HTMLAttributes<HTMLLIElement>,
{ key, ...props }: React.HTMLAttributes<HTMLLIElement> & { key?: any },
option: IAccessOption,
selected: boolean,
) => {
@ -283,9 +296,9 @@ export const ProjectAccessAssign = ({
optionUser = option.entity as IUser;
}
return (
<Tooltip title={createRootGroupWarning(optionGroup)}>
<span>
<li {...props}>
<li key={key} {...props}>
<Tooltip title={createRootGroupWarning(optionGroup)}>
<>
<Checkbox
icon={<CheckBoxOutlineBlankIcon fontSize='small' />}
checkedIcon={<CheckBoxIcon fontSize='small' />}
@ -319,9 +332,9 @@ export const ProjectAccessAssign = ({
</StyledUserOption>
}
/>
</li>
</span>
</Tooltip>
</>
</Tooltip>
</li>
);
};
@ -340,6 +353,8 @@ export const ProjectAccessAssign = ({
);
}
const autocompleteSize = 'small';
return (
<SidebarModal
open
@ -365,7 +380,7 @@ export const ProjectAccessAssign = ({
<StyledAutocompleteWrapper>
<AutocompleteVirtual
data-testid={PA_USERS_GROUPS_ID}
size='small'
size={autocompleteSize}
multiple
openOnFocus
limitTags={10}
@ -396,24 +411,19 @@ export const ProjectAccessAssign = ({
renderOption={(props, option, { selected }) =>
renderOption(props, option, selected)
}
getOptionLabel={(option: IAccessOption) => {
if (
option.type === ENTITY_TYPE.USER ||
option.type ===
ENTITY_TYPE.SERVICE_ACCOUNT
) {
const optionUser =
option.entity as IUser;
getOptionLabel={getOptionLabel}
renderTags={(tagValue, getTagProps) =>
tagValue.map((option, index) => {
return (
optionUser.email ||
optionUser.name ||
optionUser.username ||
''
<Chip
{...getTagProps({ index })}
size={autocompleteSize}
key={`${option.type}:${option.id}`}
label={getOptionLabel(option)}
/>
);
} else {
return option.entity.name;
}
}}
})
}
filterOptions={(options, { inputValue }) =>
options.filter((option: IAccessOption) => {
if (