# MAPPA-LOGICA · Gestione Utenti (admin) ⟦ INIZIO · U-ADMIN-USERS · Videata "Gestione Utenti" (admin) ⟧ File: public/admin/users.html · URL: /admin/users.html · Scopo: elenco paginato di tutti gli utenti della piattaforma con ruolo, organizzazioni di appartenenza, ultimo login; attivazione/disattivazione account e impersonificazione (login come l'utente per 1 ora) · Profili: solo `super_admin` (check `api.getMe()`: se `role !== 'super_admin'` notifica "Accesso non autorizzato." e redirect a ../dashboard.html dopo 1,5s, righe 181-193) • U-ADMIN-USERS.1 — Header pagina e breadcrumb Mostra: titolo "Gestione Utenti" + badge rosso "Super Admin"; breadcrumb "Amministrazione › Utenti" Azioni: click "Amministrazione" → torna a ../admin/index.html Dati da: nessuna Confine: `header.content-header` (riga 132) e `nav.admin-breadcrumb[aria-label="Percorso di navigazione"]` (riga 141), entrambi senza id • U-ADMIN-USERS.2 — Tabella utenti Mostra: tabella con colonne: Nome, Email, Ruolo (badge colorato; etichette: Super Admin, Amministratore, Compliance Manager, Membro CDA, Auditor, Dipendente), Organizzazioni (tag multipli, "-" se nessuna), Ultimo Login (data/ora oppure "Mai"), Attivo (toggle switch), Data Creazione, Azioni (bottone "Impersonate"). Spinner durante il caricamento (`aria-live="polite"` sul contenitore); stato vuoto "Nessun utente trovato / Gli utenti registrati appariranno qui."; errori "Errore nel caricamento" / "Errore di connessione". Azioni: vedi U-ADMIN-USERS.3 (toggle) e U-ADMIN-USERS.4 (impersonate) Dati da: GET /api/admin/users?page={n} (campi per riga: `full_name`, `email`, `role`, `organizations` lista CSV, `last_login_at`, `is_active`, `created_at`, `id`; `pagination`: `total`, `per_page` default 20, `page`) Confine: `#users-container` (riga 150); tabella generata dinamicamente da `renderUsers` senza id • U-ADMIN-USERS.3 — Toggle "Attivo" per utente Mostra: interruttore on/off per riga (verde = attivo); disabilitato per gli utenti `super_admin`; con etichette ARIA accessibili ("Attiva/Disattiva utente {email}") e focus visibile WCAG Azioni: cambio stato → `toggleUserActive(userId, checked)`: PUT con `{is_active: 1|0}`; al successo notifica "Utente attivato/disattivato con successo."; in caso di errore notifica e ricarica la pagina corrente per resettare lo stato Dati da: PUT /api/admin/users/{userId} (body `{is_active}`) Confine: `label.active-toggle` con `input[type=checkbox]` per riga (generati in JS, righe 286-290 del sorgente; senza id — selezionabili solo per posizione di riga) • U-ADMIN-USERS.4 — Azione "Impersonate" Mostra: bottone "Impersonate" con icona scambio e tooltip "Entra come questo utente per 1 ora"; visibile solo per utenti NON super_admin e attivi ("-" negli altri casi) Azioni: click → `confirm('Entrare come {email} per 1 ora?...')`; se confermato POST con `{user_id}`; al successo salva la sessione originale in sessionStorage (`nis2_impersonate_origin_token`, `nis2_impersonate_origin_refresh`, `nis2_impersonate_target_email`), sostituisce il token con quello impersonato (senza refresh token) e naviga a ../dashboard.html; il ritorno alla propria sessione avviene col logout Dati da: POST /api/auth/impersonate (risposta: `data.access_token`) Confine: bottoni `button.btn.btn-secondary.btn-sm` con `onclick="impersonateUser(...)"` generati in JS (riga 295 del sorgente; senza id) • U-ADMIN-USERS.5 — Paginazione Mostra: se più pagine: "Visualizzati {start}-{end} di {total} utenti" + bottoni "« Precedente" / "Successivo »" (disabilitati ai bordi); se una sola pagina: "Totale: {n} utente/i" Azioni: "Precedente"/"Successivo" → `loadUsers(page±1)` ricarica la tabella Dati da: GET /api/admin/users?page={n} Confine: `.pagination` dentro `#users-container` (generata dinamicamente, righe 314-336 del sorgente; senza id) • U-ADMIN-USERS.6 — Sidebar di navigazione Mostra: sidebar Bootstrap Italia condivisa (iniettata da `loadSidebar()` di ../js/common-bi.js) Azioni: navigazione app Dati da: nessuna Confine: `#sidebar` (riga 129) ⟦ FINE · U-ADMIN-USERS ⟧ ## ID STABILI MANCANTI (da aggiungere) | Elemento | Riga | Id proposto | |---|---|---| | Header pagina | 132 | `nis2-admin-users-header` | | Breadcrumb | 141 | `nis2-admin-users-breadcrumb` | | Tabella utenti (generata in JS) | 240-242 | `nis2-admin-users-table` | | Toggle attivo per riga (input checkbox) | 288 | `nis2-admin-users-toggle-{userId}` | | Bottone "Impersonate" per riga | 295 | `nis2-admin-users-impersonate-{userId}` | | Bottone paginazione "Precedente" | 321 | `nis2-admin-users-prev` | | Bottone paginazione "Successivo" | 324 | `nis2-admin-users-next` |