import { PermissionAction } from '@supabase/shared-types/out/constants' import { useRouter } from 'next/router' import { DragEvent, memo, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, } from 'react' import { ChartConfig } from 'components/interfaces/SQLEditor/UtilityPanel/ChartConfig' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import { useSelectedProject } from 'hooks/misc/useSelectedProject' import { useProfile } from 'lib/profile' import Link from 'next/link' import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state' import { Dashboards } from 'types' import { Badge, Button, cn, CodeBlock, CodeBlockLang, Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogSection, DialogTitle, DialogTrigger, } from 'ui' import { DebouncedComponent } from '../DebouncedComponent' import { EdgeFunctionBlock } from '../EdgeFunctionBlock/EdgeFunctionBlock' import { QueryBlock } from '../QueryBlock/QueryBlock' import { AssistantSnippetProps } from './AIAssistant.types' import { identifyQueryType } from './AIAssistant.utils' import { CollapsibleCodeBlock } from './CollapsibleCodeBlock' import { MessageContext } from './Message' import { defaultUrlTransform } from './Message.utils' export const OrderedList = memo(({ children }: { children: ReactNode }) => (
    {children}
)) OrderedList.displayName = 'OrderedList' export const ListItem = memo(({ children }: { children: ReactNode }) => (
  • {children}
  • )) ListItem.displayName = 'ListItem' export const Heading3 = memo(({ children }: { children: ReactNode }) => (

    {children}

    )) Heading3.displayName = 'Heading3' export const InlineCode = memo( ({ className, children }: { className?: string; children: ReactNode }) => ( {children} ) ) InlineCode.displayName = 'InlineCode' export const Hyperlink = memo(({ href, children }: { href?: string; children: ReactNode }) => { const isExternalURL = !href?.startsWith('https://supabase.com/dashboard') const safeUrl = defaultUrlTransform(href ?? '') const isSafeUrl = safeUrl.length > 0 if (!isSafeUrl) { return {children} } return ( {children} Verify the link before navigating

    This link will take you to the following URL:

    {safeUrl}

    Are you sure you want to head there?

    ) }) Hyperlink.displayName = 'Hyperlink' const MemoizedQueryBlock = memo( ({ sql, title, xAxis, yAxis, isChart, isLoading, isDraggable, runQuery, results, onRunQuery, onResults, onDragStart, onUpdateChartConfig, }: { sql: string title: string xAxis?: string yAxis?: string isChart: boolean isLoading: boolean isDraggable: boolean runQuery: boolean results?: any[] onRunQuery: (queryType: 'select' | 'mutation') => void onResults: (results: any[]) => void onDragStart: (e: DragEvent) => void onUpdateChartConfig?: ({ chart, chartConfig, }: { chart?: Partial chartConfig: Partial }) => void }) => ( Writing SQL... } > NEW

    Drag to add this chart into your custom report

    ) : undefined } showSql={!isChart} isChart={isChart} isLoading={isLoading} draggable={isDraggable} runQuery={runQuery} results={results} onRunQuery={onRunQuery} onResults={onResults} onDragStart={onDragStart} onUpdateChartConfig={onUpdateChartConfig} />
    ) ) MemoizedQueryBlock.displayName = 'MemoizedQueryBlock' export const MarkdownPre = ({ children, id, onResults, }: { children: any id: string onResults: ({ messageId, resultId, results, }: { messageId: string resultId?: string results: any[] }) => void }) => { const router = useRouter() const { profile } = useProfile() const { isLoading, readOnly } = useContext(MessageContext) const { mutate: sendEvent } = useSendEventMutation() const snap = useAiAssistantStateSnapshot() const project = useSelectedProject() const org = useSelectedOrganization() const canCreateSQLSnippet = useCheckPermissions(PermissionAction.CREATE, 'user_content', { resource: { type: 'sql', owner_id: profile?.id }, subject: { id: profile?.id }, }) // [Joshen] Using a ref as this data doesn't need to trigger a re-render const chartConfig = useRef({ view: 'table', type: 'bar', xKey: '', yKey: '', cumulative: false, }) const language = children[0].props.className?.replace('language-', '') || 'sql' const rawContent = children[0].props.children[0] const propsMatch = rawContent.match(/(?:--|\/\/)\s*props:\s*(\{[^}]+\})/) const snippetProps: AssistantSnippetProps = useMemo(() => { try { if (propsMatch) { return JSON.parse(propsMatch[1]) } } catch {} return {} }, [propsMatch]) const { xAxis, yAxis } = snippetProps const snippetId = snippetProps.id const title = snippetProps.title || (language === 'edge' ? 'Edge Function' : 'SQL Query') const isChart = snippetProps.isChart === 'true' const runQuery = snippetProps.runQuery === 'true' const results = snap.getCachedSQLResults({ messageId: id, snippetId }) // Strip props from the content for both SQL and edge functions const cleanContent = rawContent.replace(/(?:--|\/\/)\s*props:\s*\{[^}]+\}/, '').trim() const isDraggableToReports = canCreateSQLSnippet && router.pathname.endsWith('/reports/[id]') useEffect(() => { chartConfig.current = { ...chartConfig.current, view: isChart ? 'chart' : 'table', xKey: xAxis ?? '', yKey: yAxis ?? '', } // eslint-disable-next-line react-hooks/exhaustive-deps }, [snippetProps]) const onResultsReturned = useCallback( (results: any[]) => { onResults({ messageId: id, resultId: snippetProps.id, results }) }, [onResults, snippetProps.id] ) const onRunQuery = async (queryType: 'select' | 'mutation') => { sendEvent({ action: 'assistant_suggestion_run_query_clicked', properties: { queryType, ...(queryType === 'mutation' ? { category: identifyQueryType(cleanContent) ?? 'unknown' } : {}), }, groups: { project: project?.ref ?? 'Unknown', organization: org?.slug ?? 'Unknown', }, }) } return (
    {language === 'edge' ? ( ) : language === 'sql' ? ( readOnly ? ( ) : ( { chartConfig.current = { ...chartConfig.current, ...config } }} onDragStart={(e: DragEvent) => { e.dataTransfer.setData( 'application/json', JSON.stringify({ label: title, sql: cleanContent, config: chartConfig.current }) ) }} /> ) ) : ( code]:m-0 [&>code>span]:flex [&>code>span]:flex-wrap [&>code]:block [&>code>span]:text-foreground' )} /> )}
    ) }