// Main UI management const UI = { async init() { // Tab switching $$(".tab").forEach(tab => { tab.addEventListener("click", () => { const target = tab.dataset.tab; this.switchTab(target); // Load tab data if (target === "search") this.initSearch(); if (target === "memories") this.loadMemories(); if (target === "findings") this.loadFindings(); if (target === "pipeline" && STORE.currentSessionId) this.loadPipelineSession(STORE.currentSessionId); }); }); // Pipeline mode toggle const pipelineCheck = $("#pipeline-mode"); const pipelineModeSelect = $("#pipeline-output-mode"); if (pipelineCheck) { pipelineCheck.addEventListener("change", () => { const on = pipelineCheck.checked; pipelineModeSelect.style.display = on ? "inline-block" : "none"; const toggles = document.querySelectorAll("#skill-toggles .skill-toggle"); toggles.forEach(t => { const cb = t.querySelector("input"); if (cb) cb.disabled = on; }); }); } // Rebuild pipeline button const rebuildBtn = $("#rebuild-pipeline"); if (rebuildBtn && STORE.currentSessionId) { rebuildBtn.addEventListener("click", () => UI.loadPipelineSession(STORE.currentSessionId)); } // Search $("#execute-search").addEventListener("click", () => this.executeSearch()); $("#search-query").addEventListener("keydown", (e) => { if (e.key === "Enter") this.executeSearch(); }); // Check models $("#check-models").addEventListener("click", () => this.checkModels()); // Load state await loadInitialState(); // Init sub-modules DOC_VIEWER.init(); RESEARCH_UI.init(); DOC_UI.init(); }, switchTab(tabName) { $$(".tab").forEach(t => t.classList.remove("active")); $$(".tab-pane").forEach(p => p.classList.remove("active")); document.querySelector(`[data-tab="${tabName}"]`).classList.add("active"); $(`#tab-${tabName}`).classList.add("active"); }, initSearch() { // Search already bound in HTML }, async executeSearch() { const query = $("#search-query").value.trim(); if (!query) return showToast("Enter a search query", "error"); const type = $("#search-type").value; const resultsEl = $("#search-results"); resultsEl.innerHTML = '
Searching...'; try { let results; if (type === "semantic") { results = await RESEARCH_UI.runSemanticSearch(query, STORE.currentDocId); } else { results = await RESEARCH_UI.runTextSearch(query, STORE.currentDocId); } if (!results.length) { resultsEl.innerHTML = '
No results found
'; return; } resultsEl.innerHTML = results.map(r => { const score = r.similarity ?? r.rank ?? 0; const page = r.page_num != null ? `p${r.page_num}` : ""; const truncated = r.content ? r.content.substring(0, 200) : ""; // Highlight matching text let content = truncated.replace(/&/g, '&') .replace(//g, '>'); if (query) { const regex = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi'); content = content.replace(regex, '$1'); } return `
Score: ${score.toFixed(3)}
${content}${truncated.length >= 200 ? '...' : ''}
${page} ยท ${r.chunk_type || 'text'}
`; }).join(''); // Click to show chunk in viewer resultsEl.querySelectorAll(".search-result-item").forEach(item => { item.addEventListener("click", () => { const chunkId = item.dataset.chunkId; if (STORE.currentDocId) { DOC_VIEWER.showChunkInfo(chunkId); } }); }); } catch (e) { resultsEl.innerHTML = `

Search error: ${e.message}

`; } }, async loadMemories() { const list = $("#memories-list"); list.innerHTML = '
'; try { if (STORE.currentSessionId) { const res = await API.get(`/api/research/memories?session_id=${STORE.currentSessionId}`); list.innerHTML = (res.memories || []).map(m => `
${m.memory_type || "fact"} (imp: ${m.importance || "?"})
${m.content ? m.content.substring(0, 300) : "(empty)"}
`).join('') || '
No memories
'; } else { list.innerHTML = '
No active session
'; } } catch (e) { list.innerHTML = `
${e.message}
`; } }, async loadFindings() { const list = $("#findings-list"); list.innerHTML = '
'; try { const findings = await RESEARCH_UI.getFindings(STORE.currentSessionId); list.innerHTML = findings.length ? findings.map(f => `
${f.agent_name || "unknown"}
${f.question || "N/A"}
${(f.answer || f.summary || "").substring(0, 400)}
`).join('') : '
No findings yet
'; } catch (e) { list.innerHTML = `
${e.message}
`; } }, async checkModels() { const list = $("#model-list"); list.innerHTML = '
'; try { const res = await API.get("/api/ollama/models"); const models = res.models || []; list.innerHTML = models.length ? models.map(m => `
${m.name || m.model}
`).join('') : '
None found
'; } catch (e) { list.innerHTML = `
Off: ${e.message}
`; } }, updateHealth(health) { const dot = $("#health-indicator .health-dot"); const text = $("#health-indicator"); if (dot) { dot.className = health.status === "ok" ? "health-dot healthy" : "health-dot"; text.textContent = health.status === "ok" ? "All systems operational" : "Systems degraded"; } }, renderModels(models) { if (!models?.models?.length) return; const list = $("#model-list"); if (list) { list.innerHTML = models.models.map(m => `
${m.name || m.model}
`).join(''); } }, };