@lemoncat7/dsh-knowledge 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api.js +4 -0
- package/lib/api.js.map +1 -1
- package/lib/client.js +2 -3
- package/lib/client.js.map +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/local-provider.d.ts +1 -0
- package/lib/local-provider.d.ts.map +1 -1
- package/lib/local-provider.js +5 -0
- package/lib/local-provider.js.map +1 -1
- package/lib/provider.d.ts +1 -0
- package/lib/provider.d.ts.map +1 -1
- package/lib/remote-provider.d.ts +1 -0
- package/lib/remote-provider.d.ts.map +1 -1
- package/lib/remote-provider.js +19 -3
- package/lib/remote-provider.js.map +1 -1
- package/package.json +1 -1
- package/web/app.js +277 -110
- package/web/styles.css +243 -17
package/web/app.js
CHANGED
|
@@ -29,6 +29,13 @@ const app = document.querySelector('#app')
|
|
|
29
29
|
const toastRegion = document.querySelector('#toast-region')
|
|
30
30
|
const savedDocumentLayout = readDocumentLayout()
|
|
31
31
|
|
|
32
|
+
function createDocumentViewState(overrides = {}) {
|
|
33
|
+
return {
|
|
34
|
+
knowledgeBaseId: '', documentId: '', query: '', mode: 'preview', treeOpen: false,
|
|
35
|
+
expandedBases: new Set(), editor: null, ...overrides,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
32
39
|
const state = {
|
|
33
40
|
token: sessionStorage.getItem(TOKEN_KEY) || '',
|
|
34
41
|
view: 'entries',
|
|
@@ -51,14 +58,15 @@ const state = {
|
|
|
51
58
|
nextCursor: null,
|
|
52
59
|
entryFilters: { query: '', type: '', status: 'active', projectId: '', knowledgeBaseId: '' },
|
|
53
60
|
documents: [],
|
|
54
|
-
documentView: {
|
|
55
|
-
knowledgeBaseId: '', documentId: '', query: '',
|
|
56
|
-
mode: 'preview',
|
|
57
|
-
treeOpen: false,
|
|
61
|
+
documentView: createDocumentViewState({
|
|
58
62
|
sidebarHidden: savedDocumentLayout.sidebarHidden,
|
|
59
63
|
sidebarWidth: savedDocumentLayout.sidebarWidth,
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
}),
|
|
65
|
+
libraryDetail: {
|
|
66
|
+
knowledgeBaseId: '',
|
|
67
|
+
documents: [],
|
|
68
|
+
error: '',
|
|
69
|
+
view: createDocumentViewState(),
|
|
62
70
|
},
|
|
63
71
|
candidates: [],
|
|
64
72
|
candidateTargets: new Map(),
|
|
@@ -76,34 +84,45 @@ const state = {
|
|
|
76
84
|
let scrollRestoreFrame = 0
|
|
77
85
|
|
|
78
86
|
function installHostThemeBridge() {
|
|
79
|
-
if (window.parent === window) return
|
|
87
|
+
if (window.parent === window) return Promise.resolve()
|
|
80
88
|
const parentOrigin = referrerOrigin()
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const root = document.documentElement
|
|
90
|
-
for (const name of [...HOST_THEME_COLOR_TOKENS, ...HOST_THEME_STYLE_TOKENS]) root.style.removeProperty(name)
|
|
91
|
-
for (const [name, value] of Object.entries(message.tokens)) {
|
|
92
|
-
if (typeof value !== 'string' || value.length === 0 || value.length > 512) continue
|
|
93
|
-
if (HOST_THEME_COLOR_TOKENS.has(name) && CSS.supports('color', value)) root.style.setProperty(name, value)
|
|
94
|
-
else if (HOST_THEME_STYLE_TOKENS.has(name) && CSS.supports('box-shadow', value)) root.style.setProperty(name, value)
|
|
89
|
+
return new Promise(resolve => {
|
|
90
|
+
let initialThemeSettled = false
|
|
91
|
+
const settleInitialTheme = () => {
|
|
92
|
+
if (initialThemeSettled) return
|
|
93
|
+
initialThemeSettled = true
|
|
94
|
+
window.clearTimeout(fallback)
|
|
95
|
+
resolve()
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
const fallback = window.setTimeout(settleInitialTheme, 160)
|
|
98
|
+
window.addEventListener('message', event => {
|
|
99
|
+
if (event.source !== window.parent) return
|
|
100
|
+
if (parentOrigin && event.origin !== parentOrigin) return
|
|
101
|
+
const message = event.data
|
|
102
|
+
if (!message || message.type !== HOST_THEME_MESSAGE || message.version !== HOST_THEME_PROTOCOL_VERSION) return
|
|
103
|
+
if (message.colorScheme !== 'light' && message.colorScheme !== 'dark') return
|
|
104
|
+
if (!message.tokens || typeof message.tokens !== 'object' || Array.isArray(message.tokens)) return
|
|
105
|
+
|
|
106
|
+
const root = document.documentElement
|
|
107
|
+
for (const name of [...HOST_THEME_COLOR_TOKENS, ...HOST_THEME_STYLE_TOKENS]) root.style.removeProperty(name)
|
|
108
|
+
for (const [name, value] of Object.entries(message.tokens)) {
|
|
109
|
+
if (typeof value !== 'string' || value.length === 0 || value.length > 512) continue
|
|
110
|
+
if (HOST_THEME_COLOR_TOKENS.has(name) && CSS.supports('color', value)) root.style.setProperty(name, value)
|
|
111
|
+
else if (HOST_THEME_STYLE_TOKENS.has(name) && CSS.supports('box-shadow', value)) root.style.setProperty(name, value)
|
|
112
|
+
}
|
|
113
|
+
root.dataset.dshHostTheme = 'true'
|
|
114
|
+
root.style.colorScheme = message.colorScheme
|
|
115
|
+
root.style.setProperty('--dialog-surface', root.style.getPropertyValue('--surface-raised') || root.style.getPropertyValue('--surface'))
|
|
116
|
+
document.querySelector('meta[name="color-scheme"]')?.setAttribute('content', message.colorScheme)
|
|
117
|
+
const background = root.style.getPropertyValue('--bg')
|
|
118
|
+
if (background) document.querySelector('meta[name="theme-color"]')?.setAttribute('content', background)
|
|
119
|
+
settleInitialTheme()
|
|
120
|
+
})
|
|
121
|
+
window.parent.postMessage({
|
|
122
|
+
type: HOST_THEME_READY_MESSAGE,
|
|
123
|
+
version: HOST_THEME_PROTOCOL_VERSION,
|
|
124
|
+
}, parentOrigin || '*')
|
|
102
125
|
})
|
|
103
|
-
window.parent.postMessage({
|
|
104
|
-
type: HOST_THEME_READY_MESSAGE,
|
|
105
|
-
version: HOST_THEME_PROTOCOL_VERSION,
|
|
106
|
-
}, parentOrigin || '*')
|
|
107
126
|
}
|
|
108
127
|
|
|
109
128
|
function referrerOrigin() {
|
|
@@ -152,12 +171,16 @@ function captureScrollPosition() {
|
|
|
152
171
|
const key = node.getAttribute('data-scroll-key')
|
|
153
172
|
if (key) regions[key] = { left: node.scrollLeft, top: node.scrollTop }
|
|
154
173
|
})
|
|
155
|
-
state.scrollPositions.set(shell.dataset.view, {
|
|
174
|
+
state.scrollPositions.set(shell.dataset.scrollState || shell.dataset.view, {
|
|
156
175
|
window: { left: window.scrollX, top: window.scrollY },
|
|
157
176
|
regions,
|
|
158
177
|
})
|
|
159
178
|
}
|
|
160
179
|
|
|
180
|
+
function currentScrollState() {
|
|
181
|
+
return state.view === 'bases' ? `bases:${state.knowledgeBaseView}` : state.view
|
|
182
|
+
}
|
|
183
|
+
|
|
161
184
|
function restoreScrollPosition(view) {
|
|
162
185
|
if (state.loading) return
|
|
163
186
|
const saved = state.scrollPositions.get(view)
|
|
@@ -319,6 +342,10 @@ function signOut() {
|
|
|
319
342
|
}
|
|
320
343
|
|
|
321
344
|
async function navigate(view) {
|
|
345
|
+
const previousView = state.view
|
|
346
|
+
if (view === 'bases' && previousView !== 'bases' && state.knowledgeBaseView === 'detail') {
|
|
347
|
+
state.knowledgeBaseView = 'libraries'
|
|
348
|
+
}
|
|
322
349
|
state.view = view
|
|
323
350
|
state.menuOpen = false
|
|
324
351
|
state.loading = true
|
|
@@ -412,15 +439,16 @@ async function loadDocuments() {
|
|
|
412
439
|
state.resolvedMounts = resolved
|
|
413
440
|
const visibleBaseIds = new Set(documentKnowledgeBases(bases).map(base => base.id))
|
|
414
441
|
state.documents = documents.filter(document => visibleBaseIds.has(document.knowledgeBaseId))
|
|
415
|
-
const
|
|
442
|
+
const workspace = sessionDocumentWorkspace()
|
|
443
|
+
const view = workspace.view
|
|
416
444
|
const availableBaseIds = visibleBaseIds
|
|
417
445
|
if (!view.knowledgeBaseId || !availableBaseIds.has(view.knowledgeBaseId)) {
|
|
418
446
|
view.knowledgeBaseId = state.entryFilters.knowledgeBaseId && availableBaseIds.has(state.entryFilters.knowledgeBaseId)
|
|
419
447
|
? state.entryFilters.knowledgeBaseId
|
|
420
448
|
: documentKnowledgeBases(bases)[0]?.id || ''
|
|
421
449
|
}
|
|
422
|
-
selectDefaultDocument()
|
|
423
|
-
if (view.documentId) await loadDocumentEditor(view.documentId)
|
|
450
|
+
selectDefaultDocument(workspace)
|
|
451
|
+
if (view.documentId) await loadDocumentEditor(workspace, view.documentId)
|
|
424
452
|
else view.editor = null
|
|
425
453
|
if (!state.stats) await refreshStats()
|
|
426
454
|
}
|
|
@@ -432,19 +460,65 @@ function documentKnowledgeBases(bases = state.knowledgeBases) {
|
|
|
432
460
|
return active.filter(base => mountedIds.has(base.id))
|
|
433
461
|
}
|
|
434
462
|
|
|
435
|
-
function
|
|
436
|
-
|
|
437
|
-
|
|
463
|
+
function sessionDocumentWorkspace() {
|
|
464
|
+
return { kind: 'session', view: state.documentView }
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function libraryDocumentWorkspace() {
|
|
468
|
+
return { kind: 'library', view: state.libraryDetail.view }
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function activeDocumentWorkspace() {
|
|
472
|
+
if (state.view === 'entries') return sessionDocumentWorkspace()
|
|
473
|
+
if (state.view === 'bases' && state.knowledgeBaseView === 'detail') return libraryDocumentWorkspace()
|
|
474
|
+
return null
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function documentWorkspaceDocuments(workspace) {
|
|
478
|
+
return workspace.kind === 'library' ? state.libraryDetail.documents : state.documents
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function setDocumentWorkspaceDocuments(workspace, documents) {
|
|
482
|
+
if (workspace.kind === 'library') state.libraryDetail.documents = documents
|
|
483
|
+
else state.documents = documents
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function documentWorkspaceBases(workspace) {
|
|
487
|
+
if (workspace.kind === 'library') {
|
|
488
|
+
const base = state.knowledgeBases.find(item => item.id === state.libraryDetail.knowledgeBaseId)
|
|
489
|
+
return base ? [base] : []
|
|
490
|
+
}
|
|
491
|
+
return documentKnowledgeBases()
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function documentWorkspaceReadOnly(workspace) {
|
|
495
|
+
return workspace.kind === 'library' && documentWorkspaceBases(workspace)[0]?.status === 'archived'
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
async function reloadDocumentWorkspace(workspace) {
|
|
499
|
+
const documents = workspace.kind === 'library'
|
|
500
|
+
? await api(`documents?knowledgeBaseId=${encodeURIComponent(state.libraryDetail.knowledgeBaseId)}`)
|
|
501
|
+
: await api('documents')
|
|
502
|
+
if (workspace.kind === 'library') setDocumentWorkspaceDocuments(workspace, documents)
|
|
503
|
+
else {
|
|
504
|
+
const visibleBaseIds = new Set(documentKnowledgeBases().map(base => base.id))
|
|
505
|
+
setDocumentWorkspaceDocuments(workspace, documents.filter(document => visibleBaseIds.has(document.knowledgeBaseId)))
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function selectDefaultDocument(workspace) {
|
|
510
|
+
const view = workspace.view
|
|
511
|
+
const documents = documentWorkspaceDocuments(workspace).filter(document => document.knowledgeBaseId === view.knowledgeBaseId)
|
|
438
512
|
if (!documents.some(document => document.id === view.documentId)) {
|
|
439
513
|
view.documentId = documents[0]?.id || ''
|
|
440
514
|
}
|
|
441
515
|
if (view.knowledgeBaseId) view.expandedBases.add(view.knowledgeBaseId)
|
|
442
516
|
}
|
|
443
517
|
|
|
444
|
-
async function loadDocumentEditor(id) {
|
|
518
|
+
async function loadDocumentEditor(workspace, id) {
|
|
445
519
|
const entry = await api(`entries/${encodeURIComponent(id)}`)
|
|
446
|
-
|
|
447
|
-
|
|
520
|
+
workspace.view.mode = 'preview'
|
|
521
|
+
workspace.view.editor = {
|
|
448
522
|
...entry,
|
|
449
523
|
tagsText: entry.tags.join(', '),
|
|
450
524
|
dirty: false,
|
|
@@ -453,10 +527,10 @@ async function loadDocumentEditor(id) {
|
|
|
453
527
|
}
|
|
454
528
|
}
|
|
455
529
|
|
|
456
|
-
function createBlankDocument(baseId) {
|
|
530
|
+
function createBlankDocument(workspace, baseId) {
|
|
457
531
|
const base = state.knowledgeBases.find(item => item.id === baseId && item.status === 'active')
|
|
458
532
|
if (!base) return showToast('请先选择一个可用知识库。', 'error')
|
|
459
|
-
const view =
|
|
533
|
+
const view = workspace.view
|
|
460
534
|
view.knowledgeBaseId = base.id
|
|
461
535
|
view.documentId = ''
|
|
462
536
|
view.mode = 'edit'
|
|
@@ -470,20 +544,20 @@ function createBlankDocument(baseId) {
|
|
|
470
544
|
document.querySelector('.note-title-input')?.focus()
|
|
471
545
|
}
|
|
472
546
|
|
|
473
|
-
async function startBlankDocument(baseId) {
|
|
474
|
-
const editor =
|
|
547
|
+
async function startBlankDocument(workspace, baseId) {
|
|
548
|
+
const editor = workspace.view.editor
|
|
475
549
|
const emptyDraft = editor?.isNew && !editor.title.trim() && !editor.body.trim()
|
|
476
|
-
if (editor?.dirty && !emptyDraft && !await saveDocumentEditor()) return
|
|
477
|
-
createBlankDocument(baseId)
|
|
550
|
+
if (editor?.dirty && !emptyDraft && !await saveDocumentEditor(workspace)) return
|
|
551
|
+
createBlankDocument(workspace, baseId)
|
|
478
552
|
}
|
|
479
553
|
|
|
480
|
-
async function selectDocument(id) {
|
|
481
|
-
const editor =
|
|
554
|
+
async function selectDocument(workspace, id) {
|
|
555
|
+
const editor = workspace.view.editor
|
|
482
556
|
const emptyDraft = editor?.isNew && !editor.title.trim() && !editor.body.trim()
|
|
483
|
-
if (editor?.dirty && !emptyDraft && !await saveDocumentEditor()) return
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
await loadDocumentEditor(id)
|
|
557
|
+
if (editor?.dirty && !emptyDraft && !await saveDocumentEditor(workspace)) return
|
|
558
|
+
workspace.view.documentId = id
|
|
559
|
+
workspace.view.treeOpen = false
|
|
560
|
+
await loadDocumentEditor(workspace, id)
|
|
487
561
|
renderShell()
|
|
488
562
|
}
|
|
489
563
|
|
|
@@ -500,8 +574,9 @@ function editorDraft(editor) {
|
|
|
500
574
|
}
|
|
501
575
|
}
|
|
502
576
|
|
|
503
|
-
async function saveDocumentEditor() {
|
|
504
|
-
|
|
577
|
+
async function saveDocumentEditor(workspace = activeDocumentWorkspace()) {
|
|
578
|
+
if (!workspace) return false
|
|
579
|
+
const editor = workspace.view.editor
|
|
505
580
|
if (!editor || !editor.dirty) return true
|
|
506
581
|
if (!editor.isNew && editor.documentState !== 'open') {
|
|
507
582
|
showToast('这篇文档已经结束并封存;请先重新打开。', 'error')
|
|
@@ -523,10 +598,9 @@ async function saveDocumentEditor() {
|
|
|
523
598
|
editor.dirty = false
|
|
524
599
|
editor.updatedAt = saved.updatedAt
|
|
525
600
|
editor.saveState = '已保存'
|
|
526
|
-
|
|
601
|
+
workspace.view.documentId = saved.id
|
|
527
602
|
updateEditorSaveState(editor.saveState)
|
|
528
|
-
|
|
529
|
-
state.documents = documents
|
|
603
|
+
await reloadDocumentWorkspace(workspace)
|
|
530
604
|
return true
|
|
531
605
|
} catch (error) {
|
|
532
606
|
editor.saveState = '保存失败'
|
|
@@ -576,6 +650,8 @@ function renderShell() {
|
|
|
576
650
|
const shell = element('div', {
|
|
577
651
|
class: 'app-shell', 'data-menu-open': String(state.menuOpen),
|
|
578
652
|
'data-view': state.view, 'data-loading': String(state.loading),
|
|
653
|
+
'data-scroll-state': currentScrollState(),
|
|
654
|
+
'data-base-detail': String(state.view === 'bases' && state.knowledgeBaseView === 'detail'),
|
|
579
655
|
'data-sidebar-hidden': String(state.documentView.sidebarHidden),
|
|
580
656
|
style: `--sidebar-width: ${state.documentView.sidebarWidth}px`,
|
|
581
657
|
},
|
|
@@ -586,8 +662,10 @@ function renderShell() {
|
|
|
586
662
|
element('div', { class: 'topbar-title' },
|
|
587
663
|
actionButton('☰', () => { state.menuOpen = !state.menuOpen; renderShell() }, 'ghost mobile-menu', { 'aria-label': '打开导航菜单' }),
|
|
588
664
|
paneToggleButton('main', !state.documentView.sidebarHidden, () => setSidebarHidden(!state.documentView.sidebarHidden), '主导航栏'),
|
|
589
|
-
|
|
590
|
-
|
|
665
|
+
activeDocumentWorkspace() ? paneToggleButton('library', activeDocumentWorkspace().view.treeOpen, () => {
|
|
666
|
+
const workspace = activeDocumentWorkspace()
|
|
667
|
+
if (!workspace) return
|
|
668
|
+
workspace.view.treeOpen = !workspace.view.treeOpen
|
|
591
669
|
renderShell()
|
|
592
670
|
}, '知识目录') : null,
|
|
593
671
|
element('div', {}, element('h1', {}, title), element('p', {}, subtitle)),
|
|
@@ -600,7 +678,7 @@ function renderShell() {
|
|
|
600
678
|
if (event.target === shell) { state.menuOpen = false; renderShell() }
|
|
601
679
|
})
|
|
602
680
|
app.replaceChildren(shell)
|
|
603
|
-
restoreScrollPosition(
|
|
681
|
+
restoreScrollPosition(currentScrollState())
|
|
604
682
|
}
|
|
605
683
|
|
|
606
684
|
function renderAppSidebarResizer() {
|
|
@@ -751,6 +829,7 @@ function renderOverview() {
|
|
|
751
829
|
function renderKnowledgeBases() {
|
|
752
830
|
const activeBases = state.knowledgeBases.filter(base => base.status === 'active')
|
|
753
831
|
const archivedBases = state.knowledgeBases.filter(base => base.status === 'archived')
|
|
832
|
+
if (state.knowledgeBaseView === 'detail') return renderKnowledgeBaseDetail()
|
|
754
833
|
const contextAvailable = Boolean(state.mountContext.projectId || state.mountContext.sessionId)
|
|
755
834
|
const query = state.knowledgeBaseQuery.trim().toLocaleLowerCase()
|
|
756
835
|
const matchesQuery = base => !query || [base.name, base.description, base.defaultTags.join(' ')]
|
|
@@ -820,6 +899,82 @@ function renderKnowledgeBases() {
|
|
|
820
899
|
)
|
|
821
900
|
}
|
|
822
901
|
|
|
902
|
+
async function openKnowledgeBaseDocuments(base) {
|
|
903
|
+
captureScrollPosition()
|
|
904
|
+
const detail = state.libraryDetail
|
|
905
|
+
const changingBase = detail.knowledgeBaseId !== base.id
|
|
906
|
+
detail.knowledgeBaseId = base.id
|
|
907
|
+
if (changingBase) {
|
|
908
|
+
detail.documents = []
|
|
909
|
+
detail.view = createDocumentViewState({ knowledgeBaseId: base.id })
|
|
910
|
+
} else {
|
|
911
|
+
detail.view.knowledgeBaseId = base.id
|
|
912
|
+
}
|
|
913
|
+
state.knowledgeBaseView = 'detail'
|
|
914
|
+
state.loading = true
|
|
915
|
+
detail.error = ''
|
|
916
|
+
renderShell()
|
|
917
|
+
const workspace = libraryDocumentWorkspace()
|
|
918
|
+
try {
|
|
919
|
+
await reloadDocumentWorkspace(workspace)
|
|
920
|
+
selectDefaultDocument(workspace)
|
|
921
|
+
if (workspace.view.documentId) await loadDocumentEditor(workspace, workspace.view.documentId)
|
|
922
|
+
else workspace.view.editor = null
|
|
923
|
+
} catch (error) {
|
|
924
|
+
detail.error = friendlyError(error)
|
|
925
|
+
} finally {
|
|
926
|
+
state.loading = false
|
|
927
|
+
renderShell()
|
|
928
|
+
window.requestAnimationFrame(() => document.querySelector('.library-detail-back')?.focus())
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
async function closeKnowledgeBaseDetail() {
|
|
933
|
+
const workspace = libraryDocumentWorkspace()
|
|
934
|
+
const editor = workspace.view.editor
|
|
935
|
+
const emptyDraft = editor?.isNew && !editor.title.trim() && !editor.body.trim()
|
|
936
|
+
if (editor?.dirty && !emptyDraft && !await saveDocumentEditor(workspace)) return
|
|
937
|
+
const baseId = state.libraryDetail.knowledgeBaseId
|
|
938
|
+
state.knowledgeBaseView = 'libraries'
|
|
939
|
+
state.libraryDetail.error = ''
|
|
940
|
+
renderShell()
|
|
941
|
+
window.requestAnimationFrame(() => document.querySelector(`[data-open-knowledge-base="${CSS.escape(baseId)}"]`)?.focus())
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
function renderKnowledgeBaseDetail() {
|
|
945
|
+
const base = state.knowledgeBases.find(item => item.id === state.libraryDetail.knowledgeBaseId)
|
|
946
|
+
if (!base) return emptyState('知识库不可用', '它可能已被删除,请返回知识库列表重新选择。', '返回我的知识库', () => { state.knowledgeBaseView = 'libraries'; renderShell() })
|
|
947
|
+
const workspace = libraryDocumentWorkspace()
|
|
948
|
+
const archived = base.status === 'archived'
|
|
949
|
+
const mountStatus = state.mountContext.sessionId
|
|
950
|
+
? mountView(base, 'session', state.mountContext.sessionId)
|
|
951
|
+
: state.mountContext.projectId ? mountView(base, 'project', state.mountContext.projectId) : null
|
|
952
|
+
return element('section', { class: 'library-detail', 'aria-labelledby': 'library-detail-title' },
|
|
953
|
+
element('header', { class: 'library-detail-header' },
|
|
954
|
+
actionButton('我的知识库', () => { void closeKnowledgeBaseDetail() }, 'ghost small library-detail-back', { 'aria-label': '返回我的知识库' }),
|
|
955
|
+
element('div', { class: 'library-detail-identity' },
|
|
956
|
+
element('span', { class: 'base-symbol', 'aria-hidden': 'true' }, base.name.trim().slice(0, 1).toLocaleUpperCase() || 'K'),
|
|
957
|
+
element('div', {},
|
|
958
|
+
element('div', { class: 'library-detail-title-line' },
|
|
959
|
+
element('h2', { id: 'library-detail-title' }, base.name),
|
|
960
|
+
badge(archived ? '已归档' : '可用', archived ? '' : 'success'),
|
|
961
|
+
mountStatus ? badge(mountStatus.statusLabel, mountStatus.statusVariant) : badge('未选择挂载范围'),
|
|
962
|
+
),
|
|
963
|
+
element('p', {}, base.description || '通用知识库,尚未设置匹配描述。'),
|
|
964
|
+
),
|
|
965
|
+
),
|
|
966
|
+
element('div', { class: 'library-detail-actions' },
|
|
967
|
+
archived ? actionButton('恢复知识库', () => confirmRestoreKnowledgeBase(base), 'small') : actionButton('编辑知识库', () => openKnowledgeBaseEditor(base), 'small'),
|
|
968
|
+
!archived ? actionButton('+ 新建文档', () => { void startBlankDocument(workspace, base.id) }, 'primary small') : null,
|
|
969
|
+
),
|
|
970
|
+
),
|
|
971
|
+
archived ? element('div', { class: 'library-detail-notice', role: 'status' }, '这个知识库已经归档。文档仍可阅读,但恢复知识库后才能新建或修改。') : null,
|
|
972
|
+
state.libraryDetail.error
|
|
973
|
+
? errorView(state.libraryDetail.error, () => { void openKnowledgeBaseDocuments(base) })
|
|
974
|
+
: renderDocumentWorkspace(workspace, { heading: base.name, singleBase: true }),
|
|
975
|
+
)
|
|
976
|
+
}
|
|
977
|
+
|
|
823
978
|
async function openGlobalWritebackModelEditor() {
|
|
824
979
|
await loadModelCatalog()
|
|
825
980
|
const custom = element('input', { type: 'checkbox', checked: Boolean(state.service.writebackProvider && state.service.writebackModel) })
|
|
@@ -866,12 +1021,7 @@ function renderKnowledgeBaseCard(base) {
|
|
|
866
1021
|
base.extractionInstructions ? element('span', {}, element('strong', {}, '提取规则'), '已设置') : null,
|
|
867
1022
|
),
|
|
868
1023
|
element('div', { class: 'base-card-actions' },
|
|
869
|
-
actionButton('查看知识', () => {
|
|
870
|
-
state.entryFilters.knowledgeBaseId = base.id
|
|
871
|
-
state.documentView.knowledgeBaseId = base.id
|
|
872
|
-
state.documentView.documentId = ''
|
|
873
|
-
void navigate('entries')
|
|
874
|
-
}, 'ghost small'),
|
|
1024
|
+
actionButton('查看知识', () => { void openKnowledgeBaseDocuments(base) }, 'ghost small', { 'data-open-knowledge-base': base.id }),
|
|
875
1025
|
archived ? actionButton('恢复', () => confirmRestoreKnowledgeBase(base), 'small') : actionButton('编辑', () => openKnowledgeBaseEditor(base), 'small'),
|
|
876
1026
|
archived ? actionButton('永久删除', () => confirmDeleteKnowledgeBase(base), 'danger small') : null,
|
|
877
1027
|
!archived && base.id !== 'default' ? actionButton('归档', () => confirmArchiveKnowledgeBase(base), 'danger small') : null,
|
|
@@ -1027,23 +1177,30 @@ function compactEmpty(message) {
|
|
|
1027
1177
|
}
|
|
1028
1178
|
|
|
1029
1179
|
function renderEntries() {
|
|
1030
|
-
|
|
1180
|
+
return renderDocumentWorkspace(sessionDocumentWorkspace(), { heading: '知识目录' })
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
function renderDocumentWorkspace(workspace, options = {}) {
|
|
1184
|
+
const view = workspace.view
|
|
1031
1185
|
const query = view.query.trim().toLocaleLowerCase()
|
|
1032
|
-
const activeBases =
|
|
1186
|
+
const activeBases = documentWorkspaceBases(workspace)
|
|
1187
|
+
const workspaceDocuments = documentWorkspaceDocuments(workspace)
|
|
1188
|
+
const readOnly = documentWorkspaceReadOnly(workspace)
|
|
1033
1189
|
const selectedBase = activeBases.find(base => base.id === view.knowledgeBaseId)
|
|
1034
1190
|
const search = element('input', {
|
|
1035
1191
|
class: 'note-tree-search', type: 'search', value: view.query, placeholder: '搜索文档', 'aria-label': '搜索知识库文档',
|
|
1192
|
+
'data-document-scope': workspace.kind,
|
|
1036
1193
|
onInput: (event) => {
|
|
1037
1194
|
view.query = event.target.value
|
|
1038
1195
|
renderShell()
|
|
1039
|
-
const input = document.querySelector(
|
|
1196
|
+
const input = document.querySelector(`.note-tree-search[data-document-scope="${workspace.kind}"]`)
|
|
1040
1197
|
input?.focus()
|
|
1041
1198
|
input?.setSelectionRange(input.value.length, input.value.length)
|
|
1042
1199
|
},
|
|
1043
1200
|
})
|
|
1044
1201
|
const tree = activeBases.map(base => {
|
|
1045
1202
|
const expanded = view.expandedBases.has(base.id) || Boolean(query)
|
|
1046
|
-
const documents =
|
|
1203
|
+
const documents = workspaceDocuments.filter(document => document.knowledgeBaseId === base.id
|
|
1047
1204
|
&& (!query || [document.title, document.relPath, document.content].some(value => value.toLocaleLowerCase().includes(query))))
|
|
1048
1205
|
return element('section', { class: 'note-tree-group', 'data-expanded': String(expanded) },
|
|
1049
1206
|
element('button', {
|
|
@@ -1062,48 +1219,50 @@ function renderEntries() {
|
|
|
1062
1219
|
expanded ? element('div', { class: 'note-tree-documents', role: 'group', 'aria-label': `${base.name}文档` },
|
|
1063
1220
|
documents.map(document => element('button', {
|
|
1064
1221
|
type: 'button', class: 'note-tree-document', 'aria-current': document.id === view.documentId ? 'page' : undefined,
|
|
1065
|
-
onClick: () => { void selectDocument(document.id) },
|
|
1222
|
+
onClick: () => { void selectDocument(workspace, document.id) },
|
|
1066
1223
|
}, element('span', { class: 'tree-document-icon', 'aria-hidden': 'true' }), element('span', { class: 'tree-document-copy' },
|
|
1067
1224
|
element('strong', {}, document.title), element('small', {}, document.relPath)),
|
|
1068
1225
|
document.documentState !== 'open' ? badge(DOCUMENT_STATE_LABELS[document.documentState] || '已结束', 'success') : null)),
|
|
1069
|
-
!query ? element('button', { type: 'button', class: 'note-tree-new', onClick: () => { void startBlankDocument(base.id) } },
|
|
1226
|
+
!query && !readOnly ? element('button', { type: 'button', class: 'note-tree-new', onClick: () => { void startBlankDocument(workspace, base.id) } },
|
|
1070
1227
|
element('span', { 'aria-hidden': 'true' }, '+'), '新建文档') : null,
|
|
1071
1228
|
) : null,
|
|
1072
1229
|
)
|
|
1073
1230
|
})
|
|
1074
1231
|
return element('section', {
|
|
1075
|
-
class:
|
|
1232
|
+
class: `note-workspace note-workspace--${workspace.kind}`, 'aria-labelledby': `${workspace.kind}-documents-heading`,
|
|
1076
1233
|
'data-tree-open': String(view.treeOpen),
|
|
1077
1234
|
},
|
|
1078
1235
|
element('aside', { class: 'note-tree-panel', 'aria-label': '知识目录' },
|
|
1079
1236
|
element('header', { class: 'note-tree-header' },
|
|
1080
|
-
element('div', {}, element('h2', { id:
|
|
1081
|
-
actionButton('+', () => { void startBlankDocument(view.knowledgeBaseId || activeBases[0]?.id) }, 'ghost note-add-button', { 'aria-label': '新建文档', title: '新建文档' }),
|
|
1237
|
+
element('div', {}, element('h2', { id: `${workspace.kind}-documents-heading` }, options.heading || '知识目录'), element('span', {}, `${workspaceDocuments.length} 篇文档`)),
|
|
1238
|
+
!readOnly ? actionButton('+', () => { void startBlankDocument(workspace, view.knowledgeBaseId || activeBases[0]?.id) }, 'ghost note-add-button', { 'aria-label': '新建文档', title: '新建文档' }) : null,
|
|
1082
1239
|
),
|
|
1083
1240
|
element('div', { class: 'note-tree-search-wrap' }, interfaceIcon('search', 'search-symbol'), search),
|
|
1084
|
-
element('nav', { class: 'note-tree', 'data-scroll-key':
|
|
1085
|
-
element('footer', { class: 'note-tree-footer' }, actionButton('新建知识库', () => openKnowledgeBaseEditor(), 'ghost small')),
|
|
1241
|
+
element('nav', { class: 'note-tree', 'data-scroll-key': `${workspace.kind}-note-tree` }, tree.length ? tree : element('div', { class: 'note-tree-empty' }, workspace.kind === 'session' && state.mountContext.sessionId ? '当前会话未挂载知识库' : '还没有知识库')),
|
|
1242
|
+
workspace.kind === 'session' ? element('footer', { class: 'note-tree-footer' }, actionButton('新建知识库', () => openKnowledgeBaseEditor(), 'ghost small')) : null,
|
|
1086
1243
|
),
|
|
1087
1244
|
view.treeOpen ? element('button', {
|
|
1088
1245
|
type: 'button', class: 'note-tree-scrim', 'aria-label': '关闭知识目录',
|
|
1089
1246
|
onClick: () => { view.treeOpen = false; renderShell() },
|
|
1090
1247
|
}) : null,
|
|
1091
|
-
renderNoteEditor(view.editor, selectedBase),
|
|
1248
|
+
renderNoteEditor(workspace, view.editor, selectedBase),
|
|
1092
1249
|
)
|
|
1093
1250
|
}
|
|
1094
1251
|
|
|
1095
|
-
function renderNoteEditor(editor, base) {
|
|
1252
|
+
function renderNoteEditor(workspace, editor, base) {
|
|
1253
|
+
const view = workspace.view
|
|
1254
|
+
const readOnly = documentWorkspaceReadOnly(workspace)
|
|
1096
1255
|
if (!editor) return element('main', { class: 'note-editor note-editor-empty' },
|
|
1097
1256
|
element('div', { class: 'note-empty-content' },
|
|
1098
1257
|
element('span', { class: 'empty-document-mark', 'aria-hidden': 'true' }),
|
|
1099
1258
|
element('h3', {}, '选择或新建一篇文档'),
|
|
1100
|
-
element('p', {}, '文档保存后会立即参与当前知识库的搜索与召回。'),
|
|
1101
|
-
actionButton('新建文档', () => { void startBlankDocument(
|
|
1259
|
+
element('p', {}, readOnly ? '这个知识库已归档,当前只能阅读已有文档。' : '文档保存后会立即参与当前知识库的搜索与召回。'),
|
|
1260
|
+
!readOnly ? actionButton('新建文档', () => { void startBlankDocument(workspace, view.knowledgeBaseId || state.knowledgeBases.find(item => item.status === 'active')?.id) }, 'primary') : null,
|
|
1102
1261
|
))
|
|
1103
1262
|
const saveShortcut = event => {
|
|
1104
1263
|
if ((event.metaKey || event.ctrlKey) && event.key.toLocaleLowerCase() === 's') {
|
|
1105
1264
|
event.preventDefault()
|
|
1106
|
-
void saveDocumentEditor().then(saved => { if (saved) renderShell() })
|
|
1265
|
+
void saveDocumentEditor(workspace).then(saved => { if (saved) renderShell() })
|
|
1107
1266
|
}
|
|
1108
1267
|
}
|
|
1109
1268
|
const update = (key, value) => {
|
|
@@ -1122,27 +1281,27 @@ function renderNoteEditor(editor, base) {
|
|
|
1122
1281
|
})
|
|
1123
1282
|
body.value = editor.body
|
|
1124
1283
|
const finalized = !editor.isNew && editor.documentState !== 'open'
|
|
1125
|
-
const mode = finalized ? 'preview' :
|
|
1284
|
+
const mode = finalized || readOnly ? 'preview' : view.mode === 'edit' ? 'edit' : 'preview'
|
|
1126
1285
|
if (mode === 'edit') window.requestAnimationFrame(() => resizeDocumentEditor(body))
|
|
1127
1286
|
return element('main', { class: 'note-editor', 'aria-label': '文档编辑器' },
|
|
1128
1287
|
element('header', { class: 'note-editor-toolbar' },
|
|
1129
1288
|
element('div', { class: 'note-breadcrumb' },
|
|
1130
1289
|
element('span', {}, base?.name || '知识库'),
|
|
1131
1290
|
element('span', { 'aria-hidden': 'true' }, '/'),
|
|
1132
|
-
element('strong', {}, editor.isNew ? '新文档' :
|
|
1291
|
+
element('strong', {}, editor.isNew ? '新文档' : documentWorkspaceDocuments(workspace).find(item => item.id === editor.id)?.relPath || editor.title)),
|
|
1133
1292
|
element('div', { class: 'note-editor-actions' },
|
|
1134
|
-
finalized ? badge(DOCUMENT_STATE_LABELS[editor.documentState] || '已结束', 'success') : element('div', { class: 'note-mode-switch', role: 'tablist', 'aria-label': '文档视图' }, [
|
|
1293
|
+
finalized ? badge(DOCUMENT_STATE_LABELS[editor.documentState] || '已结束', 'success') : readOnly ? badge('只读') : element('div', { class: 'note-mode-switch', role: 'tablist', 'aria-label': '文档视图' }, [
|
|
1135
1294
|
['edit', '编辑'],
|
|
1136
1295
|
['preview', '预览'],
|
|
1137
1296
|
].map(([value, label]) => element('button', {
|
|
1138
1297
|
type: 'button', role: 'tab', 'aria-selected': String(mode === value),
|
|
1139
|
-
onClick: () => switchDocumentMode(value),
|
|
1298
|
+
onClick: () => switchDocumentMode(workspace, value),
|
|
1140
1299
|
}, label))),
|
|
1141
1300
|
element('span', { class: 'editor-save-status', role: 'status' }, editor.saveState),
|
|
1142
|
-
finalized ? actionButton('重新打开', () => reopenDocument(editor), 'small') : null,
|
|
1143
|
-
!editor.isNew && !finalized ? actionButton('标记结束', () => openFinalizeDocument(editor), 'small') : null,
|
|
1144
|
-
!editor.isNew && !finalized ? actionButton('删除', () => confirmDeleteDocument(editor), 'ghost small') : null,
|
|
1145
|
-
!finalized ? actionButton(editor.isNew ? '创建文档' : '保存', () => { void saveDocumentEditor().then(saved => { if (saved) renderShell() }) }, 'primary small') : null,
|
|
1301
|
+
finalized && !readOnly ? actionButton('重新打开', () => reopenDocument(workspace, editor), 'small') : null,
|
|
1302
|
+
!readOnly && !editor.isNew && !finalized ? actionButton('标记结束', () => openFinalizeDocument(workspace, editor), 'small') : null,
|
|
1303
|
+
!readOnly && !editor.isNew && !finalized ? actionButton('删除', () => confirmDeleteDocument(workspace, editor), 'ghost small') : null,
|
|
1304
|
+
!readOnly && !finalized ? actionButton(editor.isNew ? '创建文档' : '保存', () => { void saveDocumentEditor(workspace).then(saved => { if (saved) renderShell() }) }, 'primary small') : null,
|
|
1146
1305
|
),
|
|
1147
1306
|
),
|
|
1148
1307
|
element('div', { class: 'note-editor-scroll', 'data-scroll-key': 'note-editor' },
|
|
@@ -1163,20 +1322,20 @@ function renderNoteEditor(editor, base) {
|
|
|
1163
1322
|
),
|
|
1164
1323
|
),
|
|
1165
1324
|
element('footer', { class: 'note-inspector' },
|
|
1166
|
-
finalized ? element('span', { class: 'note-format-hint' }, '只读封存 · 重新打开后才能编辑') : element('label', {}, element('span', {}, '类型'), element('select', {
|
|
1325
|
+
finalized || readOnly ? element('span', { class: 'note-format-hint' }, readOnly ? '知识库已归档 · 只读' : '只读封存 · 重新打开后才能编辑') : element('label', {}, element('span', {}, '类型'), element('select', {
|
|
1167
1326
|
class: 'note-meta-select', onChange: event => update('type', event.target.value),
|
|
1168
1327
|
}, TYPES.map(type => element('option', { value: type, selected: type === editor.type }, TYPE_LABELS[type])))),
|
|
1169
|
-
finalized ? null : element('label', { class: 'note-tags-field' }, element('span', {}, '标签'), element('input', {
|
|
1328
|
+
finalized || readOnly ? null : element('label', { class: 'note-tags-field' }, element('span', {}, '标签'), element('input', {
|
|
1170
1329
|
value: editor.tagsText, placeholder: '用逗号分隔', onInput: event => update('tagsText', event.target.value),
|
|
1171
1330
|
})),
|
|
1172
|
-
!finalized ? element('span', { class: 'note-format-hint' }, mode === 'edit' ? 'Markdown · Ctrl/⌘ S 保存' : 'Markdown 预览') : null,
|
|
1331
|
+
!finalized && !readOnly ? element('span', { class: 'note-format-hint' }, mode === 'edit' ? 'Markdown · Ctrl/⌘ S 保存' : 'Markdown 预览') : null,
|
|
1173
1332
|
),
|
|
1174
1333
|
)
|
|
1175
1334
|
}
|
|
1176
1335
|
|
|
1177
|
-
function switchDocumentMode(mode) {
|
|
1336
|
+
function switchDocumentMode(workspace, mode) {
|
|
1178
1337
|
if (mode !== 'edit' && mode !== 'preview') return
|
|
1179
|
-
|
|
1338
|
+
workspace.view.mode = mode
|
|
1180
1339
|
renderShell()
|
|
1181
1340
|
if (mode === 'edit') window.requestAnimationFrame(() => document.querySelector('.note-body-editor')?.focus())
|
|
1182
1341
|
}
|
|
@@ -1193,7 +1352,7 @@ function resizeDocumentEditor(editor) {
|
|
|
1193
1352
|
editor.style.height = `${Math.max(420, editor.scrollHeight)}px`
|
|
1194
1353
|
}
|
|
1195
1354
|
|
|
1196
|
-
function openFinalizeDocument(editor) {
|
|
1355
|
+
function openFinalizeDocument(workspace, editor) {
|
|
1197
1356
|
const form = element('form', { class: 'form-grid' })
|
|
1198
1357
|
const stateField = selectField('结束状态', [
|
|
1199
1358
|
{ value: 'resolved', label: '已解决 — 问题已有最终结论' },
|
|
@@ -1216,9 +1375,9 @@ function openFinalizeDocument(editor) {
|
|
|
1216
1375
|
method: 'POST',
|
|
1217
1376
|
body: { state: stateField.input.value, note: note.input.value.trim() },
|
|
1218
1377
|
})
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1378
|
+
workspace.view.editor = { ...saved, tagsText: saved.tags.join(', '), dirty: false, isNew: false, saveState: '已封存' }
|
|
1379
|
+
workspace.view.mode = 'preview'
|
|
1380
|
+
await reloadDocumentWorkspace(workspace)
|
|
1222
1381
|
renderShell()
|
|
1223
1382
|
showToast(stateField.input.value === 'resolved' ? '文档已标记为已解决并封存。' : '文档已标记为收集完成并封存。')
|
|
1224
1383
|
return true
|
|
@@ -1226,32 +1385,34 @@ function openFinalizeDocument(editor) {
|
|
|
1226
1385
|
})
|
|
1227
1386
|
}
|
|
1228
1387
|
|
|
1229
|
-
function reopenDocument(editor) {
|
|
1388
|
+
function reopenDocument(workspace, editor) {
|
|
1230
1389
|
openConfirm({
|
|
1231
1390
|
title: `重新打开“${editor.title}”?`,
|
|
1232
1391
|
message: '重新打开后,人工编辑、AI 回写和候选审核将恢复。',
|
|
1233
1392
|
confirmLabel: '确认重新打开',
|
|
1234
1393
|
onConfirm: async () => {
|
|
1235
1394
|
const saved = await api(`documents/${encodeURIComponent(editor.id)}/reopen`, { method: 'POST' })
|
|
1236
|
-
|
|
1237
|
-
|
|
1395
|
+
workspace.view.editor = { ...saved, tagsText: saved.tags.join(', '), dirty: false, isNew: false, saveState: '已重新打开' }
|
|
1396
|
+
await reloadDocumentWorkspace(workspace)
|
|
1238
1397
|
renderShell()
|
|
1239
1398
|
showToast('文档已重新打开。')
|
|
1240
1399
|
},
|
|
1241
1400
|
})
|
|
1242
1401
|
}
|
|
1243
1402
|
|
|
1244
|
-
function confirmDeleteDocument(editor) {
|
|
1403
|
+
function confirmDeleteDocument(workspace, editor) {
|
|
1245
1404
|
openConfirm({
|
|
1246
1405
|
title: `删除“${editor.title}”?`,
|
|
1247
1406
|
message: '文档和对应的召回知识会被永久删除,此操作无法撤销。',
|
|
1248
1407
|
confirmLabel: '永久删除', danger: true,
|
|
1249
1408
|
onConfirm: async () => {
|
|
1250
1409
|
await api(`entries/${encodeURIComponent(editor.id)}`, { method: 'DELETE' })
|
|
1251
|
-
|
|
1252
|
-
|
|
1410
|
+
workspace.view.documentId = ''
|
|
1411
|
+
workspace.view.editor = null
|
|
1253
1412
|
state.stats = null
|
|
1254
|
-
await
|
|
1413
|
+
await reloadDocumentWorkspace(workspace)
|
|
1414
|
+
selectDefaultDocument(workspace)
|
|
1415
|
+
if (workspace.view.documentId) await loadDocumentEditor(workspace, workspace.view.documentId)
|
|
1255
1416
|
renderShell()
|
|
1256
1417
|
showToast('文档已删除。')
|
|
1257
1418
|
},
|
|
@@ -1644,6 +1805,12 @@ function confirmDeleteKnowledgeBase(base) {
|
|
|
1644
1805
|
state.documentView.knowledgeBaseId = ''
|
|
1645
1806
|
state.documentView.documentId = ''
|
|
1646
1807
|
}
|
|
1808
|
+
if (state.libraryDetail.knowledgeBaseId === base.id) {
|
|
1809
|
+
state.libraryDetail.knowledgeBaseId = ''
|
|
1810
|
+
state.libraryDetail.documents = []
|
|
1811
|
+
state.libraryDetail.view = createDocumentViewState()
|
|
1812
|
+
state.knowledgeBaseView = 'libraries'
|
|
1813
|
+
}
|
|
1647
1814
|
if (state.entryFilters.knowledgeBaseId === base.id) state.entryFilters.knowledgeBaseId = ''
|
|
1648
1815
|
showToast('知识库及其全部关联数据已永久删除。')
|
|
1649
1816
|
await navigate('bases')
|
|
@@ -1654,8 +1821,9 @@ function confirmDeleteKnowledgeBase(base) {
|
|
|
1654
1821
|
}
|
|
1655
1822
|
|
|
1656
1823
|
function openEntryEditor(entry, candidate) {
|
|
1824
|
+
const activeWorkspace = activeDocumentWorkspace()
|
|
1657
1825
|
const source = candidate?.draft || entry || {
|
|
1658
|
-
knowledgeBaseId:
|
|
1826
|
+
knowledgeBaseId: activeWorkspace?.view.knowledgeBaseId || undefined,
|
|
1659
1827
|
title: '', body: '', type: 'fact', tags: [], scope: { kind: 'global' }, confidence: .8,
|
|
1660
1828
|
}
|
|
1661
1829
|
const form = element('form', { class: 'form-grid' })
|
|
@@ -1942,5 +2110,4 @@ function friendlyError(error) {
|
|
|
1942
2110
|
return error.message || '操作失败,请稍后重试。'
|
|
1943
2111
|
}
|
|
1944
2112
|
|
|
1945
|
-
installHostThemeBridge()
|
|
1946
|
-
void boot()
|
|
2113
|
+
void installHostThemeBridge().then(() => boot())
|