// @ts-nocheck import React, { useEffect, useState } from "react"; import { useKeyboard } from "@opentui/react"; import type { SmithersDb } from "../../../db/adapter.js"; import type { SelectOption } from "@opentui/core"; export function SqliteBrowser({ adapter, onBack, }: { adapter: SmithersDb; onBack: () => void; }) { const [tables, setTables] = useState([]); const [selectedTableIdx, setSelectedTableIdx] = useState(0); const [query, setQuery] = useState(""); const [results, setResults] = useState([]); const [error, setError] = useState(null); const [focusedPane, setFocusedPane] = useState<"tables" | "query" | "results">("tables"); // Fetch tables on mount useEffect(() => { let mounted = true; adapter.rawQuery("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'") .then((res: any[]) => { if (mounted) { const names = res.map((r) => r.name).sort(); setTables(names); if (names.length > 0) { setQuery(`SELECT * FROM ${names[0]} LIMIT 50;`); } } }) .catch((err) => { if (mounted) setError(err.message); }); return () => { mounted = false; }; }, [adapter]); // Execute query whenever it changes useEffect(() => { let mounted = true; if (!query.trim()) { setResults([]); return; } adapter.rawQuery(query) .then((res: any[]) => { if (mounted) { setResults(res); setError(null); } }) .catch((err) => { if (mounted) { setError(err.message); setResults([]); } }); return () => { mounted = false; }; }, [adapter, query]); useKeyboard((key) => { if (key.name === "escape") { if (focusedPane === "query") { setFocusedPane("tables"); } else { onBack(); } return; } if (key.name === "tab") { setFocusedPane((p) => p === "tables" ? "query" : p === "query" ? "results" : "tables"); return; } if (focusedPane === "tables" && tables.length > 0) { if (key.name === "down" || key.name === "j") { const next = Math.min(tables.length - 1, selectedTableIdx + 1); setSelectedTableIdx(next); setQuery(`SELECT * FROM ${tables[next]} LIMIT 50;`); } if (key.name === "up" || key.name === "k") { const prev = Math.max(0, selectedTableIdx - 1); setSelectedTableIdx(prev); setQuery(`SELECT * FROM ${tables[prev]} LIMIT 50;`); } } if (focusedPane === "query") { if (key.name === "backspace") { setQuery((q) => q.slice(0, -1)); return; } if (key.name === "enter" || key.name === "return") { setFocusedPane("results"); return; } if (!key.ctrl && !key.meta && key.sequence && key.sequence.length === 1 && key.name !== "up" && key.name !== "down" && key.name !== "left" && key.name !== "right") { setQuery((q) => q + key.sequence); } } }); const tableOptions: SelectOption[] = tables.map((t) => ({ name: t, value: t, })); const resultText = error ? `[!] Query Error:\n${error}` : results.length === 0 ? "No results." : JSON.stringify(results, null, 2); return ( {/* Left Pane: Tables List */} Tables