11import { useRef , useState } from 'react'
2- import { Activity , FileText , LineChart , Loader2 , Settings , Users } from 'lucide-react'
2+ import { Activity , FileText , LineChart , Loader2 , Settings , Users , Database } from 'lucide-react'
33import { useConnectionManager } from '@/lib/hooks/useConnectionManager'
44import { useSlowLogSourceConfig } from '@/lib/hooks/queries'
55import QueryTrendsTab from '@/components/tabs/Performance/QueryTrendsTab'
66import CustomerExplorer from '@/components/tabs/Performance/CustomerExplorer'
77import SlowQuerySettingsPanel from '@/components/tabs/Performance/SlowQuerySettingsPanel'
88import WorkloadAnalysisPanel from '@/components/tabs/Performance/WorkloadAnalysisPanel'
99import SlowQuerySourceModal from '@/components/SlowQuerySourceModal'
10+ import SlowQueryAnalysisTab from '@/components/tabs/Performance/SlowQueryAnalysisTab'
1011import { HelpTooltip } from '@/components/tabs/Brain/components/HelpTooltip'
1112import sectionStyles from './TopLevelSection.module.css'
1213import styles from './SlowQueriesSection.module.css'
1314
1415const TABS = [
15- { id : 'trends' , label : 'Query Trends' , icon : LineChart } ,
16- { id : 'customers' , label : 'By Customer' , icon : Users } ,
17- { id : 'workload' , label : 'Workload' , icon : Activity } ,
18- { id : 'settings' , label : 'Settings' , icon : Settings } ,
16+ { id : 'analysis' , label : 'Analysis' , icon : Database , requiresLogSource : false } ,
17+ { id : 'trends' , label : 'Query Trends' , icon : LineChart , requiresLogSource : true } ,
18+ { id : 'customers' , label : 'By Customer' , icon : Users , requiresLogSource : true } ,
19+ { id : 'workload' , label : 'Workload' , icon : Activity , requiresLogSource : true } ,
20+ { id : 'settings' , label : 'Settings' , icon : Settings , requiresLogSource : false } ,
1921]
2022
2123const LOG_SOURCE_HELP = {
@@ -24,6 +26,12 @@ const LOG_SOURCE_HELP = {
2426 'Query trends, per-customer load, and workload analysis all read from ingested slow-query logs. Attach CloudWatch, S3, Azure, GCP, Datadog, Elasticsearch, or a file upload before those views can run.' ,
2527}
2628
29+ const PG_STAT_HELP = {
30+ title : 'pg_stat_statements' ,
31+ description :
32+ 'PostgreSQL connections use pg_stat_statements for real-time query analysis. No external log source needed. The Analysis tab shows top queries by execution time with index recommendations.' ,
33+ }
34+
2735/**
2836 * Combined Performance section — Slow Queries + Workload Analysis.
2937 *
@@ -32,8 +40,20 @@ const LOG_SOURCE_HELP = {
3240 */
3341export default function SlowQueriesSection ( ) {
3442 const { connectionId, selectedConnection, isLoading } = useConnectionManager ( )
35- const [ tab , setTab ] = useState ( 'trends' )
3643 const tabRefs = useRef ( { } )
44+ const logSourceQ = useSlowLogSourceConfig ( connectionId )
45+ const hasLogSource = Boolean ( logSourceQ . data ?. id )
46+
47+ // PostgreSQL connections can use pg_stat_statements directly without a log source
48+ const isPostgres = selectedConnection ?. dbType ?. toLowerCase ( ) === 'postgresql'
49+ const canShowPerformance = hasLogSource || isPostgres
50+
51+ // Filter tabs based on available data sources
52+ const availableTabs = TABS . filter ( ( t ) => ! t . requiresLogSource || hasLogSource )
53+
54+ // Default to 'analysis' for PostgreSQL without log source, otherwise 'trends'
55+ const defaultTab = ( isPostgres && ! hasLogSource ) ? 'analysis' : 'trends'
56+ const [ tab , setTab ] = useState ( defaultTab )
3757
3858 /** Arrow / Home / End move between tabs, as the ARIA tabs pattern expects. */
3959 const onTabKeyDown = ( e ) => {
@@ -44,20 +64,18 @@ export default function SlowQueriesSection() {
4464 // handler was created: two keypresses within one render would otherwise both move
4565 // relative to the same starting index and selection would stick after the first.
4666 setTab ( ( current ) => {
47- const i = TABS . findIndex ( ( t ) => t . id === current )
67+ const i = availableTabs . findIndex ( ( t ) => t . id === current )
4868 const next = e . key === 'Home' ? 0
49- : e . key === 'End' ? TABS . length - 1
50- : ( i + step + TABS . length ) % TABS . length
51- const id = TABS [ next ] . id
69+ : e . key === 'End' ? availableTabs . length - 1
70+ : ( i + step + availableTabs . length ) % availableTabs . length
71+ const id = availableTabs [ next ] . id
5272 // Focus follows selection, per the ARIA tabs pattern. Deferred so the tab is
5373 // already rendered with tabIndex=0 when we focus it.
5474 queueMicrotask ( ( ) => tabRefs . current [ id ] ?. focus ( ) )
5575 return id
5676 } )
5777 }
5878 const [ logSourceModalOpen , setLogSourceModalOpen ] = useState ( false )
59- const logSourceQ = useSlowLogSourceConfig ( connectionId )
60- const hasLogSource = Boolean ( logSourceQ . data ?. id )
6179
6280 // Wait for connection list to load before rendering anything
6381 if ( isLoading ) {
@@ -97,7 +115,7 @@ export default function SlowQueriesSection() {
97115 < div className = { styles . empty } >
98116 Could not load the slow query log configuration for this connection.
99117 </ div >
100- ) : ! hasLogSource ? (
118+ ) : ! canShowPerformance ? (
101119 < div className = { styles . setupCard } >
102120 < FileText size = { 32 } className = { styles . setupIcon } />
103121 < h2 className = { styles . setupTitle } > Configure slow queries</ h2 >
@@ -131,7 +149,7 @@ export default function SlowQueriesSection() {
131149 aria-label = "Performance views"
132150 onKeyDown = { onTabKeyDown }
133151 >
134- { TABS . map ( ( t ) => {
152+ { availableTabs . map ( ( t ) => {
135153 const Icon = t . icon
136154 const active = tab === t . id
137155 return (
@@ -166,13 +184,33 @@ export default function SlowQueriesSection() {
166184 </ button >
167185 </ div >
168186
187+ { /* Show pg_stat_statements info banner for PostgreSQL without log source */ }
188+ { isPostgres && ! hasLogSource && (
189+ < div className = { styles . pgStatBanner } >
190+ < HelpTooltip content = { PG_STAT_HELP } >
191+ < span className = { styles . pgStatBannerText } >
192+ < Database size = { 14 } />
193+ Using pg_stat_statements for real-time query analysis.
194+ </ span >
195+ </ HelpTooltip >
196+ < button
197+ type = "button"
198+ className = { styles . pgStatBannerLink }
199+ onClick = { ( ) => setLogSourceModalOpen ( true ) }
200+ >
201+ Add log source for trends & workload
202+ </ button >
203+ </ div >
204+ ) }
205+
169206 < div
170207 className = { styles . content }
171208 role = "tabpanel"
172209 id = { `perf-panel-${ tab } ` }
173210 aria-labelledby = { `perf-tab-${ tab } ` }
174211 tabIndex = { 0 }
175212 >
213+ { tab === 'analysis' && < SlowQueryAnalysisTab connectionId = { connectionId } /> }
176214 { tab === 'trends' && < QueryTrendsTab connectionId = { connectionId } /> }
177215 { tab === 'customers' && < CustomerExplorer connectionId = { connectionId } /> }
178216 { tab === 'workload' && < WorkloadAnalysisPanel connectionId = { connectionId } /> }
0 commit comments