"use client" import { useEffect, useMemo } from "react" import { DataGridContainer, DataGridScrollArea, DataGridTable, dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid" import { type ColumnDef, useTable, } from "@tanstack/react-table" import type { Server, VxlanTunnel } from "@/lib/data" import { Flag } from "@/components/flag" import { cn } from "@/lib/utils" import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" 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 { CodeXmlIcon, MoreHorizontalIcon, NetworkIcon, } from "lucide-react" interface VxlanDataGridProps { tunnels: VxlanTunnel[] servers: Server[] failedServerIds?: string[] onExport: (tunnel: VxlanTunnel) => void } function VxlanDataGrid({ tunnels, servers, onExport, failedServerIds = [] }: VxlanDataGridProps) { const serverMap = useMemo( () => new Map(servers.map((s) => [s.id, s])), [servers], ) const columns = useMemo[]>( () => [ { id: "name", size: 176, accessorKey: "name", header: ({ column }) => ( ), cell: ({ row }) => { const t = row.original return (

{t.name}

VTEP: {t.vtepIp}

) }, meta: { headerTitle: "Имя / VTEP", headerClassName: DATA_GRID_CELL_PAD_FIRST, cellClassName: DATA_GRID_CELL_PAD_FIRST, }, }, { id: "server", size: 128, accessorKey: "serverId", header: ({ column }) => , cell: ({ row }) => { const srv = serverMap.get(row.original.serverId) if (!srv) return — return (
{srv.name}
) }, meta: { headerTitle: "Сервер", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "vni", size: 80, accessorKey: "vni", header: ({ column }) => , cell: ({ row }) => {row.original.vni}, meta: { headerTitle: "VNI", headerClassName: DATA_GRID_CELL_PAD, cellClassName: cn(DATA_GRID_CELL_PAD, "text-center"), }, }, { id: "dstPort", size: 104, accessorKey: "dstPort", header: ({ column }) => , cell: ({ row }) => {row.original.dstPort}, meta: { headerTitle: "Port", headerClassName: DATA_GRID_CELL_PAD, cellClassName: cn(DATA_GRID_CELL_PAD, "text-center"), }, }, { id: "remoteVteps", size: 160, header: () => ( Remote ), enableSorting: false, cell: ({ row }) => ( {row.original.remoteVteps.length} ), meta: { headerTitle: "Remote", headerClassName: DATA_GRID_CELL_PAD, cellClassName: cn(DATA_GRID_CELL_PAD, "text-center"), }, }, { id: "arpProxy", size: 104, accessorKey: "arpProxy", header: () => ARP, enableSorting: false, cell: ({ row }) => ( ARP {row.original.arpProxy ? "✓" : "✗"} ), meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "macLearning", size: 128, accessorKey: "macLearning", header: () => MAC, enableSorting: false, cell: ({ row }) => ( MAC {row.original.macLearning ? "✓" : "✗"} ), meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "status", size: 104, accessorKey: "status", header: ({ column }) => , cell: ({ row }) => ( {failedServerIds.includes(row.original.serverId) ? "Неизвестно" : row.original.status === "up" ? "UP" : "DOWN"} ), meta: { headerTitle: "Статус", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "actions", header: () => Действия, cell: ({ row }) => { const tunnel = row.original return (
} /> onExport(tunnel)}> Экспорт .rsc
) }, enableSorting: false, size: 72, meta: { headerClassName: DATA_GRID_CELL_PAD_LAST, cellClassName: DATA_GRID_CELL_PAD_LAST, }, }, ], [onExport, serverMap, failedServerIds], ) const table = useTable({ features: dataGridFeatures, manualPagination: false, autoResetPageIndex: false, initialState: { pagination: { pageIndex: 0, pageSize: 50 }, columnPinning: { start: ["name"], end: [] } }, data: tunnels, columns, getRowId: (row) => JSON.stringify([row.serverId, row.id]), }) const { pageIndex, pageSize } = table.state.pagination useEffect(() => { const lastPage = Math.max(0, Math.ceil(tunnels.length / pageSize) - 1) if (pageIndex > lastPage) table.setPageIndex(lastPage) }, [tunnels.length, pageIndex, pageSize, table]) if (tunnels.length === 0) { return ( } title="Нет VXLAN-туннелей" description="Измените поиск или проверьте конфигурацию VXLAN в RouterOS" className="border-0 py-16" /> ) } return ( 50 || pageSize !== 50} tableLayout={{ dense: true, columnsPinnable: true }} tableClassNames={{ headerRow: "border-b border-border", bodyRow: cn("group/row", "[&[data-disabled=true]]:opacity-50"), }} > ) } export { VxlanDataGrid, type VxlanDataGridProps }