Files
agentic/frontend/js/doc-manager.js
T
2026-06-10 08:20:27 +02:00

106 lines
3.4 KiB
JavaScript

// Document upload and list management
const DOC_UI = {
async init() {
$("#doc-upload").addEventListener("change", (e) => this.handleUpload(e));
// Periodically refresh document list
setInterval(() => this.refreshList(), 30000);
},
async handleUpload(e) {
const file = e.target.files[0];
if (!file) return;
const output = $("#research-output");
if (!output.querySelector(".empty-state")) output.innerHTML = "";
output.innerHTML = '<div class="spinner"></div> <span class="typing">Reading file...</span>';
const formData = new FormData();
formData.append("file", file);
const res = await fetch("/api/documents/upload", { method: "POST", body: formData });
const data = await res.json();
if (res.ok) {
showToast(`Document indexed: ${data.chunks || "unknown"} chunks`, "info");
STORE.documents = [];
await this.refreshList();
// Select the new document
if (data.doc_id) {
STORE.currentDocId = data.doc_id;
this.renderDocList();
$("#viewer-doc-name").textContent = file.name;
}
} else {
output.innerHTML = `<p style="color:var(--accent-red)">Upload failed: ${data.detail || data.error || "unknown"}</p>`;
}
e.target.value = "";
},
async refreshList() {
try {
const res = await API.get("/api/documents");
STORE.documents = res.documents || [];
this.renderDocList();
// Update stats
const stats = $("#sidebar-stats");
const total = STORE.documents.length;
const indexed = STORE.documents.filter(d => d.status === "indexed").length;
stats.textContent = `${indexed}/${total} documents indexed`;
} catch (e) {
console.warn("Doc list refresh failed:", e);
}
},
async selectDoc(docId) {
STORE.currentDocId = docId;
this.renderDocList();
// Load into viewer
if (STORE.viewerDoc) {
DOC_VIEWER.loadDocument(docId);
}
// Switch to viewer tab
$$(".tab").forEach(t => t.classList.remove("active"));
$$(".tab-pane").forEach(p => p.classList.remove("active"));
document.querySelector('[data-tab="viewer"]').classList.add("active");
$("#tab-viewer").classList.add("active");
},
renderDocList() {
const list = $("#doc-list");
if (!list) return;
if (!STORE.documents.length) {
list.innerHTML = '<div style="font-size:12px;color:var(--text-muted);padding:8px">No documents</div>';
return;
}
list.innerHTML = STORE.documents.map(doc => {
const ext = doc.filename.split(".").pop().toLowerCase();
const icons = { pdf: "📄", txt: "📝", md: "📋", doc: "📑" };
const icon = icons[ext] || "📄";
const isActive = doc.id === STORE.currentDocId;
return `
<div class="doc-item ${isActive ? 'active' : ''}" data-doc-id="${doc.id}">
<span class="file-icon">${icon}</span>
<span class="file-name" title="${doc.filename}">${doc.filename.length > 25 ? doc.filename.substring(0, 25) + '...' : doc.filename}</span>
<span class="file-status ${doc.status}">${doc.status.charAt(0).toUpperCase() + doc.status.slice(1)}</span>
</div>`;
}).join('');
// Click handlers
list.querySelectorAll(".doc-item").forEach(item => {
item.addEventListener("click", (e) => {
if (e.target.closest(".file-remove")) return;
this.selectDoc(item.dataset.docId);
});
});
},
};