feat(sidebar): project rename and remove from sidebar#517
Conversation
- Add projectKey field to PawworkSessionItem and PawworkSidebarSession - Use projectKey (worktree/directory) instead of projectLabel for group identity - Update collapse key to use projectKey instead of label - Update tests to include projectKey
- Add rename project menu item to group header - Add remove from sidebar (soft-hide) menu item to group header - Add pawworkProjectHidden to layout-page-store for persistence - Add DialogRemoveProject component - Add unhide logic when session is opened - Add i18n strings for project actions (zh + en) - Add E2E tests for rename, remove, and auto-restore
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds per-project hide state and stable projectKey derivation, implements rename and remove dialogs, adds sidebar group header actions, switches grouping to projectKey, updates migrations and i18n, and adds unit + e2e tests. ChangesProject Sidebar Actions
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces functionality to rename and hide projects within the sidebar, supported by new E2E tests, a removal confirmation dialog, and persistent state management for hidden projects. Feedback focuses on addressing missing i18n keys for the 'Remove' action and fixing bugs in the auto-unhide logic where subdirectories failed to trigger project restoration. Additionally, it is recommended to remove redundant fallback logic in the project renaming handler to ensure state consistency.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/app/src/pages/layout.tsx`:
- Around line 1557-1572: The auto-unhide logic in openSession (where it computes
const key = workspaceKey(session.directory)) and openPawworkHome (const key =
workspaceKey(directory)) uses workspaceKey but the hidden state uses project
keys; change those to use the project key generator (use
projectKey(session.directory) and projectKey(directory)) so you
check/store/unhide against the same key type (pawworkProjectHidden[key] and
unhideProject(key) should use projectKey). Ensure you import or reference the
same projectKey function used elsewhere and update both occurrences in the
openSession and openPawworkHome flows.
- Around line 1129-1143: handleRenameProject only matches projects by
workspaceKey(p.worktree) and misses projects that belong to sandbox/group keys;
update the lookup in handleRenameProject (the initial
layout.projects.list().find and the fallback localProject find) to also consider
sandbox/group keys by checking p.sandboxKey and p.group?.sandboxKey (or
whichever sandbox/group identifier the Project object exposes) against
projectKey, and when using the session fallback also compare those sandbox/group
keys derived from workspaceKey(session.directory); keep using workspaceKey for
normalized comparisons so sandbox-key groups are caught and renameProject is
called for the actual project instance.
In `@packages/app/src/pages/layout/pawwork-session-source.ts`:
- Line 128: The tests call buildPawworkSidebarSessionRows but fail to pass the
required projectKeyForSession callback, causing input.projectKeyForSession to be
undefined; open pawwork-sidebar-session-rows.test.ts and in each of the six test
inputs (the cases around lines where tests start) add a simple stub property
projectKeyForSession: (session) => session.directory (or equivalent) so the
buildPawworkSidebarSessionRows call receives a valid function; ensure the stub
is added to all six test input objects to prevent runtime errors.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 66df35b4-38a4-4969-9217-0cd1ff37ee61
📒 Files selected for processing (10)
packages/app/e2e/sidebar/sidebar-project-actions.spec.tspackages/app/src/components/dialog-remove-project.tsxpackages/app/src/i18n/en.tspackages/app/src/i18n/zh.tspackages/app/src/pages/layout.tsxpackages/app/src/pages/layout/layout-page-store.tspackages/app/src/pages/layout/pawwork-session-nav.test.tspackages/app/src/pages/layout/pawwork-session-nav.tspackages/app/src/pages/layout/pawwork-session-source.tspackages/app/src/pages/layout/pawwork-sidebar.tsx
- Fix icon name 'hide' → 'archive' (icon registry compatibility) - Fix pawwork-sidebar-session-rows.test.ts missing projectKey - Fix hide/unhide key consistency using projectKeyForSession - Add Undo toast after remove from sidebar - Add missing i18n strings for toast and undo
- Add 'project.remove' i18n key (en + zh) - Fix openPawworkHome to use projectRoot(directory) for consistent key calculation - Ensures sandbox/worktree subdirectories correctly unhide parent project
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/app/src/components/dialog-rename-project.tsx (1)
25-30: ⚡ Quick winLog the error for debugging.
The catch block shows a user-friendly toast but discards the original error, making production debugging difficult. Add
console.errorto preserve the error details.📝 Suggested enhancement
- } catch { + } catch (error) { + console.error('Failed to rename project:', error) showToast({ title: language.t("toast.project.rename.failed.title"), description: language.t("toast.project.rename.failed.description"),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/app/src/components/dialog-rename-project.tsx` around lines 25 - 30, The catch block in the dialog-rename-project component currently swallows the error; change the catch to capture the error (e.g., catch (e) { ... }) and add a console.error call to log the error before calling showToast so you preserve stack/diagnostic info; update the existing catch that surrounds the rename logic and keep the existing showToast(language.t(...)) calls intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/app/src/components/dialog-rename-project.tsx`:
- Around line 25-30: The catch block in the dialog-rename-project component
currently swallows the error; change the catch to capture the error (e.g., catch
(e) { ... }) and add a console.error call to log the error before calling
showToast so you preserve stack/diagnostic info; update the existing catch that
surrounds the rename logic and keep the existing showToast(language.t(...))
calls intact.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 5134be03-1995-42a7-9896-88faf4e22245
📒 Files selected for processing (9)
packages/app/e2e/sidebar/sidebar-project-actions.spec.tspackages/app/src/components/dialog-rename-project.tsxpackages/app/src/i18n/en.tspackages/app/src/i18n/zh.tspackages/app/src/pages/layout.tsxpackages/app/src/pages/layout/pawwork-session-nav.tspackages/app/src/pages/layout/pawwork-sidebar-session-rows.test.tspackages/app/src/pages/layout/pawwork-sidebar.tsxpackages/opencode/src/provider/models-snapshot.js
✅ Files skipped from review due to trivial changes (1)
- packages/app/src/i18n/zh.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- packages/app/src/pages/layout/pawwork-session-nav.ts
- packages/app/e2e/sidebar/sidebar-project-actions.spec.ts
- packages/app/src/i18n/en.ts
- packages/app/src/pages/layout.tsx
- packages/app/src/pages/layout/pawwork-sidebar.tsx
- Fix projectLabelForSession to check layout.projects.list() for worktree projects before falling back to getFilename(), ensuring renamed project labels are reflected in sidebar - Add back rename assertion with expect.poll() retry for async update - Remove flaky restore E2E test (covered by unit tests)
- Add unhideProject to syncSessionRoute so direct URL navigation restores hidden projects (gotoSession / deep link / route change) - Fix projectLabelForSession priority: displayName(localProject) first, then project.name fallback. Prevents stale session names from shadowing ProjectMeta renames. - Add back restore E2E test with sidebar content wait
- Add sandbox lookup in handleRenameProject to handle projects where projectKey matches a sandbox directory instead of root worktree - Matches existing sandbox resolution pattern in currentProject()
Address CodeRabbit nitpick: preserve error details for debugging
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/app/src/pages/layout.tsx (1)
1119-1141: 💤 Low valueOptional: use path-based
setStoreinstead of spread +reconcile.
hideProject/unhideProjectrebuild the entirepawworkProjectHiddenrecord on each toggle and thenreconcileit. The idiomatic SolidJS store form is a path update, which avoids the spread, is cheaper, and only invalidates subscribers of the specific key.♻️ Proposed refactor
function hideProject(projectKey: string) { - const current = store.pawworkProjectHidden - if (current[projectKey]) return - setStore("pawworkProjectHidden", reconcile({ ...current, [projectKey]: true })) + if (store.pawworkProjectHidden[projectKey]) return + setStore("pawworkProjectHidden", projectKey, true) showToast({ title: language.t("project.remove.toast.title"), description: language.t("project.remove.toast.description"), actions: [ { label: language.t("common.undo"), onClick: () => unhideProject(projectKey), }, ], }) } function unhideProject(projectKey: string) { - const current = store.pawworkProjectHidden - if (!current[projectKey]) return - const next = { ...current } - delete next[projectKey] - setStore("pawworkProjectHidden", reconcile(next)) + if (!store.pawworkProjectHidden[projectKey]) return + setStore("pawworkProjectHidden", projectKey, undefined!) }(If you prefer to actually delete the key rather than set it to
undefined, wrap the mutation inproduce((draft) => { delete draft[projectKey] }).)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/app/src/pages/layout.tsx` around lines 1119 - 1141, hideProject/unhideProject rebuild the entire pawworkProjectHidden record and call reconcile; instead perform path-based updates on the SolidJS store to avoid spreading and full replace: in hideProject call setStore with the path for the specific key (pawworkProjectHidden, projectKey) to true, and in unhideProject either set that path to undefined via setStore(pawworkProjectHidden, projectKey, undefined) or use setStore with produce to delete the key (produce(draft => { delete draft[projectKey] })) so only the specific key's subscribers are invalidated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/app/src/pages/layout.tsx`:
- Around line 1119-1141: hideProject/unhideProject rebuild the entire
pawworkProjectHidden record and call reconcile; instead perform path-based
updates on the SolidJS store to avoid spreading and full replace: in hideProject
call setStore with the path for the specific key (pawworkProjectHidden,
projectKey) to true, and in unhideProject either set that path to undefined via
setStore(pawworkProjectHidden, projectKey, undefined) or use setStore with
produce to delete the key (produce(draft => { delete draft[projectKey] })) so
only the specific key's subscribers are invalidated.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: cafcb02b-158d-4004-9435-8ae9b7e0d497
📒 Files selected for processing (5)
packages/app/e2e/sidebar/sidebar-project-actions.spec.tspackages/app/src/components/dialog-rename-project.tsxpackages/app/src/pages/layout.tsxpackages/app/src/pages/layout/pawwork-sidebar.tsxpackages/ui/src/components/icon.tsx
✅ Files skipped from review due to trivial changes (1)
- packages/ui/src/components/icon.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/app/src/pages/layout/pawwork-sidebar.tsx
- packages/app/e2e/sidebar/sidebar-project-actions.spec.ts
- packages/app/src/components/dialog-rename-project.tsx
Summary
Add project-level actions to the sidebar group header:
folder/folder-openstate icons, align the project overflow button with session rows, and expose the original workspace path via hover tooltipWhy
Issue #502 requests project rename and delete actions in the sidebar. This PR implements the non-destructive sidebar actions (rename + soft-hide). Archive is out of scope; see Related Issue.
The visual refinement keeps the project group header coherent after adding rename/remove actions: the folder icon now communicates collapsed/expanded state directly, and the overflow button aligns with session-row actions.
Related Issue
Closes #502. Archive sessions is intentionally out of scope because session archive has no user-facing restore path.
Follow-up: #523 tracks broader chrome/sidebar icon stroke and size consistency. That audit is intentionally not bundled into this PR.
Changes
projectLabelto stableprojectKey(worktree/directory based)DialogRenameProjectcomponent + ProjectMeta integrationpawworkProjectHiddenstate +DialogRemoveProject+ Toast with UndosyncSessionRoute/navigateToSession/openPawworkHomeall trigger unhidefolder/folder-openicons replace chevron for collapsed/expanded project groupstitleshows the original workspace path after renameVerification
bun --cwd packages/app typecheckbun --cwd packages/ui typecheckbun --cwd packages/app test:e2e -- e2e/sidebar/sidebar-project-actions.spec.ts(3/3 passed)git diff --checkScreenshots
E2E screenshots captured via Playwright from
packages/app/e2e/sidebar/sidebar-project-actions.spec.ts:Risk Notes
pawworkProjectCollapsed[label]state will naturally invalidate after this change since collapse keys now useprojectKeyinstead ofprojectLabelChecklist
devbranchSummary by CodeRabbit
Release Notes