Skip to content

Commit

Permalink
fix(RBAC): tweaks for edit role form (#6609)
Browse files Browse the repository at this point in the history
  • Loading branch information
paabloLC authored Jan 20, 2025
1 parent bf8d10b commit 0f7c0c1
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 57 deletions.
20 changes: 9 additions & 11 deletions ui/actions/manage-groups/manage-groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,10 @@ export const updateProviderGroup = async (
const providersJson = formData.get("providers") as string;
const rolesJson = formData.get("roles") as string;

const providers = providersJson ? JSON.parse(providersJson) : [];
const roles = rolesJson ? JSON.parse(rolesJson) : [];
const providers = providersJson ? JSON.parse(providersJson) : null;
const roles = rolesJson ? JSON.parse(rolesJson) : null;

const payload: ManageGroupPayload = {
const payload: Partial<ManageGroupPayload> = {
data: {
type: "provider-groups",
id: providerGroupId,
Expand All @@ -170,14 +170,15 @@ export const updateProviderGroup = async (
},
};

// Add relationships only if there are items
if (providers.length >= 0) {
payload.data.relationships!.providers = { data: providers };
// Add relationships only if changes are detected
if (providers) {
payload.data!.relationships!.providers = { data: providers };
}

if (roles.length >= 0) {
payload.data.relationships!.roles = { data: roles };
if (roles) {
payload.data!.relationships!.roles = { data: roles };
}

try {
const url = `${keyServer}/provider-groups/${providerGroupId}`;
const response = await fetch(url, {
Expand All @@ -192,8 +193,6 @@ export const updateProviderGroup = async (

if (!response.ok) {
const errorResponse = await response.json();
// eslint-disable-next-line no-console
console.error("Error response:", errorResponse);
throw new Error(
`Failed to update provider group: ${response.status} ${response.statusText}`,
);
Expand All @@ -203,7 +202,6 @@ export const updateProviderGroup = async (
revalidatePath("/manage-groups");
return parseStringify(data);
} catch (error) {
// eslint-disable-next-line no-console
console.error("Unexpected error:", error);
return {
error: getErrorMessage(error),
Expand Down
6 changes: 6 additions & 0 deletions ui/components/manage-groups/forms/edit-group-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,27 @@ export const EditGroupForm = ({
try {
const updatedFields: Partial<FormValues> = {};

// Detect changes in the name
if (values.name !== providerGroupData.name) {
updatedFields.name = values.name;
}

// Detect changes in providers
if (
JSON.stringify(values.providers) !==
JSON.stringify(providerGroupData.providers)
) {
updatedFields.providers = values.providers;
}

// Detect changes in roles
if (
JSON.stringify(values.roles) !== JSON.stringify(providerGroupData.roles)
) {
updatedFields.roles = values.roles;
}

// If no changes, notify the user and exit
if (Object.keys(updatedFields).length === 0) {
toast({
title: "No changes detected",
Expand All @@ -75,6 +79,7 @@ export const EditGroupForm = ({
return;
}

// Create FormData dynamically
const formData = new FormData();
if (updatedFields.name) {
formData.append("name", updatedFields.name);
Expand All @@ -94,6 +99,7 @@ export const EditGroupForm = ({
formData.append("roles", JSON.stringify(rolesData));
}

// Call the update action
const data = await updateProviderGroup(providerGroupId, formData);

if (data?.errors && data.errors.length > 0) {
Expand Down
77 changes: 31 additions & 46 deletions ui/components/ui/custom/custom-dropdown-selection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,66 +31,50 @@ export const CustomDropdownSelection: React.FC<
const [selectedValues, setSelectedValues] = useState<Set<string>>(
new Set(selectedKeys),
);
const allValues = values.map((item) => item.id);

const memoizedValues = useMemo(() => values, [values]);
const allValues = useMemo(() => values.map((item) => item.id), [values]);

// Update the internal state when selectedKeys changes from props
// Update internal state when selectedKeys changes
useEffect(() => {
const newSelection = new Set(selectedKeys);
if (
JSON.stringify(Array.from(selectedValues)) !==
JSON.stringify(Array.from(newSelection))
) {
if (selectedKeys.length === allValues.length) {
newSelection.add("all");
}
setSelectedValues(newSelection);
if (selectedKeys.length === allValues.length) {
newSelection.add("all");
}
}, [selectedKeys, allValues.length, selectedValues]);
setSelectedValues(newSelection);
}, [selectedKeys, allValues]);

const onSelectionChange = useCallback(
(keys: string[]) => {
setSelectedValues((prevSelected) => {
const newSelection = new Set(keys);
const newSelection = new Set(keys);

// If all values are selected and "all" is not included,
// add "all" automatically
if (
newSelection.size === allValues.length &&
!newSelection.has("all")
) {
return new Set(["all", ...allValues]);
} else if (prevSelected.has("all")) {
// If "all" was previously selected, remove it
if (newSelection.has("all")) {
// Handle "Select All" behavior
if (newSelection.size === allValues.length + 1) {
setSelectedValues(new Set(["all", ...allValues]));
onChange(name, allValues); // Exclude "all" in the callback
} else {
newSelection.delete("all");
return new Set(allValues.filter((key) => newSelection.has(key)));
setSelectedValues(newSelection);
onChange(name, Array.from(newSelection));
}
return newSelection;
});

// Notify the change without including "all"
const selectedValues = keys.filter((key) => key !== "all");
onChange(name, selectedValues);
} else {
setSelectedValues(newSelection);
onChange(name, Array.from(newSelection));
}
},
[allValues, name, onChange],
);

const handleSelectAllClick = useCallback(() => {
setSelectedValues((prevSelected: Set<string>) => {
const newSelection: Set<string> = prevSelected.has("all")
? new Set()
: new Set(["all", ...allValues]);

// Notify the change without including "all"
const selectedValues = Array.from(newSelection).filter(
(key) => key !== "all",
);
onChange(name, selectedValues);

return newSelection;
});
}, [allValues, name, onChange]);
if (selectedValues.has("all")) {
setSelectedValues(new Set());
onChange(name, []);
} else {
const newSelection = new Set(["all", ...allValues]);
setSelectedValues(newSelection);
onChange(name, allValues);
}
}, [allValues, name, onChange, selectedValues]);

return (
<div className="relative flex w-full flex-col gap-2">
Expand Down Expand Up @@ -119,7 +103,8 @@ export const CustomDropdownSelection: React.FC<
wrapper: "checkbox-update",
}}
value="all"
onClick={handleSelectAllClick}
isSelected={selectedValues.has("all")}
onChange={handleSelectAllClick}
>
Select All
</Checkbox>
Expand All @@ -128,7 +113,7 @@ export const CustomDropdownSelection: React.FC<
hideScrollBar
className="flex max-h-96 max-w-56 flex-col gap-y-2 py-2"
>
{memoizedValues.map(({ id, name }) => (
{values.map(({ id, name }) => (
<Checkbox
classNames={{
label: "text-small font-normal",
Expand Down

0 comments on commit 0f7c0c1

Please sign in to comment.