feat(realtime): live sidebar room list on enclave room add/remove (LC-174) #219

Merged
nrupard merged 1 commit from feat/lc-174-live-sidebar-rooms into main 2026-05-26 18:42:25 +02:00
Owner

Closes LC-174. Continuation of LC-170. EnclaveRoom{Added,Removed} already updated the /enclave/{id} landing room list (#lc-enclave-rooms) for landing viewers, but a member sitting in one of the enclave's rooms saw a newly-added public room in their sidebar only after a reload.

Approach: enclave-keyed sidebar nav

The scrollable sidebar nav body is extracted into partials/sidebar_nav.html (shared by partials/sidebar.html and the live fragment). The <nav> wrapper now carries id="sidebar-nav-{enclave_id}" when viewing an enclave (plain sidebar-nav otherwise). On EnclaveRoom{Added,Removed} the WS send task additionally renders ws/sidebar_nav_live.html per recipient via load_sidebar(viewer, Some(enclave_id)) and OOB-swaps #sidebar-nav-{enclave_id}.

The enclave-keyed id is the crux of correctness: htmx applies the swap only on a connection whose current page is that enclave (its landing, settings, or a room in it). A connection on Home, on a different enclave, or a stale topic subscriber (a user who left the enclave's pages but whose hub subscription has not been cleaned up - see LC-176) all have a different nav id and silently drop the swap. So this does not depend on per-connection page tracking, nor on LC-176 landing first. Per-recipient rendering via load_sidebar keeps unread / mention / active-room state correct.

Delivery to room viewers

room/page.html now adds data-lc-live-topic="enclave:{eid}" alongside its existing data-lc-live-room when the room belongs to an enclave (live.js subscribes both from the one element). Landing / settings pages already subscribe (LC-170/172). The EnclaveRoom arm emits both fragments in one frame - the landing #lc-enclave-rooms list and the #sidebar-nav-{eid} swap - and each connection applies whichever id its page has.

Verification

just test and just test-saas both green (106 test result: ok each, zero failures); cargo clippy / cargo fmt clean. Regression test (routes_enclave_nav::room_page_subscribes_to_enclave_topic_and_keys_sidebar_nav) asserts a room page in an enclave subscribes to the enclave topic and carries the enclave-keyed sidebar-nav id. The nav extraction into partials/sidebar_nav.html is markup-preserving (verified by the existing sidebar-rendering tests still passing).

Closes LC-174. Continuation of LC-170. `EnclaveRoom{Added,Removed}` already updated the `/enclave/{id}` landing room list (`#lc-enclave-rooms`) for landing viewers, but a member sitting in one of the enclave's rooms saw a newly-added public room in their **sidebar** only after a reload. ## Approach: enclave-keyed sidebar nav The scrollable sidebar nav body is extracted into `partials/sidebar_nav.html` (shared by `partials/sidebar.html` and the live fragment). The `<nav>` wrapper now carries `id="sidebar-nav-{enclave_id}"` when viewing an enclave (plain `sidebar-nav` otherwise). On `EnclaveRoom{Added,Removed}` the WS send task additionally renders `ws/sidebar_nav_live.html` per recipient via `load_sidebar(viewer, Some(enclave_id))` and OOB-swaps `#sidebar-nav-{enclave_id}`. The enclave-keyed id is the crux of correctness: htmx applies the swap only on a connection whose current page is that enclave (its landing, settings, or a room in it). A connection on Home, on a **different** enclave, or a **stale topic subscriber** (a user who left the enclave's pages but whose hub subscription has not been cleaned up - see LC-176) all have a different nav id and silently drop the swap. So this does not depend on per-connection page tracking, nor on LC-176 landing first. Per-recipient rendering via `load_sidebar` keeps unread / mention / active-room state correct. ## Delivery to room viewers `room/page.html` now adds `data-lc-live-topic="enclave:{eid}"` alongside its existing `data-lc-live-room` when the room belongs to an enclave (live.js subscribes both from the one element). Landing / settings pages already subscribe (LC-170/172). The `EnclaveRoom` arm emits both fragments in one frame - the landing `#lc-enclave-rooms` list and the `#sidebar-nav-{eid}` swap - and each connection applies whichever id its page has. ## Verification `just test` and `just test-saas` both green (106 `test result: ok` each, zero failures); `cargo clippy` / `cargo fmt` clean. Regression test (`routes_enclave_nav::room_page_subscribes_to_enclave_topic_and_keys_sidebar_nav`) asserts a room page in an enclave subscribes to the enclave topic and carries the enclave-keyed sidebar-nav id. The nav extraction into `partials/sidebar_nav.html` is markup-preserving (verified by the existing sidebar-rendering tests still passing).
feat(realtime): live sidebar room list on enclave room add/remove (LC-174)
All checks were successful
check-secrets / Nosey parker (push) Successful in 3s
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / Kingfisher (push) Successful in 5s
check-secrets / Nosey parker (pull_request) Successful in 4s
check-secrets / TruffleHog (pull_request) Successful in 9s
check-secrets / Kingfisher (pull_request) Successful in 11s
Check / clippy + fmt + tests (pull_request) Successful in 3m12s
Create release / Create release from merged PR (pull_request) Has been skipped
dddc6f365c
Continuation of LC-170. EnclaveRoom{Added,Removed} already updated the /enclave/{id} landing room list (#lc-enclave-rooms) for landing viewers, but a member sitting in one of the enclave's rooms saw a newly-added public room in their sidebar only after a reload.

Approach: an enclave-keyed sidebar nav. The scrollable nav body is extracted into partials/sidebar_nav.html (shared by the sidebar and the live fragment); the <nav> wrapper carries id="sidebar-nav-{enclave_id}" when viewing an enclave (plain "sidebar-nav" otherwise). On EnclaveRoom{Added,Removed} the WS send task now ALSO renders ws/sidebar_nav_live.html per recipient via load_sidebar(viewer, Some(enclave_id)) and OOB-swaps #sidebar-nav-{enclave_id}.

The enclave-keyed id is the crux: htmx applies the swap only on a connection whose current page is that enclave (its landing, settings, or a room in it); a connection on Home, on a different enclave, or a stale topic subscriber (a user who left the enclave's pages but whose hub subscription has not been cleaned up yet - see LC-176) all have a different nav id and silently drop the swap. So correctness does not depend on per-connection page tracking or on LC-176 landing first. Rendering per recipient via load_sidebar keeps unread / mention / active-room state correct.

To make room-page viewers actually receive the event, room/page.html now adds data-lc-live-topic="enclave:{eid}" alongside its existing data-lc-live-room when the room belongs to an enclave (live.js subscribes both from the one element). Landing/settings pages already subscribe (LC-170/172).

The EnclaveRoom arm emits both fragments in one frame: the landing #lc-enclave-rooms list and the #sidebar-nav-{eid} swap; each connection applies whichever id its page has.

Regression test: a room page in an enclave subscribes to the enclave topic and carries the enclave-keyed sidebar-nav id.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
nrupard deleted branch feat/lc-174-live-sidebar-rooms 2026-05-26 18:42:25 +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!219
No description provided.