| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- import { zodResolver } from '@hookform/resolvers/zod'
- import { PermissionAction } from '@supabase/shared-types/out/constants'
- import { useParams } from 'common'
- import { Plus } from 'lucide-react'
- import { useState } from 'react'
- import { useForm } from 'react-hook-form'
- import {
- Button,
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogSection,
- DialogSectionSeparator,
- DialogTitle,
- DialogTrigger,
- Form,
- FormField,
- Tooltip,
- TooltipContent,
- TooltipTrigger,
- } from 'ui'
- import { Input } from 'ui-patterns/DataInputs/Input'
- import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
- import { z } from 'zod'
- import { useProjectStorageConfigQuery } from '@/data/config/project-storage-config-query'
- import { useS3AccessKeyCreateMutation } from '@/data/storage/s3-access-key-create-mutation'
- import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
- import { useIsProjectActive } from '@/hooks/misc/useSelectedProject'
- interface CreateCredentialModalProps {
- visible: boolean
- onOpenChange: (value: boolean) => void
- }
- export const CreateCredentialModal = ({ visible, onOpenChange }: CreateCredentialModalProps) => {
- const { ref: projectRef } = useParams()
- const isProjectActive = useIsProjectActive()
- const [showSuccess, setShowSuccess] = useState(false)
- const { can: canCreateCredentials } = useAsyncCheckPermissions(
- PermissionAction.STORAGE_ADMIN_WRITE,
- '*'
- )
- const { data: config } = useProjectStorageConfigQuery({ projectRef })
- const isS3ConnectionEnabled = config?.features.s3Protocol.enabled
- const disableCreation = !isProjectActive || !canCreateCredentials || !isS3ConnectionEnabled
- const FormSchema = z.object({
- description: z.string().min(3, {
- message: 'Description must be at least 3 characters long',
- }),
- })
- const form = useForm<z.infer<typeof FormSchema>>({
- resolver: zodResolver(FormSchema as any),
- defaultValues: {
- description: '',
- },
- })
- const {
- data: createS3KeyData,
- mutate: createS3AccessKey,
- isPending: isCreating,
- } = useS3AccessKeyCreateMutation({
- onSuccess: () => {
- setShowSuccess(true)
- form.reset()
- },
- })
- async function onSubmit(data: z.infer<typeof FormSchema>) {
- createS3AccessKey({ projectRef, ...data })
- }
- return (
- <Dialog
- open={visible}
- onOpenChange={(open) => {
- onOpenChange(open)
- if (!open) setShowSuccess(false)
- }}
- >
- <Tooltip>
- <TooltipTrigger asChild>
- <DialogTrigger asChild>
- <Button
- type="default"
- icon={<Plus size={14} />}
- disabled={disableCreation}
- className="pointer-events-auto"
- >
- New access key
- </Button>
- </DialogTrigger>
- </TooltipTrigger>
- {disableCreation && (
- <TooltipContent side="bottom">
- {!isProjectActive
- ? 'Restore your project to create new access keys'
- : !isS3ConnectionEnabled
- ? 'Connection via S3 protocol is currently disabled'
- : !canCreateCredentials
- ? 'You need additional permissions to create new access keys'
- : ''}
- </TooltipContent>
- )}
- </Tooltip>
- <DialogContent
- onInteractOutside={(e) => {
- if (showSuccess) e.preventDefault()
- }}
- >
- {showSuccess ? (
- <>
- <DialogHeader>
- <DialogTitle>Save your new S3 access keys</DialogTitle>
- <DialogDescription>
- You won't be able to see them again. If you lose these access keys, you'll need to
- create a new ones.
- </DialogDescription>
- </DialogHeader>
- <DialogSectionSeparator />
- <DialogSection className="flex flex-col gap-4">
- <FormItemLayout label="Access key ID" isReactForm={false}>
- <Input className="input-mono" readOnly copy value={createS3KeyData?.access_key} />
- </FormItemLayout>
- <FormItemLayout label={'Secret access key'} isReactForm={false}>
- <Input className="input-mono" readOnly copy value={createS3KeyData?.secret_key} />
- </FormItemLayout>
- </DialogSection>
- <DialogFooter>
- <Button
- onClick={() => {
- onOpenChange(false)
- setShowSuccess(false)
- }}
- >
- Done
- </Button>
- </DialogFooter>
- </>
- ) : (
- <>
- <DialogHeader>
- <DialogTitle>Create new S3 access keys</DialogTitle>
- <DialogDescription>
- S3 access keys provide full access to all S3 operations across all buckets and
- bypass any existing RLS policies.
- </DialogDescription>
- </DialogHeader>
- <DialogSectionSeparator />
- <Form {...form}>
- <form onSubmit={form.handleSubmit(onSubmit)}>
- <DialogSection>
- <FormField
- name="description"
- render={({ field }) => (
- <FormItemLayout label="Description">
- <Input
- autoComplete="off"
- placeholder="My test key"
- type="text"
- {...field}
- />
- </FormItemLayout>
- )}
- />
- </DialogSection>
- <DialogFooter>
- <Button htmlType="submit" loading={isCreating}>
- Create access key
- </Button>
- </DialogFooter>
- </form>
- </Form>
- </>
- )}
- </DialogContent>
- </Dialog>
- )
- }
|