/** * AdminUserAccessOverviewPage * * Admin page for viewing comprehensive user access permissions. * Shows what pages a user can see and what data they can access. */ import React, { useState, useEffect } from 'react'; import { FaSync, FaUserShield, FaEye, FaDatabase, FaCube, FaChevronDown, FaChevronRight, FaCheckCircle, FaTimesCircle, FaInfoCircle } from 'react-icons/fa'; import api from '../../api'; import styles from './Admin.module.css'; import { useLanguage } from '../../providers/language/LanguageContext'; import { mandateDisplayLineLabelThenSlug } from '../../utils/mandateDisplayUtils'; interface UserOption { id: string; username: string; email: string; fullName: string; isSysAdmin: boolean; isPlatformAdmin: boolean; enabled: boolean; } interface RoleInfo { id: string; roleLabel: string; description: string; scope: 'global' | 'mandate' | 'instance'; mandateId?: string; featureInstanceId?: string; source: string; sourceMandateId?: string; sourceMandateName?: string; sourceInstanceId?: string; sourceInstanceLabel?: string; } interface AccessEntry { item: string; view?: boolean; read?: string; create?: string; update?: string; delete?: string; grantedByRoleLabels: string[]; roleScope: string; } interface MandateInfo { id: string; name: string; label?: string | null; roleIds: string[]; featureInstances: { id: string; label: string; featureCode: string; featureLabel: string; roleIds: string[]; }[]; } function _roleDescriptionLine(role: RoleInfo): string { return role.description?.trim() || ''; } interface UserAccessOverview { user: UserOption; isSysAdmin: boolean; isPlatformAdmin: boolean; sysAdminNote?: string; roles: RoleInfo[]; mandates: MandateInfo[]; uiAccess: AccessEntry[]; dataAccess: AccessEntry[]; resourceAccess: AccessEntry[]; } type TabId = 'overview' | 'ui' | 'data' | 'resources'; export const AdminUserAccessOverviewPage: React.FC = () => { const { t } = useLanguage(); const [users, setUsers] = useState([]); const [selectedUserId, setSelectedUserId] = useState(''); const [overview, setOverview] = useState(null); const [loading, setLoading] = useState(false); const [loadingUsers, setLoadingUsers] = useState(true); const [error, setError] = useState(null); const [activeTab, setActiveTab] = useState('overview'); const [expandedRoles, setExpandedRoles] = useState>(new Set()); const [expandedMandates, setExpandedMandates] = useState>(new Set()); // Fetch users list on mount useEffect(() => { const fetchUsers = async () => { try { setLoadingUsers(true); const response = await api.get('/api/admin/user-access-overview/users'); setUsers(response.data); } catch (err: any) { setError(err?.response?.data?.detail || err?.message || t('Benutzer konnten nicht geladen werden')); } finally { setLoadingUsers(false); } }; fetchUsers(); }, [t]); // Fetch access overview when user is selected useEffect(() => { if (!selectedUserId) { setOverview(null); return; } const fetchOverview = async () => { try { setLoading(true); setError(null); const response = await api.get(`/api/admin/user-access-overview/${selectedUserId}`); const data = response.data; setOverview(data); // Auto-expand all mandates setExpandedMandates(new Set(data.mandates?.map((m: MandateInfo) => m.id) || [])); } catch (err: any) { setError(err?.response?.data?.detail || err?.message || t('Zugriffsübersicht konnte nicht geladen werden')); setOverview(null); } finally { setLoading(false); } }; fetchOverview(); }, [selectedUserId, t]); const toggleRole = (roleId: string) => { setExpandedRoles(prev => { const newSet = new Set(prev); if (newSet.has(roleId)) { newSet.delete(roleId); } else { newSet.add(roleId); } return newSet; }); }; const toggleMandate = (mandateId: string) => { setExpandedMandates(prev => { const newSet = new Set(prev); if (newSet.has(mandateId)) { newSet.delete(mandateId); } else { newSet.add(mandateId); } return newSet; }); }; const getScopeColor = (scope: string): string => { switch (scope) { case 'instance': return '#10b981'; case 'mandate': return '#3b82f6'; case 'global': return '#8b5cf6'; default: return '#6b7280'; } }; const getAccessLevelColor = (level: string): string => { switch (level) { case 'ALL': return '#10b981'; case 'GROUP': return '#3b82f6'; case 'MY': return '#f59e0b'; case 'NONE': return '#ef4444'; default: return '#6b7280'; } }; const renderOverviewTab = () => { if (!overview) return null; const roleById = new Map(overview.roles.map((r) => [r.id, r])); const globalRoles = overview.roles.filter((r) => r.scope === 'global'); const _resolveRoles = (roleIds: string[]): RoleInfo[] => roleIds.map((id) => roleById.get(id)).filter((r): r is RoleInfo => !!r); return (
{overview.isSysAdmin && (
{overview.sysAdminNote || t('Dieser Benutzer ist Systemadmin (Infrastruktur-Operator) und hat vollen Datenzugriff (RBAC-Bypass).')}
)} {overview.isPlatformAdmin && (
{t('Dieser Benutzer ist Plattformadmin und kann mandantsübergreifend User, Mandate und RBAC-Regeln verwalten (kein RBAC-Bypass).')}
)}

{t('Zugriff nach Mandant')}

{overview.mandates.length === 0 ? (

{t('Keine Mandatszuordnungen vorhanden')}

) : (
{overview.mandates.map((mandate) => { const mandateRoles = _resolveRoles(mandate.roleIds); return (
toggleMandate(mandate.id)}>
{expandedMandates.has(mandate.id) ? ( ) : ( )} {mandateDisplayLineLabelThenSlug(mandate)} {t('{r} Mandantenrolle(n) · {i} Feature-Instanz(en)', { r: mandateRoles.length, i: mandate.featureInstances.length, })}
{expandedMandates.has(mandate.id) && (
{mandateRoles.length === 0 ? (

{t('Keine Rollen direkt am Mandanten')}

) : (
    {mandateRoles.map((r) => (
  • {r.roleLabel} {r.scope}
  • ))}
)}
{t('Feature-Instanzen')}
{mandate.featureInstances.length === 0 ? (

{t('Keine Feature-Instanzen zugewiesen')}

) : (
{mandate.featureInstances.map((instance) => { const instanceRoles = _resolveRoles(instance.roleIds); const featureTitle = instance.featureLabel || instance.featureCode; return (
{instance.label}{' '} ({featureTitle})
{instanceRoles.length === 0 ? (

{t('Keine Rollen.')}

) : (
    {instanceRoles.map((r) => (
  • {r.roleLabel} {r.scope}
  • ))}
)}
); })}
)}
)}
); })}
)} {globalRoles.length > 0 && ( <>

{t('Globale Rollen')}

{t('Nicht an einen Mandanten gebunden.')}

{globalRoles.map((role) => (
toggleRole(role.id)}>
{expandedRoles.has(role.id) ? ( ) : ( )} {role.roleLabel} {role.scope}
{expandedRoles.has(role.id) && (

{t('Beschreibung')} {_roleDescriptionLine(role) || '—'}

)}
))}
)}
); }; const renderUiAccessTab = () => { if (!overview) return null; return (
{t('UI-Zugriffsrechte bestimmen, welche Seiten und')}
{overview.uiAccess.length === 0 ? (

{t('Keine UI-Berechtigungen')}

{t('Diesem Benutzer wurden keine expliziten UI-Berechtigungen zugewiesen.')}

) : ( {overview.uiAccess.map((entry, idx) => ( ))}
{t('UI-Element')} {t('Sichtbar')} {t('Gewährt durch')}
{entry.item} {entry.view ? ( ) : ( )} {entry.grantedByRoleLabels?.join(', ') || '-'}
)}
); }; const renderDataAccessTab = () => { if (!overview) return null; return (
{t('Daten-Zugriffsrechte:')} ALL {t('= Alle Datensätze,')} GROUP{' '} {t('= Gruppen-Datensätze,')} MY {t('= Eigene Datensätze,')} NONE {t('= Kein Zugriff')}
{overview.dataAccess.length === 0 ? (

{t('Keine Datenberechtigungen')}

{t('Diesem Benutzer wurden keine expliziten Daten-Berechtigungen zugewiesen.')}

) : ( {overview.dataAccess.map((entry, idx) => ( ))}
{t('Tabelle/Feld')} {t('Lesen')} {t('Erstellen')} {t('Update')} {t('Löschen')} {t('Gewährt durch')}
{entry.item} {entry.read || '-'} {entry.create || '-'} {entry.update || '-'} {entry.delete || '-'} {entry.grantedByRoleLabels?.join(', ') || '-'}
)}
); }; const renderResourceAccessTab = () => { if (!overview) return null; return (
{t('Ressourcenzugriffsrechte bestimmen, welche Systemressourcen z.B.')}
{overview.resourceAccess.length === 0 ? (

{t('Keine Ressourcenberechtigungen')}

{t('Diesem Benutzer wurden keine expliziten Ressourcen-Berechtigungen zugewiesen.')}

) : ( {overview.resourceAccess.map((entry, idx) => ( ))}
{t('Ressource')} {t('Zugriff')} {t('Gewährt durch')}
{entry.item} {entry.view ? ( ) : ( )} {entry.grantedByRoleLabels?.join(', ') || '-'}
)}
); }; if (error && !overview) { return (
⚠️

{t('Fehler')}: {error}

); } return (

{t('Benutzerzugriffsübersicht')}

{t('Zeigt alle Berechtigungen eines Benutzers')}

{/* User Selection */}
{selectedUserId && ( )}
{/* Content */} {!selectedUserId ? (

{t('Benutzer auswählen')}

{t('Wählen Sie einen Benutzer aus, um dessen Zugriffsberechtigungen anzuzeigen.')}

) : loading ? (
{t('Lade Zugriffsübersicht')}
) : overview ? ( <> {/* User Info */}
{overview.user.fullName || overview.user.username} | {overview.user.email} {overview.isSysAdmin && ( <> | {t('SysAdmin')} )} {overview.isPlatformAdmin && ( <> | {t('PlatformAdmin')} )}
{/* Tabs */}
{/* Tab Content */}
{activeTab === 'overview' && renderOverviewTab()} {activeTab === 'ui' && renderUiAccessTab()} {activeTab === 'data' && renderDataAccessTab()} {activeTab === 'resources' && renderResourceAccessTab()}
) : null}
); }; export default AdminUserAccessOverviewPage;