CreatePublishableAPIKeyDialog.tsx142 lines · main
| 1 | import { zodResolver } from '@hookform/resolvers/zod' |
| 2 | import { Plus } from 'lucide-react' |
| 3 | import { useParams } from 'next/navigation' |
| 4 | import { parseAsString, useQueryState } from 'nuqs' |
| 5 | import { SubmitHandler, useForm } from 'react-hook-form' |
| 6 | import { |
| 7 | Button, |
| 8 | Dialog, |
| 9 | DialogContent, |
| 10 | DialogDescription, |
| 11 | DialogFooter, |
| 12 | DialogHeader, |
| 13 | DialogSection, |
| 14 | DialogSectionSeparator, |
| 15 | DialogTitle, |
| 16 | DialogTrigger, |
| 17 | Form, |
| 18 | FormControl, |
| 19 | FormField, |
| 20 | Input, |
| 21 | } from 'ui' |
| 22 | import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' |
| 23 | import * as z from 'zod' |
| 24 | |
| 25 | import { useAPIKeyCreateMutation } from '@/data/api-keys/api-key-create-mutation' |
| 26 | |
| 27 | const FORM_ID = 'create-publishable-api-key' |
| 28 | const SCHEMA = z.object({ |
| 29 | name: z.string(), |
| 30 | description: z.string().trim(), |
| 31 | }) |
| 32 | |
| 33 | export interface CreatePublishableAPIKeyDialogProps { |
| 34 | projectRef: string |
| 35 | } |
| 36 | |
| 37 | export const CreatePublishableAPIKeyDialog = () => { |
| 38 | const params = useParams() |
| 39 | const projectRef = params?.ref as string |
| 40 | |
| 41 | const [visible, setVisible] = useQueryState('new', parseAsString.withDefault('')) |
| 42 | |
| 43 | const onOpenChange = (value: boolean) => { |
| 44 | if (value) setVisible('publishable') |
| 45 | else setVisible('') |
| 46 | } |
| 47 | |
| 48 | const defaultValues = { name: '', description: '' } |
| 49 | |
| 50 | const form = useForm<z.infer<typeof SCHEMA>>({ |
| 51 | resolver: zodResolver(SCHEMA as any), |
| 52 | defaultValues: { |
| 53 | name: '', |
| 54 | description: '', |
| 55 | }, |
| 56 | }) |
| 57 | |
| 58 | const { mutate: createAPIKey, isPending: isCreatingAPIKey } = useAPIKeyCreateMutation() |
| 59 | |
| 60 | const onSubmit: SubmitHandler<z.infer<typeof SCHEMA>> = async (values) => { |
| 61 | createAPIKey( |
| 62 | { |
| 63 | projectRef, |
| 64 | type: 'publishable', |
| 65 | name: values.name, |
| 66 | description: values.description, |
| 67 | }, |
| 68 | { |
| 69 | onSuccess: () => { |
| 70 | form.reset(defaultValues) |
| 71 | onOpenChange(false) |
| 72 | }, |
| 73 | } |
| 74 | ) |
| 75 | } |
| 76 | |
| 77 | return ( |
| 78 | <Dialog open={visible === 'publishable'} onOpenChange={onOpenChange}> |
| 79 | <DialogTrigger asChild> |
| 80 | <Button type="default" icon={<Plus />}> |
| 81 | New publishable key |
| 82 | </Button> |
| 83 | </DialogTrigger> |
| 84 | <DialogContent> |
| 85 | <DialogHeader> |
| 86 | <DialogTitle>Create new publishable API key</DialogTitle> |
| 87 | <DialogDescription> |
| 88 | Publishable API keys are used to authorize requests to your project from the web, mobile |
| 89 | or desktop apps, CLIs or other public components of your application. They are safe to |
| 90 | be published online and embedded in code. |
| 91 | </DialogDescription> |
| 92 | </DialogHeader> |
| 93 | <DialogSectionSeparator /> |
| 94 | <DialogSection className="flex flex-col gap-4"> |
| 95 | <Form {...form}> |
| 96 | <form |
| 97 | className="flex flex-col gap-4" |
| 98 | id={FORM_ID} |
| 99 | onSubmit={form.handleSubmit(onSubmit)} |
| 100 | > |
| 101 | <FormField |
| 102 | key="name" |
| 103 | name="name" |
| 104 | control={form.control} |
| 105 | render={({ field }) => ( |
| 106 | <FormItemLayout |
| 107 | label="Name" |
| 108 | description="A short name of lowercase alphanumeric characters and underscore, must start with letter or underscore." |
| 109 | > |
| 110 | <FormControl> |
| 111 | <Input {...field} /> |
| 112 | </FormControl> |
| 113 | </FormItemLayout> |
| 114 | )} |
| 115 | /> |
| 116 | <FormField |
| 117 | key="description" |
| 118 | name="description" |
| 119 | control={form.control} |
| 120 | render={({ field }) => ( |
| 121 | <FormItemLayout |
| 122 | label="Description" |
| 123 | description="Provide a description about what this key is used for." |
| 124 | > |
| 125 | <FormControl> |
| 126 | <Input {...field} placeholder="(Optional)" /> |
| 127 | </FormControl> |
| 128 | </FormItemLayout> |
| 129 | )} |
| 130 | /> |
| 131 | </form> |
| 132 | </Form> |
| 133 | </DialogSection> |
| 134 | <DialogFooter> |
| 135 | <Button form={FORM_ID} htmlType="submit" loading={isCreatingAPIKey}> |
| 136 | Create Publishable API key |
| 137 | </Button> |
| 138 | </DialogFooter> |
| 139 | </DialogContent> |
| 140 | </Dialog> |
| 141 | ) |
| 142 | } |