"use client" import { dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid" import { useMemo } from "react" import { type ColumnDef, useTable } from "@tanstack/react-table" import type { FlowTalkerDto } from "@mmapp/contracts/traffic-flow" import { ArrowDownIcon, ArrowUpIcon, MinusIcon } from "lucide-react" 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 formatEndpoint(ip: string | undefined, port: number | undefined): string { const host = String(ip ?? "").trim() if (!host) return "—" return port ? `${host}:${port}` : host } function packetTuple(row: FlowTalkerDto): string { const src = formatEndpoint(row.src, row.srcPort) const dst = formatEndpoint(row.dst, row.dstPort) return `${src} → ${dst}` } function FlowDirectionMark({ direction }: { direction: FlowTalkerDto["direction"] }) { if (direction === "to_client") { return ( ) } if (direction === "from_client") { return ( ) } return ( ) } function TrafficFlowsDataGrid({ rows, emptyHint, }: { rows: FlowTalkerDto[] emptyHint?: string }) { const columns = useMemo[]>( () => [ { id: "client", accessorFn: (r) => r.clientName || r.clientIp || "", header: () => Клиент, cell: ({ row }) => ( {row.original.clientName || "—"} {row.original.clientIp ? ( {row.original.clientIp} ) : null} ), 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: "direction", accessorFn: (r) => r.direction ?? "", header: () => Напр., cell: ({ row }) => , meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "internet", accessorFn: (r) => r.internetPeer ?? r.dst, header: () => Интернет, cell: ({ row }) => { const r = row.original const label = formatEndpoint(r.internetPeer, r.internetPeerPort) const tuple = packetTuple(r) return ( {label} ) }, 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 = useTable({ features: dataGridFeatures, manualPagination: true, manualSorting: true, data: rows, columns, getRowId: (row, i) => `${row.serverId}-${row.src}-${row.dst}-${row.proto}-${row.srcPort}-${row.dstPort}-${i}`, }) return ( ) } export { TrafficFlowsDataGrid }