mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-23 03:33:53 +00:00
refactor: Make frontend UI updates event-driven and consolidate storage data source
This commit is contained in:
+36
-47
@@ -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
|
||||
});
|
||||
@@ -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);
|
||||
|
||||
@@ -10,7 +10,6 @@ PulseApp.state = (() => {
|
||||
metricsData: [],
|
||||
dashboardData: [],
|
||||
pbsDataArray: [],
|
||||
storageData: {},
|
||||
dashboardHistory: {},
|
||||
initialDataReceived: false,
|
||||
isThresholdRowVisible: false,
|
||||
|
||||
+15
-57
@@ -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 = `<p class="p-4 text-red-700 dark:text-red-300">Error: ${storage.globalError}</p>`;
|
||||
if (!Array.isArray(nodes) || nodes.length === 0) {
|
||||
contentDiv.innerHTML = '<p class="text-gray-500 dark:text-gray-400 p-4 text-center">No node or storage data available.</p>';
|
||||
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 = '<p class="text-gray-500 dark:text-gray-400 p-4 text-center">No storage data received from server.</p>';
|
||||
return;
|
||||
} else if (allNodesAreErrors) {
|
||||
contentDiv.innerHTML = '<p class="text-red-600 dark:text-red-400 p-4 text-center">Failed to load storage data for all nodes. Check server logs.</p>';
|
||||
return;
|
||||
} else if (!hasValidNodeData) {
|
||||
contentDiv.innerHTML = '<p class="text-yellow-600 dark:text-yellow-400 p-4 text-center">Received unexpected storage data format from server.</p>';
|
||||
contentDiv.innerHTML = '<p class="text-gray-500 dark:text-gray-400 p-4 text-center">No storage data found associated with nodes.</p>';
|
||||
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 = (() => {
|
||||
</td>`;
|
||||
tbody.appendChild(nodeHeaderRow);
|
||||
|
||||
if (nodeStorageData.error) {
|
||||
const errorRow = document.createElement('tr');
|
||||
errorRow.innerHTML = `<td colspan="7" class="p-2 px-3 text-sm text-red-600 dark:text-red-400 italic">Error loading storage: ${nodeStorageData.error}</td>`;
|
||||
tbody.appendChild(errorRow);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Array.isArray(nodeStorageData) || nodeStorageData.length === 0) {
|
||||
if (nodeStorageData.length === 0) {
|
||||
const noDataRow = document.createElement('tr');
|
||||
noDataRow.innerHTML = `<td colspan="7" class="p-2 px-3 text-sm text-gray-500 dark:text-gray-400 italic">No storage configured or found for this node.</td>`;
|
||||
tbody.appendChild(noDataRow);
|
||||
@@ -221,7 +180,6 @@ PulseApp.ui.storage = (() => {
|
||||
}
|
||||
|
||||
return {
|
||||
fetchStorageData,
|
||||
updateStorageInfo
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user