From 54b5093ac0302c7db9d51e1d7fe23570eae7cdb5 Mon Sep 17 00:00:00 2001 From: MrAlders0n <55921894+MrAlders0n@users.noreply.github.com> Date: Fri, 25 Sep 2026 11:37:57 -0400 Subject: [PATCH] fix(packets): fold summaries into the endpoints cell (#73) --- src/features/packets/PacketEndpoints.tsx | 21 +++++++++++++------ src/features/packets/PacketRow.tsx | 2 +- src/features/packets/PacketTableRow.tsx | 1 - .../features/packets/PacketEndpoints.test.tsx | 20 ++++++++++++++++++ .../features/packets/PacketTableRow.test.tsx | 6 +++--- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/features/packets/PacketEndpoints.tsx b/src/features/packets/PacketEndpoints.tsx index 33e5822..6978839 100644 --- a/src/features/packets/PacketEndpoints.tsx +++ b/src/features/packets/PacketEndpoints.tsx @@ -1,5 +1,5 @@ import type { PacketSummary } from "../../types/api"; -import type { PathConfidence } from "../../types/enums"; +import { PayloadType, type PathConfidence } from "../../types/enums"; import { buildPathSummary, type PathChip } from "./path-summary"; // Same three-state vocabulary PathData uses in the analyzer. @@ -21,7 +21,7 @@ function Chip({ chip }: { chip: PathChip }) { ); } return ( - + {chip.label} ); @@ -30,12 +30,21 @@ function Chip({ chip }: { chip: PathChip }) { const Na = () => n/a; // The packet's logical endpoints. beacon-server resolves these on the WS feed only and leaves them -// nil on the REST list, so scrollback rows read n/a — as do payload types with no addressed -// endpoint at all (GRP_TXT/GRP_DATA/TRACE). +// nil on the REST list; there the server's summary (advert name, trace tag, ack checksum) stands in. export function PacketEndpoints({ packet }: { packet: PacketSummary }) { const { source, destination } = buildPathSummary(packet); - // One n/a for the pair reads better than "n/a → n/a" on every historical row. - if (!source && !destination) return ; + + // An advert is the node announcing itself, so its name is the whole story — no destination. + if (packet.payloadType === PayloadType.ADVERT) { + const self = source ?? (packet.summary ? { kind: "node" as const, label: packet.summary, confidence: "high" as const } : null); + return self ? : ; + } + + if (!source && !destination) { + return packet.summary + ? {packet.summary} + : ; + } return ( diff --git a/src/features/packets/PacketRow.tsx b/src/features/packets/PacketRow.tsx index 2fcba53..0ee9491 100644 --- a/src/features/packets/PacketRow.tsx +++ b/src/features/packets/PacketRow.tsx @@ -54,7 +54,7 @@ export function PacketRow({ packet, expanded, isFresh, onToggle }: PacketRowProp - {packet.summary &&
{packet.summary}
} + {packet.summary &&
{packet.summary}
}
diff --git a/src/features/packets/PacketTableRow.tsx b/src/features/packets/PacketTableRow.tsx index 2033903..95a430f 100644 --- a/src/features/packets/PacketTableRow.tsx +++ b/src/features/packets/PacketTableRow.tsx @@ -58,7 +58,6 @@ export function PacketTableRow({ packet, expanded, isFresh, onToggle }: PacketTa {pathLength?.hopCount ?? na} {pathLength?.hashSize ?? na} - {packet.summary && {packet.summary}} diff --git a/tests/features/packets/PacketEndpoints.test.tsx b/tests/features/packets/PacketEndpoints.test.tsx index 037489c..49d0ef2 100644 --- a/tests/features/packets/PacketEndpoints.test.tsx +++ b/tests/features/packets/PacketEndpoints.test.tsx @@ -64,4 +64,24 @@ describe("PacketEndpoints", () => { }))} />); expect(screen.getByText("?")).toBeInTheDocument(); }); + + it("shows an advert as its single source node with no destination", () => { + const advert = { ...pkt(obs({ resolvedSource: { confidence: "high", nodes: [{ id: "s", publicKey: "aa", name: "Fuzz HQ" }] } })), payloadType: 4, summary: "Fuzz HQ" }; + render(); + expect(screen.getAllByText("Fuzz HQ")).toHaveLength(1); + expect(screen.queryByText("→")).not.toBeInTheDocument(); + expect(screen.queryByText("n/a")).not.toBeInTheDocument(); + }); + + it("falls back to the summary name for an advert with no resolved source", () => { + render(); + expect(screen.getByText("Fuzz HQ").className).toContain("text-green"); + expect(screen.queryByText("n/a")).not.toBeInTheDocument(); + }); + + it("replaces n/a with the summary when there are no endpoints", () => { + render(); + expect(screen.getByText("TRACE 2ca2a79c").className).toContain("text-text-muted"); + expect(screen.queryByText("n/a")).not.toBeInTheDocument(); + }); }); diff --git a/tests/features/packets/PacketTableRow.test.tsx b/tests/features/packets/PacketTableRow.test.tsx index 2e11485..6833393 100644 --- a/tests/features/packets/PacketTableRow.test.tsx +++ b/tests/features/packets/PacketTableRow.test.tsx @@ -23,9 +23,9 @@ const observer = ( }; describe("PacketTableRow", () => { - it("keeps endpoints visible alongside a payload summary", () => { - render( {}} />); - expect(screen.getByText("Packet summary")).toBeInTheDocument(); + it("prefers endpoints over a payload summary", () => { + render( {}} />); + expect(screen.queryByText("Packet summary")).not.toBeInTheDocument(); expect(screen.getByText("Source node")).toBeInTheDocument(); expect(screen.getByText("Destination node")).toBeInTheDocument(); });