mirror of
https://github.com/MeshCore-Beacon/beacon-web.git
synced 2026-10-24 09:12:40 +00:00
fix(packets): fold summaries into the endpoints cell (#73)
This commit is contained in:
1 parent
9cd2e8f6db
commit
54b5093ac0
5 files changed
+39
-11
No files matched your search
@@ -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 (
|
||||
<span className={`font-mono text-[10px] px-1.5 py-px rounded-sm truncate ${CONFIDENCE_CLASSES[chip.confidence]}`}>
|
||||
<span className={`font-mono text-[10px] px-1.5 py-px rounded-sm truncate ${CONFIDENCE_CLASSES[chip.confidence]}`} title={chip.label}>
|
||||
{chip.label}
|
||||
</span>
|
||||
);
|
||||
@@ -30,12 +30,21 @@ function Chip({ chip }: { chip: PathChip }) {
|
||||
const Na = () => <span className="text-text-dim">n/a</span>;
|
||||
|
||||
// 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 <Na />;
|
||||
|
||||
// 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 ? <Chip chip={self} /> : <Na />;
|
||||
}
|
||||
|
||||
if (!source && !destination) {
|
||||
return packet.summary
|
||||
? <span className="block truncate font-mono text-[10px] text-text-muted tracking-wider" title={packet.summary}>{packet.summary}</span>
|
||||
: <Na />;
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="flex items-center gap-x-1 min-w-0">
|
||||
|
||||
@@ -54,7 +54,7 @@ export function PacketRow({ packet, expanded, isFresh, onToggle }: PacketRowProp
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
{packet.summary && <div className="mt-1 truncate text-[11px] text-text-bright" title={packet.summary}>{packet.summary}</div>}
|
||||
{packet.summary && <div className="mt-1 truncate font-mono text-[10px] text-text-muted tracking-wider" title={packet.summary}>{packet.summary}</div>}
|
||||
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-1 mt-1 text-[11px] text-text-dim">
|
||||
<span className="font-mono text-[11px] text-text-muted uppercase tracking-wider bg-text-muted/8 px-1.5 py-px rounded-sm">
|
||||
|
||||
@@ -58,7 +58,6 @@ export function PacketTableRow({ packet, expanded, isFresh, onToggle }: PacketTa
|
||||
<span className="font-mono text-text-muted">{pathLength?.hopCount ?? na}</span>
|
||||
<span className="font-mono text-text-muted">{pathLength?.hashSize ?? na}</span>
|
||||
<span className="min-w-0 overflow-hidden">
|
||||
{packet.summary && <span className="block truncate text-text-bright" title={packet.summary}>{packet.summary}</span>}
|
||||
<PacketEndpoints packet={packet} />
|
||||
</span>
|
||||
<span className="font-mono font-bold text-primary tracking-wider">
|
||||
|
||||
@@ -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(<PacketEndpoints packet={advert} />);
|
||||
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(<PacketEndpoints packet={{ ...pkt(obs()), payloadType: 4, summary: "Fuzz HQ" }} />);
|
||||
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(<PacketEndpoints packet={{ ...pkt(obs()), payloadType: 9, summary: "TRACE 2ca2a79c" }} />);
|
||||
expect(screen.getByText("TRACE 2ca2a79c").className).toContain("text-text-muted");
|
||||
expect(screen.queryByText("n/a")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -23,9 +23,9 @@ const observer = (
|
||||
};
|
||||
|
||||
describe("PacketTableRow", () => {
|
||||
it("keeps endpoints visible alongside a payload summary", () => {
|
||||
render(<PacketTableRow packet={pkt({ summary: "Packet summary", latestObserver: observer({ resolvedSource: node("Source node"), resolvedDestination: node("Destination node") }) })} expanded={false} onToggle={() => {}} />);
|
||||
expect(screen.getByText("Packet summary")).toBeInTheDocument();
|
||||
it("prefers endpoints over a payload summary", () => {
|
||||
render(<PacketTableRow packet={pkt({ payloadType: 2, summary: "Packet summary", latestObserver: observer({ resolvedSource: node("Source node"), resolvedDestination: node("Destination node") }) })} expanded={false} onToggle={() => {}} />);
|
||||
expect(screen.queryByText("Packet summary")).not.toBeInTheDocument();
|
||||
expect(screen.getByText("Source node")).toBeInTheDocument();
|
||||
expect(screen.getByText("Destination node")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user