mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
feat(wiki): split KB management vs reading into separate workspace views (#309)
The KB workspace previously stacked all seven surfaces in one tab strip. Split them by intent: a gear on each library card opens the management view (raw materials, config, transformations, advanced, hot cache), while clicking the card body opens the reading view (pages + graph). The reading view drives page/graph via a header segmented control with the page tree shown only for the page viewer; the two views share loaded data and toggle without refetch. Closes matevip/mateclaw#308
This commit is contained in:
parent
7478491652
commit
347e42b795
@ -2074,7 +2074,11 @@ export default {
|
||||
deleteKBConfirm: 'Delete knowledge base "{name}"? This will also remove {raws} raw materials and {pages} wiki pages. This action cannot be undone.',
|
||||
deleteKBSuccess: 'Deleted knowledge base "{name}"',
|
||||
deleteKBFailed: 'Failed to delete knowledge base',
|
||||
manageKB: 'Manage knowledge base',
|
||||
toManage: 'Manage',
|
||||
toReading: 'View wiki',
|
||||
},
|
||||
manageBadge: 'Management',
|
||||
selectPage: 'Select a page from the sidebar',
|
||||
pageKicker: 'Knowledge Page',
|
||||
confirmDelete: 'Delete page "{title}"? This cannot be undone.',
|
||||
|
||||
@ -2086,7 +2086,11 @@ export default {
|
||||
deleteKBConfirm: '确认删除知识库「{name}」?将一并清除 {raws} 个原始材料和 {pages} 个 Wiki 页面,此操作不可撤销。',
|
||||
deleteKBSuccess: '已删除知识库「{name}」',
|
||||
deleteKBFailed: '删除知识库失败',
|
||||
manageKB: '管理知识库',
|
||||
toManage: '管理',
|
||||
toReading: '查看 Wiki',
|
||||
},
|
||||
manageBadge: '管理',
|
||||
selectPage: '从左侧选择一个页面查看',
|
||||
pageKicker: '知识页面',
|
||||
confirmDelete: '确认删除页面「{title}」?此操作不可撤销。',
|
||||
|
||||
@ -126,6 +126,11 @@ export interface WikiLintJob {
|
||||
export const useWikiStore = defineStore('wiki', () => {
|
||||
const knowledgeBases = ref<WikiKB[]>([])
|
||||
const currentKB = ref<WikiKB | null>(null)
|
||||
// Which face of an opened KB to show: 'browse' = reading surfaces (pages +
|
||||
// graph), 'manage' = build/config surfaces (raw materials, config,
|
||||
// transformations, advanced, hot cache). Both views share the data loaded by
|
||||
// selectKB, so switching between them is a flag flip with no refetch.
|
||||
const workspaceMode = ref<'browse' | 'manage'>('browse')
|
||||
const rawMaterials = ref<WikiRawMaterial[]>([])
|
||||
const pages = ref<WikiPage[]>([])
|
||||
const currentPage = ref<WikiPage | null>(null)
|
||||
@ -172,7 +177,8 @@ export const useWikiStore = defineStore('wiki', () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function selectKB(id: number) {
|
||||
async function selectKB(id: number, mode: 'browse' | 'manage' = 'browse') {
|
||||
workspaceMode.value = mode
|
||||
const res: any = await wikiApi.getKB(id)
|
||||
currentKB.value = res.data || res
|
||||
// pageRefs refresh in parallel with materials + pages — the viewer needs
|
||||
@ -239,9 +245,16 @@ export const useWikiStore = defineStore('wiki', () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Switch between reading/management faces of an already-open KB without
|
||||
// refetching — both share the data selectKB already loaded.
|
||||
function setWorkspaceMode(mode: 'browse' | 'manage') {
|
||||
workspaceMode.value = mode
|
||||
}
|
||||
|
||||
function backToLibrary() {
|
||||
currentKB.value = null
|
||||
currentPage.value = null
|
||||
workspaceMode.value = 'browse'
|
||||
rawMaterials.value = []
|
||||
pages.value = []
|
||||
pageRefs.value = []
|
||||
@ -440,6 +453,7 @@ export const useWikiStore = defineStore('wiki', () => {
|
||||
return {
|
||||
knowledgeBases,
|
||||
currentKB,
|
||||
workspaceMode,
|
||||
rawMaterials,
|
||||
pages,
|
||||
currentPage,
|
||||
@ -456,6 +470,7 @@ export const useWikiStore = defineStore('wiki', () => {
|
||||
selectKB,
|
||||
createKB,
|
||||
deleteKB,
|
||||
setWorkspaceMode,
|
||||
backToLibrary,
|
||||
fetchRawMaterials,
|
||||
fetchPages,
|
||||
|
||||
@ -11,7 +11,22 @@
|
||||
<button
|
||||
v-if="canManageWiki"
|
||||
type="button"
|
||||
class="kb-card-delete"
|
||||
class="kb-card-action kb-card-manage"
|
||||
:title="t('wiki.library.manageKB')"
|
||||
:aria-label="t('wiki.library.manageKB')"
|
||||
@click.stop="$emit('manage', kb.id)"
|
||||
@keydown.enter.stop
|
||||
@keydown.space.stop
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
v-if="canManageWiki"
|
||||
type="button"
|
||||
class="kb-card-action kb-card-delete"
|
||||
:title="t('wiki.library.deleteKB')"
|
||||
:aria-label="t('wiki.library.deleteKB')"
|
||||
@click.stop="$emit('delete', kb)"
|
||||
@ -72,6 +87,7 @@ const props = defineProps<{
|
||||
|
||||
defineEmits<{
|
||||
(e: 'open', id: number): void
|
||||
(e: 'manage', id: number): void
|
||||
(e: 'delete', kb: WikiKB): void
|
||||
}>()
|
||||
|
||||
@ -111,10 +127,9 @@ const relative = computed(() => relativeTime(props.kb.updateTime, locale.value.s
|
||||
}
|
||||
.kb-card:focus-visible { outline: 2px solid var(--mc-primary); outline-offset: 2px; }
|
||||
|
||||
.kb-card-delete {
|
||||
.kb-card-action {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: inline-flex;
|
||||
@ -131,11 +146,27 @@ const relative = computed(() => relativeTime(props.kb.updateTime, locale.value.s
|
||||
padding: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
.kb-card:hover .kb-card-delete,
|
||||
.kb-card:focus-within .kb-card-delete {
|
||||
.kb-card-delete { right: 10px; }
|
||||
.kb-card-manage { right: 44px; }
|
||||
|
||||
.kb-card:hover .kb-card-action,
|
||||
.kb-card:focus-within .kb-card-action {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.kb-card-manage:hover {
|
||||
color: var(--mc-primary);
|
||||
border-color: var(--mc-primary);
|
||||
background: var(--mc-primary-bg);
|
||||
}
|
||||
.kb-card-manage:focus-visible {
|
||||
outline: 2px solid var(--mc-primary);
|
||||
outline-offset: 2px;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.kb-card-delete:hover {
|
||||
color: var(--mc-danger);
|
||||
border-color: rgba(245, 108, 108, 0.45);
|
||||
|
||||
@ -66,6 +66,7 @@
|
||||
:kb="kb"
|
||||
:failed-job-count="kbStats[kb.id]?.failedJobCount || 0"
|
||||
@open="$emit('open', $event)"
|
||||
@manage="$emit('manage', $event)"
|
||||
@delete="$emit('delete', $event)"
|
||||
/>
|
||||
</div>
|
||||
@ -104,6 +105,7 @@ const props = defineProps<{
|
||||
|
||||
defineEmits<{
|
||||
(e: 'open', id: number): void
|
||||
(e: 'manage', id: number): void
|
||||
(e: 'create'): void
|
||||
(e: 'delete', kb: WikiKB): void
|
||||
}>()
|
||||
|
||||
@ -1,22 +1,44 @@
|
||||
<template>
|
||||
<div class="wiki-workspace">
|
||||
<WikiWorkspaceHeader :kb="kb" @back="store.backToLibrary()" />
|
||||
<WikiWorkspaceHeader
|
||||
:kb="kb"
|
||||
:mode="store.workspaceMode"
|
||||
:can-manage="canManageWiki"
|
||||
:reading-tab="activeTab === 'graph' ? 'graph' : 'pages'"
|
||||
@back="store.backToLibrary()"
|
||||
@switch-mode="store.setWorkspaceMode($event)"
|
||||
@switch-reading="activeTab = $event"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Broken-link banner — surfaces lint state across every tab so the user
|
||||
can trigger a scan or view results from any browsing context. Pinned
|
||||
between the header and the tab layout so it's the first thing they see
|
||||
after entering the KB.
|
||||
Broken-link banner — surfaces lint state so the user can trigger a scan
|
||||
or view results. Only shown in the reading (browse) view; the management
|
||||
view is config/raw surfaces where page-lint state isn't relevant.
|
||||
-->
|
||||
<WikiBrokenLinksBanner @view="brokenPanelOpen = true" />
|
||||
<WikiBrokenLinksPanel :open="brokenPanelOpen" @close="brokenPanelOpen = false" />
|
||||
<template v-if="store.workspaceMode === 'browse'">
|
||||
<WikiBrokenLinksBanner @view="brokenPanelOpen = true" />
|
||||
<WikiBrokenLinksPanel :open="brokenPanelOpen" @close="brokenPanelOpen = false" />
|
||||
</template>
|
||||
|
||||
<div class="wiki-layout">
|
||||
<WikiPageSidebar @open-page="onOpenPage" />
|
||||
<!--
|
||||
Page directory tree — reading-view navigation for the page viewer only.
|
||||
Hidden on the graph (the graph is its own navigation) and in manage
|
||||
mode, so the content area spans full width in both.
|
||||
-->
|
||||
<WikiPageSidebar
|
||||
v-if="store.workspaceMode === 'browse' && activeTab === 'pages'"
|
||||
@open-page="onOpenPage"
|
||||
/>
|
||||
|
||||
<div class="wiki-content mc-surface-card">
|
||||
<div class="wiki-content-body">
|
||||
<div class="content-tabs">
|
||||
<!--
|
||||
Tab strip is the management-view navigation only. In the reading
|
||||
view the page/graph switch lives in the header (segmented control),
|
||||
so no tab strip here.
|
||||
-->
|
||||
<div v-if="store.workspaceMode === 'manage'" class="content-tabs">
|
||||
<button
|
||||
v-for="tab in tabs" :key="tab.key"
|
||||
class="tab-btn" :class="{ active: activeTab === tab.key }"
|
||||
@ -92,35 +114,39 @@ const workspace = useWorkspaceStore()
|
||||
// the processing-config and transformations tabs are management surfaces.
|
||||
const canManageWiki = computed(() => workspace.can('manage:wiki'))
|
||||
|
||||
const activeTab = ref('raw')
|
||||
const activeTab = ref('pages')
|
||||
const brokenPanelOpen = ref(false)
|
||||
|
||||
// When a page becomes the currentPage (e.g. via the global wikilink click
|
||||
// handler that lands on /wiki?kbId=X&slug=Y), switch the tab to 'pages' so
|
||||
// the viewer is the thing the user sees. Without this, the workspace stays
|
||||
// on the default 'raw' tab and the page silently loads off-screen.
|
||||
// the viewer is the thing the user sees. Only meaningful in the reading view —
|
||||
// the management view has no 'pages' tab.
|
||||
watch(() => store.currentPage, (page) => {
|
||||
if (page) activeTab.value = 'pages'
|
||||
if (page && store.workspaceMode === 'browse') activeTab.value = 'pages'
|
||||
})
|
||||
|
||||
// Management-view tab strip. The reading view (page + graph) is driven by the
|
||||
// header's segmented control instead, so it has no tabs here. Entry into manage
|
||||
// mode is gated by manage:wiki, but guard here too so a read-only viewer never
|
||||
// sees management tabs even if the mode is somehow forced.
|
||||
const tabs = computed(() => {
|
||||
const list = [
|
||||
if (!canManageWiki.value) return []
|
||||
return [
|
||||
{ key: 'raw', label: t('wiki.rawMaterials') },
|
||||
{ key: 'pages', label: t('wiki.pages') },
|
||||
{ key: 'graph', label: t('wiki.graph.tab') },
|
||||
{ key: 'config', label: t('wiki.config') },
|
||||
{ key: 'transformations', label: t('wiki.transformations.tab') },
|
||||
{ key: 'advanced', label: t('wiki.adv.tab') },
|
||||
{ key: 'hotCache', label: t('wiki.hotCache.tab') },
|
||||
]
|
||||
if (canManageWiki.value) {
|
||||
list.push({ key: 'config', label: t('wiki.config') })
|
||||
list.push({ key: 'transformations', label: t('wiki.transformations.tab') })
|
||||
list.push({ key: 'advanced', label: t('wiki.adv.tab') })
|
||||
}
|
||||
list.push({ key: 'hotCache', label: t('wiki.hotCache.tab') })
|
||||
return list
|
||||
})
|
||||
|
||||
// When the user picks a different KB from the library, snap back to the
|
||||
// raw-materials tab so they don't land on stale state from the previous KB.
|
||||
watch(() => store.currentKB?.id, () => { activeTab.value = 'raw' })
|
||||
// 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).
|
||||
watch(
|
||||
() => [store.currentKB?.id, store.workspaceMode],
|
||||
() => { activeTab.value = store.workspaceMode === 'manage' ? 'raw' : 'pages' },
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
async function onOpenPage(slug: string) {
|
||||
if (!store.currentKB) return
|
||||
|
||||
@ -10,11 +10,64 @@
|
||||
<div class="workspace-title-row">
|
||||
<div class="workspace-icon" :style="iconStyle">{{ initial }}</div>
|
||||
<div class="workspace-title-text">
|
||||
<h1 class="workspace-title">{{ kb.name }}</h1>
|
||||
<div class="workspace-title-line">
|
||||
<h1 class="workspace-title">{{ kb.name }}</h1>
|
||||
<span v-if="mode === 'manage'" class="workspace-mode-badge">{{ t('wiki.manageBadge') }}</span>
|
||||
</div>
|
||||
<p v-if="kb.description" class="workspace-desc">{{ kb.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="mode === 'browse'" class="reading-toggle" role="tablist">
|
||||
<button
|
||||
type="button"
|
||||
class="reading-toggle-btn"
|
||||
:class="{ active: readingTab === 'pages' }"
|
||||
role="tab"
|
||||
:aria-selected="readingTab === 'pages'"
|
||||
@click="$emit('switch-reading', 'pages')"
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
|
||||
{{ t('wiki.pages') }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="reading-toggle-btn"
|
||||
:class="{ active: readingTab === 'graph' }"
|
||||
role="tab"
|
||||
:aria-selected="readingTab === 'graph'"
|
||||
@click="$emit('switch-reading', 'graph')"
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="5" cy="6" r="2.5"/><circle cx="19" cy="6" r="2.5"/><circle cx="12" cy="18" r="2.5"/><path d="M7 7.5 10.5 16M17 7.5 13.5 16M6.7 6h10.6"/></svg>
|
||||
{{ t('wiki.graph.tab') }}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
v-if="mode === 'browse' && canManage"
|
||||
type="button"
|
||||
class="mode-switch-btn"
|
||||
:title="t('wiki.library.toManage')"
|
||||
@click="$emit('switch-mode', 'manage')"
|
||||
>
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
||||
</svg>
|
||||
{{ t('wiki.library.toManage') }}
|
||||
</button>
|
||||
<button
|
||||
v-else-if="mode === 'manage'"
|
||||
type="button"
|
||||
class="mode-switch-btn"
|
||||
:title="t('wiki.library.toReading')"
|
||||
@click="$emit('switch-mode', 'browse')"
|
||||
>
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
|
||||
<path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
|
||||
</svg>
|
||||
{{ t('wiki.library.toReading') }}
|
||||
</button>
|
||||
<div class="workspace-meta">
|
||||
<span class="workspace-stat">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
|
||||
@ -35,8 +88,17 @@ import { useI18n } from 'vue-i18n'
|
||||
import type { WikiKB } from '@/stores/useWikiStore'
|
||||
import { kbAccent, kbAccentFg, kbInitial } from '../utils/kbVisual'
|
||||
|
||||
const props = defineProps<{ kb: WikiKB }>()
|
||||
defineEmits<{ (e: 'back'): void }>()
|
||||
const props = defineProps<{
|
||||
kb: WikiKB
|
||||
mode: 'browse' | 'manage'
|
||||
canManage: boolean
|
||||
readingTab: 'pages' | 'graph'
|
||||
}>()
|
||||
defineEmits<{
|
||||
(e: 'back'): void
|
||||
(e: 'switch-mode', mode: 'browse' | 'manage'): void
|
||||
(e: 'switch-reading', tab: 'pages' | 'graph'): void
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@ -89,6 +151,66 @@ const iconStyle = computed(() => ({
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.workspace-title-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
||||
.workspace-title-line { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
||||
.workspace-mode-badge {
|
||||
flex-shrink: 0;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--mc-primary);
|
||||
background: var(--mc-primary-bg);
|
||||
border: 1px solid var(--mc-primary);
|
||||
padding: 1px 8px;
|
||||
border-radius: 9999px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.reading-toggle {
|
||||
display: inline-flex;
|
||||
gap: 4px;
|
||||
padding: 4px;
|
||||
background: var(--mc-bg-muted);
|
||||
border: 1px solid var(--mc-border-light);
|
||||
border-radius: 12px;
|
||||
}
|
||||
.reading-toggle-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 14px;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--mc-text-secondary);
|
||||
border-radius: 9px;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
.reading-toggle-btn:hover { color: var(--mc-text-primary); }
|
||||
.reading-toggle-btn.active {
|
||||
color: var(--mc-primary);
|
||||
background: var(--mc-bg-elevated);
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||
font-weight: 600;
|
||||
}
|
||||
.mode-switch-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px 12px;
|
||||
background: var(--mc-bg-elevated);
|
||||
border: 1px solid var(--mc-border-light);
|
||||
border-radius: 10px;
|
||||
color: var(--mc-text-secondary);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
.mode-switch-btn:hover {
|
||||
color: var(--mc-primary);
|
||||
border-color: var(--mc-primary);
|
||||
background: var(--mc-primary-bg);
|
||||
}
|
||||
.workspace-title {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
:kb-stats="kbStats"
|
||||
:loading="store.loading"
|
||||
@open="enterKB"
|
||||
@manage="enterKBManage"
|
||||
@create="showCreateKB = true"
|
||||
@delete="handleDeleteKB"
|
||||
/>
|
||||
@ -82,7 +83,11 @@ const newKBName = ref('')
|
||||
const newKBDesc = ref('')
|
||||
|
||||
async function enterKB(id: number) {
|
||||
await store.selectKB(id)
|
||||
await store.selectKB(id, 'browse')
|
||||
}
|
||||
|
||||
async function enterKBManage(id: number) {
|
||||
await store.selectKB(id, 'manage')
|
||||
}
|
||||
|
||||
async function handleCreateKB() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user