import { FormEvent, useEffect, useState } from "react"; import { useSearchParams } from "react-router-dom"; import { Code2, Database, Play, Plug, RefreshCw, Table2, Unplug } from "lucide-react"; import { useMutation, useQuery } from "@tanstack/react-query"; import { useAccountId } from "@/lib/accountStore"; import { listSqlDatabases, listSqlTables, querySql, } from "@/api/cloudProxyClient"; import type { CloudProvider } from "@/types/cloud"; import type { CloudResource, SqlCredentials, SqlDatabase, SqlEngine, SqlQueryResult, SqlTable, } from "@/types/resource"; const SQL_SERVER_DEFAULT_QUERY = `SELECT DB_NAME() AS database_name, @@SERVERNAME AS server_name, @@VERSION AS version;`; const POSTGRES_DEFAULT_QUERY = `SELECT current_database() AS database_name, current_user AS username, version();`; const MYSQL_DEFAULT_QUERY = `SELECT DATABASE() AS database_name, CURRENT_USER() AS username, VERSION() AS version;`; interface AzureSqlPanelProps { cloud: CloudProvider; resource?: CloudResource; runtimeReachable: boolean; } export function AzureSqlPanel({ cloud, resource, runtimeReachable, }: AzureSqlPanelProps) { const accountId = useAccountId(); const serverId = resource?.id; const isAwsRds = cloud === "aws" && resource?.type === "db-instance"; const engine: SqlEngine = isAwsRds ? resource?.engine === "mysql" ? "mysql" : "postgresql" : resource?.type === "postgres-flexible-server" ? "postgresql" : "azure-sql"; const defaultDatabase = engine === "postgresql" ? "postgres" : engine === "mysql" ? "mysql" : "master"; const defaultQuery = engine === "postgresql" ? POSTGRES_DEFAULT_QUERY : engine === "mysql" ? MYSQL_DEFAULT_QUERY : SQL_SERVER_DEFAULT_QUERY; const administratorLogin = metadataString( resource?.metadata.administratorLogin, ); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [connected, setConnected] = useState(false); const [databases, setDatabases] = useState([]); const [searchParams, setSearchParams] = useSearchParams(); const selectedDatabase = searchParams.get("database") || defaultDatabase; const tableSchema = searchParams.get("schema"); const tableName = searchParams.get("table"); const [queryText, setQueryText] = useState(defaultQuery); const credentials: SqlCredentials = { username, password }; const databaseExists = databases.some((database) => database.name === selectedDatabase); const tablesQuery = useQuery({ queryKey: ['sql-tables', accountId, cloud, serverId, engine, selectedDatabase, username], queryFn: ({signal}) => listSqlTables(cloud, serverId ?? "", engine, selectedDatabase, credentials, signal), enabled: connected && databaseExists && runtimeReachable, gcTime: 0, }); const tables = connected && databaseExists ? tablesQuery.data ?? [] : []; const selectedTable = tables.find((table) => table.schema === tableSchema && table.name === tableName); const previewQuery = selectedTable && tablePreviewQuery(selectedTable, engine); const databasesMut = useMutation({ mutationFn: () => listSqlDatabases(cloud, serverId ?? "", engine, credentials), }); const queryMut = useMutation({ mutationFn: ({ database, query }: { database: string; query: string }) => querySql(cloud, serverId ?? "", engine, database, credentials, query), }); const {mutate: executeQuery, reset: resetQuery} = queryMut; useEffect(() => { resetQuery(); if (!connected || !previewQuery) { setQueryText(defaultQuery); return; } setQueryText(previewQuery); executeQuery({database: selectedDatabase, query: previewQuery}); }, [connected, selectedDatabase, previewQuery, defaultQuery, executeQuery, resetQuery]); useEffect(() => { setUsername(administratorLogin); setPassword(""); setConnected(false); setDatabases([]); setQueryText(defaultQuery); }, [administratorLogin, cloud, defaultDatabase, defaultQuery, serverId]); if (cloud !== "azure" && !isAwsRds) return null; if (!serverId) { return (

Select an Azure database server

Databases, tables, rows, and SQL queries load after connection.

); } function connect(event: FormEvent) { event.preventDefault(); if (!isAwsRds && (!username || !password)) return; queryMut.reset(); loadDatabases(); } function loadDatabases() { databasesMut.mutate(undefined, { onSuccess: (items) => { setDatabases(items); setConnected(true); if (!searchParams.has('database')) { const database = items.find((item) => item.name === defaultDatabase) ?? items[0]; if (database) selectDatabase(database); } }, }); } function disconnect() { setConnected(false); setPassword(""); setDatabases([]); databasesMut.reset(); queryMut.reset(); } function selectDatabase(database: SqlDatabase) { setSearchParams((previous) => { const next = new URLSearchParams(previous); next.set('database', database.name); next.delete('schema'); next.delete('table'); return next; }); } function previewTable(table: SqlTable) { if (table.schema === tableSchema && table.name === tableName) { const query = tablePreviewQuery(table, engine); setQueryText(query); queryMut.mutate({database: selectedDatabase, query}); return; } setSearchParams((previous) => { const next = new URLSearchParams(previous); next.set('database', selectedDatabase); next.set('schema', table.schema); next.set('table', table.name); return next; }); } function runQuery() { if (!queryText.trim()) return; queryMut.mutate({ database: selectedDatabase, query: queryText }); } const connectionError = databasesMut.error instanceof Error ? databasesMut.error.message : null; return (
{isAwsRds ? "RDS DATA API" : engine === "postgresql" ? "POSTGRESQL DATA PLANE" : "SQL DATA PLANE"} {resource.name} {isAwsRds ? `${resource.engine} · ${resource.status ?? "unknown"}` : metadataString(resource.metadata.fullyQualifiedDomainName)}
{!isAwsRds && } {!isAwsRds && } {connected ? ( ) : ( )} {isAwsRds ? "Queries use TheCloud's local RDS Data API credentials. Database passwords are not sent by the console." : "Credentials remain in this page only and are sent to the local API per request."} {connectionError &&
{connectionError}
}
{!connected ? (

Connect to browse SQL data

{isAwsRds ? "Connect through TheCloud's local RDS Data API to browse databases and run SQL." : "Use the administrator login configured for this local engine."}

) : (
} />
{databases.length === 0 &&
No databases
} {databases.length > 0 && !databaseExists &&
Database not found: {selectedDatabase}
} {databases.map((database) => ( ))}
void tablesQuery.refetch()} > } /> {tablesQuery.error instanceof Error && (
{tablesQuery.error.message}
)}
{tablesQuery.isLoading &&
Loading objects
} {databaseExists && tablesQuery.isSuccess && tables.length === 0 && (
No user tables or views
)} {databaseExists && tablesQuery.isSuccess && tableName && !selectedTable &&
Table not found: {tableSchema}.{tableName}
} {tables.map((table) => ( ))}