Skip to content

Commit ebab3e7

Browse files
committed
perf: 1s debounce for active workspace git status
Active workspace now uses 1s debounce for git status refresh after file-modifying tools complete, while background workspaces keep 3s. This makes the visible git indicators feel more responsive without adding load from background workspace refreshes.
1 parent 70dc5cc commit ebab3e7

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

src/browser/App.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { buildSortedWorkspacesByProject } from "./utils/ui/workspaceFiltering";
1717
import { useResumeManager } from "./hooks/useResumeManager";
1818
import { useUnreadTracking } from "./hooks/useUnreadTracking";
1919
import { useWorkspaceStoreRaw, useWorkspaceRecency } from "./stores/WorkspaceStore";
20+
import { setActiveWorkspace } from "./stores/GitStatusStore";
2021

2122
import { useStableReference, compareMaps } from "./hooks/useStableReference";
2223
import { CommandRegistryProvider, useCommandRegistry } from "./contexts/CommandRegistryContext";
@@ -133,6 +134,11 @@ function AppInner() {
133134
prevWorkspaceRef.current = selectedWorkspace;
134135
}, [selectedWorkspace, telemetry]);
135136

137+
// Tell GitStatusStore which workspace is active (for prioritized 1s refresh)
138+
useEffect(() => {
139+
setActiveWorkspace(selectedWorkspace?.workspaceId ?? null);
140+
}, [selectedWorkspace?.workspaceId]);
141+
136142
// Track last-read timestamps for unread indicators
137143
const { lastReadTimestamps, onToggleUnread } = useUnreadTracking(selectedWorkspace);
138144

src/browser/stores/GitStatusStore.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { RefreshController } from "@/browser/utils/RefreshController";
1919
* - Lives outside React lifecycle (stable references)
2020
* - Event-driven updates (no polling):
2121
* - Initial subscription triggers immediate fetch
22-
* - File-modifying tools trigger debounced refresh (3s)
22+
* - File-modifying tools trigger debounced refresh (1s active, 3s background)
2323
* - Window focus triggers refresh for visible workspaces
2424
* - Explicit invalidation (branch switch, etc.)
2525
* - Manages git fetch with exponential backoff
@@ -31,6 +31,7 @@ import { RefreshController } from "@/browser/utils/RefreshController";
3131

3232
// Configuration
3333
const MAX_CONCURRENT_GIT_OPS = 5;
34+
const ACTIVE_WORKSPACE_DEBOUNCE_MS = 1000; // 1s for active workspace (vs 3s background)
3435

3536
// Fetch configuration - aggressive intervals for fresh data
3637
const FETCH_BASE_INTERVAL_MS = 3 * 1000; // 3 seconds
@@ -53,7 +54,12 @@ export class GitStatusStore {
5354
// File modification subscription
5455
private fileModifyUnsubscribe: (() => void) | null = null;
5556

57+
// Active workspace gets faster refresh (1s vs 3s debounce)
58+
private activeWorkspaceId: string | null = null;
59+
private activeWorkspaceTimer: ReturnType<typeof setTimeout> | null = null;
60+
5661
// RefreshController handles debouncing, focus/visibility, and in-flight guards
62+
// Used for background workspaces (3s debounce)
5763
private readonly refreshController: RefreshController;
5864

5965
setClient(client: RouterClient<AppRouter>) {
@@ -113,6 +119,14 @@ export class GitStatusStore {
113119
});
114120
}
115121

122+
/**
123+
* Set the active workspace for prioritized refresh (1s debounce vs 3s).
124+
* Call when workspace selection changes.
125+
*/
126+
setActiveWorkspace(workspaceId: string | null): void {
127+
this.activeWorkspaceId = workspaceId;
128+
}
129+
116130
/**
117131
* Invalidate status for a workspace, clearing cache and triggering immediate refresh.
118132
* Call after operations that change git state (e.g., branch switch).
@@ -468,6 +482,10 @@ export class GitStatusStore {
468482
this.fetchCache.clear();
469483
this.fileModifyUnsubscribe?.();
470484
this.fileModifyUnsubscribe = null;
485+
if (this.activeWorkspaceTimer) {
486+
clearTimeout(this.activeWorkspaceTimer);
487+
this.activeWorkspaceTimer = null;
488+
}
471489
this.refreshController.dispose();
472490
}
473491

@@ -490,8 +508,19 @@ export class GitStatusStore {
490508
return;
491509
}
492510

493-
// RefreshController handles debouncing, focus gating, and in-flight guards
494-
this.refreshController.schedule();
511+
// Active workspace gets faster refresh (1s) via dedicated timer
512+
if (workspaceId === this.activeWorkspaceId) {
513+
if (this.activeWorkspaceTimer) {
514+
clearTimeout(this.activeWorkspaceTimer);
515+
}
516+
this.activeWorkspaceTimer = setTimeout(() => {
517+
this.activeWorkspaceTimer = null;
518+
this.refreshController.requestImmediate();
519+
}, ACTIVE_WORKSPACE_DEBOUNCE_MS);
520+
} else {
521+
// Background workspaces use standard 3s debounce via RefreshController
522+
this.refreshController.schedule();
523+
}
495524
});
496525
}
497526
}
@@ -542,3 +571,11 @@ export function invalidateGitStatus(workspaceId: string): void {
542571
const store = getGitStoreInstance();
543572
store.invalidateWorkspace(workspaceId);
544573
}
574+
575+
/**
576+
* Set the active workspace for prioritized git status refresh (1s vs 3s debounce).
577+
*/
578+
export function setActiveWorkspace(workspaceId: string | null): void {
579+
const store = getGitStoreInstance();
580+
store.setActiveWorkspace(workspaceId);
581+
}

0 commit comments

Comments
 (0)