/** * Settings > Knowledge — personal knowledge base management */ const { html } = window; const { useState, useEffect, useCallback } = hooks; function fmtDate(d) { if (!d) return '\u2014'; return new Date(d).toLocaleString(undefined, { dateStyle: 'short', timeStyle: 'short' }); } function formatBytes(b) { if (!b) return '0 B'; if (b < 1024) return b + ' B'; if (b < 1048576) return (b / 1024).toFixed(1) + ' KB'; return (b / 1048576).toFixed(1) + ' MB'; } export default function KnowledgeSection() { const [kbs, setKbs] = useState([]); const [loading, setLoading] = useState(true); const [detail, setDetail] = useState(null); const [docs, setDocs] = useState([]); const [showCreate, setShowCreate] = useState(false); const load = useCallback(async () => { try { const data = await sw.api.knowledge.list(); setKbs(Array.isArray(data) ? data : data.data || []); } catch (e) { sw.toast(e.message, 'error'); } finally { setLoading(false); } }, []); useEffect(() => { load(); }, []); async function openDetail(kb) { setDetail(kb); try { const d = await sw.api.knowledge.documents(kb.id); setDocs(Array.isArray(d) ? d : d.data || []); } catch (e) { sw.toast(e.message, 'error'); } } async function createKb(e) { e.preventDefault(); const form = e.target; const name = form.name.value.trim(); if (!name) { sw.toast('Name is required', 'error'); return; } try { await sw.api.knowledge.create({ name, description: form.description.value.trim(), }); sw.toast('Knowledge base created', 'success'); form.reset(); setShowCreate(false); load(); } catch (e) { sw.toast(e.message, 'error'); } } async function deleteKb(id) { const ok = await sw.confirm('Delete this knowledge base and all its documents?', true); if (!ok) return; try { await sw.api.knowledge.del(id); sw.toast('Knowledge base deleted', 'success'); setDetail(null); load(); } catch (e) { sw.toast(e.message, 'error'); } } async function uploadDoc() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.txt,.md,.csv,.html,.pdf'; input.onchange = async () => { const file = input.files[0]; if (!file) return; try { await sw.api.knowledge.upload(detail.id, file); sw.toast('Document uploaded', 'success'); const d = await sw.api.knowledge.documents(detail.id); setDocs(Array.isArray(d) ? d : d.data || []); } catch (e) { sw.toast(e.message, 'error'); } }; input.click(); } async function deleteDoc(docId) { const ok = await sw.confirm('Delete this document?', true); if (!ok) return; try { await sw.api.knowledge.delDoc(detail.id, docId); sw.toast('Document deleted', 'success'); setDocs(prev => prev.filter(d => d.id !== docId)); } catch (e) { sw.toast(e.message, 'error'); } } function statusBadge(status) { const cls = status === 'ready' ? 'badge-active' : status === 'error' ? 'badge-inactive' : 'badge'; return html`${status}`; } if (loading) return html`
Loading\u2026
`; // Detail view if (detail) return html`

${detail.name}

${statusBadge(detail.status || 'active')}
${detail.description && html`

${detail.description}

`}

${detail.document_count || 0} docs \u2022 Created ${fmtDate(detail.created_at)}

${docs.length === 0 && html`
No documents yet. Upload one to get started.
`} ${docs.map(d => html`
${d.filename} ${formatBytes(d.size_bytes)} ${' '}${statusBadge(d.status || 'pending')}
${fmtDate(d.created_at)}
`)}
`; // List view return html`
${kbs.length} knowledge base${kbs.length !== 1 ? 's' : ''}
${showCreate && html`
`}
${kbs.length === 0 && html`
No knowledge bases. Create one to get started.
`} ${kbs.map(k => html`
openDetail(k)}>
${k.name} ${k.document_count || 0} docs
${fmtDate(k.created_at)} ${statusBadge(k.status || 'active')}
`)}
`; }