/** * Dashboard entry point. Guards against loading outside the dashboard context, * initialises navigation and all page event handlers, then starts the 2-second * refresh cycle. * Depends on: all other dashboard modules (loaded before this file) */ /** * Guard: only run when loaded as the actual dashboard page. */ if (!document.getElementById('page-dashboard') && !document.querySelector('.sidebar-logo')) { throw new Error('dashboard scripts loaded outside dashboard context — aborting'); } /** * Initialise the dashboard: set the version string, wire up navigation and all * page event handlers, run the first state refresh, and start the 2-second polling interval. * @returns {Promise} */ async function init() { log('Dashboard initializing…'); try { const manifest = chrome.runtime.getManifest(); const versionEl = $('sidebarVersion'); if (versionEl && manifest.version) { versionEl.textContent = 'v' + manifest.version + ' · hole.sail'; } } catch (_) {} setupNavigation(); setupEvents(); setupCertValidator(); setupSshEvents(); setupRdpEvents(); setupBackupEvents(); setupSyncEvents(); await refresh(); // When native host emits syncApplied, refresh state immediately chrome.runtime.onMessage.addListener((msg) => { if (msg.type === 'holesail-event' && msg.payload && msg.payload.event === 'syncApplied') { refresh(); } }); // Main state-refresh interval: configurable (2s / 5s / 10s), or paused when tab is hidden or setting is 0. let _refreshIntervalId = null; function _getRefreshMs() { const ms = (settings.dashboardRefreshIntervalMs !== undefined ? settings.dashboardRefreshIntervalMs : 2000); return (typeof ms === 'number' && ms >= 0 ? ms : 2000); } function _startRefreshInterval() { if (_refreshIntervalId) clearInterval(_refreshIntervalId); _refreshIntervalId = null; if (document.visibilityState === 'hidden') return; const ms = _getRefreshMs(); if (ms <= 0) return; _refreshIntervalId = setInterval(refresh, ms); } function _restartRefreshInterval() { _startRefreshInterval(); } document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') { refresh(); _startRefreshInterval(); } else { if (_refreshIntervalId) { clearInterval(_refreshIntervalId); _refreshIntervalId = null; } } }); _startRefreshInterval(); window._restartRefreshInterval = _restartRefreshInterval; // Latency-ping interval — driven by settings.latencyPingIntervalMs. let _pingInterval = null; function _restartPingInterval() { if (_pingInterval) clearInterval(_pingInterval); _pingInterval = null; if (settings.latencyPingEnabled === false) return; const ms = (settings.latencyPingIntervalMs > 0 ? settings.latencyPingIntervalMs : 5000); _pingInterval = setInterval(_pingLatencyBadges, ms); } _restartPingInterval(); window._restartPingInterval = _restartPingInterval; window.addEventListener('beforeunload', () => { if (_refreshIntervalId) clearInterval(_refreshIntervalId); if (_pingInterval) clearInterval(_pingInterval); }, { once: true }); } init();