Skip to content

feat(sidebar): project rename and remove from sidebar#517

Merged
Astro-Han merged 13 commits into
devfrom
feat/sidebar-project-rename-remove
May 10, 2026
Merged

feat(sidebar): project rename and remove from sidebar#517
Astro-Han merged 13 commits into
devfrom
feat/sidebar-project-rename-remove

Conversation

@Astro-Han
Copy link
Copy Markdown
Owner

@Astro-Han Astro-Han commented May 10, 2026

Summary

Add project-level actions to the sidebar group header:

  • Rename project: Change the display name of a project via dialog
  • Remove from sidebar: Soft-hide a project from the sidebar (sessions remain on disk)
  • Auto-restore: Hidden projects automatically reappear when a session is opened via URL/direct navigation
  • Sidebar visual refinement: Replace the project group chevron with folder / folder-open state icons, align the project overflow button with session rows, and expose the original workspace path via hover tooltip

Why

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

  • Phase 0: Refactor group key from projectLabel to stable projectKey (worktree/directory based)
  • Rename: DialogRenameProject component + ProjectMeta integration
  • Soft-hide: pawworkProjectHidden state + DialogRemoveProject + Toast with Undo
  • Auto-unhide: syncSessionRoute / navigateToSession / openPawworkHome all trigger unhide
  • Header affordance: folder / folder-open icons replace chevron for collapsed/expanded project groups
  • Path tooltip: project group header title shows the original workspace path after rename
  • Menu alignment: project overflow button uses the same action-slot size as session rows, with pointer-events fixed so the menu remains clickable
  • i18n: English and Chinese strings for all new UI surfaces
  • Tests: 3 E2E tests (rename, remove, restore) with screenshot capture

Verification

  • bun --cwd packages/app typecheck
  • bun --cwd packages/ui typecheck
  • bun --cwd packages/app test:e2e -- e2e/sidebar/sidebar-project-actions.spec.ts (3/3 passed)
  • git diff --check
  • Code review: GPT + Opus sign-off
  • All review threads resolved

Screenshots

E2E screenshots captured via Playwright from packages/app/e2e/sidebar/sidebar-project-actions.spec.ts:

  • Project header with folder state icon and overflow menu
  • Rename dialog
  • Remove confirmation dialog
  • Post-remove state with Toast

Risk Notes

  • Old pawworkProjectCollapsed[label] state will naturally invalidate after this change since collapse keys now use projectKey instead of projectLabel
  • Hidden projects are sidebar-only state; no session data is modified
  • Sandbox projects now supported in rename lookup
  • The broader icon consistency audit is tracked separately in [Task] Audit and align chrome/sidebar icon size and stroke consistency #523 to avoid widening this PR

Checklist

  • Human review status is stated above as pending
  • Linked related issue [Feature] Add project rename and delete actions to the sidebar #502
  • Described review focus and risks
  • Listed verification steps
  • All review threads resolved
  • CI passing before the final visual-refinement push; final CI must be green again before merge
  • No unrelated refactors
  • Targeting dev branch

Summary by CodeRabbit

Release Notes

  • New Features
    • Rename projects directly from the sidebar project menu
    • Remove/hide projects from sidebar with confirmation dialog
    • Restore previously hidden projects when navigating back to their sessions
    • Multi-language support for project management actions

Astro-Han added 2 commits May 10, 2026 13:42
- 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
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 10, 2026

Warning

Rate limit exceeded

@Astro-Han has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 51 minutes before requesting another review.

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0c472273-3ee6-4641-bb7b-7d7903983ff4

📥 Commits

Reviewing files that changed from the base of the PR and between c97709f and 8e48d8b.

📒 Files selected for processing (1)
  • packages/app/src/pages/layout.tsx
📝 Walkthrough

Walkthrough

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

Changes

Project Sidebar Actions

Layer / File(s) Summary
Data Contracts
packages/app/src/pages/layout/pawwork-session-nav.ts, packages/app/src/pages/layout/pawwork-session-source.ts, packages/app/src/pages/layout/pawwork-sidebar.tsx
Adds projectKey to session/sidebar types; sidebar builders accept projectKeyForSession and propagate projectKey; PawworkSidebar props extended with onRenameProject and onRemoveProject.
Persisted State & Migration
packages/app/src/pages/layout/layout-page-store.ts
createDefaultLayoutPageState() initializes pawworkProjectHidden; migrateLayoutPageState() normalizes hidden-project state across legacy, validated, and direct-field storage paths using projectHidden() helper.
Session Grouping & Key Derivation
packages/app/src/pages/layout.tsx, packages/app/src/pages/layout/pawwork-session-nav.ts
Adds projectKeyForSession(session) deriving from project.worktree or session.directory; grouping switches from projectLabel to projectKey with fallbacks; group objects now include stable key and computed label.
Project Lifecycle Handlers
packages/app/src/pages/layout.tsx
hideProject() and unhideProject() manage persisted hidden state; handleRenameProject() resolves project by workspaceKey or session-directory fallback and applies rename; navigation automatically unhides corresponding projects.
Rename & Remove Dialogs
packages/app/src/components/dialog-rename-project.tsx, packages/app/src/components/dialog-remove-project.tsx
Adds DialogRenameProject and DialogRemoveProject components with local state and async-safe confirm handling (saving/removing flags and error toast on rename failure).
Sidebar UI & Action Wiring
packages/app/src/pages/layout/pawwork-sidebar.tsx, packages/app/src/pages/layout.tsx
Project group headers use group.key for collapse identity, render dropdown/context-menu actions for Rename/Remove, import dialogs, and wire actions to layout handlers (onRenameProject, onRemoveProject).
Internationalization
packages/app/src/i18n/en.ts, packages/app/src/i18n/zh.ts
Adds English and Chinese translations for common.remove, project.rename, project.remove.{title,confirm,description}, and rename-failed toast keys.
Tests / E2E
packages/app/src/pages/layout/pawwork-session-nav.test.ts, packages/app/e2e/sidebar/sidebar-project-actions.spec.ts, packages/app/src/pages/layout/pawwork-sidebar-session-rows.test.ts
Unit test fixtures updated with projectKey; sidebar-row tests updated to assert projectKey; three Playwright e2e tests added for rename, remove, and hidden-project restoration with screenshot captures.
Icons
packages/ui/src/components/icon.tsx
Updates SVG glyphs for the folder icon and adds/updates folder-open glyph in the shared icons map.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped to the sidebar, bright and spry,
Renamed a project with a twinkle in my eye,
Hid a stray group, then brought it back anew,
Screenshots and tests proved the trick true — woo! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(sidebar): project rename and remove from sidebar' clearly and concisely summarizes the main changes: adding rename and remove functionality for projects in the sidebar.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering all template sections: summary, why, related issue, human review status, review focus, risk notes, verification steps with results, and screenshots.
Linked Issues check ✅ Passed The PR fully addresses issue #502's objectives: implements project rename via dialog with ProjectMeta persistence, soft-hide remove with confirmation and undo toast, auto-restore on navigation, adds i18n strings for en/zh, provides E2E test coverage, and documents scope boundaries.
Out of Scope Changes check ✅ Passed All code changes are directly aligned with the stated PR objectives and linked issue #502 scope. Visual refinements (folder icons, button alignment) and refactored group keying support the core rename/remove features. No unrelated refactors, dependencies, or generated files detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sidebar-project-rename-remove

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

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

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.

Comment thread packages/app/src/i18n/en.ts
Comment thread packages/app/src/i18n/zh.ts
Comment thread packages/app/src/pages/layout.tsx Outdated
Comment thread packages/app/src/pages/layout.tsx
Comment thread packages/app/src/pages/layout.tsx
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: 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

📥 Commits

Reviewing files that changed from the base of the PR and between 0782d4b and 022b6ee.

📒 Files selected for processing (10)
  • packages/app/e2e/sidebar/sidebar-project-actions.spec.ts
  • packages/app/src/components/dialog-remove-project.tsx
  • packages/app/src/i18n/en.ts
  • packages/app/src/i18n/zh.ts
  • packages/app/src/pages/layout.tsx
  • packages/app/src/pages/layout/layout-page-store.ts
  • packages/app/src/pages/layout/pawwork-session-nav.test.ts
  • packages/app/src/pages/layout/pawwork-session-nav.ts
  • packages/app/src/pages/layout/pawwork-session-source.ts
  • packages/app/src/pages/layout/pawwork-sidebar.tsx

Comment thread packages/app/src/pages/layout.tsx
Comment thread packages/app/src/pages/layout.tsx Outdated
Comment thread packages/app/src/pages/layout/pawwork-session-source.ts
Astro-Han added 5 commits May 10, 2026 13:54
- 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
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 (1)
packages/app/src/components/dialog-rename-project.tsx (1)

25-30: ⚡ Quick win

Log the error for debugging.

The catch block shows a user-friendly toast but discards the original error, making production debugging difficult. Add console.error to 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

📥 Commits

Reviewing files that changed from the base of the PR and between 022b6ee and 5cf2534.

📒 Files selected for processing (9)
  • packages/app/e2e/sidebar/sidebar-project-actions.spec.ts
  • packages/app/src/components/dialog-rename-project.tsx
  • packages/app/src/i18n/en.ts
  • packages/app/src/i18n/zh.ts
  • packages/app/src/pages/layout.tsx
  • packages/app/src/pages/layout/pawwork-session-nav.ts
  • packages/app/src/pages/layout/pawwork-sidebar-session-rows.test.ts
  • packages/app/src/pages/layout/pawwork-sidebar.tsx
  • packages/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

Astro-Han added 4 commits May 10, 2026 14:59
- 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
@Astro-Han Astro-Han added enhancement New feature or request P2 Medium priority app Application behavior and product flows ui Design system and user interface labels May 10, 2026
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 (1)
packages/app/src/pages/layout.tsx (1)

1119-1141: 💤 Low value

Optional: use path-based setStore instead of spread + reconcile.

hideProject/unhideProject rebuild the entire pawworkProjectHidden record on each toggle and then reconcile it. 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 in produce((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

📥 Commits

Reviewing files that changed from the base of the PR and between 5cf2534 and c97709f.

📒 Files selected for processing (5)
  • packages/app/e2e/sidebar/sidebar-project-actions.spec.ts
  • packages/app/src/components/dialog-rename-project.tsx
  • packages/app/src/pages/layout.tsx
  • packages/app/src/pages/layout/pawwork-sidebar.tsx
  • packages/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

@Astro-Han Astro-Han merged commit def9339 into dev May 10, 2026
20 checks passed
@Astro-Han Astro-Han deleted the feat/sidebar-project-rename-remove branch May 10, 2026 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application behavior and product flows enhancement New feature or request P2 Medium priority ui Design system and user interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Add project rename and delete actions to the sidebar

1 participant