/** * 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'; interface UserOption { id: string; username: string; email: string; fullName: string; isSysAdmin: boolean; enabled: boolean; } interface RoleInfo { id: string; roleLabel: string; description: { [key: string]: 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: { [key: string]: string }; roleIds: string[]; }[]; } function _mandateNameLine(mandate: MandateInfo): string { const label = mandate.label?.trim(); if (label) { return `${mandate.name} (${label})`; } return mandate.name; } function _roleDescriptionLine(role: RoleInfo): string { return role.description?.de || role.description?.en || ''; } interface UserAccessOverview { user: UserOption; isSysAdmin: 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 || 'Failed to fetch users'); } finally { setLoadingUsers(false); } }; fetchUsers(); }, []); // 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 || 'Failed to fetch overview'); setOverview(null); } finally { setLoading(false); } }; fetchOverview(); }, [selectedUserId]); 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 || 'Dieser Benutzer ist SysAdmin und hat vollen Systemzugriff.'}
)}

{t('adminUserAccessOverview.zugriffNachMandant')}

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

{t('adminUserAccessOverview.keineMandatezuordnungenVorhanden')}

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

{t('adminUserAccessOverview.keineRollenDirektAmMandanten')}

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

{t('adminUserAccessOverview.keineFeatureinstanzenZugewiesen')}

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

Keine Rollen.

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

Globale Rollen

Nicht an einen Mandanten gebunden.

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

{t('adminUserAccessOverview.beschreibung')} {_roleDescriptionLine(role) || '—'}

)}
))}
)}
); }; const renderUiAccessTab = () => { if (!overview) return null; return (
{t('adminUserAccessOverview.uizugriffsrechteBestimmenWelcheSeitenUnd')}
{overview.uiAccess.length === 0 ? (

{t('adminUserAccessOverview.keineUiberechtigungen')}

Diesem Benutzer wurden keine expliziten UI-Berechtigungen zugewiesen.

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

{t('adminUserAccessOverview.keineDatenberechtigungen')}

Diesem Benutzer wurden keine expliziten Daten-Berechtigungen zugewiesen.

) : ( {overview.dataAccess.map((entry, idx) => ( ))}
Tabelle/Feld Lesen {t('adminUserAccessOverview.erstellen')} Update {t('adminUserAccessOverview.loeschen')} {t('adminUserAccessOverview.gewaehrtDurch')}
{entry.item} {entry.read || '-'} {entry.create || '-'} {entry.update || '-'} {entry.delete || '-'} {entry.grantedByRoleLabels?.join(', ') || '-'}
)}
); }; const renderResourceAccessTab = () => { if (!overview) return null; return (
{t('adminUserAccessOverview.ressourcenzugriffsrechteBestimmenWelcheSystemressourcenZb')}
{overview.resourceAccess.length === 0 ? (

{t('adminUserAccessOverview.keineRessourcenberechtigungen')}

Diesem Benutzer wurden keine expliziten Ressourcen-Berechtigungen zugewiesen.

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

Fehler: {error}

); } return (

{t('adminUserAccessOverview.benutzerzugriffsuebersicht')}

{t('adminUserAccessOverview.zeigtAlleBerechtigungenEinesBenutzers')}

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

{t('adminUserAccessOverview.benutzerAuswaehlen')}

Wählen Sie einen Benutzer aus, um dessen Zugriffsberechtigungen anzuzeigen.

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