"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 }