From 19cfa66d9ec9318a92d14e9b2ab3484c5ad2016b Mon Sep 17 00:00:00 2001 From: "kemal.earth" <606977+kemaldotearth@users.noreply.github.com> Date: Fri, 19 Sep 2025 15:00:59 +0100 Subject: [PATCH] feat(studio): move query details to sheet (#38815) * feat: move query details to sheet This moves the click through on Query Performance to a sheet as opposed to a resizable area. This gives us more space to play with and sets us up for the Query details revamp. * fix: tabs font size * style: expand size of sheet * feat: hasOverlay prop for sheets * feat: add optional overlay for sheets * fix: closing only when clicking outside of rows * style: width of panel on different viewports * fix: horizontal scroll for table * fix: query queries label check in metrics --- .../QueryPerformance.constants.ts | 2 +- .../QueryPerformance/QueryPerformanceGrid.tsx | 104 ++++++++++-------- .../QueryPerformanceMetrics.tsx | 13 +-- .../ui/src/components/shadcn/ui/sheet.tsx | 5 +- 4 files changed, 67 insertions(+), 57 deletions(-) diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.constants.ts b/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.constants.ts index 18565e4d2a..a09da9a32b 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.constants.ts +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.constants.ts @@ -22,7 +22,7 @@ export const QUERY_PERFORMANCE_COLUMNS = [ { id: 'min_time', name: 'Min time', description: undefined, minWidth: 100 }, { id: 'rows_read', name: 'Rows processed', description: undefined, minWidth: 130 }, { id: 'cache_hit_rate', name: 'Cache hit rate', description: undefined, minWidth: 130 }, - { id: 'rolname', name: 'Role', description: undefined, minWidth: 160 }, + { id: 'rolname', name: 'Role', description: undefined, minWidth: 200 }, ] as const export const QUERY_PERFORMANCE_ROLE_DESCRIPTION = [ diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx index 52eeda41fe..36cadf22a8 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx @@ -1,4 +1,4 @@ -import { ArrowDown, ArrowUp, ChevronDown, TextSearch, X } from 'lucide-react' +import { ArrowDown, ArrowUp, ChevronDown, TextSearch } from 'lucide-react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import DataGrid, { Column, DataGridHandle, Row } from 'react-data-grid' @@ -10,15 +10,15 @@ import { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, - ResizableHandle, - ResizablePanel, - ResizablePanelGroup, + Sheet, + SheetContent, TabsContent_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_, Tabs_Shadcn_, cn, CodeBlock, + SheetTitle, } from 'ui' import { InfoTooltip } from 'ui-patterns/info-tooltip' import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' @@ -42,6 +42,7 @@ export const QueryPerformanceGrid = ({ queryPerformanceQuery }: QueryPerformance const gridRef = useRef(null) const { sort: urlSort, order, roles, search } = useParams() const { isLoading, data } = queryPerformanceQuery + const dataGridContainerRef = useRef(null) const [view, setView] = useState<'details' | 'suggestion'>('details') const [selectedRow, setSelectedRow] = useState() @@ -313,6 +314,7 @@ export const QueryPerformanceGrid = ({ queryPerformanceQuery }: QueryPerformance return rawData }, [data, sort]) + const selectedQuery = selectedRow !== undefined ? reportData[selectedRow]?.query : undefined const query = (selectedQuery ?? '').trim().toLowerCase() const showIndexSuggestions = @@ -364,12 +366,8 @@ export const QueryPerformanceGrid = ({ queryPerformanceQuery }: QueryPerformance }, [handleKeyDown]) return ( - - +
+
{ + onClick={(event) => { + event.stopPropagation() + if (typeof idx === 'number' && idx >= 0) { setSelectedRow(idx) gridRef.current?.scrollToCell({ idx: 0, rowIdx: idx }) @@ -424,58 +424,70 @@ export const QueryPerformanceGrid = ({ queryPerformanceQuery }: QueryPerformance ), }} /> - - {selectedRow !== undefined && ( - <> - - -
+ + { + if (!open) { + setSelectedRow(undefined) + } + }} + modal={false} + > + Query details + { + if (dataGridContainerRef.current?.contains(event.target as Node)) { + event.preventDefault() + } + }} + > + setView(value)} + > +
+ Query details {showIndexSuggestions && ( Indexes )} - +
+ + + {selectedRow !== undefined && ( setView('suggestion')} /> - - - - -
- - - )} - + )} + + + {selectedRow !== undefined && } + + +
+
+
) } diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceMetrics.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceMetrics.tsx index e8e3b90857..e6c5a6a5f4 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceMetrics.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceMetrics.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react' +import React, { useMemo } from 'react' import { Skeleton } from 'ui' import { useQueryPerformanceQuery } from '../Reports/Reports.queries' @@ -11,7 +11,7 @@ export const QueryPerformanceMetrics = () => { const stats = useMemo(() => { return [ { - title: queryMetrics?.[0]?.slow_queries === '1' ? 'Slow Query' : 'Slow Queries', + title: queryMetrics?.[0]?.slow_queries === 1 ? 'Slow Query' : 'Slow Queries', value: queryMetrics?.[0]?.slow_queries || '0', }, { @@ -28,11 +28,8 @@ export const QueryPerformanceMetrics = () => { return (
{stats.map((card, i) => ( - <> -
+ +
{isLoading ? ( ) : ( @@ -43,7 +40,7 @@ export const QueryPerformanceMetrics = () => { )}
{i < stats.length - 1 && /} - +
))}
) diff --git a/packages/ui/src/components/shadcn/ui/sheet.tsx b/packages/ui/src/components/shadcn/ui/sheet.tsx index 1da16eb2f1..0330af9409 100644 --- a/packages/ui/src/components/shadcn/ui/sheet.tsx +++ b/packages/ui/src/components/shadcn/ui/sheet.tsx @@ -151,14 +151,15 @@ export interface DialogContentProps extends React.ComponentPropsWithoutRef, VariantProps { showClose?: boolean + hasOverlay?: boolean } const SheetContent = React.forwardRef< React.ElementRef, DialogContentProps ->(({ side, size, className, children, showClose = true, ...props }, ref) => ( +>(({ side, size, className, children, showClose = true, hasOverlay = true, ...props }, ref) => ( - + {hasOverlay && }