feat(sidebar): add workspace sections with drag & drop reordering

Merged
JI
8mo ago
+3548-284

Demo

Sections

https://www.youtube.com/watch?v=qzNTkqexMSw

Multi-Select & Batch Move

https://www.youtube.com/shorts/HZz8ifI8mJc

Summary

  • Add workspace sections: user-created groups within a project sidebar for organizing workspaces
  • Support full drag & drop: reorder workspaces within sections, move between sections, and reorder sections themselves
  • Multi-select workspaces with Cmd+click (toggle) and Shift+click (range), then drag or context-menu move as a batch
  • New workspace_sections table in local SQLite DB with Drizzle migration

Why / Context

As the number of workspaces per project grows, the flat list becomes hard to manage. Sections let users group related workspaces (e.g., by feature, sprint, or status) with collapsible headers and drag-and-drop reordering.

How It Works

Data layer:

  • New workspace_sections table (id, projectId, name, tabOrder, isCollapsed)
  • workspaces.sectionId FK (nullable, onDelete: set null) — ungrouped workspaces remain at the top
  • 7 new tRPC mutations: create/rename/delete section, toggle collapse, reorder sections, reorder workspaces within section, move workspace to section
  • moveWorkspacesToSection batch mutation for moving multiple workspaces at once (single inArray UPDATE)

UI layer:

  • WorkspaceSection component: collapsible header with context menu (rename, delete), section-level DnD via react-dnd
  • WorkspaceList extracted as shared list renderer for both ungrouped and sectioned workspaces
  • useSectionDropZone hook: native drag event handling for cross-section workspace moves with 600ms auto-expand on collapsed sections
  • active-drag-item Zustand store: bridges react-dnd drag state with native drop zone handlers
  • workspace-selection Zustand store: tracks multi-select state (Cmd+click to toggle, Shift+click to range-select)
  • MultiDragPreview custom drag layer showing "{N} workspaces" badge during multi-drag
  • "Move to Section" context menu on workspace items (batch-aware when multiple are selected)
  • getAllGrouped query now returns sections nested under each project

Manual QA Checklist

Section CRUD

  • Right-click project header → "New Section" creates a section
  • Right-click section header → "Rename Section" works
  • Double-click section header enters rename mode
  • Right-click section header → "Delete Section" removes it (workspaces return to ungrouped)
  • Section collapse/expand toggles persist after app restart

Multi-Select

  • Cmd+click toggles individual workspace selection (highlighted with ring)
  • Shift+click selects a range of workspaces (across sections within same project)
  • Cmd+click on a workspace in a different project resets selection to that project
  • Escape clears selection
  • Clicking empty sidebar space clears selection
  • Plain click navigates and clears selection

Drag & Drop — Workspaces

  • Drag workspace within a section to reorder
  • Drag workspace from ungrouped area into a section
  • Drag workspace from one section to another
  • Drag workspace out of a section to ungrouped area
  • Hovering over collapsed section auto-expands it after ~600ms
  • Multi-select then drag moves all selected workspaces to the target section
  • Multi-drag shows "{N} workspaces" badge and dims selected items

Drag & Drop — Sections

  • Drag section header to reorder sections within a project
  • Section reorder persists after app restart

Context Menu

  • Right-click workspace → "Move to Section" submenu shows all sections
  • Moving via context menu works correctly
  • Right-click with multi-selection → "Move to Section" moves all selected workspaces

Edge Cases

  • Empty sections render correctly
  • Sidebar collapsed mode still shows workspaces (sections hidden)
  • Keyboard shortcuts (Cmd+1-9) still work across sections

Testing

  • bun run typecheck — passes (pre-existing @ai-sdk/openai error on upstream, unrelated)
  • bun run lint:fix — passes

Known Limitations

  • No search/filter within sections
  • Section names are not validated for uniqueness within a project
  • Reorder operations update all tabOrder values in a loop (fine for typical section/workspace counts, not optimized for hundreds)

Follow-ups

  • Drag workspace to create a new section (auto-group)
  • Section color/icon customization
  • Persist section collapsed state per-device sync