diff --git a/src/renderer/src/components/sidebar/WorktreeList.tsx b/src/renderer/src/components/sidebar/WorktreeList.tsx index ed36be3e4f8..a632336b9ae 100644 --- a/src/renderer/src/components/sidebar/WorktreeList.tsx +++ b/src/renderer/src/components/sidebar/WorktreeList.tsx @@ -91,6 +91,7 @@ import { PINNED_GROUP_KEY, buildRows, buildProjectGroupSidebarIndex, + findProjectGroupForRepo, getAmbiguousFolderWorkspaceSidebarIds, getProjectGroupHeaderKey, getProjectGroupMutationSelector, @@ -1477,13 +1478,13 @@ const VirtualizedWorktreeViewport = React.memo(function VirtualizedWorktreeViewp scrollAnchorRef }: VirtualizedWorktreeViewportProps) { const activeWorkspaceExecutionHostId = useAppStore((s) => s.activeWorkspaceExecutionHostId) + const projectGroupSidebarIndex = useMemo( + () => buildProjectGroupSidebarIndex(projectGroups), + [projectGroups] + ) const ambiguousFolderWorkspaceIds = useMemo( - () => - getAmbiguousFolderWorkspaceSidebarIds( - buildProjectGroupSidebarIndex(projectGroups), - folderWorkspaces - ), - [folderWorkspaces, projectGroups] + () => getAmbiguousFolderWorkspaceSidebarIds(projectGroupSidebarIndex, folderWorkspaces), + [folderWorkspaces, projectGroupSidebarIndex] ) const scrollRef = useRef(null) const suppressMeasurementAdjustmentUntilRef = useRef(0) @@ -1599,15 +1600,6 @@ const VirtualizedWorktreeViewport = React.memo(function VirtualizedWorktreeViewp const settings = useAppStore((s) => s.settings) const newCardStyle = settings?.experimentalNewWorktreeCardStyle === true const reorderRepos = useAppStore((s) => s.reorderRepos) - const folderBackedProjectGroupIds = useMemo( - () => - new Set( - projectGroups - .filter((group) => group.createdFrom === 'folder-scan') - .map((group) => group.id) - ), - [projectGroups] - ) const projectGroupByIdForHeaderDrag = useMemo( () => new Map(renderedProjectGroupsForHeaderDrag.map((group) => [group.id, group])), [renderedProjectGroupsForHeaderDrag] @@ -4930,10 +4922,10 @@ const VirtualizedWorktreeViewport = React.memo(function VirtualizedWorktreeViewp const lineageToggleGroupKey = itemRow.lineageGroupKey const experimentalNewWorktreeCardStyle = settings?.experimentalNewWorktreeCardStyle === true - const projectGroupId = itemRow.repo?.projectGroupId const isFolderBackedRepoChild = groupBy === 'repo' && - Boolean(projectGroupId && folderBackedProjectGroupIds.has(projectGroupId)) + findProjectGroupForRepo(projectGroupSidebarIndex, itemRow.repo, defaultHostId) + ?.createdFrom === 'folder-scan' // Why: experimental in-card lineage inherits the parent surface; legacy cards keep depth-based nested geometry. const paddingDepth = nested ? Math.max(0, itemRow.depth - 1) : itemRow.depth const getCardContentIndent = (lineageDepth: number): number => diff --git a/src/renderer/src/components/sidebar/project-group-header-dom.test.ts b/src/renderer/src/components/sidebar/project-group-header-dom.test.ts index 3de805ec64d..16ee1d03943 100644 --- a/src/renderer/src/components/sidebar/project-group-header-dom.test.ts +++ b/src/renderer/src/components/sidebar/project-group-header-dom.test.ts @@ -12,6 +12,7 @@ import type { FolderWorkspace, ProjectGroup, Repo, Worktree } from '../../../../ import { buildRows, buildProjectGroupSidebarIndex, + findProjectGroupForRepo, findProjectGroupForSidebarOwner, getAmbiguousFolderWorkspaceSidebarIds, getProjectGroupMutationSelector, @@ -165,6 +166,22 @@ describe('project-group sidebar identity', () => { expect(getProjectGroupSidebarIdentity(local)).not.toBe(getProjectGroupSidebarIdentity(runtime)) }) + it('keeps folder-backed card geometry scoped to the repo owner', () => { + const local = { ...sidebarIdentityGroup('same-id', 'local'), createdFrom: 'manual' as const } + const runtime = { + ...sidebarIdentityGroup('same-id', 'runtime:env-1'), + createdFrom: 'folder-scan' as const + } + const index = buildProjectGroupSidebarIndex([local, runtime]) + + expect(findProjectGroupForRepo(index, ownerHeaderRepo('local-repo', 'local'), 'local')).toBe( + local + ) + expect( + findProjectGroupForRepo(index, ownerHeaderRepo('runtime-repo', 'runtime:env-1'), 'local') + ).toBe(runtime) + }) + it('carries the exact owner from a rendered header into mutations', () => { const runtime = sidebarIdentityGroup('same-id', 'runtime:env-1')