From 8190cd572b6029a1ce090e02ad34fc26a556be0b Mon Sep 17 00:00:00 2001 From: brennanb2025 Date: Fri, 15 May 2026 01:29:01 -0700 Subject: [PATCH] Refine workspace lineage child chip Co-authored-by: Orca --- .../src/components/sidebar/WorktreeCard.tsx | 45 +++++++++++- .../src/components/sidebar/WorktreeList.tsx | 70 +++++-------------- 2 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/renderer/src/components/sidebar/WorktreeCard.tsx b/src/renderer/src/components/sidebar/WorktreeCard.tsx index a1615b8893a..5686c899421 100644 --- a/src/renderer/src/components/sidebar/WorktreeCard.tsx +++ b/src/renderer/src/components/sidebar/WorktreeCard.tsx @@ -3,10 +3,12 @@ import React, { useEffect, useMemo, useCallback, useState } from 'react' import { useShallow } from 'zustand/react/shallow' import { useAppStore } from '@/store' import { Badge } from '@/components/ui/badge' +import { Button } from '@/components/ui/button' import { Tooltip, TooltipTrigger, TooltipContent } from '@/components/ui/tooltip' import { AlertTriangle, Bell, + ChevronDown, GitMerge, LoaderCircle, CircleCheck, @@ -55,6 +57,9 @@ type WorktreeCardProps = { hideRepoBadge?: boolean parentLabel?: string lineageState?: 'valid' | 'missing' + lineageChildCount?: number + lineageCollapsed?: boolean + onLineageToggle?: (event: React.MouseEvent) => void onSelectionGesture?: (event: React.MouseEvent, worktreeId: string) => boolean onContextMenuSelect?: (event: React.MouseEvent) => readonly Worktree[] } @@ -74,7 +79,10 @@ const WorktreeCard = React.memo(function WorktreeCard({ onContextMenuSelect, hideRepoBadge, parentLabel, - lineageState + lineageState, + lineageChildCount = 0, + lineageCollapsed = false, + onLineageToggle }: WorktreeCardProps) { const openModal = useAppStore((s) => s.openModal) const updateWorktreeMeta = useAppStore((s) => s.updateWorktreeMeta) @@ -432,6 +440,13 @@ const WorktreeCard = React.memo(function WorktreeCard({ ) const unreadTooltip = worktree.isUnread ? 'Mark read' : 'Mark unread' + const childWorkspaceLabel = `${lineageChildCount} child ${ + lineageChildCount === 1 ? 'workspace' : 'workspaces' + }` + const childWorkspaceShortLabel = `${lineageChildCount} ${ + lineageChildCount === 1 ? 'child' : 'children' + }` + const showLineageChildChip = lineageChildCount > 0 && onLineageToggle !== undefined // Why: the 'unread' card property is the user's opt-out. When off, we render // as if the workspace is read so bold emphasis never appears. The persisted @@ -652,6 +667,34 @@ const WorktreeCard = React.memo(function WorktreeCard({ + {showLineageChildChip && ( + + + + + + {lineageCollapsed ? 'Show child workspaces' : 'Hide child workspaces'} + + + )} + {parentLabel && ( }) { continues ? ( ) : null )} }) { ) } -function LineageDisclosure({ - row, - onToggle -}: { - row: Extract - onToggle: (event: React.MouseEvent) => void -}) { - if (!row.lineageGroupKey || row.lineageChildCount <= 0) { - return null - } - - const label = `${row.lineageCollapsed ? 'Show' : 'Hide'} ${row.lineageChildCount} child ${ - row.lineageChildCount === 1 ? 'workspace' : 'workspaces' - }` - - return ( - - - - - - {row.lineageCollapsed ? 'Show child workspaces' : 'Hide child workspaces'} - - - ) -} - type VirtualizedWorktreeViewportProps = { rows: Row[] activeWorktreeId: string | null @@ -654,6 +615,8 @@ const VirtualizedWorktreeViewport = React.memo(function VirtualizedWorktreeViewp ) } + const lineageToggleGroupKey = row.lineageGroupKey + return (
0 && row.lineageState === 'valid' ? undefined : row.parentLabel } lineageState={row.lineageState} - /> - { - event.preventDefault() - event.stopPropagation() - if (row.lineageGroupKey) { - toggleGroup(row.lineageGroupKey) - } - }} + lineageChildCount={row.lineageChildCount} + lineageCollapsed={row.lineageCollapsed} + onLineageToggle={ + lineageToggleGroupKey + ? (event) => { + event.preventDefault() + event.stopPropagation() + toggleGroup(lineageToggleGroupKey) + } + : undefined + } />