Add packet scope to inspection. Closes #256

This commit is contained in:
Jack Kingsman
2026-05-13 16:06:05 -07:00
parent a13b16b81c
commit f1eca53625
2 changed files with 46 additions and 1 deletions
@@ -166,6 +166,10 @@ function formatPathMode(hashSize: number | undefined, hopCount: number): string
return `${hopCount} hop${hopCount === 1 ? '' : 's'} · ${hashSize} byte hash${hashSize === 1 ? '' : 'es'}`;
}
function formatTransportCodes(codes: [number, number]): string {
return codes.map((c) => `0x${c.toString(16).padStart(4, '0')}`).join(', ');
}
function buildGroupTextResolutionCandidates(channels: Channel[]): GroupTextResolutionCandidate[] {
return channels.map((channel) => ({
key: channel.key,
@@ -647,7 +651,14 @@ export function RawPacketInspectionPanel({
) : null}
</section>
<section className="grid gap-2 sm:grid-cols-3 lg:grid-cols-1 xl:grid-cols-3">
<section
className={cn(
'grid gap-2 lg:grid-cols-1',
inspection.decoded?.transportCodes
? 'sm:grid-cols-2 xl:grid-cols-4'
: 'sm:grid-cols-3 xl:grid-cols-3'
)}
>
<CompactMetaCard
label="Packet"
primary={`${packet.data.length / 2} bytes · ${packetIsDecrypted ? 'Decrypted' : 'Encrypted'}`}
@@ -658,6 +669,13 @@ export function RawPacketInspectionPanel({
primary={`${inspection.routeTypeName} · ${inspection.payloadTypeName}`}
secondary={`${inspection.payloadVersionName} · ${formatPathMode(inspection.decoded?.pathHashSize, inspection.pathTokens.length)}`}
/>
{inspection.decoded?.transportCodes ? (
<CompactMetaCard
label="Scope"
primary="Regional"
secondary={formatTransportCodes(inspection.decoded.transportCodes)}
/>
) : null}
{(() => {
const sig = formatSignal(packet, signalOverride);
return (
@@ -39,6 +39,19 @@ const BOT_PACKET: RawPacket = {
decrypted_info: null,
};
// TransportFlood ACK: header 0C (route=0 TransportFlood, type=3 ACK, ver=0),
// transport codes 3412 7856 (LE: 0x1234, 0x5678), path_len 00, ACK checksum AABBCCDD
const SCOPED_PACKET: RawPacket = {
id: 2,
timestamp: 1_700_000_000,
data: '0C3412785600AABBCCDD',
decrypted: false,
payload_type: 'Ack',
rssi: -80,
snr: 3.0,
decrypted_info: null,
};
describe('RawPacketDetailModal', () => {
it('copies the full packet hex to the clipboard', async () => {
const writeText = vi.fn().mockResolvedValue(undefined);
@@ -77,4 +90,18 @@ describe('RawPacketDetailModal', () => {
fireEvent.mouseLeave(pathFieldBox as HTMLElement);
expect(pathRun.className).toBe(idleClassName);
});
it('shows scope card with transport codes for scoped packets', () => {
render(<RawPacketDetailModal packet={SCOPED_PACKET} channels={[]} onClose={vi.fn()} />);
expect(screen.getByText('Scope')).toBeInTheDocument();
expect(screen.getByText('Regional')).toBeInTheDocument();
expect(screen.getByText('0x1234, 0x5678')).toBeInTheDocument();
});
it('does not show scope card for non-transport packets', () => {
render(<RawPacketDetailModal packet={BOT_PACKET} channels={[BOT_CHANNEL]} onClose={vi.fn()} />);
expect(screen.queryByText('Scope')).not.toBeInTheDocument();
});
});