From 19356d05e69cfd78723bc76659871340e5b2e2b3 Mon Sep 17 00:00:00 2001 From: "Joseph.Rawlings" Date: Wed, 17 Dec 2025 16:53:14 -0500 Subject: [PATCH] refactor: enhance network traffic polling logic and initialization handling --- .../Servers/Proxmox/views/overview.blade.php | 335 +++--------------- 1 file changed, 48 insertions(+), 287 deletions(-) diff --git a/extensions/Servers/Proxmox/views/overview.blade.php b/extensions/Servers/Proxmox/views/overview.blade.php index 8a3a39699..5bac642c8 100644 --- a/extensions/Servers/Proxmox/views/overview.blade.php +++ b/extensions/Servers/Proxmox/views/overview.blade.php @@ -837,7 +837,7 @@ -
+
@@ -981,12 +981,16 @@
Failed to load network data -

${error.message}

`; } @@ -1630,213 +1555,49 @@ } }; - let pollInterval = null; - + // Simplified bootstrap - initializes once const bootstrap = () => { - // Clear any existing interval + if (isInitialized) return; + + const container = document.getElementById('network-traffic-container'); + if (!container) return; + + pollingEndpoint = container.dataset.liveTrafficEndpoint; + if (!pollingEndpoint) return; + + isInitialized = true; + if (pollInterval) { clearInterval(pollInterval); - pollInterval = null; } - - const container = document.getElementById('network-traffic-container'); - pollingEndpoint = container?.dataset?.liveTrafficEndpoint || null; - console.log('Network Traffic Bootstrap: Container found:', !!container); - console.log('Network Traffic Bootstrap: Endpoint:', pollingEndpoint); - - if (pollingEndpoint && container) { - // Check if container exists and has endpoint - be less strict about visibility - // Sometimes container exists but offsetParent check fails initially - const isVisible = container.offsetParent !== null; - const containerExists = container && container.dataset.liveTrafficEndpoint; - - if (isVisible || containerExists) { - // Always poll immediately on bootstrap (don't wait for interval) - console.log('Network Traffic: Polling immediately on bootstrap...'); - - // Poll immediately - don't wait - poll(); - - // Set up interval for subsequent polls (30 seconds) - // Minimal delay to avoid race condition - setTimeout(() => { - if (!pollInterval) { - pollInterval = setInterval(poll, 30000); - console.log('Network Traffic: Polling interval set up (30 seconds)'); - } - }, 100); - } else { - console.log('Network Traffic: Container not ready, will retry via visibility check'); - } - } + // Poll immediately and set up interval + poll(); + pollInterval = setInterval(poll, 30000); }; - // Make bootstrap accessible globally for re-initialization - window.initNetworkTraffic = bootstrap; - - // Initial bootstrap - try multiple times aggressively - const tryBootstrap = () => { - const container = document.getElementById('network-traffic-container'); - if (container && container.dataset.liveTrafficEndpoint) { - bootstrap(); - return true; - } - return false; + window.initNetworkTraffic = () => { + isInitialized = false; + bootstrap(); }; - // Try immediately - if (!tryBootstrap()) { - // If DOM is loading, wait for it - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', () => { - // Try multiple times with minimal delays - setTimeout(() => tryBootstrap() || setTimeout(() => tryBootstrap() || setTimeout(tryBootstrap, 50), 50), 10); - }); - } else { - // DOM ready, try with minimal delays - setTimeout(() => tryBootstrap() || setTimeout(() => tryBootstrap() || setTimeout(tryBootstrap, 50), 50), 10); - } + // Initialize + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', bootstrap); } else { - // Successfully bootstrapped, also try immediate poll as backup - console.log('Network Traffic: Bootstrap successful, ensuring immediate poll...'); + setTimeout(bootstrap, 10); } - // Re-initialize on Livewire lifecycle events (immediate) - document.addEventListener('livewire:init', () => { - setTimeout(tryBootstrap, 10); - }); - - document.addEventListener('livewire:load', () => { - setTimeout(tryBootstrap, 10); - }); - - // Re-initialize when Livewire navigates (tab switches) + // Handle Livewire navigation document.addEventListener('livewire:navigated', () => { - // Clear charts when navigating (DOM will be replaced) - Object.keys(charts).forEach(interfaceId => { - try { - if (charts[interfaceId] && typeof charts[interfaceId].destroy === 'function') { - charts[interfaceId].destroy(); - } - } catch (e) { - console.warn('Error destroying chart during navigation:', e); - } - }); - charts = {}; // Clear charts object - - // Re-initialize after a short delay to ensure DOM is ready - setTimeout(() => { - tryBootstrap(); - // Also ensure event listeners are re-attached if interfaces are already rendered - if (networkData && networkData.interfaces && networkData.interfaces.length > 0) { - const container = document.getElementById('network-traffic-container'); - if (container && container.querySelectorAll('.chart-toggle').length > 0) { - // Re-attach chart toggle listeners - document.querySelectorAll('.chart-toggle').forEach(button => { - // Remove any existing listeners by cloning the button - const newButton = button.cloneNode(true); - button.parentNode.replaceChild(newButton, button); - - // Add fresh event listener - newButton.addEventListener('click', (e) => { - const interfaceId = e.currentTarget.dataset.interface; - const container = document.querySelector(`[data-chart-container="${interfaceId}"]`); - - if (container) { - container.classList.toggle('open'); - - // Create chart on first open - if (container.classList.contains('open') && !charts[interfaceId]) { - const attemptCreateChart = (retries = 5, delay = 200) => { - const interfaceData = networkData?.interfaces?.find(i => - i.id.replace(/[^a-z0-9]/gi, '-') === interfaceId - ); - - const canvas = document.getElementById(`chart-${interfaceId}`); - - if (canvas && interfaceData && interfaceData.history) { - const historyLength = Math.max( - interfaceData.history.download?.length || 0, - interfaceData.history.upload?.length || 0 - ); - - if (historyLength > 0) { - console.log('Creating chart for interface:', interfaceId, 'with data:', { - id: interfaceData.id, - name: interfaceData.name, - historyLength: historyLength - }); - - requestAnimationFrame(() => { - setTimeout(() => { - if (!charts[interfaceId]) { - createChart(interfaceId, interfaceData); - } - }, 50); - }); - return; - } - } - - if (retries > 0) { - console.log(`Chart data not ready for ${interfaceId}, retrying... (${retries} attempts left)`); - setTimeout(() => attemptCreateChart(retries - 1, delay), delay); - } else { - console.warn('Failed to create chart for', interfaceId, 'after multiple attempts'); - } - }; - - attemptCreateChart(); - } - } - }); - }); - } - } - }, 100); + Object.keys(charts).forEach(id => { try { charts[id]?.destroy(); } catch(e) {} }); + charts = {}; + isInitialized = false; + setTimeout(bootstrap, 50); }); - // Check periodically if container is visible and needs initialization (very frequent) - const visibilityCheck = setInterval(() => { - const container = document.getElementById('network-traffic-container'); - if (container) { - const isVisible = container.offsetParent !== null; - const hasEndpoint = container.dataset.liveTrafficEndpoint; - const showsPlaceholder = container.querySelector('.border-dashed') !== null || - container.textContent.includes('Loading live network statistics'); - - // If visible, has endpoint, and either: - // 1. No polling interval (not initialized), OR - // 2. Shows placeholder (was reset) - if (isVisible && hasEndpoint && (showsPlaceholder || !pollInterval)) { - console.log('Network Traffic: Container needs initialization (placeholder:', showsPlaceholder, 'no interval:', !pollInterval, '), re-initializing...'); - bootstrap(); - } - - // Also check if we have endpoint but haven't polled yet - poll immediately - if (isVisible && hasEndpoint && !pollInterval && !pollInFlight) { - // Update pollingEndpoint if it's not set - if (!pollingEndpoint) { - pollingEndpoint = hasEndpoint; - } - console.log('Network Traffic: Container visible with endpoint but no polling active, polling immediately...'); - poll(); - setTimeout(() => { - if (!pollInterval) { - pollInterval = setInterval(poll, 30000); - } - }, 100); - } - } - }, 200); // Check very frequently (every 200ms) for immediate response - - // Clean up on page unload window.addEventListener('beforeunload', () => { - clearInterval(visibilityCheck); - if (pollInterval) { - clearInterval(pollInterval); - } + if (pollInterval) clearInterval(pollInterval); }); })();