feat(traffic-flow): enhance flow analytics and IP handling
Docker images / prepare-release (push) Successful in 8s
Docker images / backend-test (push) Successful in 2m29s
Docker images / frontend-image (push) Successful in 3m20s
Docker images / updater-image (push) Successful in 51s
Docker images / backend-image (push) Successful in 2m40s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 13s
Docker images / prepare-release (push) Successful in 8s
Docker images / backend-test (push) Successful in 2m29s
Docker images / frontend-image (push) Successful in 3m20s
Docker images / updater-image (push) Successful in 51s
Docker images / backend-image (push) Successful in 2m40s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 13s
- Introduced `canonicalIp` function to standardize IP address formats across the application, improving consistency in flow processing. - Updated traffic flow analytics to utilize new endpoint resolution logic, enhancing accuracy in traffic classification. - Enhanced tests for traffic flow analytics and IP handling, ensuring comprehensive coverage for new functionalities. - Improved traffic flow destination resolution with additional test cases for various internet services, including Google and Fastly. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { useMemo } from "react"
|
||||
import { type ColumnDef, getCoreRowModel, useReactTable } 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,
|
||||
@@ -19,6 +20,40 @@ function formatBytes(n: number): string {
|
||||
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 (
|
||||
<span className="inline-flex text-muted-foreground" title="Download: интернет → клиент">
|
||||
<ArrowDownIcon className="size-3" />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
if (direction === "from_client") {
|
||||
return (
|
||||
<span className="inline-flex text-muted-foreground" title="Upload: клиент → интернет">
|
||||
<ArrowUpIcon className="size-3" />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<span className="inline-flex text-muted-foreground" title="Транзит">
|
||||
<MinusIcon className="size-3" />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
function TrafficFlowsDataGrid({
|
||||
rows,
|
||||
emptyHint,
|
||||
@@ -30,9 +65,16 @@ function TrafficFlowsDataGrid({
|
||||
() => [
|
||||
{
|
||||
id: "client",
|
||||
accessorFn: (r) => r.clientName ?? "",
|
||||
accessorFn: (r) => r.clientName || r.clientIp || "",
|
||||
header: () => <span className="text-xs font-medium text-muted-foreground">Клиент</span>,
|
||||
cell: ({ row }) => <span className="text-xs">{row.original.clientName || "—"}</span>,
|
||||
cell: ({ row }) => (
|
||||
<span className="flex min-w-0 flex-col gap-0.5">
|
||||
<span className="text-xs truncate">{row.original.clientName || "—"}</span>
|
||||
{row.original.clientIp ? (
|
||||
<span className="font-mono text-[10px] text-muted-foreground truncate">{row.original.clientIp}</span>
|
||||
) : null}
|
||||
</span>
|
||||
),
|
||||
meta: { headerClassName: DATA_GRID_CELL_PAD_FIRST, cellClassName: DATA_GRID_CELL_PAD_FIRST },
|
||||
},
|
||||
{
|
||||
@@ -43,27 +85,26 @@ function TrafficFlowsDataGrid({
|
||||
meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD },
|
||||
},
|
||||
{
|
||||
id: "src",
|
||||
accessorKey: "src",
|
||||
header: () => <span className="text-xs font-medium text-muted-foreground">Src</span>,
|
||||
cell: ({ row }) => (
|
||||
<span className="font-mono text-xs">
|
||||
{row.original.src}
|
||||
{row.original.srcPort ? `:${row.original.srcPort}` : ""}
|
||||
</span>
|
||||
),
|
||||
id: "direction",
|
||||
accessorFn: (r) => r.direction ?? "",
|
||||
header: () => <span className="text-xs font-medium text-muted-foreground">Напр.</span>,
|
||||
cell: ({ row }) => <FlowDirectionMark direction={row.original.direction} />,
|
||||
meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD },
|
||||
},
|
||||
{
|
||||
id: "dst",
|
||||
accessorKey: "dst",
|
||||
header: () => <span className="text-xs font-medium text-muted-foreground">Dst</span>,
|
||||
cell: ({ row }) => (
|
||||
<span className="font-mono text-xs">
|
||||
{row.original.dst}
|
||||
{row.original.dstPort ? `:${row.original.dstPort}` : ""}
|
||||
</span>
|
||||
),
|
||||
id: "internet",
|
||||
accessorFn: (r) => r.internetPeer ?? r.dst,
|
||||
header: () => <span className="text-xs font-medium text-muted-foreground">Интернет</span>,
|
||||
cell: ({ row }) => {
|
||||
const r = row.original
|
||||
const label = formatEndpoint(r.internetPeer, r.internetPeerPort)
|
||||
const tuple = packetTuple(r)
|
||||
return (
|
||||
<span className="font-mono text-xs truncate max-w-[220px]" title={tuple}>
|
||||
{label}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD },
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user