SchemaEditor.tsx122 lines · main
1import { zodResolver } from '@hookform/resolvers/zod'
2import { useEffect } from 'react'
3import { SubmitHandler, useForm } from 'react-hook-form'
4import { toast } from 'sonner'
5import {
6 Button,
7 Dialog,
8 DialogContent,
9 DialogFooter,
10 DialogHeader,
11 DialogSection,
12 DialogSectionSeparator,
13 DialogTitle,
14 Form,
15 FormControl,
16 FormField,
17 Input,
18} from 'ui'
19import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
20import * as z from 'zod'
21
22import { useSchemaCreateMutation } from '@/data/database/schema-create-mutation'
23import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
24
25interface SchemaEditorProps {
26 visible: boolean
27 onSuccess: (schema: string) => void
28 closePanel: () => void
29}
30
31const formSchema = z.object({
32 name: z.string().min(1, 'Please provide a name for your schema'),
33})
34
35type FormSchema = z.infer<typeof formSchema>
36
37export const SchemaEditor = ({ visible, onSuccess, closePanel }: SchemaEditorProps) => {
38 const { data: project } = useSelectedProjectQuery()
39
40 const { mutateAsync: createSchema, isPending } = useSchemaCreateMutation()
41
42 const onSubmit: SubmitHandler<FormSchema> = async (values) => {
43 if (project === undefined) return console.error('Project is required')
44 try {
45 await createSchema({
46 projectRef: project.ref,
47 connectionString: project.connectionString,
48 name: values.name,
49 })
50 onSuccess(values.name)
51 toast.success(`Successfully created schema "${values.name}"`)
52 } catch (error) {
53 toast.error(`Failed to create schema: ${error}`)
54 }
55 }
56
57 const form = useForm<FormSchema>({
58 resolver: zodResolver(formSchema as any),
59 defaultValues: {
60 name: '',
61 },
62 })
63
64 const { reset } = form
65
66 useEffect(() => {
67 if (visible) {
68 reset()
69 }
70 }, [reset, visible])
71
72 const formId = 'schema-form'
73
74 return (
75 <Dialog open={visible} onOpenChange={closePanel}>
76 <DialogContent className="sm:max-w-[425px]">
77 <DialogHeader>
78 <DialogTitle>Create a new schema</DialogTitle>
79 </DialogHeader>
80 <DialogSectionSeparator />
81 <DialogSection>
82 <Form {...form}>
83 <form id={formId} onSubmit={form.handleSubmit(onSubmit)} className="grow px-0">
84 <FormField
85 control={form.control}
86 name="name"
87 render={({ field }) => (
88 <FormItemLayout layout="vertical" label="Schema name">
89 <FormControl>
90 <Input {...field} />
91 </FormControl>
92 </FormItemLayout>
93 )}
94 />
95 </form>
96 </Form>
97 </DialogSection>
98 <DialogFooter>
99 <Button
100 type="default"
101 onClick={() => {
102 form.reset()
103 closePanel()
104 }}
105 disabled={isPending}
106 >
107 Cancel
108 </Button>
109 <Button
110 type="primary"
111 form={formId}
112 htmlType="submit"
113 loading={isPending}
114 disabled={isPending}
115 >
116 Save
117 </Button>
118 </DialogFooter>
119 </DialogContent>
120 </Dialog>
121 )
122}