diff --git a/src/renderer/src/components/status-bar/WorkspaceSpaceManagerPanel.tsx b/src/renderer/src/components/status-bar/WorkspaceSpaceManagerPanel.tsx index adf5a28f2e8..0fa98ec3ac6 100644 --- a/src/renderer/src/components/status-bar/WorkspaceSpaceManagerPanel.tsx +++ b/src/renderer/src/components/status-bar/WorkspaceSpaceManagerPanel.tsx @@ -66,6 +66,8 @@ import { buildTreemapLayout, type TreemapRect } from './workspace-space-layout' import { filterWorkspaceSpaceRows, countWorkspaceSpaceActiveAgents, + getLargestWorkspaceSpaceItemSize, + getLargestWorkspaceSpaceRowSize, getSelectedDeletableWorkspaceIds, getVisibleDeletableWorkspaceIds, getWorkspaceSpaceGitStatusRefreshCandidates, @@ -831,7 +833,7 @@ function BreakdownList({ ) } - const maxChildSize = Math.max(...worktree.topLevelItems.map((item) => item.sizeBytes), 0) + const maxChildSize = getLargestWorkspaceSpaceItemSize(worktree.topLevelItems) const topLevelItemCount = worktree.topLevelItems.length + worktree.omittedTopLevelItemCount return (
@@ -1276,7 +1278,7 @@ export function WorkspaceSpaceManagerPanel(): React.JSX.Element { const zoomedWorktree = sourceRows.find((row) => row.worktreeId === treemapZoomWorktreeId && row.status === 'ok') ?? null - const maxSize = Math.max(...rows.map((row) => row.sizeBytes), 0) + const maxSize = getLargestWorkspaceSpaceRowSize(rows) const selectedDeletableIds = useMemo( () => getSelectedDeletableWorkspaceIds(rows, selectedIds, isWorktreeUnavailableForDelete), [isWorktreeUnavailableForDelete, rows, selectedIds] diff --git a/src/renderer/src/components/status-bar/workspace-space-presentation.test.ts b/src/renderer/src/components/status-bar/workspace-space-presentation.test.ts index 8d52d451f00..3fe0be6b74a 100644 --- a/src/renderer/src/components/status-bar/workspace-space-presentation.test.ts +++ b/src/renderer/src/components/status-bar/workspace-space-presentation.test.ts @@ -3,6 +3,8 @@ import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-space- import { countWorkspaceSpaceActiveAgents, filterWorkspaceSpaceRows, + getLargestWorkspaceSpaceItemSize, + getLargestWorkspaceSpaceRowSize, getSelectedDeletableWorkspaceIds, getVisibleDeletableWorkspaceIds, getWorkspaceSpaceGitStatusRefreshCandidates, @@ -99,6 +101,23 @@ describe('workspace space presentation helpers', () => { expect(filterWorkspaceSpaceRows(rows, '', true).map((item) => item.worktreeId)).toEqual(['a']) }) + it('finds largest sizes without spreading large workspace arrays', () => { + const rows = Array.from({ length: 130_000 }, (_, index) => + row({ worktreeId: `wt-${index}`, sizeBytes: index === 87_654 ? 999_999 : index }) + ) + const items = Array.from({ length: 130_000 }, (_, index) => ({ + name: `item-${index}`, + path: `/repo/item-${index}`, + kind: 'directory' as const, + sizeBytes: index === 12_345 ? 888_888 : index + })) + + expect(getLargestWorkspaceSpaceRowSize(rows)).toBe(999_999) + expect(getLargestWorkspaceSpaceItemSize(items)).toBe(888_888) + expect(getLargestWorkspaceSpaceRowSize([])).toBe(0) + expect(getLargestWorkspaceSpaceItemSize([])).toBe(0) + }) + it('returns only selected worktrees that can be deleted', () => { const rows = [ row({ worktreeId: 'ok', canDelete: true, status: 'ok' }), diff --git a/src/renderer/src/components/status-bar/workspace-space-presentation.ts b/src/renderer/src/components/status-bar/workspace-space-presentation.ts index 5a8edcd35f9..28efd04b67f 100644 --- a/src/renderer/src/components/status-bar/workspace-space-presentation.ts +++ b/src/renderer/src/components/status-bar/workspace-space-presentation.ts @@ -7,7 +7,10 @@ import { } from '../../../../shared/agent-status-types' import { parsePaneKey } from '../../../../shared/stable-pane-id' import type { TerminalTab } from '../../../../shared/types' -import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-space-types' +import type { + WorkspaceSpaceItem, + WorkspaceSpaceWorktree +} from '../../../../shared/workspace-space-types' export type WorkspaceSpaceSortKey = 'size' | 'name' | 'repo' | 'activity' export type WorkspaceSpaceSortDirection = 'asc' | 'desc' @@ -140,6 +143,30 @@ export function getWorkspaceSpaceSearchText(worktree: WorkspaceSpaceWorktree): s .toLowerCase() } +export function getLargestWorkspaceSpaceItemSize( + items: readonly Pick[] +): number { + let maxSize = 0 + for (const item of items) { + if (item.sizeBytes > maxSize) { + maxSize = item.sizeBytes + } + } + return maxSize +} + +export function getLargestWorkspaceSpaceRowSize( + rows: readonly Pick[] +): number { + let maxSize = 0 + for (const row of rows) { + if (row.sizeBytes > maxSize) { + maxSize = row.sizeBytes + } + } + return maxSize +} + function compareRows( left: WorkspaceSpaceWorktree, right: WorkspaceSpaceWorktree,