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