diff --git a/public/incidents.html b/public/incidents.html index 0f64fa2..4af96a0 100644 --- a/public/incidents.html +++ b/public/incidents.html @@ -607,6 +607,8 @@ if (!data.description) { showNotification('La descrizione e\' obbligatoria', 'warning'); return; } if (!data.detected_at) { showNotification('La data di rilevamento e\' obbligatoria', 'warning'); return; } + const btn = document.querySelector('#modal-overlay .btn-primary'); + setButtonLoading(btn, true); try { const result = await api.createIncident(data); if (result.success) { @@ -617,9 +619,11 @@ showNotification(msg, 'success'); loadIncidents(); } else { + setButtonLoading(btn, false); showNotification(result.message || 'Errore nella creazione', 'error'); } } catch (e) { + setButtonLoading(btn, false); showNotification('Errore di connessione', 'error'); } } diff --git a/public/js/api.js b/public/js/api.js index 5b40712..ad41e2d 100644 --- a/public/js/api.js +++ b/public/js/api.js @@ -55,7 +55,8 @@ class NIS2API { return json; } catch (error) { console.error(`[API] Network error: ${method} ${endpoint}`, error); - return { success: false, message: 'Errore di connessione al server' }; + const msg = typeof I18n !== 'undefined' ? I18n.t('msg.error_connection') : 'Errore di connessione al server'; + return { success: false, message: msg }; } } @@ -274,7 +275,8 @@ class NIS2API { }); return response.json(); } catch (error) { - return { success: false, message: 'Errore di connessione al server' }; + const msg = typeof I18n !== 'undefined' ? I18n.t('msg.error_connection') : 'Errore di connessione al server'; + return { success: false, message: msg }; } } diff --git a/public/js/common.js b/public/js/common.js index 2b66f72..bc51b7a 100644 --- a/public/js/common.js +++ b/public/js/common.js @@ -440,6 +440,7 @@ function _toggleSidebar(forceState) { /** * Verifica che l'utente sia autenticato. Se non lo e', redirige al login. + * Attiva automaticamente il timeout di sessione per inattivita'. * @returns {boolean} */ function checkAuth() { @@ -447,10 +448,110 @@ function checkAuth() { window.location.href = 'login.html'; return false; } + if (!_idleInitialized) { + _idleInitialized = true; + initIdleTimeout(); + } return true; } +// ═══════════════════════════════════════════════════════════════════ +// Idle Session Timeout +// ═══════════════════════════════════════════════════════════════════ + +let _idleTimer = null; +let _idleWarningTimer = null; +let _idleCountdownInterval = null; +let _idleInitialized = false; + +const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minuti totali +const IDLE_WARNING_MS = 5 * 60 * 1000; // avviso 5 minuti prima della scadenza + +/** + * Avvia il monitoraggio di inattivita' della sessione. + * Mostra un avviso 5 minuti prima del logout automatico. + */ +function initIdleTimeout() { + _resetIdleTimer(); + ['mousemove', 'keydown', 'click', 'scroll', 'touchstart'].forEach(evt => { + document.addEventListener(evt, _resetIdleTimer, { passive: true }); + }); +} + +function _resetIdleTimer() { + clearTimeout(_idleTimer); + clearTimeout(_idleWarningTimer); + clearInterval(_idleCountdownInterval); + + // Chiudi avviso se gia' aperto + const existingWarning = document.getElementById('idle-warning-overlay'); + if (existingWarning) existingWarning.remove(); + + // Timer per mostrare avviso + _idleWarningTimer = setTimeout(_showIdleWarning, IDLE_TIMEOUT_MS - IDLE_WARNING_MS); + + // Timer per logout automatico + _idleTimer = setTimeout(() => { + if (typeof api !== 'undefined') api.logout(); + }, IDLE_TIMEOUT_MS); +} + +function _showIdleWarning() { + const existing = document.getElementById('idle-warning-overlay'); + if (existing) existing.remove(); + + let remaining = Math.floor(IDLE_WARNING_MS / 1000); + + const overlay = document.createElement('div'); + overlay.id = 'idle-warning-overlay'; + overlay.style.cssText = [ + 'position:fixed', 'top:0', 'left:0', 'right:0', 'bottom:0', 'z-index:9999', + 'background:rgba(0,0,0,0.55)', 'display:flex', 'align-items:center', 'justify-content:center' + ].join(';'); + + overlay.innerHTML = ` +
+ Per motivi di sicurezza, verrai disconnesso tra
+ 5:00
+ a causa di inattivita'.
+
Questo documento e' stato generato automaticamente da un sistema AI. Prima di approvarlo, verificare che sia conforme alle procedure interne, al quadro normativo applicabile e alla realta' specifica dell'organizzazione. L'AI puo' produrre contenuti imprecisi o incompleti.