"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
) }