first commit
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
// 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);
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user