@@ -330,7 +334,7 @@ function Card({
nativeDragEnabled={false}
lineageChildCount={childCount}
lineageCollapsed={collapsed}
- lineageHiddenDescendantIds={hiddenDescendantIds}
+ lineageDescendantIds={descendantIds}
lineageChildren={children}
onLineageToggle={childCount > 0 ? noop : undefined}
/>
@@ -348,10 +352,8 @@ const nestedWorktrees = worktreesFor(NESTED, now)
FOLDER_WORKSPACE.isUnread = false
FOLDER_WORKSPACE.lastActivityAt = now - 9 * MINUTE
-export const exceptions = defineFixture({
- width: SIDEBAR_WIDTH,
- setup: () => seedWorkspaces(FLAT, now),
- render: () => (
+function FlatList(): React.JSX.Element {
+ return (
{FLAT.map((seed) => (
)
+}
+
+export const exceptions = defineFixture({
+ width: SIDEBAR_WIDTH,
+ setup: () => seedWorkspaces(FLAT, now),
+ render: () =>
})
export const nesting = defineFixture({
@@ -370,8 +378,17 @@ export const nesting = defineFixture({
setup: () => seedWorkspaces(NESTED, now),
render: () => (
-
-
+
+
@@ -379,8 +396,23 @@ export const nesting = defineFixture({
worktree={nestedWorktrees.get('wt-collapsed-parent')!}
childCount={1}
collapsed
- hiddenDescendantIds={['wt-collapsed-child']}
+ descendantIds={['wt-collapsed-child']}
/>
)
})
+
+export const agentsExpanded = defineFixture({
+ width: SIDEBAR_WIDTH,
+ setup: () => {
+ seedWorkspaces(FLAT, now)
+ const none = new Set
()
+ const state = {
+ expandedLineageParents: none,
+ expandedIdleChildGroups: none,
+ compactRootListExpanded: true
+ }
+ FLAT.forEach((seed) => agentExpansion.seedWorktreeAgentExpansionStateForTests(seed.id, state))
+ },
+ render: () =>
+})
diff --git a/src/renderer/src/components/sidebar/WorktreeCardSlotContent.tsx b/src/renderer/src/components/sidebar/WorktreeCardSlotContent.tsx
index de53bdcb4d2..ba3fc9499b1 100644
--- a/src/renderer/src/components/sidebar/WorktreeCardSlotContent.tsx
+++ b/src/renderer/src/components/sidebar/WorktreeCardSlotContent.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react'
+import React, { useCallback, useMemo } from 'react'
import { ChevronDown, ChevronRight } from 'lucide-react'
import { useShallow } from 'zustand/react/shallow'
@@ -14,7 +14,7 @@ import { agentRowDisplayDotState as getAgentDotState } from '@/lib/agent-row-dot
import { WorktreeCardIdentityHover } from './worktree-card-identity-hover'
import type { WorktreeCardPresentation } from './workspace-card/surface/worktree-card-presentation'
import { WorktreeCardSecondaryRows } from './workspace-card/surface/worktree-card-secondary-rows'
-import { useCollapsedLineageSlot } from './worktree-card-slot-rollup'
+import { useCollapsedLineageSlot, useLineageLatestAt } from './worktree-card-slot-rollup'
import {
classifySlotLine,
compareSlotLines,
@@ -26,9 +26,21 @@ import {
WorktreeCardRenameFailedButton
} from './worktree-card-title-actions'
import { WorktreeCardSlot } from './WorktreeCardSlot'
-import { WorktreeCardSlotAgentLines, type SlotAgentLine } from './WorktreeCardSlotAgentLines'
+import { useWorktreeAgentExpansionState } from './workspace-card/activity/worktree-card-agents-expansion-state'
+import {
+ CompactAgentExpansion,
+ CompactAgentSummaryButton
+} from './workspace-card/activity/worktree-card-compact-agents'
+import { dispatchSuppressScrollAdjustment } from './workspace-card/activity/WorktreeCardAgents'
+import { translate } from '@/i18n/i18n'
+import {
+ SlotAgentLinesHeader,
+ WorktreeCardSlotAgentLines,
+ type SlotAgentLine
+} from './WorktreeCardSlotAgentLines'
import { shouldBeginWorktreeRename } from './workspace-card/controller/worktree-card-model'
import { WorktreeTitleInlineRename } from './workspace-card/identity/WorktreeTitleInlineRename'
+import { WorktreeCardMetaRow } from './workspace-card/metadata/worktree-card-meta-row'
const NO_DESCENDANTS: readonly string[] = []
@@ -79,42 +91,82 @@ export function WorktreeCardSlotContent({
showDeleteQuickAction,
showLineageChildChip,
lineageCollapsed,
- lineageHiddenDescendantIds,
+ lineageDescendantIds,
onLineageToggle,
lineageChildAriaLabel,
- childWorkspaceShortLabel
+ childWorkspaceShortLabel,
+ settings
} = card
const lines = useSlotAgentLines(worktree.id)
const now = useNow(30_000)
const hasLiveMarker = useAppStore((s) => workspaceHasLiveMarker(s, worktree.id))
// A flag with no tab or agent marker behind it was set by the user.
const manualUnread = worktree.isUnread && !hasLiveMarker
+ const descendantIds = lineageDescendantIds ?? NO_DESCENDANTS
const collapsedLineage = useCollapsedLineageSlot(
- lineageCollapsed ? (lineageHiddenDescendantIds ?? NO_DESCENDANTS) : NO_DESCENDANTS
+ lineageCollapsed ? descendantIds : NO_DESCENDANTS
)
- const ownLinesShown = showInlineAgentList && lines.length > 0
+ const lineageLatestAt = useLineageLatestAt(descendantIds)
+ // Several agents fold into the 1.0 summary row; the title slot speaks for them until expanded.
+ const { compactRootListExpanded: agentsExpanded, toggleCompactRootList } =
+ useWorktreeAgentExpansionState(worktree.id)
+ const toggleAgents = useCallback(() => {
+ dispatchSuppressScrollAdjustment()
+ toggleCompactRootList()
+ }, [toggleCompactRootList])
+ const showLines = showInlineAgentList && lines.length > 0
+ const foldsAgents = showLines && lines.length > 1
+ const ownLinesShown = showLines && (!foldsAgents || agentsExpanded)
const titleSlot = titleRowSlot({
offline: isRuntimeDisconnected,
hiddenLines: ownLinesShown ? [] : lines.map((line) => line.signal),
collapsedLineage,
manualUnread,
ownLinesShown,
- lastActivityAt: worktree.lastActivityAt > 0 ? worktree.lastActivityAt : null
+ lastActivityAt: worktree.lastActivityAt > 0 ? worktree.lastActivityAt : null,
+ lineageLatestAt
})
+ const showDetailsRow =
+ settings?.worktreeCardDetailsRow === true &&
+ (presentation.hasMetaRow || presentation.detailsAndPorts !== null)
const titleBold = manualUnread || lines.some((line) => line.signal.kind === 'unread')
+ const agentLines = showLines ? (
+
+ ) : null
+
+ const agentCountLabel = translate('sidebar.agentSummary.agentCount', '{{count}} agents', {
+ count: lines.length,
+ defaultValue_one: '{{count}} agent'
+ })
const slotRows = (
<>
- {ownLinesShown ? (
-
- ) : null}
+ {foldsAgents ? (
+ <>
+ {agentsExpanded ? (
+
+ ) : (
+
+ line.agent)}
+ subjectLabel={agentCountLabel}
+ expanded={false}
+ onToggle={toggleAgents}
+ />
+
+ )}
+ {agentLines}
+ >
+ ) : (
+ agentLines
+ )}
{showLineageChildChip ? (
-
+