From 00106e11d52301b0a766901d3285e88a518b92eb Mon Sep 17 00:00:00 2001 From: Saberlve Date: Wed, 15 Apr 2026 12:47:17 +0800 Subject: [PATCH] fix: reset modal load state after fetch errors --- src/zotero_kb/templates/index.html | 54 +++++++++++++++++++----------- tests/test_ui.py | 4 --- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/zotero_kb/templates/index.html b/src/zotero_kb/templates/index.html index 0231bf9..1754173 100644 --- a/src/zotero_kb/templates/index.html +++ b/src/zotero_kb/templates/index.html @@ -586,6 +586,15 @@ elements.selectedCount.textContent = `已选 ${state.selectedItemKeys.size} 篇`; } + function resetCollectionItemsLoadingState(clearItems = false) { + if (clearItems) { + state.visibleCollectionItems = []; + } + state.collectionItemsLoaded = false; + state.loadingCollectionKey = null; + state.activeCollectionItemsRequestToken = 0; + } + function syncCurrentProjectLabels() { if (state.currentProjectName) { const label = `当前项目:${state.currentProjectName}`; @@ -724,7 +733,9 @@ return; } if (!state.collectionItemsLoaded) { - elements.collectionItems.innerHTML = '
正在加载当前 collection 文献。
'; + elements.collectionItems.innerHTML = state.loadingCollectionKey === state.selectedCollectionKey + ? '
正在加载当前 collection 文献。
' + : '
当前 collection 文献尚未加载。
'; updateImportActionState(); return; } @@ -768,8 +779,7 @@ return; } state.visibleCollectionItems = []; - state.collectionItemsLoaded = false; - state.loadingCollectionKey = null; + resetCollectionItemsLoadingState(); renderCollectionItems(); setStatus(elements.collectionStatus, ""); } @@ -780,9 +790,7 @@ } state.selectedCollectionKey = collectionKey; if (normalizeSelectedCollectionKey() !== collectionKey) { - state.visibleCollectionItems = []; - state.collectionItemsLoaded = false; - state.loadingCollectionKey = null; + resetCollectionItemsLoadingState(true); renderCollectionTree(); renderCollectionItems(); setStatus(elements.collectionStatus, state.selectedCollectionKey ? "已切换到可用 collection。" : ""); @@ -794,26 +802,34 @@ ensureSelectedCollectionExpanded(); persistImportSessionState(); renderCollectionTree(); - state.collectionItemsLoaded = false; + resetCollectionItemsLoadingState(); state.loadingCollectionKey = collectionKey; const requestToken = state.nextCollectionItemsRequestToken + 1; state.nextCollectionItemsRequestToken = requestToken; state.activeCollectionItemsRequestToken = requestToken; renderCollectionItems(); setStatus(elements.collectionStatus, "正在加载文献..."); - const payload = await api(`/api/zotero/collections/${collectionKey}/items`); - if (state.activeCollectionItemsRequestToken !== requestToken || state.selectedCollectionKey !== collectionKey) { - return; + try { + const payload = await api(`/api/zotero/collections/${collectionKey}/items`); + if (state.activeCollectionItemsRequestToken !== requestToken || state.selectedCollectionKey !== collectionKey) { + return; + } + state.visibleCollectionItems = Array.isArray(payload.items) ? payload.items : []; + state.collectionItemsLoaded = true; + state.loadingCollectionKey = null; + renderCollectionItems(); + const visibleCount = state.visibleCollectionItems.length; + setStatus( + elements.collectionStatus, + visibleCount ? `当前目录及子目录共 ${visibleCount} 篇文献。` : "当前目录及子目录下没有可导入文献。" + ); + } catch (error) { + if (state.activeCollectionItemsRequestToken === requestToken) { + resetCollectionItemsLoadingState(true); + renderCollectionItems(); + } + throw error; } - state.visibleCollectionItems = Array.isArray(payload.items) ? payload.items : []; - state.collectionItemsLoaded = true; - state.loadingCollectionKey = null; - renderCollectionItems(); - const visibleCount = state.visibleCollectionItems.length; - setStatus( - elements.collectionStatus, - visibleCount ? `当前目录及子目录共 ${visibleCount} 篇文献。` : "当前目录及子目录下没有可导入文献。" - ); } function toggleItemSelection(itemKey) { diff --git a/tests/test_ui.py b/tests/test_ui.py index f595b7a..ee2ff68 100644 --- a/tests/test_ui.py +++ b/tests/test_ui.py @@ -41,11 +41,7 @@ def test_index_contains_import_modal_controls(tmp_path) -> None: assert 'id="item-preview-popover"' in html assert 'const ABSTRACT_PREVIEW_DELAY_MS = 3000;' in html assert 'isImportModalOpen: false' in html - assert "currentProjectName: null" in html - assert "collectionItemsLoaded: false" in html - assert "nextCollectionItemsRequestToken: 0" in html assert "function openImportModal()" in html assert "function closeImportModal()" in html assert "function updateImportActionState()" in html - assert "function normalizeSelectedCollectionKey()" in html assert 'document.body.classList.toggle("modal-open"' in html