feat(ui): per-room mark-as-read from the sidebar (LC-258) #307

Merged
longjacksonle merged 1 commit from feat/lc-258-per-room-mark-read into main 2026-06-14 03:55:52 +02:00

What

Adds a per-room companion to the LC-250 "Mark all as read" (LC-258). Each room/DM sidebar row that carries an unread or mention badge now shows a hover-revealed check button that clears just that one conversation without opening it - useful for dismissing a noisy channel you don't want to read right now. Every other unread conversation is left untouched.

How

  • server/src/routes/read_all.rs: new POST /room/{id}/read handler. It advances the read watermark to the room's latest message and clears its unread mentions - the same set_last_read + mark_mentions_read_for_room that opening the room runs, factored into a shared mark_room_read helper that the bulk /read-all loop now also calls. Access-gated by the same is_room_accessible check that guards page reads (403 on a room the viewer cannot see). Reuses the LC-250 ReadAllChanged broadcast to refresh the viewer's other tabs; returns the re-rendered sidebar fragment to the acting tab.
  • server/templates/partials/sidebar_room_row.html + sidebar_peer_row.html: a hover-revealed ✓ button before the star form, rendered only when the row has an unread/mention badge (room.unread > 0 || room.mentions > 0; peer.unread > 0 for DMs).
  • server/locales/{en,es}/partials.ftl: sidebar-mark-room-read.

No new WS event (reused ReadAllChanged), no new DB table, no env var. Not operator-visible.

Tests

routes_read_all.rs gains read_one_room_clears_only_that_room (clears the target room + its mention while a separate DM stays unread) and read_room_forbidden_when_inaccessible (non-member -> 403). just test and just test-saas pass.

QA note

Server-gated and covered by tests, so low-risk. The only client behavior is the htmx swap + live cross-tab refresh: worth a quick manual check that the button appears on hover only for unread rows, clears that row's badges, leaves others alone, and updates a second open tab live.

## What Adds a per-room companion to the LC-250 "Mark all as read" (LC-258). Each room/DM sidebar row that carries an unread or mention badge now shows a hover-revealed check button that clears just that one conversation without opening it - useful for dismissing a noisy channel you don't want to read right now. Every other unread conversation is left untouched. ## How - `server/src/routes/read_all.rs`: new `POST /room/{id}/read` handler. It advances the read watermark to the room's latest message and clears its unread mentions - the same `set_last_read` + `mark_mentions_read_for_room` that opening the room runs, factored into a shared `mark_room_read` helper that the bulk `/read-all` loop now also calls. Access-gated by the same `is_room_accessible` check that guards page reads (403 on a room the viewer cannot see). Reuses the LC-250 `ReadAllChanged` broadcast to refresh the viewer's other tabs; returns the re-rendered sidebar fragment to the acting tab. - `server/templates/partials/sidebar_room_row.html` + `sidebar_peer_row.html`: a hover-revealed `✓` button before the star form, rendered only when the row has an unread/mention badge (`room.unread > 0 || room.mentions > 0`; `peer.unread > 0` for DMs). - `server/locales/{en,es}/partials.ftl`: `sidebar-mark-room-read`. No new WS event (reused `ReadAllChanged`), no new DB table, no env var. Not operator-visible. ## Tests `routes_read_all.rs` gains `read_one_room_clears_only_that_room` (clears the target room + its mention while a separate DM stays unread) and `read_room_forbidden_when_inaccessible` (non-member -> 403). `just test` and `just test-saas` pass. ## QA note Server-gated and covered by tests, so low-risk. The only client behavior is the htmx swap + live cross-tab refresh: worth a quick manual check that the button appears on hover only for unread rows, clears that row's badges, leaves others alone, and updates a second open tab live.
feat(ui): per-room mark-as-read from the sidebar (LC-258)
All checks were successful
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / Nosey parker (push) Successful in 5s
check-secrets / Kingfisher (push) Successful in 6s
check-secrets / Kingfisher (pull_request) Successful in 5s
check-secrets / Nosey parker (pull_request) Successful in 5s
check-secrets / TruffleHog (pull_request) Successful in 6s
Check / clippy + fmt + tests (pull_request) Successful in 2m13s
Create release / Create release from merged PR (pull_request) Has been skipped
397239ecdc
Adds a per-room companion to the LC-250 "Mark all as read". Each room/DM sidebar row that carries an unread or mention badge now shows a hover-revealed check button that clears just that conversation without opening it; every other unread conversation is left untouched.

POST /room/{id}/read advances the read watermark to the room's latest message and clears its unread mentions (the same set_last_read + mark_mentions_read_for_room that opening the room runs, factored into a shared mark_room_read helper the bulk /read-all loop now also calls). It is access-gated by the same is_room_accessible check that guards page reads, so a viewer cannot mark a room they cannot see (403). It reuses the LC-250 ReadAllChanged broadcast to refresh the viewer's other tabs and returns the re-rendered sidebar to the acting tab.

The row button is hover-revealed (mirroring the star affordance) and only renders when there is an unread/mention badge to clear. Strings localized in en + es. Tests cover clear-one-leaves-others and the access-gate 403.

#LC-258
#LC-259

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/lc-258-per-room-mark-read 2026-06-14 03:55:53 +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!307
No description provided.