import type { PostgresExtension } from '@supabase/postgres-meta' import { ExternalLinkIcon } from 'lucide-react' import { useEffect, useState } from 'react' import toast from 'react-hot-toast' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useDatabaseExtensionEnableMutation } from 'data/database-extensions/database-extension-enable-mutation' import { useSchemasQuery } from 'data/database/schemas-query' import { executeSql } from 'data/sql/execute-sql-query' import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button, Form, IconAlertTriangle, IconDatabase, IconPlus, Input, Listbox, Modal, } from 'ui' interface EnableExtensionModalProps { visible: boolean extension: PostgresExtension onCancel: () => void } const EnableExtensionModal = ({ visible, extension, onCancel }: EnableExtensionModalProps) => { const { project } = useProjectContext() const [defaultSchema, setDefaultSchema] = useState() const [fetchingSchemaInfo, setFetchingSchemaInfo] = useState(false) const { data: schemas, isLoading: isSchemasLoading } = useSchemasQuery({ projectRef: project?.ref, connectionString: project?.connectionString, }) const { mutate: enableExtension, isLoading: isEnabling } = useDatabaseExtensionEnableMutation({ onSuccess: () => { toast.success(`${extension.name} is on.`) onCancel() }, onError: (error) => { toast.error(`Failed to enable ${extension.name}: ${error.message}`) }, }) // [Joshen] Worth checking in with users - whether having this schema selection // might be confusing, and if we should have a tooltip to explain that schemas // are just concepts of namespace, you can use that extension no matter where it's // installed in useEffect(() => { let cancel = false if (visible) { const checkExtensionSchema = async () => { if (!cancel) { setFetchingSchemaInfo(true) setDefaultSchema(undefined) } try { const res = await executeSql({ projectRef: project?.ref, connectionString: project?.connectionString, sql: `select * from pg_available_extension_versions where name = '${extension.name}'`, }) if (!cancel) setDefaultSchema(res.result[0].schema) } catch (error) {} setFetchingSchemaInfo(false) } checkExtensionSchema() } return () => { cancel = true } }, [visible, extension.name]) const validate = (values: any) => { const errors: any = {} if (values.schema === 'custom' && !values.name) errors.name = 'Required field' return errors } const onSubmit = async (values: any) => { if (project === undefined) return console.error('Project is required') const schema = defaultSchema !== undefined && defaultSchema !== null ? defaultSchema : values.schema === 'custom' ? values.name : values.schema enableExtension({ projectRef: project.ref, connectionString: project?.connectionString, schema, name: extension.name, version: extension.default_version, cascade: true, createSchema: !schema.startsWith('pg_'), }) } return (
Confirm to enable
{extension.name} } >
{({ values }: any) => { return (
{fetchingSchemaInfo || isSchemasLoading ? (
) : defaultSchema ? ( ) : ( } > Create a new schema "{extension.name}" {schemas?.map((schema) => { return ( } > {schema.name} ) })} )}
{values.schema === 'custom' && ( )} {extension.name === 'pg_cron' && project?.cloud_provider === 'FLY' && ( The pg_cron extension is not fully supported for Fly projects You can still enable the extension, but pg_cron jobs may not run due to the behaviour of Fly projects. )}
) }}
) } export default EnableExtensionModal