"use client" import { dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid" import { useMemo } from "react" import { type ColumnDef, useTable, } 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, } 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 { BgpSessionDetail } from "@/components/data-grids/bgp-session-detail" import type { BgpSessionRow, BgpState, BgpType } from "@/lib/bgp/types" import { BGP_AS_NAMES } from "@/lib/bgp/types" import { fmtBgpNum } from "@/lib/bgp/helpers" import { ChevronDownIcon, ChevronRightIcon, NetworkIcon } from "lucide-react" const STATE_STYLE: Record = { Unknown: { bg: "bg-muted", text: "text-muted-foreground", dot: "bg-muted-foreground", label: "Неизвестно" }, Established: { bg: "bg-emerald-500/10", text: "text-emerald-600 dark:text-emerald-400", dot: "bg-emerald-500", label: "Established", }, Active: { bg: "bg-amber-500/10", text: "text-amber-600 dark:text-amber-400", dot: "bg-amber-500", label: "Active", }, Idle: { bg: "bg-slate-500/10", text: "text-slate-500 dark:text-slate-400", dot: "bg-slate-500", label: "Idle", }, Connect: { bg: "bg-blue-500/10", text: "text-blue-600 dark:text-blue-400", dot: "bg-blue-500", label: "Connect", }, OpenSent: { bg: "bg-violet-500/10", text: "text-violet-600 dark:text-violet-400", dot: "bg-violet-500", label: "OpenSent", }, OpenConfirm: { bg: "bg-violet-500/10", text: "text-violet-600 dark:text-violet-400", dot: "bg-violet-500", label: "OpenConfirm", }, } const TYPE_STYLE: Record = { Unknown: { bg: "bg-muted", text: "text-muted-foreground" }, eBGP: { bg: "bg-blue-500/10", text: "text-blue-600 dark:text-blue-400" }, iBGP: { bg: "bg-purple-500/10", text: "text-purple-600 dark:text-purple-400" }, } function StateBadge({ state }: { state: BgpState }) { const s = STATE_STYLE[state] return ( {s.label} ) } function TypeBadge({ type }: { type: BgpType }) { const s = TYPE_STYLE[type] return ( {type === "Unknown" ? "Тип неизвестен" : type} ) } interface BgpSessionsDataGridProps { sessions: BgpSessionRow[] emptyTitle?: string selectedSessionId?: string | null onSelectSession?: (id: string | null) => void } function BgpSessionsDataGrid({ sessions, emptyTitle, selectedSessionId, onSelectSession }: BgpSessionsDataGridProps) { const columns = useMemo[]>( () => [ { id: "serverLabel", accessorKey: "serverLabel", header: ({ column }) => ( ), cell: ({ row }) => { const expanded = row.getIsExpanded() return (
{expanded ? ( ) : ( )} {row.original.serverLabel}
) }, meta: { headerTitle: "Роутер", headerClassName: DATA_GRID_CELL_PAD_FIRST, cellClassName: DATA_GRID_CELL_PAD_FIRST, expandedContent: (row: BgpSessionRow) => , }, }, { id: "peerIp", accessorKey: "peerIp", header: ({ column }) => , cell: ({ row }) => {row.original.peerIp}, meta: { headerTitle: "Peer IP", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "remoteAs", accessorKey: "remoteAs", header: ({ column }) => , cell: ({ row }) => { const as = row.original.remoteAs return (
{as === null ? "AS неизвестна" : "AS" + as} {as !== null && BGP_AS_NAMES[as] && ( {BGP_AS_NAMES[as]} )}
) }, meta: { headerTitle: "Remote AS", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "description", accessorKey: "description", header: ({ column }) => , cell: ({ row }) => ( {row.original.description} ), meta: { headerTitle: "Описание", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "type", accessorKey: "type", header: ({ column }) => , cell: ({ row }) => , meta: { headerTitle: "Тип", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "state", accessorKey: "state", header: ({ column }) => , cell: ({ row }) => , 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: "prefixesRx", accessorKey: "prefixesRx", header: ({ column }) => , cell: ({ row }) => { const n = row.original.prefixesRx return n !== null ? ( {fmtBgpNum(n)} ) : ( — ) }, meta: { headerTitle: "Prefixes ↓", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "prefixesTx", accessorKey: "prefixesTx", header: ({ column }) => , cell: ({ row }) => { const n = row.original.prefixesTx return n !== null ? ( {fmtBgpNum(n)} ) : ( — ) }, meta: { headerTitle: "Prefixes ↑", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, ], [], ) const table = useTable({ features: dataGridFeatures, manualPagination: true, data: sessions, columns, getRowId: (row) => row.id, getRowCanExpand: () => true, ...(onSelectSession ? { state: { expanded: selectedSessionId ? { [selectedSessionId]: true } : {} } } : {}), }) if (sessions.length === 0) { return ( } title={emptyTitle ?? "Нет BGP-сессий"} description="Измените фильтры или проверьте подключение к роутерам" className="border-0 py-10" /> ) } return ( onSelectSession ? onSelectSession(row.id === selectedSessionId ? null : row.id) : table.getRow(row.id).toggleExpanded()} /> ) } export { BgpSessionsDataGrid, type BgpSessionsDataGridProps }