fix: Resolve PBS banner bug and build issues (fixes #55)

This commit is contained in:
courtmanr@gmail.com
2025-04-25 23:47:58 +01:00
parent e02b581103
commit 42dbf8e2c7
5 changed files with 90 additions and 71 deletions
+37 -54
View File
@@ -13,6 +13,7 @@
},
"devDependencies": {
"autoprefixer": "^10.4.21",
"dotenv": "^16.5.0",
"postcss": "^8.5.3",
"tailwindcss": "^3.4.4"
}
@@ -176,13 +177,15 @@
}
},
"node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=12"
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
@@ -377,21 +380,6 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/chalk/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/chalk/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -465,21 +453,6 @@
"node": ">=8"
}
},
"node_modules/cliui/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/cliui/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -642,6 +615,19 @@
"dev": true,
"license": "MIT"
},
"node_modules/dotenv": {
"version": "16.5.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz",
"integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -650,9 +636,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.140",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.140.tgz",
"integrity": "sha512-o82Rj+ONp4Ip7Cl1r7lrqx/pXhbp/lh9DpKcMNscFJdh8ebyRofnc7Sh01B4jx403RI0oqTBvlZ7OBIZLMr2+Q==",
"version": "1.5.142",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.142.tgz",
"integrity": "sha512-Ah2HgkTu/9RhTDNThBtzu2Wirdy4DC9b0sMT1pUhbkZQ5U/iwmE+PHZX1MpjD5IkJCc2wSghgGG/B04szAx07w==",
"dev": true,
"license": "ISC"
},
@@ -1881,22 +1867,6 @@
"node": ">=8"
}
},
"node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -1932,6 +1902,19 @@
"node": ">=8"
}
},
"node_modules/wrap-ansi/node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+6 -8
View File
@@ -1,12 +1,12 @@
{
"name": "pulse",
"version": "3.1.2",
"version": "3.1.3",
"description": "A lightweight monitoring application for Proxmox VE.",
"main": "server/index.js",
"scripts": {
"start": "cd server && node index.js",
"dev:server": "NODE_ENV=development node -r dotenv/config --env-file=.env server/index.js",
"dev:css": "tailwindcss -i ./src/index.css -o ./src/public/output.css --watch",
"dev:css": "tailwindcss -c ./src/tailwind.config.js -i ./src/index.css -o ./src/public/output.css --watch",
"build:css": "tailwindcss -c ./src/tailwind.config.js -i ./src/index.css -o ./src/public/output.css",
"dev": "concurrently \"npm:dev:server\" \"npm:dev:css\"",
"test": "echo \"Error: no test specified\" && exit 1"
@@ -23,13 +23,11 @@
"dependencies": {
"concurrently": "^8.2.2"
},
// NOTE: Using Tailwind CSS v3 due to build inconsistencies observed with v4.
// v4 (specifically 4.1.4) resulted in incorrectly purged CSS files when built
// within certain Linux environments (e.g., Proxmox LXC - Debian 12 x86_64),
// failing to detect dynamically added classes. v3.4.4 builds correctly.
"_comment_tailwind_v3_reason": "Using Tailwind CSS v3 (3.4.4) due to build inconsistencies observed with v4 (specifically 4.1.4). v4 resulted in incorrectly purged CSS files when built within certain Linux environments (e.g., Proxmox LXC - Debian 12 x86_64), failing to detect dynamically added classes. v3.4.4 builds correctly.",
"devDependencies": {
"tailwindcss": "^3.4.4",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.3"
"dotenv": "^16.5.0",
"postcss": "^8.5.3",
"tailwindcss": "^3.4.4"
}
}
+40 -6
View File
@@ -1,4 +1,4 @@
// require('dotenv').config(); // Load environment variables from .env file
require('dotenv').config(); // Load environment variables from .env file
// --- BEGIN Environment Variable Validation ---
const primaryRequiredEnvVars = [
@@ -478,9 +478,19 @@ app.get('/api/version', (req, res) => {
app.get('/api/storage', async (req, res) => {
try {
// Return the current node data which includes storage information
// TODO: Consider filtering/transforming this data specifically for storage endpoint if needed
res.json({ nodes: currentNodes }); // Return current node state
// Transform currentNodes into the format expected by updateStorageInfo
const storageInfoByNode = {};
(currentNodes || []).forEach(node => {
// Assuming storage details are fetched and stored within the node object
// during the discovery cycle. Need to find where Proxmox stores this.
// Use the `storage` property added by the updated `fetchDataForNode` function
storageInfoByNode[node.node] = node.storage || []; // Use node name as key
if (!node.storage) {
// This warning should ideally not appear now unless the storage fetch itself failed
console.warn(`[API /api/storage] No storage data found for node: ${node.node}. Sending empty array.`);
}
});
res.json(storageInfoByNode); // Return the transformed object
} catch (error) {
console.error("Error in /api/storage:", error);
res.status(500).json({ globalError: error.message || "Failed to fetch storage details." });
@@ -551,7 +561,8 @@ async function fetchDataForNode(apiClient, endpointId, nodeName) {
vms: [],
containers: [],
metrics: [],
nodeStatus: null // Initialize node status object
nodeStatus: null, // Initialize node status object
storage: [] // Initialize storage array
};
// Fetch node status ONLY (removed concurrent /cpu fetch)
@@ -569,6 +580,22 @@ async function fetchDataForNode(apiClient, endpointId, nodeName) {
nodeData.nodeStatus = {}; // Ensure nodeStatus is an object even on failure
}
// ---> ADDED: Fetch Node Storage <---
try {
const storageResult = await apiClient.get(`/nodes/${nodeName}/storage`);
if (storageResult.data && storageResult.data.data && Array.isArray(storageResult.data.data)) {
nodeData.storage = storageResult.data.data; // Store storage array
} else {
console.warn(`[Discovery] Storage data for ${nodeName} (Endpoint: ${endpointId}) was empty or malformed.`);
nodeData.storage = []; // Default to empty array on failure/malformed
}
} catch (err) {
const status = err.response?.status ? ` (Status: ${err.response.status})` : '';
console.error(`[Discovery] Error fetching storage for node ${nodeName} (Endpoint: ${endpointId})${status}: ${err.message}`);
nodeData.storage = []; // Default to empty array on error
}
// ---> END ADDED <---
try {
// Fetch VMs
const vmsResponse = await apiClient.get(`/nodes/${nodeName}/qemu`);
@@ -685,7 +712,8 @@ async function fetchDataForNode(apiClient, endpointId, nodeName) {
return {
vms: nodeData.vms,
containers: nodeData.containers,
nodeStatus: nodeData.nodeStatus // Return node status
nodeStatus: nodeData.nodeStatus, // Return node status
storage: nodeData.storage // Return storage array
};
}
@@ -787,6 +815,12 @@ async function fetchDiscoveryData() {
endpointNodes[targetNodeIndex].status = statusData.uptime > 0 ? 'online' : endpointNodes[targetNodeIndex].status;
}
// ---> ADDED: Merge node storage if available <---
if (result.value.storage && Array.isArray(result.value.storage)) {
endpointNodes[targetNodeIndex].storage = result.value.storage;
}
// ---> END ADDED <---
} else if (result.status === 'rejected') {
// Log node-specific failure if needed, but continue processing others
console.error(`[Discovery Cycle - ${endpointName}] Failed fetching guest data for a node: ${result.reason?.message || result.reason}`);
+7
View File
@@ -1687,6 +1687,13 @@ document.addEventListener('DOMContentLoaded', function() {
loadingMessage.remove();
}
// ---> ADDED: Also remove the 'Not Configured' banner if present, as we now have data
const notConfiguredBanner = container.querySelector('.pbs-not-configured-banner');
if (notConfiguredBanner) {
notConfiguredBanner.remove();
}
// ---> END ADDED
// console.log('[updatePbsInfo] Processing PBS array:', pbsArray);
const currentInstanceIds = new Set();
-3
View File
@@ -10,9 +10,6 @@ module.exports = {
{
pattern: /^(bg|text)-(red|yellow|green|blue)-(100|200|300|400|500|600|700|800|900)(\/50)?$/,
},
{
pattern: /^dark:(bg|text)-(red|yellow|green|blue)-(100|200|300|400|500|600|700|800|900)(\/50)?$/,
},
'vm-icon',
'ct-icon',
],