const statusEl = document.getElementById("status"); const errorEl = document.getElementById("error"); const emptyEl = document.getElementById("empty"); const tableWrapper = document.getElementById("tableWrapper"); const bodyEl = document.getElementById("logBody"); const reloadBtn = document.getElementById("reloadBtn"); const statsEl = document.getElementById("stats"); const exportBtn = document.getElementById("exportBtn"); const exportMenu = document.getElementById("exportMenu"); function setStatus(msg) { statusEl.textContent = msg || ""; } function showError(msg) { errorEl.textContent = msg; errorEl.hidden = !msg; } // --------------------------------------------------------------------------- // Export dropdown button: one menu item per supported export format. // --------------------------------------------------------------------------- function setExportMenuOpen(open) { exportMenu.hidden = !open; exportBtn.setAttribute("aria-expanded", String(open)); } function buildExportMenu(formats) { exportMenu.innerHTML = ""; for (const fmt of formats) { const item = document.createElement("button"); item.type = "button"; item.className = "dropdownItem"; item.setAttribute("role", "menuitem"); item.dataset.format = fmt; item.textContent = fmt.toUpperCase(); exportMenu.appendChild(item); } } exportBtn.addEventListener("click", (e) => { e.stopPropagation(); setExportMenuOpen(exportMenu.hidden); }); exportMenu.addEventListener("click", (e) => { const fmt = e.target.dataset.format; if (!fmt) return; setExportMenuOpen(false); window.location.href = `/records/export?format=${encodeURIComponent(fmt)}`; }); document.addEventListener("click", () => setExportMenuOpen(false)); exportMenu.addEventListener("keydown", (e) => { if (e.key === "Escape") setExportMenuOpen(false); }); function sentimentClass(label) { const l = (label || "").toLowerCase(); if (l.includes("pos")) return "pill pos"; if (l.includes("neg")) return "pill neg"; return "pill neu"; } function renderStats(stats) { if (!stats || !stats.total) { statsEl.innerHTML = `No statistics yet.`; return; } const sentiments = Object.entries(stats.by_sentiment || {}) .map(([k, v]) => `${k}: ${v}`) .join(" "); const topics = Object.entries(stats.by_topic || {}) .map(([k, v]) => `${k}: ${v}`) .join(" "); statsEl.innerHTML = `
Total records${stats.total}
By sentiment
${sentiments}
Top topics
${topics}
`; } function renderRows(items) { bodyEl.innerHTML = ""; for (const item of items) { const tr = document.createElement("tr"); const tdTime = document.createElement("td"); tdTime.textContent = item.created_at || ""; tr.appendChild(tdTime); const tdText = document.createElement("td"); tdText.textContent = item.anonymized_text || ""; tr.appendChild(tdText); const tdTopic = document.createElement("td"); tdTopic.textContent = item.topic || "—"; tr.appendChild(tdTopic); const tdSent = document.createElement("td"); const sLabel = item.sentiment || "—"; tdSent.innerHTML = `${sLabel}`; tr.appendChild(tdSent); const tdEnt = document.createElement("td"); const ents = Array.isArray(item.entities) ? item.entities : []; tdEnt.textContent = ents.length ? ents.map((e) => `${e.type}:${e.text}`).join(", ") : "—"; tr.appendChild(tdEnt); const tdSrc = document.createElement("td"); tdSrc.textContent = item.source || ""; tr.appendChild(tdSrc); bodyEl.appendChild(tr); } } async function load() { showError(""); setStatus("Loading…"); try { const [recRes, statRes] = await Promise.all([ fetch("/records?limit=100"), fetch("/stats"), ]); const records = await recRes.json().catch(() => null); const stats = await statRes.json().catch(() => null); if (!recRes.ok) { throw new Error(`API error (${recRes.status} ${recRes.statusText})`); } renderStats(stats); buildExportMenu(stats?.export_formats || ["xml", "json", "csv"]); if (!Array.isArray(records) || records.length === 0) { emptyEl.hidden = false; tableWrapper.hidden = true; setStatus("No records yet."); return; } renderRows(records); emptyEl.hidden = true; tableWrapper.hidden = false; setStatus(`Loaded ${records.length} records.`); } catch (e) { showError(e?.message || String(e)); setStatus(""); } } reloadBtn.addEventListener("click", load); load();