[FEAT] Connettori Discovery — UI gestione per org (Fase 4)
Pagina connettori-discovery.html + connettori-discovery.js (DiscoveryUI): lista connettori, crea (mostra la chiave API una sola volta + comando agente), dettaglio con storico run, rigenera chiave, elimina. Solo org_admin. - Voce sidebar V2 "Connettori Discovery" in Operativo (common-bi.js, data-nav auto). - api.js: metodi list/create/get/update/delete/rotateDiscoveryKey. - ARIA navigationMapBlock: aggiunta la voce (coerenza assistente↔menu). - help.js: _pageMap + guida contestuale "Connettori Discovery" (multi-connettore, come funziona, sicurezza scope ingest:assets). Smoke: pagina 200, /api/discovery-connectors/list 401 (auth). Cache-buster common-bi/help/api -> 20260625d. 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
3d0bec1f7f
commit
01b016da50
@@ -71,7 +71,7 @@ class AIService
|
||||
return "\n## MAPPA DELLA NAVIGAZIONE (barra laterale REALE dell'app)\n"
|
||||
. "Sezione \"Principale\": Dashboard · Calendario · Compliance Journey · Gap Analysis · Misure e Requisiti · Modello SGSI (ISO 27001).\n"
|
||||
. "Sezione \"Gestione\": Organigramma · Competenze · Rischi · Incidenti · Policy · Supply Chain · Stakeholder · Attivita' stakeholder · Segnalazioni · Normative · AI Cross-Analysis · Knowledge Base.\n"
|
||||
. "Sezione \"Operativo\": Formazione · Inventario · Audit interni · Controlli periodici · Riesame di Direzione · Audit & Report.\n"
|
||||
. "Sezione \"Operativo\": Formazione · Inventario · Connettori Discovery · Audit interni · Controlli periodici · Riesame di Direzione · Audit & Report.\n"
|
||||
. "Sezione \"Sistema\": Guida all'uso · Impostazioni · Architettura · Simulazione Demo · Integrazioni Esterne.\n"
|
||||
. "\nREGOLE DI NAVIGAZIONE (vincolanti):\n"
|
||||
. "1. Quando indichi DOVE cliccare o COME raggiungere una funzione, usa ESCLUSIVAMENTE i nomi delle voci qui sopra, esattamente come scritti, indicando la sezione (es. \"nella sezione Operativo, voce Inventario\").\n"
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<!-- Stessa logica della app: api.js + common.js (helper) + common-bi.js (override BI) -->
|
||||
<script src="js/api.js?v=20260631"></script>
|
||||
<script src="js/common.js?v=20260624g"></script>
|
||||
<script src="js/common-bi.js?v=20260624f"></script>
|
||||
<script src="js/common-bi.js?v=20260625d"></script>
|
||||
<script>
|
||||
// Renderizza la sidebar BI (loadSidebar è stato ridefinito da common-bi.js)
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
@@ -317,7 +317,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260620"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -328,7 +328,7 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260620"></script>
|
||||
<script>
|
||||
// ── Auth check ───────────────────────────────────────────
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="../js/api.js?v=20260620"></script>
|
||||
<script src="../js/api.js?v=20260625d"></script>
|
||||
<script src="../js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -158,7 +158,7 @@
|
||||
bootstrap.loadFonts('../vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="../js/common-bi.js?v=20260624f"></script>
|
||||
<script src="../js/common-bi.js?v=20260625d"></script>
|
||||
<script src="../js/i18n.js?v=20260620"></script>
|
||||
<script>
|
||||
// ── Auth check ───────────────────────────────────────────
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="../js/api.js?v=20260620"></script>
|
||||
<script src="../js/api.js?v=20260625d"></script>
|
||||
<script src="../js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -180,7 +180,7 @@
|
||||
bootstrap.loadFonts('../vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="../js/common-bi.js?v=20260624f"></script>
|
||||
<script src="../js/common-bi.js?v=20260625d"></script>
|
||||
<script src="../js/i18n.js?v=20260620"></script>
|
||||
<script>
|
||||
// ── Auth check ───────────────────────────────────────────
|
||||
|
||||
@@ -1093,9 +1093,9 @@
|
||||
<script src="js/api.js?v=20260631"></script>
|
||||
<script src="js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="js/i18n.js?v=20260631"></script>
|
||||
<script src="js/help.js?v=20260625c"></script>
|
||||
<script src="js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
loadSidebar();
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -165,9 +165,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// ── Auth check ───────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
+3
-3
@@ -370,7 +370,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260623g"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -381,9 +381,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// ── Auth & Init ─────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
@@ -151,12 +151,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
/*
|
||||
|
||||
@@ -354,9 +354,9 @@
|
||||
<!-- 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>if (window.bootstrap && bootstrap.loadFonts) { bootstrap.loadFonts('vendor/bootstrap-italia/dist/fonts'); }</script>
|
||||
<script src="js/common-bi.js?v=20260624f"></script>
|
||||
<script src="js/common-bi.js?v=20260625d"></script>
|
||||
<script src="js/i18n.js?v=20260631"></script>
|
||||
<script src="js/help.js?v=20260625c"></script>
|
||||
<script src="js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
|
||||
@@ -183,12 +183,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script src="/js/competenze.js?v=20260617"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Connettori Discovery - NIS2 Agile</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
|
||||
<link rel="stylesheet" href="/css/style.css?v=20260618">
|
||||
<meta name="theme-color" content="#0066CC">
|
||||
<link rel="manifest" href="/manifest.webmanifest">
|
||||
<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">
|
||||
<script src="/js/pwa.js?v=20260614" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar" id="sidebar"></aside>
|
||||
<main class="main-content">
|
||||
<header class="content-header">
|
||||
<h1 class="content-title">Connettori Discovery</h1>
|
||||
<div class="content-header-actions">
|
||||
<button class="btn btn-primary" id="btn-dc-new">+ Nuovo connettore</button>
|
||||
</div>
|
||||
</header>
|
||||
<div class="content-body">
|
||||
<div class="card" style="margin-bottom:16px">
|
||||
<div class="card-body">
|
||||
<p style="margin:0;color:var(--gray-600)">
|
||||
I connettori mappano automaticamente la tua <strong>rete/cloud</strong> e <strong>popolano l'Inventario</strong>
|
||||
(asset + rilevanza NIS2 + Mappa Dipendenze + flussi di rete ID.AM-03). Puoi creare
|
||||
<strong>più connettori per azienda</strong> (es. uno per sede). Ogni connettore ha una <strong>chiave</strong>
|
||||
che usi nell'<em>agente di discovery</em> (vedi <code>scripts/discovery-agent.mjs</code>).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" id="dc-form-card" style="display:none;margin-bottom:16px">
|
||||
<div class="card-header"><h3 style="margin:0">Nuovo connettore</h3></div>
|
||||
<div class="card-body">
|
||||
<div class="form-row" style="display:flex;gap:12px;flex-wrap:wrap">
|
||||
<div class="form-group" style="flex:1;min-width:200px">
|
||||
<label>Nome</label>
|
||||
<input id="dc-name" class="form-control" placeholder="Es. Rete sede Modena" maxlength="120">
|
||||
</div>
|
||||
<div class="form-group" style="min-width:160px">
|
||||
<label>Tipo</label>
|
||||
<select id="dc-type" class="form-control">
|
||||
<option value="network">Rete (scan IP)</option>
|
||||
<option value="aws">AWS</option>
|
||||
<option value="azure">Azure</option>
|
||||
<option value="gcp">GCP</option>
|
||||
<option value="cmdb">CMDB</option>
|
||||
<option value="agent">Agente generico</option>
|
||||
<option value="custom">Custom</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="min-width:160px">
|
||||
<label>Schedulazione</label>
|
||||
<select id="dc-schedule" class="form-control">
|
||||
<option value="manual">Manuale</option>
|
||||
<option value="daily">Giornaliera</option>
|
||||
<option value="hourly">Oraria</option>
|
||||
<option value="weekly">Settimanale</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Target (CIDR/IP, separati da virgola) — descrittivo / usato dall'agente</label>
|
||||
<input id="dc-targets" class="form-control" placeholder="192.168.1.0/24, 10.0.0.5">
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;margin-top:8px">
|
||||
<button class="btn btn-primary" id="btn-dc-create">Crea connettore</button>
|
||||
<button class="btn btn-outline-primary" id="btn-dc-cancel">Annulla</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div id="dc-list">Caricamento…</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/js/api.js?v=20260625d"></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 src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script src="/js/connettori-discovery.js?v=20260625"></script>
|
||||
<script>
|
||||
if (typeof checkAuth === 'function' && !checkAuth()) {
|
||||
// checkAuth reindirizza a login
|
||||
} else {
|
||||
if (typeof loadSidebar === 'function') loadSidebar();
|
||||
if (typeof I18n !== 'undefined' && I18n.init) I18n.init();
|
||||
if (typeof HelpSystem !== 'undefined' && HelpSystem.init) HelpSystem.init();
|
||||
if (window.DiscoveryUI) DiscoveryUI.init();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -136,12 +136,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
/* Controlli periodici (control monitoring §9.1/A.8.16): controlli ricorrenti + esecuzioni (evidenza) + NC/AC. */
|
||||
|
||||
@@ -382,7 +382,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -393,7 +393,7 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script>
|
||||
const SPRITE = '/vendor/bootstrap-italia/dist/svg/sprites.svg';
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -154,9 +154,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// ── Auth check ───────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
+3
-3
@@ -1142,7 +1142,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (accordion) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI. -->
|
||||
@@ -1152,9 +1152,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// La guida è accessibile anche da non autenticati (utile per onboarding)
|
||||
// ma se sei loggato carichi sidebar + i18n normalmente. Stessa logica
|
||||
|
||||
@@ -351,7 +351,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -362,9 +362,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// ── Auth & Init ──────────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
@@ -139,12 +139,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
/*
|
||||
|
||||
+3
-3
@@ -184,7 +184,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -195,9 +195,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script src="/js/isms.js?v=20260620b"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -558,6 +558,14 @@ class NIS2API {
|
||||
getFeedback(id) { return this.get(`/feedback/${id}`); }
|
||||
updateFeedback(id, data) { return this.put(`/feedback/${id}`, data); }
|
||||
resolveFeedback(id, password) { return this.post(`/feedback/${id}/resolve`, { password }); }
|
||||
|
||||
// ── Connettori Discovery (mappatura rete/cloud → auto-popola Inventario) ──
|
||||
listDiscoveryConnectors() { return this.get('/discovery-connectors/list'); }
|
||||
createDiscoveryConnector(data) { return this.post('/discovery-connectors/create', data); }
|
||||
getDiscoveryConnector(id) { return this.get(`/discovery-connectors/${id}`); }
|
||||
updateDiscoveryConnector(id, d){ return this.put(`/discovery-connectors/${id}`, d); }
|
||||
deleteDiscoveryConnector(id) { return this.del(`/discovery-connectors/${id}`); }
|
||||
rotateDiscoveryKey(id) { return this.post(`/discovery-connectors/${id}/rotateKey`, {}); }
|
||||
}
|
||||
|
||||
// Singleton globale
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
items: [
|
||||
{ name: 'Formazione', href: 'training.html', icon: iconAcademicCap(), i18nKey: 'nav.training' },
|
||||
{ name: 'Inventario', href: 'assets.html', icon: iconServer(), i18nKey: 'nav.assets' },
|
||||
{ name: 'Connettori Discovery', href: 'connettori-discovery.html', icon: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z"/><path d="M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5V7h3a1 1 0 000-2H5z"/></svg>' },
|
||||
{ name: 'Audit interni', href: 'internal-audits.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm5.707 6.707a1 1 0 00-1.414-1.414L7 10.586l-.293-.293a1 1 0 00-1.414 1.414l1 1a1 1 0 001.414 0l2-2zM10 13a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd"/></svg>`, i18nKey: 'nav.internal_audits' },
|
||||
{ name: 'Controlli periodici', href: 'controlli-periodici.html', icon: `<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.5 2.5a1 1 0 001.414-1.414L11 9.586V6z" clip-rule="evenodd"/></svg>`, i18nKey: 'nav.periodic_controls' },
|
||||
{ name: 'Riesame di Direzione', href: 'management-review.html', icon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>`, i18nKey: 'nav.management_review' },
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* NIS2 Agile — Gestione Connettori Discovery (mappatura rete/cloud → auto-popola Inventario).
|
||||
* Usa api.js (CRUD) + helper di common.js (escHtml/showModal/closeModal/showNotification).
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function esc(s) {
|
||||
s = (s == null) ? '' : String(s);
|
||||
return (typeof escHtml === 'function') ? escHtml(s)
|
||||
: s.replace(/[&<>"]/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; });
|
||||
}
|
||||
function notify(m, t) { if (typeof showNotification === 'function') showNotification(m, t || 'info'); else alert(m); }
|
||||
function fmtDate(s) { if (!s) return '—'; try { return new Date(String(s).replace(' ', 'T')).toLocaleString('it-IT', { timeZone: 'Europe/Rome' }); } catch (e) { return s; } }
|
||||
|
||||
var INGEST_URL = location.origin + '/api/services/assets-ingest';
|
||||
|
||||
async function loadList() {
|
||||
var el = document.getElementById('dc-list');
|
||||
el.innerHTML = 'Caricamento…';
|
||||
var r = await api.get('/discovery-connectors/list');
|
||||
if (!r || !r.success) { el.innerHTML = '<div class="alert alert-danger">Errore nel caricamento.</div>'; return; }
|
||||
var rows = (r.data && r.data.connectors) || [];
|
||||
if (!rows.length) { el.innerHTML = '<p style="color:var(--gray-600)">Nessun connettore. Creane uno con «+ Nuovo connettore».</p>'; return; }
|
||||
var html = '<table class="table"><thead><tr><th>Nome</th><th>Tipo</th><th>Stato</th><th>Ultimo run</th><th>Asset</th><th>Chiave</th><th></th></tr></thead><tbody>';
|
||||
rows.forEach(function (c) {
|
||||
var badge = c.status === 'active' ? 'success' : (c.status === 'paused' ? 'secondary' : 'danger');
|
||||
var nm = esc(c.name).replace(/'/g, '');
|
||||
html += '<tr>'
|
||||
+ '<td><strong>' + esc(c.name) + '</strong></td>'
|
||||
+ '<td>' + esc(c.connector_type) + '</td>'
|
||||
+ '<td><span class="badge bg-' + badge + '">' + esc(c.status) + '</span></td>'
|
||||
+ '<td>' + fmtDate(c.last_run_at) + (c.last_status ? (' <small>(' + esc(c.last_status) + ')</small>') : '') + '</td>'
|
||||
+ '<td>' + (c.last_discovered != null ? esc(c.last_discovered) : '—') + '</td>'
|
||||
+ '<td><code>' + esc(c.key_prefix || '—') + '…</code></td>'
|
||||
+ '<td style="white-space:nowrap">'
|
||||
+ '<button class="btn btn-sm btn-outline-primary" onclick="DiscoveryUI.detail(' + c.id + ')">Dettaglio</button> '
|
||||
+ '<button class="btn btn-sm btn-outline-secondary" onclick="DiscoveryUI.rotate(' + c.id + ',\'' + nm + '\')">Rigenera chiave</button> '
|
||||
+ '<button class="btn btn-sm btn-outline-danger" onclick="DiscoveryUI.remove(' + c.id + ',\'' + nm + '\')">Elimina</button>'
|
||||
+ '</td></tr>';
|
||||
});
|
||||
html += '</tbody></table>';
|
||||
el.innerHTML = html;
|
||||
}
|
||||
|
||||
function keyModal(title, rawKey, name) {
|
||||
var cmd = 'NIS2_API_KEY=' + rawKey + ' TARGETS=192.168.1.0/24 node discovery-agent.mjs';
|
||||
var body = '<p>Copia ORA questa chiave: <strong>non sarà più visibile</strong>.</p>'
|
||||
+ '<div class="form-group"><label>API key</label><input class="form-control" readonly value="' + esc(rawKey) + '" onclick="this.select()"></div>'
|
||||
+ '<div class="form-group"><label>Comando agente (esempio)</label><textarea class="form-control" rows="3" readonly onclick="this.select()">' + esc(cmd) + '</textarea></div>'
|
||||
+ '<p style="color:var(--gray-600);font-size:.9em">Endpoint ingest: <code>' + esc(INGEST_URL) + '</code> · scope <code>ingest:assets</code>. Agente: <code>scripts/discovery-agent.mjs</code>.</p>';
|
||||
showModal(title, body, { size: 'lg', footer: '<button class="btn btn-primary" onclick="closeModal()">Ho copiato</button>' });
|
||||
}
|
||||
|
||||
async function create() {
|
||||
var name = (document.getElementById('dc-name').value || '').trim();
|
||||
if (!name) { notify('Inserisci un nome', 'warning'); return; }
|
||||
var data = {
|
||||
name: name,
|
||||
connector_type: document.getElementById('dc-type').value,
|
||||
schedule: document.getElementById('dc-schedule').value,
|
||||
config: { targets: (document.getElementById('dc-targets').value || '').split(',').map(function (s) { return s.trim(); }).filter(Boolean) }
|
||||
};
|
||||
var r = await api.post('/discovery-connectors/create', data);
|
||||
if (r && r.success) {
|
||||
document.getElementById('dc-form-card').style.display = 'none';
|
||||
document.getElementById('dc-name').value = '';
|
||||
document.getElementById('dc-targets').value = '';
|
||||
keyModal('Connettore creato — chiave API', r.data.api_key, name);
|
||||
loadList();
|
||||
} else { notify('Errore: ' + ((r && r.message) || 'sconosciuto'), 'danger'); }
|
||||
}
|
||||
|
||||
async function detail(id) {
|
||||
var r = await api.get('/discovery-connectors/' + id);
|
||||
if (!r || !r.success) { notify('Connettore non trovato', 'danger'); return; }
|
||||
var c = r.data;
|
||||
var runs = (c.runs || []).map(function (x) {
|
||||
return '<tr><td>' + fmtDate(x.started_at) + '</td><td>' + esc(x.status) + '</td><td>' + esc(x.discovered_assets) + '</td><td>' + esc(x.discovered_flows) + '</td><td>' + esc(x.message || '') + '</td></tr>';
|
||||
}).join('');
|
||||
var targets = ((c.config && c.config.targets) || []).join(', ') || '—';
|
||||
var body = '<p><strong>Tipo:</strong> ' + esc(c.connector_type) + ' · <strong>Stato:</strong> ' + esc(c.status) + ' · <strong>Schedulazione:</strong> ' + esc(c.schedule) + '</p>'
|
||||
+ '<p><strong>Target:</strong> ' + esc(targets) + '</p>'
|
||||
+ '<p><strong>Chiave:</strong> <code>' + esc(c.key_prefix || '—') + '…</code> · <strong>ultimo run:</strong> ' + fmtDate(c.last_run_at) + '</p>'
|
||||
+ '<h4>Ultimi run</h4>'
|
||||
+ (runs
|
||||
? ('<table class="table table-sm"><thead><tr><th>Quando</th><th>Esito</th><th>Asset</th><th>Flussi</th><th>Note</th></tr></thead><tbody>' + runs + '</tbody></table>')
|
||||
: '<p style="color:var(--gray-600)">Nessun run ancora. Esegui l\'agente di discovery con la chiave di questo connettore.</p>');
|
||||
showModal('Connettore: ' + esc(c.name), body, { size: 'lg', footer: '<button class="btn btn-outline-primary" onclick="closeModal()">Chiudi</button>' });
|
||||
}
|
||||
|
||||
async function rotate(id, name) {
|
||||
if (!confirm('Rigenerare la chiave di «' + name + '»? La vecchia smetterà di funzionare.')) return;
|
||||
var r = await api.post('/discovery-connectors/' + id + '/rotateKey', {});
|
||||
if (r && r.success) { keyModal('Nuova chiave API', r.data.api_key, name); loadList(); }
|
||||
else { notify('Errore nella rigenerazione', 'danger'); }
|
||||
}
|
||||
|
||||
async function remove(id, name) {
|
||||
if (!confirm('Eliminare il connettore «' + name + '»? La sua chiave verrà disattivata.')) return;
|
||||
var r = await api.del('/discovery-connectors/' + id);
|
||||
if (r && r.success) { notify('Connettore eliminato', 'success'); loadList(); }
|
||||
else { notify('Errore nell\'eliminazione', 'danger'); }
|
||||
}
|
||||
|
||||
function init() {
|
||||
var b = document.getElementById('btn-dc-new');
|
||||
if (b) b.onclick = function () { var f = document.getElementById('dc-form-card'); f.style.display = (f.style.display === 'none') ? 'block' : 'none'; };
|
||||
var bc = document.getElementById('btn-dc-create'); if (bc) bc.onclick = create;
|
||||
var bx = document.getElementById('btn-dc-cancel'); if (bx) bx.onclick = function () { document.getElementById('dc-form-card').style.display = 'none'; };
|
||||
loadList();
|
||||
}
|
||||
|
||||
window.DiscoveryUI = { init: init, detail: detail, rotate: rotate, remove: remove };
|
||||
})();
|
||||
@@ -980,6 +980,44 @@ const HelpSystem = (function () {
|
||||
]
|
||||
},
|
||||
|
||||
// ─── Connettori Discovery ────────────────────────────────────
|
||||
'connettori-discovery': {
|
||||
title: 'Guida - Connettori Discovery',
|
||||
intro: 'I connettori di discovery mappano automaticamente la rete o il cloud dell\'organizzazione e popolano l\'Inventario con gli asset rilevati, la rilevanza NIS2, le dipendenze e i flussi di rete (ID.AM-03), riducendo l\'inserimento manuale.',
|
||||
sections: [
|
||||
{
|
||||
heading: 'Più connettori per azienda',
|
||||
items: [
|
||||
'Puoi creare <strong>più connettori</strong> per la stessa organizzazione, uno per ciascuna sorgente (es. "Rete sede Roma", "Rete sede Modena", "AWS prod").',
|
||||
'Ogni connettore ha un <strong>tipo</strong> (rete, AWS, Azure, GCP, CMDB, agente, custom) e una propria <strong>chiave API</strong>.',
|
||||
'Stato (attivo/in pausa/errore) e storico delle esecuzioni sono nel dettaglio del connettore.'
|
||||
]
|
||||
},
|
||||
{
|
||||
heading: 'Come funziona',
|
||||
items: [
|
||||
'Crea un connettore con "+ Nuovo connettore": ottieni una <strong>chiave API</strong> mostrata una sola volta (copiala subito).',
|
||||
'Esegui l\'<strong>agente di discovery</strong> (<code>scripts/discovery-agent.mjs</code>) dentro la rete da mappare con quella chiave: scansiona gli host e invia gli asset a NIS2.',
|
||||
'NIS2 fa <strong>dedup</strong> per indirizzo, calcola il <strong>punteggio di rilevanza NIS2</strong> e aggiorna Inventario + Mappa Dipendenze + flussi di rete.',
|
||||
'Ogni esecuzione aggiorna "ultimo run" e il numero di asset scoperti.'
|
||||
]
|
||||
},
|
||||
{
|
||||
heading: 'Sicurezza',
|
||||
items: [
|
||||
'La chiave del connettore ha <strong>solo</strong> lo scope <code>ingest:assets</code>: può aggiungere asset/flussi solo alla tua organizzazione, non leggere altri dati.',
|
||||
'Se una chiave è compromessa usa <strong>Rigenera chiave</strong>: la vecchia smette di funzionare.',
|
||||
'La gestione dei connettori è riservata agli <strong>amministratori dell\'organizzazione</strong>.'
|
||||
]
|
||||
}
|
||||
],
|
||||
references: [
|
||||
'Art. 24 D.Lgs. 138/2024 - Gestione degli attivi e dei sistemi informativi e di rete',
|
||||
'NIST CSF ID.AM-01/02 - Inventario hardware/software; ID.AM-03 - Flussi di rete',
|
||||
'Identificazione e classificazione dei sistemi rilevanti - scoring 0-100 (GV.OC-04)'
|
||||
]
|
||||
},
|
||||
|
||||
// ─── Reports / Audit ─────────────────────────────────────────
|
||||
'reports': {
|
||||
title: 'Guida - Audit & Report',
|
||||
@@ -1509,6 +1547,8 @@ const HelpSystem = (function () {
|
||||
'training': 'training',
|
||||
'assets.html': 'assets',
|
||||
'assets': 'assets',
|
||||
'connettori-discovery.html': 'connettori-discovery',
|
||||
'connettori-discovery': 'connettori-discovery',
|
||||
'reports.html': 'reports',
|
||||
'audit.html': 'reports',
|
||||
'reports': 'reports',
|
||||
|
||||
+3
-3
@@ -152,7 +152,7 @@
|
||||
|
||||
<!-- Stessa logica JS della pagina live (parita' funzionale assoluta, zero backend). -->
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
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>
|
||||
@@ -161,9 +161,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script src="/js/kb.js"></script>
|
||||
<script>
|
||||
// Gate auth + chrome come le altre pagine -bi.
|
||||
|
||||
@@ -126,12 +126,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
/*
|
||||
|
||||
@@ -167,12 +167,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
/*
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -123,9 +123,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
loadSidebar();
|
||||
|
||||
@@ -138,12 +138,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script src="/js/organigramma.js?v=20260617"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -333,7 +333,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -344,9 +344,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// ── Auth & Init ─────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
+3
-3
@@ -131,12 +131,12 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script src="/js/raci.js?v=20260619"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+3
-3
@@ -443,7 +443,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -454,9 +454,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// ── Auth & Init ─────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
@@ -141,12 +141,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
/*
|
||||
|
||||
+3
-3
@@ -494,7 +494,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -505,9 +505,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// ── Auth & Init ──────────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
@@ -688,7 +688,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -699,9 +699,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// ── Auth check ───────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
@@ -194,12 +194,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
/*
|
||||
|
||||
@@ -191,12 +191,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
/*
|
||||
|
||||
@@ -477,7 +477,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -488,9 +488,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260621sp"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// ── Auth & Init ─────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
@@ -292,7 +292,7 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -303,9 +303,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
// ── Auth & Init ─────────────────────────────────────────
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
|
||||
<!-- Report Detail Modal handled by common.js showModal -->
|
||||
|
||||
<script src="/js/api.js?v=20260631"></script>
|
||||
<script src="/js/api.js?v=20260625d"></script>
|
||||
<script src="/js/common.js?v=20260624g"></script>
|
||||
<!-- Bootstrap Italia bundle (componenti) + override sidebar BI (common-bi.js).
|
||||
common-bi.js va DOPO common.js: ridefinisce solo loadSidebar() con markup BI,
|
||||
@@ -218,9 +218,9 @@
|
||||
bootstrap.loadFonts('/vendor/bootstrap-italia/dist/fonts');
|
||||
}
|
||||
</script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="/js/i18n.js?v=20260631"></script>
|
||||
<script src="/js/help.js?v=20260625c"></script>
|
||||
<script src="/js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
loadSidebar();
|
||||
|
||||
@@ -324,9 +324,9 @@
|
||||
<script src="js/api.js?v=20260631"></script>
|
||||
<script src="js/common.js?v=20260624g"></script>
|
||||
<script src="/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js"></script>
|
||||
<script src="/js/common-bi.js?v=20260624f"></script>
|
||||
<script src="/js/common-bi.js?v=20260625d"></script>
|
||||
<script src="js/i18n.js?v=20260631"></script>
|
||||
<script src="js/help.js?v=20260625c"></script>
|
||||
<script src="js/help.js?v=20260625d"></script>
|
||||
<script>
|
||||
if (!checkAuth()) throw new Error('Not authenticated');
|
||||
loadSidebar();
|
||||
|
||||
Reference in New Issue
Block a user