"use client" import { dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid" import { useMemo, useEffect } from "react" import { type ColumnDef, useTable, } from "@tanstack/react-table" import { cn } from "@/lib/utils" import { Badge } from "@/components/reui/badge" 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 { Button } from "@/components/ui/button" 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_DOT: Record = { Unknown: "bg-muted-foreground", Established: "bg-success", Active: "bg-warning", Idle: "bg-muted-foreground", Connect: "bg-info", OpenSent: "bg-info", OpenConfirm: "bg-info", } function StateBadge({ state }: { state: BgpState }) { return } function TypeBadge({ type }: { type: BgpType }) { 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 (
{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, }, }, ], [onSelectSession], ) const table = useTable({ features: dataGridFeatures, manualPagination: false, autoResetPageIndex: false, initialState: { pagination: { pageIndex: 0, pageSize: 50 } }, data: sessions, columns, getRowId: (row) => row.id, getRowCanExpand: () => true, ...(onSelectSession ? { state: { expanded: selectedSessionId ? { [selectedSessionId]: true } : {} } } : {}), }) const {pageIndex,pageSize}=table.state.pagination const sorting=table.state.sorting useEffect(()=>{ const last=Math.max(0,Math.ceil(sessions.length/pageSize)-1) if(pageIndex>last)table.setPageIndex(last) },[sessions.length,pageSize,pageIndex,table]) const setPageIndex = table.setPageIndex const selectedIndex = selectedSessionId ? table.getPrePaginatedRowModel().rows.findIndex(row => row.id === selectedSessionId) : -1 useEffect(() => { if (selectedIndex >= 0) setPageIndex(Math.floor(selectedIndex / pageSize)) }, [selectedSessionId, selectedIndex, pageSize, sorting, setPageIndex]) if (sessions.length === 0) { return ( } title={emptyTitle ?? "Нет BGP-сессий"} description="Измените фильтры или проверьте подключение к роутерам" className="border-0 py-10" /> ) } return ( 50 || pageSize!==50} onRowClick={(row) => onSelectSession ? onSelectSession(row.id === selectedSessionId ? null : row.id) : table.getRow(row.id).toggleExpanded()} /> ) } export { BgpSessionsDataGrid, type BgpSessionsDataGridProps }