[FIX] Epic C / C1 — correzioni post-verifica flotta (1 major + 5 minor)

Flotta di verifica (14 agenti): sicurezza pulita, fedeltà del dato perfetta (codifica
Simon intatta, 0 scostamenti). Corretti i 6 finding confermati:
- MAJOR: PolicyController::ensureFrameworkProcedures ora in transazione + SELECT...FOR UPDATE
  sulla riga org -> no procedure duplicate su fallimento parziale (rollback) o richieste concorrenti.
- MINOR: importer idempotente committato application/cli/seed_framework.php (DDL + upsert da
  nis2_framework_seed.json) -> re-seed riproducibile/versionato (verificato 2 run = 0 duplicati).
- MINOR: allineato '92 requisiti' importanti (dato autoritativo Simon) in help.js + nis2_sources.php
  (era 87, contraddizione interna); coerente '24 requisiti aggiuntivi essenziali' (116-92).
- MINOR (UI): troncamento anteprima valutazione sul RAW prima di esc() (no entita HTML spezzate).
- MINOR (UI a11y/AGID): modale valutazione con focus iniziale, ripristino focus, focus-trap.
Cache-buster ?v=20260623, version 1.18.2, SW nis2-shell-v1.18.2.
NB residuo da verificare: data esatta Determinazione 333017/2025 (mese senza giorno) in nis2_sources.php.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-16 18:40:31 +02:00
co-authored by Claude Opus 4.8
parent 1f2d48df7c
commit 45e6c3599c
41 changed files with 278 additions and 130 deletions
+121
View File
@@ -0,0 +1,121 @@
<?php
/**
* NIS2 Agile — Importer idempotente del framework canonico (Epic C / C1).
* ----------------------------------------------------------------------------
* Crea (se mancanti) le tabelle di configurazione cfg_nis2_* (mig.046) e le
* popola dal seed autoritativo application/data/nis2_framework_seed.json
* (generato dai file docs/simon/*.xlsx — codifica NON variabile).
*
* Idempotente: CREATE TABLE IF NOT EXISTS + INSERT ... ON DUPLICATE KEY UPDATE.
* Rilanciabile senza duplicare né rompere le FK. Pensato per ricreare/riseedare
* un ambiente in modo versionato (sostituisce i runner temporanei usa-e-getta).
*
* Uso (dentro il container app):
* docker exec nis2-app php /var/www/nis2-agile/application/cli/seed_framework.php
*
* NB: solo CLI. DB API via PDO singleton (Database::getInstance()), TLS gestito
* dalla config dell'app.
*/
if (PHP_SAPI !== 'cli') {
http_response_code(403);
exit("Solo da CLI.\n");
}
require_once __DIR__ . '/../config/env.php';
require_once __DIR__ . '/../config/database.php';
$pdo = Database::getInstance();
$pdo->exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci");
$ddl = [
"CREATE TABLE IF NOT EXISTS cfg_nis2_ambiti (
nist_code VARCHAR(16) NOT NULL, nist_descr TEXT NOT NULL,
PRIMARY KEY (nist_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
"CREATE TABLE IF NOT EXISTS cfg_nis2_procedure (
proc_code VARCHAR(16) NOT NULL, proc_descr TEXT NOT NULL,
PRIMARY KEY (proc_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
"CREATE TABLE IF NOT EXISTS cfg_nis2_rischi (
risk_code VARCHAR(16) NOT NULL, risk_descr TEXT NOT NULL,
PRIMARY KEY (risk_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
"CREATE TABLE IF NOT EXISTS cfg_nis2_misure (
misura_code VARCHAR(16) NOT NULL, nist_code VARCHAR(16) NOT NULL,
area_politica VARCHAR(255) NOT NULL, misura_descr TEXT NOT NULL, ord INT NOT NULL,
applies_important TINYINT(1) NOT NULL DEFAULT 1, applies_essential TINYINT(1) NOT NULL DEFAULT 1,
PRIMARY KEY (misura_code), KEY idx_misura_nist (nist_code), KEY idx_misura_ord (ord),
CONSTRAINT fk_misura_ambito FOREIGN KEY (nist_code) REFERENCES cfg_nis2_ambiti (nist_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
"CREATE TABLE IF NOT EXISTS cfg_nis2_requisiti (
id INT NOT NULL AUTO_INCREMENT, n INT NULL, misura_code VARCHAR(16) NOT NULL,
requisito_code VARCHAR(32) NOT NULL, requisito_descr TEXT NOT NULL,
proc_code VARCHAR(16) NULL, risk_code VARCHAR(16) NULL,
applies_important TINYINT(1) NOT NULL DEFAULT 0, applies_essential TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (id), UNIQUE KEY uq_req (misura_code, requisito_code),
KEY idx_req_misura (misura_code), KEY idx_req_proc (proc_code), KEY idx_req_risk (risk_code),
CONSTRAINT fk_req_misura FOREIGN KEY (misura_code) REFERENCES cfg_nis2_misure (misura_code),
CONSTRAINT fk_req_proc FOREIGN KEY (proc_code) REFERENCES cfg_nis2_procedure (proc_code),
CONSTRAINT fk_req_risk FOREIGN KEY (risk_code) REFERENCES cfg_nis2_rischi (risk_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
];
foreach ($ddl as $stmt) {
try { $pdo->exec($stmt); }
catch (PDOException $e) { if (!in_array($e->errorInfo[1] ?? 0, [1050, 1061], true)) { throw $e; } }
}
$seedPath = __DIR__ . '/../data/nis2_framework_seed.json';
$seed = json_decode(@file_get_contents($seedPath), true);
if (!$seed) { fwrite(STDERR, "SEED non leggibile: $seedPath\n"); exit(1); }
$pdo->beginTransaction();
try {
$st = $pdo->prepare("INSERT INTO cfg_nis2_ambiti (nist_code,nist_descr) VALUES (?,?)
ON DUPLICATE KEY UPDATE nist_descr=VALUES(nist_descr)");
foreach ($seed['ambiti_nist'] as $a) { $st->execute([$a['nist_code'], $a['nist_descr']]); }
$st = $pdo->prepare("INSERT INTO cfg_nis2_procedure (proc_code,proc_descr) VALUES (?,?)
ON DUPLICATE KEY UPDATE proc_descr=VALUES(proc_descr)");
foreach ($seed['procedure'] as $p) { $st->execute([$p['proc_code'], $p['proc_descr']]); }
$st = $pdo->prepare("INSERT INTO cfg_nis2_rischi (risk_code,risk_descr) VALUES (?,?)
ON DUPLICATE KEY UPDATE risk_descr=VALUES(risk_descr)");
foreach ($seed['rischi'] as $r) { $st->execute([$r['risk_code'], $r['risk_descr']]); }
$st = $pdo->prepare("INSERT INTO cfg_nis2_misure
(misura_code,nist_code,area_politica,misura_descr,ord,applies_important,applies_essential)
VALUES (?,?,?,?,?,?,?)
ON DUPLICATE KEY UPDATE nist_code=VALUES(nist_code),area_politica=VALUES(area_politica),
misura_descr=VALUES(misura_descr),ord=VALUES(ord),
applies_important=VALUES(applies_important),applies_essential=VALUES(applies_essential)");
foreach ($seed['misure'] as $m) {
$st->execute([$m['misura_code'], $m['nist_code'], $m['area_politica'], $m['misura_descr'],
$m['ord'], $m['applies_important'], $m['applies_essential']]);
}
$st = $pdo->prepare("INSERT INTO cfg_nis2_requisiti
(n,misura_code,requisito_code,requisito_descr,proc_code,risk_code,applies_important,applies_essential)
VALUES (?,?,?,?,?,?,?,?)
ON DUPLICATE KEY UPDATE n=VALUES(n),requisito_descr=VALUES(requisito_descr),
proc_code=VALUES(proc_code),risk_code=VALUES(risk_code),
applies_important=VALUES(applies_important),applies_essential=VALUES(applies_essential)");
foreach ($seed['requisiti'] as $q) {
$st->execute([$q['n'], $q['misura_code'], $q['requisito_code'], $q['requisito_descr'],
$q['proc_code'], $q['risk_code'], $q['applies_important'], $q['applies_essential']]);
}
$pdo->commit();
} catch (Throwable $e) {
$pdo->rollBack();
fwrite(STDERR, "SEED FALLITO: " . $e->getMessage() . "\n");
exit(1);
}
$counts = [
'ambiti' => (int) $pdo->query("SELECT COUNT(*) FROM cfg_nis2_ambiti")->fetchColumn(),
'procedure' => (int) $pdo->query("SELECT COUNT(*) FROM cfg_nis2_procedure")->fetchColumn(),
'rischi' => (int) $pdo->query("SELECT COUNT(*) FROM cfg_nis2_rischi")->fetchColumn(),
'misure' => (int) $pdo->query("SELECT COUNT(*) FROM cfg_nis2_misure")->fetchColumn(),
'requisiti' => (int) $pdo->query("SELECT COUNT(*) FROM cfg_nis2_requisiti")->fetchColumn(),
];
echo "OK seed-framework — " . json_encode($counts, JSON_UNESCAPED_UNICODE) . "\n";
+1 -1
View File
@@ -76,7 +76,7 @@ return [
'key' => 'acn_specifiche_base_2025', 'key' => 'acn_specifiche_base_2025',
'short' => 'Specifiche di base ACN (Framework Nazionale 2025)', 'short' => 'Specifiche di base ACN (Framework Nazionale 2025)',
'citation' => 'ACN, Misure di sicurezza di base NIS - Allegati 1 e 2 alla Determinazione n. 164179/2025', 'citation' => 'ACN, Misure di sicurezza di base NIS - Allegati 1 e 2 alla Determinazione n. 164179/2025',
'full' => 'Misure di sicurezza di base (Determinazione ACN 164179/2025) articolate secondo il Framework Nazionale per la Cybersecurity e la Data Protection (ed. 2025): funzioni Governance (GV), Identificazione (ID), Protezione (PR), Rilevazione (DE), Risposta (RS), Ripristino (RC), poi categorie, sottocategorie e requisiti. Soggetti importanti: 37 misure / 87 requisiti (Allegato 1). Soggetti essenziali: 43 misure / 116 requisiti (Allegato 2), codifica identica con requisiti aggiuntivi. Esempi: GV.RR-04 (cybersicurezza nelle risorse umane, adeguatezza al ruolo), GV.PO-01 (policy di gestione del rischio). Adozione: 18 mesi dalla notifica di inserimento nell elenco NIS.', 'full' => 'Misure di sicurezza di base (Determinazione ACN 164179/2025) articolate secondo il Framework Nazionale per la Cybersecurity e la Data Protection (ed. 2025): funzioni Governance (GV), Identificazione (ID), Protezione (PR), Rilevazione (DE), Risposta (RS), Ripristino (RC), poi categorie, sottocategorie e requisiti. Soggetti importanti: 37 misure / 92 requisiti (Allegato 1). Soggetti essenziali: 43 misure / 116 requisiti (Allegato 2), codifica identica con requisiti aggiuntivi. Esempi: GV.RR-04 (cybersicurezza nelle risorse umane, adeguatezza al ruolo), GV.PO-01 (policy di gestione del rischio). Adozione: 18 mesi dalla notifica di inserimento nell elenco NIS.',
'file' => 'docs/nis2/Determina164179_apr2025.pdf', 'file' => 'docs/nis2/Determina164179_apr2025.pdf',
'authority' => 'Agenzia per la Cybersicurezza Nazionale (ACN)', 'authority' => 'Agenzia per la Cybersicurezza Nazionale (ACN)',
'url' => 'https://www.acn.gov.it/portale/nis/modalita-specifiche-base', 'url' => 'https://www.acn.gov.it/portale/nis/modalita-specifiche-base',
+11 -3
View File
@@ -67,12 +67,18 @@ class PolicyController extends BaseController
if (!empty($this->isDemo)) { return; } if (!empty($this->isDemo)) { return; }
$orgId = $this->getCurrentOrgId(); $orgId = $this->getCurrentOrgId();
if (!$orgId) { return; } if (!$orgId) { return; }
$pdo = Database::getInstance();
try { try {
// Transazione + lock di riga: serializza richieste concorrenti (niente doppio
// seed) e, in caso di fallimento parziale, il rollback annulla gli insert già
// fatti (niente procedure duplicate alla ri-prova). Il flag si scrive nello
// stesso commit degli insert.
$pdo->beginTransaction();
$org = Database::fetchOne( $org = Database::fetchOne(
'SELECT framework_procedures_seeded_at FROM organizations WHERE id = ?', 'SELECT framework_procedures_seeded_at FROM organizations WHERE id = ? FOR UPDATE',
[$orgId] [$orgId]
); );
if (!$org || $org['framework_procedures_seeded_at'] !== null) { return; } if (!$org || $org['framework_procedures_seeded_at'] !== null) { $pdo->commit(); return; }
$procs = Database::fetchAll( $procs = Database::fetchAll(
"SELECT p.proc_code, p.proc_descr, "SELECT p.proc_code, p.proc_descr,
@@ -85,7 +91,7 @@ class PolicyController extends BaseController
FROM cfg_nis2_requisiti q3 WHERE q3.proc_code = p.proc_code) AS misure FROM cfg_nis2_requisiti q3 WHERE q3.proc_code = p.proc_code) AS misure
FROM cfg_nis2_procedure p ORDER BY p.proc_code" FROM cfg_nis2_procedure p ORDER BY p.proc_code"
); );
if (!$procs) { return; } // framework non ancora seedato: riprova al prossimo accesso if (!$procs) { $pdo->commit(); return; } // framework non ancora seedato: riprova al prossimo accesso
foreach ($procs as $p) { foreach ($procs as $p) {
$cat = self::PROC_NIST_CATEGORY[$p['nist_code'] ?? ''] ?? 'information_security'; $cat = self::PROC_NIST_CATEGORY[$p['nist_code'] ?? ''] ?? 'information_security';
@@ -107,7 +113,9 @@ class PolicyController extends BaseController
'UPDATE organizations SET framework_procedures_seeded_at = NOW() WHERE id = ?', 'UPDATE organizations SET framework_procedures_seeded_at = NOW() WHERE id = ?',
[$orgId] [$orgId]
); );
$pdo->commit();
} catch (Throwable $e) { } catch (Throwable $e) {
if ($pdo->inTransaction()) { $pdo->rollBack(); }
error_log('[PolicyController] seed procedure default fallito (org ' . $orgId . '): ' . $e->getMessage()); error_log('[PolicyController] seed procedure default fallito (org ' . $orgId . '): ' . $e->getMessage());
} }
} }
+2 -2
View File
@@ -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=20260622"></script> <script src="js/api.js?v=20260623"></script>
<script src="js/common.js?v=20260622"></script> <script src="js/common.js?v=20260623"></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
View File
@@ -152,8 +152,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
'use strict'; 'use strict';
const FUNC_LABELS = { const FUNC_LABELS = {
+4 -4
View File
@@ -1088,10 +1088,10 @@
</main> </main>
</div> </div>
<script src="js/api.js?v=20260622"></script> <script src="js/api.js?v=20260623"></script>
<script src="js/common.js?v=20260622"></script> <script src="js/common.js?v=20260623"></script>
<script src="js/i18n.js?v=20260622"></script> <script src="js/i18n.js?v=20260623"></script>
<script src="js/help.js?v=20260622"></script> <script src="js/help.js?v=20260623"></script>
<script> <script>
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
loadSidebar(); loadSidebar();
+4 -4
View File
@@ -154,8 +154,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
// ── Auth check ─────────────────────────────────────────── // ── Auth check ───────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+4 -4
View File
@@ -366,8 +366,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
// ── Auth & Init ───────────────────────────────────────── // ── Auth & Init ─────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+4 -4
View File
@@ -349,14 +349,14 @@
</main> </main>
</div> </div>
<script src="js/api.js?v=20260622"></script> <script src="js/api.js?v=20260623"></script>
<script src="js/common.js?v=20260622"></script> <script src="js/common.js?v=20260623"></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=20260622"></script> <script src="js/i18n.js?v=20260623"></script>
<script src="js/help.js?v=20260622"></script> <script src="js/help.js?v=20260623"></script>
<script> <script>
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+4 -4
View File
@@ -183,12 +183,12 @@
</div> </div>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script src="/js/competenze.js?v=20260617"></script> <script src="/js/competenze.js?v=20260617"></script>
</body> </body>
</html> </html>
+3 -3
View File
@@ -382,8 +382,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></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>`; }
+4 -4
View File
@@ -143,8 +143,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
// ── Auth check ─────────────────────────────────────────── // ── Auth check ───────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+1 -1
View File
@@ -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=20260622"></script> <script src="js/api.js?v=20260623"></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
View File
@@ -1142,8 +1142,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></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
+4 -4
View File
@@ -351,8 +351,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
// ── Auth & Init ────────────────────────────────────────────── // ── Auth & Init ──────────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+2 -2
View File
@@ -910,8 +910,8 @@ curl -H <span class="str">"X-API-Key: nis2_TUA_CHIAVE"</span> \
</main> </main>
<script src="js/common.js?v=20260622"></script> <script src="js/common.js?v=20260623"></script>
<script src="js/i18n.js?v=20260622"></script> <script src="js/i18n.js?v=20260623"></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
View File
@@ -184,8 +184,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script src="/js/isms.js"></script> <script src="/js/isms.js"></script>
</body> </body>
</html> </html>
+3 -3
View File
@@ -121,8 +121,8 @@ const HelpSystem = (function () {
{ {
heading: 'Importanti vs Essenziali', heading: 'Importanti vs Essenziali',
items: [ items: [
'Il perimetro dipende dalla classificazione del soggetto: <strong>importante</strong> (Allegato 1) = <strong>37 misure / 87 requisiti</strong>; <strong>essenziale</strong> (Allegato 2) = <strong>43 misure / 116 requisiti</strong>.', 'Il perimetro dipende dalla classificazione del soggetto: <strong>importante</strong> (Allegato 1) = <strong>37 misure / 92 requisiti</strong>; <strong>essenziale</strong> (Allegato 2) = <strong>43 misure / 116 requisiti</strong>.',
'La codifica dei requisiti e\' <strong>identica</strong> per i due livelli (stessi codici GV/ID/PR/DE/RS/RC): agli essenziali si aggiungono 6 misure e 29 requisiti, oltre a punti aggiuntivi su misure gia\' presenti.', 'La codifica dei requisiti e\' <strong>identica</strong> per i due livelli (stessi codici GV/ID/PR/DE/RS/RC): agli essenziali si aggiungono 6 misure e 24 requisiti, oltre a punti aggiuntivi su misure gia\' presenti.',
'L\'app filtra automaticamente i requisiti applicabili in base al livello del soggetto (Impostazioni › Classificazione NIS2).' 'L\'app filtra automaticamente i requisiti applicabili in base al livello del soggetto (Impostazioni › Classificazione NIS2).'
] ]
}, },
@@ -152,7 +152,7 @@ const HelpSystem = (function () {
], ],
references: [ references: [
'Determinazione ACN n. 164179 del 14/04/2025 - Misure di sicurezza di base per i soggetti NIS', 'Determinazione ACN n. 164179 del 14/04/2025 - Misure di sicurezza di base per i soggetti NIS',
'Allegato 1 - Misure di base per i soggetti IMPORTANTI (37 misure, 87 requisiti)', 'Allegato 1 - Misure di base per i soggetti IMPORTANTI (37 misure, 92 requisiti)',
'Allegato 2 - Misure di base per i soggetti ESSENZIALI (43 misure, 116 requisiti)', 'Allegato 2 - Misure di base per i soggetti ESSENZIALI (43 misure, 116 requisiti)',
'Framework Nazionale per la Cybersecurity e la Data Protection - funzioni GV/ID/PR/DE/RS/RC', 'Framework Nazionale per la Cybersecurity e la Data Protection - funzioni GV/ID/PR/DE/RS/RC',
'Art. 24 D.Lgs. 138/2024 (recepisce l\'art. 21 della Direttiva (UE) 2022/2555) - base normativa primaria' 'Art. 24 D.Lgs. 138/2024 (recepisce l\'art. 21 della Direttiva (UE) 2022/2555) - base normativa primaria'
+4 -4
View File
@@ -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=20260622"></script> <script src="/js/common.js?v=20260623"></script>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></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.
+1 -1
View File
@@ -515,7 +515,7 @@ body { background: var(--bg-main); }
<div id="toast"></div> <div id="toast"></div>
<script src="js/api.js?v=20260622"></script> <script src="js/api.js?v=20260623"></script>
<script> <script>
// ══════════════════════════════════════════════════════ // ══════════════════════════════════════════════════════
// CONFIG // CONFIG
+2 -2
View File
@@ -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=20260622"></script> <script src="js/api.js?v=20260623"></script>
<script src="js/common.js?v=20260622"></script> <script src="js/common.js?v=20260623"></script>
<script> <script>
if (api.isAuthenticated()) { window.location.href = 'dashboard.html'; } if (api.isAuthenticated()) { window.location.href = 'dashboard.html'; }
+27 -8
View File
@@ -6,7 +6,7 @@
<title>Misure e Requisiti - NIS2 Agile</title> <title>Misure e Requisiti - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css. --> <!-- 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="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
<link rel="stylesheet" href="/css/style.css?v=20260622"> <link rel="stylesheet" href="/css/style.css?v=20260623">
<style> <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-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-note { font-size:.82rem; color:#92400e; background:#fffbeb; border:1px solid #fde68a; border-radius:8px; padding:10px 12px; margin:0 0 16px; }
@@ -162,12 +162,12 @@
</div> </div>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
'use strict'; 'use strict';
/* /*
@@ -301,7 +301,8 @@
html += '<td class="mr-yn ' + (req.applies_essential ? 'y' : 'n') + '">' + (req.applies_essential ? '✓' : '—') + '</td>'; html += '<td class="mr-yn ' + (req.applies_essential ? 'y' : 'n') + '">' + (req.applies_essential ? '✓' : '—') + '</td>';
if (MR.has_org) { if (MR.has_org) {
const sm = statoMeta(req.stato); const sm = statoMeta(req.stato);
const val = req.valutazione_rischio ? esc(req.valutazione_rischio).slice(0, 90) + (req.valutazione_rischio.length > 90 ? '…' : '') : ''; const _vr = req.valutazione_rischio || '';
const val = _vr ? esc(_vr.slice(0, 90)) + (_vr.length > 90 ? '…' : '') : '';
html += '<td><button type="button" class="sv-badge ' + sm.cls + '" onclick="mrEdit(' + req.id + ')" title="Modifica valutazione">' + esc(sm.label) + '</button>' + html += '<td><button type="button" class="sv-badge ' + sm.cls + '" onclick="mrEdit(' + req.id + ')" title="Modifica valutazione">' + esc(sm.label) + '</button>' +
(val ? '<div class="sv-val">' + val + '</div>' : '') + '</td>'; (val ? '<div class="sv-val">' + val + '</div>' : '') + '</td>';
} }
@@ -325,9 +326,14 @@
el('mr-eval-val').value = q.valutazione_rischio || ''; el('mr-eval-val').value = q.valutazione_rischio || '';
el('mr-eval-note').value = q.note || ''; el('mr-eval-note').value = q.note || '';
el('mr-eval-err').textContent = ''; el('mr-eval-err').textContent = '';
MR._lastFocus = document.activeElement;
el('mr-modal').classList.add('open'); el('mr-modal').classList.add('open');
setTimeout(function () { const s = el('mr-eval-stato'); if (s) s.focus(); }, 0);
}
function mrCloseEval() {
el('mr-modal').classList.remove('open');
if (MR._lastFocus && typeof MR._lastFocus.focus === 'function') { try { MR._lastFocus.focus(); } catch (e) {} }
} }
function mrCloseEval() { el('mr-modal').classList.remove('open'); }
async function mrSaveEval() { async function mrSaveEval() {
const reqId = parseInt(el('mr-eval-id').value, 10); const reqId = parseInt(el('mr-eval-id').value, 10);
const btn = el('mr-eval-save'); const btn = el('mr-eval-save');
@@ -350,7 +356,20 @@
} finally { btn.disabled = false; } } finally { btn.disabled = false; }
} }
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') mrCloseEval(); }); document.addEventListener('keydown', function (e) { if (e.key === 'Escape') mrCloseEval(); });
(function () { const ov = el('mr-modal'); if (ov) ov.addEventListener('click', function (e) { if (e.target === ov) mrCloseEval(); }); })(); (function () {
const ov = el('mr-modal'); if (!ov) return;
ov.addEventListener('click', function (e) { if (e.target === ov) mrCloseEval(); });
// focus-trap: Tab/Shift+Tab restano dentro la modale aperta
ov.addEventListener('keydown', function (e) {
if (e.key !== 'Tab' || !ov.classList.contains('open')) return;
const nodes = ov.querySelectorAll('select, textarea, button');
const list = Array.prototype.filter.call(nodes, function (x) { return !x.disabled && x.offsetParent !== null; });
if (!list.length) return;
const first = list[0], last = list[list.length - 1];
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
});
})();
</script> </script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -424,6 +424,6 @@ curl https://nis2.agile.software/api/services/status</pre>
</div> </div>
</div> </div>
<script src="js/common.js?v=20260622"></script> <script src="js/common.js?v=20260623"></script>
</body> </body>
</html> </html>
+4 -4
View File
@@ -112,8 +112,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
loadSidebar(); loadSidebar();
+2 -2
View File
@@ -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=20260622"></script> <script src="js/api.js?v=20260623"></script>
<script src="js/common.js?v=20260622"></script> <script src="js/common.js?v=20260623"></script>
<script> <script>
// ── Auth check ────────────────────────────────────────────────── // ── Auth check ──────────────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+4 -4
View File
@@ -138,12 +138,12 @@
</div> </div>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script src="/js/organigramma.js?v=20260617"></script> <script src="/js/organigramma.js?v=20260617"></script>
</body> </body>
</html> </html>
+4 -4
View File
@@ -333,8 +333,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
// ── Auth & Init ───────────────────────────────────────── // ── Auth & Init ─────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+4 -4
View File
@@ -131,12 +131,12 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script src="/js/raci.js?v=20260619"></script> <script src="/js/raci.js?v=20260619"></script>
</body> </body>
</html> </html>
+2 -2
View File
@@ -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=20260622"></script> <script src="js/api.js?v=20260623"></script>
<script src="js/common.js?v=20260622"></script> <script src="js/common.js?v=20260623"></script>
<script> <script>
if (api.isAuthenticated()) { window.location.href = 'dashboard.html'; } if (api.isAuthenticated()) { window.location.href = 'dashboard.html'; }
+4 -4
View File
@@ -443,8 +443,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
// ── Auth & Init ───────────────────────────────────────── // ── Auth & Init ─────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+4 -4
View File
@@ -141,12 +141,12 @@
</div> </div>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
'use strict'; 'use strict';
/* /*
+4 -4
View File
@@ -494,8 +494,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
// ── Auth & Init ────────────────────────────────────────────── // ── Auth & Init ──────────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+4 -4
View File
@@ -672,8 +672,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
// ── Auth check ─────────────────────────────────────────── // ── Auth check ───────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+2 -2
View File
@@ -165,8 +165,8 @@
</main> </main>
</div> </div>
<script src="js/api.js?v=20260622"></script> <script src="js/api.js?v=20260623"></script>
<script src="js/common.js?v=20260622"></script> <script src="js/common.js?v=20260623"></script>
<script> <script>
// ── Auth check ─────────────────────────────────────────── // ── Auth check ───────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+4 -4
View File
@@ -124,12 +124,12 @@
</div> </div>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
'use strict'; 'use strict';
/* /*
+4 -4
View File
@@ -477,8 +477,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
// ── Auth & Init ───────────────────────────────────────── // ── Auth & Init ─────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+1 -1
View File
@@ -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.18.1'; const CACHE = 'nis2-shell-v1.18.2';
const PRECACHE = [ const PRECACHE = [
'/offline.html', '/offline.html',
+4 -4
View File
@@ -292,8 +292,8 @@
</main> </main>
</div> </div>
<script src="/js/api.js?v=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
// ── Auth & Init ───────────────────────────────────────── // ── Auth & Init ─────────────────────────────────────────
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
+1 -1
View File
@@ -1 +1 @@
{"version": "1.18.1", "build": "2026-06-16-v1.18.1", "date": "2026-06-16", "changelog": "Epic C / C1 operativo: valutazione/stato di conformità per requisito (org_requisito_state, mig.047) editabile dalla pagina Misure e Requisiti - da qui emerge la conformità (sostituisce Gap ACN); copia delle 42 procedure di default nel modulo Procedure al 1° accesso (mig.048, idempotente, org demo escluse). Help/KB aggiornati. Additivo."} {"version": "1.18.2", "build": "2026-06-16-v1.18.2", "date": "2026-06-16", "changelog": "Epic C / C1 - fix post verifica flotta: copia procedure ora transazionale (SELECT FOR UPDATE, anti-duplicati su fallimento parziale/concorrenza); importer idempotente committato (application/cli/seed_framework.php); allineato conteggio requisiti importanti 92 (dato autoritativo Simon) in help/registry fonti; troncamento anteprima valutazione corretto (raw prima di esc); focus management modale (a11y). Additivo."}
+4 -4
View File
@@ -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=20260622"></script> <script src="/js/api.js?v=20260623"></script>
<script src="/js/common.js?v=20260622"></script> <script src="/js/common.js?v=20260623"></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=20260622"></script> <script src="/js/i18n.js?v=20260623"></script>
<script src="/js/help.js?v=20260622"></script> <script src="/js/help.js?v=20260623"></script>
<script> <script>
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
loadSidebar(); loadSidebar();
+3 -3
View File
@@ -319,9 +319,9 @@
</main> </main>
</div> </div>
<script src="js/api.js?v=20260622"></script> <script src="js/api.js?v=20260623"></script>
<script src="js/common.js?v=20260622"></script> <script src="js/common.js?v=20260623"></script>
<script src="js/i18n.js?v=20260622"></script> <script src="js/i18n.js?v=20260623"></script>
<script> <script>
if (!checkAuth()) throw new Error('Not authenticated'); if (!checkAuth()) throw new Error('Not authenticated');
loadSidebar(); loadSidebar();