Skip to content

feat(desktop): add drag-and-drop reordering for projects in sidebar#744

Merged
Kitenite merged 5 commits intomainfrom
drag-drop-projects
Jan 14, 2026
Merged

feat(desktop): add drag-and-drop reordering for projects in sidebar#744
Kitenite merged 5 commits intomainfrom
drag-drop-projects

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Jan 14, 2026

Summary

  • Add drag-and-drop functionality to reorder projects in the sidebar
  • Uses existing projects.reorder backend mutation
  • Works in both collapsed and expanded sidebar modes

Test plan

  • Open the desktop app with multiple projects
  • Drag a project to reorder it in the list
  • Verify the new order persists after refresh
  • Test in collapsed sidebar mode
  • Verify workspace drag-and-drop still works within projects

Summary by CodeRabbit

  • New Features
    • Added drag-and-drop functionality to reorder projects in the workspace sidebar. Users can now click and drag projects to rearrange them, with visual feedback during the drag operation.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 14, 2026

Warning

Rate limit exceeded

@Kitenite has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 2 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between c4eeedf and 33deba6.

📒 Files selected for processing (4)
  • apps/desktop/src/renderer/react-query/projects/index.ts
  • apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
📝 Walkthrough

Walkthrough

Introduces project reordering functionality via a new React Query mutation hook that wraps a TRPC endpoint. The hook invalidates related workspace and project queries on success. Implements drag-and-drop reordering in ProjectSection using react-dnd, adding index prop propagation through the component hierarchy.

Changes

Cohort / File(s) Summary
React Query Hook Setup
apps/desktop/src/renderer/react-query/projects/index.ts, apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts
New useReorderProjects hook exported; wraps trpc.projects.reorder.useMutation and extends onSuccess with query invalidations for workspace groups and project recents.
Drag-and-Drop Implementation
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
Integrates react-dnd for project reordering with drag refs on containers and drop handlers; adds index prop to ProjectSectionProps; refactors child indexing logic to use wsIndex for accurate drag-and-drop state tracking.
Index Prop Wiring
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
Passes index prop to ProjectSection component.

Sequence Diagram

sequenceDiagram
    participant User
    participant ProjectSection as ProjectSection<br/>(Component)
    participant useDnD as react-dnd<br/>(useDrag/useDrop)
    participant Hook as useReorderProjects<br/>(Hook)
    participant TRPC as TRPC Mutation<br/>(trpc.projects.reorder)
    participant QueryCache as Query Cache<br/>(React Query)

    User->>ProjectSection: Drag project item
    ProjectSection->>useDnD: onDrop event triggered
    useDnD->>Hook: Call mutate() with new order
    Hook->>TRPC: Execute projects.reorder mutation
    TRPC-->>Hook: Success response
    Hook->>QueryCache: Invalidate getAllGrouped
    Hook->>QueryCache: Invalidate getRecents
    QueryCache-->>ProjectSection: Refetch & update UI
    ProjectSection->>User: Display reordered projects
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~23 minutes

Possibly Related PRs

Poem

🐰 Hop, hop, the projects rearrange!
Drag and drop through the code exchange,
React Query flows, queries invalidate,
Projects reorder—oh, how they migrate!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding drag-and-drop reordering for projects in the sidebar, which is the primary focus of the changeset.
Description check ✅ Passed The description covers the key aspects but lacks some template sections; it provides a summary and test plan but is missing Related Issues, Type of Change, Screenshots, and Additional Notes sections.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@Kitenite Kitenite linked an issue Jan 14, 2026 that may be closed by this pull request
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx:
- Around line 74-85: The hover handler inside the useDrop callback is calling
reorderProjects.mutate on every hover, causing excessive requests and races;
change this by moving the server mutation to a drop handler (add a drop: (item)
=> { ... } in the useDrop config) so you only call reorderProjects.mutate once
when the drag ends, and instead maintain local drag state for immediate UI
feedback (e.g., track a temporary index map or use local state in the component
to update item.index/index visually during hover without calling mutate). Ensure
you still update item.index locally in hover for UI ordering but remove the
mutate call from hover and invoke reorderProjects.mutate with fromIndex/toIndex
inside the new drop handler.
- Line 54: The call to the reorder mutation created via useReorderProjects in
ProjectSection currently swallows errors; wrap the mutation invocation
(reorderProjects) with proper error handling (either an async try/catch or an
onError handler on the mutation) so failures are not silent: log the error with
context (e.g., "reorderProjects failed in ProjectSection") and surface user
feedback via the app's notification/toast system (or at minimum console.error)
and ensure any optimistic UI change is rolled back or reconciled on error.
🧹 Nitpick comments (1)
apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts (1)

14-18: Consider parallelizing query invalidations.

The two invalidations are independent and can run concurrently using Promise.all instead of sequential awaits. This minor optimization reduces the delay before calling the user's onSuccess.

♻️ Suggested improvement
		onSuccess: async (...args) => {
-			await utils.workspaces.getAllGrouped.invalidate();
-			await utils.projects.getRecents.invalidate();
+			await Promise.all([
+				utils.workspaces.getAllGrouped.invalidate(),
+				utils.projects.getRecents.invalidate(),
+			]);
			await options?.onSuccess?.(...args);
		},
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 071a29b and c4eeedf.

📒 Files selected for processing (4)
  • apps/desktop/src/renderer/react-query/projects/index.ts
  • apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
🧰 Additional context used
📓 Path-based instructions (6)
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc
Use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from @trpc/server/observable instead of async generators, as the library explicitly checks isObservable(result) and throws an error otherwise

Files:

  • apps/desktop/src/renderer/react-query/projects/index.ts
  • apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid using any type - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness

Files:

  • apps/desktop/src/renderer/react-query/projects/index.ts
  • apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility

Files:

  • apps/desktop/src/renderer/react-query/projects/index.ts
  • apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
apps/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Drizzle ORM for all database operations - never use raw SQL

Files:

  • apps/desktop/src/renderer/react-query/projects/index.ts
  • apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for formatting and linting - run at root level with bun run lint:fix or biome check --write

Files:

  • apps/desktop/src/renderer/react-query/projects/index.ts
  • apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

One component per file - do not create multi-component files

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
🧠 Learnings (1)
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/*/src/components/{ui,ai-elements,react-flow}/*.tsx : Use kebab-case single files for shadcn/ui components (e.g., button.tsx, base-node.tsx) in src/components/ui/, src/components/ai-elements, and src/components/react-flow/

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
🧬 Code graph analysis (2)
apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts (1)
apps/desktop/src/renderer/react-query/projects/index.ts (1)
  • useReorderProjects (2-2)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx (3)
apps/desktop/src/renderer/stores/new-workspace-modal.ts (1)
  • useOpenNewWorkspaceModal (32-33)
apps/desktop/src/renderer/react-query/projects/useReorderProjects.ts (1)
  • useReorderProjects (7-20)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (3)
apps/desktop/src/renderer/react-query/projects/index.ts (1)

2-2: LGTM!

Clean re-export following the existing pattern.

apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx (1)

90-98: Good drag-and-drop visual feedback implementation.

The ref composition pattern drag(drop(node)) is correct for combining drag source and drop target. The visual feedback with opacity reduction and cursor change provides clear indication of drag state.

Also applies to: 147-156

apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx (1)

46-46: LGTM!

Correctly passes the array index to enable drag-and-drop reordering in ProjectSection.

Allow users to reorder projects in the sidebar using drag-and-drop,
similar to how workspaces can already be reordered within projects.

Server mutation is called only on drop (not during hover) to avoid
excessive requests and race conditions.
Use React Query cache manipulation during hover to provide immediate
visual feedback while still only calling the server mutation on drop.
@Kitenite Kitenite merged commit 959af35 into main Jan 14, 2026
5 checks passed
@Kitenite Kitenite deleted the drag-drop-projects branch January 14, 2026 01:14
@github-actions
Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch
  • ⚠️ Electric Fly.io app

Thank you for your contribution! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement] Drag-and-drop reordering for workspaces

1 participant