diff --git a/apps/docs/content/guides/auth/social-login/auth-google.mdx b/apps/docs/content/guides/auth/social-login/auth-google.mdx index 11b24c66efd89..eaa07a8ecaa4d 100644 --- a/apps/docs/content/guides/auth/social-login/auth-google.mdx +++ b/apps/docs/content/guides/auth/social-login/auth-google.mdx @@ -166,9 +166,9 @@ To use Google's pre-built signin buttons: ### Configuration [#ios-configuration] - 1. Follow the integration instructions on the [get started with Google Sign-In](https://developers.google.com/identity/sign-in/ios/start-integrating) for iOS guide. + 1. Follow the integration instructions on the [get started with Google Sign-In](https://developers.google.com/identity/sign-in/ios/start-integrating) for the iOS guide. 2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service. - 3. Add only the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_. Enable the `Skip nonce check` option. + 3. Add web client ID and iOS client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_, separated by a comma. Enable the `Skip nonce check` option. diff --git a/apps/docs/content/guides/database/connection-management.mdx b/apps/docs/content/guides/database/connection-management.mdx index 72c5df291c996..720f87700f31e 100644 --- a/apps/docs/content/guides/database/connection-management.mdx +++ b/apps/docs/content/guides/database/connection-management.mdx @@ -70,11 +70,10 @@ The usename can be used to identify the source: | Role | API/Tool | | ---------------------------- | ------------------------------------------------------------------------- | -| supabase_admin | Used by Supabase to configure projects and for monitoring | +| supabase_admin | Used by Supabase for monitoring and by Realtime | | authenticator | Data API (PostgREST) | | supabase_auth_admin | Auth | | supabase_storage_admin | Storage | -| supabase_realtime_admin | Realtime | | supabase_replication_admin | Synchronizes Read Replicas | | postgres | Supabase Dashboard and External Tools (e.g., Prisma, SQLAlchemy, PSQL...) | | Custom roles defined by user | External Tools (e.g., Prisma, SQLAlchemy, PSQL...) | diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx index e8e00f70abe56..78e1b2d1a5eed 100644 --- a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx @@ -1,8 +1,8 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { AnimatePresence, motion } from 'framer-motion' import { last } from 'lodash' -import { FileText, Info, X } from 'lucide-react' -import { memo, useEffect, useMemo, useRef, useState } from 'react' +import { FileText, Info, X, ArrowDown } from 'lucide-react' +import { memo, useEffect, useMemo, useRef, useState, useCallback } from 'react' import { toast } from 'sonner' import type { Message as MessageType } from 'ai/react' @@ -44,6 +44,7 @@ import DotGrid from '../DotGrid' import AIOnboarding from './AIOnboarding' import CollapsibleCodeBlock from './CollapsibleCodeBlock' import { Message } from './Message' +import { useAutoScroll } from './hooks' const MemoizedMessage = memo( ({ message, isLoading }: { message: MessageType; isLoading: boolean }) => { @@ -89,8 +90,7 @@ export const AIAssistant = ({ const { open, initialInput, sqlSnippets, suggestions } = aiAssistantPanel const inputRef = useRef(null) - const bottomRef = useRef(null) - const scrollContainerRef = useRef(null) + const { ref: scrollContainerRef, isSticky, scrollToEnd } = useAutoScroll() const [value, setValue] = useState(initialInput) const [assistantError, setAssistantError] = useState() @@ -229,37 +229,16 @@ export const AIAssistant = ({ ) } - const handleScroll = () => { - const container = scrollContainerRef.current - if (container) { - const scrollPercentage = - (container.scrollTop / (container.scrollHeight - container.clientHeight)) * 100 - const isScrollable = container.scrollHeight > container.clientHeight - const isAtBottom = scrollPercentage >= 100 - - setShowFade(isScrollable && !isAtBottom) - } - } - - // Add useEffect to set up scroll listener + // Update scroll behavior for new messages useEffect(() => { - // Use a small delay to ensure container is mounted and has content - const timeoutId = setTimeout(() => { - const container = scrollContainerRef.current - if (container) { - container.addEventListener('scroll', handleScroll) - handleScroll() - } - }, 100) + if (!isChatLoading) { + if (inputRef.current) inputRef.current.focus() + } - return () => { - clearTimeout(timeoutId) - const container = scrollContainerRef.current - if (container) { - container.removeEventListener('scroll', handleScroll) - } + if (isSticky) { + setTimeout(scrollToEnd, 0) } - }, []) + }, [isChatLoading, isSticky, scrollToEnd, messages]) useEffect(() => { setValue(initialInput) @@ -269,30 +248,6 @@ export const AIAssistant = ({ } }, [initialInput]) - useEffect(() => { - if (!isChatLoading) { - if (inputRef.current) inputRef.current.focus() - } - - setTimeout( - () => { - if (bottomRef.current) bottomRef.current.scrollIntoView({ behavior: 'smooth' }) - }, - isChatLoading ? 100 : 500 - ) - }, [isChatLoading]) - - useEffect(() => { - if (bottomRef.current) bottomRef.current.scrollIntoView({ behavior: 'smooth' }) - handleScroll() - // Load messages into state - if (!isChatLoading) { - setAiAssistantPanel({ - messages, - }) - } - }, [messages, isChatLoading, setAiAssistantPanel]) - // Remove suggestions if sqlSnippets were removed useEffect(() => { if (!sqlSnippets || sqlSnippets.length === 0) { @@ -310,11 +265,7 @@ export const AIAssistant = ({ return ( <>
-
+
@@ -401,7 +352,7 @@ export const AIAssistant = ({
)} -
+
) : suggestions ? (
@@ -490,16 +441,41 @@ export const AIAssistant = ({
)}
+ - {showFade && ( - -
- + {!isSticky && ( + <> + +
+ + + + + )} @@ -567,6 +543,7 @@ export const AIAssistant = ({ .join('\n') || '' const valueWithSnippets = [value, sqlSnippetsString].filter(Boolean).join('\n\n') sendMessageToAssistant(valueWithSnippets) + scrollToEnd() } else { sendMessageToAssistant(value) } diff --git a/apps/studio/components/ui/AIAssistantPanel/SqlSnippet.tsx b/apps/studio/components/ui/AIAssistantPanel/SqlSnippet.tsx index ff9f68ca87306..a948822e79ef9 100644 --- a/apps/studio/components/ui/AIAssistantPanel/SqlSnippet.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/SqlSnippet.tsx @@ -183,6 +183,9 @@ export const SqlCard = ({ : 'This query involves running a function.'}{' '} Are you sure you want to execute it?

+

+ Make sure you are not accidentally removing something important. +