Files
supabase/apps/studio/components/interfaces/QueryInsights/QueryInsightsTable/QueryInsightsDetailSheet.tsx
Ivan Vasilov 56de26fe22 chore: Migrate the monorepo to use Tailwind v4 (#45318)
This PR migrates the whole monorepo to use Tailwind v4:
- Removed `@tailwindcss/container-queries` plugin since it's included by
default in v4,
- Bump all instances of Tailwind to v4. Made minimal changes to the
shared config to remove non-supported features (`alpha` mentions),
- Migrate all apps to be compatible with v4 configs,
- Fix the `typography.css` import in 3 apps,
- Add missing rules which were included by default in v3,
- Run `pnpm dlx @tailwindcss/upgrade` on all apps, which renames a lot
of classes
- Rename all misnamed classes according to
https://tailwindcss.com/docs/upgrade-guide#renamed-utilities in all
apps.

---------

Co-authored-by: Jordi Enric <jordi.err@gmail.com>
2026-04-30 10:53:24 +00:00

163 lines
6.3 KiB
TypeScript

import { Loader2 } from 'lucide-react'
import {
AiIconAnimation,
Button,
Sheet,
SheetContent,
SheetDescription,
SheetTitle,
Tabs_Shadcn_,
TabsContent_Shadcn_,
TabsList_Shadcn_,
TabsTrigger_Shadcn_,
} from 'ui'
import { QueryDetail } from '../../QueryPerformance/QueryDetail'
import { QueryIndexes } from '../../QueryPerformance/QueryIndexes'
import { buildExplainOptimizationPrompt } from '../../QueryPerformance/QueryPerformance.ai'
import type { ClassifiedQuery } from '../QueryInsightsHealth/QueryInsightsHealth.types'
import { ExplainVisualizer } from '@/components/interfaces/ExplainVisualizer/ExplainVisualizer'
import type { QueryPlanRow } from '@/components/interfaces/ExplainVisualizer/ExplainVisualizer.types'
import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
interface QueryInsightsDetailSheetProps {
open: boolean
onOpenChange: (open: boolean) => void
activeSheetRow: ClassifiedQuery | undefined
sheetView: 'details' | 'indexes' | 'explain'
onSheetViewChange: (view: 'details' | 'indexes' | 'explain') => void
onClose: () => void
dataGridContainerRef: React.RefObject<HTMLDivElement | null>
triageContainerRef: React.RefObject<HTMLDivElement | null>
explainLoadingQuery: string | null
explainResults: Record<string, QueryPlanRow[]>
}
export const QueryInsightsDetailSheet = ({
open,
onOpenChange,
activeSheetRow,
sheetView,
onSheetViewChange,
onClose,
dataGridContainerRef,
triageContainerRef,
explainLoadingQuery,
explainResults,
}: QueryInsightsDetailSheetProps) => {
const { openSidebar } = useSidebarManagerSnapshot()
const aiSnap = useAiAssistantStateSnapshot()
return (
<Sheet open={open} onOpenChange={onOpenChange} modal={false}>
<SheetTitle className="sr-only">Query details</SheetTitle>
<SheetDescription className="sr-only">Query Insights Details &amp; Indexes</SheetDescription>
<SheetContent
side="right"
className="flex flex-col h-full bg-studio border-l lg:w-[calc(100vw-802px)]! max-w-[700px] w-full"
hasOverlay={false}
onInteractOutside={(event) => {
if (
dataGridContainerRef.current?.contains(event.target as Node) ||
triageContainerRef.current?.contains(event.target as Node)
) {
event.preventDefault()
}
}}
>
<Tabs_Shadcn_
value={sheetView}
className="flex flex-col h-full"
onValueChange={(v) => onSheetViewChange(v as 'details' | 'indexes' | 'explain')}
>
<div className="px-5 border-b">
<TabsList_Shadcn_ className="px-0 flex gap-x-4 min-h-[46px] border-b-0 [&>button]:h-[47px]">
<TabsTrigger_Shadcn_
value="details"
className="px-0 pb-0 data-[state=active]:bg-transparent shadow-none!"
>
Query details
</TabsTrigger_Shadcn_>
<TabsTrigger_Shadcn_
value="indexes"
className="px-0 pb-0 data-[state=active]:bg-transparent shadow-none!"
>
Indexes
</TabsTrigger_Shadcn_>
{activeSheetRow?.issueType !== 'error' && (
<TabsTrigger_Shadcn_
value="explain"
className="px-0 pb-0 data-[state=active]:bg-transparent shadow-none!"
>
Explain
</TabsTrigger_Shadcn_>
)}
</TabsList_Shadcn_>
</div>
<TabsContent_Shadcn_ value="details" className="mt-0 grow min-h-0 overflow-y-auto">
{activeSheetRow && (
<QueryDetail
selectedRow={activeSheetRow}
onClickViewSuggestion={() => onSheetViewChange('indexes')}
onClose={onClose}
/>
)}
</TabsContent_Shadcn_>
<TabsContent_Shadcn_ value="indexes" className="mt-0 grow min-h-0 overflow-y-auto">
{activeSheetRow && <QueryIndexes selectedRow={activeSheetRow} />}
</TabsContent_Shadcn_>
<TabsContent_Shadcn_
value="explain"
className="mt-0 grow min-h-0 flex flex-col overflow-hidden"
>
{explainLoadingQuery ? (
<div className="px-6 py-4 flex items-center gap-2 text-sm text-foreground-light">
<Loader2 size={14} className="animate-spin" /> Running EXPLAIN ANALYZE...
</div>
) : activeSheetRow && explainResults[activeSheetRow.query]?.length > 0 ? (
<>
<div className="flex items-center justify-between px-5 py-2 border-b shrink-0">
<p className="text-xs text-foreground-lighter">EXPLAIN ANALYZE output</p>
<Button
type="default"
size="tiny"
icon={<AiIconAnimation size={14} />}
onClick={() => {
const rows = explainResults[activeSheetRow.query]
const { query, prompt } = buildExplainOptimizationPrompt(
activeSheetRow.query,
rows,
{
mean_time: activeSheetRow.mean_time,
calls: activeSheetRow.calls,
total_time: activeSheetRow.total_time,
}
)
openSidebar(SIDEBAR_KEYS.AI_ASSISTANT)
aiSnap.newChat({
sqlSnippets: [{ label: 'Query', content: query }],
initialMessage: prompt,
})
}}
>
Optimize with AI
</Button>
</div>
<div className="flex-1 min-h-0 overflow-y-auto">
<ExplainVisualizer rows={explainResults[activeSheetRow.query]} />
</div>
</>
) : (
<div className="px-6 py-4 text-sm text-foreground-lighter">
No explain results available.
</div>
)}
</TabsContent_Shadcn_>
</Tabs_Shadcn_>
</SheetContent>
</Sheet>
)
}