Live wall: filter bar, discipline presets and text search (#235) #267

Merged
logan merged 2 commits from feat/235-filter-bar into main 2026-10-05 03:17:48 -04:00
Owner

Map filter bar, discipline presets and free-text search on the live wall.

What changed

  • lib/liveFilter.ts (new, pure): WallFilter + applyFilter over the incidents and calls the wall already loaded. An incident passes on type, severity floor, system/talkgroup, age window (last activity), tags, a preset rule, and q matched case-insensitively over title/location/summary and its loaded transcripts. A call passes when its incident passes; with no type/preset criterion, an unlinked call can also pass on its own fields.
  • Presets: Fire (fire + EMS assists heard on a fire channel; Weather Radar on), Storm (weather/wires/tree/flood/storm tags; Radar on), Traffic (accident type or MVA/crash tags; Traffic Events on). The layers go through #234's saved-view layer state; MapView is not edited.
  • components/live/FilterBar.tsx (new): one wrapping row under the wall bar with presets, search (debounced), type chips, severity floor, age, system/talkgroup selects (built from loaded data), the top tag chips, a "Filtered: N of M" label and Clear. Below md the less-used controls fold behind a "Filters" toggle. In kiosk mode it shows a read-only summary only when a filter is on.
  • LiveView.tsx: applies the filter once and feeds the result to MapView (pins, paths, rail), RegionPanel, TranscriptTicker, TimeScrubber bands, the wall cameras and the auto-tour. The KPIs count the filtered set and read "N of M active · filtered". Pipeline health stays unfiltered, so a filter never hides an outage. A drilled-into #inc= stays on the map even when it is filtered out, but the tour skips it.
  • liveWall.ts: f.* values keep literal commas so links stay readable.

Acceptance

  • "fire, moderate+, last 6h" is #f.age=6&f.sev=moderate&f.type=fire, one shareable link (Copy view link carries it).
  • The KPI bar and the filter row both say "filtered" with N of M. The rail inside MapView gets the filtered list, so its count follows. MapView.tsx is owned by #184-map this batch, so the rail header itself does not add the word "filtered"; the label sits right above the map.
  • Auto-tour only visits incidents that pass the filter.

Verification

  • tsc --noEmit: exit 0, run on a clean scratch copy.
  • c2-core pytest: 919 passed, 4 warnings. This PR has no backend change.
  • Ad-hoc sucrase-node smoke test of liveFilter against synthetic incidents: fire/moderate+/6h picks only the matching one, and the Fire preset includes an EMS incident heard on a "County Fire Dispatch" talkgroup. Storm, Traffic and q-over-transcript behave as described, and junk hash values parse as an empty filter. No JS test runner exists in the repo, so this is not committed.

Closes #235

🤖 Generated with Claude Code

Map filter bar, discipline presets and free-text search on the live wall. **What changed** - `lib/liveFilter.ts` (new, pure): `WallFilter` + `applyFilter` over the incidents and calls the wall already loaded. An incident passes on type, severity floor, system/talkgroup, age window (last activity), tags, a preset rule, and `q` matched case-insensitively over title/location/summary and its loaded transcripts. A call passes when its incident passes; with no type/preset criterion, an unlinked call can also pass on its own fields. - Presets: **Fire** (fire + EMS assists heard on a fire channel; Weather Radar on), **Storm** (weather/wires/tree/flood/storm tags; Radar on), **Traffic** (accident type or MVA/crash tags; Traffic Events on). The layers go through #234's saved-view layer state; MapView is not edited. - `components/live/FilterBar.tsx` (new): one wrapping row under the wall bar with presets, search (debounced), type chips, severity floor, age, system/talkgroup selects (built from loaded data), the top tag chips, a "Filtered: N of M" label and Clear. Below `md` the less-used controls fold behind a "Filters" toggle. In kiosk mode it shows a read-only summary only when a filter is on. - `LiveView.tsx`: applies the filter once and feeds the result to MapView (pins, paths, rail), RegionPanel, TranscriptTicker, TimeScrubber bands, the wall cameras and the auto-tour. The KPIs count the filtered set and read "N of M active · filtered". Pipeline health stays unfiltered, so a filter never hides an outage. A drilled-into `#inc=` stays on the map even when it is filtered out, but the tour skips it. - `liveWall.ts`: `f.*` values keep literal commas so links stay readable. **Acceptance** - "fire, moderate+, last 6h" is `#f.age=6&f.sev=moderate&f.type=fire`, one shareable link (Copy view link carries it). - The KPI bar and the filter row both say "filtered" with N of M. The rail inside MapView gets the filtered list, so its count follows. MapView.tsx is owned by #184-map this batch, so the rail header itself does not add the word "filtered"; the label sits right above the map. - Auto-tour only visits incidents that pass the filter. **Verification** - `tsc --noEmit`: exit 0, run on a clean scratch copy. - c2-core pytest: 919 passed, 4 warnings. This PR has no backend change. - Ad-hoc sucrase-node smoke test of liveFilter against synthetic incidents: fire/moderate+/6h picks only the matching one, and the Fire preset includes an EMS incident heard on a "County Fire Dispatch" talkgroup. Storm, Traffic and q-over-transcript behave as described, and junk hash values parse as an empty filter. No JS test runner exists in the repo, so this is not committed. Closes #235 🤖 Generated with [Claude Code](https://claude.com/claude-code)
logan added 1 commit 2026-10-05 03:11:34 -04:00
lib/liveFilter.ts (pure): WallFilter {types, sevFloor, systems, talkgroups,
ageH, tags, q, preset}, applyFilter over loaded incidents + calls, parse /
serialise to the f.* hash keys #234 reserved. Presets: Fire (fire + EMS
assists heard on a fire channel; Radar on), Storm (weather/wires/tree/flood
tags; Radar on), Traffic (accident / MVA tags; Traffic Events on).

components/live/FilterBar.tsx: one wrapping row under the wall bar; less-used
controls fold behind a toggle below md; read-only summary in kiosk.

LiveView applies the filter once and feeds the filtered lists to MapView
(pins, paths, rail), RegionPanel, TranscriptTicker, TimeScrubber and the
auto-tour; KPIs count the filtered set and say "filtered". Presets turn
layers on through the saved-view layer state, not a MapView edit. Pipeline
health stays unfiltered. liveWall.ts keeps commas literal in f.* values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
logan added 1 commit 2026-10-05 03:16:22 -04:00
- Storm/Traffic preset tag terms now match at the start of a word, so
  "tree" no longer pulls "street-racing"/"street-fight" into Storm mode.
- FilterBar search compared the trimmed hash q against the untrimmed
  typed text, so pausing after "main " reset the box to "main" and the
  next word ran on ("mainst"). Compare trimmed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
logan merged commit fdcedf175c into main 2026-10-05 03:17:48 -04:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: logan/server-26#267