Skip to content

Allow deleting projects with chats#1753

Open
Prunty2 wants to merge 1 commit intopingdotgg:mainfrom
Prunty2:codex/remove-non-empty-projects
Open

Allow deleting projects with chats#1753
Prunty2 wants to merge 1 commit intopingdotgg:mainfrom
Prunty2:codex/remove-non-empty-projects

Conversation

@Prunty2
Copy link
Copy Markdown

@Prunty2 Prunty2 commented Apr 5, 2026

Summary

This fixes project removal so a project can be deleted even when it still contains chats.

What changed

  • replaced the previous hard stop for non-empty projects with a destructive confirmation dialog in the sidebar
  • reused the existing thread deletion flow so deleting a project also clears the project's chats and related draft/terminal state
  • added fallback selection logic so navigation stays stable when the active project is removed
  • added a focused logic test for the bulk-delete fallback path

Why

Previously, the UI refused to remove a project until every chat inside it had been deleted individually. That made project cleanup unnecessarily tedious and inconsistent with the destructive action the user was already trying to perform.

Validation

  • bun fmt
  • bun lint
  • bun typecheck

Example [After]

image

Note

Allow deleting projects with chats via a confirmation dialog in the sidebar

  • Replaces the previous behavior (blocking deletion of non-empty projects) with an AlertDialog confirmation that shows the project name and number of chats to be deleted.
  • On confirmation, all threads in the project are bulk-deleted (skipping per-thread worktree prompts and navigation), the project is removed, and the UI navigates to the next surviving thread or home.
  • Adds getFallbackThreadIdAfterBulkDelete in Sidebar.logic.ts to select the top non-archived thread after deletion.
  • Extends deleteThread in useThreadActions.ts with skipWorktreeConfirm and suppressNavigation options used during bulk deletion.
  • Behavioral Change: projects with chats can now be fully deleted in one action; previously this was blocked.

Macroscope summarized 1e0acdd.


Note

Medium Risk
Enables bulk deletion of a project’s threads and changes navigation behavior when the active thread/project is removed, which could cause unexpected data loss or routing edge cases if the new flow misfires.

Overview
Projects can now be removed even when they still contain chats: selecting Remove project opens a destructive AlertDialog and, on confirmation, deletes all threads in that project before dispatching project.delete.

To keep routing stable, the sidebar computes a cross-project fallback thread via new getFallbackThreadIdAfterBulkDelete and navigates to it (or home) if the active thread/draft is affected. Thread deletion is extended with skipWorktreeConfirm and suppressNavigation options to support this bulk-delete flow without per-thread prompts or intermediate redirects, and a focused logic test covers the bulk fallback selection.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

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: dc43c200-ad32-40ec-b25d-0ffe800a2f4a

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 Apr 5, 2026
@Prunty2 Prunty2 changed the title [codex] Allow deleting projects with chats Allow deleting projects with chats Apr 5, 2026
@@ -83,6 +90,7 @@ export function useThreadActions() {
: null;
const canDeleteWorktree = orphanedWorktreePath !== null && threadProject !== undefined;
const shouldDeleteWorktree =
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.

🟡 Medium hooks/useThreadActions.ts:92

When opts.skipWorktreeConfirm is true, the worktree is never deleted. The expression !opts.skipWorktreeConfirm && canDeleteWorktree && (await api.dialogs.confirm(...)) evaluates to false immediately when skipWorktreeConfirm is set, so shouldDeleteWorktree becomes false and the worktree cleanup is skipped entirely. For batch deletions this leaves orphaned worktrees behind even though the option name suggests only the confirmation dialog should be bypassed. Consider changing the logic to canDeleteWorktree && (opts.skipWorktreeConfirm || (await api.dialogs.confirm(...))) so the worktree is deleted without prompting when the flag is set.

🤖 Copy this AI Prompt to have your agent fix this:
In file apps/web/src/hooks/useThreadActions.ts around line 92:

When `opts.skipWorktreeConfirm` is `true`, the worktree is never deleted. The expression `!opts.skipWorktreeConfirm && canDeleteWorktree && (await api.dialogs.confirm(...))` evaluates to `false` immediately when `skipWorktreeConfirm` is set, so `shouldDeleteWorktree` becomes `false` and the worktree cleanup is skipped entirely. For batch deletions this leaves orphaned worktrees behind even though the option name suggests only the confirmation dialog should be bypassed. Consider changing the logic to `canDeleteWorktree && (opts.skipWorktreeConfirm || (await api.dialogs.confirm(...)))` so the worktree is deleted without prompting when the flag is set.

Evidence trail:
apps/web/src/hooks/useThreadActions.ts lines 92-102 (shouldDeleteWorktree definition with `!opts.skipWorktreeConfirm && canDeleteWorktree && (await api.dialogs.confirm(...))`), lines 150-152 (early return when shouldDeleteWorktree is false), lines 154-159 (worktree deletion via removeWorktreeMutation.mutateAsync only reached if shouldDeleteWorktree is true). Commit: REVIEWED_COMMIT

@Prunty2 Prunty2 marked this pull request as ready for review April 5, 2026 03:40
Copilot AI review requested due to automatic review settings April 5, 2026 03:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Enables deleting a project even when it still contains chats/threads by introducing a destructive confirmation dialog and a bulk-delete flow that clears related UI state and keeps navigation stable.

Changes:

  • Replace the “project not empty” hard stop with an AlertDialog confirmation in the sidebar.
  • Bulk-delete all threads in a project (reusing deleteThread with new options) before dispatching project.delete.
  • Add cross-project fallback-thread selection logic (+ a focused unit test) to keep routing stable after bulk deletion.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
apps/web/src/hooks/useThreadActions.ts Extends deleteThread with options to suppress navigation and bypass worktree confirmation during bulk deletion.
apps/web/src/components/Sidebar.tsx Adds project deletion confirmation dialog and bulk delete orchestration + fallback navigation.
apps/web/src/components/Sidebar.logic.ts Adds getFallbackThreadIdAfterBulkDelete to pick a remaining non-archived thread after bulk deletion.
apps/web/src/components/Sidebar.logic.test.ts Adds a unit test for the bulk-delete fallback-thread selection behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 91 to 95
const canDeleteWorktree = orphanedWorktreePath !== null && threadProject !== undefined;
const shouldDeleteWorktree =
!opts.skipWorktreeConfirm &&
canDeleteWorktree &&
(await api.dialogs.confirm(
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

skipWorktreeConfirm currently prevents worktree deletion entirely (because shouldDeleteWorktree becomes false), not just skipping the confirmation UI. If the intent is to delete orphaned worktrees without prompting during bulk deletion, adjust the boolean logic (or rename the option to reflect that it disables deletion). Otherwise, bulk project deletion will leave orphaned worktrees behind with no cleanup path in this flow.

Copilot uses AI. Check for mistakes.
Comment on lines +1274 to +1280
const projectThreadIds = [...(threadIdsByProjectId[projectId] ?? [])];
setPendingProjectDelete({
projectId,
projectName: project.name,
threadIds: projectThreadIds,
threadCount: projectThreadIds.length,
});
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

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

PendingProjectDelete snapshots threadIds/threadCount at context-menu time. If threads are created/moved/deleted before the user confirms, this list can become stale (e.g., leaving threads behind or causing project.delete to fail because the project is no longer empty, and the dialog count can be inaccurate). Prefer recomputing the current thread IDs for the project at confirm-time (or store only projectId/projectName and derive the rest).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

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 1e0acdd. Configure here.

: null;
const canDeleteWorktree = orphanedWorktreePath !== null && threadProject !== undefined;
const shouldDeleteWorktree =
!opts.skipWorktreeConfirm &&
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.

skipWorktreeConfirm skips deletion, not just confirmation

Medium Severity

The skipWorktreeConfirm flag short-circuits shouldDeleteWorktree to false, which skips the actual worktree removal entirely — not just the confirmation dialog. When bulk-deleting a project's threads, any orphaned git worktrees are silently left on disk. The option name implies skipping only the prompt while still performing cleanup, but the implementation prevents both.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1e0acdd. Configure here.

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp bot commented Apr 5, 2026

Approvability

Verdict: Needs human review

1 blocking correctness issue found. This PR enables a new capability to delete projects along with all their chats, which is a significant behavior change affecting data deletion. Multiple unresolved review comments have identified a bug where the skipWorktreeConfirm flag incorrectly skips worktree cleanup entirely, potentially leaving orphaned worktrees on disk during bulk deletion.

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

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

Labels

size:L 100-499 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.

2 participants