import {Download, Play, RefreshCw, Square} from 'lucide-react' import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' import {useEffect, useMemo, useState} from 'react' import {Link} from 'react-router-dom' import {describeQueryCatalog, getCloudResource, getQueryResult, listQueries, startQuery, stopQuery, storageObjectDownloadUrl} from '@/api/cloudProxyClient' import {useAccountId} from '@/lib/accountStore' import {formatDateTime} from '@/lib/format' import type {CloudResource, QueryExecutionSummary} from '@/types/resource' type Props = { resource?: CloudResource runtimeReachable: boolean } /** Athena reports a running query's state; it is re-read this often until it finishes. */ const RUNNING_POLL_MS = 1000 const FINISHED = new Set(['SUCCEEDED', 'FAILED', 'CANCELLED']) export function QueryPanel({resource, runtimeReachable}: Props) { const accountId = useAccountId() const queryClient = useQueryClient() const workGroup = resource?.id ?? '' const [database, setDatabase] = useState('') const [sql, setSql] = useState('') const [activeQueryId, setActiveQueryId] = useState(null) const [seededFor, setSeededFor] = useState(null) const historyKey = useMemo(() => ['athena-history', accountId, workGroup], [accountId, workGroup]) const workGroupQuery = useQuery({ queryKey: ['athena-workgroup', accountId, workGroup], queryFn: ({signal}) => getCloudResource('aws', 'query', workGroup, signal), enabled: Boolean(resource) && runtimeReachable, }) const catalogQuery = useQuery({ queryKey: ['athena-catalog', accountId, database], queryFn: ({signal}) => describeQueryCatalog('aws', database || undefined, signal), enabled: Boolean(resource) && runtimeReachable, }) const historyQuery = useQuery({ queryKey: historyKey, queryFn: ({signal}) => listQueries('aws', workGroup, signal), enabled: Boolean(resource) && runtimeReachable, }) const resultQuery = useQuery({ queryKey: ['athena-result', accountId, workGroup, activeQueryId], queryFn: ({signal}) => getQueryResult('aws', workGroup, activeQueryId ?? '', signal), enabled: Boolean(activeQueryId) && runtimeReachable, refetchInterval: (query) => query.state.data && !FINISHED.has(query.state.data.execution.state) ? RUNNING_POLL_MS : false, }) const catalog = catalogQuery.data const chosenDatabase = database || catalog?.database || '' const firstTable = catalog?.tables[0]?.name useEffect(() => { setActiveQueryId(null) setSql('') }, [workGroup]) // Start each workgroup from a query that runs as-is, the way the Athena console opens on a table. useEffect(() => { if (!firstTable || seededFor === workGroup) return setSeededFor(workGroup) setSql((current) => current || `SELECT * FROM ${quote(firstTable)} LIMIT 10`) }, [firstTable, seededFor, workGroup]) const execution = resultQuery.data?.execution const finished = execution ? FINISHED.has(execution.state) : true const executionState = execution?.state useEffect(() => { if (executionState && FINISHED.has(executionState)) void queryClient.invalidateQueries({queryKey: historyKey}) }, [executionState, historyKey, queryClient]) const run = useMutation({ mutationFn: () => startQuery('aws', workGroup, {sql, ...(chosenDatabase ? {database: chosenDatabase} : {})}), onSuccess: (started) => { setActiveQueryId(started.id) return queryClient.invalidateQueries({queryKey: historyKey}) }, }) const cancel = useMutation({ mutationFn: () => stopQuery('aws', workGroup, activeQueryId ?? ''), onSuccess: () => resultQuery.refetch(), }) if (!resource) { return

Select a workgroup

Choose a workgroup to run SQL against the tables in the Glue Data Catalog.

} const outputLocation = (workGroupQuery.data ?? resource).metadata.outputLocation const disabled = !runtimeReachable || run.isPending const result = resultQuery.data const error = run.error ?? cancel.error ?? resultQuery.error ?? catalogQuery.error const history = historyQuery.data ?? [] const download = execution?.outputLocation ? s3Location(execution.outputLocation) : null const submit = () => { if (sql.trim() && !disabled) run.mutate() } const openHistory = (entry: QueryExecutionSummary) => { setActiveQueryId(entry.id) setSql(entry.sql) if (entry.database) setDatabase(entry.database) } return

Athena query editor

Workgroup {resource.name}{outputLocation ? <> · results in {String(outputLocation)} : null}
{ event.preventDefault(); submit() }}>