[FEAT] UI Fasi 4+5: Impersonate banner + Preferenze + Branding white-label (v1.6.0)
Completamento UI per gli endpoint backend già attivi (commit e4f9e91):
- admin/users.html: colonna Azioni con pulsante "Impersonate" per utenti non-super_admin
attivi → salva token originale in sessionStorage, sostituisce con quello impersonate,
redirige a dashboard
- js/common.js: banner persistente arancione "Modalità Impersonate" in tutte le
pagine quando sessionStorage ha impersonate origin → pulsante "Esci impersonate"
ripristina token originale e torna ad admin/users
- settings.html: nuovo tab "Preferenze" (lingua/tema/timezone/notifiche email+in-app)
con form salva via PUT /auth/preferences
- settings.html: nuovo tab "Branding" (solo super_admin / consulente) con
brand_name/logo_url/primary_color/secondary_color, PUT /branding
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
e4f9e9179e
commit
a7bd37a797
@@ -231,6 +231,7 @@
|
||||
<th>Ultimo Login</th>
|
||||
<th>Attivo</th>
|
||||
<th>Data Creazione</th>
|
||||
<th>Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>`;
|
||||
@@ -270,6 +271,14 @@
|
||||
</label>
|
||||
</td>
|
||||
<td>${formatDate(user.created_at)}</td>
|
||||
<td>
|
||||
${role !== 'super_admin' && isActive
|
||||
? `<button class="btn btn-secondary btn-sm" onclick="impersonateUser(${user.id}, '${escapeHtml(user.email)}')" title="Entra come questo utente per 1 ora">
|
||||
<svg width="14" height="14" viewBox="0 0 20 20" fill="currentColor" style="vertical-align:-2px"><path d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"/></svg>
|
||||
Impersonate
|
||||
</button>`
|
||||
: '<span class="text-muted">-</span>'}
|
||||
</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
@@ -333,6 +342,27 @@
|
||||
loadUsers(currentPage);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Impersonate (Fase 4 / G11 — UI) ──
|
||||
async function impersonateUser(userId, email) {
|
||||
if (!confirm('Entrare come ' + email + ' per 1 ora?\n\nSarai loggato come quell\'utente. Tornerai alla tua sessione facendo logout.')) return;
|
||||
try {
|
||||
const res = await api.post('/auth/impersonate', { user_id: userId });
|
||||
if (res.success && res.data && res.data.access_token) {
|
||||
// Salva sessione originale per "Exit impersonate"
|
||||
sessionStorage.setItem('nis2_impersonate_origin_token', api.token);
|
||||
sessionStorage.setItem('nis2_impersonate_origin_refresh', api.refreshToken || '');
|
||||
sessionStorage.setItem('nis2_impersonate_target_email', email);
|
||||
// Sostituisce token con quello impersonate (no refresh per default)
|
||||
api.setTokens(res.data.access_token, '');
|
||||
window.location.href = '/dashboard.html';
|
||||
} else {
|
||||
showNotification(res.message || 'Impersonate fallito.', 'error');
|
||||
}
|
||||
} catch (e) {
|
||||
showNotification('Errore di connessione.', 'error');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user