From 3afec0a0be430ed4c881e47ad2e88c9e42f81196 Mon Sep 17 00:00:00 2001 From: Will Miao Date: Mon, 24 Aug 2026 09:15:55 +0800 Subject: [PATCH] fix(ui): fall back to folder root when persisted active folder no longer exists restoreSelectedFolder trusted localStorage blindly: a stale activeFolder (moved/deleted, or saved while the tree was still empty) left the grid filtered to a nonexistent folder with a phantom breadcrumb and no way to recover short of clicking the root breadcrumb. Validate the persisted path against the freshly loaded tree and reset to root when it is gone; skip validation when the tree load failed so transient errors don't wipe the saved location. --- static/js/components/SidebarManager.js | 36 +++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/static/js/components/SidebarManager.js b/static/js/components/SidebarManager.js index 5ecdcc20..cc7fa6e8 100644 --- a/static/js/components/SidebarManager.js +++ b/static/js/components/SidebarManager.js @@ -16,6 +16,7 @@ export class SidebarManager { this.pageControls = null; this.pageType = null; this.treeData = {}; + this.folderTreeLoaded = false; this.selectedPath = ''; this.expandedNodes = new Set(); this.apiClient = null; @@ -1171,13 +1172,32 @@ export class SidebarManager { const response = await this.apiClient.fetchModelFolders(); this.foldersList = response.folders || []; } + this.folderTreeLoaded = true; this.renderFolderDisplay(); } catch (error) { + this.folderTreeLoaded = false; console.error('Failed to load folder data:', error); this.renderEmptyState(); } } + folderExistsInTree(path) { + if (!path) return true; + + if (this.displayMode === 'tree') { + let node = this.treeData; + for (const segment of path.split('/')) { + if (!node || typeof node !== 'object' || !(segment in node)) { + return false; + } + node = node[segment]; + } + return true; + } + + return this.foldersList.includes(path); + } + renderFolderDisplay() { if (this.displayMode === 'tree') { this.renderTree(); @@ -1809,7 +1829,21 @@ export class SidebarManager { restoreSelectedFolder() { const activeFolder = getStorageItem(`${this.pageType}_activeFolder`); if (activeFolder && typeof activeFolder === 'string') { - this.selectedPath = activeFolder; + // Fall back to the root when the persisted folder no longer + // exists in the freshly loaded tree (e.g. it was moved or + // deleted); otherwise the grid stays empty with a phantom + // breadcrumb. Skip validation when the tree failed to load so a + // transient API error doesn't wipe the saved location. + if (this.folderTreeLoaded && !this.folderExistsInTree(activeFolder)) { + console.warn(`Persisted folder "${activeFolder}" not found in folder tree, falling back to root`); + this.selectedPath = ''; + if (this.pageControls?.pageState) { + this.pageControls.pageState.activeFolder = ''; + } + setStorageItem(`${this.pageType}_activeFolder`, ''); + } else { + this.selectedPath = activeFolder; + } this.updateTreeSelection(); this.updateBreadcrumbs(); this.updateSidebarHeader();