Skip to content

Commit a66dd2f

Browse files
fix: [UIE-10329] - UpdateDelegationDrawer Follow up (#13446)
* handle select all * feedback * feedback
1 parent faa6873 commit a66dd2f

2 files changed

Lines changed: 77 additions & 9 deletions

File tree

packages/manager/src/features/IAM/Delegations/UpdateDelegationForm.tsx

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
useAccountUsersInfiniteQuery,
3+
useAllAccountUsersQuery,
34
useUpdateChildAccountDelegatesQuery,
45
} from '@linode/queries';
56
import { ActionsPanel, Autocomplete, Notice, Typography } from '@linode/ui';
@@ -41,6 +42,7 @@ export const UpdateDelegationForm = ({
4142
}: DelegationsFormProps) => {
4243
const theme = useTheme();
4344
const [inputValue, setInputValue] = React.useState<string>('');
45+
const [allUserSelected, setAllUserSelected] = React.useState<boolean>(false);
4446
const debouncedInputValue = useDebouncedValue(inputValue);
4547

4648
const { data: permissions } = usePermissions('account', [
@@ -55,13 +57,35 @@ export const UpdateDelegationForm = ({
5557
const { data, error, fetchNextPage, hasNextPage, isFetching } =
5658
useAccountUsersInfiniteQuery(apiFilter);
5759

60+
const {
61+
data: allUsers,
62+
isFetching: isFetchingAllUsers,
63+
refetch: refetchAllUsers,
64+
} = useAllAccountUsersQuery(allUserSelected, {
65+
user_type: 'parent',
66+
});
67+
5868
const users =
59-
data?.pages.flatMap((page) => {
60-
return page.data.map((user) => ({
61-
label: user.username,
62-
value: user.username,
63-
}));
64-
}) ?? [];
69+
allUserSelected && allUsers
70+
? allUsers.map((user) => ({
71+
label: user.username,
72+
value: user.username,
73+
}))
74+
: (data?.pages.flatMap((page) => {
75+
return page.data.map((user) => ({
76+
label: user.username,
77+
value: user.username,
78+
}));
79+
}) ?? []);
80+
81+
const isSearching =
82+
inputValue.length > 0 && debouncedInputValue !== inputValue;
83+
84+
const isLoadingOptions = isFetching || isFetchingAllUsers;
85+
86+
const showNoOptionsText = !isLoadingOptions && !isSearching;
87+
88+
const isSelectAllFetching = allUserSelected && isFetchingAllUsers;
6589

6690
const { mutateAsync: updateDelegates } =
6791
useUpdateChildAccountDelegatesQuery();
@@ -78,6 +102,7 @@ export const UpdateDelegationForm = ({
78102
handleSubmit,
79103
reset,
80104
setError,
105+
setValue,
81106
} = form;
82107

83108
const onSubmit = async (values: UpdateDelegationsFormValues) => {
@@ -99,9 +124,21 @@ export const UpdateDelegationForm = ({
99124
}
100125
};
101126

127+
const onSelectAllClick = async () => {
128+
setAllUserSelected(true);
129+
const { data } = await refetchAllUsers();
130+
if (data) {
131+
setValue(
132+
'users',
133+
data.map((user) => ({ label: user.username, value: user.username }))
134+
);
135+
}
136+
};
137+
102138
const handleClose = () => {
103139
reset();
104140
onClose();
141+
setAllUserSelected(false);
105142
};
106143

107144
return (
@@ -135,20 +172,27 @@ export const UpdateDelegationForm = ({
135172
render={({ field, fieldState }) => (
136173
<Autocomplete
137174
data-testid="delegates-autocomplete"
175+
disabled={isFetchingAllUsers}
138176
errorText={fieldState.error?.message ?? error?.[0].reason}
139177
isOptionEqualToValue={(option, value) =>
140178
option.value === value.value
141179
}
142-
label={'Delegate Users'}
143-
loading={isFetching}
180+
label="Delegate Users"
181+
loading={isFetching || isFetchingAllUsers}
144182
multiple
145183
noMarginTop
184+
noOptionsText={showNoOptionsText ? 'No users found' : ' '}
146185
onChange={(_, newValue) => {
147186
field.onChange(newValue || []);
148187
}}
149188
onInputChange={(_, value) => {
150189
setInputValue(value);
151190
}}
191+
onSelectAllClick={(isSelectAllActive) => {
192+
if (isSelectAllActive && !allUserSelected) {
193+
onSelectAllClick();
194+
}
195+
}}
152196
options={users}
153197
placeholder={getPlaceholder(
154198
'delegates',
@@ -171,6 +215,12 @@ export const UpdateDelegationForm = ({
171215
}}
172216
textFieldProps={{
173217
hideLabel: true,
218+
helperText: isSelectAllFetching
219+
? 'Fetching all users...'
220+
: undefined,
221+
InputProps: isSelectAllFetching
222+
? { startAdornment: null }
223+
: undefined,
174224
}}
175225
value={field.value}
176226
/>

packages/ui/src/components/Autocomplete/Autocomplete.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ export interface EnhancedAutocompleteProps<
4848
noMarginTop?: boolean;
4949
/** Element to show when the Autocomplete search yields no results. */
5050
noOptionsText?: JSX.Element | string;
51+
/** Handler called when the Select All option is clicked. */
52+
onSelectAllClick?: (
53+
event: React.MouseEvent<HTMLLIElement, MouseEvent>,
54+
) => void;
5155
placeholder?: string;
5256
renderInput?: (_params: AutocompleteRenderInputParams) => React.ReactNode;
5357
/** Label for the "select all" option. */
@@ -96,6 +100,7 @@ export const Autocomplete = <
96100
keepSearchEnabledOnMobile = false,
97101
onBlur,
98102
onChange,
103+
onSelectAllClick,
99104
options,
100105
placeholder,
101106
renderInput,
@@ -191,16 +196,29 @@ export const Autocomplete = <
191196
const isSelectAllOption = option === selectAllOption;
192197
const ListItem = isSelectAllOption ? StyledListItem : 'li';
193198

199+
// If this is the Select All option, add a click handler
200+
const handleClick = (
201+
event: React.MouseEvent<HTMLLIElement, MouseEvent>,
202+
) => {
203+
if (isSelectAllOption && onSelectAllClick) {
204+
onSelectAllClick(event);
205+
}
206+
if (props.onClick) {
207+
props.onClick(event);
208+
}
209+
};
210+
194211
return renderOption ? (
195212
renderOption(props, option, state, ownerState)
196213
) : (
197214
<ListItem
198215
{...props}
199216
data-pendo-id={
200217
rest.getOptionLabel ? rest.getOptionLabel(option) : option.label
201-
} // Adding data-pendo-id for better tracking in Pendo analytics, using the option label as the identifier for the option element.
218+
}
202219
data-qa-option
203220
key={props.key}
221+
onClick={isSelectAllOption ? handleClick : props.onClick}
204222
>
205223
<>
206224
<Box

0 commit comments

Comments
 (0)