Skip to content

fix(projects): allow removing manually added projects#620

Open
Steve-Rye wants to merge 1 commit intositeboon:mainfrom
Steve-Rye:fix/remove-manually-added-projects
Open

fix(projects): allow removing manually added projects#620
Steve-Rye wants to merge 1 commit intositeboon:mainfrom
Steve-Rye:fix/remove-manually-added-projects

Conversation

@Steve-Rye
Copy link
Copy Markdown

@Steve-Rye Steve-Rye commented Apr 5, 2026

Summary

This PR adds a safe Remove flow for manually added projects so they can be removed from the sidebar without deleting the underlying project directory or related session data.

What changed

  • add DELETE /api/projects/:projectName/remove for eligible manually added projects
  • keep Delete Project behavior unchanged for projects with local Claude history
  • show Remove instead of Delete for manually added sidebar-only projects
  • add separate confirmation copy that explicitly states files and sessions are not deleted
  • add a focused backend regression test for removeProjectFromList
  • add locale strings for the new sidebar action and confirmation copy

Why

Users can add existing workspaces to the project list, but the reverse action was missing. The only available action was Delete Project, which is much heavier and can delete local data. For manually added projects that only exist as sidebar entries, users need a way to remove them from the list without treating them as disposable data.

Scope

This PR intentionally only adds Remove for projects that are:

  • manually added via config
  • not backed by a local Claude project directory in ~/.claude/projects

Projects with local Claude history still use the existing delete flow because they are auto-discovered again from disk and cannot be truly hidden by removing config alone.

Testing

  • node --test server/projects.remove-project.test.mjs
  • npm run typecheck
  • npm run build

Related

Summary by CodeRabbit

  • New Features

    • Added ability to remove manually added projects from the sidebar without deleting local history or sessions.
    • Distinct UI and messaging for removing projects versus full deletion.
  • Tests

    • Added test coverage for project removal functionality.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 5, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a "remove project" feature distinct from deletion. Manually added projects can now be removed from the project list without deleting their local Claude history or sessions. The backend adds a new REST endpoint, the frontend differentiates between remove and delete actions with separate UI and messaging, and internationalization strings are added across all supported languages.

Changes

Cohort / File(s) Summary
Backend Removal Endpoint
server/index.js, server/projects.js
Added authenticated DELETE /api/projects/:projectName/remove endpoint and removeProjectFromList() function that removes project config entries only if manually added and no local history exists.
Backend Tests
server/projects.remove-project.test.mjs
New test suite validating removeProjectFromList() behavior: verifies removal of manually added projects, rejects non-manual projects, and prevents removal when local history is present.
Type Definitions
src/components/sidebar/types/types.ts, src/types/app.ts
Extended DeleteProjectConfirmation with action: 'delete' | 'remove' discriminator and added optional isManuallyAdded field to Project interface.
Frontend State Management
src/components/sidebar/hooks/useSidebarController.ts
Updated to track remove vs delete action, branching confirmation handler between api.removeProject() and api.deleteProject() with action-specific error messaging.
Frontend UI Components
src/components/sidebar/view/subcomponents/SidebarModals.tsx, src/components/sidebar/view/subcomponents/SidebarProjectItem.tsx
Conditional rendering for remove confirmations with distinct modal styling (X icon instead of AlertTriangle, outline button instead of destructive), different copy, and updated project item buttons with neutral styling for removable projects.
Frontend API Client
src/utils/api.js
Added new removeProject(projectName) function making authenticated DELETE request to the remove endpoint.
Internationalization
src/i18n/locales/{de,en,ja,ko,ru,zh-CN}/sidebar.json
Added new translation keys across all supported languages: tooltips.removeProject, actions.remove, messages.removeProjectFailed, messages.removeProjectError, and removeConfirmation.* section with confirmation and outcome text.

Suggested reviewers

  • blackmammoth

Poem

🐰 A project removed, but not forgotten,
Still safe on disk, never rotten,
Sessions remain for another day,
Re-add anytime—hooray, hooray! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature being added: enabling removal of manually added projects from the sidebar.

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

✨ 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.

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.

🧹 Nitpick comments (2)
src/components/sidebar/view/subcomponents/SidebarModals.tsx (1)

108-113: Consider using neutral styling for the remove icon container.

The icon container uses bg-red-100 dark:bg-red-900/30 even for remove confirmations, but remove is a non-destructive action. Consider making the container styling conditional as well for visual consistency.

♻️ Proposed optional change
-                  <div className="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/30">
+                  <div className={cn(
+                    "flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full",
+                    isRemoveConfirmation
+                      ? "bg-muted"
+                      : "bg-red-100 dark:bg-red-900/30"
+                  )}>
                     {isRemoveConfirmation ? (
                       <X className="h-6 w-6 text-muted-foreground" />
                     ) : (
                       <AlertTriangle className="h-6 w-6 text-red-600 dark:text-red-400" />
                     )}
                   </div>

Note: You'll need to import cn if not already available in this file.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/sidebar/view/subcomponents/SidebarModals.tsx` around lines 108
- 113, The icon container always uses the destructive classes "bg-red-100
dark:bg-red-900/30" even when isRemoveConfirmation is true (remove is
non-destructive); update the container div rendering in SidebarModals so its
className is conditional based on isRemoveConfirmation (e.g., use a neutral bg
when isRemoveConfirmation is true and the red bg only for destructive alerts)
and use the shared cn utility to compose classes (import cn if not present);
adjust the inner icon rendering to remain the same but ensure the container
classes reflect the non-destructive state.
server/projects.remove-project.test.mjs (1)

9-21: Consider Windows compatibility for the HOME override.

process.env.HOME works on Unix-like systems, but Windows uses USERPROFILE. Since the code calls os.homedir(), which is platform-aware, the test environment override will only affect Unix systems. If this test needs to run on Windows, override both environment variables.

♻️ Proposed optional change for cross-platform support
 async function withTempHome(fn) {
   const originalHome = process.env.HOME;
+  const originalUserProfile = process.env.USERPROFILE;
   const tempHome = await mkdtemp(path.join(os.tmpdir(), 'claudecodeui-home-'));
 
   process.env.HOME = tempHome;
+  process.env.USERPROFILE = tempHome;
 
   try {
     return await fn(tempHome);
   } finally {
     process.env.HOME = originalHome;
+    process.env.USERPROFILE = originalUserProfile;
     await rm(tempHome, { recursive: true, force: true });
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/projects.remove-project.test.mjs` around lines 9 - 21, The test helper
withTempHome overrides only process.env.HOME which breaks on Windows; update
withTempHome to save both originalHome = process.env.HOME and
originalUserProfile = process.env.USERPROFILE, set both process.env.HOME and
process.env.USERPROFILE to the tempHome before calling fn(tempHome), and restore
both originals in the finally block (handling undefined values) so os.homedir()
and other platform-aware calls see the temp directory on Windows and Unix.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@server/projects.remove-project.test.mjs`:
- Around line 9-21: The test helper withTempHome overrides only process.env.HOME
which breaks on Windows; update withTempHome to save both originalHome =
process.env.HOME and originalUserProfile = process.env.USERPROFILE, set both
process.env.HOME and process.env.USERPROFILE to the tempHome before calling
fn(tempHome), and restore both originals in the finally block (handling
undefined values) so os.homedir() and other platform-aware calls see the temp
directory on Windows and Unix.

In `@src/components/sidebar/view/subcomponents/SidebarModals.tsx`:
- Around line 108-113: The icon container always uses the destructive classes
"bg-red-100 dark:bg-red-900/30" even when isRemoveConfirmation is true (remove
is non-destructive); update the container div rendering in SidebarModals so its
className is conditional based on isRemoveConfirmation (e.g., use a neutral bg
when isRemoveConfirmation is true and the red bg only for destructive alerts)
and use the shared cn utility to compose classes (import cn if not present);
adjust the inner icon rendering to remain the same but ensure the container
classes reflect the non-destructive state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5aaa8fb9-d66d-4d30-9941-37c1ecf04249

📥 Commits

Reviewing files that changed from the base of the PR and between 388134c and b404516.

📒 Files selected for processing (15)
  • server/index.js
  • server/projects.js
  • server/projects.remove-project.test.mjs
  • src/components/sidebar/hooks/useSidebarController.ts
  • src/components/sidebar/types/types.ts
  • src/components/sidebar/view/subcomponents/SidebarModals.tsx
  • src/components/sidebar/view/subcomponents/SidebarProjectItem.tsx
  • src/i18n/locales/de/sidebar.json
  • src/i18n/locales/en/sidebar.json
  • src/i18n/locales/ja/sidebar.json
  • src/i18n/locales/ko/sidebar.json
  • src/i18n/locales/ru/sidebar.json
  • src/i18n/locales/zh-CN/sidebar.json
  • src/types/app.ts
  • src/utils/api.js

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.

1 participant