From 23d251e4823550fa5afc4d19cf268fe8dddc3a2e Mon Sep 17 00:00:00 2001 From: jelveh Date: Sun, 2 Aug 2026 20:30:20 -0700 Subject: [PATCH] fix: dashboard files list blanking during same-directory refresh Re-rendering the directory already on screen (after an upload, sort change, undo, etc.) used to clear the list and show a spinner before the readdir round-trip, blanking the pane for the whole fetch. Keep the current rows visible until the fresh listing arrives, then swap the DOM in one pass and restore the scroll position. Navigation to a different directory still clears immediately. --- src/gui/src/UI/Dashboard/TabFiles.js | 59 ++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/src/gui/src/UI/Dashboard/TabFiles.js b/src/gui/src/UI/Dashboard/TabFiles.js index be3c51fc5..8d56cd985 100644 --- a/src/gui/src/UI/Dashboard/TabFiles.js +++ b/src/gui/src/UI/Dashboard/TabFiles.js @@ -1934,20 +1934,36 @@ const TabFiles = { async renderDirectory (target, options = {}) { if ( this.renderingDirectory ) return; this.renderingDirectory = true; - this.$el_window.find('.files-tab .files').html(''); - this.showSpinner(); const _this = this; - document.querySelectorAll('.files-tab .row.selected').forEach(r => { - r.classList.remove('selected'); - }); + // Re-rendering the directory already on screen (after an upload, sort + // change, undo, …) keeps the current rows visible while the fresh + // listing is fetched, then swaps the DOM in one pass — clearing up + // front would blank the pane for the whole network round-trip and + // read as flicker. Navigating to a different directory still clears + // immediately so the user gets instant feedback. + const isSameDirRefresh = typeof target === 'string' && target === this.currentPath; + const $files = this.$el_window.find('.files-tab .files'); + const prevScrollTop = isSameDirRefresh ? $files.scrollTop() : 0; - // Drop the shift-click anchor — it points at a row from the directory - // we're leaving, and a stale detached anchor makes the first shift-click - // in the new directory select nothing. - if ( window.latest_selected_item && ! document.body.contains(window.latest_selected_item) ) { - window.latest_selected_item = null; - window.active_element = null; + const clearListing = () => { + $files.html(''); + document.querySelectorAll('.files-tab .row.selected').forEach(r => { + r.classList.remove('selected'); + }); + + // Drop the shift-click anchor — it points at a row that no longer + // exists, and a stale detached anchor makes the first shift-click + // after the render select nothing. + if ( window.latest_selected_item && ! document.body.contains(window.latest_selected_item) ) { + window.latest_selected_item = null; + window.active_element = null; + } + }; + + if ( ! isSameDirRefresh ) { + clearListing(); + this.showSpinner(); } // Determine whether target is a path or uid @@ -1963,8 +1979,10 @@ const TabFiles = { // network). Without this, renderingDirectory would stay true and // the guard above would block all further navigation. console.error('Failed to read directory:', err); - // The container was already emptied above; show a message instead of - // leaving a blank pane with no explanation. + // Replace whatever the pane shows (blank after navigation, the + // stale rows during a same-directory refresh) with a message + // rather than leaving it unexplained. + clearListing(); this.$el_window.find('.files-tab .files').html(`