import { useParams } from 'common' import { ChevronDown } from 'lucide-react' import Link from 'next/link' import { useState } from 'react' import { toast } from 'sonner' import { type SubmitHandler, useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' import { Button, CollapsibleContent_Shadcn_, CollapsibleTrigger_Shadcn_, Collapsible_Shadcn_, Dialog, DialogContent, DialogFooter, DialogHeader, DialogSectionSeparator, DialogSection, DialogTitle, FormControl_Shadcn_, FormField_Shadcn_, Form_Shadcn_, Input_Shadcn_, SelectContent_Shadcn_, SelectItem_Shadcn_, SelectTrigger_Shadcn_, SelectValue_Shadcn_, Select_Shadcn_, Switch, cn, } from 'ui' import { StorageSizeUnits } from 'components/interfaces/Storage/StorageSettings/StorageSettings.constants' import { convertFromBytes, convertToBytes, } from 'components/interfaces/Storage/StorageSettings/StorageSettings.utils' import { InlineLink } from 'components/ui/InlineLink' import { useProjectStorageConfigQuery } from 'data/config/project-storage-config-query' import { useBucketUpdateMutation } from 'data/storage/bucket-update-mutation' import { IS_PLATFORM } from 'lib/constants' import { Admonition } from 'ui-patterns' import { Bucket } from 'data/storage/buckets-query' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { isNonNullable } from 'lib/isNonNullable' export interface EditBucketModalProps { visible: boolean bucket: Bucket onClose: () => void } const BucketSchema = z.object({ name: z.string(), public: z.boolean().default(false), has_file_size_limit: z.boolean().default(false), formatted_size_limit: z.coerce .number() .min(0, 'File size upload limit has to be at least 0') .default(0), allowed_mime_types: z.string().trim().default(''), }) const formId = 'edit-storage-bucket-form' export const EditBucketModal = ({ visible, bucket, onClose }: EditBucketModalProps) => { const { ref } = useParams() const { mutate: updateBucket, isLoading: isUpdating } = useBucketUpdateMutation() const { data } = useProjectStorageConfigQuery({ projectRef: ref }, { enabled: IS_PLATFORM }) const { value, unit } = convertFromBytes(data?.fileSizeLimit ?? 0) const formattedGlobalUploadLimit = `${value} ${unit}` const [selectedUnit, setSelectedUnit] = useState(StorageSizeUnits.BYTES) const [showConfiguration, setShowConfiguration] = useState(false) const { value: fileSizeLimit } = convertFromBytes(bucket?.file_size_limit ?? 0) const form = useForm>({ resolver: zodResolver(BucketSchema), defaultValues: { name: bucket?.name ?? '', public: bucket?.public, has_file_size_limit: isNonNullable(bucket?.file_size_limit), formatted_size_limit: fileSizeLimit ?? 0, allowed_mime_types: (bucket?.allowed_mime_types ?? []).join(', '), }, values: { name: bucket?.name ?? '', public: bucket?.public, has_file_size_limit: isNonNullable(bucket?.file_size_limit), formatted_size_limit: fileSizeLimit ?? 0, allowed_mime_types: (bucket?.allowed_mime_types ?? []).join(', '), }, mode: 'onSubmit', }) const isPublicBucket = form.watch('public') const hasFileSizeLimit = form.watch('has_file_size_limit') const formattedSizeLimit = form.watch('formatted_size_limit') const isChangingBucketVisibility = bucket?.public !== isPublicBucket const isMakingBucketPrivate = bucket?.public && !isPublicBucket const isMakingBucketPublic = !bucket?.public && isPublicBucket const onSubmit: SubmitHandler> = async (values) => { if (bucket === undefined) return console.error('Bucket is required') if (ref === undefined) return console.error('Project ref is required') updateBucket( { projectRef: ref, id: bucket.id, isPublic: values.public, file_size_limit: values.has_file_size_limit ? convertToBytes(values.formatted_size_limit, selectedUnit as StorageSizeUnits) : null, allowed_mime_types: values.allowed_mime_types.length > 0 ? values.allowed_mime_types.split(',').map((x: string) => x.trim()) : null, }, { onSuccess: () => { toast.success(`Successfully updated bucket "${bucket?.name}"`) onClose() }, } ) } return ( { if (!open) { form.reset() onClose() } }} > {`Edit bucket "${bucket?.name}"`}
( )} /> ( )} /> {isChangingBucketVisibility && ( {isMakingBucketPublic ? (

`This will make all objects in your bucket publicly accessible.`

) : isMakingBucketPrivate ? (

`All objects in your bucket will be private and only accessible via signed URLs, or downloaded with the right authorisation headers.`

) : null} {isMakingBucketPrivate && (

{ 'Assets cached in the CDN may still be publicly accessible. You can consider ' } purging the cache {' or moving your assets to a new bucket.'}

)} } /> )} setShowConfiguration(!showConfiguration)} >
( )} /> {hasFileSizeLimit && (
( )} />
<>{selectedUnit} {Object.values(StorageSizeUnits).map((unit: string) => (
{unit}
))}
{IS_PLATFORM && (

Note: Individual bucket upload will still be capped at the{' '} global upload limit {' '} of {formattedGlobalUploadLimit}

)}
)}
( )} />
) } export default EditBucketModal