From 7bd6061a5960cd6444b71896692fbd1600fb926a Mon Sep 17 00:00:00 2001 From: MacRimi Date: Fri, 24 Oct 2025 21:06:45 +0200 Subject: [PATCH] Update network-metrics.tsx --- AppImage/components/network-metrics.tsx | 55 +++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/AppImage/components/network-metrics.tsx b/AppImage/components/network-metrics.tsx index d44760d..8b8dce0 100644 --- a/AppImage/components/network-metrics.tsx +++ b/AppImage/components/network-metrics.tsx @@ -1,6 +1,6 @@ "use client" -import { useState } from "react" +import { useState, useEffect } from "react" import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" import { Badge } from "./ui/badge" import { Dialog, DialogContent, DialogHeader, DialogTitle } from "./ui/dialog" @@ -155,12 +155,58 @@ export function NetworkMetrics() { const [selectedInterface, setSelectedInterface] = useState(null) const [timeframe, setTimeframe] = useState<"hour" | "day" | "week" | "month" | "year">("day") const [networkTotals, setNetworkTotals] = useState<{ received: number; sent: number }>({ received: 0, sent: 0 }) + const [vmLxcTraffic, setVmLxcTraffic] = useState>({}) const { data: interfaceHistoricalData } = useSWR(`/api/node/metrics?timeframe=${timeframe}`, fetcher, { refreshInterval: 30000, revalidateOnFocus: false, }) + useEffect(() => { + if (!networkData?.vm_lxc_interfaces) return + + const fetchVMTraffic = async () => { + const trafficData: Record = {} + + for (const iface of networkData.vm_lxc_interfaces) { + if (!iface.vmid || !iface.vm_type) continue + + try { + const response = await fetch(`/api/vm/${iface.vmid}/metrics?timeframe=${timeframe}&type=${iface.vm_type}`) + if (!response.ok) continue + + const data = await response.json() + if (!data.rrddata) continue + + // Calculate total traffic from RRD data + let totalReceived = 0 + let totalSent = 0 + + for (const point of data.rrddata) { + if (point.netin !== null && point.netin !== undefined) { + // netin is in bytes/second, multiply by interval to get total bytes + totalReceived += point.netin * (data.rrddata.length > 1 ? 60 : 1) // Assume 60 second intervals + } + if (point.netout !== null && point.netout !== undefined) { + totalSent += point.netout * (data.rrddata.length > 1 ? 60 : 1) + } + } + + trafficData[iface.vmid] = { + received: totalReceived, + sent: totalSent, + } + } catch (error) { + console.error(`[v0] Error fetching traffic for VM/LXC ${iface.vmid}:`, error) + } + } + + setVmLxcTraffic(trafficData) + } + + fetchVMTraffic() + }, [networkData?.vm_lxc_interfaces, timeframe]) + if (isLoading) { return (
@@ -360,6 +406,9 @@ export function NetworkMetrics() {
{networkData.vm_lxc_interfaces.map((interface_, index) => { const vmTypeBadge = getVMTypeBadge(interface_.vm_type) + const trafficData = interface_.vmid && vmLxcTraffic[interface_.vmid] + const bytesRecv = trafficData ? trafficData.received : interface_.bytes_recv + const bytesSent = trafficData ? trafficData.sent : interface_.bytes_sent return (
Traffic
- ↓ {formatBytes(interface_.bytes_recv)} + ↓ {formatBytes(bytesRecv)} {" / "} - ↑ {formatBytes(interface_.bytes_sent)} + ↑ {formatBytes(bytesSent)}