[FEAT] UI frontend gap competitivi + help/i18n + OpenAPI + scorecard EVIX
UI delle 4 feature backend (ora usabili dagli utenti, non solo via API): - risks.html: vista 'Quantitativo (FAIR)' con form + istogramma distribuzione ALE + registro portafoglio; vista 'KRI' con dashboard semafori green/amber/red + CRUD - reports.html: tab 'Monitoraggio Continuo' con semafori freschezza controlli (healthy/warning/stale/failing) + copertura - assets.html: bottone 'Importa' CSV/CMDB con parsing client + anteprima + scoring auto GV.OC-04 - api.js: metodi computeFair/getFairRegister/listKri/createKri/updateKri/importAssets/getControlsMonitoring Trasversale: - help.js: sezioni guida FAIR+KRI (risks), import CMDB (assets), monitoraggio continuo (reports) - i18n.js: chiavi IT/EN (risks.fair_tab, risks.kri_tab, assets.import_btn, audit.monitoring_tab) - ServicesController::openapi esteso con incidents-ingest/evidence-ingest/assets-ingest/controls-monitoring + securityScheme ApiKeyAuth - AuditController::controlsMonitoring (versione JWT per la UI) + route audit/controlsMonitoring - EVIX scorecard: gap P1/P2 marcati chiusi (backend), roadmap aggiornata Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
edf0394616
commit
372ccb5ec1
@@ -359,6 +359,7 @@
|
||||
<button onclick="switchTab('controls', this)">Controlli</button>
|
||||
<button onclick="switchTab('audit', this)">Audit Log</button>
|
||||
<button onclick="switchTab('iso', this)">ISO 27001</button>
|
||||
<button onclick="switchTab('monitoring', this)" data-i18n="audit.monitoring_tab">Monitoraggio Continuo</button>
|
||||
</div>
|
||||
|
||||
<!-- Tab: Report Compliance -->
|
||||
@@ -401,6 +402,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab: Continuous Control Monitoring -->
|
||||
<div class="tab-panel" id="tab-monitoring">
|
||||
<div id="monitoring-container">
|
||||
<div class="loading-state">
|
||||
<div class="spinner"></div>
|
||||
<p>Caricamento monitoraggio...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
@@ -467,6 +478,46 @@
|
||||
if (tabId === 'controls') loadControls();
|
||||
if (tabId === 'audit') { auditPage = 1; loadAuditLogs(); }
|
||||
if (tabId === 'iso') loadIsoMapping();
|
||||
if (tabId === 'monitoring') loadMonitoring();
|
||||
}
|
||||
|
||||
// ── Continuous Control Monitoring (P1) ───────────────────────
|
||||
const MON_STATUS = {
|
||||
healthy: ['#22c55e', 'Sano'],
|
||||
warning: ['#eab308', 'Attenzione'],
|
||||
stale: ['#f97316', 'Evidenza scaduta'],
|
||||
failing: ['#ef4444', 'Non conforme'],
|
||||
not_monitored: ['#9ca3af', 'Non monitorato']
|
||||
};
|
||||
async function loadMonitoring() {
|
||||
const c = document.getElementById('monitoring-container');
|
||||
try {
|
||||
const res = await api.getControlsMonitoring();
|
||||
if (!res.success) { c.innerHTML = '<div class="empty-state-box"><p>' + escapeHtml(res.message || 'Errore') + '</p></div>'; return; }
|
||||
const d = res.data, s = d.summary || {};
|
||||
const cards = ['healthy','warning','stale','failing','not_monitored'].map(k =>
|
||||
`<div class="stat-box" style="border-left:4px solid ${MON_STATUS[k][0]};min-width:120px;">
|
||||
<div class="stat-value">${s[k] || 0}</div><div class="stat-label">${MON_STATUS[k][1]}</div></div>`).join('');
|
||||
const rows = (d.controls || []).map(ct => {
|
||||
const st = MON_STATUS[ct.monitoring_status] || MON_STATUS.not_monitored;
|
||||
return `<tr>
|
||||
<td><span style="display:inline-block;width:11px;height:11px;border-radius:50%;background:${st[0]};vertical-align:middle;" title="${st[1]}"></span> ${st[1]}</td>
|
||||
<td><code>${escapeHtml(ct.control_code)}</code></td>
|
||||
<td>${escapeHtml(ct.title || '')}</td>
|
||||
<td>${ct.last_checked_at || '<span style="color:var(--gray-400);">mai</span>'}</td>
|
||||
<td>${ct.freshness_days || 30} gg</td></tr>`;
|
||||
}).join('');
|
||||
c.innerHTML = `
|
||||
<p style="font-size:.85rem;color:var(--gray-600);margin-bottom:12px;">
|
||||
Stato di freschezza dei controlli alimentato dalle <strong>evidenze automatiche</strong> dai connettori (Evidence Automation).
|
||||
Copertura: <strong>${d.coverage_percent}%</strong> (${d.monitored}/${d.total_controls} controlli monitorati).</p>
|
||||
<div style="display:flex;gap:12px;flex-wrap:wrap;margin-bottom:16px;">${cards}</div>
|
||||
<table class="data-table"><thead><tr>
|
||||
<th>Stato</th><th>Controllo</th><th>Titolo</th><th>Ultima evidenza</th><th>Freschezza</th>
|
||||
</tr></thead><tbody>${rows || '<tr><td colspan="5" style="text-align:center;padding:20px;color:var(--gray-500);">Nessun controllo. Le evidenze arrivano via POST /api/services/evidence-ingest.</td></tr>'}</tbody></table>`;
|
||||
} catch (e) {
|
||||
c.innerHTML = '<div class="empty-state-box"><p>Errore di connessione</p></div>';
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user