fix(RBAC): tweaks for edit role form (#6609)

This commit is contained in:
Pablo Lara
2025-01-20 14:09:16 +01:00
committed by GitHub
parent bf8d10b6f6
commit 0f7c0c1b2c
3 changed files with 46 additions and 57 deletions
+9 -11
View File
@@ -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,
@@ -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, {
@@ -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}`,
);
@@ -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),
@@ -50,10 +50,12 @@ 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)
@@ -61,12 +63,14 @@ export const EditGroupForm = ({
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",
@@ -75,6 +79,7 @@ export const EditGroupForm = ({
return;
}
// Create FormData dynamically
const formData = new FormData();
if (updatedFields.name) {
formData.append("name", updatedFields.name);
@@ -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) {
@@ -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">
@@ -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>
@@ -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",