From d058cd9258bf3b70b8c4ca0f75ee25c9b77aa6dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sun, 30 Aug 2026 11:09:31 +0100 Subject: [PATCH] re-reading a folder does not blank it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `loading` swaps the whole grid for a spinner. That is right when arriving somewhere new and wrong when re-reading a folder already on screen — and every refresh went through the same path: after a paste, after a delete, and now every time a window comes forward. On a folder of a hundred files that is a flash and a lost scroll position, to replace information that was already correct. The spinner is now for a folder that cannot yet be shown: nothing listed, or a different folder than the one listed. Re-reading the same folder leaves what is there until better information arrives, so the only visible change is whatever actually changed. `shownPath` is what separates the two cases. From inside `refresh` they are identical — it is called the same way by a navigation and by a refresh — and they need opposite treatment. Co-Authored-By: Claude Opus 5 (1M context) --- .../FileBrowserApp/useFileBrowserApp.ts | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts index 2b0360ab..cebf6d83 100644 --- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts +++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts @@ -247,6 +247,10 @@ export const useFileBrowserApp = ( filesRef.current = files; const currentPathRef = useRef(currentPath); currentPathRef.current = currentPath; + // Read inside `refresh`, which is not re-created per render and would otherwise close over a + // stale list the first time it ran. + const entriesRef = useRef(entries); + entriesRef.current = entries; const visibleEntries = showHidden ? entries : entries.filter((e) => !e.name.startsWith('.')); const entryPath = (name: string) => (currentPath === '/' ? `/${name}` : `${currentPath}/${name}`); @@ -254,8 +258,29 @@ export const useFileBrowserApp = ( const firstListing = useRef(true); + /** + * The folder the entries currently on screen belong to. + * + * What separates "re-read this folder" from "go to a different one", which look identical from + * inside `refresh` and need opposite treatment — see below. + */ + const shownPath = useRef(null); + const refresh = async () => { - setLoading(true); + /* + Blank the list only when there is nothing true to show. + + `loading` swaps the whole grid for a spinner, which is right when arriving somewhere new and + wrong when re-reading a folder already on screen: every refresh — after a paste, after a delete, + and now every time the window comes forward — made the contents vanish and come back. On a + folder of a hundred files that is a flash and a lost scroll position, for information that was + already correct. + + So the spinner is for a folder we cannot yet show: nothing listed, or a different folder than the + one listed. Re-reading the same folder leaves what is there until better information arrives, and + the only visible change is whatever actually changed. + */ + if (entriesRef.current.length === 0 || shownPath.current !== currentPathRef.current) setLoading(true); try { const data = await filesRef.current.listDir(currentPathRef.current); if (data.reset) { @@ -263,6 +288,7 @@ export const useFileBrowserApp = ( return; } setEntries(data.entries); + shownPath.current = currentPathRef.current; if (data.rootDir) setRootDir(data.rootDir); } catch (err: any) { console.error('[FileBrowser] refresh error:', err);