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 }, )