import { zodResolver } from '@hookform/resolvers/zod' import { SubmitHandler, useForm } from 'react-hook-form' import { toast } from 'sonner' import z from 'zod' import { Markdown } from 'components/interfaces/Markdown' import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query' import { useDatabaseQueueCreateMutation } from 'data/database-queues/database-queues-create-mutation' import { useQueuesExposePostgrestStatusQuery } from 'data/database-queues/database-queues-expose-postgrest-status-query' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { useConfirmOnClose, type ConfirmOnCloseModalProps } from 'hooks/ui/useConfirmOnClose' import { useRouter } from 'next/router' import { useEffect } from 'react' import { Badge, Button, Checkbox_Shadcn_, Form_Shadcn_, FormControl_Shadcn_, FormField_Shadcn_, Input, Input_Shadcn_, RadioGroupStacked, RadioGroupStackedItem, Separator, Sheet, SheetContent, SheetFooter, SheetHeader, SheetSection, SheetTitle, } from 'ui' import { Admonition } from 'ui-patterns' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { QUEUE_TYPES } from './Queues.constants' import { QueryNameSchema } from './Queues.utils' export interface CreateQueueSheetProps { visible: boolean onClose: () => void } const normalQueueSchema = z.object({ type: z.literal('basic'), }) const partitionedQueueSchema = z.object({ type: z.literal('partitioned'), partitionInterval: z.number(), retentionInterval: z.number(), }) const unloggedQueueSchema = z.object({ type: z.literal('unlogged'), }) const FormSchema = z.object({ name: QueryNameSchema, enableRls: z.boolean(), values: z.discriminatedUnion('type', [ normalQueueSchema, partitionedQueueSchema, unloggedQueueSchema, ]), }) export type CreateQueueForm = z.infer export type QueueType = CreateQueueForm['values'] const FORM_ID = 'create-queue-sidepanel' export const CreateQueueSheet = ({ visible, onClose }: CreateQueueSheetProps) => { const router = useRouter() const { data: project } = useSelectedProjectQuery() const { data: isExposed } = useQueuesExposePostgrestStatusQuery({ projectRef: project?.ref, connectionString: project?.connectionString, }) const { mutate: createQueue, isPending } = useDatabaseQueueCreateMutation() const form = useForm({ resolver: zodResolver(FormSchema), defaultValues: { name: '', enableRls: true, values: { type: 'basic' }, }, }) useEffect(() => { if (visible) { form.reset() } }, [ form, // end of stable references visible, ]) const checkIsDirty = () => form.formState.isDirty const { confirmOnClose, modalProps: closeConfirmationModalProps } = useConfirmOnClose({ checkIsDirty, onClose, }) const onSubmit: SubmitHandler = async ({ name, enableRls, values }) => { createQueue( { projectRef: project!.ref, connectionString: project?.connectionString, name, enableRls, type: values.type, configuration: values.type === 'partitioned' ? { partitionInterval: values.partitionInterval, retentionInterval: values.retentionInterval, } : undefined, }, { onSuccess: () => { toast.success(`Successfully created queue ${name}`) router.push(`/project/${project?.ref}/integrations/queues/queues/${name}`) onClose() }, } ) } const { data } = useDatabaseExtensionsQuery({ projectRef: project?.ref, connectionString: project?.connectionString, }) const pgPartmanExtension = (data ?? []).find((ext) => ext.name === 'pg_partman') const pgPartmanExtensionInstalled = pgPartmanExtension?.installed_version != undefined const queueType = form.watch('values.type') return (
Create a new queue
( Must be all lowercase letters )} /> ( {QUEUE_TYPES.map((definition) => (
{definition.icon}

{definition.label}

{definition.value === 'partitioned' && ( Coming soon )}

{definition.description}

))}
)} />
{queueType === 'partitioned' && ( <> ( ms

} />
)} /> ( ms

} />
)} />
)} (

Enable Row Level Security (RLS)

Recommended
} description="Restrict access to your queue by enabling RLS and writing Postgres policies to control access for each role." > )} /> {!isExposed ? ( ) : ( )}
) } const CloseConfirmationModal = ({ visible, onClose, onCancel }: ConfirmOnCloseModalProps) => (

There are unsaved changes. Are you sure you want to close the panel? Your changes will be lost.

)