/** * NIS2 Agile - Knowledge Base UI (Migration 012-014) * * Gestisce upload documento, listing, search semantica con visibilita' multi-livello. */ (function () { 'use strict'; function getJwt() { try { return localStorage.getItem('nis2_access_token') || sessionStorage.getItem('nis2_access_token') || ''; } catch (e) { return ''; } } function authHeaders() { return { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + getJwt(), }; } function escHtml(s) { var d = document.createElement('div'); d.textContent = s == null ? '' : String(s); return d.innerHTML; } function fmtScopeBadge(scope) { return '' + escHtml(scope) + ''; } var btnUpload = document.getElementById('btn-kb-upload'); var btnSubmit = document.getElementById('btn-kb-submit'); var btnCancel = document.getElementById('btn-kb-cancel'); var btnSearch = document.getElementById('btn-kb-search'); var formCard = document.getElementById('kb-form-card'); var statusEl = document.getElementById('kb-status'); var listEl = document.getElementById('kb-doc-list'); var resultsEl = document.getElementById('kb-search-results'); var shareSel = document.getElementById('kb-shared-with'); if (!btnUpload || !formCard) return; function setupScopeForUser() { // Decodifica JWT per estrarre role e consulting_firm_id var jwt = getJwt(); if (!jwt) return; try { var payload = JSON.parse(atob(jwt.split('.')[1])); // Il JWT NIS2 contiene solo user_id; chiamo /api/auth/me per role + firm fetch('/api/auth/me', { headers: authHeaders() }) .then(function (r) { return r.json(); }) .then(function (res) { var u = (res && res.data && (res.data.user || res.data)) || {}; var role = u.role || ''; var firmId = u.consulting_firm_id || null; var optSystem = document.querySelector('[data-scope-opt="SYSTEM"]'); var optFirm = document.querySelector('[data-scope-opt="FIRM"]'); var optOrg = document.querySelector('[data-scope-opt="ORG"]'); if (role === 'super_admin' && optSystem) optSystem.style.display = 'inline-flex'; if (firmId && optFirm) optFirm.style.display = 'inline-flex'; if (optOrg) optOrg.style.display = 'inline-flex'; if (firmId) loadFirmOrgs(); }); } catch (e) { /* ignore */ } } function loadFirmOrgs() { if (!shareSel) return; fetch('/api/knowledgebase/firmOrgs', { headers: authHeaders() }) .then(function (r) { return r.json(); }) .then(function (res) { var orgs = (res && res.data && res.data.organizations) || []; if (!orgs.length) { shareSel.innerHTML = ''; return; } shareSel.innerHTML = orgs.map(function (o) { var label = o.name + (o.vat_number ? ' (P.IVA ' + o.vat_number + ')' : ''); return ''; }).join(''); }).catch(function () { shareSel.innerHTML = ''; }); } function loadDocList() { if (!listEl) return; listEl.innerHTML = '
Caricamento...
'; fetch('/api/knowledgebase/list', { headers: authHeaders() }) .then(function (r) { return r.json(); }) .then(function (res) { var docs = (res && res.data && res.data.documents) || []; if (!docs.length) { listEl.innerHTML = '
Nessun documento visibile
'; return; } listEl.innerHTML = docs.map(function (d) { return '
' + '
' + '' + escHtml(d.title) + ' ' + fmtScopeBadge(d.scope) + '
' + escHtml(d.entity_type || '') + ' · ' + (d.chunk_count || 0) + ' chunk · ' + escHtml(d.created_at) + '
' + '
' + '' + '
'; }).join(''); // Wire delete buttons listEl.querySelectorAll('[data-del-id]').forEach(function (btn) { btn.addEventListener('click', function () { if (!confirm('Eliminare definitivamente questo documento dalla KB?')) return; var id = this.getAttribute('data-del-id'); fetch('/api/knowledgebase/' + id, { method: 'DELETE', headers: authHeaders(), }).then(function (r) { return r.json(); }).then(function (res) { if (res && res.success) loadDocList(); else alert('Errore: ' + ((res && res.message) || 'sconosciuto')); }); }); }); }).catch(function () { listEl.innerHTML = '
Errore caricamento
'; }); } btnUpload.addEventListener('click', function () { var visible = formCard.style.display !== 'none'; formCard.style.display = visible ? 'none' : 'block'; if (!visible) setupScopeForUser(); }); btnCancel.addEventListener('click', function () { formCard.style.display = 'none'; }); document.querySelectorAll('input[name="kb-scope"]').forEach(function (r) { r.addEventListener('change', function () { var block = document.getElementById('kb-share-block'); if (block) block.style.display = (this.value === 'FIRM') ? 'block' : 'none'; }); }); btnSubmit.addEventListener('click', function () { var title = (document.getElementById('kb-title') || {}).value || ''; var text = (document.getElementById('kb-text') || {}).value || ''; var entityType = (document.getElementById('kb-entity-type') || {}).value || 'custom'; var scopeEl = document.querySelector('input[name="kb-scope"]:checked'); var scope = scopeEl ? scopeEl.value : 'ORG'; if (!title.trim()) { statusEl.textContent = 'Inserisci un titolo'; statusEl.style.color = '#ef4444'; return; } if (text.length < 50) { statusEl.textContent = 'Testo troppo breve (min 50 caratteri)'; statusEl.style.color = '#ef4444'; return; } var sharedWith = []; if (scope === 'FIRM' && shareSel) { for (var i = 0; i < shareSel.options.length; i++) { if (shareSel.options[i].selected && shareSel.options[i].value) { sharedWith.push(parseInt(shareSel.options[i].value, 10)); } } } btnSubmit.disabled = true; statusEl.style.color = '#0ea5e9'; statusEl.textContent = 'Indicizzazione in corso...'; fetch('/api/knowledgebase/ingest', { method: 'POST', headers: authHeaders(), body: JSON.stringify({ title: title.trim(), text: text, entity_type: entityType, scope: scope, shared_with_orgs: sharedWith, }), }).then(function (r) { return r.json().then(function (j) { return { ok: r.ok, body: j }; }); }) .then(function (res) { btnSubmit.disabled = false; if (res.ok && res.body && res.body.success !== false) { var d = res.body.data || res.body; statusEl.style.color = '#22C55E'; statusEl.textContent = 'Documento indicizzato (' + (d.scope || scope) + ', ' + (d.chunks || '?') + ' chunk)' + (sharedWith.length ? ' — condiviso con ' + sharedWith.length + ' org.' : ''); document.getElementById('kb-title').value = ''; document.getElementById('kb-text').value = ''; loadDocList(); } else { statusEl.style.color = '#ef4444'; statusEl.textContent = 'Errore: ' + ((res.body && res.body.message) || 'sconosciuto'); } }).catch(function (e) { btnSubmit.disabled = false; statusEl.style.color = '#ef4444'; statusEl.textContent = 'Errore di rete: ' + (e.message || ''); }); }); btnSearch.addEventListener('click', function () { var q = (document.getElementById('kb-search-query') || {}).value || ''; if (!q.trim()) return; resultsEl.innerHTML = '
Ricerca in corso...
'; fetch('/api/knowledgebase/search', { method: 'POST', headers: authHeaders(), body: JSON.stringify({ query: q.trim(), top_k: 5 }), }).then(function (r) { return r.json(); }) .then(function (res) { var hits = (res && res.data && res.data.results) || []; if (!hits.length) { resultsEl.innerHTML = '
Nessun risultato
'; return; } resultsEl.innerHTML = hits.map(function (h, i) { return '
' + '
[' + (i + 1) + '] ' + escHtml(h.title) + ' ' + fmtScopeBadge(h.scope) + ' score=' + h.score + '
' + '
' + escHtml(h.content.substring(0, 300)) + (h.content.length > 300 ? '...' : '') + '
'; }).join(''); }); }); // Carica lista al boot loadDocList(); })();