Skip to content

feat(desktop): rename branch from workspace hover card#3793

Merged
AviPeltz merged 1 commit intomainfrom
edit-branch-name-in-hover-card-modal
Apr 27, 2026
Merged

feat(desktop): rename branch from workspace hover card#3793
AviPeltz merged 1 commit intomainfrom
edit-branch-name-in-hover-card-modal

Conversation

@AviPeltz
Copy link
Copy Markdown
Collaborator

@AviPeltz AviPeltz commented Apr 27, 2026

Summary

  • Click a workspace's branch name in the hover card to open a rename modal; submit (or Enter) renames the local git branch via the host service.
  • GitHub external-link is split into its own icon so the branch text itself is always the rename trigger.
  • In the v2 dashboard sidebar, the rename also writes the new branch through the `v2Workspaces` optimistic action so the hover card reflects the new name immediately.

Test plan

  • Hover a worktree in the v2 dashboard sidebar, click the branch name, rename, verify hover card shows the new name without refresh.
  • Press Enter in the rename input and confirm it submits.
  • Click the GitHub external-link icon and confirm it still opens the branch on GitHub.
  • Try renaming a branch that has been pushed to remote and confirm the host-service error is surfaced via toast.
  • Repeat in the v1 workspace sidebar (collapsed and expanded list items) to confirm the dialog opens from both the hover card and the right-click hover surface.

Summary by cubic

Enable branch renaming directly from the workspace hover card. Clicking the branch name opens a modal to rename the local git branch, with GitHub open moved to a separate external-link icon.

  • New Features
    • Rename from the hover card in both v1 and v2 sidebars; Enter submits.
    • Renames the local branch via the host service; errors (e.g., pushed branches) show via toast.
    • GitHub open is now a separate icon; branch text always triggers rename.
    • V2 dashboard updates branch name optimistically via v2Workspaces, then invalidates queries on success.

Written for commit fff69c0. Summary will update on new commits.

Summary by CodeRabbit

  • New Features
    • Added branch renaming functionality directly from workspace sidebar hover cards and context menus
    • Users can edit branch names with input validation and automatic trimming
    • Rename operations display loading and success/error notifications
    • Successfully renamed branches update immediately across the application

Click the branch name in a workspace hover card to open a modal that
renames the local git branch via the host service. The GitHub external-
link icon is split out as a separate affordance so the branch name
itself is always the rename trigger.

In the v2 dashboard sidebar, the rename also writes the new branch
through the v2Workspaces optimistic action so the hover card reflects
the new name immediately without waiting for a manual refresh.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

📝 Walkthrough

Walkthrough

This change introduces branch renaming functionality across multiple workspace sidebar components. A new RenameBranchDialog component handles the rename operation, while existing hover-card and workspace item components are updated to expose edit-branch callbacks and conditionally render the dialog.

Changes

Cohort / File(s) Summary
Branch Rename Dialog
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx, RenameBranchDialog/index.ts
New dialog component for renaming local branches. Accepts workspaceId and currentBranchName, calls client.git.renameBranch.mutate, invalidates caches on success, and invokes optional onAfterRename callback.
Dashboard Sidebar Components
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx, DashboardSidebarWorkspaceHoverCardContent/DashboardSidebarWorkspaceHoverCardContent.tsx
Adds renameBranchTarget state tracking and passes onEditBranchClick callback to hover card. Hover card now renders pencil-icon edit button alongside branch display and independent external-link icon for remote branches.
Workspace Sidebar Items
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/CollapsedWorkspaceItem.tsx, WorkspaceContextMenu.tsx, WorkspaceHoverCard/WorkspaceHoverCard.tsx
Integrates branch rename capability by managing renameBranchTarget state and conditionally rendering RenameBranchDialog. Updates hover card UI to show edit button for branches with pencil icon.
Module Exports
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/index.ts
Adds RenameBranchDialog to module exports alongside existing components.

Sequence Diagram

sequenceDiagram
    actor User
    participant HoverCard as Hover Card
    participant Parent as Parent Component
    participant Dialog as Rename Dialog
    participant API as Git API
    participant Cache as Cache/Store

    User->>HoverCard: Click pencil icon on branch
    HoverCard->>Parent: onEditBranchClick(branchName)
    Parent->>Parent: setRenameBranchTarget(branchName)
    Parent->>Dialog: Render with renameBranchTarget
    User->>Dialog: Enter new branch name & submit
    Dialog->>API: client.git.renameBranch.mutate({workspaceId, oldName, newName})
    API-->>Dialog: Success
    Dialog->>Cache: Invalidate worktree/workspace caches
    Dialog->>Parent: onAfterRename(newName)
    Parent->>Parent: setRenameBranchTarget(null)
    Dialog->>Dialog: Close
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 With whiskers and will, branches find new names,
Pencil-icons sparkle in the sidebar games,
Dialogs bloom open, ready to play,
Rename branches in a hoppy-skippy way! 🌱✨

🚥 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 clearly and concisely summarizes the main feature: enabling branch renaming from the workspace hover card.
Description check ✅ Passed The description covers the main objective, test plan, and feature details, though the template sections (Related Issues, Type of Change, Testing, Screenshots) are not formally completed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch edit-branch-name-in-hover-card-modal

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 27, 2026

Greptile Summary

This PR adds a rename-branch flow accessible from workspace hover cards in both the v1 and v2 sidebars. Clicking the branch name opens a new RenameBranchDialog that calls the host-service git RPC, surfaces errors via toast, and invalidates relevant query caches; the v2 dashboard path additionally applies an optimistic update so the hover card reflects the new name immediately.

Confidence Score: 5/5

Safe to merge; all remaining findings are P2 style/robustness suggestions.

No P0 or P1 issues found. The double-submission window is real but requires a simultaneous Enter+click before a single React re-render, and is guarded visually by the disabled button state. The redundant open prop is cosmetic. Core rename flow, optimistic updates, cache invalidation, and error surfacing are all correct.

RenameBranchDialog.tsx — minor ordering of setIsSubmitting.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx New dialog component for renaming a git branch; has a narrow double-submission window because setIsSubmitting(true) is placed after the RPC call starts.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx Wires rename-branch dialog + optimistic branch update for the v2 dashboard sidebar; redundant open={renameBranchTarget !== null} in conditional render blocks.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceHoverCardContent/DashboardSidebarWorkspaceHoverCardContent.tsx Splits GitHub external link from branch text and adds rename-trigger button + pencil icon; logic is clean.
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/CollapsedWorkspaceItem.tsx Adds rename-branch dialog to v1 collapsed item; no onAfterRename callback (intentional – relies on cache invalidation).
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceContextMenu.tsx Mirrors the same rename-dialog wiring for the v1 context-menu hover surface; consistent with CollapsedWorkspaceItem.
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx Splits GitHub external-link icon from branch text; branchName is guarded by {branchName && ...} so the rename callback is safe.
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/index.ts Barrel export for the new RenameBranchDialog component.
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/index.ts Re-exports RenameBranchDialog from the components barrel; straightforward addition.

Sequence Diagram

sequenceDiagram
    participant User
    participant HoverCard
    participant RenameBranchDialog
    participant HostService
    participant QueryCache
    participant OptimisticStore

    User->>HoverCard: Click branch name
    HoverCard->>RenameBranchDialog: onEditBranchClick(branchName)
    RenameBranchDialog-->>User: Open dialog (pre-filled)
    User->>RenameBranchDialog: Type new name, submit
    RenameBranchDialog->>HostService: git.renameBranch.mutate(workspaceId, oldName, newName)
    HostService-->>RenameBranchDialog: success / error
    alt Success
        RenameBranchDialog->>OptimisticStore: updateWorkspace(id, { branch: newName }) [v2 only]
        RenameBranchDialog->>QueryCache: invalidate getWorktreeInfo, get, getAllGrouped
        RenameBranchDialog-->>User: toast Branch renamed
        RenameBranchDialog->>RenameBranchDialog: onOpenChange(false)
    else Error
        RenameBranchDialog-->>User: toast error message
    end
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx
Line: 46-68

Comment:
**`setIsSubmitting` called after async operation begins**

`setIsSubmitting(true)` is set after `toast.promise(renamePromise, ...)` starts and the RPC call is already in-flight. Because `isSubmitting` is React state (not a ref), if `handleSubmit` is invoked twice before the first re-render (e.g. Enter key + button click in the same tick), both calls pass the `if (isSubmitting) return` guard and two concurrent rename mutations fire. Moving `setIsSubmitting(true)` above the `client.git.renameBranch.mutate` call would close the window.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx
Line: 167-177

Comment:
**Redundant `open` prop inside conditional render**

`renameBranchTarget !== null` is always `true` inside the `{renameBranchTarget && ...}` guard, so `open` is a constant `true` here. The same pattern appears in the second return path (line ~253) and in `CollapsedWorkspaceItem.tsx` / `WorkspaceContextMenu.tsx`. Consider either always rendering the dialog and driving visibility purely through `open={!!renameBranchTarget}`, or simplifying to `open={true}` inside the guard.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat(desktop): rename branch from worksp..." | Re-trigger Greptile

Comment on lines +46 to +68
const handleSubmit = async () => {
if (isInvalid || isSubmitting) return;
if (!activeHostUrl) {
toast.error("Host service is not available");
return;
}

const client = getHostServiceClientByUrl(activeHostUrl);
const renamePromise = client.git.renameBranch.mutate({
workspaceId,
oldName: currentBranchName,
newName: trimmed,
});

toast.promise(renamePromise, {
loading: `Renaming branch to ${trimmed}...`,
success: `Branch renamed to ${trimmed}`,
error: (err) =>
err instanceof Error ? err.message : "Failed to rename branch",
});

setIsSubmitting(true);
try {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 setIsSubmitting called after async operation begins

setIsSubmitting(true) is set after toast.promise(renamePromise, ...) starts and the RPC call is already in-flight. Because isSubmitting is React state (not a ref), if handleSubmit is invoked twice before the first re-render (e.g. Enter key + button click in the same tick), both calls pass the if (isSubmitting) return guard and two concurrent rename mutations fire. Moving setIsSubmitting(true) above the client.git.renameBranch.mutate call would close the window.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx
Line: 46-68

Comment:
**`setIsSubmitting` called after async operation begins**

`setIsSubmitting(true)` is set after `toast.promise(renamePromise, ...)` starts and the RPC call is already in-flight. Because `isSubmitting` is React state (not a ref), if `handleSubmit` is invoked twice before the first re-render (e.g. Enter key + button click in the same tick), both calls pass the `if (isSubmitting) return` guard and two concurrent rename mutations fire. Moving `setIsSubmitting(true)` above the `client.git.renameBranch.mutate` call would close the window.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +167 to +177
{renameBranchTarget && (
<RenameBranchDialog
workspaceId={id}
currentBranchName={renameBranchTarget}
open={renameBranchTarget !== null}
onOpenChange={(open) => {
if (!open) setRenameBranchTarget(null);
}}
onAfterRename={handleAfterBranchRename}
/>
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Redundant open prop inside conditional render

renameBranchTarget !== null is always true inside the {renameBranchTarget && ...} guard, so open is a constant true here. The same pattern appears in the second return path (line ~253) and in CollapsedWorkspaceItem.tsx / WorkspaceContextMenu.tsx. Consider either always rendering the dialog and driving visibility purely through open={!!renameBranchTarget}, or simplifying to open={true} inside the guard.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx
Line: 167-177

Comment:
**Redundant `open` prop inside conditional render**

`renameBranchTarget !== null` is always `true` inside the `{renameBranchTarget && ...}` guard, so `open` is a constant `true` here. The same pattern appears in the second return path (line ~253) and in `CollapsedWorkspaceItem.tsx` / `WorkspaceContextMenu.tsx`. Consider either always rendering the dialog and driving visibility purely through `open={!!renameBranchTarget}`, or simplifying to `open={true}` inside the guard.

How can I resolve this? If you propose a fix, please make it concise.

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: 1

🧹 Nitpick comments (4)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx (2)

46-82: Consider basic client-side validation of the new branch name.

trimmed is sent straight to client.git.renameBranch.mutate with only empty/unchanged checks. Git refuses many names (whitespace, .., leading -, control chars, ending in .lock, etc.). Without a client check, users hit a backend error toast for trivial typos. Optionally add a quick git check-ref-format-style guard or at least disable submit on whitespace/- prefix:

-	const isInvalid = trimmed.length === 0 || isUnchanged;
+	const hasInvalidChars = /[\s~^:?*\[\\]/.test(trimmed) || trimmed.startsWith("-");
+	const isInvalid = trimmed.length === 0 || isUnchanged || hasInvalidChars;

If the backend already rejects with a friendly message, feel free to ignore — just flagging for UX consideration.

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

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx`
around lines 46 - 82, The submit flow in handleSubmit sends trimmed directly to
client.git.renameBranch.mutate without validating Git ref rules; add a
client-side validation step (e.g., a git-ref-check helper or simple guards for
empty, only-whitespace, leading '-', '..' segments, control chars, names ending
with '.lock', and other invalid patterns) and use that to set isInvalid/disable
the submit button and show a clear toast.error message before calling
client.git.renameBranch.mutate; update handleSubmit to return early on
validation failure and reference trimmed, isInvalid/isSubmitting, and
client.git.renameBranch.mutate when making this change.

38-40: Optional: select the branch name on focus and avoid resetting input on prop changes mid-edit.

Two small UX/edge cases:

  1. With autoFocus, the cursor lands at the end of the value but the existing name is not selected, so users must clear the field manually before typing. Selecting the text on open is a more typical rename UX (e.g., inputRef.current?.select()).
  2. The effect resets value to currentBranchName whenever currentBranchName changes while open is true. If a parent triggers a re-render with an updated branch name (e.g., from an upstream cache invalidation) while the user is mid-edit, their input gets wiped. Gating the reset on open transitions only would be safer:
♻️ Proposed reset-on-open
-	useEffect(() => {
-		if (open) setValue(currentBranchName);
-	}, [open, currentBranchName]);
+	useEffect(() => {
+		if (open) setValue(currentBranchName);
+		// Intentionally only resync when the dialog (re)opens, not on every
+		// currentBranchName change, to avoid wiping the user's in-flight edit.
+		// eslint-disable-next-line react-hooks/exhaustive-deps
+	}, [open]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx`
around lines 38 - 40, The effect that currently runs useEffect(() => { if (open)
setValue(currentBranchName); }, [open, currentBranchName]) will reset the input
whenever currentBranchName changes while the dialog is open and also doesn't
select the text on focus; update RenameBranchDialog to (1) only reset value when
the dialog is opened (i.e., when open transitions false→true) instead of on
every currentBranchName change while open, and (2) after setting the value on
open call inputRef.current?.select() (or select on the input's onFocus) so the
existing branch name is highlighted for immediate replacement; locate the
useEffect, the open and currentBranchName props, setValue, and the
inputRef/autoFocus usage to implement these changes.
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx (1)

88-99: Minor: pencil icon should be marked decorative for assistive tech.

The <button>'s accessible name will currently include both the branch text and the unlabeled LuPencil SVG. Add aria-hidden to the icon (and an explicit aria-label on the button if you want screen reader output independent of branch length). Same applies to the LuExternalLink link below.

-								<LuPencil
-									className="size-3 shrink-0 opacity-0 group-hover/branch:opacity-100 transition-opacity"
-									strokeWidth={STROKE_WIDTH}
-								/>
+								<LuPencil
+									aria-hidden
+									className="size-3 shrink-0 opacity-0 group-hover/branch:opacity-100 transition-opacity"
+									strokeWidth={STROKE_WIDTH}
+								/>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx`
around lines 88 - 99, The pencil SVG LuPencil inside the branch rename button is
being exposed to assistive tech and should be marked decorative; update the
WorkspaceHoverCard component to add aria-hidden="true" to LuPencil (and
similarly add aria-hidden="true" to the LuExternalLink icon used for the
external link), and add an explicit accessible name for the button by adding an
aria-label on the button that calls onEditBranchClick (e.g., aria-label={`Rename
${branchName}`}) so the screen reader receives a clear label independent of
branch text; locate the branch rename button (onClick handler onEditBranchClick,
class group/branch, using STROKE_WIDTH) and the external link containing
LuExternalLink to make these changes.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceHoverCardContent/DashboardSidebarWorkspaceHoverCardContent.tsx (1)

69-99: DRY: this branch row is duplicated with WorkspaceHoverCard.tsx.

The branch-row JSX (rename button with hover-revealed pencil + conditional GitHub external-link) is now an exact structural twin of the equivalent block in apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx (lines 86–122). Worth extracting into a shared component (e.g., WorkspaceHoverCardBranchRow({ branch, repoUrl, branchExistsOnRemote, hasCustomAlias, onEditBranchClick })) so future tweaks (a11y, styling, validation) don't have to be applied in two places.

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

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceHoverCardContent/DashboardSidebarWorkspaceHoverCardContent.tsx`
around lines 69 - 99, The branch-row JSX is duplicated; extract it into a shared
component (e.g., WorkspaceHoverCardBranchRow) that accepts props: branch,
repoUrl, branchExistsOnRemote, hasCustomAlias, onEditBranchClick, and implements
the same behavior (rename button with hover pencil, conditional external link,
same classNames and stopPropagation). Create the new component and replace the
duplicated blocks in DashboardSidebarWorkspaceHoverCardContent and
WorkspaceHoverCard.tsx with <WorkspaceHoverCardBranchRow {...} /> (or equivalent
import/use), preserving prop names and event handler semantics so styling, a11y,
and logic remain identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx`:
- Around line 86-122: The rename/branch edit button in WorkspaceHoverCard is
only reachable via mouse hover (onEditBranchClick inside WorkspaceHoverCard),
which blocks keyboard/right-click users; add a "Rename Branch" menu item to the
workspace context menus so it calls the same setter used by the hover action
(setRenameBranchTarget(branchName)). Update WorkspaceContextMenu and
DashboardSidebarWorkspaceContextMenu (and any collapsed-item context menus) to
include a "Rename Branch" entry that invokes setRenameBranchTarget(branchName)
or delegates to the same handler used by onEditBranchClick, ensuring the branch
rename action is available from keyboard-accessible context menus and wired to
existing branchName state.

---

Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceHoverCardContent/DashboardSidebarWorkspaceHoverCardContent.tsx`:
- Around line 69-99: The branch-row JSX is duplicated; extract it into a shared
component (e.g., WorkspaceHoverCardBranchRow) that accepts props: branch,
repoUrl, branchExistsOnRemote, hasCustomAlias, onEditBranchClick, and implements
the same behavior (rename button with hover pencil, conditional external link,
same classNames and stopPropagation). Create the new component and replace the
duplicated blocks in DashboardSidebarWorkspaceHoverCardContent and
WorkspaceHoverCard.tsx with <WorkspaceHoverCardBranchRow {...} /> (or equivalent
import/use), preserving prop names and event handler semantics so styling, a11y,
and logic remain identical.

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx`:
- Around line 46-82: The submit flow in handleSubmit sends trimmed directly to
client.git.renameBranch.mutate without validating Git ref rules; add a
client-side validation step (e.g., a git-ref-check helper or simple guards for
empty, only-whitespace, leading '-', '..' segments, control chars, names ending
with '.lock', and other invalid patterns) and use that to set isInvalid/disable
the submit button and show a clear toast.error message before calling
client.git.renameBranch.mutate; update handleSubmit to return early on
validation failure and reference trimmed, isInvalid/isSubmitting, and
client.git.renameBranch.mutate when making this change.
- Around line 38-40: The effect that currently runs useEffect(() => { if (open)
setValue(currentBranchName); }, [open, currentBranchName]) will reset the input
whenever currentBranchName changes while the dialog is open and also doesn't
select the text on focus; update RenameBranchDialog to (1) only reset value when
the dialog is opened (i.e., when open transitions false→true) instead of on
every currentBranchName change while open, and (2) after setting the value on
open call inputRef.current?.select() (or select on the input's onFocus) so the
existing branch name is highlighted for immediate replacement; locate the
useEffect, the open and currentBranchName props, setValue, and the
inputRef/autoFocus usage to implement these changes.

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx`:
- Around line 88-99: The pencil SVG LuPencil inside the branch rename button is
being exposed to assistive tech and should be marked decorative; update the
WorkspaceHoverCard component to add aria-hidden="true" to LuPencil (and
similarly add aria-hidden="true" to the LuExternalLink icon used for the
external link), and add an explicit accessible name for the button by adding an
aria-label on the button that calls onEditBranchClick (e.g., aria-label={`Rename
${branchName}`}) so the screen reader receives a clear label independent of
branch text; locate the branch rename button (onClick handler onEditBranchClick,
class group/branch, using STROKE_WIDTH) and the external link containing
LuExternalLink to make these changes.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: ee9b3485-bb2f-4076-8cc6-c7425e98eff8

📥 Commits

Reviewing files that changed from the base of the PR and between 693dd29 and fff69c0.

📒 Files selected for processing (8)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceHoverCardContent/DashboardSidebarWorkspaceHoverCardContent.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/CollapsedWorkspaceItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceContextMenu.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/index.ts

Comment on lines +86 to +122
<div className="flex items-center gap-1.5">
{onEditBranchClick ? (
<button
type="button"
onClick={() => onEditBranchClick(branchName)}
className={`group/branch flex min-w-0 flex-1 items-center gap-1 font-mono break-all text-left hover:text-foreground hover:underline ${hasCustomAlias ? "text-xs" : "text-sm"}`}
title="Rename branch"
>
<span className="break-all">{branchName}</span>
<LuPencil
className="size-3 shrink-0 opacity-0 group-hover/branch:opacity-100 transition-opacity"
strokeWidth={STROKE_WIDTH}
/>
</button>
) : (
<code
className={`font-mono break-all block min-w-0 flex-1 ${hasCustomAlias ? "text-xs" : "text-sm"}`}
>
{branchName}
</code>
)}
{repoUrl && branchExistsOnRemote && (
<a
href={`${repoUrl}/tree/${branchName}`}
target="_blank"
rel="noopener noreferrer"
className="shrink-0 text-muted-foreground hover:text-foreground"
title="Open branch on GitHub"
onClick={(e) => e.stopPropagation()}
>
<LuExternalLink
className="size-3"
strokeWidth={STROKE_WIDTH}
/>
</a>
)}
</div>
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.

⚠️ Potential issue | 🟡 Minor

Rename action is only reachable via mouse hover.

The rename trigger now lives exclusively inside HoverCardContent, which is opened by mouse hover on the workspace item. Keyboard-only users (tabbing through the sidebar) have no way to surface the hover card and therefore cannot rename the branch — there is no equivalent entry in WorkspaceContextMenu's menu items (the existing "Rename" menu item targets the workspace alias, not the branch). This also applies to the dashboard sidebar variant.

Consider adding a "Rename Branch" item to WorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu (and the collapsed-item context menus) that calls the same setRenameBranchTarget(branchName) setter, so the action is reachable via right-click / keyboard.

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

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx`
around lines 86 - 122, The rename/branch edit button in WorkspaceHoverCard is
only reachable via mouse hover (onEditBranchClick inside WorkspaceHoverCard),
which blocks keyboard/right-click users; add a "Rename Branch" menu item to the
workspace context menus so it calls the same setter used by the hover action
(setRenameBranchTarget(branchName)). Update WorkspaceContextMenu and
DashboardSidebarWorkspaceContextMenu (and any collapsed-item context menus) to
include a "Rename Branch" entry that invokes setRenameBranchTarget(branchName)
or delegates to the same handler used by onEditBranchClick, ensuring the branch
rename action is available from keyboard-accessible context menus and wired to
existing branchName state.

@AviPeltz AviPeltz merged commit 2183bcf into main Apr 27, 2026
7 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch

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.

1 participant