"use client" import { useMemo } from "react" import { type ColumnDef, getCoreRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table" import { cn } from "@/lib/utils" 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 { EmptyState } from "@/components/empty-state" import { ActivityIcon } from "lucide-react" export interface BfdSessionRow { id: string serverId: string serverLabel: string localAddr: string remoteAddr: string state: "Up" | "Down" | "Init" | "AdminDown" interval: number multiplier: number iface: string uptime: string | null multihop: boolean rxInterval: number holdTime: number packetsRx: number packetsTx: number stateChanges: number } function stateClass(state: BfdSessionRow["state"]) { if (state === "Up") return "bg-[var(--status-online-bg)] text-[var(--status-online-fg)] border-current/25" if (state === "Init") return "bg-[var(--status-degraded-bg)] text-[var(--status-degraded-fg)] border-current/25" return "bg-[var(--status-offline-bg)] text-[var(--status-offline-fg)] border-current/25" } function Chip({ children, color }: { children: React.ReactNode; color?: string }) { return ( {children} ) } function fmtMs(ms: number) { if (!ms) return "—" if (ms < 1000) return `${ms}ms` return `${(ms / 1000).toFixed(1)}s` } interface OspfBfdDataGridProps { sessions: BfdSessionRow[] } function OspfBfdDataGrid({ sessions }: OspfBfdDataGridProps) { const columns = useMemo[]>( () => [ { id: "serverLabel", accessorKey: "serverLabel", header: ({ column }) => ( ), cell: ({ row }) => { const b = row.original return (
{b.serverLabel} {b.multihop && ( multihop )}
) }, meta: { headerTitle: "Роутер", headerClassName: DATA_GRID_CELL_PAD_FIRST, cellClassName: DATA_GRID_CELL_PAD_FIRST, }, }, { id: "iface", accessorKey: "iface", header: ({ column }) => , cell: ({ row }) => ( {row.original.iface || "—"} ), meta: { headerTitle: "Интерфейс", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "localAddr", accessorKey: "localAddr", header: ({ column }) => , cell: ({ row }) => ( {row.original.localAddr} ), meta: { headerTitle: "Локальный", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "remoteAddr", accessorKey: "remoteAddr", header: ({ column }) => , cell: ({ row }) => ( {row.original.remoteAddr} ), meta: { headerTitle: "Удалённый", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "state", accessorKey: "state", header: ({ column }) => , cell: ({ row }) => ( {row.original.state} ), meta: { headerTitle: "Состояние", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "uptime", accessorKey: "uptime", header: ({ column }) => , cell: ({ row }) => ( {row.original.uptime ?? "—"} ), meta: { headerTitle: "Uptime", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "intervals", header: () => Tx / Rx, enableSorting: false, cell: ({ row }) => { const b = row.original return ( {fmtMs(b.interval)} / {fmtMs(b.rxInterval)} ) }, meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "holdTime", accessorKey: "holdTime", header: ({ column }) => , cell: ({ row }) => ( {fmtMs(row.original.holdTime)} ), meta: { headerTitle: "Hold", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "multiplier", accessorKey: "multiplier", header: ({ column }) => , cell: ({ row }) => ( {row.original.multiplier} ), meta: { headerTitle: "Mult", headerClassName: DATA_GRID_CELL_PAD, cellClassName: cn(DATA_GRID_CELL_PAD, "text-center"), }, }, { id: "packetsRx", accessorKey: "packetsRx", header: ({ column }) => ( ), cell: ({ row }) => ( {row.original.packetsRx.toLocaleString()} ), meta: { headerTitle: "Пакеты Rx", headerClassName: cn(DATA_GRID_CELL_PAD, "text-right"), cellClassName: cn(DATA_GRID_CELL_PAD, "text-right"), }, }, { id: "packetsTx", accessorKey: "packetsTx", header: ({ column }) => ( ), cell: ({ row }) => ( {row.original.packetsTx.toLocaleString()} ), meta: { headerTitle: "Пакеты Tx", headerClassName: DATA_GRID_CELL_PAD, cellClassName: cn(DATA_GRID_CELL_PAD, "text-right"), }, }, { id: "stateChanges", accessorKey: "stateChanges", header: ({ column }) => ( ), cell: ({ row }) => ( {row.original.stateChanges} ), meta: { headerTitle: "Переходы", headerClassName: DATA_GRID_CELL_PAD_LAST, cellClassName: cn(DATA_GRID_CELL_PAD_LAST, "text-right"), }, }, ], [], ) const table = useReactTable({ data: sessions, columns, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getRowId: (row) => row.id, }) if (sessions.length === 0) { return ( } title="BFD-сессий не обнаружено" className="border-0 py-10" /> ) } return ( ) } export { OspfBfdDataGrid, type OspfBfdDataGridProps }