mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-25 19:20:16 +00:00
6a75907802
Spliced from contributor PRs #1497 (Thanatos-Z) and #1513 (AlexeyDsov), which both added the ability to filter the sidebar to sessions with no project_id assigned. Lands here as a focused PR with the best of both: ## Synthesis decisions - **Sentinel constant approach** (from #1497, Thanatos-Z): single state variable (`_activeProject` set to `NO_PROJECT_FILTER` sentinel) instead of a parallel `_showNoneProject` boolean. No two-state-machine ambiguity, no risk of "All" + "Unassigned" both reading active. Clicking "All" automatically clears the unassigned filter because there is only one variable to reset. - **Conditional rendering** (from #1497): the chip only appears when there are actually unassigned sessions to filter to (`hasUnprojected`). Common case where every session is organized → chip stays hidden, uncluttered chip bar. The project-bar itself also renders when there are unassigned sessions (was previously gated on `_allProjects.length`). - **Dashed-border visual treatment** (from #1497): `.project-chip.no-project {border-style:dashed;}` distinguishes the chip from real project chips so it reads as a meta-filter ("things without a project") rather than another project. Subtle but present. - **"Unassigned" label** (new): clearer than #1497s "No project" (which reads like a status filter) or #1513s "None" (which is ambiguous — none of what?). Matches the conventional file-manager / task-tracker mental model: "things not yet assigned to a category." Tooltip elaborates: "Show conversations not yet assigned to a project." - **Branched empty-state copy**: when the Unassigned filter is active and the result is empty, show "No unassigned sessions." instead of the generic "No sessions in this project yet." ## Tests 7 new tests in tests/test_sidebar_unassigned_filter.py pin every contract: sentinel constant declared; filter logic uses !s.project_id when sentinel is active; chip only renders when hasUnprojected; chip label and click handler; visual treatment (dashed border + .no-project class); empty-state copy branches on the active filter; All chip handler clears _activeProject to null (would catch a regression if a parallel _showNoneProject boolean is ever reintroduced). Local full suite: 3929 → 3936 passing (+7). Live verified at port 8789 with seeded data (5 projects + 73 unassigned sessions in active profile): chip appears between "All" and project chips when unassigned sessions exist; click cycles correctly; clicking a real project hides the Unassigned chip from active state; clicking "All" deactivates everything; dashed border present per getComputedStyle. Co-authored-by: Thanatos-Z <thanatos-z@users.noreply.github.com> Co-authored-by: Alexey Denisov <AlexeyDsov@users.noreply.github.com>