[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
+45
-31
@@ -4,6 +4,10 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Gestione Incidenti - NIS2 Agile</title>
|
||||
<!-- 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 (tabelle/decision-tree/modali) -> parita' funzionale assoluta. BI veste la chrome. -->
|
||||
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<style>
|
||||
/* ── Filters Bar ─────────────────────────────────────── */
|
||||
@@ -262,7 +266,7 @@
|
||||
|
||||
<main class="main-content">
|
||||
<header class="content-header">
|
||||
<h2 data-i18n="incidents.title">Gestione Incidenti</h2>
|
||||
<h1 class="h2" data-i18n="incidents.title">Gestione Incidenti</h1>
|
||||
<div class="content-header-actions">
|
||||
<button class="btn btn-primary" onclick="showCreateIncidentModal()">+ Nuovo Incidente</button>
|
||||
</div>
|
||||
@@ -272,7 +276,7 @@
|
||||
<!-- List View -->
|
||||
<div id="view-list">
|
||||
<div class="filters-bar">
|
||||
<select class="form-select" id="filter-classification" onchange="loadIncidents()">
|
||||
<select class="form-select" id="filter-classification" onchange="loadIncidents()" aria-label="Filtra per classificazione">
|
||||
<option value="">Tutte le classificazioni</option>
|
||||
<option value="cyber_attack">Attacco Cyber</option>
|
||||
<option value="data_breach">Data Breach</option>
|
||||
@@ -282,14 +286,14 @@
|
||||
<option value="supply_chain">Supply Chain</option>
|
||||
<option value="other">Altro</option>
|
||||
</select>
|
||||
<select class="form-select" id="filter-severity" onchange="loadIncidents()">
|
||||
<select class="form-select" id="filter-severity" onchange="loadIncidents()" aria-label="Filtra per gravità">
|
||||
<option value="">Tutte le severita'</option>
|
||||
<option value="critical">Critico</option>
|
||||
<option value="high">Alto</option>
|
||||
<option value="medium">Medio</option>
|
||||
<option value="low">Basso</option>
|
||||
</select>
|
||||
<select class="form-select" id="filter-status" onchange="loadIncidents()">
|
||||
<select class="form-select" id="filter-status" onchange="loadIncidents()" aria-label="Filtra per stato">
|
||||
<option value="">Tutti gli stati</option>
|
||||
<option value="detected">Rilevato</option>
|
||||
<option value="analyzing">In Analisi</option>
|
||||
@@ -336,6 +340,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 src="/js/help.js"></script>
|
||||
<script>
|
||||
@@ -467,7 +481,7 @@
|
||||
<div class="nis2-compact">
|
||||
<span class="nis2-dot ${ew}" title="Early Warning 24h"></span>
|
||||
<span class="nis2-dot ${nt}" title="Notifica 72h"></span>
|
||||
<span class="nis2-dot ${fr}" title="Report Finale 30gg"></span>
|
||||
<span class="nis2-dot ${fr}" title="Report Finale 1 mese"></span>
|
||||
${ew === 'overdue' || nt === 'overdue' || fr === 'overdue'
|
||||
? '<span class="overdue-icon"><svg width="14" height="14" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/></svg></span>'
|
||||
: ''}
|
||||
@@ -485,16 +499,16 @@
|
||||
|
||||
const content = `
|
||||
<div class="form-group">
|
||||
<label class="form-label">Titolo <span class="required">*</span></label>
|
||||
<label for="inc-title" class="form-label">Titolo <span class="required">*</span></label>
|
||||
<input type="text" class="form-input" id="inc-title" placeholder="Titolo dell'incidente">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Descrizione <span class="required">*</span></label>
|
||||
<label for="inc-description" class="form-label">Descrizione <span class="required">*</span></label>
|
||||
<textarea class="form-textarea" id="inc-description" rows="3" placeholder="Descrizione dettagliata dell'incidente"></textarea>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Classificazione</label>
|
||||
<label for="inc-classification" class="form-label">Classificazione</label>
|
||||
<select class="form-select" id="inc-classification">
|
||||
<option value="cyber_attack">Attacco Cyber</option>
|
||||
<option value="data_breach">Data Breach</option>
|
||||
@@ -506,7 +520,7 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Severita'</label>
|
||||
<label for="inc-severity" class="form-label">Severita'</label>
|
||||
<select class="form-select" id="inc-severity">
|
||||
<option value="low">Basso</option>
|
||||
<option value="medium" selected>Medio</option>
|
||||
@@ -516,7 +530,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Data e ora rilevamento <span class="required">*</span></label>
|
||||
<label for="inc-detected-at" class="form-label">Data e ora rilevamento <span class="required">*</span></label>
|
||||
<input type="datetime-local" class="form-input" id="inc-detected-at" value="${dtLocal}">
|
||||
</div>
|
||||
<!-- Decision tree Art.23 NIS2 - significativita' incidente -->
|
||||
@@ -527,23 +541,23 @@
|
||||
</div>
|
||||
<p style="font-size:0.75rem; color:var(--gray-500); margin-bottom:10px;">Un incidente e' significativo se soddisfa almeno uno dei criteri seguenti (Considerando 101 NIS2 / D.Lgs. 138/2024 art. 25):</p>
|
||||
<div style="display:grid; gap:6px;">
|
||||
<label style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
|
||||
<label for="crit-users" style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
|
||||
<input type="checkbox" id="crit-users" onchange="evalSignificance()" style="accent-color:var(--primary); width:16px; height:16px;">
|
||||
<span>Ha causato o puo' causare interruzione grave dei servizi per <strong>≥500 utenti</strong></span>
|
||||
</label>
|
||||
<label style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
|
||||
<label for="crit-duration" style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
|
||||
<input type="checkbox" id="crit-duration" onchange="evalSignificance()" style="accent-color:var(--primary); width:16px; height:16px;">
|
||||
<span>Durata dell'interruzione superiore a <strong>4 ore</strong></span>
|
||||
</label>
|
||||
<label style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
|
||||
<label for="crit-crossborder" style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
|
||||
<input type="checkbox" id="crit-crossborder" onchange="evalSignificance()" style="accent-color:var(--primary); width:16px; height:16px;">
|
||||
<span>Impatto su altri Stati Membri UE (impatto transfrontaliero)</span>
|
||||
</label>
|
||||
<label style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
|
||||
<label for="crit-attack" style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
|
||||
<input type="checkbox" id="crit-attack" onchange="evalSignificance()" style="accent-color:var(--primary); width:16px; height:16px;">
|
||||
<span>E' un attacco cyber o data breach con dati personali coinvolti</span>
|
||||
</label>
|
||||
<label style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
|
||||
<label for="crit-financial" style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
|
||||
<input type="checkbox" id="crit-financial" onchange="evalSignificance()" style="accent-color:var(--primary); width:16px; height:16px;">
|
||||
<span>Perdita finanziaria stimata superiore a <strong>€100.000</strong></span>
|
||||
</label>
|
||||
@@ -551,29 +565,29 @@
|
||||
<div id="significance-result" style="margin-top:10px; padding:8px 12px; border-radius:6px; font-size:0.8rem; font-weight:600; display:none;"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-check-inline">
|
||||
<label for="inc-significant" class="form-check-inline">
|
||||
<input type="checkbox" id="inc-significant">
|
||||
<span><strong>Incidente significativo</strong> (richiede notifica CSIRT/ACN ai sensi dell'Art. 23 NIS2)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Servizi interessati</label>
|
||||
<label for="inc-affected-services" class="form-label">Servizi interessati</label>
|
||||
<textarea class="form-textarea" id="inc-affected-services" rows="2" placeholder="Elenco dei servizi e sistemi interessati"></textarea>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Utenti coinvolti</label>
|
||||
<label for="inc-affected-users" class="form-label">Utenti coinvolti</label>
|
||||
<input type="number" class="form-input" id="inc-affected-users" min="0" placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-check-inline">
|
||||
<label for="inc-cross-border" class="form-check-inline">
|
||||
<input type="checkbox" id="inc-cross-border">
|
||||
<span>Impatto transfrontaliero</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-check-inline">
|
||||
<label for="inc-malicious" class="form-check-inline">
|
||||
<input type="checkbox" id="inc-malicious">
|
||||
<span>Azione dolosa / malevola</span>
|
||||
</label>
|
||||
@@ -638,7 +652,7 @@
|
||||
|
||||
const content = `
|
||||
<div class="form-group">
|
||||
<label class="form-label">Stato</label>
|
||||
<label for="upd-status" class="form-label">Stato</label>
|
||||
<select class="form-select" id="upd-status">
|
||||
${Object.entries(STATUS_LABELS).map(([k, v]) =>
|
||||
`<option value="${k}" ${incident.status === k ? 'selected' : ''}>${v}</option>`
|
||||
@@ -646,15 +660,15 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Causa Radice</label>
|
||||
<label for="upd-root-cause" class="form-label">Causa Radice</label>
|
||||
<textarea class="form-textarea" id="upd-root-cause" rows="3" placeholder="Analisi della causa radice">${escapeHtml(incident.root_cause || '')}</textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Azioni di Rimedio</label>
|
||||
<label for="upd-remediation" class="form-label">Azioni di Rimedio</label>
|
||||
<textarea class="form-textarea" id="upd-remediation" rows="3" placeholder="Azioni correttive intraprese">${escapeHtml(incident.remediation_actions || '')}</textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Lezioni Apprese</label>
|
||||
<label for="upd-lessons" class="form-label">Lezioni Apprese</label>
|
||||
<textarea class="form-textarea" id="upd-lessons" rows="3" placeholder="Lezioni apprese dall'incidente">${escapeHtml(incident.lessons_learned || '')}</textarea>
|
||||
</div>
|
||||
`;
|
||||
@@ -904,7 +918,7 @@
|
||||
<div class="card-body" style="display:flex; flex-direction:column; gap:8px;">
|
||||
${!inc.early_warning_sent_at ? `<button class="btn btn-warning w-full" onclick="doSendEarlyWarning(${inc.id})">Invia Early Warning (24h)</button>` : `<button class="btn btn-success w-full" disabled>Early Warning Inviato</button>`}
|
||||
${!inc.notification_sent_at ? `<button class="btn btn-warning w-full" onclick="doSendNotification(${inc.id})">Invia Notifica (72h)</button>` : `<button class="btn btn-success w-full" disabled>Notifica Inviata</button>`}
|
||||
${!inc.final_report_sent_at ? `<button class="btn btn-warning w-full" onclick="doSendFinalReport(${inc.id})">Invia Report Finale (30gg)</button>` : `<button class="btn btn-success w-full" disabled>Report Finale Inviato</button>`}
|
||||
${!inc.final_report_sent_at ? `<button class="btn btn-warning w-full" onclick="doSendFinalReport(${inc.id})">Invia Report Finale (1 mese)</button>` : `<button class="btn btn-success w-full" disabled>Report Finale Inviato</button>`}
|
||||
</div>
|
||||
</div>` : ''}
|
||||
</div>
|
||||
@@ -932,10 +946,10 @@
|
||||
actionLabel: 'Invia Notifica'
|
||||
},
|
||||
{
|
||||
title: 'Report Finale (30 giorni)',
|
||||
title: 'Report Finale (1 mese)',
|
||||
dueDate: inc.final_report_due,
|
||||
sentAt: inc.final_report_sent_at,
|
||||
description: 'Report finale completo con analisi della causa radice, impatto e lezioni apprese entro 30 giorni.',
|
||||
description: 'Report finale completo con analisi della causa radice, impatto e lezioni apprese entro 1 mese.',
|
||||
action: `doSendFinalReport(${inc.id})`,
|
||||
actionLabel: 'Invia Report Finale'
|
||||
}
|
||||
@@ -1092,7 +1106,7 @@
|
||||
|
||||
async function doSendFinalReport(id) {
|
||||
showModal('Conferma Report Finale', `
|
||||
<p>Stai per registrare l'invio del <strong>Report Finale (30 giorni)</strong> al CSIRT nazionale (ACN).</p>
|
||||
<p>Stai per registrare l'invio del <strong>Report Finale (1 mese)</strong> al CSIRT nazionale (ACN).</p>
|
||||
<p class="text-muted" style="margin-top:8px; font-size:0.85rem;">
|
||||
Il report finale deve includere la descrizione dettagliata dell'incidente, la causa radice,
|
||||
le misure di mitigazione applicate e l'impatto transfrontaliero, se applicabile.
|
||||
@@ -1125,7 +1139,7 @@
|
||||
function showAddEventModal(incidentId) {
|
||||
const content = `
|
||||
<div class="form-group">
|
||||
<label class="form-label">Tipo Evento</label>
|
||||
<label for="event-type" class="form-label">Tipo Evento</label>
|
||||
<select class="form-select" id="event-type">
|
||||
<option value="detection">Rilevamento</option>
|
||||
<option value="analysis">Analisi</option>
|
||||
@@ -1139,7 +1153,7 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Descrizione <span class="required">*</span></label>
|
||||
<label for="event-description" class="form-label">Descrizione <span class="required">*</span></label>
|
||||
<textarea class="form-textarea" id="event-description" rows="3" placeholder="Descrizione dell'evento"></textarea>
|
||||
</div>
|
||||
`;
|
||||
@@ -1198,7 +1212,7 @@
|
||||
resultDiv.style.background = '#fef2f2';
|
||||
resultDiv.style.border = '1px solid #fca5a5';
|
||||
resultDiv.style.color = 'var(--danger)';
|
||||
resultDiv.innerHTML = '⚠ ' + checkedCount + ' criteri soddisfatti — l\'incidente e\' probabilmente <strong>SIGNIFICATIVO</strong>. Attivare le notifiche Art. 23 (24h/72h/30gg).';
|
||||
resultDiv.innerHTML = '⚠ ' + checkedCount + ' criteri soddisfatti — l\'incidente e\' probabilmente <strong>SIGNIFICATIVO</strong>. Attivare le notifiche Art. 23 (24h/72h/1 mese).';
|
||||
if (sigCheckbox) sigCheckbox.checked = true;
|
||||
} else {
|
||||
resultDiv.style.background = '#f0fdf4';
|
||||
|
||||
Reference in New Issue
Block a user