From 1bce1fc1b98be20f366ad341cfd072a198d94964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=80=AA=E7=A8=8B=E4=BC=9F?= Date: Sat, 27 Jun 2026 00:08:17 +0800 Subject: [PATCH] fix(wiki): stop config tab from auto-switching back to sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two compounding causes made the management view jump from the config tab back to 'raw' a few seconds after the user selected it: 1. The tab-snap watcher used a single getter returning a new array (`() => [currentKB?.id, workspaceMode]`). Vue compares the returned value with Object.is, so a fresh array reference reports a change on every re-evaluation — including background refreshCurrentKB() calls that reassign the KB object with the same id. That re-ran the snap and forced activeTab back to 'raw'. Switch to an array of getters so each source is compared individually and the callback fires only on a real id/mode change. 2. RawMaterialPanel's onBeforeUnmount cleared the SSE stream and the 60s fallback timer but not the per-raw jobPoller setTimeout chain. While a raw was still processing, leaving the sources tab left that 3s poller running, calling refreshCurrentKB() indefinitely. Clear jobPoller on unmount as well. --- .../src/views/Wiki/components/RawMaterialPanel.vue | 8 ++++++++ mateclaw-ui/src/views/Wiki/components/WikiWorkspace.vue | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/mateclaw-ui/src/views/Wiki/components/RawMaterialPanel.vue b/mateclaw-ui/src/views/Wiki/components/RawMaterialPanel.vue index 2dba1300..dbbf9bb0 100644 --- a/mateclaw-ui/src/views/Wiki/components/RawMaterialPanel.vue +++ b/mateclaw-ui/src/views/Wiki/components/RawMaterialPanel.vue @@ -439,6 +439,14 @@ onBeforeUnmount(() => { clearInterval(fallbackTimer) fallbackTimer = null } + // Stop the per-raw job poller too. Without this the setTimeout chain keeps + // running after the panel unmounts (e.g. switching to the config tab while a + // raw is still processing), calling refreshCurrentKB() every 3s and snapping + // the user back to this tab. + if (jobPoller != null) { + clearTimeout(jobPoller) + jobPoller = null + } }) // RFC-033: Job polling per raw material diff --git a/mateclaw-ui/src/views/Wiki/components/WikiWorkspace.vue b/mateclaw-ui/src/views/Wiki/components/WikiWorkspace.vue index e5d9be72..83fac232 100644 --- a/mateclaw-ui/src/views/Wiki/components/WikiWorkspace.vue +++ b/mateclaw-ui/src/views/Wiki/components/WikiWorkspace.vue @@ -157,8 +157,15 @@ const tabs = computed<{ key: WikiTab; label: string }[]>(() => { // Snap to each view's default tab whenever the KB or the view mode changes, so // the user never lands on a stale tab (or one that doesn't exist in this mode). +// Use an array of getters (not a single getter returning an array): the latter +// returns a fresh array reference on every evaluation, so Vue's Object.is check +// always reports a change and the callback fires on *any* currentKB +// reassignment — including background refreshes (refreshCurrentKB) that keep the +// same id. That would yank the user off the config tab back to 'raw' every time +// a poll/SSE refresh reassigned the KB object. The array-of-getters form +// compares each source individually, so it fires only on a real id/mode change. watch( - () => [store.currentKB?.id, store.workspaceMode], + [() => store.currentKB?.id, () => store.workspaceMode], () => { activeTab.value = store.workspaceMode === 'manage' ? 'raw' : 'pages' }, { immediate: true }, )