import { Loader2 } from 'lucide-react' import { useMemo, useState } from 'react' import { Tabs_Shadcn_, TabsContent_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_ } from 'ui' import type { ChartDataPoint } from '../QueryInsights/QueryInsights.types' import { QUERY_PERFORMANCE_CHART_TABS } from './QueryPerformance.constants' import { ComposedChart } from '@/components/ui/Charts/ComposedChart' import type { MultiAttribute } from '@/components/ui/Charts/ComposedChart.utils' interface QueryPerformanceChartProps { dateRange?: { period_start: { date: string; time_period: string } period_end: { date: string; time_period: string } interval: string } onDateRangeChange?: (from: string, to: string) => void chartData: ChartDataPoint[] isLoading: boolean error: any currentSelectedQuery: string | null parsedLogs: any[] } const QueryMetricBlock = ({ label, value, }: { label: string value: string | number | undefined }) => { return (
{label} {value}
) } const formatTimeValue = (value: number): string => { if (value >= 1000) { return `${(value / 1000).toFixed(1)}s` } return `${value.toFixed(1)}ms` } const formatNumberValue = (value: number): string => { return value.toLocaleString() } export const QueryPerformanceChart = ({ onDateRangeChange, chartData, isLoading, error, currentSelectedQuery, parsedLogs, }: QueryPerformanceChartProps) => { const [selectedMetric, setSelectedMetric] = useState('query_latency') const currentMetrics = useMemo(() => { if (!chartData || chartData.length === 0) return [] switch (selectedMetric) { case 'query_latency': { const totalCalls = chartData.reduce((sum, d) => sum + d.calls, 0) const trueP95 = totalCalls > 0 ? chartData.reduce((sum, d) => sum + d.p95_time * d.calls, 0) / totalCalls : 0 return [ { label: 'Average p95', value: `${Math.round(trueP95)}ms`, }, ] } case 'rows_read': { const totalRowsRead = chartData.reduce((sum, d) => sum + d.rows_read, 0) return [ { label: 'Total Rows Read', value: totalRowsRead.toLocaleString(), }, ] } case 'calls': { const totalCalls = chartData.reduce((sum, d) => sum + d.calls, 0) return [ { label: 'Total Calls', value: totalCalls.toLocaleString(), }, ] } case 'cache_hits': { const totalHits = chartData.reduce((sum, d) => sum + d.cache_hits, 0) const totalMisses = chartData.reduce((sum, d) => sum + d.cache_misses, 0) const total = totalHits + totalMisses const hitRate = total > 0 ? (totalHits / total) * 100 : 0 return [ { label: 'Cache Hit Rate', value: `${hitRate.toFixed(2)}%`, }, ] } default: return [] } }, [chartData, selectedMetric]) const transformedChartData = useMemo(() => { if (selectedMetric !== 'query_latency') return chartData const transformed = chartData.map((dataPoint) => ({ ...dataPoint, p50_time: parseFloat((dataPoint.p50_time / 1000).toFixed(3)), p95_time: parseFloat((dataPoint.p95_time / 1000).toFixed(3)), })) return transformed }, [chartData, selectedMetric]) const querySpecificData = useMemo(() => { if (!currentSelectedQuery || !parsedLogs.length) return null const normalizedSelected = currentSelectedQuery.replace(/\s+/g, ' ').trim() const queryLogs = parsedLogs.filter((log) => { const normalized = (log.query || '').replace(/\s+/g, ' ').trim() return normalized === normalizedSelected }) const queryDataMap = new Map< number, { time: number rows_read: number calls: number cache_hits: number } >() queryLogs.forEach((log) => { const time = new Date(log.timestamp).getTime() const meanTime = log.mean_time ?? log.mean_exec_time ?? log.mean_query_time ?? 0 const rowsRead = log.rows_read ?? log.rows ?? 0 const calls = log.calls ?? 0 const cacheHits = log.shared_blks_hit ?? log.cache_hits ?? 0 queryDataMap.set(time, { time: parseFloat(String(meanTime)), rows_read: parseFloat(String(rowsRead)), calls: parseFloat(String(calls)), cache_hits: parseFloat(String(cacheHits)), }) }) return queryDataMap }, [currentSelectedQuery, parsedLogs]) const mergedChartData = useMemo(() => { if (!querySpecificData || !currentSelectedQuery) { return transformedChartData } return transformedChartData.map((dataPoint) => { const queryData = querySpecificData.get(dataPoint.period_start) return { ...dataPoint, selected_query_time: queryData?.time !== undefined ? selectedMetric === 'query_latency' ? queryData.time / 1000 : queryData.time : null, selected_query_rows_read: queryData?.rows_read !== undefined ? queryData.rows_read : null, selected_query_calls: queryData?.calls !== undefined ? queryData.calls : null, selected_query_cache_hits: queryData?.cache_hits !== undefined ? queryData.cache_hits : null, } }) }, [transformedChartData, querySpecificData, currentSelectedQuery, selectedMetric]) const getChartAttributes = useMemo((): MultiAttribute[] => { const attributeMap: Record = { query_latency: [ { attribute: 'p50_time', label: 'p50', provider: 'logs', type: 'line', color: { light: '#8B5CF6', dark: '#8B5CF6' }, }, { attribute: 'p95_time', label: 'p95', provider: 'logs', type: 'line', color: { light: '#65BCD9', dark: '#65BCD9' }, }, ], rows_read: [ { attribute: 'rows_read', label: 'Rows Read', provider: 'logs', }, ], calls: [ { attribute: 'calls', label: 'Calls', provider: 'logs', }, ], cache_hits: [ { attribute: 'cache_hits', label: 'Cache Hits', provider: 'logs', type: 'line', color: { light: '#10B981', dark: '#10B981' }, }, ], } const baseAttributes = attributeMap[selectedMetric] || [] if (currentSelectedQuery && querySpecificData) { const dimmedBaseAttributes = baseAttributes.map((attr) => ({ ...attr, color: attr.color ? { light: attr.color.light + '4D', dark: attr.color.dark + '4D' } : attr.color, })) const selectedQueryAttributes: Record = { query_latency: { attribute: 'selected_query_time', label: 'Selected Query', provider: 'logs', type: 'line', color: { light: '#10B981', dark: '#10B981' }, strokeWidth: 3, }, rows_read: { attribute: 'selected_query_rows_read', label: 'Selected Query', provider: 'logs', type: 'line', color: { light: '#F59E0B', dark: '#F59E0B' }, strokeWidth: 3, }, calls: { attribute: 'selected_query_calls', label: 'Selected Query', provider: 'logs', type: 'line', color: { light: '#EC4899', dark: '#EC4899' }, strokeWidth: 3, }, cache_hits: { attribute: 'selected_query_cache_hits', label: 'Selected Query', provider: 'logs', type: 'line', color: { light: '#8B5CF6', dark: '#8B5CF6' }, strokeWidth: 3, }, } const selectedQueryAttr = selectedQueryAttributes[selectedMetric] if (selectedQueryAttr) { return [...dimmedBaseAttributes, selectedQueryAttr] } } return baseAttributes }, [selectedMetric, currentSelectedQuery, querySpecificData]) const updateDateRange = (from: string, to: string) => { onDateRangeChange?.(from, to) } const getYAxisFormatter = useMemo(() => { if (selectedMetric === 'query_latency') { return formatTimeValue } return formatNumberValue }, [selectedMetric]) return (
setSelectedMetric(value as string)} className="w-full" > {QUERY_PERFORMANCE_CHART_TABS.map((tab) => ( {tab.label} ))}
{isLoading ? ( ) : error ? (

Error loading chart data

) : (
{currentMetrics.map((metric, index) => ( ))}
)}
) }