mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(wiki): open failure records in owning workspace (#614)
This commit is contained in:
parent
709218e2ac
commit
2372827762
44
mateclaw-ui/src/views/Wiki/__tests__/failureOpen.test.ts
Normal file
44
mateclaw-ui/src/views/Wiki/__tests__/failureOpen.test.ts
Normal 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')
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -16,7 +16,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div v-show="!collapsed" class="fc-body">
|
<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>
|
<span class="fc-badge" :class="rowKind(it)">{{ t(`wiki.status.${it.processingStatus}`) }}</span>
|
||||||
<div class="fc-main">
|
<div class="fc-main">
|
||||||
<div class="fc-line1">
|
<div class="fc-line1">
|
||||||
@ -25,7 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="fc-msg" :title="it.errorMessage || it.warningMessage || ''">{{ friendly(it) }}</div>
|
<div class="fc-msg" :title="it.errorMessage || it.warningMessage || ''">{{ friendly(it) }}</div>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -36,7 +36,7 @@ import { ref, onMounted } from 'vue'
|
|||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { wikiApi, type WikiFailureItem } from '@/api/index'
|
import { wikiApi, type WikiFailureItem } from '@/api/index'
|
||||||
|
|
||||||
defineEmits<{ (e: 'open', kbId: string): void }>()
|
defineEmits<{ (e: 'open', item: WikiFailureItem): void }>()
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const items = ref<WikiFailureItem[]>([])
|
const items = ref<WikiFailureItem[]>([])
|
||||||
|
|||||||
@ -48,18 +48,21 @@ import { ref, reactive, watch, onMounted, computed } from 'vue'
|
|||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useWikiStore, type WikiKB } from '@/stores/useWikiStore'
|
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 { mcConfirm } from '@/components/common/useConfirm'
|
||||||
import { mcToast } from '@/composables/useMcToast'
|
import { mcToast } from '@/composables/useMcToast'
|
||||||
import WikiLibrary from './components/WikiLibrary.vue'
|
import WikiLibrary from './components/WikiLibrary.vue'
|
||||||
import WikiWorkspace from './components/WikiWorkspace.vue'
|
import WikiWorkspace from './components/WikiWorkspace.vue'
|
||||||
import WikiFailureCenter from './components/WikiFailureCenter.vue'
|
import WikiFailureCenter from './components/WikiFailureCenter.vue'
|
||||||
|
import { openWikiFailureItem } from './utils/failureOpen'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const store = useWikiStore()
|
const store = useWikiStore()
|
||||||
|
const workspaceStore = useWorkspaceStore()
|
||||||
|
|
||||||
// The cross-KB failure center spans every workspace, so it is admin-only —
|
// The cross-KB failure center spans every workspace, so it is admin-only —
|
||||||
// mirrors the gate on the backing endpoint.
|
// mirrors the gate on the backing endpoint.
|
||||||
@ -95,10 +98,8 @@ async function enterKB(id: number) {
|
|||||||
await store.selectKB(id, 'browse')
|
await store.selectKB(id, 'browse')
|
||||||
}
|
}
|
||||||
|
|
||||||
// The failure center emits a Snowflake kbId as a string — keep it a string end
|
async function openFromFailureCenter(item: WikiFailureItem) {
|
||||||
// to end (snowflake-precision-ok) and let the store cast satisfy its signature.
|
await openWikiFailureItem(item, { workspaceStore, wikiStore: store })
|
||||||
async function openFromFailureCenter(kbId: string) {
|
|
||||||
await store.selectKB(kbId as unknown as number, 'browse')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function enterKBManage(id: number) {
|
async function enterKBManage(id: number) {
|
||||||
|
|||||||
27
mateclaw-ui/src/views/Wiki/utils/failureOpen.ts
Normal file
27
mateclaw-ui/src/views/Wiki/utils/failureOpen.ts
Normal 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')
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user