diff --git a/frontend/src/pages/SettingsRoles.tsx b/frontend/src/pages/SettingsRoles.tsx index 09dfa98..3c0772d 100644 --- a/frontend/src/pages/SettingsRoles.tsx +++ b/frontend/src/pages/SettingsRoles.tsx @@ -1,6 +1,7 @@ -import React, { useState } from 'react'; +import React, { useState, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { useRoles, useCreateRole, useUpdateRole, useDeleteRole } from '@/api/hooks'; +import { useRoles, useCreateRole, useUpdateRole, useDeleteRole, usePermissions } from '@/api/hooks'; +import type { PermissionItem } from '@/api/hooks'; import { Input } from '@/components/ui/Input'; import { Button } from '@/components/ui/Button'; import { Card } from '@/components/ui/Card'; @@ -18,17 +19,6 @@ interface Role { field_permissions?: Record; } -const ALL_PERMISSIONS = [ - { key: 'companies:read', label: 'Firmen lesen' }, - { key: 'companies:write', label: 'Firmen bearbeiten' }, - { key: 'contacts:read', label: 'Kontakte lesen' }, - { key: 'contacts:write', label: 'Kontakte bearbeiten' }, - { key: 'users:read', label: 'Benutzer lesen' }, - { key: 'users:write', label: 'Benutzer bearbeiten' }, - { key: 'audit:read', label: 'Audit-Log lesen' }, - { key: 'settings:write', label: 'Einstellungen bearbeiten' }, -]; - function isPermissionGranted(permissions: Record, permKey: string): boolean { if (!permissions) return false; if (typeof permissions === 'boolean') return permissions; @@ -66,6 +56,7 @@ export function SettingsRolesPage() { const { t } = useTranslation(); const toast = useToast(); const { data, isLoading, isError, error, refetch } = useRoles(); + const { data: permissionsData, isLoading: permissionsLoading } = usePermissions(); const createRoleMutation = useCreateRole(); const updateRoleMutation = useUpdateRole(); const deleteRoleMutation = useDeleteRole(); @@ -78,6 +69,29 @@ export function SettingsRolesPage() { const roles: Role[] = data?.items ?? []; + const allPermissions: PermissionItem[] = useMemo(() => { + return permissionsData?.all ?? []; + }, [permissionsData]); + + const permissionLabelMap = useMemo(() => { + const map = new Map(); + for (const perm of allPermissions) { + map.set(perm.key, perm.label); + } + return map; + }, [allPermissions]); + + const groupedPermissions = useMemo(() => { + const groups: Record = {}; + for (const perm of allPermissions) { + if (!groups[perm.category]) { + groups[perm.category] = []; + } + groups[perm.category].push(perm); + } + return groups; + }, [allPermissions]); + const handleCreateRole = async () => { if (!newRoleName.trim()) { toast.error(t('validation.required')); @@ -138,7 +152,7 @@ export function SettingsRolesPage() { } }; - if (isLoading) { + if (isLoading || permissionsLoading) { return (
@@ -211,7 +225,7 @@ export function SettingsRolesPage() { ) : ( grantedKeys.map((perm) => { - const label = ALL_PERMISSIONS.find((p) => p.key === perm)?.label || perm; + const label = permissionLabelMap.get(perm) || perm; return {label}; }) )} @@ -228,22 +242,32 @@ export function SettingsRolesPage() { label={t('settings.roleName')} value={newRoleName} onChange={(e) => setNewRoleName(e.target.value)} - placeholder="z.B. Vertrieb" + placeholder={t('settings.roleName')} data-testid="new-role-name" />
- {ALL_PERMISSIONS.map((perm) => ( - + {allPermissions.length === 0 && ( +

{t('settings.noPermissions')}

+ )} + {Object.entries(groupedPermissions).map(([category, perms]) => ( +
+

+ {category === 'system' ? t('settings.systemPermissions') : t('settings.pluginPermissions')} +

+ {perms.map((perm) => ( + + ))} +
))}
@@ -271,16 +295,26 @@ export function SettingsRolesPage() {
- {ALL_PERMISSIONS.map((perm) => ( - + {allPermissions.length === 0 && ( +

{t('settings.noPermissions')}

+ )} + {Object.entries(groupedPermissions).map(([category, perms]) => ( +
+

+ {category === 'system' ? t('settings.systemPermissions') : t('settings.pluginPermissions')} +

+ {perms.map((perm) => ( + + ))} +
))}