{canManage && (
({ id: m.userId, name: m.name, email: m.email, avatarUrl: m.avatarUrl }))}
+ users={pendingRemovals.map((m) => ({
+ id: m.userId,
+ name: m.name,
+ email: m.email,
+ avatarUrl: m.avatarUrl,
+ }))}
onRemove={unstageRemoval}
disabled={mutation.isPending}
/>
@@ -254,7 +268,9 @@ export function EditGroupDialog({ group, canManage, onClose }: t.EditGroupDialog
diff --git a/src/components/access/EditRoleDialog.tsx b/src/components/access/EditRoleDialog.tsx
index 841b238..891c1ac 100644
--- a/src/components/access/EditRoleDialog.tsx
+++ b/src/components/access/EditRoleDialog.tsx
@@ -21,8 +21,8 @@ import {
UserSearchInline,
} from '@/components/shared';
import { RolePermissionsPanel } from './RolePermissionsPanel';
+import { cn, notifySuccess, notifyError } from '@/utils';
import { useLocalize } from '@/hooks';
-import { cn } from '@/utils';
type EditRoleTab = 'details' | 'permissions' | 'members';
@@ -91,11 +91,17 @@ export function EditRoleDialog({ role, canManage, onClose }: t.EditRoleDialogPro
};
const updateMutation = useMutation({
- mutationFn: async (): Promise => {
- if (!role) return '';
+ mutationFn: async ({
+ name: submittedName,
+ }: {
+ name: string;
+ }): Promise<{ roleId: string; name: string }> => {
+ if (!role) throw new Error(localize('com_access_role_unavailable'));
let roleId = role.id;
if (detailsDirty) {
- const result = await updateRoleFn({ data: { id: role.id, name, description } });
+ const result = await updateRoleFn({
+ data: { id: role.id, name: submittedName, description },
+ });
roleId = result.role.id;
}
if (permissionsDirty && permissions) {
@@ -113,9 +119,7 @@ export function EditRoleDialog({ role, canManage, onClose }: t.EditRoleDialogPro
}
}
const memberResults = await Promise.allSettled([
- ...pendingAdditions.map((user) =>
- addRoleMemberFn({ data: { roleId, userId: user.id } }),
- ),
+ ...pendingAdditions.map((user) => addRoleMemberFn({ data: { roleId, userId: user.id } })),
...pendingRemovals.map((member) =>
removeRoleMemberFn({ data: { roleId, userId: member.userId } }),
),
@@ -130,32 +134,34 @@ export function EditRoleDialog({ role, canManage, onClose }: t.EditRoleDialogPro
parts.push(localize('com_access_member_ops_failed', { count: failures.length }));
throw new Error(parts.join(', '));
}
- return roleId;
+ return { roleId, name: submittedName };
},
- onSuccess: (newRoleId) => {
+ onSuccess: (data) => {
queryClient.invalidateQueries({ queryKey: ['roles'] });
queryClient.invalidateQueries({ queryKey: ['role', role?.id] });
- if (newRoleId !== role?.id) {
- queryClient.invalidateQueries({ queryKey: ['role', newRoleId] });
+ if (data.roleId !== role?.id) {
+ queryClient.invalidateQueries({ queryKey: ['role', data.roleId] });
}
queryClient.invalidateQueries({ queryKey: ['roleAssignments'] });
queryClient.invalidateQueries({ queryKey: ['roleMembers', role?.id] });
- if (newRoleId !== role?.id) {
- queryClient.invalidateQueries({ queryKey: ['roleMembers', newRoleId] });
+ if (data.roleId !== role?.id) {
+ queryClient.invalidateQueries({ queryKey: ['roleMembers', data.roleId] });
}
+ notifySuccess(localize('com_toast_role_updated', { name: data.name }));
onClose();
},
- onError: (err: Error) => setError(err.message),
+ onError: (err: Error) => notifyError(err.message),
});
const doSubmit = () => {
setError('');
+ if (!role) return;
if (!name.trim()) {
setError(localize('com_access_name_required'));
setActiveTab('details');
return;
}
- updateMutation.mutate();
+ updateMutation.mutate({ name });
};
const handleSubmit = (e: React.FormEvent) => {
@@ -183,17 +189,18 @@ export function EditRoleDialog({ role, canManage, onClose }: t.EditRoleDialogPro
ariaLabel={localize('com_access_edit_role')}
>
-
- {localize('com_access_tab_details')}
-
+ {localize('com_access_tab_details')}
{localize('com_access_tab_permissions')}
-
- {localize('com_access_tab_members')}
-
+ {localize('com_access_tab_members')}
-
+
{role?.isSystemRole && (
@@ -239,7 +246,12 @@ export function EditRoleDialog({ role, canManage, onClose }: t.EditRoleDialogPro