"use client" import { useMemo, type ReactNode } from "react" import { type ColumnDef, getCoreRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table" import type { WireGuardPeer } from "@/lib/data" import { Flag } from "@/components/flag" import { cn } from "@/lib/utils" import { Button } from "@/components/ui/button" 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 { fmtBytes, truncKey } from "@/components/data-grids/wireguard-peers-detail" import { ArrowDownIcon, ArrowUpIcon, CodeXmlIcon, KeyRoundIcon, Trash2Icon, UsersIcon, } from "lucide-react" export interface WgPeerRow extends WireGuardPeer { id: string ifaceId: string ifaceName: string serverId: string serverName: string serverCountry: string } interface WireguardPeersGridProps { peers: WgPeerRow[] compactServer?: boolean emptyAction?: ReactNode onDeletePeer?: (row: WgPeerRow) => void onExportPeer?: (row: WgPeerRow) => void } function WireguardPeersGrid({ peers, compactServer = false, emptyAction, onDeletePeer, onExportPeer, }: WireguardPeersGridProps) { const columns = useMemo[]>(() => { const cols: ColumnDef[] = [ { id: "peer", accessorKey: "publicKey", header: ({ column }) => ( ), cell: ({ row }) => { const peer = row.original return (
{peer.name || truncKey(peer.publicKey)}
) }, meta: { headerTitle: "Пир", headerClassName: DATA_GRID_CELL_PAD_FIRST, cellClassName: DATA_GRID_CELL_PAD_FIRST, }, }, { id: "iface", accessorKey: "ifaceName", header: ({ column }) => , cell: ({ row }) => ( {row.original.ifaceName} ), meta: { headerTitle: "Интерфейс", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, ] if (!compactServer) { cols.push({ id: "server", accessorKey: "serverName", header: ({ column }) => , cell: ({ row }) => (
{row.original.serverName}
), meta: { headerTitle: "Сервер", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }) } cols.push( { id: "allowedIps", accessorFn: (row) => row.allowedIps.join(", "), header: ({ column }) => , cell: ({ row }) => ( {row.original.allowedIps.join(", ") || "—"} ), meta: { headerTitle: "Allowed IPs", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "handshake", accessorKey: "latestHandshake", header: ({ column }) => , cell: ({ row }) => ( {row.original.latestHandshake ?? "нет рукопожатия"} ), meta: { headerTitle: "Handshake", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "transfer", header: () => ( RX / TX ), enableSorting: false, cell: ({ row }) => (
{fmtBytes(row.original.transferRx)} {fmtBytes(row.original.transferTx)}
), meta: { headerTitle: "RX / TX", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "endpoint", accessorKey: "endpoint", header: ({ column }) => , cell: ({ row }) => ( {row.original.endpoint ?? "—"} ), meta: { headerTitle: "Endpoint", headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD, }, }, { id: "actions", header: () => Действия, enableSorting: false, size: 72, cell: ({ row }) => { const peer = row.original return (
{onExportPeer ? ( ) : null} {onDeletePeer ? ( ) : null}
) }, meta: { headerClassName: DATA_GRID_CELL_PAD_LAST, cellClassName: DATA_GRID_CELL_PAD_LAST, }, }, ) return cols }, [compactServer, onDeletePeer, onExportPeer]) const table = useReactTable({ data: peers, columns, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getRowId: (row) => row.id, }) if (peers.length === 0) { return ( } title="Нет пиров" description="Добавьте пира к интерфейсу или сбросьте поиск" action={emptyAction} className="border-0 py-16" /> ) } return ( ) } export { WireguardPeersGrid, type WireguardPeersGridProps }