From 6e80df9913aa948c7b805d489e78f19d7d018bc4 Mon Sep 17 00:00:00 2001 From: Ammar Date: Sun, 21 Dec 2025 00:40:24 -0600 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20fix:=20improve=20code=20review?= =?UTF-8?q?=20auto-refresh=20reliability=20in=20Electron?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add window.focus event listener alongside visibilitychange to handle cases where the Electron app loses/gains focus without the document becoming hidden (e.g., app behind other windows, different desktop/space). The visibilitychange API is designed for browser tab visibility, which doesn't map perfectly to Electron window focus states. Adding the focus event ensures pending refreshes are flushed when the user returns to the app regardless of how they left. --- _Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_ --- .../hooks/useReviewRefreshController.test.ts | 4 +++- src/browser/hooks/useReviewRefreshController.ts | 14 ++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/browser/hooks/useReviewRefreshController.test.ts b/src/browser/hooks/useReviewRefreshController.test.ts index ccbb42c5e4..003d273ae6 100644 --- a/src/browser/hooks/useReviewRefreshController.test.ts +++ b/src/browser/hooks/useReviewRefreshController.test.ts @@ -59,7 +59,9 @@ describe("useReviewRefreshController design", () => { test("visibility contract: hidden tab queues refresh for later", () => { // Contract: When document.hidden is true, refresh is queued. - // When visibilitychange fires and document.hidden becomes false, queued refresh executes. + // When visibilitychange fires or window.focus fires (and document is visible), + // queued refresh executes. Uses both events since visibilitychange alone is + // unreliable in Electron when app is behind other windows or on different desktop. // This prevents wasted git operations when user isn't looking. expect(true).toBe(true); }); diff --git a/src/browser/hooks/useReviewRefreshController.ts b/src/browser/hooks/useReviewRefreshController.ts index 106e279d35..0a37ffbb2b 100644 --- a/src/browser/hooks/useReviewRefreshController.ts +++ b/src/browser/hooks/useReviewRefreshController.ts @@ -238,17 +238,23 @@ export function useReviewRefreshController( // eslint-disable-next-line react-hooks/exhaustive-deps }, [api, workspaceId, isCreating]); - // Handle visibility changes - flush pending refresh when tab becomes visible + // Handle visibility/focus changes - flush pending refresh when user returns. + // Uses both visibilitychange (for browser tab hidden state) and window focus + // (for Electron app focus) since visibilitychange alone is unreliable in Electron + // when the app is behind other windows or on a different desktop/space. useEffect(() => { - const handleVisibilityChange = () => { + const handleReturn = () => { + // Only flush if document is actually visible if (!document.hidden) { flushPending("hidden"); } }; - document.addEventListener("visibilitychange", handleVisibilityChange); + document.addEventListener("visibilitychange", handleReturn); + window.addEventListener("focus", handleReturn); return () => { - document.removeEventListener("visibilitychange", handleVisibilityChange); + document.removeEventListener("visibilitychange", handleReturn); + window.removeEventListener("focus", handleReturn); }; // flushPending is stable (only uses refs internally) // eslint-disable-next-line react-hooks/exhaustive-deps