@lemoncat7/dsh-knowledge 1.1.1 → 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/client.js +1 -1
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
- package/web/app.js +278 -114
- 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,15 +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
|
-
inspectedKnowledgeBaseId: '',
|
|
57
|
-
mode: 'preview',
|
|
58
|
-
treeOpen: false,
|
|
61
|
+
documentView: createDocumentViewState({
|
|
59
62
|
sidebarHidden: savedDocumentLayout.sidebarHidden,
|
|
60
63
|
sidebarWidth: savedDocumentLayout.sidebarWidth,
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
}),
|
|
65
|
+
libraryDetail: {
|
|
66
|
+
knowledgeBaseId: '',
|
|
67
|
+
documents: [],
|
|
68
|
+
error: '',
|
|
69
|
+
view: createDocumentViewState(),
|
|
63
70
|
},
|
|
64
71
|
candidates: [],
|
|
65
72
|
candidateTargets: new Map(),
|
|
@@ -77,34 +84,45 @@ const state = {
|
|
|
77
84
|
let scrollRestoreFrame = 0
|
|
78
85
|
|
|
79
86
|
function installHostThemeBridge() {
|
|
80
|
-
if (window.parent === window) return
|
|
87
|
+
if (window.parent === window) return Promise.resolve()
|
|
81
88
|
const parentOrigin = referrerOrigin()
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const root = document.documentElement
|
|
91
|
-
for (const name of [...HOST_THEME_COLOR_TOKENS, ...HOST_THEME_STYLE_TOKENS]) root.style.removeProperty(name)
|
|
92
|
-
for (const [name, value] of Object.entries(message.tokens)) {
|
|
93
|
-
if (typeof value !== 'string' || value.length === 0 || value.length > 512) continue
|
|
94
|
-
if (HOST_THEME_COLOR_TOKENS.has(name) && CSS.supports('color', value)) root.style.setProperty(name, value)
|
|
95
|
-
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()
|
|
96
96
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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 || '*')
|
|
103
125
|
})
|
|
104
|
-
window.parent.postMessage({
|
|
105
|
-
type: HOST_THEME_READY_MESSAGE,
|
|
106
|
-
version: HOST_THEME_PROTOCOL_VERSION,
|
|
107
|
-
}, parentOrigin || '*')
|
|
108
126
|
}
|
|
109
127
|
|
|
110
128
|
function referrerOrigin() {
|
|
@@ -153,12 +171,16 @@ function captureScrollPosition() {
|
|
|
153
171
|
const key = node.getAttribute('data-scroll-key')
|
|
154
172
|
if (key) regions[key] = { left: node.scrollLeft, top: node.scrollTop }
|
|
155
173
|
})
|
|
156
|
-
state.scrollPositions.set(shell.dataset.view, {
|
|
174
|
+
state.scrollPositions.set(shell.dataset.scrollState || shell.dataset.view, {
|
|
157
175
|
window: { left: window.scrollX, top: window.scrollY },
|
|
158
176
|
regions,
|
|
159
177
|
})
|
|
160
178
|
}
|
|
161
179
|
|
|
180
|
+
function currentScrollState() {
|
|
181
|
+
return state.view === 'bases' ? `bases:${state.knowledgeBaseView}` : state.view
|
|
182
|
+
}
|
|
183
|
+
|
|
162
184
|
function restoreScrollPosition(view) {
|
|
163
185
|
if (state.loading) return
|
|
164
186
|
const saved = state.scrollPositions.get(view)
|
|
@@ -320,6 +342,10 @@ function signOut() {
|
|
|
320
342
|
}
|
|
321
343
|
|
|
322
344
|
async function navigate(view) {
|
|
345
|
+
const previousView = state.view
|
|
346
|
+
if (view === 'bases' && previousView !== 'bases' && state.knowledgeBaseView === 'detail') {
|
|
347
|
+
state.knowledgeBaseView = 'libraries'
|
|
348
|
+
}
|
|
323
349
|
state.view = view
|
|
324
350
|
state.menuOpen = false
|
|
325
351
|
state.loading = true
|
|
@@ -413,15 +439,16 @@ async function loadDocuments() {
|
|
|
413
439
|
state.resolvedMounts = resolved
|
|
414
440
|
const visibleBaseIds = new Set(documentKnowledgeBases(bases).map(base => base.id))
|
|
415
441
|
state.documents = documents.filter(document => visibleBaseIds.has(document.knowledgeBaseId))
|
|
416
|
-
const
|
|
442
|
+
const workspace = sessionDocumentWorkspace()
|
|
443
|
+
const view = workspace.view
|
|
417
444
|
const availableBaseIds = visibleBaseIds
|
|
418
445
|
if (!view.knowledgeBaseId || !availableBaseIds.has(view.knowledgeBaseId)) {
|
|
419
446
|
view.knowledgeBaseId = state.entryFilters.knowledgeBaseId && availableBaseIds.has(state.entryFilters.knowledgeBaseId)
|
|
420
447
|
? state.entryFilters.knowledgeBaseId
|
|
421
448
|
: documentKnowledgeBases(bases)[0]?.id || ''
|
|
422
449
|
}
|
|
423
|
-
selectDefaultDocument()
|
|
424
|
-
if (view.documentId) await loadDocumentEditor(view.documentId)
|
|
450
|
+
selectDefaultDocument(workspace)
|
|
451
|
+
if (view.documentId) await loadDocumentEditor(workspace, view.documentId)
|
|
425
452
|
else view.editor = null
|
|
426
453
|
if (!state.stats) await refreshStats()
|
|
427
454
|
}
|
|
@@ -430,22 +457,68 @@ function documentKnowledgeBases(bases = state.knowledgeBases) {
|
|
|
430
457
|
const active = bases.filter(base => base.status === 'active')
|
|
431
458
|
if (!state.mountContext.sessionId) return active
|
|
432
459
|
const mountedIds = new Set(state.resolvedMounts.map(mount => mount.knowledgeBaseId))
|
|
433
|
-
return active.filter(base => mountedIds.has(base.id)
|
|
460
|
+
return active.filter(base => mountedIds.has(base.id))
|
|
461
|
+
}
|
|
462
|
+
|
|
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
|
|
434
475
|
}
|
|
435
476
|
|
|
436
|
-
function
|
|
437
|
-
|
|
438
|
-
|
|
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)
|
|
439
512
|
if (!documents.some(document => document.id === view.documentId)) {
|
|
440
513
|
view.documentId = documents[0]?.id || ''
|
|
441
514
|
}
|
|
442
515
|
if (view.knowledgeBaseId) view.expandedBases.add(view.knowledgeBaseId)
|
|
443
516
|
}
|
|
444
517
|
|
|
445
|
-
async function loadDocumentEditor(id) {
|
|
518
|
+
async function loadDocumentEditor(workspace, id) {
|
|
446
519
|
const entry = await api(`entries/${encodeURIComponent(id)}`)
|
|
447
|
-
|
|
448
|
-
|
|
520
|
+
workspace.view.mode = 'preview'
|
|
521
|
+
workspace.view.editor = {
|
|
449
522
|
...entry,
|
|
450
523
|
tagsText: entry.tags.join(', '),
|
|
451
524
|
dirty: false,
|
|
@@ -454,10 +527,10 @@ async function loadDocumentEditor(id) {
|
|
|
454
527
|
}
|
|
455
528
|
}
|
|
456
529
|
|
|
457
|
-
function createBlankDocument(baseId) {
|
|
530
|
+
function createBlankDocument(workspace, baseId) {
|
|
458
531
|
const base = state.knowledgeBases.find(item => item.id === baseId && item.status === 'active')
|
|
459
532
|
if (!base) return showToast('请先选择一个可用知识库。', 'error')
|
|
460
|
-
const view =
|
|
533
|
+
const view = workspace.view
|
|
461
534
|
view.knowledgeBaseId = base.id
|
|
462
535
|
view.documentId = ''
|
|
463
536
|
view.mode = 'edit'
|
|
@@ -471,20 +544,20 @@ function createBlankDocument(baseId) {
|
|
|
471
544
|
document.querySelector('.note-title-input')?.focus()
|
|
472
545
|
}
|
|
473
546
|
|
|
474
|
-
async function startBlankDocument(baseId) {
|
|
475
|
-
const editor =
|
|
547
|
+
async function startBlankDocument(workspace, baseId) {
|
|
548
|
+
const editor = workspace.view.editor
|
|
476
549
|
const emptyDraft = editor?.isNew && !editor.title.trim() && !editor.body.trim()
|
|
477
|
-
if (editor?.dirty && !emptyDraft && !await saveDocumentEditor()) return
|
|
478
|
-
createBlankDocument(baseId)
|
|
550
|
+
if (editor?.dirty && !emptyDraft && !await saveDocumentEditor(workspace)) return
|
|
551
|
+
createBlankDocument(workspace, baseId)
|
|
479
552
|
}
|
|
480
553
|
|
|
481
|
-
async function selectDocument(id) {
|
|
482
|
-
const editor =
|
|
554
|
+
async function selectDocument(workspace, id) {
|
|
555
|
+
const editor = workspace.view.editor
|
|
483
556
|
const emptyDraft = editor?.isNew && !editor.title.trim() && !editor.body.trim()
|
|
484
|
-
if (editor?.dirty && !emptyDraft && !await saveDocumentEditor()) return
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
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)
|
|
488
561
|
renderShell()
|
|
489
562
|
}
|
|
490
563
|
|
|
@@ -501,8 +574,9 @@ function editorDraft(editor) {
|
|
|
501
574
|
}
|
|
502
575
|
}
|
|
503
576
|
|
|
504
|
-
async function saveDocumentEditor() {
|
|
505
|
-
|
|
577
|
+
async function saveDocumentEditor(workspace = activeDocumentWorkspace()) {
|
|
578
|
+
if (!workspace) return false
|
|
579
|
+
const editor = workspace.view.editor
|
|
506
580
|
if (!editor || !editor.dirty) return true
|
|
507
581
|
if (!editor.isNew && editor.documentState !== 'open') {
|
|
508
582
|
showToast('这篇文档已经结束并封存;请先重新打开。', 'error')
|
|
@@ -524,10 +598,9 @@ async function saveDocumentEditor() {
|
|
|
524
598
|
editor.dirty = false
|
|
525
599
|
editor.updatedAt = saved.updatedAt
|
|
526
600
|
editor.saveState = '已保存'
|
|
527
|
-
|
|
601
|
+
workspace.view.documentId = saved.id
|
|
528
602
|
updateEditorSaveState(editor.saveState)
|
|
529
|
-
|
|
530
|
-
state.documents = documents
|
|
603
|
+
await reloadDocumentWorkspace(workspace)
|
|
531
604
|
return true
|
|
532
605
|
} catch (error) {
|
|
533
606
|
editor.saveState = '保存失败'
|
|
@@ -577,6 +650,8 @@ function renderShell() {
|
|
|
577
650
|
const shell = element('div', {
|
|
578
651
|
class: 'app-shell', 'data-menu-open': String(state.menuOpen),
|
|
579
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'),
|
|
580
655
|
'data-sidebar-hidden': String(state.documentView.sidebarHidden),
|
|
581
656
|
style: `--sidebar-width: ${state.documentView.sidebarWidth}px`,
|
|
582
657
|
},
|
|
@@ -587,8 +662,10 @@ function renderShell() {
|
|
|
587
662
|
element('div', { class: 'topbar-title' },
|
|
588
663
|
actionButton('☰', () => { state.menuOpen = !state.menuOpen; renderShell() }, 'ghost mobile-menu', { 'aria-label': '打开导航菜单' }),
|
|
589
664
|
paneToggleButton('main', !state.documentView.sidebarHidden, () => setSidebarHidden(!state.documentView.sidebarHidden), '主导航栏'),
|
|
590
|
-
|
|
591
|
-
|
|
665
|
+
activeDocumentWorkspace() ? paneToggleButton('library', activeDocumentWorkspace().view.treeOpen, () => {
|
|
666
|
+
const workspace = activeDocumentWorkspace()
|
|
667
|
+
if (!workspace) return
|
|
668
|
+
workspace.view.treeOpen = !workspace.view.treeOpen
|
|
592
669
|
renderShell()
|
|
593
670
|
}, '知识目录') : null,
|
|
594
671
|
element('div', {}, element('h1', {}, title), element('p', {}, subtitle)),
|
|
@@ -601,7 +678,7 @@ function renderShell() {
|
|
|
601
678
|
if (event.target === shell) { state.menuOpen = false; renderShell() }
|
|
602
679
|
})
|
|
603
680
|
app.replaceChildren(shell)
|
|
604
|
-
restoreScrollPosition(
|
|
681
|
+
restoreScrollPosition(currentScrollState())
|
|
605
682
|
}
|
|
606
683
|
|
|
607
684
|
function renderAppSidebarResizer() {
|
|
@@ -752,6 +829,7 @@ function renderOverview() {
|
|
|
752
829
|
function renderKnowledgeBases() {
|
|
753
830
|
const activeBases = state.knowledgeBases.filter(base => base.status === 'active')
|
|
754
831
|
const archivedBases = state.knowledgeBases.filter(base => base.status === 'archived')
|
|
832
|
+
if (state.knowledgeBaseView === 'detail') return renderKnowledgeBaseDetail()
|
|
755
833
|
const contextAvailable = Boolean(state.mountContext.projectId || state.mountContext.sessionId)
|
|
756
834
|
const query = state.knowledgeBaseQuery.trim().toLocaleLowerCase()
|
|
757
835
|
const matchesQuery = base => !query || [base.name, base.description, base.defaultTags.join(' ')]
|
|
@@ -821,6 +899,82 @@ function renderKnowledgeBases() {
|
|
|
821
899
|
)
|
|
822
900
|
}
|
|
823
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
|
+
|
|
824
978
|
async function openGlobalWritebackModelEditor() {
|
|
825
979
|
await loadModelCatalog()
|
|
826
980
|
const custom = element('input', { type: 'checkbox', checked: Boolean(state.service.writebackProvider && state.service.writebackModel) })
|
|
@@ -867,14 +1021,7 @@ function renderKnowledgeBaseCard(base) {
|
|
|
867
1021
|
base.extractionInstructions ? element('span', {}, element('strong', {}, '提取规则'), '已设置') : null,
|
|
868
1022
|
),
|
|
869
1023
|
element('div', { class: 'base-card-actions' },
|
|
870
|
-
actionButton('查看知识', () => {
|
|
871
|
-
state.entryFilters.knowledgeBaseId = base.id
|
|
872
|
-
state.documentView.knowledgeBaseId = base.id
|
|
873
|
-
state.documentView.inspectedKnowledgeBaseId = base.id
|
|
874
|
-
state.documentView.documentId = ''
|
|
875
|
-
state.documentView.expandedBases.add(base.id)
|
|
876
|
-
void navigate('entries')
|
|
877
|
-
}, 'ghost small'),
|
|
1024
|
+
actionButton('查看知识', () => { void openKnowledgeBaseDocuments(base) }, 'ghost small', { 'data-open-knowledge-base': base.id }),
|
|
878
1025
|
archived ? actionButton('恢复', () => confirmRestoreKnowledgeBase(base), 'small') : actionButton('编辑', () => openKnowledgeBaseEditor(base), 'small'),
|
|
879
1026
|
archived ? actionButton('永久删除', () => confirmDeleteKnowledgeBase(base), 'danger small') : null,
|
|
880
1027
|
!archived && base.id !== 'default' ? actionButton('归档', () => confirmArchiveKnowledgeBase(base), 'danger small') : null,
|
|
@@ -1030,23 +1177,30 @@ function compactEmpty(message) {
|
|
|
1030
1177
|
}
|
|
1031
1178
|
|
|
1032
1179
|
function renderEntries() {
|
|
1033
|
-
|
|
1180
|
+
return renderDocumentWorkspace(sessionDocumentWorkspace(), { heading: '知识目录' })
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
function renderDocumentWorkspace(workspace, options = {}) {
|
|
1184
|
+
const view = workspace.view
|
|
1034
1185
|
const query = view.query.trim().toLocaleLowerCase()
|
|
1035
|
-
const activeBases =
|
|
1186
|
+
const activeBases = documentWorkspaceBases(workspace)
|
|
1187
|
+
const workspaceDocuments = documentWorkspaceDocuments(workspace)
|
|
1188
|
+
const readOnly = documentWorkspaceReadOnly(workspace)
|
|
1036
1189
|
const selectedBase = activeBases.find(base => base.id === view.knowledgeBaseId)
|
|
1037
1190
|
const search = element('input', {
|
|
1038
1191
|
class: 'note-tree-search', type: 'search', value: view.query, placeholder: '搜索文档', 'aria-label': '搜索知识库文档',
|
|
1192
|
+
'data-document-scope': workspace.kind,
|
|
1039
1193
|
onInput: (event) => {
|
|
1040
1194
|
view.query = event.target.value
|
|
1041
1195
|
renderShell()
|
|
1042
|
-
const input = document.querySelector(
|
|
1196
|
+
const input = document.querySelector(`.note-tree-search[data-document-scope="${workspace.kind}"]`)
|
|
1043
1197
|
input?.focus()
|
|
1044
1198
|
input?.setSelectionRange(input.value.length, input.value.length)
|
|
1045
1199
|
},
|
|
1046
1200
|
})
|
|
1047
1201
|
const tree = activeBases.map(base => {
|
|
1048
1202
|
const expanded = view.expandedBases.has(base.id) || Boolean(query)
|
|
1049
|
-
const documents =
|
|
1203
|
+
const documents = workspaceDocuments.filter(document => document.knowledgeBaseId === base.id
|
|
1050
1204
|
&& (!query || [document.title, document.relPath, document.content].some(value => value.toLocaleLowerCase().includes(query))))
|
|
1051
1205
|
return element('section', { class: 'note-tree-group', 'data-expanded': String(expanded) },
|
|
1052
1206
|
element('button', {
|
|
@@ -1065,48 +1219,50 @@ function renderEntries() {
|
|
|
1065
1219
|
expanded ? element('div', { class: 'note-tree-documents', role: 'group', 'aria-label': `${base.name}文档` },
|
|
1066
1220
|
documents.map(document => element('button', {
|
|
1067
1221
|
type: 'button', class: 'note-tree-document', 'aria-current': document.id === view.documentId ? 'page' : undefined,
|
|
1068
|
-
onClick: () => { void selectDocument(document.id) },
|
|
1222
|
+
onClick: () => { void selectDocument(workspace, document.id) },
|
|
1069
1223
|
}, element('span', { class: 'tree-document-icon', 'aria-hidden': 'true' }), element('span', { class: 'tree-document-copy' },
|
|
1070
1224
|
element('strong', {}, document.title), element('small', {}, document.relPath)),
|
|
1071
1225
|
document.documentState !== 'open' ? badge(DOCUMENT_STATE_LABELS[document.documentState] || '已结束', 'success') : null)),
|
|
1072
|
-
!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) } },
|
|
1073
1227
|
element('span', { 'aria-hidden': 'true' }, '+'), '新建文档') : null,
|
|
1074
1228
|
) : null,
|
|
1075
1229
|
)
|
|
1076
1230
|
})
|
|
1077
1231
|
return element('section', {
|
|
1078
|
-
class:
|
|
1232
|
+
class: `note-workspace note-workspace--${workspace.kind}`, 'aria-labelledby': `${workspace.kind}-documents-heading`,
|
|
1079
1233
|
'data-tree-open': String(view.treeOpen),
|
|
1080
1234
|
},
|
|
1081
1235
|
element('aside', { class: 'note-tree-panel', 'aria-label': '知识目录' },
|
|
1082
1236
|
element('header', { class: 'note-tree-header' },
|
|
1083
|
-
element('div', {}, element('h2', { id:
|
|
1084
|
-
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,
|
|
1085
1239
|
),
|
|
1086
1240
|
element('div', { class: 'note-tree-search-wrap' }, interfaceIcon('search', 'search-symbol'), search),
|
|
1087
|
-
element('nav', { class: 'note-tree', 'data-scroll-key':
|
|
1088
|
-
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,
|
|
1089
1243
|
),
|
|
1090
1244
|
view.treeOpen ? element('button', {
|
|
1091
1245
|
type: 'button', class: 'note-tree-scrim', 'aria-label': '关闭知识目录',
|
|
1092
1246
|
onClick: () => { view.treeOpen = false; renderShell() },
|
|
1093
1247
|
}) : null,
|
|
1094
|
-
renderNoteEditor(view.editor, selectedBase),
|
|
1248
|
+
renderNoteEditor(workspace, view.editor, selectedBase),
|
|
1095
1249
|
)
|
|
1096
1250
|
}
|
|
1097
1251
|
|
|
1098
|
-
function renderNoteEditor(editor, base) {
|
|
1252
|
+
function renderNoteEditor(workspace, editor, base) {
|
|
1253
|
+
const view = workspace.view
|
|
1254
|
+
const readOnly = documentWorkspaceReadOnly(workspace)
|
|
1099
1255
|
if (!editor) return element('main', { class: 'note-editor note-editor-empty' },
|
|
1100
1256
|
element('div', { class: 'note-empty-content' },
|
|
1101
1257
|
element('span', { class: 'empty-document-mark', 'aria-hidden': 'true' }),
|
|
1102
1258
|
element('h3', {}, '选择或新建一篇文档'),
|
|
1103
|
-
element('p', {}, '文档保存后会立即参与当前知识库的搜索与召回。'),
|
|
1104
|
-
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,
|
|
1105
1261
|
))
|
|
1106
1262
|
const saveShortcut = event => {
|
|
1107
1263
|
if ((event.metaKey || event.ctrlKey) && event.key.toLocaleLowerCase() === 's') {
|
|
1108
1264
|
event.preventDefault()
|
|
1109
|
-
void saveDocumentEditor().then(saved => { if (saved) renderShell() })
|
|
1265
|
+
void saveDocumentEditor(workspace).then(saved => { if (saved) renderShell() })
|
|
1110
1266
|
}
|
|
1111
1267
|
}
|
|
1112
1268
|
const update = (key, value) => {
|
|
@@ -1125,27 +1281,27 @@ function renderNoteEditor(editor, base) {
|
|
|
1125
1281
|
})
|
|
1126
1282
|
body.value = editor.body
|
|
1127
1283
|
const finalized = !editor.isNew && editor.documentState !== 'open'
|
|
1128
|
-
const mode = finalized ? 'preview' :
|
|
1284
|
+
const mode = finalized || readOnly ? 'preview' : view.mode === 'edit' ? 'edit' : 'preview'
|
|
1129
1285
|
if (mode === 'edit') window.requestAnimationFrame(() => resizeDocumentEditor(body))
|
|
1130
1286
|
return element('main', { class: 'note-editor', 'aria-label': '文档编辑器' },
|
|
1131
1287
|
element('header', { class: 'note-editor-toolbar' },
|
|
1132
1288
|
element('div', { class: 'note-breadcrumb' },
|
|
1133
1289
|
element('span', {}, base?.name || '知识库'),
|
|
1134
1290
|
element('span', { 'aria-hidden': 'true' }, '/'),
|
|
1135
|
-
element('strong', {}, editor.isNew ? '新文档' :
|
|
1291
|
+
element('strong', {}, editor.isNew ? '新文档' : documentWorkspaceDocuments(workspace).find(item => item.id === editor.id)?.relPath || editor.title)),
|
|
1136
1292
|
element('div', { class: 'note-editor-actions' },
|
|
1137
|
-
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': '文档视图' }, [
|
|
1138
1294
|
['edit', '编辑'],
|
|
1139
1295
|
['preview', '预览'],
|
|
1140
1296
|
].map(([value, label]) => element('button', {
|
|
1141
1297
|
type: 'button', role: 'tab', 'aria-selected': String(mode === value),
|
|
1142
|
-
onClick: () => switchDocumentMode(value),
|
|
1298
|
+
onClick: () => switchDocumentMode(workspace, value),
|
|
1143
1299
|
}, label))),
|
|
1144
1300
|
element('span', { class: 'editor-save-status', role: 'status' }, editor.saveState),
|
|
1145
|
-
finalized ? actionButton('重新打开', () => reopenDocument(editor), 'small') : null,
|
|
1146
|
-
!editor.isNew && !finalized ? actionButton('标记结束', () => openFinalizeDocument(editor), 'small') : null,
|
|
1147
|
-
!editor.isNew && !finalized ? actionButton('删除', () => confirmDeleteDocument(editor), 'ghost small') : null,
|
|
1148
|
-
!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,
|
|
1149
1305
|
),
|
|
1150
1306
|
),
|
|
1151
1307
|
element('div', { class: 'note-editor-scroll', 'data-scroll-key': 'note-editor' },
|
|
@@ -1166,20 +1322,20 @@ function renderNoteEditor(editor, base) {
|
|
|
1166
1322
|
),
|
|
1167
1323
|
),
|
|
1168
1324
|
element('footer', { class: 'note-inspector' },
|
|
1169
|
-
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', {
|
|
1170
1326
|
class: 'note-meta-select', onChange: event => update('type', event.target.value),
|
|
1171
1327
|
}, TYPES.map(type => element('option', { value: type, selected: type === editor.type }, TYPE_LABELS[type])))),
|
|
1172
|
-
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', {
|
|
1173
1329
|
value: editor.tagsText, placeholder: '用逗号分隔', onInput: event => update('tagsText', event.target.value),
|
|
1174
1330
|
})),
|
|
1175
|
-
!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,
|
|
1176
1332
|
),
|
|
1177
1333
|
)
|
|
1178
1334
|
}
|
|
1179
1335
|
|
|
1180
|
-
function switchDocumentMode(mode) {
|
|
1336
|
+
function switchDocumentMode(workspace, mode) {
|
|
1181
1337
|
if (mode !== 'edit' && mode !== 'preview') return
|
|
1182
|
-
|
|
1338
|
+
workspace.view.mode = mode
|
|
1183
1339
|
renderShell()
|
|
1184
1340
|
if (mode === 'edit') window.requestAnimationFrame(() => document.querySelector('.note-body-editor')?.focus())
|
|
1185
1341
|
}
|
|
@@ -1196,7 +1352,7 @@ function resizeDocumentEditor(editor) {
|
|
|
1196
1352
|
editor.style.height = `${Math.max(420, editor.scrollHeight)}px`
|
|
1197
1353
|
}
|
|
1198
1354
|
|
|
1199
|
-
function openFinalizeDocument(editor) {
|
|
1355
|
+
function openFinalizeDocument(workspace, editor) {
|
|
1200
1356
|
const form = element('form', { class: 'form-grid' })
|
|
1201
1357
|
const stateField = selectField('结束状态', [
|
|
1202
1358
|
{ value: 'resolved', label: '已解决 — 问题已有最终结论' },
|
|
@@ -1219,9 +1375,9 @@ function openFinalizeDocument(editor) {
|
|
|
1219
1375
|
method: 'POST',
|
|
1220
1376
|
body: { state: stateField.input.value, note: note.input.value.trim() },
|
|
1221
1377
|
})
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1378
|
+
workspace.view.editor = { ...saved, tagsText: saved.tags.join(', '), dirty: false, isNew: false, saveState: '已封存' }
|
|
1379
|
+
workspace.view.mode = 'preview'
|
|
1380
|
+
await reloadDocumentWorkspace(workspace)
|
|
1225
1381
|
renderShell()
|
|
1226
1382
|
showToast(stateField.input.value === 'resolved' ? '文档已标记为已解决并封存。' : '文档已标记为收集完成并封存。')
|
|
1227
1383
|
return true
|
|
@@ -1229,32 +1385,34 @@ function openFinalizeDocument(editor) {
|
|
|
1229
1385
|
})
|
|
1230
1386
|
}
|
|
1231
1387
|
|
|
1232
|
-
function reopenDocument(editor) {
|
|
1388
|
+
function reopenDocument(workspace, editor) {
|
|
1233
1389
|
openConfirm({
|
|
1234
1390
|
title: `重新打开“${editor.title}”?`,
|
|
1235
1391
|
message: '重新打开后,人工编辑、AI 回写和候选审核将恢复。',
|
|
1236
1392
|
confirmLabel: '确认重新打开',
|
|
1237
1393
|
onConfirm: async () => {
|
|
1238
1394
|
const saved = await api(`documents/${encodeURIComponent(editor.id)}/reopen`, { method: 'POST' })
|
|
1239
|
-
|
|
1240
|
-
|
|
1395
|
+
workspace.view.editor = { ...saved, tagsText: saved.tags.join(', '), dirty: false, isNew: false, saveState: '已重新打开' }
|
|
1396
|
+
await reloadDocumentWorkspace(workspace)
|
|
1241
1397
|
renderShell()
|
|
1242
1398
|
showToast('文档已重新打开。')
|
|
1243
1399
|
},
|
|
1244
1400
|
})
|
|
1245
1401
|
}
|
|
1246
1402
|
|
|
1247
|
-
function confirmDeleteDocument(editor) {
|
|
1403
|
+
function confirmDeleteDocument(workspace, editor) {
|
|
1248
1404
|
openConfirm({
|
|
1249
1405
|
title: `删除“${editor.title}”?`,
|
|
1250
1406
|
message: '文档和对应的召回知识会被永久删除,此操作无法撤销。',
|
|
1251
1407
|
confirmLabel: '永久删除', danger: true,
|
|
1252
1408
|
onConfirm: async () => {
|
|
1253
1409
|
await api(`entries/${encodeURIComponent(editor.id)}`, { method: 'DELETE' })
|
|
1254
|
-
|
|
1255
|
-
|
|
1410
|
+
workspace.view.documentId = ''
|
|
1411
|
+
workspace.view.editor = null
|
|
1256
1412
|
state.stats = null
|
|
1257
|
-
await
|
|
1413
|
+
await reloadDocumentWorkspace(workspace)
|
|
1414
|
+
selectDefaultDocument(workspace)
|
|
1415
|
+
if (workspace.view.documentId) await loadDocumentEditor(workspace, workspace.view.documentId)
|
|
1258
1416
|
renderShell()
|
|
1259
1417
|
showToast('文档已删除。')
|
|
1260
1418
|
},
|
|
@@ -1647,6 +1805,12 @@ function confirmDeleteKnowledgeBase(base) {
|
|
|
1647
1805
|
state.documentView.knowledgeBaseId = ''
|
|
1648
1806
|
state.documentView.documentId = ''
|
|
1649
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
|
+
}
|
|
1650
1814
|
if (state.entryFilters.knowledgeBaseId === base.id) state.entryFilters.knowledgeBaseId = ''
|
|
1651
1815
|
showToast('知识库及其全部关联数据已永久删除。')
|
|
1652
1816
|
await navigate('bases')
|
|
@@ -1657,8 +1821,9 @@ function confirmDeleteKnowledgeBase(base) {
|
|
|
1657
1821
|
}
|
|
1658
1822
|
|
|
1659
1823
|
function openEntryEditor(entry, candidate) {
|
|
1824
|
+
const activeWorkspace = activeDocumentWorkspace()
|
|
1660
1825
|
const source = candidate?.draft || entry || {
|
|
1661
|
-
knowledgeBaseId:
|
|
1826
|
+
knowledgeBaseId: activeWorkspace?.view.knowledgeBaseId || undefined,
|
|
1662
1827
|
title: '', body: '', type: 'fact', tags: [], scope: { kind: 'global' }, confidence: .8,
|
|
1663
1828
|
}
|
|
1664
1829
|
const form = element('form', { class: 'form-grid' })
|
|
@@ -1945,5 +2110,4 @@ function friendlyError(error) {
|
|
|
1945
2110
|
return error.message || '操作失败,请稍后重试。'
|
|
1946
2111
|
}
|
|
1947
2112
|
|
|
1948
|
-
installHostThemeBridge()
|
|
1949
|
-
void boot()
|
|
2113
|
+
void installHostThemeBridge().then(() => boot())
|