a window re-reads its folder when it comes forward

Cutting in one window and pasting in another moves the file on disk, and the window it left went on
listing it until somebody pressed refresh. The clipboard was the obvious half of "these two windows
disagree"; the listing is the half that matters more, because a file that is not there any more is a
lie rather than a stale label.

Same trigger as the clipboard, for the same reason: coming back to a window is exactly when its
contents need to be true, and never while nobody is looking at it.

`refresh` is held in a ref because it is rebuilt on every render — in the dependency array it would
tear down and re-add both listeners several times a second.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-30 11:05:36 +01:00
co-authored by Claude Opus 5
parent a53c07d71f
commit dfe837dfd0
@@ -342,15 +342,31 @@ export const useFileBrowserApp = (
`visibilitychange` as well as `focus`, because a background tab brought forward by switching tabs `visibilitychange` as well as `focus`, because a background tab brought forward by switching tabs
fires only the second one in some browsers. fires only the second one in some browsers.
*/ */
/*
...and the FOLDER as well as the clipboard.
Cutting in one window and pasting in another moves the file on disk, and the window it left went on
listing it until somebody pressed refresh. The clipboard was the obvious half of "these two windows
disagree"; the listing is the half that matters more, because a file that is not there any more is
a lie rather than a stale label.
Held in a ref because `refreshRef.current` is rebuilt on every render — putting it in the
dependency array would tear down and re-add both listeners several times a second.
*/
const refreshRef = useRef(refresh);
refreshRef.current = refresh;
useEffect(() => { useEffect(() => {
const refresh = () => { const onForeground = () => {
if (document.visibilityState === 'visible') void queryClient.invalidateQueries({ queryKey: ['USER_STATE'] }); if (document.visibilityState !== 'visible') return;
void queryClient.invalidateQueries({ queryKey: ['USER_STATE'] });
void refreshRef.current();
}; };
window.addEventListener('focus', refresh); window.addEventListener('focus', onForeground);
document.addEventListener('visibilitychange', refresh); document.addEventListener('visibilitychange', onForeground);
return () => { return () => {
window.removeEventListener('focus', refresh); window.removeEventListener('focus', onForeground);
document.removeEventListener('visibilitychange', refresh); document.removeEventListener('visibilitychange', onForeground);
}; };
}, [queryClient]); }, [queryClient]);