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 { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' 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 { Badge, Button, Checkbox_Shadcn_, Form_Shadcn_, FormControl_Shadcn_, FormField_Shadcn_, Input, Input_Shadcn_, RadioGroupStacked, RadioGroupStackedItem, Separator, 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 { useRouter } from 'next/router' export interface CreateQueueSheetProps { isClosing: boolean setIsClosing: (v: boolean) => void 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: z .string() .trim() .min(1, 'Please provide a name for your queue') .max(47, "The name can't be longer than 47 characters") .regex(/^[a-z_-]+$/, 'Name must contain only lowercase letters, hyphens, and underscores'), 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 = ({ isClosing, setIsClosing, onClose }: CreateQueueSheetProps) => { // This is for enabling pg_partman extension which will be used for partitioned queues (3rd kind of queue) // const [showEnableExtensionModal, setShowEnableExtensionModal] = useState(false) // const canToggleExtensions = useCheckPermissions( // PermissionAction.TENANT_SQL_ADMIN_WRITE, // 'extensions' // ) const router = useRouter() const { project } = useProjectContext() const { data: isExposed } = useQueuesExposePostgrestStatusQuery({ projectRef: project?.ref, connectionString: project?.connectionString, }) const { mutate: createQueue, isLoading } = useDatabaseQueueCreateMutation() const form = useForm({ resolver: zodResolver(FormSchema), defaultValues: { name: '', enableRls: true, values: { type: 'basic' }, }, }) const isEdited = form.formState.isDirty // if the form hasn't been touched and the user clicked esc or the backdrop, close the sheet if (!isEdited && isClosing) onClose() const onClosePanel = () => { if (isEdited) { setIsClosing(true) } else { 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}

{/* {!pgPartmanExtensionInstalled && definition.value === 'partitioned' ? (
pg_partman needs to be installed to use this type
) : null} */}
))}
)} /> {/* {!pgPartmanExtensionInstalled && ( Enable pg_partman for partitioned queues } description={
This will allow you to create partitioned queues which can handle a large amount of messages setShowEnableExtensionModal(true)} tooltip={{ content: { side: 'bottom', text: 'You need additional permissions to enable database extensions', }, }} > Install pg_partman extension
} /> )} */}
{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 ? ( ) : ( )}
setIsClosing(false)} onConfirm={() => onClose()} >

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

{/* {pgPartmanExtension && ( setShowEnableExtensionModal(false)} /> )} */} ) }