import Link from 'next/link' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import toast from 'react-hot-toast' import { useParams } from 'common' import { StorageSizeUnits } from 'components/to-be-cleaned/Storage/StorageSettings/StorageSettings.constants' import { convertFromBytes, convertToBytes, } from 'components/to-be-cleaned/Storage/StorageSettings/StorageSettings.utils' import { useProjectStorageConfigQuery } from 'data/config/project-storage-config-query' import { useBucketCreateMutation } from 'data/storage/bucket-create-mutation' import { IS_PLATFORM } from 'lib/constants' import { Alert, Button, Collapsible, Form, IconChevronDown, Input, Listbox, Modal, Toggle, cn, } from 'ui' export interface CreateBucketModalProps { visible: boolean onClose: () => void } const CreateBucketModal = ({ visible, onClose }: CreateBucketModalProps) => { const { ref } = useParams() const router = useRouter() const { mutate: createBucket, isLoading: isCreating } = useBucketCreateMutation({ onSuccess: (res) => { toast.success(`Successfully created bucket ${res.name}`) router.push(`/project/${ref}/storage/buckets/${res.name}`) onClose() }, }) 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 initialValues = { name: '', public: false, file_size_limit: 0, allowed_mime_types: '', has_file_size_limit: false, formatted_size_limit: 0, } const validate = (values: any) => { const errors = {} as any if (!values.name) { errors.name = 'Please provide a name for your bucket' } if (values.name && values.name.endsWith(' ')) { errors.name = 'The name of the bucket cannot end with a whitespace' } if (values.has_file_size_limit && values.formatted_size_limit < 0) { errors.formatted_size_limit = 'File size upload limit has to be at least 0' } if (values.name === 'public') { errors.name = '"public" is a reserved name. Please choose another name' } return errors } const onSubmit = async (values: any) => { if (!ref) return console.error('Project ref is required') createBucket({ projectRef: ref, id: values.name, isPublic: values.public, file_size_limit: values.has_file_size_limit ? convertToBytes(values.formatted_size_limit, selectedUnit) : null, allowed_mime_types: values.allowed_mime_types.length > 0 ? values.allowed_mime_types.split(',').map((x: string) => x.trim()) : null, }) } useEffect(() => { if (visible) { setSelectedUnit(StorageSizeUnits.BYTES) setShowConfiguration(false) } }, [visible]) return ( onClose()} >
{({ values }: { values: any }) => { return (
{values.public && (

Users can read objects in public buckets without any authorization.

Row level security (RLS) policies are still required for other operations such as object uploads and deletes.

)}
setShowConfiguration(!showConfiguration)} >

Additional configuration

{values.has_file_size_limit && (
{ if (event.charCode < 48 || event.charCode > 57) { event.preventDefault() } }} descriptionText={`Equivalent to ${convertToBytes( values.formatted_size_limit, selectedUnit ).toLocaleString()} bytes.`} />
{Object.values(StorageSizeUnits).map((unit: string) => (
{unit}
))}
{IS_PLATFORM && (

Note: The{' '} global upload limit {' '} takes precedence over this value ({formattedGlobalUploadLimit})

)}
)}
) }} ) } export default CreateBucketModal