[FEAT] Inventario Rilevanza NIS2: significato opzioni combo + dettaglio punteggio per criterio (ticket #431, #432)
- AssetScoringService::GRID: aggiunto campo 'desc' a tutte le 35 opzioni dei 6 criteri (significato operativo, additivo) - assets.html: ogni combo mostra il significato dell'opzione selezionata + nuovo box 'Dettaglio punteggio per criterio' (live, anche alla riapertura di una valutazione salvata) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
ea5966eaee
commit
cf23be9c77
@@ -33,12 +33,12 @@ class AssetScoringService
|
|||||||
'max' => 25,
|
'max' => 25,
|
||||||
'help' => 'Quanto il sistema e essenziale per l\'erogazione dei servizi core business.',
|
'help' => 'Quanto il sistema e essenziale per l\'erogazione dei servizi core business.',
|
||||||
'options' => [
|
'options' => [
|
||||||
'critical' => ['label' => 'Critico', 'points' => 25],
|
'critical' => ['label' => 'Critico', 'points' => 25, 'desc' => 'Sistema indispensabile: un suo fermo blocca subito i servizi core dell\'organizzazione.'],
|
||||||
'very_high' => ['label' => 'Molto Alto', 'points' => 20],
|
'very_high' => ['label' => 'Molto Alto', 'points' => 20, 'desc' => 'Sistema primario: un fermo degrada gravemente i servizi core, con alternative molto limitate.'],
|
||||||
'high' => ['label' => 'Alto', 'points' => 15],
|
'high' => ['label' => 'Alto', 'points' => 15, 'desc' => 'Sistema importante: il fermo rallenta i servizi core ma esistono alternative parziali.'],
|
||||||
'medium' => ['label' => 'Medio', 'points' => 10],
|
'medium' => ['label' => 'Medio', 'points' => 10, 'desc' => 'Sistema di supporto: il fermo ha impatto contenuto e gestibile sui servizi core.'],
|
||||||
'low' => ['label' => 'Basso', 'points' => 5],
|
'low' => ['label' => 'Basso', 'points' => 5, 'desc' => 'Sistema accessorio: il fermo incide poco sull\'operativita.'],
|
||||||
'negligible' => ['label' => 'Trascurabile', 'points' => 0],
|
'negligible' => ['label' => 'Trascurabile', 'points' => 0, 'desc' => 'Sistema non essenziale: nessun impatto pratico sui servizi core.'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'c2_disruption_impact' => [
|
'c2_disruption_impact' => [
|
||||||
@@ -46,12 +46,12 @@ class AssetScoringService
|
|||||||
'max' => 25,
|
'max' => 25,
|
||||||
'help' => 'Conseguenze di un\'interruzione in termini di durata e utenti impattati.',
|
'help' => 'Conseguenze di un\'interruzione in termini di durata e utenti impattati.',
|
||||||
'options' => [
|
'options' => [
|
||||||
'gt24h_gt70' => ['label' => '>24h + >70% utenti', 'points' => 25],
|
'gt24h_gt70' => ['label' => '>24h + >70% utenti', 'points' => 25, 'desc' => 'Interruzione oltre 24 ore che coinvolge piu del 70% degli utenti.'],
|
||||||
'h8_24_50_70' => ['label' => '8-24h + 50-70% utenti', 'points' => 20],
|
'h8_24_50_70' => ['label' => '8-24h + 50-70% utenti', 'points' => 20, 'desc' => 'Interruzione da 8 a 24 ore, dal 50 al 70% degli utenti coinvolti.'],
|
||||||
'h4_8_30_50' => ['label' => '4-8h + 30-50% utenti', 'points' => 15],
|
'h4_8_30_50' => ['label' => '4-8h + 30-50% utenti', 'points' => 15, 'desc' => 'Interruzione da 4 a 8 ore, dal 30 al 50% degli utenti coinvolti.'],
|
||||||
'h1_4_10_30' => ['label' => '1-4h + 10-30% utenti', 'points' => 10],
|
'h1_4_10_30' => ['label' => '1-4h + 10-30% utenti', 'points' => 10, 'desc' => 'Interruzione da 1 a 4 ore, dal 10 al 30% degli utenti coinvolti.'],
|
||||||
'lt1h_lt10' => ['label' => '<1h + <10% utenti', 'points' => 5],
|
'lt1h_lt10' => ['label' => '<1h + <10% utenti', 'points' => 5, 'desc' => 'Interruzione sotto 1 ora, meno del 10% degli utenti coinvolti.'],
|
||||||
'none' => ['label' => 'Nessun impatto', 'points' => 0],
|
'none' => ['label' => 'Nessun impatto', 'points' => 0, 'desc' => 'Nessun impatto operativo apprezzabile in caso di interruzione.'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'c3_data_processed' => [
|
'c3_data_processed' => [
|
||||||
@@ -59,11 +59,11 @@ class AssetScoringService
|
|||||||
'max' => 20,
|
'max' => 20,
|
||||||
'help' => 'Sensibilita e criticita dei dati gestiti dal sistema.',
|
'help' => 'Sensibilita e criticita dei dati gestiti dal sistema.',
|
||||||
'options' => [
|
'options' => [
|
||||||
'gdpr_art9' => ['label' => 'Dati Sensibili Art.9 GDPR', 'points' => 20],
|
'gdpr_art9' => ['label' => 'Dati Sensibili Art.9 GDPR', 'points' => 20, 'desc' => 'Categorie particolari di dati personali (salute, biometrici, ecc.) ai sensi dell\'Art.9 GDPR.'],
|
||||||
'personal_large' => ['label' => 'Dati Personali larga scala', 'points' => 15],
|
'personal_large' => ['label' => 'Dati Personali larga scala', 'points' => 15, 'desc' => 'Dati personali comuni trattati su larga scala.'],
|
||||||
'personal_fin' => ['label' => 'Dati Personali + Finanziari', 'points' => 10],
|
'personal_fin' => ['label' => 'Dati Personali + Finanziari', 'points' => 10, 'desc' => 'Dati personali insieme a dati finanziari o di pagamento.'],
|
||||||
'confidential' => ['label' => 'Dati Aziendali Riservati', 'points' => 5],
|
'confidential' => ['label' => 'Dati Aziendali Riservati', 'points' => 5, 'desc' => 'Dati aziendali riservati non personali (know-how, contratti).'],
|
||||||
'public' => ['label' => 'Dati Pubblici', 'points' => 0],
|
'public' => ['label' => 'Dati Pubblici', 'points' => 0, 'desc' => 'Solo dati pubblici o gia liberamente divulgabili.'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'c4_dependencies' => [
|
'c4_dependencies' => [
|
||||||
@@ -71,12 +71,12 @@ class AssetScoringService
|
|||||||
'max' => 15,
|
'max' => 15,
|
||||||
'help' => 'Quanti altri sistemi critici dipendono da questo sistema.',
|
'help' => 'Quanti altri sistemi critici dipendono da questo sistema.',
|
||||||
'options' => [
|
'options' => [
|
||||||
'ge5_critical' => ['label' => '>=5 sistemi critici', 'points' => 15],
|
'ge5_critical' => ['label' => '>=5 sistemi critici', 'points' => 15, 'desc' => 'Da questo sistema dipendono 5 o piu sistemi critici.'],
|
||||||
'n3_4_critical' => ['label' => '3-4 sistemi critici', 'points' => 12],
|
'n3_4_critical' => ['label' => '3-4 sistemi critici', 'points' => 12, 'desc' => 'Da questo sistema dipendono 3 o 4 sistemi critici.'],
|
||||||
'n2_critical' => ['label' => '2 sistemi critici', 'points' => 9],
|
'n2_critical' => ['label' => '2 sistemi critici', 'points' => 9, 'desc' => 'Da questo sistema dipendono 2 sistemi critici.'],
|
||||||
'n1_critical' => ['label' => '1 sistema critico', 'points' => 6],
|
'n1_critical' => ['label' => '1 sistema critico', 'points' => 6, 'desc' => 'Da questo sistema dipende 1 sistema critico.'],
|
||||||
'noncritical' => ['label' => '1-2 sistemi non critici', 'points' => 3],
|
'noncritical' => ['label' => '1-2 sistemi non critici', 'points' => 3, 'desc' => 'Dipendono solo 1-2 sistemi non critici.'],
|
||||||
'none' => ['label' => 'Nessuna dipendenza', 'points' => 0],
|
'none' => ['label' => 'Nessuna dipendenza', 'points' => 0, 'desc' => 'Nessun altro sistema dipende da questo.'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'c5_exposure' => [
|
'c5_exposure' => [
|
||||||
@@ -84,12 +84,12 @@ class AssetScoringService
|
|||||||
'max' => 10,
|
'max' => 10,
|
||||||
'help' => 'Superficie di attacco ed esposizione del sistema.',
|
'help' => 'Superficie di attacco ed esposizione del sistema.',
|
||||||
'options' => [
|
'options' => [
|
||||||
'internet_no_mfa' => ['label' => 'Internet pubblico senza MFA', 'points' => 10],
|
'internet_no_mfa' => ['label' => 'Internet pubblico senza MFA', 'points' => 10, 'desc' => 'Esposto su Internet pubblico senza autenticazione a piu fattori.'],
|
||||||
'internet_mfa' => ['label' => 'Internet con MFA', 'points' => 8],
|
'internet_mfa' => ['label' => 'Internet con MFA', 'points' => 8, 'desc' => 'Esposto su Internet ma protetto da autenticazione a piu fattori.'],
|
||||||
'partner_net' => ['label' => 'Reti partner/fornitori', 'points' => 6],
|
'partner_net' => ['label' => 'Reti partner/fornitori', 'points' => 6, 'desc' => 'Raggiungibile dalle reti di partner o fornitori.'],
|
||||||
'intranet' => ['label' => 'Rete aziendale intranet', 'points' => 4],
|
'intranet' => ['label' => 'Rete aziendale intranet', 'points' => 4, 'desc' => 'Raggiungibile solo dalla rete aziendale interna.'],
|
||||||
'mgmt_isolated' => ['label' => 'Rete gestione isolata', 'points' => 2],
|
'mgmt_isolated' => ['label' => 'Rete gestione isolata', 'points' => 2, 'desc' => 'Accessibile solo da una rete di gestione isolata.'],
|
||||||
'air_gapped' => ['label' => 'Completamente isolato', 'points' => 0],
|
'air_gapped' => ['label' => 'Completamente isolato', 'points' => 0, 'desc' => 'Completamente isolato, senza connettivita di rete.'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'c6_regulatory' => [
|
'c6_regulatory' => [
|
||||||
@@ -97,11 +97,11 @@ class AssetScoringService
|
|||||||
'max' => 5,
|
'max' => 5,
|
||||||
'help' => 'Se il sistema e soggetto a obblighi normativi o contrattuali specifici.',
|
'help' => 'Se il sistema e soggetto a obblighi normativi o contrattuali specifici.',
|
||||||
'options' => [
|
'options' => [
|
||||||
'nis2_required' => ['label' => 'Richiesto da NIS2', 'points' => 5],
|
'nis2_required' => ['label' => 'Richiesto da NIS2', 'points' => 5, 'desc' => 'Sistema che rientra negli obblighi NIS2 dell\'organizzazione.'],
|
||||||
'mandatory_cert' => ['label' => 'Certificazioni obbligatorie', 'points' => 4],
|
'mandatory_cert' => ['label' => 'Certificazioni obbligatorie', 'points' => 4, 'desc' => 'Soggetto a certificazioni obbligatorie (es. ISO o settoriali).'],
|
||||||
'strict_sla' => ['label' => 'Obblighi SLA stringenti', 'points' => 3],
|
'strict_sla' => ['label' => 'Obblighi SLA stringenti', 'points' => 3, 'desc' => 'Vincolato a SLA contrattuali stringenti.'],
|
||||||
'external_audit' => ['label' => 'Audit esterni regolari', 'points' => 2],
|
'external_audit' => ['label' => 'Audit esterni regolari', 'points' => 2, 'desc' => 'Sottoposto regolarmente ad audit esterni.'],
|
||||||
'none' => ['label' => 'Nessun obbligo', 'points' => 0],
|
'none' => ['label' => 'Nessun obbligo', 'points' => 0, 'desc' => 'Nessun obbligo normativo o contrattuale specifico.'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
+25
-5
@@ -634,16 +634,18 @@
|
|||||||
const sel = (pv != null) ? (typeof pv === 'object' ? (pv.value || '') : pv) : '';
|
const sel = (pv != null) ? (typeof pv === 'object' ? (pv.value || '') : pv) : '';
|
||||||
let opts = `<option value="">— seleziona —</option>`;
|
let opts = `<option value="">— seleziona —</option>`;
|
||||||
for (const [ov, od] of Object.entries(def.options)) {
|
for (const [ov, od] of Object.entries(def.options)) {
|
||||||
opts += `<option value="${ov}" data-pts="${od.points}" ${ov === sel ? 'selected' : ''}>${od.label} (${od.points})</option>`;
|
opts += `<option value="${ov}" data-pts="${od.points}" data-lbl="${escapeHtml(od.label)}" data-desc="${escapeHtml(od.desc || '')}" ${ov === sel ? 'selected' : ''}>${od.label} (${od.points})</option>`;
|
||||||
}
|
}
|
||||||
body += `<div class="form-group" style="margin-bottom:0.75rem;">
|
body += `<div class="form-group" style="margin-bottom:0.75rem;">
|
||||||
<label class="form-label" style="font-weight:600;">${def.label} <span style="color:var(--gray-400);font-weight:400;">(max ${def.max})</span></label>
|
<label class="form-label" style="font-weight:600;">${def.label} <span style="color:var(--gray-400);font-weight:400;">(max ${def.max})</span></label>
|
||||||
<div style="font-size:0.78rem;color:var(--gray-500);margin-bottom:4px;">${def.help}</div>
|
<div style="font-size:0.78rem;color:var(--gray-500);margin-bottom:4px;">${def.help}</div>
|
||||||
<select class="form-select score-criterion" data-key="${key}" onchange="updateScorePreview()" aria-label="${def.label}">${opts}</select>
|
<select class="form-select score-criterion" data-key="${key}" data-crit-label="${escapeHtml(def.label)}" data-max="${def.max}" onchange="updateScorePreview()" aria-label="${def.label}">${opts}</select>
|
||||||
|
<div class="score-meaning" id="meaning-${key}" style="font-size:0.78rem;color:var(--gray-600);margin-top:4px;min-height:1.1em;font-style:italic;"></div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
body += `<div id="score-preview" style="margin-top:1rem;padding:0.9rem;border-radius:10px;background:var(--gray-50);font-weight:600;text-align:center;">
|
body += `<div id="score-preview" style="margin-top:1rem;padding:0.9rem;border-radius:10px;background:var(--gray-50);font-weight:600;text-align:center;">
|
||||||
Totale: <span id="score-total">0</span>/100 — <span id="score-class">—</span></div>`;
|
Totale: <span id="score-total">0</span>/100 — <span id="score-class">—</span></div>
|
||||||
|
<div id="score-breakdown" style="margin-top:0.6rem;font-size:0.8rem;color:var(--gray-700);"></div>`;
|
||||||
|
|
||||||
showModal(`Valuta Rilevanza NIS2 — ${escapeHtml(a.name)}`, body, {
|
showModal(`Valuta Rilevanza NIS2 — ${escapeHtml(a.name)}`, body, {
|
||||||
size: 'lg',
|
size: 'lg',
|
||||||
@@ -658,9 +660,23 @@
|
|||||||
|
|
||||||
function updateScorePreview() {
|
function updateScorePreview() {
|
||||||
let total = 0, complete = true;
|
let total = 0, complete = true;
|
||||||
|
let rows = '';
|
||||||
document.querySelectorAll('.score-criterion').forEach(s => {
|
document.querySelectorAll('.score-criterion').forEach(s => {
|
||||||
if (!s.value) { complete = false; return; }
|
const meaningEl = document.getElementById('meaning-' + s.dataset.key);
|
||||||
total += parseInt(s.selectedOptions[0].dataset.pts || '0', 10);
|
if (!s.value) {
|
||||||
|
complete = false;
|
||||||
|
if (meaningEl) meaningEl.textContent = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const opt = s.selectedOptions[0];
|
||||||
|
const pts = parseInt(opt.dataset.pts || '0', 10);
|
||||||
|
total += pts;
|
||||||
|
// #432: mostra il significato dell'opzione selezionata sotto la combo
|
||||||
|
if (meaningEl) meaningEl.textContent = opt.dataset.desc || '';
|
||||||
|
// #431: dettaglio per criterio del punteggio raggiunto
|
||||||
|
rows += `<div style="display:flex;justify-content:space-between;gap:0.5rem;padding:3px 0;border-bottom:1px solid var(--gray-100);">
|
||||||
|
<span>${escapeHtml(s.dataset.critLabel)}: ${escapeHtml(opt.dataset.lbl || '')}</span>
|
||||||
|
<span style="font-weight:600;white-space:nowrap;">${pts}/${s.dataset.max}</span></div>`;
|
||||||
});
|
});
|
||||||
let cls = total >= 80 ? 'critico' : total >= 60 ? 'alto' : total >= 40 ? 'medio' : total >= 20 ? 'basso' : 'trascurabile';
|
let cls = total >= 80 ? 'critico' : total >= 60 ? 'alto' : total >= 40 ? 'medio' : total >= 20 ? 'basso' : 'trascurabile';
|
||||||
const color = relevanceClassColors[cls];
|
const color = relevanceClassColors[cls];
|
||||||
@@ -668,6 +684,10 @@
|
|||||||
const clsEl = document.getElementById('score-class');
|
const clsEl = document.getElementById('score-class');
|
||||||
clsEl.textContent = complete ? `${cls.charAt(0).toUpperCase() + cls.slice(1)}${total >= 40 ? ' — Rilevante NIS2 ✓' : ''}` : '(completa tutti i criteri)';
|
clsEl.textContent = complete ? `${cls.charAt(0).toUpperCase() + cls.slice(1)}${total >= 40 ? ' — Rilevante NIS2 ✓' : ''}` : '(completa tutti i criteri)';
|
||||||
clsEl.style.color = complete ? color : 'var(--gray-400)';
|
clsEl.style.color = complete ? color : 'var(--gray-400)';
|
||||||
|
const bdEl = document.getElementById('score-breakdown');
|
||||||
|
if (bdEl) bdEl.innerHTML = rows
|
||||||
|
? `<div style="font-weight:600;margin-bottom:4px;">Dettaglio punteggio per criterio</div>${rows}`
|
||||||
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitScoring(id) {
|
async function submitScoring(id) {
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
{"version": "1.24.9", "build": "2026-06-23-v1.24.9", "date": "2026-06-23", "changelog": "Assistente ARIA — Ora ARIA conosce la barra laterale REALE dell'app e, quando ti spiega dove cliccare, usa i nomi esatti delle voci di menu (es. «sezione Operativo > Inventario») senza piu' inventare moduli o «fasi» inesistenti. Inoltre riceve la pagina da cui stai scrivendo, cosi' da darti indicazioni piu' pertinenti al punto in cui ti trovi. Risolto ticket #424."}
|
{"version": "1.24.10", "build": "2026-06-23-v1.24.10", "date": "2026-06-23", "changelog": "Valuta Rilevanza NIS2 (Inventario) — Ogni voce delle tendine ora mostra anche il suo SIGNIFICATO: scegliendo un'opzione compare sotto la combo una breve spiegazione di cosa indica (es. cosa vuol dire «Critico» per la Criticita Operativa). In piu' la finestra mostra il «Dettaglio punteggio per criterio»: vedi quanti punti hai ottenuto da ciascuna voce e come si compone il totale, anche riaprendo una valutazione gia' salvata. Risolti ticket #431 e #432."}
|
||||||
|
|||||||
Reference in New Issue
Block a user