const form = document.getElementById("query-form"); const resultsPanel = document.getElementById("results"); const errorPanel = document.getElementById("error"); const warningEl = document.getElementById("warning"); const summaryEl = document.getElementById("summary"); const generatedSqlEl = document.getElementById("generated-sql"); const sanitizedBlock = document.getElementById("sanitized-block"); const sanitizedSqlEl = document.getElementById("sanitized-sql"); const rowCountEl = document.getElementById("row-count"); const tableEl = document.getElementById("result-table"); const tableHeadEl = document.getElementById("result-thead"); const tableBodyEl = document.getElementById("result-tbody"); const errorMessageEl = document.getElementById("error-message"); const feedbackPanel = document.getElementById("feedback-panel"); const feedbackCorrectBtn = document.getElementById("feedback-correct"); const feedbackIncorrectBtn = document.getElementById("feedback-incorrect"); const feedbackStatus = document.getElementById("feedback-status"); let latestResult = null; function resetPanels() { resultsPanel.hidden = true; errorPanel.hidden = true; warningEl.hidden = true; warningEl.textContent = ""; summaryEl.textContent = ""; generatedSqlEl.textContent = ""; sanitizedBlock.hidden = true; sanitizedSqlEl.textContent = ""; rowCountEl.textContent = ""; tableEl.hidden = true; tableHeadEl.innerHTML = ""; tableBodyEl.innerHTML = ""; errorMessageEl.textContent = ""; feedbackPanel.hidden = true; feedbackStatus.hidden = true; feedbackStatus.textContent = ""; latestResult = null; } function renderTable(columns, rows) { if (!columns || !rows || rows.length === 0) { tableEl.hidden = true; return; } const headerRow = document.createElement("tr"); columns.forEach((col) => { const th = document.createElement("th"); th.textContent = col; headerRow.appendChild(th); }); tableHeadEl.appendChild(headerRow); rows.forEach((row) => { const tr = document.createElement("tr"); columns.forEach((col) => { const td = document.createElement("td"); const value = row[col]; td.textContent = value === null || value === undefined ? "" : String(value); tr.appendChild(td); }); tableBodyEl.appendChild(tr); }); tableEl.hidden = false; } form.addEventListener("submit", async (event) => { event.preventDefault(); resetPanels(); const question = document.getElementById("question").value.trim(); const tablesValue = document.getElementById("tables").value.trim(); const execute = document.getElementById("execute").checked; const maxRows = parseInt(document.getElementById("max-rows").value, 10) || 500; if (!question) { errorPanel.hidden = false; errorMessageEl.textContent = "Please enter a question."; return; } const payload = { question, tables: tablesValue ? tablesValue.split(",").map((s) => s.trim()).filter(Boolean) : undefined, execute, max_rows: maxRows, feedback: null, }; try { const response = await fetch("/api/query", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.detail || `Request failed with status ${response.status}`); } const data = await response.json(); summaryEl.textContent = data.summary || "(No summary provided)"; generatedSqlEl.textContent = data.sql || ""; if (data.llm_warning) { warningEl.textContent = data.llm_warning; warningEl.hidden = false; } if (data.sanitized_sql) { sanitizedSqlEl.textContent = data.sanitized_sql; sanitizedBlock.hidden = false; } if (typeof data.row_count === "number") { rowCountEl.textContent = `Rows returned: ${data.row_count}`; } renderTable(data.columns, data.rows); latestResult = { question, sql: data.sql || "", summary: data.summary || "", sanitized_sql: data.sanitized_sql || null, }; feedbackPanel.hidden = false; feedbackStatus.hidden = true; feedbackStatus.textContent = ""; resultsPanel.hidden = false; } catch (error) { errorPanel.hidden = false; errorMessageEl.textContent = error.message || String(error); } }); async function sendFeedback(tag) { if (!latestResult) { return; } const payload = { question: latestResult.question, sql: latestResult.sql, summary: latestResult.summary, sanitized_sql: latestResult.sanitized_sql, feedback: tag, }; feedbackStatus.hidden = false; feedbackStatus.textContent = "Sending feedback..."; feedbackCorrectBtn.disabled = true; feedbackIncorrectBtn.disabled = true; try { const response = await fetch("/api/feedback", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.detail || `Feedback request failed with status ${response.status}`); } feedbackStatus.textContent = tag === "correct" ? "Marked as correct." : "Marked as needs work."; } catch (error) { feedbackStatus.textContent = error.message || String(error); } finally { feedbackCorrectBtn.disabled = false; feedbackIncorrectBtn.disabled = false; } } feedbackCorrectBtn.addEventListener("click", () => sendFeedback("correct")); feedbackIncorrectBtn.addEventListener("click", () => sendFeedback("incorrect"));