Skip to content

feat(desktop): worktree bar refactor + open workspace modal base branch#438

Merged
AviPeltz merged 7 commits intomainfrom
scientific-toad-d97ce2
Dec 20, 2025
Merged

feat(desktop): worktree bar refactor + open workspace modal base branch#438
AviPeltz merged 7 commits intomainfrom
scientific-toad-d97ce2

Conversation

@AviPeltz
Copy link
Copy Markdown
Collaborator

@AviPeltz AviPeltz commented Dec 20, 2025

Description

Related Issues

Type of Change

  • Bug fix
  • [x ] New feature
  • Documentation
  • Refactor
  • Other (please describe):

Testing

Screenshots (if applicable)

Additional Notes

Summary by CodeRabbit

  • New Features

    • Add branch listing API and base-branch detection to support branch-aware workflows
    • Base branch selection added to New Workspace flow; baseBranch persisted on worktrees
  • UI/UX Improvements

    • Redesigned workspace header with integrated open-in app menu and path actions
    • Improved workspace tabs spacing and sidebar border for clearer layout
  • Removals / Simplifications

    • Removed legacy branch selector and standalone path display components
  • Documentation

    • Added notes on branch-workspace improvements and testing ideas

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 20, 2025

Walkthrough

Adds remote-aware branch tooling and UI: a new getBranches endpoint, enhanced git utilities (getDefaultBranch, detectBaseBranch, getCurrentBranch), workspace baseBranch lifecycle (create, persist, expose), NewWorkspaceModal branch picker, WorkspaceHeader consolidation, and related UI/export/layout changes.

Changes

Cohort / File(s) Summary
Projects router
apps/desktop/src/lib/trpc/routers/projects/projects.ts
New getBranches publicProcedure returning normalized local/remote branches with lastCommitDate and computed defaultBranch (with fallbacks and error handling).
Workspaces git utilities
apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts
Reworked getDefaultBranch with multi-fallbacks; added detectBaseBranch(worktreePath, currentBranch, defaultBranch) and getCurrentBranch(repoPath) exports for base-branch detection and current-branch retrieval.
Workspaces router
apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
Added optional baseBranch input to create; validates/fetches remote branch, sets/persists baseBranch on create and getActive (uses detectBaseBranch); exposes baseBranch in worktree payloads.
DB schema
apps/desktop/src/main/lib/db/schemas.ts
Worktree interface extended with optional `baseBranch?: string
New workspace UI
apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
Adds branch fetching (uses getBranches), searchable popover branch picker, loading/error handling, auto-default selection, and sends baseBranch in create payload.
WorkspaceHeader redesign
apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx
Replaces prior PathDisplay/BranchSelector pieces with an integrated header: branch/base-branch display, app-open dropdown, copy-path action, and TRPC-backed mutations.
Removed header subcomponents
apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/components/BranchSelector/*
apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/components/PathDisplay/*
Deleted BranchSelector and PathDisplay components and their index re-exports.
UI layout & visuals
apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
Moved WorkspaceHeader placement relative to ContentView; added sidebar right border styling and container sizing adjustments.
Workspace tab UI
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
Adjusted padding and conditionally hide delete/close button for branch workspaces; simplified tooltip/aria-label.
Open-in exports
apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
apps/desktop/src/renderer/components/OpenInButton/index.ts
Made APP_OPTIONS and JETBRAINS_OPTIONS public exports and re-exported alongside existing APIs.
Docs
apps/desktop/docs/BRANCH_WORKSPACE_IMPROVEMENTS.md
New docs describing further branch-workspace improvement ideas and testing notes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay extra attention to:
    • getDefaultBranch and detectBaseBranch logic (remote vs local fallbacks, merge-base/ahead-count calculations).
    • Workspaces create and getActive code paths that validate/fetch remote branches and persist baseBranch to DB.
    • New UI interactions in NewWorkspaceModal and WorkspaceHeader: TRPC calls, loading/error states, and selection propagation.
    • Removal of BranchSelector/PathDisplay and the integration correctness in the new header layout.

Possibly related PRs

Poem

🐰 I nibble branches, sniff the git, and hum,
I find the base where new worktrees come from.
Header stitched, old bits retired,
Base branches tracked and freshly wired.
Thump—new branches, hop to the drum!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete. It only contains the template structure with no actual details filled in—no description of changes, related issues, testing steps, or additional context provided. Fill in the Description section with details about the base branch feature and worktree bar refactor, add any related issues, describe testing performed, and provide additional context as needed.
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: a worktree bar refactor and base branch selection in the workspace modal, both of which are central to the changeset.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch scientific-toad-d97ce2

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.

@AviPeltz AviPeltz marked this pull request as ready for review December 20, 2025 03:24
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 (3)
apps/desktop/src/lib/trpc/routers/projects/projects.ts (2)

181-195: Consider wrapping git.branch(["-a"]) in try-catch for resilience.

If the repository path is invalid or inaccessible, this call will throw and propagate an unhandled error to the client. Other git operations in this procedure have try-catch blocks for graceful degradation.

Proposed fix
-				// Get all branches (local and remote)
-				const branchSummary = await git.branch(["-a"]);
-
-				const localBranches: string[] = [];
-				const remoteBranches: string[] = [];
-
-				for (const name of Object.keys(branchSummary.branches)) {
+				// Get all branches (local and remote)
+				let branchSummary;
+				try {
+					branchSummary = await git.branch(["-a"]);
+				} catch {
+					// If we can't get branches, return empty with default
+					const defaultBranch = project.defaultBranch ?? await getDefaultBranch(project.mainRepoPath);
+					return { branches: [], defaultBranch };
+				}
+
+				const localBranches: string[] = [];
+				const remoteBranches: string[] = [];
+
+				for (const name of Object.keys(branchSummary.branches)) {

212-235: Add defensive check for malformed git output lines.

If a line doesn't contain a space (unexpected format), lastSpaceIdx will be -1, causing substring(0, -1) to return an empty string and parseInt to return NaN. Consider adding a guard.

Proposed fix
 					for (const line of branchInfo.trim().split("\n")) {
 						if (!line) continue;
 						const lastSpaceIdx = line.lastIndexOf(" ");
+						if (lastSpaceIdx === -1) continue; // Skip malformed lines
 						let branch = line.substring(0, lastSpaceIdx);
 						const timestamp = Number.parseInt(
 							line.substring(lastSpaceIdx + 1),
 							10,
 						);
+						if (Number.isNaN(timestamp)) continue; // Skip if timestamp is invalid
apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx (1)

156-162: Consider cross-platform keyboard shortcut display.

The hardcoded ⌘O and ⌘⇧C shortcuts are macOS-specific. If the desktop app targets Windows/Linux, consider using a utility to render platform-appropriate shortcuts (e.g., Ctrl+O on Windows).

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2ecbc3 and 9c80f28.

📒 Files selected for processing (15)
  • apps/desktop/src/lib/trpc/routers/projects/projects.ts (1 hunks)
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts (2 hunks)
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts (7 hunks)
  • apps/desktop/src/main/lib/db/schemas.ts (1 hunks)
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx (9 hunks)
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx (2 hunks)
  • apps/desktop/src/renderer/components/OpenInButton/index.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx (2 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/components/BranchSelector/BranchSelector.tsx (0 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/components/BranchSelector/index.ts (0 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/components/PathDisplay/PathDisplay.tsx (0 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/components/PathDisplay/index.ts (0 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (1 hunks)
💤 Files with no reviewable changes (4)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/components/BranchSelector/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/components/BranchSelector/BranchSelector.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/components/PathDisplay/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/components/PathDisplay/PathDisplay.tsx
🧰 Additional context used
📓 Path-based instructions (10)
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx,js,jsx}: For Electron interprocess communication, ALWAYS use trpc as defined in src/lib/trpc
Use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.

Files:

  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/main/lib/db/schemas.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/components/OpenInButton/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid using any type in TypeScript - maintain type safety unless absolutely necessary

Files:

  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/main/lib/db/schemas.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/components/OpenInButton/index.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Run Biome for formatting, linting, import organization, and safe fixes at the root level using bun run lint:fix

Files:

  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/main/lib/db/schemas.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/components/OpenInButton/index.ts
**/{components,features}/**/[!.]*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Organize project structure with one folder per component: ComponentName/ComponentName.tsx with index.ts barrel export

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
**/{components,features}/**/*.{ts,tsx,test.ts,test.tsx,stories.tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Co-locate component dependencies (utils, hooks, constants, config, tests, stories) next to the file using them

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/components/OpenInButton/index.ts
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules in renderer process or shared code - use only in main process (src/main/)

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/components/OpenInButton/index.ts
apps/desktop/src/{main,renderer,preload}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use type-safe IPC communication - define channel types in apps/desktop/src/shared/ipc-channels.ts before implementing handlers

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/main/lib/db/schemas.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/components/OpenInButton/index.ts
**/*.{tsx,css}

📄 CodeRabbit inference engine (AGENTS.md)

Use React + TailwindCSS v4 + shadcn/ui for UI development

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
**/{components,features}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/{components,features}/**/*.tsx: Nest components in parent's components/ folder if used only once, promote to highest shared parent's components/ if used 2+ times
Use one component per file - do not combine multiple components in a single file

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
apps/desktop/src/main/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Accept object parameters in IPC handlers - do not use positional parameters in ipcMain.handle()

Files:

  • apps/desktop/src/main/lib/db/schemas.ts
🧠 Learnings (1)
📚 Learning: 2025-12-18T23:19:10.405Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T23:19:10.405Z
Learning: Applies to **/*.{tsx,css} : Use React + TailwindCSS v4 + shadcn/ui for UI development

Applied to files:

  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
🧬 Code graph analysis (5)
apps/desktop/src/lib/trpc/routers/projects/projects.ts (2)
apps/desktop/src/main/lib/db/index.ts (1)
  • db (69-76)
apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts (1)
  • getDefaultBranch (248-310)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (2)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/index.tsx (1)
  • ContentView (5-19)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx (1)
  • WorkspaceHeader (62-233)
apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx (1)
apps/desktop/src/renderer/components/OpenInButton/index.ts (2)
  • APP_OPTIONS (3-3)
  • JETBRAINS_OPTIONS (5-5)
apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts (1)
apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts (4)
  • hasOriginRemote (238-246)
  • branchExistsOnRemote (370-390)
  • fetchDefaultBranch (312-320)
  • detectBaseBranch (396-442)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx (3)
packages/ui/src/components/ui/tooltip.tsx (3)
  • Tooltip (76-76)
  • TooltipTrigger (76-76)
  • TooltipContent (76-76)
packages/ui/src/components/ui/button.tsx (1)
  • Button (60-60)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
🔇 Additional comments (23)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx (1)

13-13: LGTM! Clean styling enhancement.

The addition of border-r border-border/50 appropriately adds a subtle right border to the sidebar, following TailwindCSS and shadcn/ui conventions. The change enhances visual separation without affecting functionality.

apps/desktop/src/renderer/components/OpenInButton/OpenInButton.tsx (1)

47-71: LGTM!

The export visibility change for APP_OPTIONS and JETBRAINS_OPTIONS is appropriate. This enables reuse in WorkspaceHeader without duplicating the option definitions, maintaining a single source of truth for app configurations.

apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts (3)

251-309: LGTM!

The multi-fallback strategy for getDefaultBranch is well-designed, covering various scenarios:

  1. Remote repos with origin/HEAD
  2. Remote repos with common default branch names
  3. Remote repos via ls-remote
  4. Local-only repos using current branch
  5. Local-only repos with common branch names
  6. Ultimate fallback to "main"

The empty catch blocks are appropriate here since failures should cascade to the next fallback.


392-442: LGTM!

The detectBaseBranch implementation uses a sound heuristic: the base branch is likely the one with the smallest "ahead" commit count from the merge-base. The candidate list with deduplication and priority ordering is appropriate.


483-495: LGTM!

Clean implementation of getCurrentBranch with proper handling of detached HEAD state.

apps/desktop/src/main/lib/db/schemas.ts (1)

48-48: LGTM!

The optional baseBranch property with clear semantics (null = detection attempted but not found) is well-designed. The string | null type distinguishes between "not set" (undefined) and "explicitly no base branch" (null), which is useful for UI rendering logic.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (1)

133-138: LGTM!

The restructured layout correctly uses:

  • flex flex-col for vertical stacking
  • flex-1 min-h-0 on ContentView wrapper to prevent overflow and allow shrinking
  • WorkspaceHeader positioned at the bottom of the panel

This aligns with the PR's goal of integrating the header with the workspace content area.

apps/desktop/src/renderer/components/OpenInButton/index.ts (1)

1-7: LGTM!

Clean barrel export with alphabetically sorted named exports. The newly exposed APP_OPTIONS and JETBRAINS_OPTIONS are appropriately consumed by WorkspaceHeader.tsx for the app launcher dropdown.

apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx (6)

1-40: LGTM!

Imports are well-organized, using shadcn/ui components as per coding guidelines. No Node.js modules in renderer code.


67-95: LGTM!

State management and branch filtering are well implemented. The useMemo for filteredBranches has correct dependencies, and the query is properly gated on selectedProjectId.


104-115: LGTM!

The effects work together correctly: when the project changes, baseBranch resets to null, then re-auto-selects when the new branchData.defaultBranch loads. The biome-ignore comment appropriately documents the intentional dependency omission.


144-167: LGTM!

The workspace creation handler correctly passes baseBranch: baseBranch || undefined to convert null to undefined for the API contract.


308-400: LGTM!

Well-implemented branch picker using the Popover/Command pattern from shadcn/ui. Good UX touches: error state display, loading disabled state, default branch indicator, relative time for commits, and search reset on selection.


420-429: LGTM!

Disabling the Create button on branch loading errors is a reasonable conservative approach—if branches can't be loaded, there may be underlying git connectivity issues that would also affect workspace creation.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceHeader/WorkspaceHeader.tsx (4)

33-60: LGTM!

The path formatting utility handles both home directory substitution and .superset/worktrees truncation. The logic is defensive and covers edge cases where homeDir might be undefined.


62-79: LGTM!

Data fetching and mutations are well-structured. The cache invalidation on openInApp.onSuccess ensures the UI reflects the most recently used app.


81-94: LGTM!

Handlers are clean with appropriate null checks before mutations.


98-231: LGTM!

The JSX structure is well-organized with clear separation between branch info (left) and path/open controls (right). Good use of tooltips for discoverability and proper truncation handling for long paths/branch names.

apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts (4)

33-40: LGTM!

The baseBranch input is appropriately optional, maintaining backward compatibility with existing callers.


69-99: LGTM!

The base branch validation logic is solid:

  • Validates remote branch existence before use
  • Provides a clear user-facing error message
  • Silent fetch failure is acceptable since existence was already confirmed
  • Local-only repos correctly use the branch name without origin/ prefix

467-509: LGTM!

The lazy migration pattern for baseBranch detection is well-designed:

  • Uses undefined vs null semantics to distinguish "not attempted" from "attempted but not found"
  • Persists results to avoid repeated expensive git operations
  • Handles errors gracefully by persisting null to prevent infinite retries
  • Correctly handles repos without remotes

108-120: LGTM!

New worktrees correctly persist baseBranch: targetBranch, ensuring the base branch is always known for newly created workspaces.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx (1)

210-211: LGTM! Padding adjustments align with button visibility.

The conditional padding logic is correct: pr-6 for worktree workspaces accommodates the absolutely-positioned close button, while pr-2 for branch workspaces provides appropriate spacing when no button is present.

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 (2)
apps/desktop/docs/BRANCH_WORKSPACE_IMPROVEMENTS.md (2)

29-54: Clarify priority and scope of Low Priority items.

Items #5 (rename parameter), #6 (extract magic numbers), and #7 (lazy compute arrays) are minor refactors that could plausibly be addressed in this PR if they improve clarity or performance. Consider whether any should be promoted or explicitly deferred to a follow-up issue. Items #8#9 (UX polish) are clearly post-release.


56-64: Testing recommendations are valuable but underdeveloped.

The unit testing suggestion is solid, but the section lacks specificity on coverage expectations (e.g., are existing integration tests sufficient, or are new unit tests critical?). Recommend clarifying test priorities and whether any are blockers for this PR or post-release.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c80f28 and 4be2d2d.

📒 Files selected for processing (1)
  • apps/desktop/docs/BRANCH_WORKSPACE_IMPROVEMENTS.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
apps/desktop/docs/BRANCH_WORKSPACE_IMPROVEMENTS.md

[style] ~27-~27: To form a complete sentence, be sure to include a subject.
Context: ...s), the Create button is still enabled. Should be disabled with a helpful message. ##...

(MISSING_IT_THERE)


[style] ~44-~44: To form a complete sentence, be sure to include a subject.
Context: ...ilt but only used in the fallback path. Could be computed lazily for minor perf impro...

(MISSING_IT_THERE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (1)
apps/desktop/docs/BRANCH_WORKSPACE_IMPROVEMENTS.md (1)

1-3: Documentation is well-structured and actionable.

The file clearly categorizes improvement opportunities with precise file:line locations, making it straightforward for future issues/PRs to address these items. Well done organizing this as technical debt capture.

Comment on lines +5 to +27
## Medium Priority

### 1. Cache `hasOrigin` at project level
**Location**: `workspaces.ts:460`, `projects.ts`

Currently `hasOriginRemote()` is called on every `getActive` poll until base branch detection completes. Cache this at the project level in the database to avoid repeated git calls.

### 2. Race condition in worktree creation
**Location**: `workspaces.ts:78-86`

The branch existence check and the actual worktree creation are not atomic. If a branch is deleted between the check and use, it fails with a generic git error. Consider:
- Wrapping in a retry with exponential backoff
- Catching the specific git error and providing a clear message

### 3. `getDefaultBranch` for local repos uses current branch
**Location**: `git.ts:287-306`

For repos without a remote, `getDefaultBranch` returns the current branch. If the user is on a feature branch, that becomes the "default" for new worktrees, which may not be intended. Consider always preferring `main`/`master` if they exist locally.

### 4. Disable Create button when no branches available
**Location**: `NewWorkspaceModal.tsx`

If `getBranches` returns an empty array (e.g., new repo with no commits), the Create button is still enabled. Should be disabled with a helpful message.
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

Fix style issues in Medium Priority section.

Lines 27 and 44 contain incomplete sentences missing subjects. Additionally, clarify whether any of these medium-priority items are blocking the current PR or are intended as post-release improvements.

🔎 Proposed style fixes
- If `getBranches` returns an empty array (e.g., new repo with no commits), the Create button is still enabled. Should be disabled with a helpful message.
+ If `getBranches` returns an empty array (e.g., new repo with no commits), the Create button is still enabled and should be disabled with a helpful message.

- `localBranches` and `remoteBranches` arrays are always built but only used in the fallback path. Could be computed lazily for minor perf improvement.
+ `localBranches` and `remoteBranches` arrays are always built but only used in the fallback path and could be computed lazily for minor perf improvement.

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 LanguageTool

[style] ~27-~27: To form a complete sentence, be sure to include a subject.
Context: ...s), the Create button is still enabled. Should be disabled with a helpful message. ##...

(MISSING_IT_THERE)

🤖 Prompt for AI Agents
In apps/desktop/docs/BRANCH_WORKSPACE_IMPROVEMENTS.md around lines 5-27 (Medium
Priority section) there are style issues: complete the incomplete sentences at
lines 27 and 44 by adding clear subjects and verbs so each bullet reads as a
full sentence, remove or populate the empty "Proposed style fixes" details
block, and add one explicit sentence in the Medium Priority intro clarifying
whether these items are blocking the current PR or are intended as post-release
improvements.

@AviPeltz AviPeltz merged commit df9c1fc into main Dec 20, 2025
5 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

Service Status
Neon Database (Neon)

Thank you for your contribution! 🎉


Preview resources have been processed for cleanup

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