"use client" import { useMemo } from "react" import { type ColumnDef, getCoreRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table" import type { Server } from "@/lib/data" import { Flag } from "@/components/flag" import { DataGridShell } from "@/components/data-grids/shared/data-grid-shell" import { DATA_GRID_CELL_PAD, DATA_GRID_CELL_PAD_FIRST, DATA_GRID_CELL_PAD_LAST, } from "@/components/data-grids/shared/data-grid-layout" import { DataGridSortHeader } from "@/components/data-grids/shared/data-grid-sort-header" import { cn } from "@/lib/utils" import { ArrowRightIcon, RefreshCwIcon } from "lucide-react" export interface SpeedTestRunRow { id: string startedAt: number srcServerId: string dstServerId: string srcInterface?: string dstInterface?: string protocol: "tcp" | "udp" direction: "transmit" | "receive" | "both" durationSec: number txAvgMbps: number rxAvgMbps: number status: "running" | "done" | "error" afterBtPing?: { rttMs: number | null; lossPct: number | null; error: string | null } | null srcInterfaceAddress?: string | null dstInterfaceAddress?: string | null } interface UptimeSpeedHistoryDataGridProps { runs: SpeedTestRunRow[] servers: Server[] } function UptimeSpeedHistoryDataGrid({ runs, servers }: UptimeSpeedHistoryDataGridProps) { const columns = useMemo[]>( () => [ { id: "startedAt", accessorKey: "startedAt", header: ({ column }) => , cell: ({ row }) => ( {new Date(row.original.startedAt).toLocaleString("ru-RU", { hour: "2-digit", minute: "2-digit", second: "2-digit", day: "2-digit", month: "2-digit", })} ), meta: { headerTitle: "Время", headerClassName: DATA_GRID_CELL_PAD_FIRST, cellClassName: DATA_GRID_CELL_PAD_FIRST, }, }, { id: "route", accessorFn: (row) => `${row.srcServerId}-${row.dstServerId}`, header: ({ column }) => , cell: ({ row }) => { const run = row.original const src = servers.find((s) => s.id === run.srcServerId) const dst = servers.find((s) => s.id === run.dstServerId) return (
{src?.name ?? run.srcServerId} {dst?.name ?? run.dstServerId}
{run.srcInterfaceAddress && run.dstInterfaceAddress ? `${run.srcInterfaceAddress} → ${run.dstInterfaceAddress}` : "внутренние IP: auto/не указаны"}
) }, meta: { headerTitle: "Маршрут", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "params", accessorFn: (row) => `${row.protocol}-${row.direction}-${row.durationSec}`, header: ({ column }) => , cell: ({ row }) => { const run = row.original return (
{run.protocol.toUpperCase()} · {run.direction} · {run.durationSec}s
) }, meta: { headerTitle: "Параметры", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "status", accessorKey: "status", header: ({ column }) => , cell: ({ row }) => { const status = row.original.status if (status === "running") { return ( running ) } if (status === "error") { return error } return done }, meta: { headerTitle: "Статус", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "txAvgMbps", accessorKey: "txAvgMbps", header: ({ column }) => , cell: ({ row }) => { const run = row.original const maxVal = Math.max(run.txAvgMbps, run.rxAvgMbps, 1) return (
{run.txAvgMbps} Мбит/с
) }, meta: { headerTitle: "TX avg", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "rxAvgMbps", accessorKey: "rxAvgMbps", header: ({ column }) => , cell: ({ row }) => { const run = row.original const maxVal = Math.max(run.txAvgMbps, run.rxAvgMbps, 1) return (
{run.rxAvgMbps} Мбит/с
) }, meta: { headerTitle: "RX avg", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "afterBtPing", accessorFn: (row) => row.afterBtPing?.rttMs ?? -1, header: ({ column }) => , cell: ({ row }) => { const run = row.original if (run.status !== "done") return if (run.afterBtPing?.error) { return ( ошибка ) } if (run.afterBtPing?.rttMs != null) { return ( {run.afterBtPing.rttMs} мс {run.afterBtPing.lossPct != null && run.afterBtPing.lossPct > 0 && ( · {run.afterBtPing.lossPct}% )} ) } return ( timeout {run.afterBtPing?.lossPct != null && · {run.afterBtPing.lossPct}%} ) }, meta: { headerTitle: "Ping после BT", headerClassName: DATA_GRID_CELL_PAD_LAST, cellClassName: DATA_GRID_CELL_PAD_LAST, }, }, ], [servers], ) const table = useReactTable({ data: runs, columns, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getRowId: (row) => row.id, initialState: { sorting: [{ id: "startedAt", desc: true }] }, }) return ( ) } export { UptimeSpeedHistoryDataGrid, type UptimeSpeedHistoryDataGridProps }