"use client" import { useMemo } from "react" import { type ColumnDef, getCoreRowModel, useReactTable } from "@tanstack/react-table" import type { FlowTalkerDto } from "@mmapp/contracts/traffic-flow" 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 { fmtRate } from "@/lib/fmt-rate" import { cn } from "@/lib/utils" function formatBytes(n: number): string { if (n >= 1_000_000_000) return `${(n / 1_000_000_000).toFixed(2)} ГБ` if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)} МБ` if (n >= 1000) return `${(n / 1000).toFixed(1)} КБ` return `${n} Б` } function TrafficFlowsDataGrid({ rows, emptyHint, }: { rows: FlowTalkerDto[] emptyHint?: string }) { const columns = useMemo[]>( () => [ { id: "client", accessorFn: (r) => r.clientName ?? "", header: () => Клиент, cell: ({ row }) => {row.original.clientName || "—"}, meta: { headerClassName: DATA_GRID_CELL_PAD_FIRST, cellClassName: DATA_GRID_CELL_PAD_FIRST }, }, { id: "server", accessorKey: "serverName", header: () => JH, cell: ({ row }) => {row.original.serverName}, meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "src", accessorKey: "src", header: () => Src, cell: ({ row }) => ( {row.original.src} {row.original.srcPort ? `:${row.original.srcPort}` : ""} ), meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "dst", accessorKey: "dst", header: () => Dst, cell: ({ row }) => ( {row.original.dst} {row.original.dstPort ? `:${row.original.dstPort}` : ""} ), meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "app", accessorFn: (r) => r.application ?? r.protoName, header: () => App, cell: ({ row }) => ( {row.original.application ?? row.original.protoName} {row.original.category || row.original.service ? ( {[row.original.category, row.original.service].filter(Boolean).join(" · ")} ) : null} ), meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "proto", accessorKey: "protoName", header: () => Proto, cell: ({ row }) => {row.original.protoName}, meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "rate", accessorFn: (r) => r.bps, header: () => Скорость, cell: ({ row }) => {fmtRate(row.original.bps / 1_000_000)}, meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "bytes", accessorKey: "bytes", header: () => Байты, cell: ({ row }) => {formatBytes(row.original.bytes)}, meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "en", accessorFn: (r) => r.enName ?? "", header: () => EN, cell: ({ row }) => {row.original.enName || "—"}, meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "plane", accessorFn: (r) => r.plane ?? "", header: () => Плоскость, cell: ({ row }) => {row.original.plane || "—"}, meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "iface", accessorKey: "inIface", header: () => Iface, cell: ({ row }) => {row.original.inIface || "—"}, meta: { headerClassName: DATA_GRID_CELL_PAD_LAST, cellClassName: cn(DATA_GRID_CELL_PAD_LAST) }, }, ], [], ) const table = useReactTable({ data: rows, columns, getCoreRowModel: getCoreRowModel(), getRowId: (row, i) => `${row.serverId}-${row.src}-${row.dst}-${row.proto}-${row.srcPort}-${row.dstPort}-${i}`, }) return ( ) } export { TrafficFlowsDataGrid }