Summary
The session drawer has two color-related pieces of state, but only one of them is persisted today. The other — the marker-color filter in the drawer header — resets to "all colors" on every page reload, so the chosen filter is silently thrown away.
Persist the filter selection: at minimum to localStorage (per-device), and ideally as user preference in the existing session-UI-state store (so it syncs alongside pinned sessions, markers, and the selected paint color).
Why this matters
Once you've moved to using marker colors as buckets (e.g. green for active feature work, yellow for "waiting on review", red for "important / pinned escalations") the filter is the primary lens through which the drawer becomes useful. Having to reapply that filter every time the tab is reloaded — or after a service-worker update, or after the supervisor restarts — is an immediate context-loss tax.
It also conflicts with users' mental model: every other piece of drawer state (pinned sessions, marker assignments, the paint color, collapsed folders, drawer width) is sticky. The filter being the only ephemeral one is a surprising inconsistency.
Current behaviour
src/sessions/sessionDrawer.ts (origin/main):
state.selectedMarkerColor — the paint color (which color a click on a session's marker button applies). ✅ Already persisted server-side via pi-web-session-ui-state.json and round-tripped through persistSessionUiState({ selectedMarkerColor }).
allowedMarkerColors — the filter set (which color buckets are visible). ❌ Initialised as new Set<SessionMarkerColorId>() on every load (~line 125) and only mutated in the in-memory menu handlers (~lines 738–760). Never written to localStorage, never sent to the server, never restored on reload.
Repro:
- Open the drawer, click the color filter, select e.g. just
green and yellow.
- Verify the drawer now shows only sessions in those two buckets.
- Reload the page.
- Observe: the filter resets to "all colors". Drawer shows everything again.
Proposed fix
Two-tier approach, mirroring how selectedMarkerColor already works:
-
Tier 1 — localStorage (per-device, easy):
- On every change in
allowedMarkerColors, serialise to a localStorage key like pi-web-allowed-marker-colors.
- On startup, hydrate from that key before the first
renderSessionList call.
- Validate against the known
sessionMarkerColors set so a stale color id from a future schema doesn't break rendering.
-
Tier 2 — server-side preference (cross-device, ideal):
- Add an optional
allowedMarkerColors: SessionMarkerColorId[] field to SessionUiState in server/sessionUiState.ts (next to pinnedSessions, sessionMarkers, selectedMarkerColor).
- Round-trip via the existing
persistSessionUiState / applySessionUiStatePatch plumbing.
- Treat empty array / missing field as "all colors" (current default), so existing files migrate transparently.
Tier 1 alone is enough to fix the papercut. Tier 2 is a polish step once the maintainer is happy with the schema change.
Edge cases
- Unknown color id in stored value (e.g. older schema) — ignore that entry, keep the rest.
- All-colors selection — represented by an empty set today; keep that as the canonical "no restriction" form so we don't have to enumerate every color when nothing is filtered.
- Filter persisted across users on shared machines — same trade-off as
selectedMarkerColor already makes; not a new concern.
Acceptance criteria
Related
Summary
The session drawer has two color-related pieces of state, but only one of them is persisted today. The other — the marker-color filter in the drawer header — resets to "all colors" on every page reload, so the chosen filter is silently thrown away.
Persist the filter selection: at minimum to
localStorage(per-device), and ideally as user preference in the existing session-UI-state store (so it syncs alongside pinned sessions, markers, and the selected paint color).Why this matters
Once you've moved to using marker colors as buckets (e.g.
greenfor active feature work,yellowfor "waiting on review",redfor "important / pinned escalations") the filter is the primary lens through which the drawer becomes useful. Having to reapply that filter every time the tab is reloaded — or after a service-worker update, or after the supervisor restarts — is an immediate context-loss tax.It also conflicts with users' mental model: every other piece of drawer state (pinned sessions, marker assignments, the paint color, collapsed folders, drawer width) is sticky. The filter being the only ephemeral one is a surprising inconsistency.
Current behaviour
src/sessions/sessionDrawer.ts(origin/main):state.selectedMarkerColor— the paint color (which color a click on a session's marker button applies). ✅ Already persisted server-side viapi-web-session-ui-state.jsonand round-tripped throughpersistSessionUiState({ selectedMarkerColor }).allowedMarkerColors— the filter set (which color buckets are visible). ❌ Initialised asnew Set<SessionMarkerColorId>()on every load (~line 125) and only mutated in the in-memory menu handlers (~lines 738–760). Never written tolocalStorage, never sent to the server, never restored on reload.Repro:
greenandyellow.Proposed fix
Two-tier approach, mirroring how
selectedMarkerColoralready works:Tier 1 —
localStorage(per-device, easy):allowedMarkerColors, serialise to a localStorage key likepi-web-allowed-marker-colors.renderSessionListcall.sessionMarkerColorsset so a stale color id from a future schema doesn't break rendering.Tier 2 — server-side preference (cross-device, ideal):
allowedMarkerColors: SessionMarkerColorId[]field toSessionUiStateinserver/sessionUiState.ts(next topinnedSessions,sessionMarkers,selectedMarkerColor).persistSessionUiState/applySessionUiStatePatchplumbing.Tier 1 alone is enough to fix the papercut. Tier 2 is a polish step once the maintainer is happy with the schema change.
Edge cases
selectedMarkerColoralready makes; not a new concern.Acceptance criteria
sessionMarkerColors; unknown ids are dropped, not crashed on.selectedMarkerColorpersistence (which already works).Related
28a6bc3/c797c58/a6d0c76.