diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx index fd3650a2779..ee0e04438de 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx @@ -37,6 +37,7 @@ import { navigateToWorkspace } from "renderer/routes/_authenticated/_dashboard/u import { AsciiSpinner } from "renderer/screens/main/components/AsciiSpinner"; import { StatusIndicator } from "renderer/screens/main/components/StatusIndicator"; import { useBranchSyncInvalidation } from "renderer/screens/main/hooks/useBranchSyncInvalidation"; +import { useGitChangesStatus } from "renderer/screens/main/hooks/useGitChangesStatus"; import { useWorkspaceRename } from "renderer/screens/main/hooks/useWorkspaceRename"; import { useTabsStore } from "renderer/stores/tabs/store"; import { extractPaneIdsFromLayout } from "renderer/stores/tabs/utils"; @@ -93,7 +94,6 @@ export function WorkspaceListItem({ ); const utils = electronTrpc.useUtils(); - // Derive isActive from route const isActive = !!matchRoute({ to: "/workspace/$workspaceId", params: { workspaceId: id }, @@ -118,11 +118,10 @@ export function WorkspaceListItem({ toast.error(`Failed to update unread status: ${error.message}`), }); - // Shared delete logic const { showDeleteDialog, setShowDeleteDialog, handleDeleteClick } = useWorkspaceDeleteHandler(); - // Lazy-load GitHub status on hover to avoid N+1 queries + // Lazy-load on hover to avoid N+1 queries for every sidebar item const { data: githubStatus } = electronTrpc.workspaces.getGitHubStatus.useQuery( { workspaceId: id }, @@ -132,14 +131,11 @@ export function WorkspaceListItem({ }, ); - // Lazy-load local git changes on hover - const { data: localChanges } = electronTrpc.changes.getStatus.useQuery( - { worktreePath }, - { - enabled: hasHovered && type === "worktree" && !!worktreePath, - staleTime: GITHUB_STATUS_STALE_TIME, - }, - ); + const { status: localChanges } = useGitChangesStatus({ + worktreePath, + enabled: hasHovered && type === "worktree", + staleTime: GITHUB_STATUS_STALE_TIME, + }); useBranchSyncInvalidation({ gitBranch: localChanges?.branch, @@ -147,21 +143,23 @@ export function WorkspaceListItem({ workspaceId: id, }); - // Calculate total local changes (staged + unstaged + untracked) + // Prefer againstBase (committed diff vs base branch) over uncommitted changes only const localDiffStats = useMemo(() => { if (!localChanges) return null; - const allFiles = [ - ...localChanges.staged, - ...localChanges.unstaged, - ...localChanges.untracked, - ]; + const allFiles = + localChanges.againstBase.length > 0 + ? localChanges.againstBase + : [ + ...localChanges.staged, + ...localChanges.unstaged, + ...localChanges.untracked, + ]; const additions = allFiles.reduce((sum, f) => sum + (f.additions || 0), 0); const deletions = allFiles.reduce((sum, f) => sum + (f.deletions || 0), 0); if (additions === 0 && deletions === 0) return null; return { additions, deletions }; }, [localChanges]); - // Memoize workspace pane IDs to avoid recalculating on every render const workspacePaneIds = useMemo(() => { const workspaceTabs = tabs.filter((t) => t.workspaceId === id); return new Set( @@ -169,9 +167,7 @@ export function WorkspaceListItem({ ); }, [tabs, id]); - // Compute aggregate status for workspace using shared priority logic const workspaceStatus = useMemo(() => { - // Generator avoids array allocation function* paneStatuses() { for (const paneId of workspacePaneIds) { yield panes[paneId]?.status; @@ -214,7 +210,6 @@ export function WorkspaceListItem({ } }; - // Drag and drop const [{ isDragging }, drag] = useDrag( () => ({ type: WORKSPACE_TYPE, @@ -291,7 +286,6 @@ export function WorkspaceListItem({ }); const pr = githubStatus?.pr; - // Show diff stats from PR if available, otherwise from local changes const diffStats = localDiffStats || (pr && (pr.additions > 0 || pr.deletions > 0) @@ -299,10 +293,8 @@ export function WorkspaceListItem({ : null); const showDiffStats = !!diffStats; - // Determine if we should show the branch subtitle const showBranchSubtitle = isBranchWorkspace || (!!name && name !== branch); - // Collapsed sidebar: show just the icon with hover card (worktree) or tooltip (branch) if (isCollapsed) { const collapsedButton = (