feat(studio): remove query performance tabs (#38606)

* feat: remove tabs and unify columns

This removes the tabs from Query Performance with unified columns in the table.

* chore: remove unused imports

* chore: small adjustment to min max and mean time col size

* chore: remove unused prop
This commit is contained in:
kemal.earth
2025-09-11 15:20:52 +01:00
committed by GitHub
parent 55154a6065
commit 5fe3383c39
8 changed files with 84 additions and 190 deletions

View File

@@ -1,7 +1,6 @@
import { InformationCircleIcon } from '@heroicons/react/16/solid'
import { X } from 'lucide-react'
import { parseAsString, useQueryStates } from 'nuqs'
import { useEffect, useMemo, useState } from 'react'
import { parseAsArrayOf, parseAsString, useQueryStates } from 'nuqs'
import { useEffect, useState } from 'react'
import { toast } from 'sonner'
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
@@ -13,23 +12,10 @@ import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { IS_PLATFORM } from 'lib/constants'
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
import {
Button,
LoadingLine,
TabsList_Shadcn_,
TabsTrigger_Shadcn_,
Tabs_Shadcn_,
Tooltip,
TooltipContent,
TooltipTrigger,
cn,
} from 'ui'
import { Button, LoadingLine, cn } from 'ui'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
import { Markdown } from '../Markdown'
import { useQueryPerformanceQuery } from '../Reports/Reports.queries'
import { PresetHookResult } from '../Reports/Reports.utils'
import { QUERY_PERFORMANCE_REPORT_TYPES } from './QueryPerformance.constants'
import { QueryPerformanceFilterBar } from './QueryPerformanceFilterBar'
import { QueryPerformanceGrid } from './QueryPerformanceGrid'
@@ -46,11 +32,11 @@ export const QueryPerformance = ({
const { data: project } = useSelectedProjectQuery()
const state = useDatabaseSelectorStateSnapshot()
const [{ preset }, setSearchParams] = useQueryStates({
const [{ search: searchQuery, roles }] = useQueryStates({
sort: parseAsString,
search: parseAsString,
order: parseAsString,
preset: parseAsString.withDefault(QUERY_PERFORMANCE_REPORT_TYPES.MOST_TIME_CONSUMING),
roles: parseAsArrayOf(parseAsString).withDefault([]),
})
const { isLoading, isRefetching } = queryPerformanceQuery
@@ -71,133 +57,13 @@ export const QueryPerformance = ({
const { data: databases } = useReadReplicasQuery({ projectRef: ref })
const { data: mostTimeConsumingQueries, isLoading: isLoadingMTC } = useQueryPerformanceQuery({
preset: 'mostTimeConsuming',
})
const { data: mostFrequentlyInvoked, isLoading: isLoadingMFI } = useQueryPerformanceQuery({
preset: 'mostFrequentlyInvoked',
})
const { data: slowestExecutionTime, isLoading: isLoadingMMF } = useQueryPerformanceQuery({
preset: 'slowestExecutionTime',
})
const QUERY_PERFORMANCE_TABS = useMemo(() => {
return [
{
id: QUERY_PERFORMANCE_REPORT_TYPES.MOST_TIME_CONSUMING,
label: 'Most time consuming',
description: 'Lists queries ordered by their cumulative total execution time.',
isLoading: isLoadingMTC,
max:
(mostTimeConsumingQueries ?? []).length > 0
? Math.max(...(mostTimeConsumingQueries ?? []).map((x: any) => x.total_time)).toFixed(2)
: undefined,
},
{
id: QUERY_PERFORMANCE_REPORT_TYPES.MOST_FREQUENT,
label: 'Most frequent',
description: 'Lists queries in order of their execution count',
isLoading: isLoadingMFI,
max:
(mostFrequentlyInvoked ?? []).length > 0
? Math.max(...(mostFrequentlyInvoked ?? []).map((x: any) => x.calls)).toFixed(2)
: undefined,
},
{
id: QUERY_PERFORMANCE_REPORT_TYPES.SLOWEST_EXECUTION,
label: 'Slowest execution',
description: 'Lists queries ordered by their maximum execution time',
isLoading: isLoadingMMF,
max:
(slowestExecutionTime ?? []).length > 0
? Math.max(...(slowestExecutionTime ?? []).map((x: any) => x.max_time)).toFixed(2)
: undefined,
},
]
}, [
isLoadingMFI,
isLoadingMMF,
isLoadingMTC,
mostFrequentlyInvoked,
mostTimeConsumingQueries,
slowestExecutionTime,
])
useEffect(() => {
state.setSelectedDatabaseId(ref)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ref])
return (
<>
<Tabs_Shadcn_
value={preset}
defaultValue={preset}
onValueChange={(value) => setSearchParams({ preset: value })}
>
<TabsList_Shadcn_ className={cn('flex gap-0 border-0 items-end z-10')}>
{QUERY_PERFORMANCE_TABS.map((tab) => {
const tabMax = Number(tab.max)
const maxValue =
tab.id !== QUERY_PERFORMANCE_REPORT_TYPES.MOST_FREQUENT
? tabMax > 1000
? (tabMax / 1000).toFixed(2)
: tabMax.toFixed(0)
: tabMax.toLocaleString()
return (
<TabsTrigger_Shadcn_
key={tab.id}
value={tab.id}
className={cn(
'group relative',
'px-6 py-3 border-b-0 flex flex-col items-start !shadow-none border-default border-t',
'even:border-x last:border-r even:!border-x-strong last:!border-r-strong',
tab.id === preset ? '!bg-surface-200' : '!bg-surface-200/[33%]',
'hover:!bg-surface-100',
'data-[state=active]:!bg-surface-200',
'hover:text-foreground-light',
'transition'
)}
>
{tab.id === preset && (
<div className="absolute top-0 left-0 w-full h-[1px] bg-foreground" />
)}
<div className="flex items-center gap-x-2">
<span className="">{tab.label}</span>
<Tooltip>
<TooltipTrigger asChild>
<InformationCircleIcon className="transition text-foreground-muted w-3 h-3 data-[state=delayed-open]:text-foreground-light" />
</TooltipTrigger>
<TooltipContent side="top">{tab.description}</TooltipContent>
</Tooltip>
</div>
{tab.isLoading ? (
<ShimmeringLoader className="w-32 pt-1" />
) : tab.max === undefined ? (
<span className="text-xs text-foreground-muted group-hover:text-foreground-lighter group-data-[state=active]:text-foreground-lighter transition">
No data yet
</span>
) : (
<span className="text-xs text-foreground-muted group-hover:text-foreground-lighter group-data-[state=active]:text-foreground-lighter transition">
{maxValue}
{tab.id !== QUERY_PERFORMANCE_REPORT_TYPES.MOST_FREQUENT
? tabMax > 1000
? 's'
: 'ms'
: ' calls'}
</span>
)}
{tab.id === preset && (
<div className="absolute bottom-0 left-0 w-full h-[1px] bg-surface-200"></div>
)}
</TabsTrigger_Shadcn_>
)
})}
</TabsList_Shadcn_>
</Tabs_Shadcn_>
<QueryPerformanceFilterBar
queryPerformanceQuery={queryPerformanceQuery}
onResetReportClick={() => setShowResetgPgStatStatements(true)}