Files
supabase/apps/studio/components/ui/HighQueryCost.tsx
Ali Waseem 8681e4d4e9 fix: Load data button not working for high cost query tables (#44812)
## Summary

- Reset the table rows query after the user confirms loading data on a
high-cost table, so React Query re-executes the fetch without the
preflight check
- Close the confirmation dialog after the user clicks "I understand,
proceed"

**Root cause:** `preflightCheck` is intentionally excluded from the
React Query query key (to avoid duplicate cache entries). When the user
clicked "Load data", the preflight flag flipped to `false` but the query
key stayed the same — so React Query returned the cached error instead
of refetching.

## Test plan

- [x] Navigate to a table with high estimated query cost (triggers "Data
not loaded to protect database performance")
- [x] Click "Load data" → "I understand, proceed"
- [x] Verify the dialog closes and table data loads
- [x] Verify the warning does not reappear for the same table in the
same session

To test this you can run this locally with COST_THRESHOLD set to a low
value (< 10)

Fixes FE-2979

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Confirming the high-cost warning now closes the dialog and proceeds
with loading as expected.
* Improved query cache key composition so queries reflect the full set
of relevant parameters for correct caching.
* Loading from the grid error now properly clears related cached results
and proceeds when the user confirms.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-14 12:50:00 +09:00

184 lines
5.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogSection,
DialogSectionSeparator,
DialogTitle,
DialogTrigger,
Tooltip,
TooltipContent,
TooltipTrigger,
} from 'ui'
import { Admonition } from 'ui-patterns'
import { DocsButton } from './DocsButton'
import { InlineLinkClassName } from './InlineLink'
import { DOCS_URL } from '@/lib/constants'
import { ResponseError } from '@/types'
interface HighQueryCostErrorProps {
error: ResponseError
suggestions?: string[]
onSelectLoadData?: () => void
}
export const HighCostError = ({
error,
suggestions,
onSelectLoadData,
}: HighQueryCostErrorProps) => {
return (
<Admonition
type="default"
title="Data not loaded to protect database performance"
description="The query to retrieve the data was not run as it could place heavy load on the database and impact performance"
>
<div className="mt-2 flex items-center gap-x-2 items-center">
{!!onSelectLoadData && (
<LoadDataWarningDialog error={error} onSelectLoadData={onSelectLoadData} />
)}
<HighQueryCostDialog error={error} suggestions={suggestions} />
</div>
</Admonition>
)
}
const HighQueryCostDialog = ({ error, suggestions = [] }: HighQueryCostErrorProps) => {
const metadata = error.metadata
return (
<Dialog>
<DialogTrigger asChild>
<Button type="outline">Learn more</Button>
</DialogTrigger>
<DialogContent onOpenAutoFocus={(event) => event.preventDefault()}>
<DialogHeader>
<DialogTitle>Estimated query cost exceeds safety thresholds</DialogTitle>
<DialogDescription>
Preventive measure to mitigate impacting the database
</DialogDescription>
</DialogHeader>
<DialogSectionSeparator />
<DialogSection className="flex flex-col gap-y-2 text-sm">
<p>
The dashboard runs optimized SQL queries on your projects database to load data for
this interface.
</p>
<p>
However, the query was skipped as its{' '}
<Tooltip>
<TooltipTrigger className={InlineLinkClassName}>estimated cost</TooltipTrigger>
<TooltipContent side="bottom" className="flex flex-col gap-y-1">
<p>Estimated cost: {metadata?.cost.toLocaleString()}</p>
<p className="text-foreground-light">
Determined via the <code className="text-code-inline">EXPLAIN</code> command
</p>
</TooltipContent>
</Tooltip>{' '}
is high and could place significant load on the database with high disk I/O or CPU
usage.
</p>
</DialogSection>
{suggestions.length > 0 && (
<>
<DialogSectionSeparator />
<DialogSection className="flex flex-col gap-y-4 text-sm">
<p className="font-mono text-foreground-lighter uppercase tracking-tight text-sm">
Suggested steps
</p>
{suggestions.length > 0 && (
<div className="flex flex-col gap-y-1">
<p>You may check the following to lower the cost of the query</p>
<ul className="list-disc pl-6">
{suggestions.map((x) => (
<li key={x}>{x}</li>
))}
</ul>
</div>
)}
</DialogSection>
</>
)}
<DialogFooter>
<DocsButton
href={`${DOCS_URL}/guides/troubleshooting/understanding-postgresql-explain-output-Un9dqX`}
/>
<DialogClose asChild>
<Button type="default" className="opacity-100">
Understood
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
const LoadDataWarningDialog = ({
error,
onSelectLoadData,
}: {
error: ResponseError
onSelectLoadData: () => void
}) => {
const metadata = error.metadata
return (
<Dialog>
<DialogTrigger asChild>
<Button type="default">Load data</Button>
</DialogTrigger>
<DialogContent onOpenAutoFocus={(event) => event.preventDefault()}>
<DialogHeader>
<DialogTitle>Confirm to proceed loading data</DialogTitle>
<DialogDescription>
Preventive measure to mitigate impacting the database
</DialogDescription>
</DialogHeader>
<DialogSectionSeparator />
<DialogSection className="flex flex-col gap-y-2 text-sm">
<p>
The query to load your table's data was initially skipped as its{' '}
<Tooltip>
<TooltipTrigger className={InlineLinkClassName}>estimated cost</TooltipTrigger>
<TooltipContent side="bottom" className="flex flex-col gap-y-1">
<p>Estimated cost: {metadata?.cost.toLocaleString()}</p>
<p className="text-foreground-light">
Determined via the <code className="text-code-inline">EXPLAIN</code> command
</p>
</TooltipContent>
</Tooltip>{' '}
is high and could place significant load on the database with high disk I/O or CPU
usage.
</p>
<p>
You may proceed to run the query, and we'll suppress this warning for this table for the
rest of this browser session.
</p>
</DialogSection>
<DialogFooter>
<DialogClose asChild>
<Button type="default" className="opacity-100">
Cancel
</Button>
</DialogClose>
<DialogClose asChild>
<Button type="warning" onClick={() => onSelectLoadData()}>
I understand, proceed
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
)
}