diff options
Diffstat (limited to 'static/js/main.js')
-rw-r--r-- | static/js/main.js | 341 |
1 files changed, 227 insertions, 114 deletions
diff --git a/static/js/main.js b/static/js/main.js index b06bfee..55de443 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -1,6 +1,25 @@ // --- JWT Constants --- const JWT_TOKEN_KEY = 'metrics_jwt_token'; +// --- Global DOM Elements --- +// These will be properly initialized in DOMContentLoaded +let chartModal = null; +let chartModalTitle = null; +let closeChartModalBtn = null; +let closeChartBtn = null; +let expandedChart = null; +let metricsSection = null; +let viewMetricsBtn = null; +let passwordModal = null; +let passwordInput = null; +let submitPasswordBtn = null; +let closeModalBtn = null; +let passwordError = null; +let metricsControls = null; + +// --- DOM Ready Flag --- +let domReady = false; + // --- Server Stats Logic --- async function getServerStats() { const statusElement = document.getElementById('server-status'); @@ -95,14 +114,8 @@ function updateServiceStatusDisplay() { } // --- Metrics Authentication & Display Logic --- -const viewMetricsBtn = document.getElementById('view-metrics-btn'); -const passwordModal = document.getElementById('password-modal'); -const passwordInput = document.getElementById('metrics-password'); -const submitPasswordBtn = document.getElementById('submit-password'); -const closeModalBtn = document.querySelector('.close-button'); -const passwordError = document.getElementById('password-error'); -const metricsSection = document.getElementById('metrics-section'); -const metricsControls = document.getElementById('metrics-controls'); // Container for buttons +// Constants and variables will now be initialized when DOM is ready +// Functions stay decoupled from global DOM element references function getToken() { return localStorage.getItem(JWT_TOKEN_KEY); @@ -309,91 +322,125 @@ function calculateRates(data) { } function createChartContainers(metrics) { - const metricGrid = document.querySelector('.metric-grid'); - if (!metricGrid) { + if (!domReady) { + console.warn("DOM not ready for creating chart containers"); + // Wait a bit and try again + setTimeout(() => createChartContainers(metrics), 300); return; } - metricGrid.innerHTML = ''; // Clear previous - charts = {}; // Clear chart objects + if (!metricsSection) { + metricsSection = document.getElementById('metrics-section'); + if (!metricsSection) { + console.error("Metrics section not found in DOM"); + return; + } + } - // Group the metrics into two sections - const networkAndSystemMetrics = {}; - const appPerformanceMetrics = {}; - const serviceStatusMetrics = {}; + const metricGrid = metricsSection.querySelector('.metric-grid'); + if (!metricGrid) { + console.error("Metric grid not found in DOM"); + return; + } - // First categorize the metrics - for (const [metricName, definition] of Object.entries(metrics)) { - // Skip system_uptime and memory metrics (as requested) - if (metricName === 'system_uptime' || - metricName.includes('memory_total') || - metricName === 'memory_size') { - continue; - } + try { + metricGrid.innerHTML = ''; // Clear previous + charts = {}; // Clear chart objects - // Categorize based on metric name - if (metricName.startsWith('app_')) { - appPerformanceMetrics[metricName] = definition; - } else if (metricName.startsWith('service_')) { - serviceStatusMetrics[metricName] = definition; - } else { - networkAndSystemMetrics[metricName] = definition; + // Group the metrics into two sections + const networkAndSystemMetrics = {}; + const appPerformanceMetrics = {}; + const serviceStatusMetrics = {}; + + // First categorize the metrics + for (const [metricName, definition] of Object.entries(metrics)) { + // Skip system_uptime and memory metrics (as requested) + if (metricName === 'system_uptime' || + metricName.includes('memory_total') || + metricName === 'memory_size') { + continue; + } + + // Categorize based on metric name + if (metricName.startsWith('app_')) { + appPerformanceMetrics[metricName] = definition; + } else if (metricName.startsWith('service_')) { + serviceStatusMetrics[metricName] = definition; + } else { + networkAndSystemMetrics[metricName] = definition; + } } - } - - // Create section headers and containers - if (Object.keys(networkAndSystemMetrics).length > 0) { - const sectionHeader = document.createElement('h4'); - sectionHeader.textContent = 'Network & System Metrics'; - sectionHeader.className = 'metric-section-header'; - metricGrid.appendChild(sectionHeader); - // Create containers for network & system metrics - for (const [metricName, definition] of Object.entries(networkAndSystemMetrics)) { - createMetricCard(metricGrid, metricName, definition); + // Create section headers and containers + if (Object.keys(networkAndSystemMetrics).length > 0) { + const sectionHeader = document.createElement('h4'); + sectionHeader.textContent = 'Network & System Metrics'; + sectionHeader.className = 'metric-section-header'; + metricGrid.appendChild(sectionHeader); + + // Create containers for network & system metrics + for (const [metricName, definition] of Object.entries(networkAndSystemMetrics)) { + createMetricCard(metricGrid, metricName, definition); + } } - } - - // Application Performance section - if (Object.keys(appPerformanceMetrics).length > 0) { - const sectionHeader = document.createElement('h4'); - sectionHeader.textContent = 'Application Performance'; - sectionHeader.className = 'metric-section-header'; - metricGrid.appendChild(sectionHeader); - // Create containers for app performance metrics - for (const [metricName, definition] of Object.entries(appPerformanceMetrics)) { - createMetricCard(metricGrid, metricName, definition); + // Application Performance section + if (Object.keys(appPerformanceMetrics).length > 0) { + const sectionHeader = document.createElement('h4'); + sectionHeader.textContent = 'Application Performance'; + sectionHeader.className = 'metric-section-header'; + metricGrid.appendChild(sectionHeader); + + // Create containers for app performance metrics + for (const [metricName, definition] of Object.entries(appPerformanceMetrics)) { + createMetricCard(metricGrid, metricName, definition); + } } + } catch (error) { + console.error("Error creating chart containers:", error); } - - // Service Status section (not displayed as a chart - we already added it to server stats) - // We skip adding charts for service_* metrics } function createMetricCard(container, metricName, definition) { - const displayName = definition.label || metricName; - const metricCard = document.createElement('div'); - metricCard.className = 'metric-card'; - metricCard.innerHTML = `<h5>${displayName}</h5><div class="chart-container" data-metric="${metricName}" data-label="${displayName}"><canvas id="${metricName}Chart"></canvas></div>`; - container.appendChild(metricCard); - - // Add click event for chart expansion - const chartContainer = metricCard.querySelector('.chart-container'); - if (chartContainer) { - chartContainer.addEventListener('click', function() { - try { - const metricAttr = this.getAttribute('data-metric'); - const labelAttr = this.getAttribute('data-label'); - if (metricAttr && labelAttr && typeof expandChart === 'function') { - expandChart(metricAttr, labelAttr); + if (!container) return; + + try { + const displayName = definition.label || metricName; + const metricCard = document.createElement('div'); + metricCard.className = 'metric-card'; + metricCard.innerHTML = `<h5>${displayName}</h5><div class="chart-container" data-metric="${metricName}" data-label="${displayName}"><canvas id="${metricName}Chart"></canvas></div>`; + container.appendChild(metricCard); + + // Add click event for chart expansion + const chartContainer = metricCard.querySelector('.chart-container'); + if (chartContainer) { + chartContainer.addEventListener('click', function() { + try { + const metricAttr = this.getAttribute('data-metric'); + const labelAttr = this.getAttribute('data-label'); + if (metricAttr && labelAttr && typeof expandChart === 'function') { + // Wait until DOM is ready before trying to expand + if (domReady) { + expandChart(metricAttr, labelAttr); + } else { + console.warn("DOM not ready for chart expansion, delaying..."); + // Delay expansion until DOM is ready + setTimeout(() => { + if (typeof expandChart === 'function') { + expandChart(metricAttr, labelAttr); + } + }, 500); + } + } + } catch (error) { + console.error("Error expanding chart:", error); + // Fallback if there's an error - show a simple alert + alert(`Could not expand the ${displayName} chart. Please try again later.`); } - } catch (error) { - console.error("Error expanding chart:", error); - // Fallback if there's an error - show a simple alert - alert(`Could not expand the ${displayName} chart. Please try again later.`); - } - }); + }); + } + } catch (error) { + console.error("Error creating metric card:", error); } } @@ -750,21 +797,19 @@ function handleMetricsVisibilityChange() { } // Chart expansion functionality -let chartModal; -let chartModalTitle; -let closeChartModalBtn; -let closeChartBtn; -let expandedChart = null; - function expandChart(metricName, displayName) { - // Make sure the modal elements are initialized - if (!chartModal || !chartModalTitle) { - chartModal = document.getElementById('chart-modal'); - chartModalTitle = document.getElementById('chart-modal-title'); - closeChartModalBtn = document.querySelector('#chart-modal .close-button'); - closeChartBtn = document.getElementById('close-chart-modal'); + // Safety check - if DOM is not ready, we can't expand the chart yet + if (!domReady) { + console.warn("Cannot expand chart, DOM not ready yet"); + return; } + // Make sure the modal elements are initialized + if (!chartModal) chartModal = document.getElementById('chart-modal'); + if (!chartModalTitle) chartModalTitle = document.getElementById('chart-modal-title'); + if (!closeChartModalBtn) closeChartModalBtn = document.querySelector('#chart-modal .close-button'); + if (!closeChartBtn) closeChartBtn = document.getElementById('close-chart-modal'); + // Safety check - if elements still not found, exit if (!chartModal || !chartModalTitle) { console.error("Chart modal elements not found"); @@ -793,7 +838,11 @@ function expandChart(metricName, displayName) { // If there's already an expanded chart, destroy it first if (expandedChart) { - expandedChart.destroy(); + try { + expandedChart.destroy(); + } catch (error) { + console.warn("Error destroying previous chart:", error); + } } // Clone the options and data from the original chart @@ -803,47 +852,95 @@ function expandChart(metricName, displayName) { return; } - const chartOptions = JSON.parse(JSON.stringify(originalChart.options)); - // Adjust options for the expanded view - chartOptions.maintainAspectRatio = false; - if (chartOptions.scales && chartOptions.scales.y) { - chartOptions.scales.y.ticks.maxTicksLimit = 10; // More ticks for expanded view + try { + const chartOptions = JSON.parse(JSON.stringify(originalChart.options)); + // Adjust options for the expanded view + chartOptions.maintainAspectRatio = false; + if (chartOptions.scales && chartOptions.scales.y) { + chartOptions.scales.y.ticks.maxTicksLimit = 10; // More ticks for expanded view + } + + // Create the expanded chart with cloned data + const chartData = { + datasets: originalChart.data.datasets.map(dataset => ({ + ...dataset, + data: [...dataset.data], + pointRadius: 3 // Show points in expanded view + })) + }; + + expandedChart = new Chart(ctx, { + type: 'line', + data: chartData, + options: chartOptions + }); + } catch (error) { + console.error("Error creating expanded chart:", error); } - - // Create the expanded chart with cloned data - const chartData = { - datasets: originalChart.data.datasets.map(dataset => ({ - ...dataset, - data: [...dataset.data], - pointRadius: 3 // Show points in expanded view - })) - }; - - expandedChart = new Chart(ctx, { - type: 'line', - data: chartData, - options: chartOptions - }); } // Close modal events function closeChartModal() { + if (!domReady) { + console.warn("Cannot close chart modal, DOM not ready yet"); + return; + } + if (!chartModal) { chartModal = document.getElementById('chart-modal'); - if (!chartModal) return; + if (!chartModal) { + console.error("Chart modal element not found"); + return; + } } - chartModal.classList.remove('show'); - setTimeout(() => chartModal.style.display = 'none', 300); + try { + chartModal.classList.remove('show'); + setTimeout(() => { + if (chartModal) chartModal.style.display = 'none'; + }, 300); + } catch (error) { + console.error("Error closing chart modal:", error); + } } // --- Initialize everything when DOM is loaded --- document.addEventListener('DOMContentLoaded', function() { - // Initialize chart modal elements + // Set DOM ready flag + domReady = true; + + // Initialize all DOM elements chartModal = document.getElementById('chart-modal'); chartModalTitle = document.getElementById('chart-modal-title'); closeChartModalBtn = document.querySelector('#chart-modal .close-button'); closeChartBtn = document.getElementById('close-chart-modal'); + metricsSection = document.getElementById('metrics-section'); + viewMetricsBtn = document.getElementById('view-metrics-btn'); + passwordModal = document.getElementById('password-modal'); + passwordInput = document.getElementById('metrics-password'); + submitPasswordBtn = document.getElementById('submit-password'); + passwordError = document.getElementById('password-error'); + metricsControls = document.getElementById('metrics-controls'); + + // Log any missing critical elements + if (!chartModal) console.warn("Chart modal element not found in DOM"); + if (!chartModalTitle) console.warn("Chart modal title element not found in DOM"); + if (!metricsSection) console.warn("Metrics section element not found in DOM"); + if (!passwordModal) console.warn("Password modal element not found in DOM"); + + // For debugging - log all initialized elements + console.log("DOM elements initialized:", { + chartModal: !!chartModal, + chartModalTitle: !!chartModalTitle, + closeChartModalBtn: !!closeChartModalBtn, + closeChartBtn: !!closeChartBtn, + metricsSection: !!metricsSection, + viewMetricsBtn: !!viewMetricsBtn, + passwordModal: !!passwordModal + }); + + // Dispatch a custom event to indicate DOM is ready + document.dispatchEvent(new Event('dom-fully-ready')); // Start server stats check getServerStats(); @@ -929,4 +1026,20 @@ document.addEventListener('DOMContentLoaded', function() { } } }); +}); + +// Ensure chart elements are initialized when DOM is fully ready +document.addEventListener('dom-fully-ready', function() { + // Initialize chart elements again to be extra safe + chartModal = document.getElementById('chart-modal'); + chartModalTitle = document.getElementById('chart-modal-title'); + closeChartModalBtn = document.querySelector('#chart-modal .close-button'); + closeChartBtn = document.getElementById('close-chart-modal'); + + console.log("Chart elements initialized on dom-fully-ready event:", { + chartModal: !!chartModal, + chartModalTitle: !!chartModalTitle, + closeChartModalBtn: !!closeChartModalBtn, + closeChartBtn: !!closeChartBtn + }); });
\ No newline at end of file |