Repository Public
1"use client";23import { useState } from "react";4import { getDict, type Locale } from "@/lib/i18n";5import { HISTORY_WINDOWS, type HistoryWindow } from "@/lib/live-types";6import { LineChart, type Series } from "./LineChart";7import { useHistory } from "./store";89/** History chart with its time-range control, for the whole cluster or one node. */10export function HistoryCard({ target, locale, title, headingId }: { target: string; locale: Locale; title: string; headingId: string }) {11 const c = getDict(locale).live.chart;12 const [window, setWindow] = useState<HistoryWindow>("1h");13 const { loading, history } = useHistory(target, window);14 const series: Series[] = [15 { key: "cpu", label: c.cpu, color: "var(--color-viz-cpu)" },16 { key: "mem", label: c.memory, color: "var(--color-viz-mem)" },17 { key: "gpu", label: c.gpu, color: "var(--color-viz-gpu)" },18 ];19 const labels: Record<HistoryWindow, string> = { "1h": c.w1h, "6h": c.w6h, "24h": c.w24h };20 const points = history?.points ?? [];21 return (22 <section aria-labelledby={headingId} className="card p-5 md:p-7">23 <div className="flex flex-wrap items-center justify-between gap-3">24 <div>25 <h2 id={headingId} className="text-lg font-semibold tracking-[-0.02em]">{title}</h2>26 <p className="mt-0.5 text-[0.8125rem] text-mute">{c.unit}</p>27 </div>28 <div role="group" aria-label={c.window} className="flex gap-1.5">29 {HISTORY_WINDOWS.map((w) => <button key={w} type="button" className="chip" aria-pressed={window === w} onClick={() => setWindow(w)}>{labels[w]}</button>)}30 </div>31 </div>32 <div className="mt-5" data-testid="history-chart" data-state={loading ? "loading" : points.length > 1 ? "ready" : "empty"}>33 {points.length > 1 ? (34 <LineChart points={points} series={series} locale={locale} longWindow={window === "24h"} alt={c.alt(labels[window])} tableLabel={c.table} timeLabel={c.time} />35 ) : (36 <p className="flex h-[240px] items-center justify-center rounded-xl bg-surface-2 text-[0.9375rem] text-mute">{loading ? c.loading : c.empty}</p>37 )}38 </div>39 </section>40 );41}42