fix(wiki): open failure records in owning workspace (#614)

This commit is contained in:
matevip 2026-08-21 22:32:48 -04:00
parent 709218e2ac
commit 2372827762
4 changed files with 80 additions and 8 deletions

View File

@ -0,0 +1,44 @@
import { describe, expect, it, vi } from 'vitest'
import { openWikiFailureItem } from '../utils/failureOpen'
describe('openWikiFailureItem', () => {
it('switches to the owning workspace before opening a cross-workspace KB', async () => {
const calls: string[] = []
const workspaceStore = {
currentWorkspaceId: 'ws-a',
switchWorkspace: vi.fn(async (id: string) => {
calls.push(`switch:${id}`)
}),
}
const wikiStore = {
selectKB: vi.fn(async (id: string, mode: 'browse' | 'manage') => {
calls.push(`select:${id}:${mode}`)
}),
}
await openWikiFailureItem(
{ kbId: 'kb-2', workspaceId: 'ws-b' },
{ workspaceStore, wikiStore },
)
expect(calls).toEqual(['switch:ws-b', 'select:kb-2:browse'])
})
it('opens directly when the failure item belongs to the active workspace', async () => {
const workspaceStore = {
currentWorkspaceId: 'ws-a',
switchWorkspace: vi.fn(),
}
const wikiStore = {
selectKB: vi.fn(async () => {}),
}
await openWikiFailureItem(
{ kbId: 'kb-1', workspaceId: 'ws-a' },
{ workspaceStore, wikiStore },
)
expect(workspaceStore.switchWorkspace).not.toHaveBeenCalled()
expect(wikiStore.selectKB).toHaveBeenCalledWith('kb-1', 'browse')
})
})

View File

@ -16,7 +16,7 @@
</button>
<div v-show="!collapsed" class="fc-body">
<div v-for="it in items" :key="it.rawId" class="fc-row" @click="$emit('open', it.kbId)">
<div v-for="it in items" :key="it.rawId" class="fc-row" @click="$emit('open', it)">
<span class="fc-badge" :class="rowKind(it)">{{ t(`wiki.status.${it.processingStatus}`) }}</span>
<div class="fc-main">
<div class="fc-line1">
@ -25,7 +25,7 @@
</div>
<div class="fc-msg" :title="it.errorMessage || it.warningMessage || ''">{{ friendly(it) }}</div>
</div>
<button class="fc-open" @click.stop="$emit('open', it.kbId)">{{ t('wiki.failureCenter.open') }}</button>
<button class="fc-open" @click.stop="$emit('open', it)">{{ t('wiki.failureCenter.open') }}</button>
</div>
</div>
</section>
@ -36,7 +36,7 @@ import { ref, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { wikiApi, type WikiFailureItem } from '@/api/index'
defineEmits<{ (e: 'open', kbId: string): void }>()
defineEmits<{ (e: 'open', item: WikiFailureItem): void }>()
const { t } = useI18n()
const items = ref<WikiFailureItem[]>([])

View File

@ -48,18 +48,21 @@ import { ref, reactive, watch, onMounted, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import { useWikiStore, type WikiKB } from '@/stores/useWikiStore'
import { wikiApi } from '@/api/index'
import { useWorkspaceStore } from '@/stores/useWorkspaceStore'
import { wikiApi, type WikiFailureItem } from '@/api/index'
import { mcConfirm } from '@/components/common/useConfirm'
import { mcToast } from '@/composables/useMcToast'
import WikiLibrary from './components/WikiLibrary.vue'
import WikiWorkspace from './components/WikiWorkspace.vue'
import WikiFailureCenter from './components/WikiFailureCenter.vue'
import { openWikiFailureItem } from './utils/failureOpen'
const route = useRoute()
const router = useRouter()
const { t } = useI18n()
const store = useWikiStore()
const workspaceStore = useWorkspaceStore()
// The cross-KB failure center spans every workspace, so it is admin-only
// mirrors the gate on the backing endpoint.
@ -95,10 +98,8 @@ async function enterKB(id: number) {
await store.selectKB(id, 'browse')
}
// The failure center emits a Snowflake kbId as a string keep it a string end
// to end (snowflake-precision-ok) and let the store cast satisfy its signature.
async function openFromFailureCenter(kbId: string) {
await store.selectKB(kbId as unknown as number, 'browse')
async function openFromFailureCenter(item: WikiFailureItem) {
await openWikiFailureItem(item, { workspaceStore, wikiStore: store })
}
async function enterKBManage(id: number) {

View File

@ -0,0 +1,27 @@
export interface WikiFailureOpenItem {
kbId: string
workspaceId?: string | null
}
export interface WikiFailureOpenDeps {
workspaceStore: {
currentWorkspaceId: string | null
switchWorkspace: (id: string) => Promise<void> | void
}
wikiStore: {
// The wiki store is still typed as number in places, but Snowflake KB IDs
// are passed as strings at runtime to avoid precision loss.
selectKB: (id: any, mode: 'browse' | 'manage') => Promise<void> | void
}
}
export async function openWikiFailureItem(
item: WikiFailureOpenItem,
deps: WikiFailureOpenDeps,
) {
const targetWorkspaceId = item.workspaceId || null
if (targetWorkspaceId && deps.workspaceStore.currentWorkspaceId !== targetWorkspaceId) {
await deps.workspaceStore.switchWorkspace(targetWorkspaceId)
}
await deps.wikiStore.selectKB(item.kbId, 'browse')
}