import React, { useState, useEffect, useRef } from "react"; import QueryInput from "./QueryInput"; import QueryResult from "./QueryResult"; import LoadingResult from "./LoadingResult"; import { queryDataset, getSuggestions } from "../api"; export default function QueryView({ selectedDataset, schema, onQuerySuccess, activeQuestion, addToast }) { const [queryHistory, setQueryHistory] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // Dynamic suggestions states const [suggestions, setSuggestions] = useState([]); const [suggestionsLoading, setSuggestionsLoading] = useState(false); const historyEndRef = useRef(null); // 1. Clear history & Fetch suggestions when selected dataset changes useEffect(() => { setQueryHistory([]); setError(null); setLoading(false); setSuggestions([]); const fetchSuggestions = async () => { setSuggestionsLoading(true); try { console.log("[QueryView] Loading suggestions for database:", selectedDataset.db_name); const res = await getSuggestions(selectedDataset.db_name); setSuggestions(res.suggestions || []); } catch (err) { console.error("[QueryView] Failed to fetch dynamic suggestions:", err); } finally { setSuggestionsLoading(false); } }; if (selectedDataset) { fetchSuggestions(); } }, [selectedDataset]); // 2. Scroll to bottom when history grows useEffect(() => { if (historyEndRef.current) { historyEndRef.current.scrollIntoView({ behavior: "smooth" }); } }, [queryHistory]); // 3. Register global keyboard shortcut Ctrl+K to focus query input from anywhere useEffect(() => { const handleGlobalKeyDown = (e) => { if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "k") { e.preventDefault(); const inputEl = document.querySelector(".query-input"); if (inputEl) { inputEl.focus(); inputEl.select(); // Highlight any existing text inside } } }; window.addEventListener("keydown", handleGlobalKeyDown); return () => window.removeEventListener("keydown", handleGlobalKeyDown); }, []); // 4. Trigger query from external prop (like sidebar recent queries) useEffect(() => { if (activeQuestion && activeQuestion.text && activeQuestion.timestamp) { handleQuerySubmit(activeQuestion.text); } }, [activeQuestion]); const handleQuerySubmit = async (questionText) => { setError(null); setLoading(true); const pendingId = "pending_" + Date.now(); const pendingEntry = { id: pendingId, question: questionText, timestamp: new Date(), isPending: true }; setQueryHistory((prev) => [...prev, pendingEntry]); try { console.log(`[QueryView] Executing query: '${questionText}' on '${selectedDataset.db_name}'`); const res = await queryDataset(questionText, selectedDataset.db_name); // Update entry with real execution results setQueryHistory((prev) => prev.map((item) => item.id === pendingId ? { ...res, id: pendingId, timestamp: pendingEntry.timestamp } : item ) ); setLoading(false); addToast("Query completed", "success"); if (onQuerySuccess) { onQuerySuccess(); } } catch (err) { console.error("[QueryView] Query pipeline error:", err); setError(err.message || "Failed to execute query."); setLoading(false); addToast("Query failed: " + err.message, "error"); // Remove loading block setQueryHistory((prev) => prev.filter((item) => item.id !== pendingId)); } }; const getLastQuestion = () => { if (queryHistory.length === 0) return null; // Get last non-pending query question const completedQueries = queryHistory.filter(h => !h.isPending); if (completedQueries.length === 0) return null; return completedQueries[completedQueries.length - 1].question; }; const colCount = selectedDataset.columns ? selectedDataset.columns.length : 0; return (