diff --git a/public/app.js b/public/app.js index aeade733a..6263759d5 100644 --- a/public/app.js +++ b/public/app.js @@ -121,11 +121,13 @@ document.addEventListener('DOMContentLoaded', function() { let containersData = []; let metricsData = []; let dashboardData = []; + // Load saved sort state from localStorage or use defaults + const savedSortState = JSON.parse(localStorage.getItem('pulseSortState')) || {}; const sortState = { - nodes: { column: null, direction: 'asc' }, - vms: { column: null, direction: 'asc' }, - containers: { column: null, direction: 'asc' }, - main: { column: 'id', direction: 'asc' } + nodes: { column: null, direction: 'asc', ...savedSortState.nodes }, + vms: { column: null, direction: 'asc', ...savedSortState.vms }, + containers: { column: null, direction: 'asc', ...savedSortState.containers }, + main: { column: 'id', direction: 'asc', ...savedSortState.main } }; let groupByNode = true; // Default view let filterGuestType = 'all'; // Default filter @@ -233,6 +235,9 @@ document.addEventListener('DOMContentLoaded', function() { sortState[tableType].direction = 'asc'; } + // Save updated sort state to localStorage + localStorage.setItem('pulseSortState', JSON.stringify(sortState)); + // Trigger the correct update function based on table type switch(tableType) { case 'nodes': updateNodesTable(nodesData); break; diff --git a/server/index.js b/server/index.js index 30ad9925b..8dc19dea2 100644 --- a/server/index.js +++ b/server/index.js @@ -47,6 +47,7 @@ const cors = require('cors'); const { Server } = require('socket.io'); const axios = require('axios'); const https = require('https'); +const axiosRetry = require('axios-retry').default; // Import axios-retry // Development specific dependencies let chokidar; @@ -114,6 +115,23 @@ proxmoxApi.interceptors.request.use(config => { return config; }); +// Apply retry logic to the axios instance +axiosRetry(proxmoxApi, { + retries: 3, // Number of retries + retryDelay: (retryCount, error) => { + console.warn(`Retrying API request (attempt ${retryCount}) due to error: ${error.message}`); + return axiosRetry.exponentialDelay(retryCount); // Exponential backoff + }, + retryCondition: (error) => { + // Retry on network errors or specific status codes + return ( + axiosRetry.isNetworkError(error) || + axiosRetry.isRetryableError(error) || // Includes 5xx errors by default + error.response?.status === 596 // Specifically retry on 596 + ); + }, +}); + // Create Express app const app = express(); diff --git a/server/package-lock.json b/server/package-lock.json index 2c42a34ba..326e0dc0b 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "dependencies": { "axios": "^1.6.0", + "axios-retry": "^4.5.0", "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", @@ -78,6 +79,18 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/axios-retry": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-4.5.0.tgz", + "integrity": "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==", + "license": "Apache-2.0", + "dependencies": { + "is-retry-allowed": "^2.2.0" + }, + "peerDependencies": { + "axios": "0.x || 1.x" + } + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -682,6 +695,18 @@ "node": ">= 0.10" } }, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", diff --git a/server/package.json b/server/package.json index 7d6fe6984..0f204ff18 100644 --- a/server/package.json +++ b/server/package.json @@ -5,6 +5,7 @@ "main": "index.js", "dependencies": { "axios": "^1.6.0", + "axios-retry": "^4.5.0", "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2",