From c67f3347ce47463dde0faff14b6f00d9f2db5b7f Mon Sep 17 00:00:00 2001 From: Kpa-clawbot Date: Sat, 2 May 2026 09:55:09 -0700 Subject: [PATCH] fix(ui): add GRP_DATA (type 6) to filter dropdown + color tables (#965) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Bug Packet type 6 (`PAYLOAD_TYPE_GRP_DATA` per `firmware/src/Packet.h:25`) was missing from three frontend lookup tables: - `public/app.js:7` — `PAYLOAD_COLORS` had no entry for 6 → badge color fell back to `unknown` (grey) - `public/packets.js:29` — `TYPE_NAMES` (used by the Packets page type-filter dropdown) had no entry for 6 → "Group Data" missing from the menu - `public/roles.js:17,24` — `TYPE_COLORS` and `TYPE_BADGE_MAP` had no `GRP_DATA` entry → no dedicated CSS class The packet detail page already handled it (via `PAYLOAD_TYPES` in `app.js:6` which had `6: 'Group Data'`) so individual GRP_DATA packets render correctly. The gap was only in the filter UI + badge styling. ## Fix Add the missing entry in each table. 4 lines across 3 files. - `app.js`: add `6: 'grp-data'` to `PAYLOAD_COLORS` - `packets.js`: add `6:'Group Data'` to `TYPE_NAMES` - `roles.js`: add `GRP_DATA: '#8b5cf6'` to `TYPE_COLORS` and `GRP_DATA: 'grp-data'` to `TYPE_BADGE_MAP` Color choice `#8b5cf6` (violet) — distinct from GRP_TXT's blue but visually adjacent so operators read them as related types. ## Verification (rule 18 + 19) Built server locally, served the JS files, grepped the rendered output: ``` $ curl -s http://localhost:13900/packets.js | grep TYPE_NAMES const TYPE_NAMES = { ... 5:'Channel Msg', 6:'Group Data', 7:'Anon Req' ... }; $ curl -s http://localhost:13900/app.js | grep PAYLOAD_TYPES const PAYLOAD_TYPES = { ... 5: 'Channel Msg', 6: 'Group Data', 7: 'Anon Req' ... }; $ curl -s http://localhost:13900/roles.js | grep GRP_DATA ADVERT: '#22c55e', GRP_TXT: '#3b82f6', GRP_DATA: '#8b5cf6', ... ADVERT: 'advert', GRP_TXT: 'grp-txt', GRP_DATA: 'grp-data', ... ``` Frontend tests pass: `test-packets.js` 82/82, `test-hash-color.js` 32/32. ## Out of scope Consolidating the duplicated PAYLOAD_TYPES / TYPE_NAMES tables into a single source of truth is a separate cleanup. Two parallel name maps continues to be a footgun (this is the second time a new type's been added to one but not the other). Co-authored-by: Kpa-clawbot --- public/app.js | 2 +- public/packets.js | 2 +- public/roles.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/app.js b/public/app.js index 58c2f25a..1b3e4aac 100644 --- a/public/app.js +++ b/public/app.js @@ -4,7 +4,7 @@ // --- Route/Payload name maps --- const ROUTE_TYPES = { 0: 'TRANSPORT_FLOOD', 1: 'FLOOD', 2: 'DIRECT', 3: 'TRANSPORT_DIRECT' }; const PAYLOAD_TYPES = { 0: 'Request', 1: 'Response', 2: 'Direct Msg', 3: 'ACK', 4: 'Advert', 5: 'Channel Msg', 6: 'Group Data', 7: 'Anon Req', 8: 'Path', 9: 'Trace', 10: 'Multipart', 11: 'Control', 15: 'Raw Custom' }; -const PAYLOAD_COLORS = { 0: 'req', 1: 'response', 2: 'txt-msg', 3: 'ack', 4: 'advert', 5: 'grp-txt', 7: 'anon-req', 8: 'path', 9: 'trace' }; +const PAYLOAD_COLORS = { 0: 'req', 1: 'response', 2: 'txt-msg', 3: 'ack', 4: 'advert', 5: 'grp-txt', 6: 'grp-data', 7: 'anon-req', 8: 'path', 9: 'trace' }; function routeTypeName(n) { return ROUTE_TYPES[n] || 'UNKNOWN'; } function payloadTypeName(n) { return PAYLOAD_TYPES[n] || 'UNKNOWN'; } diff --git a/public/packets.js b/public/packets.js index a9203f56..c98975f9 100644 --- a/public/packets.js +++ b/public/packets.js @@ -26,7 +26,7 @@ let observers = []; let observerMap = new Map(); // id → observer for O(1) lookups (#383) let regionMap = {}; - const TYPE_NAMES = { 0:'Request', 1:'Response', 2:'Direct Msg', 3:'ACK', 4:'Advert', 5:'Channel Msg', 7:'Anon Req', 8:'Path', 9:'Trace', 11:'Control' }; + const TYPE_NAMES = { 0:'Request', 1:'Response', 2:'Direct Msg', 3:'ACK', 4:'Advert', 5:'Channel Msg', 6:'Group Data', 7:'Anon Req', 8:'Path', 9:'Trace', 11:'Control' }; function typeName(t) { return TYPE_NAMES[t] ?? `Type ${t}`; } const isMobile = window.innerWidth <= 1024; const PACKET_LIMIT = isMobile ? 1000 : 50000; diff --git a/public/roles.js b/public/roles.js index 27937988..ae657cb7 100644 --- a/public/roles.js +++ b/public/roles.js @@ -15,14 +15,14 @@ }; window.TYPE_COLORS = { - ADVERT: '#22c55e', GRP_TXT: '#3b82f6', TXT_MSG: '#f59e0b', ACK: '#6b7280', + ADVERT: '#22c55e', GRP_TXT: '#3b82f6', GRP_DATA: '#8b5cf6', TXT_MSG: '#f59e0b', ACK: '#6b7280', REQUEST: '#a855f7', RESPONSE: '#06b6d4', TRACE: '#ec4899', PATH: '#14b8a6', ANON_REQ: '#f43f5e', UNKNOWN: '#6b7280' }; // Badge CSS class name mapping const TYPE_BADGE_MAP = { - ADVERT: 'advert', GRP_TXT: 'grp-txt', TXT_MSG: 'txt-msg', ACK: 'ack', + ADVERT: 'advert', GRP_TXT: 'grp-txt', GRP_DATA: 'grp-data', TXT_MSG: 'txt-msg', ACK: 'ack', REQUEST: 'req', RESPONSE: 'response', TRACE: 'trace', PATH: 'path', ANON_REQ: 'anon-req', UNKNOWN: 'unknown' };