import { Search, TextSearch, LoaderCircle } from 'lucide-react' import { useRouter } from 'next/router' import { useEffect, useRef, useState, useMemo } from 'react' import DataGrid, { DataGridHandle, Row } from 'react-data-grid' import { LOCAL_STORAGE_KEYS, useParams } from 'common' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' import { cn } from 'ui' import { Input } from 'ui-patterns/DataInputs/Input' import { FilterPopover } from 'components/ui/FilterPopover' import { useInsightsQueriesQuery, type InsightsQuery, } from 'data/query-insights/insights-queries-query' import { ColumnConfiguration, QUERY_INSIGHTS_TABLE_COLUMNS } from './QueryInsights.constants' import { formatQueryInsightsColumns } from './QueryInsights.utils' interface QueryRowExplorerProps { startTime: string endTime: string onQuerySelect?: (query: InsightsQuery | undefined) => void selectedQueryId?: number } export const QueryRowExplorer = ({ startTime, endTime, onQuerySelect, selectedQueryId, }: QueryRowExplorerProps) => { const router = useRouter() const gridRef = useRef(null) const { ref } = useParams() const { data: project } = useSelectedProjectQuery() const { data: queries, isLoading, error, } = useInsightsQueriesQuery(ref, startTime, endTime, { enabled: !!ref, }) // Debug logging (commented out to reduce console noise) // console.log('QueryRowExplorer Debug:', { // ref, // startTime, // endTime, // queries, // isLoading, // error, // queriesLength: queries?.length, // refUndefined: !ref, // }) const [sort, setSort] = useState<{ column: string; order: 'asc' | 'desc' } | undefined>({ column: 'last_run', order: 'desc', }) const [selectedRow, setSelectedRow] = useState() const [filterText, setFilterText] = useState('') const [selectedColumns, setSelectedColumns] = useState([]) const [ columnConfiguration, setColumnConfiguration, { isSuccess: isSuccessStorage, isError: isErrorStorage, error: errorStorage }, ] = useLocalStorageQuery( LOCAL_STORAGE_KEYS.QUERY_INSIGHTS_COLUMNS_CONFIGURATION(ref ?? ''), null as ColumnConfiguration[] | null ) const onSortChange = (column: string) => { let updatedSort: { column: string; order: 'asc' | 'desc' } | undefined = undefined if (sort?.column === column) { if (sort.order === 'desc') { updatedSort = { column, order: 'asc' as const } } else { updatedSort = undefined } } else { updatedSort = { column, order: 'desc' as const } } setSort(updatedSort) } // Generate columns dynamically based on configuration const columns = formatQueryInsightsColumns({ config: columnConfiguration ?? [], visibleColumns: selectedColumns, sort, onSortChange, }) // Use actual queries data or empty array if no queries found const reportData = queries || [] // Sort data based on current sort state const sortedData = [...reportData].sort((a, b) => { if (!sort) return 0 const aValue = a[sort.column as keyof InsightsQuery] const bValue = b[sort.column as keyof InsightsQuery] if (aValue === undefined || bValue === undefined) return 0 if (typeof aValue === 'string' && typeof bValue === 'string') { return sort.order === 'asc' ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue) } if (typeof aValue === 'number' && typeof bValue === 'number') { return sort.order === 'asc' ? aValue - bValue : bValue - aValue } return 0 }) // Filter data based on filter text const filteredData = filterText.trim() ? sortedData.filter((query) => query.query.toLowerCase().includes(filterText.toLowerCase())) : sortedData const selectedQuery = useMemo(() => { return selectedRow !== undefined ? filteredData[selectedRow] : undefined }, [selectedRow, filteredData]) // Update selectedRow when selectedQueryId changes from parent useEffect(() => { if (selectedQueryId !== undefined) { const index = filteredData.findIndex((query) => query.query_id === selectedQueryId) if (index !== -1) { setSelectedRow(index) gridRef.current?.scrollToCell({ idx: 0, rowIdx: index }) } } else { setSelectedRow(undefined) } }, [selectedQueryId, filteredData]) // Reset selection when date range changes useEffect(() => { setSelectedRow(undefined) }, [startTime, endTime]) // Initialize selected columns when column configuration changes useEffect(() => { if (columnConfiguration && columnConfiguration.length > 0) { setSelectedColumns(columnConfiguration.map((c) => c.id)) } else { setSelectedColumns([]) } }, [columnConfiguration]) return (
} className="w-64" value={filterText} onChange={(e) => setFilterText(e.target.value)} /> { // When adding back hidden columns: // (1) width set to default value if any // (2) they will just get appended to the end // (3) If "clearing", reset order of the columns to original let updatedConfig = (columnConfiguration ?? []).slice() if (value.length === 0) { updatedConfig = QUERY_INSIGHTS_TABLE_COLUMNS.map((c) => ({ id: c.id, width: c.width, })) } else { value.forEach((col) => { const hasExisting = updatedConfig.find((c) => c.id === col) if (!hasExisting) updatedConfig.push({ id: col, width: QUERY_INSIGHTS_TABLE_COLUMNS.find((c) => c.id === col)?.width, }) }) } setSelectedColumns(value) setColumnConfiguration(updatedConfig) }} />
{ // console.log('DataGrid rows changed:', newRows.length) }} rowClass={(_, idx) => { const isSelected = idx === selectedRow return [ `${isSelected ? 'bg-surface-300 dark:bg-surface-300' : 'bg-200'} cursor-pointer`, `${isSelected ? '[&>div:first-child]:border-l-4 border-l-secondary [&>div]:border-l-foreground' : ''}`, '[&>.rdg-cell]:border-box [&>.rdg-cell]:outline-none [&>.rdg-cell]:shadow-none', '[&>.rdg-cell:first-child>div]:ml-4', ].join(' ') }} renderers={{ renderRow(idx, props) { return ( { if (typeof idx === 'number' && idx >= 0 && idx < filteredData.length) { const query = filteredData[idx] const isAlreadySelected = selectedQuery?.query_id === query.query_id // If the query is already selected, deselect it if (isAlreadySelected) { setSelectedRow(undefined) onQuerySelect?.(undefined) } else { // Otherwise, select the new query setSelectedRow(idx) onQuerySelect?.(query) gridRef.current?.scrollToCell({ idx: 0, rowIdx: idx }) } } }} /> ) }, noRowsFallback: isLoading ? (

Loading...

) : (

{filterText ? 'No queries found' : 'No queries detected'}

{filterText ? `No queries match "${filterText}" in the selected time range` : 'There are no queries that match the criteria in the selected time range'}

), }} />
) }