[UI] SWAP V2: Bootstrap Italia ora UFFICIALE su 27 pagine app (kill della vecchia UI)
Promosse le pagine -bi a nomi ufficiali (contenuto BI), link -bi->plain, titoli '(BI)' rimossi.
La vecchia UI delle pagine app e sostituita. Backup: git (commit 36967f9) + /tmp/nis2-v1-backup.
Promosse (27): auth (login/register/onboarding/forgot/reset) + app (dashboard/assessment/
risks/incidents/policies/supply-chain/training/assets/reports/settings/isms/acn-gap/normative/
whistleblowing/kb/cross-analysis/service-continuity/guida/companies) + admin (index/orgs/users).
common-bi.js: sidebar BI ora linka le pagine ufficiali.
ESCLUSA: index.html (landing marketing 1298 righe) -> conversione dedicata a parte (la -bi
era 557 righe, rischio perdita contenuti). Pagine marketing/demo (presentation/simulate/
workflow/architecture/index-en) restano vecchio stile (fuori scope app autenticata).
Verifica produzione: 27/27 servite 200 con BI, 0 link -bi residui, 0 '(BI)' nei titoli,
auth intatta (401 su pwd errata), common-bi.js node --check OK.
Rollback: git revert HEAD (oppure ripristino da /tmp/nis2-v1-backup).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
36967f9452
commit
1c64211685
+61
-40
@@ -4,6 +4,10 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Pannello Amministrazione - NIS2 Agile</title>
|
||||
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
|
||||
cosi' style.css resta autorevole per i widget renderizzati via JS -> parita' funzionale.
|
||||
Pagina in /admin/: gli asset usano path ASSOLUTI (/vendor, /js, /css) serviti dal web root. -->
|
||||
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<style>
|
||||
.admin-stats-grid {
|
||||
@@ -55,6 +59,8 @@
|
||||
.admin-stat-icon.orange { background: var(--warning-bg); color: #d97706; }
|
||||
.admin-stat-icon.red { background: var(--danger-bg); color: var(--danger); }
|
||||
.admin-stat-icon.purple { background: #f3e8ff; color: #7c3aed; }
|
||||
/* Le icone BI usano fill=currentColor: garantiamo che il colore del wrapper sia ereditato. */
|
||||
.admin-stat-icon svg.icon { fill: currentColor; width: 20px; height: 20px; }
|
||||
.chart-container {
|
||||
padding: 24px;
|
||||
}
|
||||
@@ -118,6 +124,10 @@
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--card-shadow-hover);
|
||||
}
|
||||
.quick-link-card:focus-visible {
|
||||
outline: 2px solid var(--primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.quick-link-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
@@ -132,6 +142,7 @@
|
||||
.quick-link-icon svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
fill: currentColor;
|
||||
}
|
||||
.quick-link-info h4 {
|
||||
font-size: 0.9375rem;
|
||||
@@ -178,7 +189,7 @@
|
||||
|
||||
<main class="main-content">
|
||||
<header class="content-header">
|
||||
<h2>Pannello Amministrazione</h2>
|
||||
<h1 class="h2">Pannello Amministrazione</h1>
|
||||
<div class="content-header-actions">
|
||||
<span class="badge badge-danger">Super Admin</span>
|
||||
</div>
|
||||
@@ -188,64 +199,64 @@
|
||||
<!-- Stats Row 1 -->
|
||||
<div class="admin-stats-grid" id="stats-row-1">
|
||||
<div class="admin-stat-card">
|
||||
<div class="admin-stat-icon blue">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path d="M4 4a2 2 0 012-2h8a2 2 0 012 2v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z"/></svg>
|
||||
<div class="admin-stat-icon blue" aria-hidden="true">
|
||||
<svg class="icon" role="img"><use href="/vendor/bootstrap-italia/dist/svg/sprites.svg#it-pa"></use></svg>
|
||||
</div>
|
||||
<div class="admin-stat-label">Totale Organizzazioni</div>
|
||||
<div class="admin-stat-value" id="stat-total-orgs">--</div>
|
||||
<div class="admin-stat-label" id="lbl-total-orgs">Totale Organizzazioni</div>
|
||||
<div class="admin-stat-value" id="stat-total-orgs" aria-labelledby="lbl-total-orgs">--</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="admin-stat-icon green">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg>
|
||||
<div class="admin-stat-icon green" aria-hidden="true">
|
||||
<svg class="icon" role="img"><use href="/vendor/bootstrap-italia/dist/svg/sprites.svg#it-check-circle"></use></svg>
|
||||
</div>
|
||||
<div class="admin-stat-label">Organizzazioni Attive</div>
|
||||
<div class="admin-stat-value" id="stat-active-orgs">--</div>
|
||||
<div class="admin-stat-label" id="lbl-active-orgs">Organizzazioni Attive</div>
|
||||
<div class="admin-stat-value" id="stat-active-orgs" aria-labelledby="lbl-active-orgs">--</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="admin-stat-icon blue">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z"/></svg>
|
||||
<div class="admin-stat-icon blue" aria-hidden="true">
|
||||
<svg class="icon" role="img"><use href="/vendor/bootstrap-italia/dist/svg/sprites.svg#it-user"></use></svg>
|
||||
</div>
|
||||
<div class="admin-stat-label">Totale Utenti</div>
|
||||
<div class="admin-stat-value" id="stat-total-users">--</div>
|
||||
<div class="admin-stat-label" id="lbl-total-users">Totale Utenti</div>
|
||||
<div class="admin-stat-value" id="stat-total-users" aria-labelledby="lbl-total-users">--</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="admin-stat-icon green">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"/></svg>
|
||||
<div class="admin-stat-icon green" aria-hidden="true">
|
||||
<svg class="icon" role="img"><use href="/vendor/bootstrap-italia/dist/svg/sprites.svg#it-user"></use></svg>
|
||||
</div>
|
||||
<div class="admin-stat-label">Utenti Attivi</div>
|
||||
<div class="admin-stat-value" id="stat-active-users">--</div>
|
||||
<div class="admin-stat-label" id="lbl-active-users">Utenti Attivi</div>
|
||||
<div class="admin-stat-value" id="stat-active-users" aria-labelledby="lbl-active-users">--</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats Row 2 -->
|
||||
<div class="admin-stats-grid" id="stats-row-2">
|
||||
<div class="admin-stat-card">
|
||||
<div class="admin-stat-icon purple">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z"/><path fill-rule="evenodd" d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm9.707 5.707a1 1 0 00-1.414-1.414L9 12.586l-1.293-1.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg>
|
||||
<div class="admin-stat-icon purple" aria-hidden="true">
|
||||
<svg class="icon" role="img"><use href="/vendor/bootstrap-italia/dist/svg/sprites.svg#it-check"></use></svg>
|
||||
</div>
|
||||
<div class="admin-stat-label">Assessment Completati</div>
|
||||
<div class="admin-stat-value" id="stat-assessments">--</div>
|
||||
<div class="admin-stat-label" id="lbl-assessments">Assessment Completati</div>
|
||||
<div class="admin-stat-value" id="stat-assessments" aria-labelledby="lbl-assessments">--</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="admin-stat-icon orange">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path d="M10 2a6 6 0 00-6 6v3.586l-.707.707A1 1 0 004 14h12a1 1 0 00.707-1.707L16 11.586V8a6 6 0 00-6-6zM10 18a3 3 0 01-3-3h6a3 3 0 01-3 3z"/></svg>
|
||||
<div class="admin-stat-icon orange" aria-hidden="true">
|
||||
<svg class="icon" role="img"><use href="/vendor/bootstrap-italia/dist/svg/sprites.svg#it-warning-circle"></use></svg>
|
||||
</div>
|
||||
<div class="admin-stat-label">Incidenti Aperti</div>
|
||||
<div class="admin-stat-value" id="stat-incidents">--</div>
|
||||
<div class="admin-stat-label" id="lbl-incidents">Incidenti Aperti</div>
|
||||
<div class="admin-stat-value" id="stat-incidents" aria-labelledby="lbl-incidents">--</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="admin-stat-icon red">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 1.944A11.954 11.954 0 012.166 5C2.056 5.649 2 6.319 2 7c0 5.225 3.34 9.67 8 11.317C14.66 16.67 18 12.225 18 7c0-.682-.057-1.35-.166-2.001A11.954 11.954 0 0110 1.944zM11 14a1 1 0 11-2 0 1 1 0 012 0zm0-7a1 1 0 10-2 0v3a1 1 0 102 0V7z" clip-rule="evenodd"/></svg>
|
||||
<div class="admin-stat-icon red" aria-hidden="true">
|
||||
<svg class="icon" role="img"><use href="/vendor/bootstrap-italia/dist/svg/sprites.svg#it-error"></use></svg>
|
||||
</div>
|
||||
<div class="admin-stat-label">Totale Rischi</div>
|
||||
<div class="admin-stat-value" id="stat-risks">--</div>
|
||||
<div class="admin-stat-label" id="lbl-risks">Totale Rischi</div>
|
||||
<div class="admin-stat-value" id="stat-risks" aria-labelledby="lbl-risks">--</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="admin-stat-icon purple">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path d="M5 2a1 1 0 011 1v1h1a1 1 0 010 2H6v1a1 1 0 01-2 0V6H3a1 1 0 010-2h1V3a1 1 0 011-1zm0 10a1 1 0 011 1v1h1a1 1 0 110 2H6v1a1 1 0 11-2 0v-1H3a1 1 0 110-2h1v-1a1 1 0 011-1zm7-10a1 1 0 01.967.744L14.146 7.2 17.5 8.512a1 1 0 010 1.836l-3.354 1.311-1.18 4.456a1 1 0 01-1.932 0L9.854 11.66 6.5 10.348a1 1 0 010-1.836l3.354-1.311 1.18-4.456A1 1 0 0112 2z"/></svg>
|
||||
<div class="admin-stat-icon purple" aria-hidden="true">
|
||||
<svg class="icon" role="img"><use href="/vendor/bootstrap-italia/dist/svg/sprites.svg#it-software"></use></svg>
|
||||
</div>
|
||||
<div class="admin-stat-label">Interazioni AI</div>
|
||||
<div class="admin-stat-value" id="stat-ai">--</div>
|
||||
<div class="admin-stat-label" id="lbl-ai">Interazioni AI</div>
|
||||
<div class="admin-stat-value" id="stat-ai" aria-labelledby="lbl-ai">--</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -255,7 +266,7 @@
|
||||
<h3>Distribuzione Piani</h3>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<div class="bar-chart" id="plans-chart">
|
||||
<div class="bar-chart" id="plans-chart" role="img" aria-label="Grafico a barre: distribuzione delle organizzazioni per piano di sottoscrizione">
|
||||
<div class="spinner" style="margin:40px auto;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -267,10 +278,10 @@
|
||||
<h3>Gestione Piattaforma</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="quick-links-grid">
|
||||
<nav class="quick-links-grid" aria-label="Collegamenti rapidi gestione piattaforma">
|
||||
<a href="/admin/organizations.html" class="quick-link-card">
|
||||
<div class="quick-link-icon">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path d="M4 4a2 2 0 012-2h8a2 2 0 012 2v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z"/></svg>
|
||||
<div class="quick-link-icon" aria-hidden="true">
|
||||
<svg class="icon" role="img"><use href="/vendor/bootstrap-italia/dist/svg/sprites.svg#it-pa"></use></svg>
|
||||
</div>
|
||||
<div class="quick-link-info">
|
||||
<h4>Gestisci Organizzazioni</h4>
|
||||
@@ -278,15 +289,15 @@
|
||||
</div>
|
||||
</a>
|
||||
<a href="/admin/users.html" class="quick-link-card">
|
||||
<div class="quick-link-icon">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z"/></svg>
|
||||
<div class="quick-link-icon" aria-hidden="true">
|
||||
<svg class="icon" role="img"><use href="/vendor/bootstrap-italia/dist/svg/sprites.svg#it-user"></use></svg>
|
||||
</div>
|
||||
<div class="quick-link-info">
|
||||
<h4>Gestisci Utenti</h4>
|
||||
<p>Visualizza e gestisci tutti gli utenti registrati sulla piattaforma.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -295,6 +306,16 @@
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/common.js"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
riusando tutti gli helper di common.js (zero backend). -->
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script>
|
||||
if (window.bootstrap && bootstrap.loadFonts) {
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js"></script>
|
||||
<script src="/js/i18n.js"></script>
|
||||
<script>
|
||||
// ── Auth check ───────────────────────────────────────────
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Gestione Organizzazioni - NIS2 Agile</title>
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
|
||||
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
|
||||
via JS (tabella org/paginazione/badge) -> parita' funzionale assoluta. BI veste la chrome.
|
||||
Path relativi ../ perche' la pagina vive sotto public/admin/. -->
|
||||
<link rel="stylesheet" href="../vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<style>
|
||||
.entity-type-badge {
|
||||
display: inline-flex;
|
||||
@@ -89,10 +94,11 @@
|
||||
.admin-breadcrumb a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.admin-breadcrumb svg {
|
||||
.admin-breadcrumb .icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
color: var(--gray-400);
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -102,7 +108,7 @@
|
||||
|
||||
<main class="main-content">
|
||||
<header class="content-header">
|
||||
<h2>Gestione Organizzazioni</h2>
|
||||
<h1 class="h2">Gestione Organizzazioni</h1>
|
||||
<div class="content-header-actions">
|
||||
<span class="badge badge-danger">Super Admin</span>
|
||||
</div>
|
||||
@@ -110,17 +116,17 @@
|
||||
|
||||
<div class="content-body">
|
||||
<!-- Breadcrumb -->
|
||||
<div class="admin-breadcrumb">
|
||||
<a href="/admin/index.html">Amministrazione</a>
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/></svg>
|
||||
<span>Organizzazioni</span>
|
||||
</div>
|
||||
<nav class="admin-breadcrumb" aria-label="Percorso di navigazione">
|
||||
<a href="../admin/index.html">Amministrazione</a>
|
||||
<svg class="icon icon-sm" aria-hidden="true"><use href="../vendor/bootstrap-italia/dist/svg/sprites.svg#it-chevron-right"></use></svg>
|
||||
<span aria-current="page">Organizzazioni</span>
|
||||
</nav>
|
||||
|
||||
<!-- Table -->
|
||||
<div class="card">
|
||||
<div class="card-body" style="padding:0;">
|
||||
<div id="orgs-container">
|
||||
<div class="spinner" style="margin:60px auto;"></div>
|
||||
<div class="spinner" style="margin:60px auto;" role="status" aria-label="Caricamento in corso"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -128,9 +134,19 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/common.js"></script>
|
||||
<script src="/js/i18n.js"></script>
|
||||
<script src="../js/api.js"></script>
|
||||
<script src="../js/common.js"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
riusando tutti gli helper di common.js (zero backend). -->
|
||||
<script src="../vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script>
|
||||
if (window.bootstrap && bootstrap.loadFonts) {
|
||||
bootstrap.loadFonts('../vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="../js/common-bi.js"></script>
|
||||
<script src="../js/i18n.js"></script>
|
||||
<script>
|
||||
// ── Auth check ───────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
@@ -176,7 +192,7 @@
|
||||
// ── Caricamento ──────────────────────────────────────────
|
||||
async function loadOrganizations(page) {
|
||||
const container = document.getElementById('orgs-container');
|
||||
container.innerHTML = '<div class="spinner" style="margin:60px auto;"></div>';
|
||||
container.innerHTML = '<div class="spinner" style="margin:60px auto;" role="status" aria-label="Caricamento in corso"></div>';
|
||||
currentPage = page;
|
||||
|
||||
try {
|
||||
@@ -201,7 +217,7 @@
|
||||
if (!orgs || orgs.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path d="M4 4a2 2 0 012-2h8a2 2 0 012 2v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z"/></svg>
|
||||
<svg class="icon" aria-hidden="true" style="width:48px;height:48px;fill:var(--gray-300);"><use href="../vendor/bootstrap-italia/dist/svg/sprites.svg#it-pa"></use></svg>
|
||||
<h4>Nessuna organizzazione trovata</h4>
|
||||
<p>Le organizzazioni registrate appariranno qui.</p>
|
||||
</div>`;
|
||||
@@ -213,14 +229,14 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nome</th>
|
||||
<th>Settore</th>
|
||||
<th>Tipo Entita'</th>
|
||||
<th>Membri</th>
|
||||
<th>Ultimo Score</th>
|
||||
<th>Piano</th>
|
||||
<th>Stato</th>
|
||||
<th>Data Creazione</th>
|
||||
<th scope="col">Nome</th>
|
||||
<th scope="col">Settore</th>
|
||||
<th scope="col">Tipo Entita'</th>
|
||||
<th scope="col">Membri</th>
|
||||
<th scope="col">Ultimo Score</th>
|
||||
<th scope="col">Piano</th>
|
||||
<th scope="col">Stato</th>
|
||||
<th scope="col">Data Creazione</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>`;
|
||||
|
||||
+50
-31
@@ -4,7 +4,12 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Gestione Utenti - NIS2 Agile</title>
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
|
||||
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
|
||||
via JS (tabella utenti/azioni) -> parita' funzionale assoluta. BI veste la chrome.
|
||||
Path ../ perche' questa pagina vive in /admin/. -->
|
||||
<link rel="stylesheet" href="../vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
|
||||
<link rel="stylesheet" href="../css/style.css">
|
||||
<style>
|
||||
.role-badge {
|
||||
display: inline-flex;
|
||||
@@ -59,6 +64,11 @@
|
||||
.active-toggle input:checked + .toggle-slider::after {
|
||||
transform: translateX(16px);
|
||||
}
|
||||
/* Focus visibile WCAG su toggle keyboard-operabile */
|
||||
.active-toggle input:focus-visible + .toggle-slider {
|
||||
outline: 2px solid var(--primary, #06c);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -109,9 +119,7 @@
|
||||
.admin-breadcrumb a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.admin-breadcrumb svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
.admin-breadcrumb .icon {
|
||||
color: var(--gray-400);
|
||||
}
|
||||
</style>
|
||||
@@ -122,7 +130,7 @@
|
||||
|
||||
<main class="main-content">
|
||||
<header class="content-header">
|
||||
<h2>Gestione Utenti</h2>
|
||||
<h1 class="h2">Gestione Utenti</h1>
|
||||
<div class="content-header-actions">
|
||||
<span class="badge badge-danger">Super Admin</span>
|
||||
</div>
|
||||
@@ -130,17 +138,17 @@
|
||||
|
||||
<div class="content-body">
|
||||
<!-- Breadcrumb -->
|
||||
<div class="admin-breadcrumb">
|
||||
<a href="/admin/index.html">Amministrazione</a>
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/></svg>
|
||||
<span>Utenti</span>
|
||||
</div>
|
||||
<nav class="admin-breadcrumb" aria-label="Percorso di navigazione">
|
||||
<a href="../admin/index.html">Amministrazione</a>
|
||||
<svg class="icon icon-sm" aria-hidden="true"><use href="../vendor/bootstrap-italia/dist/svg/sprites.svg#it-chevron-right"></use></svg>
|
||||
<span aria-current="page">Utenti</span>
|
||||
</nav>
|
||||
|
||||
<!-- Table -->
|
||||
<div class="card">
|
||||
<div class="card-body" style="padding:0;">
|
||||
<div id="users-container">
|
||||
<div class="spinner" style="margin:60px auto;"></div>
|
||||
<div id="users-container" aria-live="polite">
|
||||
<div class="spinner" style="margin:60px auto;" role="status" aria-label="Caricamento utenti"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -148,9 +156,19 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/common.js"></script>
|
||||
<script src="/js/i18n.js"></script>
|
||||
<script src="../js/api.js"></script>
|
||||
<script src="../js/common.js"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
riusando tutti gli helper di common.js (zero backend). -->
|
||||
<script src="../vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script>
|
||||
if (window.bootstrap && bootstrap.loadFonts) {
|
||||
bootstrap.loadFonts('../vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="../js/common-bi.js"></script>
|
||||
<script src="../js/i18n.js"></script>
|
||||
<script>
|
||||
// ── Auth check ───────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
@@ -165,12 +183,12 @@
|
||||
const me = await api.getMe();
|
||||
if (!me.success || !me.data || me.data.role !== 'super_admin') {
|
||||
showNotification('Accesso non autorizzato.', 'error');
|
||||
setTimeout(() => { window.location.href = '/dashboard.html'; }, 1500);
|
||||
setTimeout(() => { window.location.href = '../dashboard.html'; }, 1500);
|
||||
return;
|
||||
}
|
||||
loadUsers(1);
|
||||
} catch (e) {
|
||||
window.location.href = '/dashboard.html';
|
||||
window.location.href = '../dashboard.html';
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -187,7 +205,7 @@
|
||||
// ── Caricamento ──────────────────────────────────────────
|
||||
async function loadUsers(page) {
|
||||
const container = document.getElementById('users-container');
|
||||
container.innerHTML = '<div class="spinner" style="margin:60px auto;"></div>';
|
||||
container.innerHTML = '<div class="spinner" style="margin:60px auto;" role="status" aria-label="Caricamento utenti"></div>';
|
||||
currentPage = page;
|
||||
|
||||
try {
|
||||
@@ -212,7 +230,7 @@
|
||||
if (!users || users.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<svg viewBox="0 0 20 20" fill="currentColor"><path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z"/></svg>
|
||||
<svg class="icon icon-lg" aria-hidden="true" style="margin:0 auto;"><use href="../vendor/bootstrap-italia/dist/svg/sprites.svg#it-user"></use></svg>
|
||||
<h4>Nessun utente trovato</h4>
|
||||
<p>Gli utenti registrati appariranno qui.</p>
|
||||
</div>`;
|
||||
@@ -224,14 +242,14 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nome</th>
|
||||
<th>Email</th>
|
||||
<th>Ruolo</th>
|
||||
<th>Organizzazioni</th>
|
||||
<th>Ultimo Login</th>
|
||||
<th>Attivo</th>
|
||||
<th>Data Creazione</th>
|
||||
<th>Azioni</th>
|
||||
<th scope="col">Nome</th>
|
||||
<th scope="col">Email</th>
|
||||
<th scope="col">Ruolo</th>
|
||||
<th scope="col">Organizzazioni</th>
|
||||
<th scope="col">Ultimo Login</th>
|
||||
<th scope="col">Attivo</th>
|
||||
<th scope="col">Data Creazione</th>
|
||||
<th scope="col">Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>`;
|
||||
@@ -266,15 +284,16 @@
|
||||
<td>${lastLogin}</td>
|
||||
<td>
|
||||
<label class="active-toggle" title="${isActive ? 'Attivo' : 'Inattivo'}">
|
||||
<input type="checkbox" ${isActive ? 'checked' : ''} onchange="toggleUserActive(${user.id}, this.checked)" ${role === 'super_admin' ? 'disabled' : ''}>
|
||||
<span class="toggle-slider"></span>
|
||||
<span class="visually-hidden">Stato attivo utente ${escapeHtml(user.email || '')}</span>
|
||||
<input type="checkbox" ${isActive ? 'checked' : ''} onchange="toggleUserActive(${user.id}, this.checked)" ${role === 'super_admin' ? 'disabled' : ''} aria-label="${isActive ? 'Disattiva' : 'Attiva'} utente ${escapeHtml(user.email || '')}">
|
||||
<span class="toggle-slider" aria-hidden="true"></span>
|
||||
</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>
|
||||
<svg class="icon icon-sm" aria-hidden="true" style="vertical-align:-2px"><use href="../vendor/bootstrap-italia/dist/svg/sprites.svg#it-exchange-circle"></use></svg>
|
||||
Impersonate
|
||||
</button>`
|
||||
: '<span class="text-muted">-</span>'}
|
||||
@@ -355,7 +374,7 @@
|
||||
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';
|
||||
window.location.href = '../dashboard.html';
|
||||
} else {
|
||||
showNotification(res.message || 'Impersonate fallito.', 'error');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user