feat(ui): per-room scoped search from the room header (LC-268) #312

Merged
longjacksonle merged 1 commit from feat/lc-268-per-room-search into main 2026-06-14 05:43:08 +02:00

What

Adds a "search this room" box to the room header (LC-268). Typing scopes the existing full-text search to the current room, so you can find a message in the room you are viewing without wading through global results. Hits are jump links (#msg-{id}) into the room, with the shared search.js combobox keyboard nav (Arrow/Enter/Esc).

How

  • routes::search: SearchQuery gains an optional room_id. When set it takes precedence over enclave scope: the caller's room access is gated with is_room_accessible (403 if they cannot see it), then the FTS is narrowed via search_messages' existing room_id_filter. The home-scope clause still enforces readability, so the filter only narrows - it cannot widen access. With no room_id, the sidebar global search behaves exactly as before. No new DB query.
  • partials/room_header.html: a compact data-lc-search input whose hx-get="/search?room_id={{ room.id }}" targets a small results popover below it, mirroring the sidebar search markup so search.js drives nav and Enter jumps to the hit.
  • Strings localized in en + es.

No new route, DB query, or env var. Not operator-visible.

Tests

routes_search_room: a room-A-scoped search returns A's hit and not room B's; searching a private room a non-admin cannot access 403s. just test and just test-saas pass.

Note

This branch also picks up a 2-line cargo fmt normalization of routes_reactions_authz.rs (the LC-266 react_body helper merged without a fmt pass since CI does not gate fmt); it just makes main fmt-clean again.

QA note

Server-gated and test-covered, so low-risk. Worth a quick manual check: open a room, type in the header search (results are from this room only, jump on click/Enter); confirm an empty query collapses the popover; confirm the sidebar global search still works unchanged.

## What Adds a "search this room" box to the room header (LC-268). Typing scopes the existing full-text search to the current room, so you can find a message in the room you are viewing without wading through global results. Hits are jump links (`#msg-{id}`) into the room, with the shared `search.js` combobox keyboard nav (Arrow/Enter/Esc). ## How - `routes::search`: `SearchQuery` gains an optional `room_id`. When set it takes precedence over enclave scope: the caller's room access is gated with `is_room_accessible` (403 if they cannot see it), then the FTS is narrowed via `search_messages`' existing `room_id_filter`. The home-scope clause still enforces readability, so the filter only narrows - it cannot widen access. With no `room_id`, the sidebar global search behaves exactly as before. No new DB query. - `partials/room_header.html`: a compact `data-lc-search` input whose `hx-get="/search?room_id={{ room.id }}"` targets a small results popover below it, mirroring the sidebar search markup so `search.js` drives nav and Enter jumps to the hit. - Strings localized in en + es. No new route, DB query, or env var. Not operator-visible. ## Tests `routes_search_room`: a room-A-scoped search returns A's hit and not room B's; searching a private room a non-admin cannot access 403s. `just test` and `just test-saas` pass. ## Note This branch also picks up a 2-line `cargo fmt` normalization of `routes_reactions_authz.rs` (the LC-266 `react_body` helper merged without a fmt pass since CI does not gate fmt); it just makes `main` fmt-clean again. ## QA note Server-gated and test-covered, so low-risk. Worth a quick manual check: open a room, type in the header search (results are from this room only, jump on click/Enter); confirm an empty query collapses the popover; confirm the sidebar global search still works unchanged.
feat(ui): per-room scoped search from the room header (LC-268)
All checks were successful
check-secrets / Nosey parker (push) Successful in 3s
check-secrets / TruffleHog (push) Successful in 5s
check-secrets / Kingfisher (push) Successful in 6s
check-secrets / TruffleHog (pull_request) Successful in 4s
Create release / Create release from merged PR (pull_request) Has been skipped
check-secrets / Kingfisher (pull_request) Successful in 6s
check-secrets / Nosey parker (pull_request) Successful in 6s
Check / clippy + fmt + tests (pull_request) Successful in 3m21s
dce7e883cd
Adds a "search this room" box to the room header. Typing scopes the existing full-text search to the current room, so you can find a message in the room you are viewing without wading through global results. Hits are jump links (#msg-{id}) into the room, with the shared search.js combobox keyboard nav.

The /search handler gains an optional room_id param. When set it takes precedence over enclave scope: the caller's room access is gated (403 if they cannot see the room), then the FTS is narrowed to that room via search_messages' existing room_id_filter. The home-scope clause still enforces readability, so the filter only narrows - it cannot widen access. With no room_id the behavior (sidebar global search) is unchanged. No new DB query.

The header input reuses the sidebar search markup (data-lc-search + results popover) so search.js drives Arrow/Enter/Esc. Strings localized in en + es. Tests assert a room-scoped search excludes other rooms' hits and that an inaccessible room 403s.

#LC-268
#LC-269

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/lc-268-per-room-search 2026-06-14 05:43:09 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!312
No description provided.