[FEAT] Epic C / C1 — Elenco Misure/Requisiti consultabile (read-only) + FrameworkController
UI data-driven sulle tabelle di config cfg_nis2_* (mig.046): - FrameworkController::catalog (GET /api/framework/catalog): 43 misure / 116 requisiti, procedura+rischio di default per requisito, flag importanti/essenziali, classe org. - public/misure-requisiti.html (Bootstrap Italia/AGID): vista per misura / per area politica, selettore soggetto (auto/importante/essenziale/tutti), righe che si 'spengono' per classe, ricerca, sola lettura (codifica non modificabile). Voce sidebar in sezione Compliance. - api.js frameworkCatalog(); routing index.php; i18n nav.framework IT/EN. - help.js: guida 'misure-requisiti' (struttura, importanti/essenziali, riferimenti art.23/24 D.Lgs.). - KB AI: doc SYSTEM ingestato (uuid 7871c1ea). - Cache-buster ?v=20260621 (35 pagine), version 1.18.0, SW cache nis2-shell-v1.18.0. - docs/simon/: file sorgente autoritativi (provenienza seed, codifica Simon non variata). Smoke prod: /framework/catalog 200 (43/116, 6 misure solo-essenziali, GV.OC-04->Proc.01/Risk.01), pagina 200, USR2 applicato. Additivo, nessuna modifica a dati esistenti. 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
d37047987f
commit
92d101b6f4
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* NIS2 Agile - Framework canonico Misure/Requisiti (Epic C / C1)
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* Espone in SOLA LETTURA l'elenco canonico delle misure di sicurezza di base e
|
||||||
|
* dei relativi requisiti (Determinazione ACN n. 164179 del 14 aprile 2025),
|
||||||
|
* con la procedura e il rischio di default associati a ciascun requisito.
|
||||||
|
*
|
||||||
|
* Fonte dati: tabelle di CONFIGURAZIONE cfg_nis2_* (system-level), popolate dai
|
||||||
|
* file autoritativi forniti dal referente compliance (docs/simon/) — codifica
|
||||||
|
* NON variabile. Il dato NON e' org-scoped (e' framework normativo condiviso);
|
||||||
|
* l'unico contributo dell'org e' la sua CLASSE (essential/important), usata dal
|
||||||
|
* frontend per "spegnere" le righe non applicabili al soggetto.
|
||||||
|
*
|
||||||
|
* Sola lettura: nessun endpoint di scrittura. L'utente NON puo' modificare la
|
||||||
|
* codifica; la configurazione del framework e' riservata a super_admin/sistema
|
||||||
|
* (gestione futura). Vista doppia (per misura / per area politica a..p) gestita
|
||||||
|
* lato frontend sugli stessi dati.
|
||||||
|
*
|
||||||
|
* NOTE strutturali: DB API Database::query/fetchAll/fetchOne (NON Database::execute).
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . '/BaseController.php';
|
||||||
|
|
||||||
|
class FrameworkController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* GET /api/framework/catalog
|
||||||
|
* Ritorna ambiti NIST, misure (con requisiti annidati, procedura+rischio di
|
||||||
|
* default e flag di applicabilita' importanti/essenziali) e la classe dell'org
|
||||||
|
* corrente (se disponibile). Ordine 'ord'/'n' = ordine di default immutabile.
|
||||||
|
*/
|
||||||
|
public function catalog(): void
|
||||||
|
{
|
||||||
|
$this->requireAuth();
|
||||||
|
|
||||||
|
// Classe del soggetto (per evidenziare/spegnere le righe) — opzionale.
|
||||||
|
$orgClass = null;
|
||||||
|
$orgId = $this->getCurrentOrgId();
|
||||||
|
if ($orgId) {
|
||||||
|
$row = Database::fetchOne('SELECT entity_type FROM organizations WHERE id = ?', [$orgId]);
|
||||||
|
$orgClass = $row['entity_type'] ?? null; // essential | important | not_applicable
|
||||||
|
}
|
||||||
|
|
||||||
|
$ambiti = Database::fetchAll(
|
||||||
|
'SELECT nist_code, nist_descr FROM cfg_nis2_ambiti ORDER BY nist_code ASC'
|
||||||
|
);
|
||||||
|
|
||||||
|
$misure = Database::fetchAll(
|
||||||
|
'SELECT misura_code, nist_code, area_politica, misura_descr, ord,
|
||||||
|
applies_important, applies_essential
|
||||||
|
FROM cfg_nis2_misure
|
||||||
|
ORDER BY ord ASC'
|
||||||
|
);
|
||||||
|
|
||||||
|
$reqs = Database::fetchAll(
|
||||||
|
'SELECT q.n, q.misura_code, q.requisito_code, q.requisito_descr,
|
||||||
|
q.proc_code, p.proc_descr, q.risk_code, r.risk_descr,
|
||||||
|
q.applies_important, q.applies_essential
|
||||||
|
FROM cfg_nis2_requisiti q
|
||||||
|
LEFT JOIN cfg_nis2_procedure p ON p.proc_code = q.proc_code
|
||||||
|
LEFT JOIN cfg_nis2_rischi r ON r.risk_code = q.risk_code
|
||||||
|
ORDER BY q.n ASC, q.id ASC'
|
||||||
|
);
|
||||||
|
|
||||||
|
$byMis = [];
|
||||||
|
foreach ($reqs as $q) {
|
||||||
|
$byMis[$q['misura_code']][] = [
|
||||||
|
'n' => $q['n'] !== null ? (int) $q['n'] : null,
|
||||||
|
'requisito_code' => $q['requisito_code'],
|
||||||
|
'requisito_descr' => $q['requisito_descr'],
|
||||||
|
'proc_code' => $q['proc_code'],
|
||||||
|
'proc_descr' => $q['proc_descr'],
|
||||||
|
'risk_code' => $q['risk_code'],
|
||||||
|
'risk_descr' => $q['risk_descr'],
|
||||||
|
'applies_important' => (int) $q['applies_important'],
|
||||||
|
'applies_essential' => (int) $q['applies_essential'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$measures = [];
|
||||||
|
foreach ($misure as $m) {
|
||||||
|
$measures[] = [
|
||||||
|
'misura_code' => $m['misura_code'],
|
||||||
|
'nist_code' => $m['nist_code'],
|
||||||
|
'area_politica' => $m['area_politica'],
|
||||||
|
'misura_descr' => $m['misura_descr'],
|
||||||
|
'ord' => (int) $m['ord'],
|
||||||
|
'applies_important' => (int) $m['applies_important'],
|
||||||
|
'applies_essential' => (int) $m['applies_essential'],
|
||||||
|
'requisiti' => $byMis[$m['misura_code']] ?? [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->jsonSuccess([
|
||||||
|
'org_class' => $orgClass,
|
||||||
|
'ambiti' => $ambiti,
|
||||||
|
'measures' => $measures,
|
||||||
|
'totals' => ['misure' => count($measures), 'requisiti' => count($reqs)],
|
||||||
|
'readonly' => true,
|
||||||
|
'source' => 'Determinazione ACN n. 164179 del 14 aprile 2025',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -70,8 +70,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Stessa logica della app: api.js + common.js (helper) + common-bi.js (override BI) -->
|
<!-- Stessa logica della app: api.js + common.js (helper) + common-bi.js (override BI) -->
|
||||||
<script src="js/api.js?v=20260620"></script>
|
<script src="js/api.js?v=20260621"></script>
|
||||||
<script src="js/common.js?v=20260620"></script>
|
<script src="js/common.js?v=20260621"></script>
|
||||||
<script src="js/common-bi.js?v=20260618"></script>
|
<script src="js/common-bi.js?v=20260618"></script>
|
||||||
<script>
|
<script>
|
||||||
// Renderizza la sidebar BI (loadSidebar è stato ridefinito da common-bi.js)
|
// Renderizza la sidebar BI (loadSidebar è stato ridefinito da common-bi.js)
|
||||||
|
|||||||
+4
-4
@@ -152,8 +152,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -164,8 +164,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
const FUNC_LABELS = {
|
const FUNC_LABELS = {
|
||||||
|
|||||||
@@ -1088,10 +1088,10 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="js/api.js?v=20260620"></script>
|
<script src="js/api.js?v=20260621"></script>
|
||||||
<script src="js/common.js?v=20260620"></script>
|
<script src="js/common.js?v=20260621"></script>
|
||||||
<script src="js/i18n.js?v=20260620"></script>
|
<script src="js/i18n.js?v=20260621"></script>
|
||||||
<script src="js/help.js?v=20260620"></script>
|
<script src="js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
loadSidebar();
|
loadSidebar();
|
||||||
|
|||||||
@@ -154,8 +154,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -166,8 +166,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth check ───────────────────────────────────────────
|
// ── Auth check ───────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
+4
-4
@@ -366,8 +366,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -378,8 +378,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth & Init ─────────────────────────────────────────
|
// ── Auth & Init ─────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
@@ -349,14 +349,14 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="js/api.js?v=20260620"></script>
|
<script src="js/api.js?v=20260621"></script>
|
||||||
<script src="js/common.js?v=20260620"></script>
|
<script src="js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle + override sidebar BI (common-bi.js dopo common.js: ridefinisce solo loadSidebar) -->
|
<!-- Bootstrap Italia bundle + override sidebar BI (common-bi.js dopo common.js: ridefinisce solo loadSidebar) -->
|
||||||
<script src="vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
<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>if (window.bootstrap && bootstrap.loadFonts) { bootstrap.loadFonts('vendor/bootstrap-italia/dist/fonts'); }</script>
|
||||||
<script src="js/common-bi.js?v=20260618"></script>
|
<script src="js/common-bi.js?v=20260618"></script>
|
||||||
<script src="js/i18n.js?v=20260620"></script>
|
<script src="js/i18n.js?v=20260621"></script>
|
||||||
<script src="js/help.js?v=20260620"></script>
|
<script src="js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|
||||||
|
|||||||
@@ -183,12 +183,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script src="/js/competenze.js?v=20260617"></script>
|
<script src="/js/competenze.js?v=20260617"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -382,8 +382,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -394,7 +394,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
const SPRITE = '/vendor/bootstrap-italia/dist/svg/sprites.svg';
|
const SPRITE = '/vendor/bootstrap-italia/dist/svg/sprites.svg';
|
||||||
function ico(name, cls) { return `<svg class="ico ${cls||''}" aria-hidden="true"><use href="${SPRITE}#${name}"></use></svg>`; }
|
function ico(name, cls) { return `<svg class="ico ${cls||''}" aria-hidden="true"><use href="${SPRITE}#${name}"></use></svg>`; }
|
||||||
|
|||||||
@@ -143,8 +143,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -155,8 +155,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth check ───────────────────────────────────────────
|
// ── Auth check ───────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Stessa logica della forgot-password.html: ZERO modifiche backend -->
|
<!-- Stessa logica della forgot-password.html: ZERO modifiche backend -->
|
||||||
<script src="js/api.js?v=20260620"></script>
|
<script src="js/api.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
const form = document.getElementById('forgot-form');
|
const form = document.getElementById('forgot-form');
|
||||||
const err = document.getElementById('err');
|
const err = document.getElementById('err');
|
||||||
|
|||||||
+4
-4
@@ -1142,8 +1142,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (accordion) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (accordion) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI. -->
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI. -->
|
||||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||||
@@ -1153,8 +1153,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// La guida è accessibile anche da non autenticati (utile per onboarding)
|
// La guida è accessibile anche da non autenticati (utile per onboarding)
|
||||||
// ma se sei loggato carichi sidebar + i18n normalmente. Stessa logica
|
// ma se sei loggato carichi sidebar + i18n normalmente. Stessa logica
|
||||||
|
|||||||
@@ -351,8 +351,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -363,8 +363,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth & Init ──────────────────────────────────────────────
|
// ── Auth & Init ──────────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ $controllerMap = [
|
|||||||
'competences' => 'CompetenceController', // A4 Fase 4.2 — Competenze (skill, requisiti ruolo, gap, alert->azione)
|
'competences' => 'CompetenceController', // A4 Fase 4.2 — Competenze (skill, requisiti ruolo, gap, alert->azione)
|
||||||
'raci' => 'RaciController', // A4 Fase 4.3 — Matrice RACI + link m2m (procedure/inventario/rischi/misure)
|
'raci' => 'RaciController', // A4 Fase 4.3 — Matrice RACI + link m2m (procedure/inventario/rischi/misure)
|
||||||
'review-schedule' => 'ReviewScheduleController', // A4 Fase 4.4 — Scadenziario centralizzato (revisioni periodiche GV.PO-02/GV.SC-07/PR.AT/DE.CM)
|
'review-schedule' => 'ReviewScheduleController', // A4 Fase 4.4 — Scadenziario centralizzato (revisioni periodiche GV.PO-02/GV.SC-07/PR.AT/DE.CM)
|
||||||
|
'framework' => 'FrameworkController', // Epic C / C1 — Elenco canonico Misure/Requisiti (cfg_nis2_*, read-only)
|
||||||
'assessments' => 'AssessmentController',
|
'assessments' => 'AssessmentController',
|
||||||
'acn-gap' => 'AcnAssessmentController', // Gap Analysis ACN (Det. 164179/2025, misure/requisiti)
|
'acn-gap' => 'AcnAssessmentController', // Gap Analysis ACN (Det. 164179/2025, misure/requisiti)
|
||||||
'isms' => 'IsmsModelController', // Modello Organizzativo SGSI (ISO 27001/27017/27018 + SoA)
|
'isms' => 'IsmsModelController', // Modello Organizzativo SGSI (ISO 27001/27017/27018 + SoA)
|
||||||
@@ -249,6 +250,13 @@ $actionMap = [
|
|||||||
'POST:{id}/complete' => 'complete',
|
'POST:{id}/complete' => 'complete',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// ── FrameworkController — Elenco canonico Misure/Requisiti (Epic C / C1) ──
|
||||||
|
// Sola lettura: catalogo cfg_nis2_* (misure 43 / requisiti 116 + procedura e
|
||||||
|
// rischio di default per requisito). Nessuna scrittura (codifica non variabile).
|
||||||
|
'framework' => [
|
||||||
|
'GET:catalog' => 'catalog',
|
||||||
|
],
|
||||||
|
|
||||||
// ── AssessmentController ────────────────────────
|
// ── AssessmentController ────────────────────────
|
||||||
'assessments' => [
|
'assessments' => [
|
||||||
'GET:list' => 'list',
|
'GET:list' => 'list',
|
||||||
|
|||||||
@@ -910,8 +910,8 @@ curl -H <span class="str">"X-API-Key: nis2_TUA_CHIAVE"</span> \
|
|||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script src="js/common.js?v=20260620"></script>
|
<script src="js/common.js?v=20260621"></script>
|
||||||
<script src="js/i18n.js?v=20260620"></script>
|
<script src="js/i18n.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
function showTab(id) {
|
function showTab(id) {
|
||||||
document.querySelectorAll('.tab-btn').forEach((b, i) => {
|
document.querySelectorAll('.tab-btn').forEach((b, i) => {
|
||||||
|
|||||||
+4
-4
@@ -184,8 +184,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -196,8 +196,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script src="/js/isms.js"></script>
|
<script src="/js/isms.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -289,6 +289,12 @@ class NIS2API {
|
|||||||
rsComplete(id) { return this.revComplete(id); }
|
rsComplete(id) { return this.revComplete(id); }
|
||||||
rsSync() { return this.revSync(); }
|
rsSync() { return this.revSync(); }
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════
|
||||||
|
// Framework canonico Misure/Requisiti (Epic C / C1) — SOLA LETTURA.
|
||||||
|
// Catalogo cfg_nis2_* (43 misure / 116 requisiti + procedura+rischio default).
|
||||||
|
// ═══════════════════════════════════════════════════════════════════
|
||||||
|
frameworkCatalog() { return this._acn(this.get('/framework/catalog')); }
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════
|
||||||
// Stakeholder estesi (A4 Fase 4.5) — riusa suppliers (GV.SC-02).
|
// Stakeholder estesi (A4 Fase 4.5) — riusa suppliers (GV.SC-02).
|
||||||
// stakeholderMap = vista di sintesi raggruppata (supplier/customer/partner). _acn.
|
// stakeholderMap = vista di sintesi raggruppata (supplier/customer/partner). _acn.
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ function loadSidebar() {
|
|||||||
{ 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: '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', href: 'assessment.html', icon: iconClipboardCheck(), i18nKey: 'nav.gap_analysis' },
|
||||||
{ name: 'Gap Analysis ACN', href: 'acn-gap.html', icon: iconClipboardCheck(), i18nKey: 'nav.acn_gap' },
|
{ name: 'Gap Analysis ACN', href: 'acn-gap.html', icon: iconClipboardCheck(), i18nKey: 'nav.acn_gap' },
|
||||||
|
{ name: 'Misure e Requisiti', href: 'misure-requisiti.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h8a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"/></svg>`, i18nKey: 'nav.framework' },
|
||||||
{ name: 'Modello SGSI (ISO 27001)', href: 'isms.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M2.166 4.999A11.954 11.954 0 0010 1.944 11.954 11.954 0 0017.834 5c.11.65.166 1.32.166 2.001 0 5.225-3.34 9.67-8 11.317C5.34 16.67 2 12.225 2 7c0-.682.057-1.35.166-2.001zm11.541 3.708a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg>`, i18nKey: 'nav.isms' },
|
{ name: 'Modello SGSI (ISO 27001)', href: 'isms.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M2.166 4.999A11.954 11.954 0 0010 1.944 11.954 11.954 0 0017.834 5c.11.65.166 1.32.166 2.001 0 5.225-3.34 9.67-8 11.317C5.34 16.67 2 12.225 2 7c0-.682.057-1.35.166-2.001zm11.541 3.708a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg>`, i18nKey: 'nav.isms' },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -360,6 +360,43 @@ const HelpSystem = (function () {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ─── Misure e Requisiti — elenco canonico (Epic C / C1) ───────
|
||||||
|
'misure-requisiti': {
|
||||||
|
title: 'Guida - Misure e Requisiti',
|
||||||
|
intro: 'Questa pagina mostra l\'elenco canonico delle misure di sicurezza di base e dei relativi requisiti previsti dalla Determinazione ACN n. 164179 del 14 aprile 2025. Per ogni requisito sono indicati la procedura di default che lo soddisfa e il rischio di default associato. È un elenco di riferimento in sola lettura: la codifica e l\'ordine non sono modificabili. È uno strumento di supporto, non un parere legale.',
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: 'Come è organizzato',
|
||||||
|
items: [
|
||||||
|
'Le <strong>misure</strong> sono 43 in totale; ogni misura è descritta da uno o più <strong>requisiti</strong> (i singoli punti/commi).',
|
||||||
|
'A ogni requisito è abbinata una <strong>procedura di default</strong> (che lo risolve) e un <strong>rischio di default</strong>: queste alimentano, come contenuto iniziale modificabile, i moduli Procedure e Rischi.',
|
||||||
|
'La <strong>valutazione del rischio</strong> parte vuota: la compili tu nel modulo Rischi. È da lì, e dall\'analisi degli stakeholder, che emerge lo stato di conformità dell\'azienda.'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: 'Importanti ed essenziali',
|
||||||
|
items: [
|
||||||
|
'Alcuni requisiti, e alcune intere misure, riguardano solo i <strong>soggetti essenziali</strong>: per un soggetto <strong>importante</strong> quelle righe si "spengono" (appaiono in grigio).',
|
||||||
|
'Soggetti <strong>importanti</strong>: 37 misure / 92 requisiti. Soggetti <strong>essenziali</strong>: 43 misure / 116 requisiti.',
|
||||||
|
'Con il selettore "Soggetto" scegli quale profilo applicare; con "nascondi non applicabili" mostri solo le righe pertinenti. Le viste "per misura" e "per area politica" mostrano gli stessi dati in due modi.'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: 'Riferimenti normativi',
|
||||||
|
items: [
|
||||||
|
'Misure di base: <strong>Determinazione ACN n. 164179 del 14 aprile 2025</strong> (Allegato 1 = importanti, Allegato 2 = essenziali).',
|
||||||
|
'Gli obblighi di gestione del rischio fanno capo all\'<strong>art. 24 del D.Lgs. 138/2024</strong>; la governance all\'<strong>art. 23</strong>.',
|
||||||
|
'L\'elenco non è modificabile dall\'utente: rappresenta la codifica ufficiale e va mantenuto fedele alla fonte.'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
references: [
|
||||||
|
'Determinazione ACN n. 164179 del 14 aprile 2025 - misure di sicurezza di base (Allegati 1-2)',
|
||||||
|
'Obblighi: art. 24 D.Lgs. 138/2024 (gestione del rischio), art. 23 (governance)',
|
||||||
|
'NOTA: l\'elenco è uno strumento di supporto; la classificazione del soggetto e la conformità formale restano valutazione di Direzione/Legale e verifica ACN.'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
// ─── Stakeholder estesi (A4 Fase 4.5) ─────────────────────────
|
// ─── Stakeholder estesi (A4 Fase 4.5) ─────────────────────────
|
||||||
'stakeholders': {
|
'stakeholders': {
|
||||||
title: 'Guida - Stakeholder',
|
title: 'Guida - Stakeholder',
|
||||||
@@ -1247,6 +1284,8 @@ const HelpSystem = (function () {
|
|||||||
'raci': 'raci',
|
'raci': 'raci',
|
||||||
'review-schedule.html': 'review-schedule',
|
'review-schedule.html': 'review-schedule',
|
||||||
'review-schedule': 'review-schedule',
|
'review-schedule': 'review-schedule',
|
||||||
|
'misure-requisiti.html': 'misure-requisiti',
|
||||||
|
'misure-requisiti': 'misure-requisiti',
|
||||||
'stakeholders.html': 'stakeholders',
|
'stakeholders.html': 'stakeholders',
|
||||||
'stakeholders': 'stakeholders',
|
'stakeholders': 'stakeholders',
|
||||||
'risks.html': 'risks',
|
'risks.html': 'risks',
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const I18n = (function () {
|
|||||||
'nav.dashboard': { it: 'Dashboard', en: 'Dashboard' },
|
'nav.dashboard': { it: 'Dashboard', en: 'Dashboard' },
|
||||||
'nav.gap_analysis': { it: 'Gap Analysis', en: 'Gap Analysis' },
|
'nav.gap_analysis': { it: 'Gap Analysis', en: 'Gap Analysis' },
|
||||||
'nav.acn_gap': { it: 'Gap Analysis ACN', en: 'ACN Gap Analysis' },
|
'nav.acn_gap': { it: 'Gap Analysis ACN', en: 'ACN Gap Analysis' },
|
||||||
|
'nav.framework': { it: 'Misure e Requisiti', en: 'Measures & Requirements' },
|
||||||
// Gap Analysis ACN (Determinazione 164179/2025)
|
// Gap Analysis ACN (Determinazione 164179/2025)
|
||||||
'acn.title': { it: 'Gap Analysis ACN (misure di base)', en: 'ACN Gap Analysis (baseline measures)' },
|
'acn.title': { it: 'Gap Analysis ACN (misure di base)', en: 'ACN Gap Analysis (baseline measures)' },
|
||||||
'acn.ai': { it: 'Analisi AI dei gap', en: 'AI gap analysis' },
|
'acn.ai': { it: 'Analisi AI dei gap', en: 'AI gap analysis' },
|
||||||
|
|||||||
+4
-4
@@ -151,8 +151,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Stessa logica JS della pagina live (parita' funzionale assoluta, zero backend). -->
|
<!-- Stessa logica JS della pagina live (parita' funzionale assoluta, zero backend). -->
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI. -->
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI. -->
|
||||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||||
@@ -162,8 +162,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script src="/js/kb.js"></script>
|
<script src="/js/kb.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// Gate auth + chrome come le altre pagine -bi.
|
// Gate auth + chrome come le altre pagine -bi.
|
||||||
|
|||||||
@@ -515,7 +515,7 @@ body { background: var(--bg-main); }
|
|||||||
|
|
||||||
<div id="toast"></div>
|
<div id="toast"></div>
|
||||||
|
|
||||||
<script src="js/api.js?v=20260620"></script>
|
<script src="js/api.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ══════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════
|
||||||
// CONFIG
|
// CONFIG
|
||||||
|
|||||||
+2
-2
@@ -94,8 +94,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Stessa logica della login attuale: ZERO modifiche backend -->
|
<!-- Stessa logica della login attuale: ZERO modifiche backend -->
|
||||||
<script src="js/api.js?v=20260620"></script>
|
<script src="js/api.js?v=20260621"></script>
|
||||||
<script src="js/common.js?v=20260620"></script>
|
<script src="js/common.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
if (api.isAuthenticated()) { window.location.href = 'dashboard.html'; }
|
if (api.isAuthenticated()) { window.location.href = 'dashboard.html'; }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,237 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="it">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||||
|
<title>Misure e Requisiti - NIS2 Agile</title>
|
||||||
|
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css. -->
|
||||||
|
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
|
||||||
|
<link rel="stylesheet" href="/css/style.css?v=20260621">
|
||||||
|
<style>
|
||||||
|
.mr-intro { background:#eff6ff; border-left:4px solid var(--primary,#2563eb); padding:14px 18px; border-radius:8px; margin-bottom:14px; font-size:.92rem; line-height:1.6; }
|
||||||
|
.mr-note { font-size:.82rem; color:#92400e; background:#fffbeb; border:1px solid #fde68a; border-radius:8px; padding:10px 12px; margin:0 0 16px; }
|
||||||
|
.mr-ro { font-size:.8rem; color:#3730a3; background:#eef2ff; border:1px solid #c7d2fe; border-radius:8px; padding:8px 12px; margin:0 0 16px; display:flex; gap:8px; align-items:center; }
|
||||||
|
.mr-stats { display:flex; flex-wrap:wrap; gap:10px; margin-bottom:16px; }
|
||||||
|
.mr-stat { flex:1 1 140px; min-width:120px; background:#fff; border:1px solid var(--gray-200,#e5e7eb); border-radius:10px; padding:12px 14px; }
|
||||||
|
.mr-stat .n { font-size:1.5rem; font-weight:800; line-height:1; }
|
||||||
|
.mr-stat .l { font-size:.76rem; color:var(--gray-500,#6b7280); margin-top:4px; }
|
||||||
|
.mr-toolbar { display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin-bottom:14px; }
|
||||||
|
.mr-toolbar label { font-weight:600; font-size:.82rem; }
|
||||||
|
.mr-toolbar select, .mr-toolbar input[type=search] { padding:8px 10px; border:1px solid var(--gray-200,#e5e7eb); border-radius:8px; font-size:.88rem; }
|
||||||
|
.mr-toolbar .grow { flex:1 1 auto; }
|
||||||
|
.mr-group { border:1px solid var(--gray-200,#e5e7eb); border-radius:10px; margin-bottom:14px; overflow:hidden; }
|
||||||
|
.mr-group-head { background:#f8fafc; padding:11px 14px; border-bottom:1px solid var(--gray-100,#f3f4f6); }
|
||||||
|
.mr-group-head .code { font-weight:800; color:#1e3a8a; font-size:.95rem; }
|
||||||
|
.mr-group-head .area { font-size:.78rem; color:var(--gray-500,#6b7280); }
|
||||||
|
.mr-group-head .descr { font-size:.86rem; color:#334155; margin-top:3px; line-height:1.5; }
|
||||||
|
.mr-tag { display:inline-block; font-size:.66rem; font-weight:800; padding:2px 8px; border-radius:20px; margin-left:6px; vertical-align:middle; }
|
||||||
|
.mr-tag.ess { background:#fef3c7; color:#92400e; }
|
||||||
|
.mr-table { width:100%; border-collapse:collapse; font-size:.85rem; }
|
||||||
|
.mr-table th, .mr-table td { text-align:left; padding:9px 11px; border-bottom:1px solid var(--gray-100,#f3f4f6); vertical-align:top; }
|
||||||
|
.mr-table th { font-size:.72rem; text-transform:uppercase; letter-spacing:.04em; color:var(--gray-500,#6b7280); background:#fff; position:sticky; top:0; }
|
||||||
|
.mr-req-code { white-space:nowrap; font-weight:700; color:#475569; }
|
||||||
|
.mr-code-pill { display:inline-block; font-size:.7rem; font-weight:700; color:#3730a3; background:#eef2ff; border-radius:6px; padding:1px 6px; }
|
||||||
|
.mr-yn { text-align:center; font-weight:800; }
|
||||||
|
.mr-yn.y { color:#166534; }
|
||||||
|
.mr-yn.n { color:#cbd5e1; }
|
||||||
|
.mr-row.spento { opacity:.4; }
|
||||||
|
.mr-row.spento td { font-style:italic; }
|
||||||
|
.mr-empty { text-align:center; padding:34px 16px; color:var(--gray-500,#6b7280); }
|
||||||
|
</style>
|
||||||
|
<!-- PWA:start -->
|
||||||
|
<link rel="manifest" href="/manifest.webmanifest">
|
||||||
|
<meta name="theme-color" content="#0066CC">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||||
|
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
|
||||||
|
<meta name="application-name" content="NIS2 Agile">
|
||||||
|
<script src="/js/pwa.js?v=20260614" defer></script>
|
||||||
|
<!-- PWA:end -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="app-layout">
|
||||||
|
<aside class="sidebar" id="sidebar"></aside>
|
||||||
|
<main class="main-content">
|
||||||
|
<header class="content-header">
|
||||||
|
<h2 data-i18n="mr.title">Misure e Requisiti</h2>
|
||||||
|
<div class="content-header-actions">
|
||||||
|
<span class="savehint" id="mr-hint" role="status" aria-live="polite"></span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="content-body">
|
||||||
|
<div class="mr-intro">
|
||||||
|
<strong>L'elenco canonico delle misure di sicurezza di base e dei relativi requisiti.</strong>
|
||||||
|
Ogni requisito riporta la <strong>procedura di default</strong> che lo soddisfa e il <strong>rischio di default</strong> associato. È la base su cui si costruiscono procedure, rischi e attività: le righe si "spengono" quando non sono applicabili alla classe del tuo soggetto.
|
||||||
|
</div>
|
||||||
|
<div class="mr-ro">
|
||||||
|
🔒 <span>Elenco di riferimento, <strong>sola lettura</strong>: la codifica (misure, requisiti, ordine) non è modificabile. Procedure e rischi qui elencati vengono proposti come <em>default</em> nei rispettivi moduli, dove potrai personalizzarli.</span>
|
||||||
|
</div>
|
||||||
|
<div class="mr-note">
|
||||||
|
Fonte: <strong>Determinazione ACN n. 164179 del 14 aprile 2025</strong> (misure di base, Allegati 1–2). Le misure applicabili dipendono dalla classe del soggetto: <strong>importanti</strong> 37 misure / 92 requisiti, <strong>essenziali</strong> 43 / 116. Strumento di supporto, non un parere legale.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mr-stats" id="mr-stats" style="display:none;">
|
||||||
|
<div class="mr-stat"><div class="n" id="mr-stat-mis">0</div><div class="l">Misure</div></div>
|
||||||
|
<div class="mr-stat"><div class="n" id="mr-stat-req">0</div><div class="l">Requisiti</div></div>
|
||||||
|
<div class="mr-stat"><div class="n" id="mr-stat-active">0</div><div class="l">Applicabili al soggetto</div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mr-toolbar">
|
||||||
|
<label for="mr-view">Vista:</label>
|
||||||
|
<select id="mr-view" onchange="mrRender()">
|
||||||
|
<option value="misura">Per misura</option>
|
||||||
|
<option value="area">Per area politica</option>
|
||||||
|
</select>
|
||||||
|
<label for="mr-class">Soggetto:</label>
|
||||||
|
<select id="mr-class" onchange="mrRender()">
|
||||||
|
<option value="auto">Automatico (dalla mia org)</option>
|
||||||
|
<option value="important">Importante</option>
|
||||||
|
<option value="essential">Essenziale</option>
|
||||||
|
<option value="all">Tutti (mostra tutto)</option>
|
||||||
|
</select>
|
||||||
|
<label style="font-weight:500;"><input type="checkbox" id="mr-hide" onchange="mrRender()"> nascondi non applicabili</label>
|
||||||
|
<span class="grow"></span>
|
||||||
|
<input type="search" id="mr-q" placeholder="Cerca codice o testo…" oninput="mrRender()" style="min-width:200px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="mr-list" aria-live="polite"><div class="mr-empty">Caricamento…</div></div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
|
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||||
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
/*
|
||||||
|
* NIS2 Agile - Elenco canonico Misure/Requisiti (Epic C / C1) - SOLA LETTURA.
|
||||||
|
* Dati da api.frameworkCatalog() (tabelle cfg_nis2_*). Codifica non modificabile.
|
||||||
|
* Le righe si "spengono" per la classe del soggetto (importante/essenziale).
|
||||||
|
*/
|
||||||
|
let MR = { measures: [], org_class: null };
|
||||||
|
|
||||||
|
function el(id) { return document.getElementById(id); }
|
||||||
|
function esc(s) { const d = document.createElement('div'); d.textContent = (s == null ? '' : String(s)); return d.innerHTML; }
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', async function () {
|
||||||
|
if (typeof checkAuth === 'function' && !checkAuth()) return;
|
||||||
|
if (window.I18n && I18n.init) I18n.init('it');
|
||||||
|
if (typeof loadSidebar === 'function') loadSidebar();
|
||||||
|
if (window.HelpSystem && HelpSystem.init) HelpSystem.init();
|
||||||
|
await mrLoad();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function mrLoad() {
|
||||||
|
try {
|
||||||
|
const data = await api.frameworkCatalog();
|
||||||
|
MR.measures = (data && data.measures) || [];
|
||||||
|
MR.org_class = (data && data.org_class) || null;
|
||||||
|
// se conosco la classe dell'org, parto in modalità "auto"; altrimenti mostro tutto
|
||||||
|
if (!MR.org_class) el('mr-class').value = 'all';
|
||||||
|
el('mr-stat-mis').textContent = (data && data.totals && data.totals.misure) || MR.measures.length;
|
||||||
|
el('mr-stat-req').textContent = (data && data.totals && data.totals.requisiti) || 0;
|
||||||
|
el('mr-stats').style.display = 'flex';
|
||||||
|
mrRender();
|
||||||
|
} catch (e) {
|
||||||
|
el('mr-list').innerHTML = '<div class="mr-empty">Impossibile caricare l\'elenco. Riprova più tardi.</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// classe effettiva selezionata (risolve "auto" sulla classe dell'org)
|
||||||
|
function mrEffectiveClass() {
|
||||||
|
const sel = el('mr-class').value;
|
||||||
|
if (sel === 'auto') return MR.org_class; // può essere null => tutto attivo
|
||||||
|
if (sel === 'all') return null;
|
||||||
|
return sel; // important | essential
|
||||||
|
}
|
||||||
|
// un requisito è "attivo" per la classe effettiva?
|
||||||
|
function reqActive(req, cls) {
|
||||||
|
if (!cls) return true;
|
||||||
|
return cls === 'important' ? !!req.applies_important : !!req.applies_essential;
|
||||||
|
}
|
||||||
|
function matchQuery(m, req, q) {
|
||||||
|
if (!q) return true;
|
||||||
|
q = q.toLowerCase();
|
||||||
|
return (m.misura_code + ' ' + m.misura_descr + ' ' + m.area_politica + ' ' +
|
||||||
|
req.requisito_code + ' ' + req.requisito_descr + ' ' +
|
||||||
|
(req.proc_descr || '') + ' ' + (req.risk_descr || '')).toLowerCase().indexOf(q) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mrRender() {
|
||||||
|
const cls = mrEffectiveClass();
|
||||||
|
const hide = el('mr-hide').checked;
|
||||||
|
const q = (el('mr-q').value || '').trim();
|
||||||
|
const view = el('mr-view').value;
|
||||||
|
|
||||||
|
// costruisco le righe filtrate (misura -> requisiti visibili)
|
||||||
|
let activeCount = 0;
|
||||||
|
const groupsByKey = {}; // key -> {label, descr, area, code, essOnly, rows:[]}
|
||||||
|
|
||||||
|
MR.measures.forEach(function (m) {
|
||||||
|
const essOnly = !m.applies_important;
|
||||||
|
m.requisiti.forEach(function (req) {
|
||||||
|
if (!matchQuery(m, req, q)) return;
|
||||||
|
const active = reqActive(req, cls);
|
||||||
|
if (active) activeCount++;
|
||||||
|
if (hide && !active) return;
|
||||||
|
let key, head;
|
||||||
|
if (view === 'area') {
|
||||||
|
key = m.area_politica || '—';
|
||||||
|
head = { code: m.area_politica || '—', descr: '', area: '', essOnly: false };
|
||||||
|
} else {
|
||||||
|
key = m.misura_code;
|
||||||
|
head = { code: m.misura_code + ' — ' + (m.nist_code || ''), descr: m.misura_descr, area: m.area_politica, essOnly: essOnly };
|
||||||
|
}
|
||||||
|
if (!groupsByKey[key]) groupsByKey[key] = Object.assign({ rows: [] }, head);
|
||||||
|
groupsByKey[key].rows.push({ m: m, req: req, active: active });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
el('mr-stat-active').textContent = activeCount;
|
||||||
|
|
||||||
|
const keys = Object.keys(groupsByKey);
|
||||||
|
if (!keys.length) { el('mr-list').innerHTML = '<div class="mr-empty">Nessun risultato per i filtri selezionati.</div>'; return; }
|
||||||
|
|
||||||
|
let html = '';
|
||||||
|
keys.forEach(function (key) {
|
||||||
|
const g = groupsByKey[key];
|
||||||
|
html += '<div class="mr-group">';
|
||||||
|
html += '<div class="mr-group-head"><div><span class="code">' + esc(g.code) + '</span>' +
|
||||||
|
(g.essOnly ? '<span class="mr-tag ess">solo essenziali</span>' : '') + '</div>';
|
||||||
|
if (g.area) html += '<div class="area">' + esc(g.area) + '</div>';
|
||||||
|
if (g.descr) html += '<div class="descr">' + esc(g.descr) + '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '<table class="mr-table"><thead><tr>' +
|
||||||
|
'<th>Requisito</th><th>Descrizione</th><th>Procedura (default)</th><th>Rischio (default)</th>' +
|
||||||
|
'<th style="text-align:center">Imp.</th><th style="text-align:center">Ess.</th></tr></thead><tbody>';
|
||||||
|
g.rows.forEach(function (r) {
|
||||||
|
const req = r.req, m = r.m;
|
||||||
|
html += '<tr class="mr-row' + (r.active ? '' : ' spento') + '">';
|
||||||
|
if (view === 'area') {
|
||||||
|
html += '<td class="mr-req-code"><span class="mr-code-pill">' + esc(m.misura_code) + '</span> ' + esc(req.requisito_code) + '</td>';
|
||||||
|
} else {
|
||||||
|
html += '<td class="mr-req-code">' + esc(req.requisito_code) + '</td>';
|
||||||
|
}
|
||||||
|
html += '<td>' + esc(req.requisito_descr) + '</td>';
|
||||||
|
html += '<td>' + (req.proc_code ? '<span class="mr-code-pill">' + esc(req.proc_code) + '</span> ' + esc(req.proc_descr || '') : '—') + '</td>';
|
||||||
|
html += '<td>' + (req.risk_code ? '<span class="mr-code-pill">' + esc(req.risk_code) + '</span> ' + esc(req.risk_descr || '') : '—') + '</td>';
|
||||||
|
html += '<td class="mr-yn ' + (req.applies_important ? 'y' : 'n') + '">' + (req.applies_important ? '✓' : '—') + '</td>';
|
||||||
|
html += '<td class="mr-yn ' + (req.applies_essential ? 'y' : 'n') + '">' + (req.applies_essential ? '✓' : '—') + '</td>';
|
||||||
|
html += '</tr>';
|
||||||
|
});
|
||||||
|
html += '</tbody></table></div>';
|
||||||
|
});
|
||||||
|
el('mr-list').innerHTML = html;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -424,6 +424,6 @@ curl https://nis2.agile.software/api/services/status</pre>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script src="js/common.js?v=20260620"></script>
|
<script src="js/common.js?v=20260621"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -112,8 +112,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -124,8 +124,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
loadSidebar();
|
loadSidebar();
|
||||||
|
|||||||
@@ -494,8 +494,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Stessa logica della onboarding.html: ZERO modifiche backend -->
|
<!-- Stessa logica della onboarding.html: ZERO modifiche backend -->
|
||||||
<script src="js/api.js?v=20260620"></script>
|
<script src="js/api.js?v=20260621"></script>
|
||||||
<script src="js/common.js?v=20260620"></script>
|
<script src="js/common.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth check ──────────────────────────────────────────────────
|
// ── Auth check ──────────────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
@@ -138,12 +138,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script src="/js/organigramma.js?v=20260617"></script>
|
<script src="/js/organigramma.js?v=20260617"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -333,8 +333,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -345,8 +345,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth & Init ─────────────────────────────────────────
|
// ── Auth & Init ─────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
+4
-4
@@ -131,12 +131,12 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script src="/js/raci.js?v=20260619"></script>
|
<script src="/js/raci.js?v=20260619"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -268,8 +268,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Stessa logica della register.html: ZERO modifiche backend -->
|
<!-- Stessa logica della register.html: ZERO modifiche backend -->
|
||||||
<script src="js/api.js?v=20260620"></script>
|
<script src="js/api.js?v=20260621"></script>
|
||||||
<script src="js/common.js?v=20260620"></script>
|
<script src="js/common.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
if (api.isAuthenticated()) { window.location.href = 'dashboard.html'; }
|
if (api.isAuthenticated()) { window.location.href = 'dashboard.html'; }
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -443,8 +443,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -455,8 +455,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth & Init ─────────────────────────────────────────
|
// ── Auth & Init ─────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
@@ -141,12 +141,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
/*
|
/*
|
||||||
|
|||||||
+4
-4
@@ -494,8 +494,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -506,8 +506,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth & Init ──────────────────────────────────────────────
|
// ── Auth & Init ──────────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
@@ -672,8 +672,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -684,8 +684,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth check ───────────────────────────────────────────
|
// ── Auth check ───────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
@@ -165,8 +165,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="js/api.js?v=20260620"></script>
|
<script src="js/api.js?v=20260621"></script>
|
||||||
<script src="js/common.js?v=20260620"></script>
|
<script src="js/common.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth check ───────────────────────────────────────────
|
// ── Auth check ───────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
@@ -124,12 +124,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -477,8 +477,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -489,8 +489,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth & Init ─────────────────────────────────────────
|
// ── Auth & Init ─────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@
|
|||||||
* Il nome cache include la release: va BUMPATO ad ogni rilascio (vedi version.json),
|
* Il nome cache include la release: va BUMPATO ad ogni rilascio (vedi version.json),
|
||||||
* cosi' activate elimina automaticamente la shell vecchia.
|
* cosi' activate elimina automaticamente la shell vecchia.
|
||||||
*/
|
*/
|
||||||
const CACHE = 'nis2-shell-v1.17.0';
|
const CACHE = 'nis2-shell-v1.18.0';
|
||||||
|
|
||||||
const PRECACHE = [
|
const PRECACHE = [
|
||||||
'/offline.html',
|
'/offline.html',
|
||||||
|
|||||||
@@ -292,8 +292,8 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -304,8 +304,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
// ── Auth & Init ─────────────────────────────────────────
|
// ── Auth & Init ─────────────────────────────────────────
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
{"version": "1.17.2", "build": "2026-06-15-v1.17.2", "date": "2026-06-15", "changelog": "A4 Fasi 4.4 (scadenziario centralizzato review_schedule: list/complete/sync, mig.044) e 4.5 (stakeholder estesi a clienti/partner GV.SC-02: suppliers.stakeholder_type, stakeholderMap, mig.045) - completano A4 (5/5 fasi). Nuove pagine review-schedule.html, stakeholders.html. Nessuna modifica a dati esistenti."}
|
{"version": "1.18.0", "build": "2026-06-16-v1.18.0", "date": "2026-06-16", "changelog": "Epic C / C1 - Elenco canonico Misure/Requisiti (Determinazione ACN 164179/2025) come tabelle di configurazione (mig.046: cfg_nis2_ambiti/misure/requisiti/procedure/rischi, 43 misure/116 requisiti/42 procedure/84 rischi, codifica autoritativa Simon). Nuova pagina misure-requisiti.html (sola lettura, vista per misura/per area, righe che si spengono per classe) + FrameworkController GET /framework/catalog. Help + i18n + sidebar (sezione Compliance). Additivo, nessuna modifica a dati esistenti."}
|
||||||
|
|||||||
@@ -207,8 +207,8 @@
|
|||||||
|
|
||||||
<!-- Report Detail Modal handled by common.js showModal -->
|
<!-- Report Detail Modal handled by common.js showModal -->
|
||||||
|
|
||||||
<script src="/js/api.js?v=20260620"></script>
|
<script src="/js/api.js?v=20260621"></script>
|
||||||
<script src="/js/common.js?v=20260620"></script>
|
<script src="/js/common.js?v=20260621"></script>
|
||||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||||
riusando tutti gli helper di common.js (zero backend). -->
|
riusando tutti gli helper di common.js (zero backend). -->
|
||||||
@@ -219,8 +219,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/common-bi.js?v=20260618"></script>
|
<script src="/js/common-bi.js?v=20260618"></script>
|
||||||
<script src="/js/i18n.js?v=20260620"></script>
|
<script src="/js/i18n.js?v=20260621"></script>
|
||||||
<script src="/js/help.js?v=20260620"></script>
|
<script src="/js/help.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
loadSidebar();
|
loadSidebar();
|
||||||
|
|||||||
@@ -319,9 +319,9 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="js/api.js?v=20260620"></script>
|
<script src="js/api.js?v=20260621"></script>
|
||||||
<script src="js/common.js?v=20260620"></script>
|
<script src="js/common.js?v=20260621"></script>
|
||||||
<script src="js/i18n.js?v=20260620"></script>
|
<script src="js/i18n.js?v=20260621"></script>
|
||||||
<script>
|
<script>
|
||||||
if (!checkAuth()) throw new Error('Not authenticated');
|
if (!checkAuth()) throw new Error('Not authenticated');
|
||||||
loadSidebar();
|
loadSidebar();
|
||||||
|
|||||||
Reference in New Issue
Block a user