mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-22 19:23:31 +00:00
feat: Improve initial load experience with placeholder config
This commit is contained in:
+14
-10
@@ -82,9 +82,11 @@ function loadPbsConfig(index = null) {
|
||||
function loadConfiguration() {
|
||||
// Only load .env file if not in test environment
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
require('dotenv').config();
|
||||
require('dotenv').config();
|
||||
}
|
||||
|
||||
let isConfigPlaceholder = false; // Add this flag
|
||||
|
||||
// --- Proxmox Primary Endpoint Validation ---
|
||||
const primaryRequiredEnvVars = [
|
||||
'PROXMOX_HOST',
|
||||
@@ -103,20 +105,21 @@ function loadConfiguration() {
|
||||
}
|
||||
});
|
||||
|
||||
if (missingVars.length > 0 || placeholderVars.length > 0) {
|
||||
// Throw error only if required vars are MISSING
|
||||
if (missingVars.length > 0) {
|
||||
let errorMessages = ['--- Configuration Error (Primary Endpoint) ---'];
|
||||
if (missingVars.length > 0) {
|
||||
errorMessages.push(`Missing required environment variables: ${missingVars.join(', ')}.`);
|
||||
}
|
||||
if (placeholderVars.length > 0) {
|
||||
errorMessages.push(`The following primary environment variables seem to contain placeholder values: ${placeholderVars.join(', ')}.`);
|
||||
}
|
||||
errorMessages.push(`Missing required environment variables: ${missingVars.join(', ')}.`);
|
||||
errorMessages.push('Please ensure valid Proxmox connection details are provided.');
|
||||
errorMessages.push('Refer to server/.env.example for the required variable names and format.');
|
||||
// Throw error instead of exiting
|
||||
throw new ConfigurationError(errorMessages.join('\n'));
|
||||
}
|
||||
|
||||
// Set the flag if placeholders were detected (but don't throw error)
|
||||
if (placeholderVars.length > 0) {
|
||||
isConfigPlaceholder = true;
|
||||
console.warn(`WARN: Primary Proxmox environment variables seem to contain placeholder values: ${placeholderVars.join(', ')}. Pulse may not function correctly until configured.`);
|
||||
}
|
||||
|
||||
// --- Load All Proxmox Endpoint Configurations ---
|
||||
const endpoints = [];
|
||||
|
||||
@@ -201,7 +204,8 @@ function loadConfiguration() {
|
||||
}
|
||||
|
||||
console.log('INFO: Configuration loaded successfully.');
|
||||
return { endpoints, pbsConfigs };
|
||||
// Return the flag along with endpoints and pbsConfigs
|
||||
return { endpoints, pbsConfigs, isConfigPlaceholder };
|
||||
}
|
||||
|
||||
module.exports = { loadConfiguration, ConfigurationError }; // Export the function and error class
|
||||
+25
-22
@@ -5,9 +5,10 @@ const { loadConfiguration, ConfigurationError } = require('./configLoader');
|
||||
|
||||
let endpoints;
|
||||
let pbsConfigs;
|
||||
let isConfigPlaceholder = false; // Add global flag
|
||||
|
||||
try {
|
||||
({ endpoints, pbsConfigs } = loadConfiguration());
|
||||
({ endpoints, pbsConfigs, isConfigPlaceholder } = loadConfiguration());
|
||||
} catch (error) {
|
||||
if (error instanceof ConfigurationError) {
|
||||
console.error(error.message);
|
||||
@@ -139,21 +140,27 @@ const io = new Server(server, {
|
||||
io.on('connection', (socket) => {
|
||||
console.log('Client connected');
|
||||
// Immediately send current data if available
|
||||
// if (cachedDiscoveryData) {
|
||||
// socket.emit('rawData', cachedDiscoveryData);
|
||||
// }
|
||||
const currentState = stateManager.getState();
|
||||
if (stateManager.hasData()) {
|
||||
// Include flag in rawData
|
||||
socket.emit('rawData', { ...currentState, isConfigPlaceholder });
|
||||
} else {
|
||||
console.log('No data available yet on connect, sending initial state.');
|
||||
// Include flag in initialState
|
||||
socket.emit('initialState', { loading: true, isConfigPlaceholder });
|
||||
}
|
||||
|
||||
socket.on('requestData', async () => {
|
||||
console.log('Client requested data');
|
||||
try {
|
||||
// Get current state
|
||||
const currentState = stateManager.getState();
|
||||
if (stateManager.hasData()) {
|
||||
socket.emit('rawData', currentState);
|
||||
// Include flag in rawData
|
||||
socket.emit('rawData', { ...currentState, isConfigPlaceholder });
|
||||
} else {
|
||||
console.log('No data available yet on request, sending loading state.');
|
||||
// Send an explicit loading state if no data is available yet
|
||||
socket.emit('initialState', { loading: true });
|
||||
// Include flag in initialState
|
||||
socket.emit('initialState', { loading: true, isConfigPlaceholder });
|
||||
// Optionally trigger an immediate discovery cycle?
|
||||
// runDiscoveryCycle(); // Be careful with triggering cycles on demand
|
||||
}
|
||||
@@ -203,19 +210,15 @@ async function runDiscoveryCycle() {
|
||||
|
||||
// Update state using the state manager
|
||||
stateManager.updateDiscoveryData(discoveryData);
|
||||
// currentNodes = discoveryData.nodes || [];
|
||||
// currentVms = discoveryData.vms || [];
|
||||
// currentContainers = discoveryData.containers || [];
|
||||
// pbsDataArray = discoveryData.pbs || [];
|
||||
// No need to store in global vars anymore
|
||||
|
||||
// ... (logging summary) ...
|
||||
const currentState = stateManager.getState();
|
||||
console.log(`[Discovery Cycle] Updated state. Nodes: ${currentState.nodes.length}, VMs: ${currentState.vms.length}, CTs: ${currentState.containers.length}, PBS: ${currentState.pbs.length}`);
|
||||
const updatedState = stateManager.getState(); // Get the fully updated state
|
||||
console.log(`[Discovery Cycle] Updated state. Nodes: ${updatedState.nodes.length}, VMs: ${updatedState.vms.length}, CTs: ${updatedState.containers.length}, PBS: ${updatedState.pbs.length}`);
|
||||
|
||||
// Emit combined data using updated global state
|
||||
// Emit combined data using updated state manager state, including the flag
|
||||
if (io.engine.clientsCount > 0) {
|
||||
// ... (emit rawData with currentNodes, currentVms, etc.) ...
|
||||
io.emit('rawData', stateManager.getState());
|
||||
io.emit('rawData', { ...updatedState, isConfigPlaceholder });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[Discovery Cycle] Error during execution: ${error.message}`, error.stack);
|
||||
@@ -246,12 +249,12 @@ async function runMetricCycle() {
|
||||
// Use imported fetchMetricsData
|
||||
const fetchedMetrics = await fetchMetricsData(runningVms, runningContainers, apiClients);
|
||||
|
||||
// Update global currentMetrics state
|
||||
// Update metrics state
|
||||
if (fetchedMetrics && fetchedMetrics.length >= 0) { // Allow empty array to clear metrics
|
||||
stateManager.updateMetricsData(fetchedMetrics);
|
||||
console.log(`[Metrics Cycle] Updated metrics state for ${stateManager.getState().metrics.length} guests.`);
|
||||
} else {
|
||||
console.warn('[Metrics Cycle] fetchMetricsData returned unexpected value. Preserving previous metrics state.');
|
||||
stateManager.updateMetricsData(fetchedMetrics);
|
||||
// Emit only metrics updates if needed, or rely on full rawData updates?
|
||||
// Consider emitting a smaller 'metricsUpdate' event if performance is key
|
||||
// io.emit('metricsUpdate', stateManager.getState().metrics);
|
||||
}
|
||||
|
||||
// Emit rawData with updated global state (including metrics)
|
||||
|
||||
@@ -52,6 +52,9 @@ PulseApp.socketHandler = (() => {
|
||||
|
||||
function handleInitialState(state) {
|
||||
console.log('[socketHandler] Received initial state:', state);
|
||||
// Store the placeholder flag
|
||||
PulseApp.state.set('isConfigPlaceholder', state.isConfigPlaceholder || false);
|
||||
|
||||
if (state && state.loading) {
|
||||
// Update status text to indicate loading
|
||||
const statusText = document.getElementById('dashboard-status-text');
|
||||
@@ -100,6 +103,9 @@ PulseApp.socketHandler = (() => {
|
||||
|
||||
}
|
||||
|
||||
// Store the placeholder flag
|
||||
PulseApp.state.set('isConfigPlaceholder', data.isConfigPlaceholder || false);
|
||||
|
||||
// --- Trigger UI update after processing data ---
|
||||
if (typeof updateAllUITablesRef === 'function') {
|
||||
updateAllUITablesRef();
|
||||
@@ -147,7 +153,12 @@ PulseApp.socketHandler = (() => {
|
||||
if (loadingOverlay) {
|
||||
const loadingText = loadingOverlay.querySelector('p');
|
||||
if (loadingText) {
|
||||
loadingText.textContent = 'Connected. Reloading data...';
|
||||
// Check the flag before setting the text
|
||||
if (PulseApp.state.get('isConfigPlaceholder')) {
|
||||
loadingText.textContent = 'Configuration Required';
|
||||
} else {
|
||||
loadingText.textContent = 'Connected. Reloading data...';
|
||||
}
|
||||
}
|
||||
loadingOverlay.style.display = 'flex';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user