[FEAT] Gap Analysis ACN: frontend (acn-gap.html + sidebar + api.js)
- public/acn-gap.html: catalogo requisiti consultabile, wizard per funzione FW con accordion misure/requisiti, opzioni attuato/parziale/non attuato/N.A., autosave batch debounce, risultati con punteggio per funzione + piano d'azione gap + analisi AI. Badge livello soggetto (importante/essenziale). IT/EN inline. - api.js: metodi acn* (catalog/list/create/requirements/respond/complete/report/ aiAnalyze) che spacchettano l'envelope e lanciano errore su success=false. - common.js: voce sidebar "Gap Analysis ACN". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
ea2a291325
commit
91043d7391
@@ -179,6 +179,31 @@ class NIS2API {
|
||||
getAssessmentReport(id) { return this.get(`/assessments/${id}/report`); }
|
||||
aiAnalyzeAssessment(id) { return this.post(`/assessments/${id}/ai-analyze`, {}); }
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// Gap Analysis ACN (Determinazione 164179/2025 - misure/requisiti)
|
||||
// I metodi acn* ritornano direttamente il payload `data` e lanciano
|
||||
// un errore {message, error_code} se success=false (per il try/catch UI).
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
async _acn(promise) {
|
||||
const r = await promise;
|
||||
if (!r || !r.success) {
|
||||
const err = new Error((r && r.message) || 'Errore');
|
||||
err.error_code = r && (r.error_code || (r.data && r.data.error_code));
|
||||
err.data = r && r.data;
|
||||
throw err;
|
||||
}
|
||||
return r.data;
|
||||
}
|
||||
acnCatalog() { return this._acn(this.get('/acn-gap/catalog')); }
|
||||
acnList() { return this._acn(this.get('/acn-gap/list')); }
|
||||
acnCreate(data) { return this._acn(this.post('/acn-gap/create', data || {})); }
|
||||
acnGet(id) { return this._acn(this.get(`/acn-gap/${id}`)); }
|
||||
acnRequirements(id) { return this._acn(this.get(`/acn-gap/${id}/requirements`)); }
|
||||
acnRespond(id, data) { return this._acn(this.post(`/acn-gap/${id}/respond`, data)); }
|
||||
acnComplete(id) { return this._acn(this.post(`/acn-gap/${id}/complete`, {})); }
|
||||
acnReport(id) { return this._acn(this.get(`/acn-gap/${id}/report`)); }
|
||||
acnAiAnalyze(id) { return this._acn(this.post(`/acn-gap/${id}/aiAnalyze`, {})); }
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// Dashboard
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -188,6 +188,7 @@ function loadSidebar() {
|
||||
{ name: 'Dashboard', href: 'dashboard.html', icon: iconGrid(), i18nKey: 'nav.dashboard' },
|
||||
{ name: 'Compliance Journey', href: 'workflow.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"/></svg>` },
|
||||
{ name: 'Gap Analysis', href: 'assessment.html', icon: iconClipboardCheck(), i18nKey: 'nav.gap_analysis' },
|
||||
{ name: 'Gap Analysis ACN', href: 'acn-gap.html', icon: iconClipboardCheck(), i18nKey: 'nav.acn_gap' },
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user