diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx index 8a438a3a5f9..6e23b04cec5 100644 --- a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx @@ -47,18 +47,20 @@ import AIOnboarding from './AIOnboarding' import CollapsibleCodeBlock from './CollapsibleCodeBlock' import { Message } from './Message' -const MemoizedMessage = memo(({ message }: { message: MessageType }) => { - return ( - - ) -}) +const MemoizedMessage = memo( + ({ message, isLoading }: { message: MessageType; isLoading: boolean }) => { + return ( + + ) + } +) MemoizedMessage.displayName = 'MemoizedMessage' @@ -133,8 +135,6 @@ export const AIAssistant = ({ id, className, onResetConversation }: AIAssistantP const canUpdateOrganization = useCheckPermissions(PermissionAction.UPDATE, 'organizations') const { mutate: updateOrganization, isLoading: isUpdating } = useOrganizationUpdateMutation() - const isLoading = isChatLoading - const messages = useMemo(() => { const merged = [ ...chatMessages, @@ -151,9 +151,9 @@ export const AIAssistant = ({ id, className, onResetConversation }: AIAssistantP const renderedMessages = useMemo( () => messages.map((message) => { - return + return }), - [messages] + [messages, isChatLoading] ) const hasMessages = messages.length > 0 @@ -237,7 +237,7 @@ export const AIAssistant = ({ id, className, onResetConversation }: AIAssistantP }, [initialInput]) useEffect(() => { - if (!isLoading) { + if (!isChatLoading) { if (inputRef.current) inputRef.current.focus() } @@ -245,9 +245,9 @@ export const AIAssistant = ({ id, className, onResetConversation }: AIAssistantP () => { if (bottomRef.current) bottomRef.current.scrollIntoView({ behavior: 'smooth' }) }, - isLoading ? 100 : 500 + isChatLoading ? 100 : 500 ) - }, [isLoading]) + }, [isChatLoading]) useEffect(() => { if (bottomRef.current) bottomRef.current.scrollIntoView({ behavior: 'smooth' }) @@ -278,7 +278,7 @@ export const AIAssistant = ({ id, className, onResetConversation }: AIAssistantP
{hasMessages ? 'New chat' : 'Assistant'}
{(hasMessages || suggestions || sqlSnippets) && ( - )} @@ -516,8 +516,8 @@ export const AIAssistant = ({ id, className, onResetConversation }: AIAssistantP className={cn( 'z-20 [&>textarea]:border-1 [&>textarea]:rounded-md [&>textarea]:!outline-none [&>textarea]:!ring-offset-0 [&>textarea]:!ring-0' )} - loading={isLoading} - disabled={!isApiKeySet || disablePrompts || isLoading} + loading={isChatLoading} + disabled={!isApiKeySet || disablePrompts || isChatLoading} placeholder={ hasMessages ? 'Reply to the assistant...' diff --git a/apps/studio/components/ui/AIAssistantPanel/Message.tsx b/apps/studio/components/ui/AIAssistantPanel/Message.tsx index 025779a86b3..21cdf3f085d 100644 --- a/apps/studio/components/ui/AIAssistantPanel/Message.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/Message.tsx @@ -8,25 +8,21 @@ import CollapsibleCodeBlock from './CollapsibleCodeBlock' import { SqlSnippet } from './SqlSnippet' interface MessageProps { - name?: string + id: string role: 'function' | 'system' | 'user' | 'assistant' | 'data' | 'tool' content?: string - createdAt?: number - isSelected?: boolean - isLoading?: boolean + isLoading: boolean readOnly?: boolean action?: React.ReactNode variant?: 'default' | 'warning' } export const Message = function Message({ - name, + id, role, content, - createdAt, isLoading, readOnly, - isSelected = false, children, action = null, variant = 'default', @@ -70,6 +66,7 @@ export const Message = function Message({
) : ( { +const SqlSnippetWrapper = ({ id, sql, isLoading, readOnly = false }: SqlSnippetWrapperProps) => { const formatted = (sql || [''])[0] const propsMatch = formatted.match(/--\s*props:\s*(\{[^}]+\})/) const props = propsMatch ? JSON.parse(propsMatch[1]) : {} @@ -50,24 +43,39 @@ const SqlSnippetWrapper = ({ sql, readOnly = false }: SqlSnippetWrapperProps) => return (
) } +interface ParsedSqlProps { + id: string + sql: string + title: string + isLoading: boolean + readOnly?: boolean + isChart: boolean + xAxis: string + yAxis: string +} + export const SqlCard = ({ + id, sql, isChart, xAxis, yAxis, title, readOnly = false, + isLoading, }: ParsedSqlProps) => { const router = useRouter() const project = useSelectedProject() @@ -76,6 +84,7 @@ export const SqlCard = ({ const isInSQLEditor = router.pathname.includes('/sql') const isInNewSnippet = router.pathname.endsWith('/sql') + const [showCode, setShowCode] = useState(readOnly || !isReadOnlySelect(sql)) const [showResults, setShowResults] = useState(false) const [results, setResults] = useState() @@ -84,7 +93,6 @@ export const SqlCard = ({ const { mutate: executeSql, isLoading: isExecuting } = useExecuteSqlMutation({ onSuccess: (res) => { - console.log('SQL executed successfully:', res) setShowResults(true) setResults(res.result) setShowWarning(false) @@ -118,13 +126,6 @@ export const SqlCard = ({ }) }, [project?.ref, project?.connectionString, sql, executeSql, readOnly]) - useEffect(() => { - if (isReadOnlySelect(sql) && !results && !readOnly) { - handleExecute() - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [sql, handleExecute, readOnly]) - const handleEditInSQLEditor = () => { if (isInSQLEditor) { snapV2.setDiffContent(sql, DiffType.Addition) @@ -136,6 +137,13 @@ export const SqlCard = ({ const [errorHeader, ...errorContent] = (error?.formattedError?.split('\n') ?? [])?.filter((x: string) => x.length > 0) ?? [] + useEffect(() => { + if (isReadOnlySelect(sql) && !results && !readOnly && !isLoading) { + handleExecute() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [sql, readOnly, isLoading]) + return (