import { useState, useEffect, useMemo } from "react"; import { HardDrive } from "lucide-react"; import { useTranslation } from "react-i18next"; import type { ServerMetrics } from "@/main-axios"; import { FilesystemPicker } from "./FilesystemPicker"; import { RadialGauge, Sparkline, MiniStat } from "@/components/charts"; import { MetricCard } from "@/components/metric-card"; import { LineChart, type LineChartSeries } from "@/components/charts/LineChart"; import { getMetricsHistory, type MetricsHistoryRow, } from "@/api/host-metrics-api"; import { CardTimeTabs, type HistoryTab } from "./CardTimeTabs"; export function DiskCard({ metrics, history, hostId, }: { metrics: ServerMetrics | null; history: number[]; hostId: number | null; }) { const { t } = useTranslation(); const [activeTab, setActiveTab] = useState("live"); const [rows, setRows] = useState(null); const [loading, setLoading] = useState(false); useEffect(() => { if (activeTab === "live" || hostId == null) return; let cancelled = false; setLoading(true); setRows(null); getMetricsHistory(hostId, { range: activeTab }) .then((res) => { if (!cancelled) { setRows(res.rows); setLoading(false); } }) .catch(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, [activeTab, hostId]); const filesystems = useMemo( () => metrics?.disk?.filesystems ?? [], [metrics?.disk?.filesystems], ); const defaultMount = metrics?.disk?.mount ?? null; const [selectedMount, setSelectedMount] = useState(null); // Drop a stale selection if the mount disappears between polls, so the card // falls back to the primary filesystem instead of rendering nothing. useEffect(() => { if ( selectedMount !== null && filesystems.length > 0 && !filesystems.some((fs) => fs.mount === selectedMount) ) { setSelectedMount(null); } }, [filesystems, selectedMount]); const activeMount = selectedMount ?? defaultMount; const activeFs = filesystems.find((fs) => fs.mount === activeMount) ?? null; const isCustomMount = selectedMount !== null && activeFs !== null; const percent = isCustomMount ? activeFs.percent : (metrics?.disk?.percent ?? null); const usedHuman = isCustomMount ? activeFs.usedHuman : (metrics?.disk?.usedHuman ?? null); const totalHuman = isCustomMount ? activeFs.totalHuman : (metrics?.disk?.totalHuman ?? null); const availableHuman = isCustomMount ? activeFs.availableHuman : (metrics?.disk?.availableHuman ?? null); const series: LineChartSeries[] = [ { key: "disk", label: t("hostMetrics.diskUsage"), color: "var(--chart-4)", data: rows?.map((r) => r.disk_percent) ?? [], }, ]; const timestamps = rows?.map((r) => r.ts) ?? []; return ( } action={
{activeTab === "live" && ( )} {hostId != null && ( )}
} >
{activeTab === "live" && (
)} {activeTab !== "live" && ( <> {loading && (
{t("common.loading")}
)} {!loading && rows !== null && rows.length === 0 && (
{t("metricsHistory.noData")}
)} {!loading && rows !== null && rows.length > 0 && ( `${v.toFixed(0)}%`} height={160} /> )} )}
); }