diff --git a/AppImage/components/hardware.tsx b/AppImage/components/hardware.tsx index 53e0b2a..89981d4 100644 --- a/AppImage/components/hardware.tsx +++ b/AppImage/components/hardware.tsx @@ -21,6 +21,7 @@ import { import useSWR from "swr" import { useState, useEffect } from "react" import { type HardwareData, type GPU, type PCIDevice, type StorageDevice, fetcher } from "../types/hardware" +import { usePollingConfig } from "@/lib/polling-config" const parseLsblkSize = (sizeStr: string | undefined): number => { if (!sizeStr) return 0 @@ -163,14 +164,38 @@ const groupAndSortTemperatures = (temperatures: any[]) => { } export default function Hardware() { + const { intervals } = usePollingConfig() + + // Static data (loaded once on mount): system info, memory, PCI, network/storage summaries const { - data: hardwareData, - error, - isLoading, + data: staticHardwareData, + error: staticError, + isLoading: staticLoading, } = useSWR("/api/hardware", fetcher, { - refreshInterval: 5000, + refreshInterval: 0, // Never refresh automatically - only load once + revalidateOnFocus: false, + revalidateOnReconnect: false, }) + // Dynamic data (temperatures only) - polls at configured interval + const { data: temperatureData, error: tempError } = useSWR<{ temperatures: any[] }>( + "/api/hardware/temperatures", + fetcher, + { + refreshInterval: intervals.hardware, + }, + ) + + const hardwareData = staticHardwareData + ? { + ...staticHardwareData, + temperatures: temperatureData?.temperatures || staticHardwareData.temperatures || [], + } + : null + + const error = staticError || tempError + const isLoading = staticLoading + useEffect(() => { if (hardwareData?.storage_devices) { console.log("[v0] Storage devices data from backend:", hardwareData.storage_devices) diff --git a/AppImage/components/network-metrics.tsx b/AppImage/components/network-metrics.tsx index 0d9386a..5a5458b 100644 --- a/AppImage/components/network-metrics.tsx +++ b/AppImage/components/network-metrics.tsx @@ -73,6 +73,10 @@ interface NetworkInterface { vm_status?: string } +interface NetworkMetricsProps { + isActive?: boolean +} + const getInterfaceTypeBadge = (type: string) => { switch (type) { case "physical": @@ -143,15 +147,16 @@ const fetcher = async (url: string): Promise => { return response.json() } -export function NetworkMetrics() { +export function NetworkMetrics({ isActive = true }: NetworkMetricsProps) { const { data: networkData, error, isLoading, } = useSWR("/api/network", fetcher, { - refreshInterval: 60000, // Refresh every 60 seconds + refreshInterval: isActive ? 60000 : 0, // Refresh every 60 seconds only if active, otherwise pause revalidateOnFocus: false, revalidateOnReconnect: true, + isPaused: () => !isActive, }) const [selectedInterface, setSelectedInterface] = useState(null) @@ -166,10 +171,15 @@ export function NetworkMetrics() { revalidateOnReconnect: true, }) - const { data: interfaceHistoricalData } = useSWR(`/api/node/metrics?timeframe=${timeframe}`, fetcher, { - refreshInterval: 30000, - revalidateOnFocus: false, - }) + const { data: interfaceHistoricalData } = useSWR( + isActive ? `/api/node/metrics?timeframe=${timeframe}` : null, + fetcher, + { + refreshInterval: isActive ? 30000 : 0, + revalidateOnFocus: false, + isPaused: () => !isActive, + }, + ) if (isLoading) { return ( diff --git a/AppImage/components/network-traffic-chart.tsx b/AppImage/components/network-traffic-chart.tsx index a1576f3..770ebe3 100644 --- a/AppImage/components/network-traffic-chart.tsx +++ b/AppImage/components/network-traffic-chart.tsx @@ -16,6 +16,7 @@ interface NetworkTrafficChartProps { interfaceName?: string onTotalsCalculated?: (totals: { received: number; sent: number }) => void refreshInterval?: number // En milisegundos, por defecto 60000 (60 segundos) + isActive?: boolean } const CustomNetworkTooltip = ({ active, payload, label }: any) => { @@ -43,6 +44,7 @@ export function NetworkTrafficChart({ interfaceName, onTotalsCalculated, refreshInterval = 60000, + isActive = true, }: NetworkTrafficChartProps) { const [data, setData] = useState([]) const [loading, setLoading] = useState(true) @@ -59,16 +61,20 @@ export function NetworkTrafficChart({ }, [timeframe, interfaceName]) useEffect(() => { - if (refreshInterval > 0) { + if (refreshInterval > 0 && isActive) { const interval = setInterval(() => { fetchMetrics() }, refreshInterval) return () => clearInterval(interval) } - }, [timeframe, interfaceName, refreshInterval]) + }, [timeframe, interfaceName, refreshInterval, isActive]) const fetchMetrics = async () => { + if (!isActive) { + return + } + if (isInitialLoad) { setLoading(true) } diff --git a/AppImage/components/node-metrics-charts.tsx b/AppImage/components/node-metrics-charts.tsx index a8d86e4..d6b16f7 100644 --- a/AppImage/components/node-metrics-charts.tsx +++ b/AppImage/components/node-metrics-charts.tsx @@ -78,6 +78,12 @@ export function NodeMetricsCharts() { useEffect(() => { console.log("[v0] NodeMetricsCharts component mounted") fetchMetrics() + + const interval = setInterval(() => { + fetchMetrics() + }, 60000) // 60 seconds instead of 30 to reduce server load + + return () => clearInterval(interval) }, [timeframe]) const fetchMetrics = async () => { diff --git a/AppImage/components/proxmox-dashboard.tsx b/AppImage/components/proxmox-dashboard.tsx index 71651d1..20a41cc 100644 --- a/AppImage/components/proxmox-dashboard.tsx +++ b/AppImage/components/proxmox-dashboard.tsx @@ -13,6 +13,9 @@ import { SystemLogs } from "./system-logs" import { OnboardingCarousel } from "./onboarding-carousel" import { HealthStatusModal } from "./health-status-modal" import { getApiUrl } from "../lib/api-config" +import { usePollingConfig, INTERVAL_OPTIONS } from "@/lib/polling-config" +import { Label } from "./ui/label" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select" import { RefreshCw, AlertTriangle, @@ -26,6 +29,7 @@ import { Box, Cpu, FileText, + Settings, } from "lucide-react" import Image from "next/image" import { ThemeToggle } from "./theme-toggle" @@ -65,6 +69,7 @@ export function ProxmoxDashboard() { const [showNavigation, setShowNavigation] = useState(true) const [lastScrollY, setLastScrollY] = useState(0) const [showHealthModal, setShowHealthModal] = useState(false) + const { intervals, updateInterval } = usePollingConfig() const fetchSystemData = useCallback(async () => { console.log("[v0] Fetching system data from Flask server...") @@ -127,8 +132,12 @@ export function ProxmoxDashboard() { }, []) useEffect(() => { + // Only fetch if we actually need the data (always for header) fetchSystemData() - const interval = setInterval(fetchSystemData, 10000) + + // Poll every 30 seconds for header info (less frequent since it's just for display) + const interval = setInterval(fetchSystemData, 30000) + return () => clearInterval(interval) }, [fetchSystemData]) @@ -216,6 +225,8 @@ export function ProxmoxDashboard() { return "Hardware" case "logs": return "System Logs" + case "settings": + return "Settings" default: return "Navigation Menu" } @@ -362,7 +373,7 @@ export function ProxmoxDashboard() { >
- + System Logs + + Settings + @@ -507,6 +524,21 @@ export function ProxmoxDashboard() { System Logs +
@@ -517,7 +549,7 @@ export function ProxmoxDashboard() {
- + @@ -525,7 +557,7 @@ export function ProxmoxDashboard() { - + @@ -539,6 +571,183 @@ export function ProxmoxDashboard() { + + +
+
+

+ + Settings +

+

+ Configure your ProxMenux Monitor preferences and system settings. +

+ +
+
+

Appearance

+
+
+

Theme

+

Choose your preferred color scheme

+
+ +
+
+ +
+

System Information

+
+
+ Version: + ProxMenux Monitor v1.0.0 +
+
+ Server: + {systemStatus.serverName} +
+
+ Node ID: + {systemStatus.nodeId} +
+
+ Status: + + {statusIcon} + {systemStatus.status} + +
+
+
+ +
+

Polling Intervals

+

+ Configure how frequently each section updates its data. Lower values provide more real-time data + but increase server load. +

+
+
+
+ +

Update frequency for storage metrics

+
+ +
+ +
+
+ +

Update frequency for network metrics

+
+ +
+ +
+
+ +

Update frequency for VM/LXC data

+
+ +
+ +
+
+ +

Update frequency for temperature sensors only

+
+ +
+
+

+ Note: Hardware static information (System Info, Memory Modules, PCI Devices, + Network/Storage Summaries) is loaded only once when entering the Hardware page and does not + refresh automatically. +

+
+ +
+

About

+

+ ProxMenux Monitor is a comprehensive dashboard for monitoring and managing Proxmox VE systems. +

+ + Support and contribute to the project → + +
+
+
+
+