From f25654ead792cef8198d22b43ca4cadf2e6ea1a4 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Wed, 22 Oct 2025 19:25:04 +0200 Subject: [PATCH] Updte AppImage --- AppImage/components/node-metrics-charts.tsx | 343 ++++++++++++++++++++ AppImage/components/system-overview.tsx | 4 + 2 files changed, 347 insertions(+) create mode 100644 AppImage/components/node-metrics-charts.tsx diff --git a/AppImage/components/node-metrics-charts.tsx b/AppImage/components/node-metrics-charts.tsx new file mode 100644 index 0000000..f42148a --- /dev/null +++ b/AppImage/components/node-metrics-charts.tsx @@ -0,0 +1,343 @@ +"use client" + +import { useState, useEffect } from "react" +import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select" +import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from "recharts" +import { Loader2, TrendingUp, MemoryStick } from "lucide-react" + +const TIMEFRAME_OPTIONS = [ + { value: "hour", label: "1 Hour" }, + { value: "day", label: "24 Hours" }, + { value: "week", label: "7 Days" }, + { value: "month", label: "30 Days" }, +] + +interface NodeMetricsData { + time: string + timestamp: number + cpu: number + load: number + memoryTotal: number + memoryUsed: number + memoryFree: number + memoryZfsArc: number +} + +export function NodeMetricsCharts() { + const [timeframe, setTimeframe] = useState("day") + const [data, setData] = useState([]) + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + + useEffect(() => { + fetchMetrics() + }, [timeframe]) + + const fetchMetrics = async () => { + setLoading(true) + setError(null) + + try { + const baseUrl = + typeof window !== "undefined" ? `${window.location.protocol}//${window.location.hostname}:8008` : "" + const apiUrl = `${baseUrl}/api/node/metrics?timeframe=${timeframe}` + + const response = await fetch(apiUrl) + + if (!response.ok) { + const errorData = await response.json() + throw new Error(errorData.error || "Failed to fetch node metrics") + } + + const result = await response.json() + + const transformedData = result.data.map((item: any) => { + const date = new Date(item.time * 1000) + let timeLabel = "" + + if (timeframe === "hour") { + timeLabel = date.toLocaleString("en-US", { + hour: "2-digit", + minute: "2-digit", + hour12: false, + }) + } else if (timeframe === "day") { + timeLabel = date.toLocaleString("en-US", { + hour: "2-digit", + minute: "2-digit", + hour12: false, + }) + } else if (timeframe === "week") { + timeLabel = date.toLocaleString("en-US", { + month: "short", + day: "numeric", + hour: "2-digit", + hour12: false, + }) + } else { + timeLabel = date.toLocaleString("en-US", { + month: "short", + day: "numeric", + }) + } + + return { + time: timeLabel, + timestamp: item.time, + cpu: item.cpu ? Number((item.cpu * 100).toFixed(2)) : 0, + load: item.loadavg ? Number(item.loadavg[0].toFixed(2)) : 0, + memoryTotal: item.memtotal ? Number((item.memtotal / 1024 / 1024 / 1024).toFixed(2)) : 0, + memoryUsed: item.memused ? Number((item.memused / 1024 / 1024 / 1024).toFixed(2)) : 0, + memoryFree: item.memfree ? Number((item.memfree / 1024 / 1024 / 1024).toFixed(2)) : 0, + memoryZfsArc: item.zfsarc ? Number((item.zfsarc / 1024 / 1024 / 1024).toFixed(2)) : 0, + } + }) + + setData(transformedData) + } catch (err: any) { + console.error("[v0] Error fetching node metrics:", err) + setError(err.message || "Error loading metrics") + } finally { + setLoading(false) + } + } + + const tickInterval = Math.ceil(data.length / 8) + + if (loading) { + return ( +
+ + +
+ +
+
+
+ + +
+ +
+
+
+
+ ) + } + + if (error) { + return ( +
+ + +
+

Metrics data not available yet

+
+
+
+ + +
+

Metrics data not available yet

+
+
+
+
+ ) + } + + if (data.length === 0) { + return ( +
+ + +
+

No metrics data available

+
+
+
+ + +
+

No metrics data available

+
+
+
+
+ ) + } + + return ( +
+ {/* Timeframe Selector */} +
+ +
+ + {/* Charts Grid */} +
+ {/* CPU Usage + Load Average Chart */} + + + + + CPU Usage & Load Average + + + + + + + + + + + + + + + + + + + {/* Memory Usage Chart */} + + + + + Memory Usage + + + + + + + + + + + + + + + + + + +
+
+ ) +} diff --git a/AppImage/components/system-overview.tsx b/AppImage/components/system-overview.tsx index d5fa6ab..1d82d20 100644 --- a/AppImage/components/system-overview.tsx +++ b/AppImage/components/system-overview.tsx @@ -5,6 +5,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" import { Progress } from "./ui/progress" import { Badge } from "./ui/badge" import { Cpu, MemoryStick, Thermometer, Server, Zap, AlertCircle, HardDrive, Network } from "lucide-react" +import { NodeMetricsCharts } from "./node-metrics-charts" interface SystemData { cpu_usage: number @@ -515,6 +516,9 @@ export function SystemOverview() { + {/* Node Metrics Charts */} + +
{/* Storage Summary */}