diff --git a/src/public/js/main.js b/src/public/js/main.js index 3187e548b..13d012ff6 100644 --- a/src/public/js/main.js +++ b/src/public/js/main.js @@ -1,12 +1,39 @@ document.addEventListener('DOMContentLoaded', function() { const PulseApp = window.PulseApp || {}; + function updateAllUITables() { + if (!PulseApp.state || !PulseApp.state.get('initialDataReceived')) { + return; + } + + const nodesData = PulseApp.state.get('nodesData'); + const pbsDataArray = PulseApp.state.get('pbsDataArray'); + + PulseApp.ui.nodes?.updateNodesTable(nodesData); + PulseApp.ui.dashboard?.updateDashboardTable(); + PulseApp.ui.storage?.updateStorageInfo(); + PulseApp.ui.pbs?.updatePbsInfo(pbsDataArray); + PulseApp.ui.backups?.updateBackupsTab(); + + const loadingOverlay = document.getElementById('loading-overlay'); + if (loadingOverlay && loadingOverlay.style.display !== 'none') { + if (PulseApp.socketHandler?.isConnected()) { + console.log('[UI Update] First data received, hiding loading overlay.'); + loadingOverlay.style.display = 'none'; + } else { + console.log('[UI Update] Data received, but socket disconnected. Keeping loading overlay.'); + } + } + + PulseApp.thresholds?.logging?.checkThresholdViolations(); + } + function initializeModules() { - PulseApp.state?.init?.(); // Although state is IIFE, init might be added later - PulseApp.config?.init?.(); // Although config is obj literal, init might be added later - PulseApp.utils?.init?.(); // Although utils is obj literal, init might be added later + PulseApp.state?.init?.(); + PulseApp.config?.init?.(); + PulseApp.utils?.init?.(); PulseApp.theme?.init?.(); - PulseApp.socketHandler?.init?.(); + PulseApp.socketHandler?.init?.(updateAllUITables); PulseApp.tooltips?.init?.(); PulseApp.ui = PulseApp.ui || {}; @@ -14,7 +41,7 @@ document.addEventListener('DOMContentLoaded', function() { PulseApp.ui.nodes?.init?.(); PulseApp.ui.dashboard?.init?.(); PulseApp.ui.storage?.init?.(); - PulseApp.ui.pbs?.initPbsEventListeners?.(); // Specific init for PBS listeners + PulseApp.ui.pbs?.initPbsEventListeners?.(); PulseApp.ui.backups?.init?.(); PulseApp.ui.thresholds?.init?.(); PulseApp.ui.common?.init?.(); @@ -26,24 +53,19 @@ document.addEventListener('DOMContentLoaded', function() { function validateCriticalElements() { const criticalElements = [ 'connection-status', - 'main-table', // Check for table itself - // 'custom-tooltip', // Non-critical - // 'slider-value-tooltip', // Non-critical - 'dashboard-search', // Optional but important - 'dashboard-status-text', // Status display - 'app-version' // Version display + 'main-table', + 'dashboard-search', + 'dashboard-status-text', + 'app-version' ]; let allFound = true; criticalElements.forEach(id => { if (!document.getElementById(id)) { console.error(`Critical element #${id} not found!`); - // allFound = false; // Decide if you want to stop execution } }); - // Check for table body specifically needed by dashboard updates if (!document.querySelector('#main-table tbody')) { console.error('Critical element #main-table tbody not found!'); - // allFound = false; } return allFound; } @@ -65,44 +87,11 @@ document.addEventListener('DOMContentLoaded', function() { }); } - function updateAllUITables() { - const nodesData = PulseApp.state.get('nodesData'); - const pbsDataArray = PulseApp.state.get('pbsDataArray'); - const storageData = PulseApp.state.get('storageData'); - - PulseApp.ui.nodes?.updateNodesTable(nodesData); - PulseApp.ui.dashboard?.updateDashboardTable(); // Refreshes data internally - PulseApp.ui.storage?.updateStorageInfo(); // Uses state internaly - PulseApp.ui.pbs?.updatePbsInfo(pbsDataArray); - PulseApp.ui.backups?.updateBackupsTab(); - - const loadingOverlay = document.getElementById('loading-overlay'); - if (loadingOverlay && loadingOverlay.style.display !== 'none') { - if (PulseApp.socketHandler.isConnected()) { - console.log('[UI Update] Hiding loading overlay.'); - loadingOverlay.style.display = 'none'; - } else { - } - } - } - - // --- Main Execution --- if (!validateCriticalElements()) { console.error("Stopping JS execution due to missing critical elements."); - // Optionally display a user-facing error message here return; } initializeModules(); fetchVersion(); - PulseApp.ui.storage.fetchStorageData(); // Initial fetch - - setInterval(() => { - if (PulseApp.state.get('initialDataReceived')) { - updateAllUITables(); - PulseApp.thresholds.logging?.checkThresholdViolations(); - } - }, 2000); // UI update interval - - setInterval(PulseApp.ui.storage.fetchStorageData, 30000); // Storage fetch interval }); \ No newline at end of file diff --git a/src/public/js/socketHandler.js b/src/public/js/socketHandler.js index 4d86ea01c..5a8c0facc 100644 --- a/src/public/js/socketHandler.js +++ b/src/public/js/socketHandler.js @@ -1,11 +1,18 @@ PulseApp.socketHandler = (() => { let socket = null; - function init() { + // Expose the UI update function reference + let updateAllUITablesRef = () => { + console.warn('[socketHandler] updateAllUITablesRef is not yet assigned.'); + }; + + function init(updateFunctionRef) { socket = io(); + updateAllUITablesRef = updateFunctionRef; // Assign the function passed from main.js socket.on('connect', handleConnect); socket.on('disconnect', handleDisconnect); + socket.on('initialState', handleInitialState); socket.on('rawData', handleRawData); socket.on('pbsInitialStatus', handlePbsInitialStatus); @@ -43,6 +50,26 @@ PulseApp.socketHandler = (() => { } } + function handleInitialState(state) { + console.log('[socketHandler] Received initial state:', state); + if (state && state.loading) { + // Update status text to indicate loading + const statusText = document.getElementById('dashboard-status-text'); + if (statusText) { + statusText.textContent = 'Loading initial data...'; + } + // Ensure loading overlay is visible + const loadingOverlay = document.getElementById('loading-overlay'); + if (loadingOverlay && loadingOverlay.style.display === 'none') { + const loadingText = loadingOverlay.querySelector('p'); + if (loadingText) { + loadingText.textContent = 'Loading data...'; // Or a specific initial loading message + } + loadingOverlay.style.display = 'flex'; + } + } + } + function handleRawData(jsonData) { try { const data = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData; @@ -72,7 +99,14 @@ PulseApp.socketHandler = (() => { PulseApp.state.set('initialDataReceived', true); } - + + // --- Trigger UI update after processing data --- + if (typeof updateAllUITablesRef === 'function') { + updateAllUITablesRef(); + } else { + console.error('[socketHandler] updateAllUITablesRef is not a function!'); + } + // --- END Trigger --- } catch (e) { console.error('Error processing received rawData:', e, jsonData); diff --git a/src/public/js/state.js b/src/public/js/state.js index 97924312c..f5125a392 100644 --- a/src/public/js/state.js +++ b/src/public/js/state.js @@ -10,7 +10,6 @@ PulseApp.state = (() => { metricsData: [], dashboardData: [], pbsDataArray: [], - storageData: {}, dashboardHistory: {}, initialDataReceived: false, isThresholdRowVisible: false, diff --git a/src/public/js/ui/storage.js b/src/public/js/ui/storage.js index 99d1fc200..c02b23f98 100644 --- a/src/public/js/ui/storage.js +++ b/src/public/js/ui/storage.js @@ -2,39 +2,6 @@ PulseApp.ui = PulseApp.ui || {}; PulseApp.ui.storage = (() => { - async function fetchStorageData() { - try { - const response = await fetch('/api/storage'); - if (!response.ok) { - let serverErrorMsg = `Server responded with status: ${response.status} ${response.statusText}`; - try { - const errorJson = await response.json(); - if (errorJson && errorJson.globalError) { - serverErrorMsg = errorJson.globalError; - } else if (errorJson) { - serverErrorMsg += ` | Body: ${JSON.stringify(errorJson)}`; - } - } catch (parseError) { - } - throw new Error(serverErrorMsg); - } - - const fetchedData = await response.json(); - PulseApp.state.set('storageData', fetchedData); - - } catch (error) { - let finalErrorMessage = 'Failed to load storage data due to an unknown error.'; - if (error instanceof TypeError) { - finalErrorMessage = `Failed to load storage data due to a network error: ${error.message}`; - console.error('Network error during storage fetch:', error); - } else { - finalErrorMessage = error.message; - console.error('Error processing storage response:', error); - } - console.error(`Storage fetch failed, preserving previous data. Error: ${finalErrorMessage}`); - } - } - function getStorageTypeIcon(type) { switch(type) { case 'dir': @@ -108,25 +75,24 @@ PulseApp.ui.storage = (() => { contentDiv.innerHTML = ''; contentDiv.className = ''; - const storage = PulseApp.state.get('storageData'); + const nodes = PulseApp.state.get('nodesData') || []; - if (storage && storage.globalError) { - contentDiv.innerHTML = `

Error: ${storage.globalError}

`; + if (!Array.isArray(nodes) || nodes.length === 0) { + contentDiv.innerHTML = '

No node or storage data available.

'; return; } - const nodeKeys = storage ? Object.keys(storage) : []; - const hasValidNodeData = nodeKeys.length > 0 && nodeKeys.some(key => Array.isArray(storage[key])); - const allNodesAreErrors = nodeKeys.length > 0 && nodeKeys.every(key => storage[key] && storage[key].error); + const storageByNode = nodes.reduce((acc, node) => { + if (node && node.node) { + acc[node.node] = Array.isArray(node.storage) ? node.storage : []; + } + return acc; + }, {}); + + const nodeKeys = Object.keys(storageByNode); if (nodeKeys.length === 0) { - contentDiv.innerHTML = '

No storage data received from server.

'; - return; - } else if (allNodesAreErrors) { - contentDiv.innerHTML = '

Failed to load storage data for all nodes. Check server logs.

'; - return; - } else if (!hasValidNodeData) { - contentDiv.innerHTML = '

Received unexpected storage data format from server.

'; + contentDiv.innerHTML = '

No storage data found associated with nodes.

'; return; } @@ -150,10 +116,10 @@ PulseApp.ui.storage = (() => { const tbody = document.createElement('tbody'); tbody.className = 'divide-y divide-gray-200 dark:divide-gray-600'; - const sortedNodeNames = Object.keys(storage).sort((a, b) => a.localeCompare(b)); + const sortedNodeNames = Object.keys(storageByNode).sort((a, b) => a.localeCompare(b)); sortedNodeNames.forEach(nodeName => { - const nodeStorageData = storage[nodeName]; + const nodeStorageData = storageByNode[nodeName]; const nodeHeaderRow = document.createElement('tr'); nodeHeaderRow.className = 'bg-gray-100 dark:bg-gray-700/80 font-semibold text-gray-700 dark:text-gray-300 text-xs node-storage-header'; @@ -164,14 +130,7 @@ PulseApp.ui.storage = (() => { `; tbody.appendChild(nodeHeaderRow); - if (nodeStorageData.error) { - const errorRow = document.createElement('tr'); - errorRow.innerHTML = `Error loading storage: ${nodeStorageData.error}`; - tbody.appendChild(errorRow); - return; - } - - if (!Array.isArray(nodeStorageData) || nodeStorageData.length === 0) { + if (nodeStorageData.length === 0) { const noDataRow = document.createElement('tr'); noDataRow.innerHTML = `No storage configured or found for this node.`; tbody.appendChild(noDataRow); @@ -221,7 +180,6 @@ PulseApp.ui.storage = (() => { } return { - fetchStorageData, updateStorageInfo }; })(); \ No newline at end of file