diff --git a/apps/studio/components/interfaces/QueryPerformance/IndexAdvisor/EnableIndexAdvisorButton.tsx b/apps/studio/components/interfaces/QueryPerformance/IndexAdvisor/EnableIndexAdvisorButton.tsx index 741f8a3a153..06b938331b6 100644 --- a/apps/studio/components/interfaces/QueryPerformance/IndexAdvisor/EnableIndexAdvisorButton.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/IndexAdvisor/EnableIndexAdvisorButton.tsx @@ -1,7 +1,6 @@ import { useState } from 'react' import { toast } from 'sonner' -import { useIndexAdvisorStatus } from 'components/interfaces/QueryPerformance/hooks/useIsIndexAdvisorStatus' import { useDatabaseExtensionEnableMutation } from 'data/database-extensions/database-extension-enable-mutation' import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' @@ -17,18 +16,12 @@ import { AlertDialogTrigger, Badge, Button, - InfoIcon, - Tooltip, - TooltipContent, - TooltipTrigger, } from 'ui' import { getIndexAdvisorExtensions } from './index-advisor.utils' export const EnableIndexAdvisorButton = () => { const { data: project } = useSelectedProjectQuery() - const { isIndexAdvisorAvailable, isIndexAdvisorEnabled } = useIndexAdvisorStatus() - const [isDialogOpen, setIsDialogOpen] = useState(false) const { data: extensions } = useDatabaseExtensionsQuery({ @@ -72,21 +65,11 @@ export const EnableIndexAdvisorButton = () => { } } - // if index_advisor is already enabled or not available to install, show nothing - if (!isIndexAdvisorAvailable || isIndexAdvisorEnabled) return null - return ( setIsDialogOpen(!isDialogOpen)}> - - - - - - - Recommends indexes to improve query performance - + + + diff --git a/apps/studio/components/interfaces/QueryPerformance/IndexAdvisor/IndexAdvisorNotice.tsx b/apps/studio/components/interfaces/QueryPerformance/IndexAdvisor/IndexAdvisorNotice.tsx new file mode 100644 index 00000000000..c1fe2791529 --- /dev/null +++ b/apps/studio/components/interfaces/QueryPerformance/IndexAdvisor/IndexAdvisorNotice.tsx @@ -0,0 +1,60 @@ +import { useIndexAdvisorStatus } from 'components/interfaces/QueryPerformance/hooks/useIsIndexAdvisorStatus' +import { BASE_PATH } from 'lib/constants' +import { Admonition } from 'ui-patterns' +import { EnableIndexAdvisorButton } from './EnableIndexAdvisorButton' +import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' +import { LOCAL_STORAGE_KEYS } from 'common' +import { useParams } from 'common/hooks' +import { Button } from 'ui' + +export const IndexAdvisorNotice = () => { + const { ref } = useParams() + const { isIndexAdvisorAvailable, isIndexAdvisorEnabled } = useIndexAdvisorStatus() + const [isDismissed, setIsDismissed] = useLocalStorageQuery( + LOCAL_STORAGE_KEYS.INDEX_ADVISOR_NOTICE_DISMISSED(ref ?? ''), + false + ) + + if (!isIndexAdvisorAvailable || isIndexAdvisorEnabled || isDismissed) return null + + return ( +
+ +
+ Index Advisor + Index Advisor +
+
+
+
+
+

Enable Index Advisor

+
+

+ Recommends indexes to improve query performance. +

+
+
+ + +
+
+ +
+ ) +} diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryIndexes.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryIndexes.tsx index 036b2bfb867..5e4e85447f3 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryIndexes.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryIndexes.tsx @@ -32,6 +32,9 @@ import { createIndexes, hasIndexRecommendations, } from './IndexAdvisor/index-advisor.utils' +import { EnableIndexAdvisorButton } from './IndexAdvisor/EnableIndexAdvisorButton' +import { DocsButton } from 'components/ui/DocsButton' +import { DOCS_URL } from 'lib/constants' interface QueryIndexesProps { selectedRow: any @@ -122,11 +125,30 @@ export const QueryIndexes = ({ selectedRow }: QueryIndexesProps) => { } } + if (!isLoadingExtensions && !isIndexAdvisorEnabled) { + return ( + + +
+

Enable Index Advisor

+

+ Recommends indexes to improve query performance. +

+
+ + +
+
+
+
+ ) + } + return (
-

Indexes in use

+

Indexes in use

This query is using the following index{(usedIndexes ?? []).length > 1 ? 's' : ''}:

@@ -142,7 +164,7 @@ export const QueryIndexes = ({ selectedRow }: QueryIndexesProps) => { {isSuccess && (
{usedIndexes.length === 0 && ( -
+

No indexes are involved in this query

@@ -173,7 +195,7 @@ export const QueryIndexes = ({ selectedRow }: QueryIndexesProps) => {
-

New index recommendations

+

New index recommendations

{isLoadingExtensions ? ( ) : !isIndexAdvisorEnabled ? ( @@ -252,8 +274,8 @@ export const QueryIndexes = ({ selectedRow }: QueryIndexesProps) => { <>
-

Query costs

-
+

Query costs

+
{
-

FAQ

+

FAQ

diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceChart.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceChart.tsx index a8672d4ac2a..a8dc5314b83 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceChart.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceChart.tsx @@ -335,7 +335,7 @@ export const QueryPerformanceChart = ({ -
+
{isLoading ? ( ) : error ? ( @@ -375,7 +375,7 @@ export const QueryPerformanceChart = ({ tickFormatter: getYAxisFormatter, }} xAxisIsDate={true} - className="mt-6" + className="mt-2" />
)} diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceFilterBar.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceFilterBar.tsx index 33af5d28f9a..69377159ae9 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceFilterBar.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceFilterBar.tsx @@ -13,6 +13,7 @@ import { ReportsNumericFilter, NumericFilter, } from 'components/interfaces/Reports/v2/ReportsNumericFilter' +import { useIndexAdvisorStatus } from './hooks/useIsIndexAdvisorStatus' export const QueryPerformanceFilterBar = ({ actions, @@ -23,16 +24,20 @@ export const QueryPerformanceFilterBar = ({ }) => { const { data: project } = useSelectedProjectQuery() const { sort, clearSort } = useQueryPerformanceSort() + const { isIndexAdvisorEnabled } = useIndexAdvisorStatus() - const [{ search: searchQuery, roles: defaultFilterRoles, callsFilter }, setSearchParams] = - useQueryStates({ - search: parseAsString.withDefault(''), - roles: parseAsArrayOf(parseAsString).withDefault([]), - callsFilter: parseAsJson((value) => value as NumericFilter | null).withDefault({ - operator: '>=', - value: 0, - } as NumericFilter), - }) + const [ + { search: searchQuery, roles: defaultFilterRoles, callsFilter, indexAdvisor }, + setSearchParams, + ] = useQueryStates({ + search: parseAsString.withDefault(''), + roles: parseAsArrayOf(parseAsString).withDefault([]), + callsFilter: parseAsJson((value) => value as NumericFilter | null).withDefault({ + operator: '>=', + value: 0, + } as NumericFilter), + indexAdvisor: parseAsString.withDefault('false'), + }) const { data, isLoading: isLoadingRoles } = useDatabaseRolesQuery({ projectRef: project?.ref, connectionString: project?.connectionString, @@ -56,11 +61,17 @@ export const QueryPerformanceFilterBar = ({ setSearchParams({ roles }) } + const onIndexAdvisorChange = (options: string[]) => { + setSearchParams({ indexAdvisor: options.includes('true') ? 'true' : 'false' }) + } + useEffect(() => { onSearchQueryChange(searchValue) // eslint-disable-next-line react-hooks/exhaustive-deps }, [searchValue]) + const indexAdvisorOptions = [{ value: 'true', label: 'Index Advisor' }] + return (
@@ -111,6 +122,18 @@ export const QueryPerformanceFilterBar = ({ /> )} + {isIndexAdvisorEnabled && ( + + )} + {sort && (

diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx index 9a3157d1f2a..ee5b1acd2bd 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx @@ -13,6 +13,7 @@ import { DropdownMenuTrigger, Sheet, SheetContent, + SheetDescription, SheetTitle, TabsContent_Shadcn_, TabsList_Shadcn_, @@ -40,8 +41,8 @@ import { NumericFilter } from 'components/interfaces/Reports/v2/ReportsNumericFi interface QueryPerformanceGridProps { aggregatedData: QueryPerformanceRow[] isLoading: boolean - currentSelectedQuery?: string | null // Make optional - onCurrentSelectQuery?: (query: string) => void // Make optional + currentSelectedQuery?: string | null + onCurrentSelectQuery?: (query: string) => void } const calculateTimeConsumedWidth = (data: QueryPerformanceRow[]) => { @@ -397,14 +398,6 @@ export const QueryPerformanceGrid = ({ return data }, [aggregatedData, sort, search, roles, callsFilter]) - const selectedQuery = selectedRow !== undefined ? reportData[selectedRow]?.query : undefined - const query = (selectedQuery ?? '').trim().toLowerCase() - const showIndexSuggestions = - (query.startsWith('select') || - query.startsWith('with pgrst_source') || - query.startsWith('with pgrst_payload')) && - hasIndexRecommendations(reportData[selectedRow!]?.index_advisor_result, true) - useEffect(() => { setSelectedRow(undefined) }, [search, roles, urlSort, order, callsFilter]) @@ -460,10 +453,14 @@ export const QueryPerformanceGrid = ({ const isSelected = idx === selectedRow const query = reportData[idx]?.query const isCharted = currentSelectedQuery ? currentSelectedQuery === query : false + const hasRecommendations = hasIndexRecommendations( + reportData[idx]?.index_advisor_result, + true + ) return [ - `${isSelected ? 'bg-surface-300 dark:bg-surface-300' : 'bg-200'} cursor-pointer`, - `${isSelected ? '[&>div:first-child]:border-l-4 border-l-secondary [&>div]:!border-l-foreground' : ''}`, + `${isSelected ? (hasRecommendations ? 'bg-warning/10 hover:bg-warning/20' : 'bg-surface-300 dark:bg-surface-300') : hasRecommendations ? 'bg-warning/10 hover:bg-warning/20' : 'bg-200 hover:bg-surface-200'} cursor-pointer`, + `${isSelected ? (hasRecommendations ? '[&>div:first-child]:border-l-4 border-l-warning [&>div]:border-l-warning' : '[&>div:first-child]:border-l-4 border-l-secondary [&>div]:!border-l-foreground') : ''}`, `${isCharted ? 'bg-surface-200 dark:bg-surface-200' : ''}`, `${isCharted ? '[&>div:first-child]:border-l-4 border-l-secondary [&>div]:border-l-brand' : ''}`, '[&>.rdg-cell]:box-border [&>.rdg-cell]:outline-none [&>.rdg-cell]:shadow-none', @@ -489,7 +486,11 @@ export const QueryPerformanceGrid = ({ } else { // Otherwise, open the detail panel setSelectedRow(idx) - setView('details') + const hasRecommendations = hasIndexRecommendations( + reportData[idx]?.index_advisor_result, + true + ) + setView(hasRecommendations ? 'suggestion' : 'details') gridRef.current?.scrollToCell({ idx: 0, rowIdx: idx }) } } @@ -526,6 +527,9 @@ export const QueryPerformanceGrid = ({ modal={false} > Query details + + Query Performance Details & Indexes + Query details - {showIndexSuggestions && ( - - Indexes - - )} + + Indexes +

diff --git a/apps/studio/components/interfaces/QueryPerformance/WithMonitor/WithMonitor.tsx b/apps/studio/components/interfaces/QueryPerformance/WithMonitor/WithMonitor.tsx index db34a8def4c..1199dc87f64 100644 --- a/apps/studio/components/interfaces/QueryPerformance/WithMonitor/WithMonitor.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/WithMonitor/WithMonitor.tsx @@ -14,6 +14,7 @@ import { } from './WithMonitor.utils' import { useParams } from 'common' import { DownloadResultsButton } from 'components/ui/DownloadResultsButton' +import { IndexAdvisorNotice } from '../IndexAdvisor/IndexAdvisorNotice' dayjs.extend(utc) @@ -81,6 +82,7 @@ export const WithMonitor = ({ dateRange, onDateRangeChange }: WithMonitorProps) return ( <> + + - - + tooltip={{ content: { side: 'top', text: 'Reset report' } }} + className="w-[26px]" + /> + ` + sql: (_params, where, orderBy, runIndexAdvisor = false, filterIndexAdvisor = false) => ` -- reports-query-performance-most-frequently-invoked set search_path to public, extensions; @@ -416,7 +416,7 @@ select }, mostTimeConsuming: { queryType: 'db', - sql: (_, where, orderBy, runIndexAdvisor = false) => ` + sql: (_, where, orderBy, runIndexAdvisor = false, filterIndexAdvisor = false) => ` -- reports-query-performance-most-time-consuming set search_path to public, extensions; @@ -454,7 +454,7 @@ select }, slowestExecutionTime: { queryType: 'db', - sql: (_params, where, orderBy, runIndexAdvisor = false) => ` + sql: (_params, where, orderBy, runIndexAdvisor = false, filterIndexAdvisor = false) => ` -- reports-query-performance-slowest-execution-time set search_path to public, extensions; @@ -513,59 +513,68 @@ select }, unified: { queryType: 'db', - sql: (_params, where, orderBy, runIndexAdvisor = false) => ` + sql: (_params, where, orderBy, runIndexAdvisor = false, filterIndexAdvisor = false) => { + const baseQuery = ` -- reports-query-performance-unified set search_path to public, extensions; - select - auth.rolname, - statements.query, - statements.calls, - -- -- Postgres 13, 14, 15 - statements.total_exec_time + statements.total_plan_time as total_time, - statements.min_exec_time + statements.min_plan_time as min_time, - statements.max_exec_time + statements.max_plan_time as max_time, - statements.mean_exec_time + statements.mean_plan_time as mean_time, - -- -- Postgres <= 12 - -- total_time, - -- min_time, - -- max_time, - -- mean_time, - statements.rows / statements.calls as avg_rows, - statements.rows as rows_read, - statements.shared_blks_hit as debug_hit, - statements.shared_blks_read as debug_read, - case - when (statements.shared_blks_hit + statements.shared_blks_read) > 0 - then (statements.shared_blks_hit::numeric * 100.0) / - (statements.shared_blks_hit + statements.shared_blks_read) - else 0 - end as cache_hit_rate, - ((statements.total_exec_time + statements.total_plan_time)/sum(statements.total_exec_time + statements.total_plan_time) OVER()) * 100 as prop_total_time${ - runIndexAdvisor - ? `, - case - when (lower(statements.query) like 'select%' or lower(statements.query) like 'with pgrst%') - then ( - select json_build_object( - 'has_suggestion', array_length(index_statements, 1) > 0, - 'startup_cost_before', startup_cost_before, - 'startup_cost_after', startup_cost_after, - 'total_cost_before', total_cost_before, - 'total_cost_after', total_cost_after, - 'index_statements', index_statements + with query_results as ( + select + auth.rolname, + statements.query, + statements.calls, + -- -- Postgres 13, 14, 15 + statements.total_exec_time + statements.total_plan_time as total_time, + statements.min_exec_time + statements.min_plan_time as min_time, + statements.max_exec_time + statements.max_plan_time as max_time, + statements.mean_exec_time + statements.mean_plan_time as mean_time, + -- -- Postgres <= 12 + -- total_time, + -- min_time, + -- max_time, + -- mean_time, + statements.rows / statements.calls as avg_rows, + statements.rows as rows_read, + statements.shared_blks_hit as debug_hit, + statements.shared_blks_read as debug_read, + case + when (statements.shared_blks_hit + statements.shared_blks_read) > 0 + then (statements.shared_blks_hit::numeric * 100.0) / + (statements.shared_blks_hit + statements.shared_blks_read) + else 0 + end as cache_hit_rate, + ((statements.total_exec_time + statements.total_plan_time)/sum(statements.total_exec_time + statements.total_plan_time) OVER()) * 100 as prop_total_time${ + runIndexAdvisor + ? `, + case + when (lower(statements.query) like 'select%' or lower(statements.query) like 'with pgrst%') + then ( + select json_build_object( + 'has_suggestion', array_length(index_statements, 1) > 0, + 'startup_cost_before', startup_cost_before, + 'startup_cost_after', startup_cost_after, + 'total_cost_before', total_cost_before, + 'total_cost_after', total_cost_after, + 'index_statements', index_statements + ) + from index_advisor(statements.query) ) - from index_advisor(statements.query) - ) - else null - end as index_advisor_result` - : '' - } - from pg_stat_statements as statements - inner join pg_authid as auth on statements.userid = auth.oid - ${where || ''} - ${orderBy || 'order by statements.total_exec_time + statements.total_plan_time desc'} - limit 20`, + else null + end as index_advisor_result` + : '' + } + from pg_stat_statements as statements + inner join pg_authid as auth on statements.userid = auth.oid + ${where || ''} + ) + select * + from query_results + ${filterIndexAdvisor && runIndexAdvisor ? `where (index_advisor_result->>'has_suggestion')::boolean = true` : ''} + ${orderBy || 'order by total_time desc'} + limit 20` + + return baseQuery + }, }, slowQueriesCount: { queryType: 'db', @@ -580,7 +589,7 @@ select }, queryMetrics: { queryType: 'db', - sql: (_params, where, orderBy, runIndexAdvisor = false) => ` + sql: (_params, where, orderBy, runIndexAdvisor = false, filterIndexAdvisor = false) => ` -- reports-query-performance-metrics set search_path to public, extensions; diff --git a/apps/studio/components/interfaces/Reports/Reports.queries.ts b/apps/studio/components/interfaces/Reports/Reports.queries.ts index 3e56da4f3b0..cdfbcaf8cf1 100644 --- a/apps/studio/components/interfaces/Reports/Reports.queries.ts +++ b/apps/studio/components/interfaces/Reports/Reports.queries.ts @@ -30,6 +30,7 @@ export type QueryPerformanceQueryOpts = { roles?: string[] runIndexAdvisor?: boolean minCalls?: number + filterIndexAdvisor?: boolean } export const useQueryPerformanceQuery = ({ @@ -39,6 +40,7 @@ export const useQueryPerformanceQuery = ({ roles, runIndexAdvisor = false, minCalls, + filterIndexAdvisor = false, }: QueryPerformanceQueryOpts) => { const queryPerfQueries = PRESET_CONFIG[Presets.QUERY_PERFORMANCE] const baseSQL = queryPerfQueries.queries[preset] @@ -58,7 +60,8 @@ export const useQueryPerformanceQuery = ({ [], whereSql.length > 0 ? `WHERE ${whereSql}` : undefined, orderBySql, - runIndexAdvisor + runIndexAdvisor, + filterIndexAdvisor ) return useDbQuery({ sql, diff --git a/apps/studio/components/interfaces/Reports/Reports.types.ts b/apps/studio/components/interfaces/Reports/Reports.types.ts index bc304f2d21a..246afb7fca7 100644 --- a/apps/studio/components/interfaces/Reports/Reports.types.ts +++ b/apps/studio/components/interfaces/Reports/Reports.types.ts @@ -25,7 +25,8 @@ export interface ReportQuery { filters: ReportFilterItem[], where?: string, orderBy?: string, - runIndexAdvisor?: boolean + runIndexAdvisor?: boolean, + filterIndexAdvisor?: boolean ) => string } diff --git a/apps/studio/components/interfaces/UnifiedLogs/components/DownloadLogsButton.tsx b/apps/studio/components/interfaces/UnifiedLogs/components/DownloadLogsButton.tsx index 0d5843b8515..4defc893008 100644 --- a/apps/studio/components/interfaces/UnifiedLogs/components/DownloadLogsButton.tsx +++ b/apps/studio/components/interfaces/UnifiedLogs/components/DownloadLogsButton.tsx @@ -1,11 +1,12 @@ import saveAs from 'file-saver' -import { Download } from 'lucide-react' +import { Download, Settings } from 'lucide-react' import Link from 'next/link' import Papa from 'papaparse' import { useEffect, useState } from 'react' import { toast } from 'sonner' -import { useParams } from 'common' +import { usePathname } from 'next/navigation' +import { IS_PLATFORM, useParams } from 'common' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { useGetUnifiedLogsMutation } from 'data/logs/get-unified-logs' import { @@ -38,6 +39,8 @@ interface DownloadLogsButtonProps { export const DownloadLogsButton = ({ searchParameters }: DownloadLogsButtonProps) => { const { ref } = useParams() + const pathname = usePathname() + const isLogs = pathname?.includes?.('/logs') ?? false const [numRows, setNumRows] = useState(DEFAULT_NUM_ROWS) const [numHours, setNumHours] = useState(DEFAULT_NUM_ROWS) const [selectedFormat, setSelectedFormat] = useState<'csv' | 'json'>() @@ -98,16 +101,21 @@ export const DownloadLogsButton = ({ searchParameters }: DownloadLogsButtonProps tooltip={{ content: { side: 'bottom', text: 'Download logs' } }} /> - - - -

Add a Log Drain

- -
- setSelectedFormat('csv')}> + + {isLogs && IS_PLATFORM && ( + + + +

Add a Log Drain

+ +
+ )} + setSelectedFormat('csv')} className="gap-x-2"> +

Download as CSV

- setSelectedFormat('json')}> + setSelectedFormat('json')} className="gap-x-2"> +

Download as JSON

diff --git a/apps/studio/components/layouts/ObservabilityLayout/ObservabilityMenu.tsx b/apps/studio/components/layouts/ObservabilityLayout/ObservabilityMenu.tsx index 07b5a69ebd0..4237519d1b3 100644 --- a/apps/studio/components/layouts/ObservabilityLayout/ObservabilityMenu.tsx +++ b/apps/studio/components/layouts/ObservabilityLayout/ObservabilityMenu.tsx @@ -2,7 +2,7 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { Plus } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/router' -import { useMemo, useState } from 'react' +import { Fragment, useMemo, useState } from 'react' import { toast } from 'sonner' import { useFlag, useParams } from 'common' @@ -275,9 +275,9 @@ const ObservabilityMenu = () => {
{menuItems.map((item, idx) => ( - <> +
-
+
{item.items ? (
{item.title}} /> @@ -305,7 +305,7 @@ const ObservabilityMenu = () => {
) : null}
- + ))} { const { ref } = useParams() + const pathname = usePathname() + const isLogs = pathname?.includes?.('/logs') ?? false // [Joshen] Ensure JSON values are stringified for CSV and Markdown const formattedResults = results.map((row) => { const r = { ...row } @@ -109,12 +113,14 @@ export const DownloadResultsButton = ({ - - - -

Add a Log Drain

- -
+ {isLogs && IS_PLATFORM && ( + + + +

Add a Log Drain

+ +
+ )}

Copy as markdown

diff --git a/apps/studio/pages/project/[ref]/observability/query-performance.tsx b/apps/studio/pages/project/[ref]/observability/query-performance.tsx index 95b8b580f11..4ccabcd5b7c 100644 --- a/apps/studio/pages/project/[ref]/observability/query-performance.tsx +++ b/apps/studio/pages/project/[ref]/observability/query-performance.tsx @@ -3,7 +3,6 @@ import { parseAsArrayOf, parseAsInteger, parseAsString, useQueryStates } from 'n import { useParams } from 'common' import { useIndexAdvisorStatus } from 'components/interfaces/QueryPerformance/hooks/useIsIndexAdvisorStatus' import { useQueryPerformanceSort } from 'components/interfaces/QueryPerformance/hooks/useQueryPerformanceSort' -import { EnableIndexAdvisorButton } from 'components/interfaces/QueryPerformance/IndexAdvisor/EnableIndexAdvisorButton' import { QueryPerformance } from 'components/interfaces/QueryPerformance/QueryPerformance' import { PRESET_CONFIG, @@ -17,7 +16,6 @@ import DefaultLayout from 'components/layouts/DefaultLayout' import ObservabilityLayout from 'components/layouts/ObservabilityLayout/ObservabilityLayout' import DatabaseSelector from 'components/ui/DatabaseSelector' import { DocsButton } from 'components/ui/DocsButton' -import { FormHeader } from 'components/ui/Forms/FormHeader' import { useReportDateRange } from 'hooks/misc/useReportDateRange' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { DOCS_URL } from 'lib/constants' @@ -37,12 +35,13 @@ const QueryPerformanceReport: NextPageWithLayout = () => { handleDatePickerChange, } = useReportDateRange(REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES) - const [{ search: searchQuery, roles, minCalls }] = useQueryStates({ + const [{ search: searchQuery, roles, minCalls, indexAdvisor }] = useQueryStates({ sort: parseAsString, order: parseAsString, search: parseAsString.withDefault(''), roles: parseAsArrayOf(parseAsString).withDefault([]), minCalls: parseAsInteger, + indexAdvisor: parseAsString.withDefault('false'), }) const config = PRESET_CONFIG[Presets.QUERY_PERFORMANCE] @@ -57,37 +56,34 @@ const QueryPerformanceReport: NextPageWithLayout = () => { roles, runIndexAdvisor: isIndexAdvisorEnabled, minCalls: minCalls ?? undefined, + filterIndexAdvisor: indexAdvisor === 'true', }) const isPgStatMonitorEnabled = project?.dbVersion === '17.4.1.076-psml-1' return (
- - - +

Query Performance

+
+ + + {isPgStatMonitorEnabled && ( + + h.text === REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES || + h.text === REPORT_DATERANGE_HELPER_LABELS.LAST_3_HOURS || + h.text === REPORT_DATERANGE_HELPER_LABELS.LAST_24_HOURS + )} + onSubmit={handleDatePickerChange} /> - - {isPgStatMonitorEnabled && ( - - h.text === REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES || - h.text === REPORT_DATERANGE_HELPER_LABELS.LAST_3_HOURS || - h.text === REPORT_DATERANGE_HELPER_LABELS.LAST_24_HOURS - )} - onSubmit={handleDatePickerChange} - /> - )} -
- } - /> + )} +
+
`supabase-dashboard-hotkey-sidebar-${sidebarId}`, + // Index Advisor notice dismissed + INDEX_ADVISOR_NOTICE_DISMISSED: (ref: string) => `index-advisor-notice-dismissed-${ref}`, + /** * COMMON */