query-performance.tsx114 lines · main
1import { useParams } from 'common'
2import { parseAsArrayOf, parseAsInteger, parseAsJson, parseAsString, useQueryStates } from 'nuqs'
3import { Admonition } from 'ui-patterns'
4
5import { useIndexAdvisorStatus } from '@/components/interfaces/QueryPerformance/hooks/useIsIndexAdvisorStatus'
6import { useQueryPerformanceSort } from '@/components/interfaces/QueryPerformance/hooks/useQueryPerformanceSort'
7import { QueryPerformance } from '@/components/interfaces/QueryPerformance/QueryPerformance'
8import { type QuerySource } from '@/components/interfaces/QueryPerformance/QueryPerformance.types'
9import { useQueryPerformanceInfiniteQuery } from '@/components/interfaces/QueryPerformance/useQueryPerformanceQuery'
10import { PRESET_CONFIG } from '@/components/interfaces/Reports/Reports.constants'
11import { Presets } from '@/components/interfaces/Reports/Reports.types'
12import { queriesFactory } from '@/components/interfaces/Reports/Reports.utils'
13import { NumericFilter } from '@/components/interfaces/Reports/v2/ReportsNumericFilter'
14import { DefaultLayout } from '@/components/layouts/DefaultLayout'
15import ObservabilityLayout from '@/components/layouts/ObservabilityLayout/ObservabilityLayout'
16import { DatabaseSelector } from '@/components/ui/DatabaseSelector'
17import { DocsButton } from '@/components/ui/DocsButton'
18import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
19import { DOCS_URL } from '@/lib/constants'
20import type { NextPageWithLayout } from '@/types'
21
22const QueryPerformanceReport: NextPageWithLayout = () => {
23 const { ref } = useParams()
24 const { data: project, isLoading: isLoadingProject } = useSelectedProjectQuery()
25 const { isIndexAdvisorEnabled } = useIndexAdvisorStatus()
26 const { sort: sortConfig } = useQueryPerformanceSort()
27
28 const [
29 {
30 search: searchQuery,
31 roles,
32 sources,
33 minCalls,
34 totalTimeFilter: totalTimeFilterRaw,
35 indexAdvisor,
36 },
37 ] = useQueryStates({
38 sort: parseAsString,
39 order: parseAsString,
40 search: parseAsString.withDefault(''),
41 roles: parseAsArrayOf(parseAsString).withDefault([]),
42 sources: parseAsArrayOf(parseAsString).withDefault([]),
43 minCalls: parseAsInteger,
44 totalTimeFilter: parseAsJson<NumericFilter | null>((value) =>
45 value === null || value === undefined ? null : (value as NumericFilter)
46 ),
47 indexAdvisor: parseAsString.withDefault('false'),
48 })
49
50 const totalTimeFilter = totalTimeFilterRaw ?? null
51
52 const config = PRESET_CONFIG[Presets.QUERY_PERFORMANCE]
53 const hooks = queriesFactory(config.queries, ref ?? 'default')
54 const queryHitRate = hooks.queryHitRate()
55 const queryMetrics = hooks.queryMetrics()
56
57 const minTotalTime =
58 totalTimeFilter && totalTimeFilter.operator === '>'
59 ? totalTimeFilter.value
60 : totalTimeFilter && totalTimeFilter.operator === '>='
61 ? totalTimeFilter.value
62 : undefined
63
64 const queryPerformanceQuery = useQueryPerformanceInfiniteQuery({
65 searchQuery,
66 orderBy: sortConfig || undefined,
67 preset: 'unified',
68 roles,
69 sources: sources as QuerySource[],
70 runIndexAdvisor: isIndexAdvisorEnabled,
71 minCalls: minCalls ?? undefined,
72 minTotalTime,
73 filterIndexAdvisor: indexAdvisor === 'true',
74 })
75
76 if (!isLoadingProject && !project) {
77 return (
78 <div className="h-full flex flex-col p-6">
79 <Admonition
80 type="destructive"
81 title="Project not found"
82 description="Unable to load project data. Please check your project reference and try again."
83 />
84 </div>
85 )
86 }
87
88 return (
89 <div className="h-full flex flex-col">
90 <div className="w-full mb-0 flex lg:items-center justify-between gap-4 py-4 px-6 lg:flex-row flex-col">
91 <h3 className="text-foreground text-xl prose">Query Performance</h3>
92 <div className="flex items-center gap-2 flex-wrap">
93 <DocsButton
94 href={`${DOCS_URL}/guides/platform/performance#examining-query-performance`}
95 />
96 <DatabaseSelector />
97 </div>
98 </div>
99 <QueryPerformance
100 queryHitRate={queryHitRate}
101 queryPerformanceQuery={queryPerformanceQuery}
102 queryMetrics={queryMetrics}
103 />
104 </div>
105 )
106}
107
108QueryPerformanceReport.getLayout = (page) => (
109 <DefaultLayout>
110 <ObservabilityLayout title="Query Performance">{page}</ObservabilityLayout>
111 </DefaultLayout>
112)
113
114export default QueryPerformanceReport