From 060ca885bb303bb0477f34b2d5512cd5497b08fc Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 30 May 2026 12:33:46 -0700 Subject: [PATCH] Keep main workspace first in project groups (#3178) Co-authored-by: Jinwoo-H --- .../sidebar/worktree-list-groups.test.ts | 33 +++++++++++++++++++ .../sidebar/worktree-list-groups.ts | 13 +++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/components/sidebar/worktree-list-groups.test.ts b/src/renderer/src/components/sidebar/worktree-list-groups.test.ts index 6efe8a1a2ea..6dd20d0079f 100644 --- a/src/renderer/src/components/sidebar/worktree-list-groups.test.ts +++ b/src/renderer/src/components/sidebar/worktree-list-groups.test.ts @@ -638,6 +638,39 @@ describe('buildRows project grouping order', () => { ]) }) + it('keeps the main workspace first inside its project group', () => { + const main = { + ...wA, + id: 'wt-a-main', + displayName: 'main', + isMainWorktree: true + } + const freshChild = { + ...wA, + id: 'wt-a-fresh-child', + displayName: 'fresh-child', + isMainWorktree: false + } + const rows = buildRows( + 'repo', + [freshChild, wB, main], + map, + null, + new Set(), + undefined, + undefined, + 'visible-worktree-order' + ) + + expect(rows).toMatchObject([ + { type: 'header', key: 'repo:repo-a' }, + { type: 'item', worktree: { id: 'wt-a-main' } }, + { type: 'item', worktree: { id: 'wt-a-fresh-child' } }, + { type: 'header', key: 'repo:repo-b' }, + { type: 'item', worktree: { id: 'wt-b' } } + ]) + }) + it('keeps repoOrder for manual project group ordering', () => { const repoOrder = new Map([ [repoB.id, 0], diff --git a/src/renderer/src/components/sidebar/worktree-list-groups.ts b/src/renderer/src/components/sidebar/worktree-list-groups.ts index 5375e3b7570..0eeca8a6747 100644 --- a/src/renderer/src/components/sidebar/worktree-list-groups.ts +++ b/src/renderer/src/components/sidebar/worktree-list-groups.ts @@ -381,6 +381,16 @@ function appendWorktreeRows( } } +function orderMainWorktreeFirst(worktrees: Worktree[]): Worktree[] { + const mainWorktrees = worktrees.filter((worktree) => worktree.isMainWorktree) + if (mainWorktrees.length === 0) { + return worktrees + } + // Why: project groups are scanned by repo; keep the repo's canonical + // workspace anchored even when dynamic sorts rank a child workspace first. + return [...mainWorktrees, ...worktrees.filter((worktree) => !worktree.isMainWorktree)] +} + /** * Build the flat row list consumed by the virtualizer. * Extracted here to keep WorktreeList.tsx under the line-count lint limit. @@ -593,7 +603,8 @@ export function buildRows( result.push(buildImportedWorktreesCardRow(candidate, 'repo-group')) } } - appendWorktreeRows(result, group.items, repoMap, lineageById, worktreeMap, { + const items = groupBy === 'repo' ? orderMainWorktreeFirst(group.items) : group.items + appendWorktreeRows(result, items, repoMap, lineageById, worktreeMap, { nestLineage, collapsedGroups })