fix(ws): render_sidebar uses recipient's current enclave, not None (LC-337) #353

Merged
nrupard merged 1 commit from fix/lc-337-render-sidebar-enclave-aware into main 2026-06-18 18:12:07 +02:00
Owner

Problem

render_sidebar (server/src/routes/ws.rs) re-renders a user's whole sidebar as an OOB swap of #sidebar and is the WS render for ReadAllChanged (mark-all-read), DmMuteChanged, RoomNotifyPrefsChanged, and the self-targeted RoomMemberAdded/RoomMemberRemoved arms. It called load_sidebar(state, viewer, None) - the Home / DM-only shape.

#sidebar exists on every page, so that OOB swap is not self-limiting. For a recipient currently viewing an enclave it replaced the enclave sidebar (categories + enclave rooms) with the DM-only shape - blanking it until a manual refresh - and renamed the inner nav sidebar-nav-{eid} -> sidebar-nav, so a following render_enclave_sidebar_nav OOB fragment could no longer find its target and was dropped.

Reproduced live: viewing an enclave and clicking "Mark all as read" delivers a <aside id="sidebar" hx-swap-oob="outerHTML"> DM-only frame that blanks the sidebar. LC-331 fixed only the SidebarCategoriesChanged arm; the other render_sidebar callers were still clobbering enclave viewers.

Fix

Track each connection's current enclave from its enclave:{id} SubscribeTopic frame and pass it to render_sidebar.

  • Every enclave page sends a subscribe_topic enclave:{id} frame: the room page (room/page.html:6), enclave landing (enclave/page.html:11), and settings (enclave/settings.html:10).
  • There is no hx-boost, so each navigation is a full page load and a connection lives for exactly one page view - the tracked enclave is stable for the connection's lifetime, no staleness.
  • handle_socket gains a per-connection current_enclave: Arc<Mutex<Option<i64>>>; the SubscribeTopic handler sets it when the topic is enclave:{id}; render_sidebar takes it and renders the recipient's real context.

Rendering is already per-connection, so a user's Home tab renders the Home sidebar and an enclave tab renders that enclave's sidebar with the correct sidebar-nav-{eid} id.

Notes

  • The mutex guard is snapshotted to a local (cur_enclave, Copy) before the awaits so the send-task future stays Send.
  • No regression test added: render_sidebar is a WS send-task render with no integration harness. Verified manually + full suites.

Test

  • just check (clippy standalone + saas + desktop, fmt) clean.
  • just test and just test-saas both pass.

Closes LC-337.

## Problem `render_sidebar` (`server/src/routes/ws.rs`) re-renders a user's whole sidebar as an OOB swap of `#sidebar` and is the WS render for `ReadAllChanged` (mark-all-read), `DmMuteChanged`, `RoomNotifyPrefsChanged`, and the self-targeted `RoomMemberAdded`/`RoomMemberRemoved` arms. It called `load_sidebar(state, viewer, None)` - the Home / DM-only shape. `#sidebar` exists on every page, so that OOB swap is not self-limiting. For a recipient currently viewing an enclave it replaced the enclave sidebar (categories + enclave rooms) with the DM-only shape - blanking it until a manual refresh - and renamed the inner nav `sidebar-nav-{eid}` -> `sidebar-nav`, so a following `render_enclave_sidebar_nav` OOB fragment could no longer find its target and was dropped. Reproduced live: viewing an enclave and clicking "Mark all as read" delivers a `<aside id="sidebar" hx-swap-oob="outerHTML">` DM-only frame that blanks the sidebar. LC-331 fixed only the `SidebarCategoriesChanged` arm; the other `render_sidebar` callers were still clobbering enclave viewers. ## Fix Track each connection's current enclave from its `enclave:{id}` `SubscribeTopic` frame and pass it to `render_sidebar`. - Every enclave page sends a `subscribe_topic enclave:{id}` frame: the room page (`room/page.html:6`), enclave landing (`enclave/page.html:11`), and settings (`enclave/settings.html:10`). - There is no `hx-boost`, so each navigation is a full page load and a connection lives for exactly one page view - the tracked enclave is stable for the connection's lifetime, no staleness. - `handle_socket` gains a per-connection `current_enclave: Arc<Mutex<Option<i64>>>`; the `SubscribeTopic` handler sets it when the topic is `enclave:{id}`; `render_sidebar` takes it and renders the recipient's real context. Rendering is already per-connection, so a user's Home tab renders the Home sidebar and an enclave tab renders that enclave's sidebar with the correct `sidebar-nav-{eid}` id. ## Notes - The mutex guard is snapshotted to a local (`cur_enclave`, `Copy`) before the awaits so the send-task future stays `Send`. - No regression test added: `render_sidebar` is a WS send-task render with no integration harness. Verified manually + full suites. ## Test - `just check` (clippy standalone + saas + desktop, fmt) clean. - `just test` and `just test-saas` both pass. Closes LC-337.
fix(ws): render_sidebar uses the recipient's current enclave, not None
All checks were successful
check-secrets / Kingfisher (push) Successful in 4s
check-secrets / Nosey parker (push) Successful in 4s
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / Nosey parker (pull_request) Successful in 3s
check-secrets / Kingfisher (pull_request) Successful in 5s
Check / clippy + fmt + tests (pull_request) Successful in 2m19s
check-secrets / TruffleHog (pull_request) Successful in 4s
Create release / Create release from merged PR (pull_request) Has been skipped
0917b76d31
render_sidebar re-renders a user's whole sidebar as an OOB swap of #sidebar and backs several live events: ReadAllChanged (mark-all-read), DmMuteChanged, RoomNotifyPrefsChanged, and the self-targeted RoomMemberAdded/Removed arms. It called load_sidebar(state, viewer, None), producing the Home / DM-only shape. Because the #sidebar id exists on every page, that OOB swap is not self-limiting: for a recipient currently viewing an enclave it replaced the enclave sidebar (categories + enclave rooms) with the DM-only shape, blanking it until a manual refresh, and renamed the inner nav from sidebar-nav-{eid} to sidebar-nav so a following render_enclave_sidebar_nav fragment could no longer find its target. LC-331 fixed only the SidebarCategoriesChanged arm; these callers were left clobbering enclave viewers.

Track each connection's current enclave from its enclave:{id} SubscribeTopic frame (every enclave page - room, landing, settings - sends one; there is no hx-boost, so a connection lives for exactly one page view and the value is stable) and pass it to render_sidebar. Rendering is already per-connection, so each of a user's tabs renders for the page it is actually on: a Home tab gets the Home sidebar, an enclave tab gets that enclave's sidebar with the correct sidebar-nav-{eid} id.

#LC-337

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nrupard deleted branch fix/lc-337-render-sidebar-enclave-aware 2026-06-18 18:12:07 +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!353
No description provided.