[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
+55
-1
@@ -869,6 +869,60 @@
|
||||
|
||||
// ── Initial Load ────────────────────────────────────────
|
||||
loadAssets();
|
||||
</script>
|
||||
|
||||
/* ── Import asset CMDB/CSV (P2) ───────────────────────────── */
|
||||
function openImportModal(){
|
||||
const body = `
|
||||
<p style="font-size:.85rem;color:var(--gray-600);margin-bottom:10px;">Incolla CSV o carica un file. Colonne riconosciute:
|
||||
<code>name, asset_type, criticality, data_classification, internet_facing, dependencies_count, regulated, external_ref, vendor, location</code>.
|
||||
Lo scoring di rilevanza NIS2 (GV.OC-04) viene calcolato automaticamente.</p>
|
||||
<div class="form-group"><input type="file" accept=".csv,text/csv" id="imp-file" onchange="impFile(event)"></div>
|
||||
<div class="form-group"><label class="form-label">Oppure incolla CSV (prima riga = intestazioni)</label>
|
||||
<textarea class="form-input" id="imp-csv" rows="8" placeholder="name,asset_type,criticality,data_classification,internet_facing,dependencies_count,regulated
|
||||
Core ERP,software,critical,financial,false,8,true
|
||||
Web Portal,service,high,personal,true,3,true"></textarea></div>
|
||||
<div id="imp-preview" style="font-size:.8rem;color:var(--gray-600);"></div>`;
|
||||
showModal('Importa Asset', body, {
|
||||
size:'lg',
|
||||
footer:`<button class="btn btn-secondary" onclick="closeModal()">Annulla</button>
|
||||
<button class="btn btn-primary" onclick="doImport()">Importa</button>`
|
||||
});
|
||||
}
|
||||
function impFile(e){
|
||||
const f=e.target.files[0]; if(!f)return;
|
||||
const r=new FileReader(); r.onload=()=>{document.getElementById('imp-csv').value=r.result;}; r.readAsText(f);
|
||||
}
|
||||
function parseCsv(text){
|
||||
const lines=text.trim().split(/\r?\n/).filter(l=>l.trim());
|
||||
if(lines.length<2)return [];
|
||||
const headers=lines[0].split(',').map(h=>h.trim().toLowerCase());
|
||||
const truthy=v=>/^(1|true|si|sì|yes|y)$/i.test((v||'').trim());
|
||||
return lines.slice(1).map(line=>{
|
||||
const cells=line.split(','); const o={};
|
||||
headers.forEach((h,i)=>{ o[h]=(cells[i]||'').trim(); });
|
||||
const a={name:o.name, asset_type:o.asset_type, criticality:o.criticality,
|
||||
data_classification:o.data_classification, vendor:o.vendor, location:o.location,
|
||||
external_ref:o.external_ref};
|
||||
if('internet_facing' in o) a.internet_facing=truthy(o.internet_facing);
|
||||
if('regulated' in o) a.regulated=truthy(o.regulated);
|
||||
if('dependencies_count' in o) a.dependencies_count=parseInt(o.dependencies_count)||0;
|
||||
return a;
|
||||
}).filter(a=>a.name);
|
||||
}
|
||||
async function doImport(){
|
||||
const assets=parseCsv(document.getElementById('imp-csv').value);
|
||||
if(!assets.length){showNotification('Nessuna riga valida (serve almeno name)','warning');return;}
|
||||
try{
|
||||
const res=await api.importAssets({source:'csv', assets});
|
||||
if(res.success){
|
||||
const d=res.data;
|
||||
closeModal();
|
||||
showNotification(`Import: ${d.imported} nuovi, ${d.updated} aggiornati, ${d.relevant} rilevanti NIS2, ${d.skipped} scartati`,'success');
|
||||
if(typeof loadAssets==='function')loadAssets();
|
||||
} else showNotification(res.message||'Errore import','error');
|
||||
}catch(e){showNotification('Errore di connessione','error');}
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user