Skip to content

Persist marker-color filter selection in the session drawer (localStorage and/or user preference) #20

@goyamegh

Description

@goyamegh

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:

  1. Open the drawer, click the color filter, select e.g. just green and yellow.
  2. Verify the drawer now shows only sessions in those two buckets.
  3. Reload the page.
  4. Observe: the filter resets to "all colors". Drawer shows everything again.

Proposed fix

Two-tier approach, mirroring how selectedMarkerColor already works:

  1. 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.
  2. 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

  • After applying a color filter and reloading the page, the same filter is still active.
  • Clearing the filter ("All colors") and reloading also persists — empty / cleared state is sticky too.
  • Persistence survives service-worker updates and supervisor restarts.
  • Stored value validates against sessionMarkerColors; unknown ids are dropped, not crashed on.
  • No regression to selectedMarkerColor persistence (which already works).

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions