"use client" import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts" import { Frame, FramePanel } from "@/components/reui/frame" import { ChartContainer, ChartTooltip, type ChartConfig } from "@/components/ui/chart" import { fmtRate, formatRangeAgo, TRAFFIC_RANGE_MINUTES } from "@/lib/fmt-rate" /** * История RX/TX — adapt ReUI PRO chart-23 (multi-line + tooltip). * @see https://reui.io/preview/base/chart-23 * @see https://reui.io/blocks */ const chartConfig = { rx: { label: "RX", color: "var(--chart-rx)" }, tx: { label: "TX", color: "var(--chart-tx)" }, } satisfies ChartConfig function ChartLegendItem({ label, color }: { label: string; color: string }) { return (
{label}
) } function CustomTooltip({ active, payload, }: { active?: boolean payload?: { dataKey: string color: string value: number }[] }) { if (!active || !payload?.length) return null return (
{payload.map((item) => (
{item.dataKey === "rx" ? "RX" : "TX"}:
{fmtRate(item.value)}
))}
) } function toChartData(rx: (number|null)[], tx: (number|null)[], rangeMinutes: number) { const n = Math.max(rx.length, tx.length, 1) const denom = Math.max(n - 1, 1) return Array.from({ length: n }, (_, i) => { const minutesAgo = Math.round((1 - i / denom) * rangeMinutes) return { time: formatRangeAgo(minutesAgo), rx: typeof rx[i] === "number" && Number.isFinite(rx[i]) && rx[i] >= 0 ? rx[i] : null, tx: typeof tx[i] === "number" && Number.isFinite(tx[i]) && tx[i] >= 0 ? tx[i] : null, } }) } export function TrafficRxTxChart({ rx, tx, range = "1h", embedded = false, }: { rx: (number|null)[] tx: (number|null)[] range?: string /** Skip outer Frame when already inside OpsPanel / Frame. */ embedded?: boolean }) { const rangeMinutes = TRAFFIC_RANGE_MINUTES[range] ?? 60 const data = toChartData(rx, tx, rangeMinutes) const tickEvery = Math.max(1, Math.ceil(data.length / 6)) const hasRx = data.some(point => point.rx !== null) const hasTx = data.some(point => point.tx !== null) const hasData = hasRx || hasTx const isolatedDot = (direction: "rx" | "tx") => function IsolatedDot({ cx, cy, index }: { cx?: number; cy?: number; index?: number }) { if (index == null || cx == null || cy == null || data[index]?.[direction] == null || data[index - 1]?.[direction] != null || data[index + 1]?.[direction] != null) return return } const chart = !hasData ? (

Нет исторических измерений за выбранный период

) : (
{(!hasRx || !hasTx) &&

{!hasRx ? "Нет измерений RX за выбранный период" : "Нет измерений TX за выбранный период"}

} fmtRate(Number(v))} tickMargin={8} width={72} /> } /> {hasRx && } {hasTx && }
) if (embedded) return chart return ( {chart} ) }