Skip to content

feat(sidebar): drag-and-drop reordering of threads within a project#3069

Open
TheIcarusWings wants to merge 2 commits into
pingdotgg:mainfrom
TheIcarusWings:t3code/thread-drag-reorder
Open

feat(sidebar): drag-and-drop reordering of threads within a project#3069
TheIcarusWings wants to merge 2 commits into
pingdotgg:mainfrom
TheIcarusWings:t3code/thread-drag-reorder

Conversation

@TheIcarusWings

@TheIcarusWings TheIcarusWings commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

What

Adds drag-and-drop reordering of threads within their project in the sidebar — grab a thread row and move it among the other threads in the same project. This is reordering within one project, not moving threads between projects. It mirrors the existing project-reorder pattern (same @dnd-kit setup, same client-side persistence model).

Changes

  • contracts: add "manual" to SidebarThreadSortOrder (alongside updated_at/created_at), matching SidebarProjectSortOrder. New "Manual" option in the "Sort threads" menu.
  • threadSort: sortThreads returns input order for "manual", so the user-defined order is layered on top via orderItemsByPreferredIds (same shape as sortProjectsForSidebar).
  • uiStateStore: new threadOrderByProject: Record<projectKey, threadKey[]>. Because scopedThreadKey is stable, it persists directly to localStorage (no id→cwd remapping like projects need). New reorderThreads action; syncThreads prunes stale thread keys and drops emptied projects.
  • Sidebar: per-project DndContext + SortableContext + SortableThreadItem rendered only when manual sort is active (non-DnD fallback otherwise). dragInProgress / suppressClickAfterDrag refs guard click, cmd/shift multi-select and rename so they don't fire on a drag. Manual mode auto-expands the full list (skips preview slicing / "Show more") so the whole list is reorderable; auto-animate stays attached.

The order map is keyed per project now but keyed so it extends naturally to user-defined groups once folders land.

Verification

  • tsgo --noEmit passes (web + contracts).
  • Full web unit suite green (1055 tests); contracts 148. Added 8 store tests (reorder up/down, first-drag seeding, no-ops, sync pruning, persistence round-trip).
  • Manually tested on localhost: enabled Manual thread sort, dragged a thread within a project, confirmed the new order persists across reload, and that click / rename / multi-select still work.

🤖 Generated with Claude Code


Note

Low Risk
Client-only sidebar ordering and localStorage persistence; navigation/delete fallbacks are aligned with manual order but do not touch server auth or data.

Overview
Adds manual thread sort so users can drag thread rows within a project to define sidebar order, with the same persistence model as manual project reorder.

Contracts & sorting: SidebarThreadSortOrder gains "manual". orderItemsByPreferredIds moves to threadSort.ts; manual mode keeps store order and callers apply persisted scoped thread keys. getLatestThreadForProject and post-delete fallback navigation use that order so “open project” and delete routing match the first visible thread.

Persistence: uiStateStore adds threadOrderByProject and reorderThreads, saved to localStorage; syncThreads prunes removed threads.

Sidebar UX: When sort is manual, per-project DndContext/SortableContext enables vertical drag on rows (grab cursor, drop highlight), suppresses clicks during/after drag, and shows the full thread list (no “Show more” truncation). Thread-jump indices and prewarm lists follow the same manual ordering.

Call sites: Command palette project open paths pass flattened manual order into getLatestThreadForProject.

Reviewed by Cursor Bugbot for commit 1ed1189. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add drag-and-drop manual reordering of threads within sidebar projects

  • Adds a new 'manual' sort mode to SidebarThreadSortOrder and a reorderThreads reducer in uiStateStore.ts that persists per-project thread order to localStorage.
  • Wraps sidebar thread rows in a SortableThreadItem component using @dnd-kit, enabling vertical drag-and-drop reordering within each project in Sidebar.tsx.
  • Extends sortThreads and getLatestThreadForProject in threadSort.ts so manual mode preserves input order and resolves "latest" thread by manual position rather than timestamp.
  • Fallback navigation after thread deletion and command palette project opening both respect manual order when active.
  • syncThreads prunes stale thread keys from the saved order automatically when threads are removed.

Macroscope summarized 1ed1189.

Add a "Manual" thread sort mode that lets you drag a thread row to reorder
it among the other threads in the same project, mirroring the existing
project-reorder pattern.

- contracts: add "manual" to SidebarThreadSortOrder
- threadSort: sortThreads returns input order for "manual" so a user-defined
  order can be layered on top (matches sortProjectsForSidebar)
- uiStateStore: persist threadOrderByProject directly (thread keys are stable,
  no id->cwd remapping); add reorderThreads action and prune stale keys /
  empty projects in syncThreads
- Sidebar: per-project DndContext + SortableContext + SortableThreadItem when
  manual sort is active; suppress click/multi-select/rename during drag; apply
  the order via orderItemsByPreferredIds and auto-expand the full list

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 21981e0e-a37c-489b-b623-0244d0809ec2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jun 13, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 83326f5. Configure here.

Comment thread apps/web/src/lib/threadSort.ts
@macroscopeapp

macroscopeapp Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new user-facing feature (drag-and-drop thread reordering) with new state management and UI interactions across multiple components. New capabilities of this scope warrant human review.

You can customize Macroscope's approvability policy. Learn more.

Cursor Bugbot flagged that helpers picking a thread via sortThreads still
used raw store order under manual sort, so the delete-fallback navigation
and "open project from search" could jump to a thread that isn't first in
the sidebar's manual list.

- getLatestThreadForProject / getFallbackThreadIdAfterDelete now accept the
  manual order (scoped thread keys) and apply orderItemsByPreferredIds when
  sort is "manual", matching the sidebar's on-screen order
- move orderItemsByPreferredIds into lib/threadSort (re-exported from
  Sidebar.logic) so the lib helper can use it without an import cycle
- callers (useThreadActions, CommandPalette) pass the flattened
  threadOrderByProject; the per-project filter means only the relevant
  project's keys match

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jun 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant