mirror of
https://github.com/supabase/supabase.git
synced 2026-06-16 11:58:16 +08:00
This PR disabled generating snippet titles when running and disables the "generate titles" buttons in Rename Snippet and Save Snippet dialogs (which is accessed through the side SQL Editor). How to test: 1. Disable AI for an org. 2. Try to run a new snippet, it shouldn't be renamed automatically. 3. Right click it, click Rename. The "generate title" in the dialog should be disabled with a reason in a tooltip. 4. Open the side SQL Editor, write "select 1", click Save snippet. The "generate title" in the dialog should be disabled. Testing the same flows for HIPAA projects should say `This feature is not available for HIPAA projects.` <img width="715" height="833" alt="Screenshot 2026-06-15 at 23 02 15" src="https://github.com/user-attachments/assets/f9b68f2f-5a5a-4a66-bd0d-9245f4e2f78e" /> <img width="948" height="845" alt="Screenshot 2026-06-15 at 23 02 01" src="https://github.com/user-attachments/assets/b0c9a90e-6cc1-4262-a246-88617cec41dc" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * AI feature availability is now gated by organization-level AI opt-in settings instead of subscription-based HIPAA add-ons. * **Bug Fixes** * Updated "Generate with AI" buttons to display disabled state with contextual messaging (missing API key, organization AI opt-out, HIPAA project restriction, or generation in progress). <!-- end of auto-generated comment: release notes by coderabbit.ai -->
119 lines
3.8 KiB
TypeScript
119 lines
3.8 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { toast } from 'sonner'
|
|
import {
|
|
AiIconAnimation,
|
|
Button,
|
|
Dialog,
|
|
DialogContent,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogSection,
|
|
DialogSectionSeparator,
|
|
DialogTitle,
|
|
Input,
|
|
Label,
|
|
} from 'ui'
|
|
|
|
import { generateSnippetTitle } from '@/components/interfaces/SQLEditor/SQLEditor.constants'
|
|
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
|
|
import { useCheckOpenAIKeyQuery } from '@/data/ai/check-api-key-query'
|
|
import { useSqlTitleGenerateMutation } from '@/data/ai/sql-title-mutation'
|
|
import { useOrgAiOptInLevel } from '@/hooks/misc/useOrgOptedIntoAi'
|
|
|
|
interface SaveSnippetDialogProps {
|
|
open: boolean
|
|
sql: string
|
|
onOpenChange: (open: boolean) => void
|
|
onSave: (name: string) => void
|
|
}
|
|
|
|
export const SaveSnippetDialog = ({ open, sql, onOpenChange, onSave }: SaveSnippetDialogProps) => {
|
|
const { data: check } = useCheckOpenAIKeyQuery()
|
|
|
|
const [name, setName] = useState(generateSnippetTitle())
|
|
|
|
const isApiKeySet = !!check?.hasKey
|
|
|
|
// Orgs on HIPAA plans or that have disabled AI should not have access to Supabase AI
|
|
const { aiOptInLevel, isHipaaProjectDisallowed } = useOrgAiOptInLevel()
|
|
const isAiOptedOut = aiOptInLevel === 'disabled'
|
|
|
|
const { mutate: generateTitle, isPending: isGenerating } = useSqlTitleGenerateMutation({
|
|
onSuccess: ({ title }) => setName(title),
|
|
onError: (error) => toast.error(`Failed to generate title: ${error.message}`),
|
|
})
|
|
|
|
// Reset the name each time the dialog opens
|
|
useEffect(() => {
|
|
if (open) setName(generateSnippetTitle())
|
|
}, [open])
|
|
|
|
const handleSave = () => {
|
|
const trimmed = name.trim()
|
|
if (!trimmed) return
|
|
onSave(trimmed)
|
|
onOpenChange(false)
|
|
}
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent size="small">
|
|
<DialogHeader>
|
|
<DialogTitle>Save snippet</DialogTitle>
|
|
</DialogHeader>
|
|
<DialogSectionSeparator />
|
|
<DialogSection className="flex flex-col gap-y-4 py-5">
|
|
<div className="flex flex-col gap-y-2">
|
|
<Label htmlFor="snippet-name">Name</Label>
|
|
<Input
|
|
id="snippet-name"
|
|
autoFocus
|
|
value={name}
|
|
onChange={(e) => setName(e.target.value)}
|
|
onKeyDown={(e) => {
|
|
if (e.key === 'Enter') handleSave()
|
|
}}
|
|
/>
|
|
</div>
|
|
<div className="flex justify-end">
|
|
<ButtonTooltip
|
|
type="default"
|
|
size="tiny"
|
|
disabled={isGenerating || !isApiKeySet || isHipaaProjectDisallowed || isAiOptedOut}
|
|
onClick={() => generateTitle({ sql })}
|
|
tooltip={{
|
|
content: {
|
|
side: 'bottom',
|
|
text: isHipaaProjectDisallowed
|
|
? 'This feature is not available for HIPAA projects.'
|
|
: isAiOptedOut
|
|
? 'Your organization has opted out of AI features.'
|
|
: isApiKeySet
|
|
? undefined
|
|
: 'Add your "OPENAI_API_KEY" to your environment variables to use this feature.',
|
|
},
|
|
}}
|
|
>
|
|
<div className="flex items-center gap-1">
|
|
<div className="scale-75">
|
|
<AiIconAnimation loading={isGenerating} />
|
|
</div>
|
|
<span>Generate with AI</span>
|
|
</div>
|
|
</ButtonTooltip>
|
|
</div>
|
|
</DialogSection>
|
|
<DialogSectionSeparator />
|
|
<DialogFooter className="px-5 py-4">
|
|
<Button type="default" onClick={() => onOpenChange(false)}>
|
|
Cancel
|
|
</Button>
|
|
<Button disabled={!name.trim()} onClick={handleSave}>
|
|
Save snippet
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|