feat(desktop): filter and sort projects in the dashboard sidebar

Merged
AV
3mo ago
+736-23

Summary

  • Adds a sort mode for sidebar projects — Manual (existing drag order, default), Date created, Last updated — persisted per-user in v2UserPreferences and switchable from a new radio dropdown in the PROJECTS header.
  • Adds an inline filter: a VscListFilter icon in the PROJECTS header expands into a text input; case-insensitive substring match over project, workspace, and section names.

Why / Context

The project list was ordered solely by manual drag (tabOrder), with no way to find a project/workspace by name or surface recently active work. Inspired by PostHog Code's sidebar (sort by created/updated + searchable switcher).

How It Works

  • Sorting/filtering are applied as derived memos in DashboardSidebar — the data hook (useDashboardSidebarData) and the persisted tabOrder remain untouched, so switching back to Manual restores the hand-arranged order exactly.
  • "Last updated" sorts by the most recently updated workspace in each project (including inside sections), not the project's own updatedAt — the host only bumps project updatedAt on metadata patches (e.g. rename), so workspace timestamps are the real activity signal.
  • The filter helper returns derived project/section objects with isCollapsed: false so matches are auto-expanded and non-matching siblings pruned; persisted collapse state is never written. In the default state (manual + empty query) the original array references pass through, preserving existing memo stability.
  • Drag-to-reorder is disabled (useSortable({ disabled }) + drag-start/end guards) while a non-manual sort or filter is active, so a sorted/pruned order can never be persisted into tabOrder.
  • Filter state is ephemeral useState; it auto-clears when the sidebar collapses to icon-only (the input is hidden there, and an invisible filter would silently hide projects). Shortcut labels (⌘1–⌘9) are computed from the sorted-but-unfiltered list so they stay stable while typing.

Manual QA Checklist

Sort

  • Switching Manual → Date created → Last updated reorders projects; drag handles are inert in non-manual modes
  • Sort mode persists after app restart
  • Switching back to Manual restores the original drag order; dragging works again
  • Touching a workspace raises its project in "Last updated"

Filter

  • Typing a workspace-name match auto-expands its project/section and prunes non-matching siblings
  • A project-name match keeps all its children
  • Garbage query shows the "No projects match" row; Esc clears and restores collapse state and DnD
  • Expanding the filter while the PROJECTS list is collapsed expands the list
  • Collapsing the sidebar to icon-only with an active filter shows all projects again
  • ⌘1–⌘9 target the same workspaces while a filter is typed

Testing

  • bun run typecheck
  • bun run lint
  • bun test src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/utils — 11 new tests for the sort/filter helpers

Design Decisions

  • Sort in the component, not the data hook: sort is a view preference with one consumer; keeping useDashboardSidebarData on tabOrder preserves its referential-stability machinery and the optimistic drag path.
  • Derived expansion instead of a forceExpanded prop: avoids threading a prop through 3+ components and guarantees persisted collapse state is never mutated by filtering.
  • No branch-name matching: v2 workspace names are branch-derived; matching hidden text would surface rows whose visible label doesn't contain the query.

https://claude.ai/code/session_01MycxWhiezTmQAbvPR4tcYW


Open in Stage

Summary by cubic

Adds sorting and inline filtering to Projects in the dashboard sidebar so you can quickly find work and organize lists. “Last updated” uses recent workspace activity and the chosen sort persists per user.

  • New Features

    • Sort menu in the PROJECTS header: Manual (default), Last updated, Date created; preference saved in v2UserPreferences. Switching back to Manual restores drag order. Uses a list-filter icon and a dim “Sort by” label with checkmarks.
    • Inline filter with a magnifier; case-insensitive match on project, section, and workspace names. Matches auto-expand, non-matching siblings are hidden, and a “No projects match” message appears when empty. Esc clears, and the filter auto-clears when the sidebar collapses.
    • Dragging is gated to protect ordering: project drag is disabled while a non-manual sort or a filter is active; workspace/section drag is disabled while a filter is active so pruned lists can’t write a bad tabOrder. ⌘1–⌘9 shortcuts remain stable while typing.
  • Bug Fixes

    • Clicking items in the sort menu or Add Project menu no longer toggles the Projects collapse; dropdown events are stopped from bubbling.
    • Filter clear button is keyboard-operable and doesn’t blur the input.
    • Filtering preserves object identity when items don’t change, keeping memoized rows stable and avoiding flicker.
    • Use the theme’s destructive color for failed automation statuses for better contrast across themes.

Summary by CodeRabbit

  • New Features
    • Added dashboard sidebar sorting controls (manual, created, recent activity) with your selection saved for future sessions.
    • Added an inline project filter that searches projects, workspaces, and sections; matching items auto-expand, and a “No projects match …” message appears when nothing matches.
  • Bug Fixes
    • Improved header interactions so filter/sort controls don’t unintentionally collapse the sidebar.
    • Disabled drag-and-drop reordering while filtering is active or when sorting isn’t set to manual.
  • Tests
    • Added coverage for sorting (including tie-breaking) and filtering behavior.