diff --git a/web/src/components/AppLayout.vue b/web/src/components/AppLayout.vue index cef33ca..93d7d74 100644 --- a/web/src/components/AppLayout.vue +++ b/web/src/components/AppLayout.vue @@ -19,24 +19,33 @@ const selectedArticleId = ref('') const isReportPage = computed(() => !!reportWorkflowId.value) -function parseUrl(): { projectId: string; reportId: string } { +function parseUrl(): { projectId: string; reportId: string; kb: boolean } { const reportMatch = location.pathname.match(/^\/report\/([^/]+)/) - if (reportMatch) return { projectId: '', reportId: reportMatch[1] ?? '' } + if (reportMatch) return { projectId: '', reportId: reportMatch[1] ?? '', kb: false } + if (location.pathname.startsWith('/kb')) return { projectId: '', reportId: '', kb: true } const projectMatch = location.pathname.match(/^\/projects\/([^/]+)/) - return { projectId: projectMatch?.[1] ?? '', reportId: '' } + return { projectId: projectMatch?.[1] ?? '', reportId: '', kb: false } } function onPopState() { - const { projectId, reportId } = parseUrl() - selectedProjectId.value = projectId - reportWorkflowId.value = reportId + const { projectId, reportId, kb } = parseUrl() + if (kb) { + onOpenKb() + } else { + showKb.value = false + selectedArticleId.value = '' + selectedProjectId.value = projectId + reportWorkflowId.value = reportId + } } onMounted(async () => { try { projects.value = await api.listProjects() - const { projectId, reportId } = parseUrl() - if (reportId) { + const { projectId, reportId, kb } = parseUrl() + if (kb) { + onOpenKb() + } else if (reportId) { reportWorkflowId.value = reportId } else if (projectId && projects.value.some(p => p.id === projectId)) { selectedProjectId.value = projectId @@ -107,6 +116,9 @@ async function onOpenKb() { showKb.value = true selectedProjectId.value = '' creating.value = false + if (location.pathname !== '/kb') { + history.pushState(null, '', '/kb') + } try { kbArticles.value = await api.listArticles() if (kbArticles.value.length > 0 && !selectedArticleId.value) { @@ -148,9 +160,14 @@ async function onDeleteArticle(id: string) { } } -function onArticleSaved(id: string, title: string) { +function onArticleSaved(id: string, title: string, updatedAt: string) { const a = kbArticles.value.find(a => a.id === id) - if (a) a.title = title + if (a) { + a.title = title + a.updated_at = updatedAt + } + // Re-sort by updated_at descending + kbArticles.value.sort((a, b) => b.updated_at.localeCompare(a.updated_at)) } diff --git a/web/src/components/KbEditor.vue b/web/src/components/KbEditor.vue index c7d4255..7e45b1f 100644 --- a/web/src/components/KbEditor.vue +++ b/web/src/components/KbEditor.vue @@ -31,7 +31,7 @@ watch(() => props.articleId, (id) => { }, { immediate: true }) const emit = defineEmits<{ - saved: [id: string, title: string] + saved: [id: string, title: string, updatedAt: string] }>() async function save() { @@ -43,7 +43,7 @@ async function save() { content: content.value, }) message.value = 'Saved & indexed' - emit('saved', updated.id, updated.title) + emit('saved', updated.id, updated.title, updated.updated_at) setTimeout(() => { message.value = '' }, 2000) } catch (e: any) { message.value = 'Error: ' + e.message