import { zodResolver } from '@hookform/resolvers/zod' import { get as _get, find } from 'lodash' import { useRouter } from 'next/router' import { SubmitHandler, useForm } from 'react-hook-form' import { toast } from 'sonner' import z from 'zod' import { useParams } from 'common' import { useDatabasePoliciesQuery } from 'data/database-policies/database-policies-query' import { useDatabasePolicyDeleteMutation } from 'data/database-policies/database-policy-delete-mutation' import { useBucketDeleteMutation } from 'data/storage/bucket-delete-mutation' import { Bucket, useBucketsQuery } from 'data/storage/buckets-query' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { Button, Dialog, DialogContent, DialogFooter, DialogHeader, DialogSection, DialogSectionSeparator, DialogTitle, Form_Shadcn_, FormControl_Shadcn_, FormField_Shadcn_, Input_Shadcn_, } from 'ui' import { Admonition } from 'ui-patterns' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { formatPoliciesForStorage } from './Storage.utils' export interface DeleteBucketModalProps { visible: boolean bucket: Bucket onClose: () => void } const formId = `delete-storage-bucket-form` export const DeleteBucketModal = ({ visible, bucket, onClose }: DeleteBucketModalProps) => { const router = useRouter() const { ref: projectRef } = useParams() const { data: project } = useSelectedProjectQuery() const schema = z.object({ confirm: z.literal(bucket.name, { errorMap: () => ({ message: `Please enter "${bucket.name}" to confirm` }), }), }) const form = useForm>({ resolver: zodResolver(schema), }) const { data } = useBucketsQuery({ projectRef }) const { data: policies } = useDatabasePoliciesQuery({ projectRef: project?.ref, connectionString: project?.connectionString, schema: 'storage', }) const { mutateAsync: deletePolicy } = useDatabasePolicyDeleteMutation() const { mutate: deleteBucket, isLoading } = useBucketDeleteMutation({ onSuccess: async () => { if (!project) return console.error('Project is required') // Clean up policies from the corresponding bucket that was deleted const storageObjectsPolicies = (policies ?? []).filter((policy) => policy.table === 'objects') const formattedStorageObjectPolicies = formatPoliciesForStorage( buckets, storageObjectsPolicies ) const bucketPolicies = _get( find(formattedStorageObjectPolicies, { name: bucket.name }), ['policies'], [] ) try { await Promise.all( bucketPolicies.map((policy: any) => deletePolicy({ projectRef: project?.ref, connectionString: project?.connectionString, originalPolicy: policy, }) ) ) toast.success(`Successfully deleted bucket ${bucket.name}`) router.push(`/project/${projectRef}/storage/buckets`) onClose() } catch (error) { toast.success( `Successfully deleted bucket ${bucket.name}. However, there was a problem deleting the policies tied to the bucket. Please review them in the storage policies section` ) } }, }) const buckets = data ?? [] const onSubmit: SubmitHandler> = async () => { if (!projectRef) return console.error('Project ref is required') if (!bucket) return console.error('No bucket is selected') deleteBucket({ projectRef, id: bucket.id, type: bucket.type }) } return ( { if (!open) onClose() }} > Confirm deletion of {bucket.name}

Your bucket {bucket.name} and all its contents will be permanently deleted.

( Type {bucket.name} to confirm. } > )} />
) }