Commit Graph

5 Commits

Author SHA1 Message Date
efiten f99c9c21d9 feat(live): node filter — show only traffic through a specific node (closes #771 M3) (#924)
Adds a node filter input to the live controls bar. When active, only
packets whose hop chain passes through the selected node(s) are
animated. A counter shows "Showing X of Y" so operators know traffic is
filtered, not absent.

## Changes
- `packetInvolvesFilterNode(pkt, filterKeys)`: pure filter function
using same prefix-matching logic as the favorites filter
- `setNodeFilter(keys)`: sets filter state, resets counters, persists to
localStorage
- `updateNodeFilterUI()`: updates counter + clear button visibility +
datalist autocomplete
- Filter input in controls bar (after Favorites toggle): text input +
datalist autocomplete + × clear button + counter div
- Filter wired into `renderPacketTree`: increments total/shown counters,
returns early when packet doesn't match
- URL hash sync: `?node=ABCD1234` — read on init, written on filter
change

## Tests
8 new unit tests covering filter logic, localStorage persistence, and
edge cases; 78 pass, 0 regressions.

Closes #771 (M3 of 3)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 23:53:08 -07:00
Kpa-clawbot 7e0b904d09 fix: refresh live feed relative timestamps every 10s (#709)
## Summary

Fixes #701 — Live feed timestamps showed stale relative times (e.g. "2s
ago" never updated to "5m ago").

## Root Cause

`formatLiveTimestampHtml()` was called once when each feed item was
created and never refreshed. The dedup path (when a duplicate hash moves
an item to the top) also didn't update the timestamp.

## Changes

### `public/live.js`
- **`data-ts` attribute on `.feed-time` spans**: All three feed item
creation paths (VCR replay, `addFeedItemDOM`, `addFeedItem`) now store
the packet timestamp as `data-ts` on the `.feed-time` span element
- **10-second refresh interval**: A `setInterval` queries all
`.feed-time[data-ts]` elements and re-renders their content via
`formatLiveTimestampHtml()`, keeping relative times accurate
- **Dedup path timestamp update**: When a duplicate hash observation
moves an existing feed item to the top, the `.feed-time` span is updated
with the new observation's timestamp
- **Cleanup**: The interval is cleared on page teardown alongside other
intervals

### `test-live.js`
- 3 new tests: formatting idempotency, numeric timestamp acceptance,
`data-ts` round-trip correctness

## Performance

- The refresh interval runs every 10s, iterating over at most 25
`.feed-time` DOM elements (feed is capped at 25 items via `while
(feed.children.length > 25)`). Negligible overhead.
- Uses `querySelectorAll` with attribute selector — O(n) where n ≤ 25.

## Testing

- All 3 new tests pass
- All pre-existing test suites pass (70 live.js tests, 62 packet-filter,
501 frontend-helpers)
- 8 pre-existing failures in `test-live.js` are unrelated
(`getParsedDecoded` missing from sandbox)

Co-authored-by: you <you@example.com>
2026-04-11 21:30:38 -07:00
Kpa-clawbot f3caf42be4 feat: show transport badge in live packet feed (#551)
## Summary

Show the transport badge ("T") in the live packet feed, matching the
packets table (#337).

## Changes

- Add `transportBadge(pkt.route_type)` to all 4 feed rendering paths in
`live.js`:
  - Grouped feed items (initial history load)
  - `addFeedItemDOM()` (VCR replay)
  - Dedup new feed items (live WebSocket updates)
  - Node detail panel recent packets list
- Uses existing `transportBadge()` from `app.js` and `.badge-transport`
CSS from `style.css`

## Testing

- 2 new source-level assertions in `test-live.js` verifying
`transportBadge()` calls exist
- All existing tests pass (67 passed in test-live.js, no new failures)

Fixes #338

Co-authored-by: you <you@example.com>
2026-04-03 21:09:02 -07:00
Kpa-clawbot 526ea8a1fc perf(live): chunk VCR replay packet processing to avoid UI freezes (#549)
## Summary

VCR replay functions (`vcrReplayFromTs`, `vcrRewind`,
`fetchNextReplayPage`) fetch up to 10K packets and process them all
synchronously on the main thread via `expandToBufferEntries`, causing
multi-second UI freezes — especially on mobile.

## Fix

- Added `expandToBufferEntriesAsync()` — processes packets in chunks of
200, yielding to the event loop via `setTimeout(0)` between chunks
- Updated all three VCR replay callers to use the async variant
- Kept the synchronous `expandToBufferEntries()` for backward
compatibility (tests, small datasets)
- Exposed `_liveExpandToBufferEntriesAsync` on window for test access

## Perf justification

- **Before:** 10K packets × ~2 observations = 20K+ objects created
synchronously, blocking the main thread for 1-3 seconds on mobile
- **After:** Same work split into chunks of 200 packets (~400 entries)
with event loop yields between chunks. Each chunk takes <5ms, keeping
the UI responsive (well under the 16ms frame budget)
- Chunk size of 200 is tunable via `VCR_CHUNK_SIZE`

## Tests

- Added regression test: sync expand correctness at scale (500 packets →
1000 entries)
- Added structural test: verifies `VCR_CHUNK_SIZE` exists and async
function yields via `setTimeout`
- All existing tests pass (`npm test`)

Fixes #395

---------

Co-authored-by: you <you@example.com>
2026-04-03 21:22:05 +00:00
Kpa-clawbot 698514e5e6 test: comprehensive live.js coverage (71 tests) (#489)
## Summary

Add comprehensive test coverage for `live.js` — the largest and most
complex frontend file (2500+ lines) covering animation modes, VCR
playback, WebSocket handling, audio integration, and the live map.

Part of #344 — live.js coverage.

## What's Tested (71 tests)

### Pure function tests via `vm.createContext`
- **`dbPacketToLive`** — DB packet → live format conversion, null
`decoded_json`, `payload_type_name` fallback, `created_at` timestamp
fallback
- **`expandToBufferEntries`** — observation expansion (1→N entries),
empty observations, multi-packet batches
- **`SEG_MAP`** — 7-segment LCD digit mapping completeness (all digits,
colon, space, VCR mode letters)
- **VCR state machine** — mode transitions (`LIVE`→`PAUSED`→`REPLAY`),
`frozenNow` lifecycle, speed cycling (1→2→4→8→1), pause idempotency
- **`getFavoritePubkeys`** — localStorage merging from
`meshcore-favorites` + `meshcore-my-nodes`, corrupt data handling, falsy
filtering
- **`packetInvolvesFavorite`** — sender pubKey matching, hop prefix
matching, missing decoded fields
- **`isNodeFavorited`** — basic favorite lookup, empty state
- **`formatLiveTimestampHtml`** — timestamp formatting with tooltip,
null input, numeric input, future warning icon
- **`resolveHopPositions`** — HopResolver integration, ghost hop
interpolation between known nodes
- **`bufferPacket`** — VCR buffer management, 2000-entry cap with
playhead adjustment, missed count in PAUSED mode

### Source-level safety checks (20 tests)
- Null guards: `renderPacketTree`, `animatePath`, `pulseNode`, `nextHop`
(all verified via source-level checks)
- Animation limit enforcement (`MAX_CONCURRENT_ANIMS`)
- Tab visibility optimization (skip animations when hidden, clear
propagation buffer on restore)
- WebSocket auto-reconnect
- `addNodeMarker` deduplication
- All toggle state persistence to localStorage (matrix, rain, realistic,
favorites, ghost hops)
- `clearNodeMarkers` resets HopResolver
- `startReplay` pre-aggregates by hash
- Orientation change retry delays
- `vcrRewind` deduplicates buffer entries by ID

## Changes
- `public/live.js` — expose 14 additional functions via `window._live*`
for testing (following existing pattern)
- `test-live.js` — new test file, 841 lines, 71 tests

## Constraints
- No new dependencies
- Tests run via `vm.createContext` against real code (not copies)
- No build step — vanilla JS

---------

Co-authored-by: you <you@example.com>
2026-04-02 17:16:03 -07:00