Enforced approval rights

This commit is contained in:
2026-10-22 11:25:55 +02:00
parent 0261a6093e
commit 92891438f6
32 changed files with 1891 additions and 870 deletions
@@ -117,8 +117,8 @@ export const UserSecurityModal: React.FC<UserSecurityModalProps> = ({
return null;
}, [userRoles, userRoleStr, systemRoles]);
const assignedRoleId = assignedRole?.id || (assignedRole as any)?.Id || '';
const assignedRoleName = assignedRole?.name || (assignedRole as any)?.Name || '';
const assignedRoleId = assignedRole?.id || assignedRole?.Id || '';
const assignedRoleName = assignedRole?.name || assignedRole?.Name || '';
// 4. Fetch claims derived from the user's role by hitting the endpoint
const {
@@ -197,9 +197,9 @@ export const UserSecurityModal: React.FC<UserSecurityModalProps> = ({
throw new Error('Single-role policy: This user already has an assigned role. Please remove the existing role before assigning a new one.');
}
const selectedRole = (Array.isArray(systemRoles) ? systemRoles : []).find(
(r) => r && (String(r.id) === String(roleId) || String((r as any).Id) === String(roleId))
(r) => r && (String(r.id) === String(roleId) || String(r.Id) === String(roleId))
);
const roleName = selectedRole?.name || (selectedRole as any)?.Name || '';
const roleName = selectedRole?.name || selectedRole?.Name || '';
if (selectedRole && (roleName.toLowerCase() === 'admin' || String(selectedRole.id) === '1') && hasTenantSelfHelpAccess) {
throw new Error('Security policy: Users with tenant self-help access cannot assign Admin roles.');
}
@@ -214,7 +214,7 @@ export const UserSecurityModal: React.FC<UserSecurityModalProps> = ({
queryClient.invalidateQueries({ queryKey: ['users'] });
setSelectedRoleToAdd('');
},
onError: (err: any) => toastError('Role Assignment Failed', err),
onError: (err: unknown) => toastError('Role Assignment Failed', err),
});
const removeRoleMutation = useMutation({
@@ -227,14 +227,14 @@ export const UserSecurityModal: React.FC<UserSecurityModalProps> = ({
refetchRoleClaims();
queryClient.invalidateQueries({ queryKey: ['users'] });
},
onError: (err: any) => toastError('Role Removal Failed', err),
onError: (err: unknown) => toastError('Role Removal Failed', err),
});
// Session & Lockout Mutations
const logoutMutation = useMutation({
mutationFn: () => forceLogoutUser(userId),
onSuccess: () => success('Session Terminated', 'Target user session revoked. Re-authentication required.'),
onError: (err: any) => toastError('Logout Failed', err),
onError: (err: unknown) => toastError('Logout Failed', err),
});
const lockoutMutation = useMutation({
@@ -246,7 +246,7 @@ export const UserSecurityModal: React.FC<UserSecurityModalProps> = ({
);
refetchUser();
},
onError: (err: any) => toastError('Lockout Update Failed', err),
onError: (err: unknown) => toastError('Lockout Update Failed', err),
});
const statusMutation = useMutation({
@@ -256,14 +256,14 @@ export const UserSecurityModal: React.FC<UserSecurityModalProps> = ({
refetchUser();
queryClient.invalidateQueries({ queryKey: ['users'] });
},
onError: (err: any) => toastError('Status Update Failed', err),
onError: (err: unknown) => toastError('Status Update Failed', err),
});
const availableRoles = React.useMemo(() => {
return (Array.isArray(systemRoles) ? systemRoles : []).filter((r) => {
if (!r) return false;
const rId = r.id || (r as any).Id;
const rName = r.name || (r as any).Name || '';
const rId = r.id || r.Id;
const rName = r.name || r.Name || '';
if (hasTenantSelfHelpAccess && (rName.toLowerCase() === 'admin' || String(rId) === '1')) {
return false;
}
@@ -446,7 +446,7 @@ export const UserSecurityModal: React.FC<UserSecurityModalProps> = ({
<option value="">
{availableRoles.length === 0 ? 'No available roles' : 'Select role to assign...'}
</option>
{availableRoles.map((r: any) => {
{availableRoles.map((r) => {
const roleOptId = r?.id || r?.Id || String(r);
const roleOptName = r?.name || r?.Name || String(r);
return (
@@ -485,8 +485,8 @@ export const UserSecurityModal: React.FC<UserSecurityModalProps> = ({
) : (
(Array.isArray(userRoles) ? userRoles : []).map((role) => {
if (!role) return null;
const roleId = role.id || (role as any).Id || String(role);
const roleName = role.name || (role as any).Name || String(role);
const roleId = role.id || role.Id || String(role);
const roleName = role.name || role.Name || String(role);
return (
<div key={roleId} className="p-3.5 flex items-center justify-between gap-3">
<div className="min-w-0">