@@ -7,85 +7,178 @@ import { FormLabel } from '@/components/ui/form/FormLabel';
77import { FormMessage } from '@/components/ui/form/FormMessage' ;
88import { Input } from '@/components/ui/input' ;
99import { Select , SelectContent , SelectItem , SelectTrigger , SelectValue } from '@/components/ui/select' ;
10- import { Plus , TrashIcon } from 'lucide-react' ;
10+ import { useEditorFileContent } from '@/features/instance/applications/context/editorFileContent' ;
11+ import { useEditorView } from '@/features/instance/applications/hooks/useEditorView' ;
12+ import { fieldNameSchema } from '@/integrations/api/instance/database/fieldNameSchema' ;
13+ import { FieldType } from '@/integrations/api/instance/database/fieldType' ;
14+ import { tableNameSchema } from '@/integrations/api/instance/database/tableNameSchema' ;
15+ import { useSetWatchedValue } from '@/lib/events/watcher' ;
16+ import { zodResolver } from '@hookform/resolvers/zod' ;
17+ import { Ban , Plus , PlusIcon , TrashIcon } from 'lucide-react' ;
18+ import { useCallback } from 'react' ;
1119import { useFieldArray , useForm } from 'react-hook-form' ;
20+ import { z } from 'zod' ;
21+
22+ const addSchema = z . object ( {
23+ tableName : tableNameSchema ,
24+ enableRest : z . boolean ( ) ,
25+ sealed : z . boolean ( ) ,
26+ replicate : z . boolean ( ) ,
27+ tableFields : z . array (
28+ z . object ( {
29+ fieldName : fieldNameSchema ,
30+ fieldType : z . enum ( FieldType ) ,
31+ primaryKey : z . boolean ( ) ,
32+ nullable : z . boolean ( ) ,
33+ indexed : z . boolean ( ) ,
34+ array : z . boolean ( ) ,
35+ } ) ,
36+ ) . min ( 1 , { error : 'Please add at least one field.' } ) ,
37+ } ) ;
1238
1339export function AddSchemaForm ( ) {
40+ const closeModal = useSetWatchedValue ( 'ShowAddSchemaModal' , false ) ;
41+ const { openedEntry, openedEntryContents } = useEditorView ( ) ;
42+ const { setContent } = useEditorFileContent ( ! ! openedEntry && ! openedEntry . package && openedEntry . path ) ;
43+
1444 const methods = useForm ( {
45+ resolver : zodResolver ( addSchema ) ,
1546 defaultValues : {
1647 tableName : '' ,
17- isRestEndpoint : 'false' ,
18- noAdditionalProperties : 'false' ,
19- tableFields : [ { fieldName : '' , fieldType : 'id' , isPrimaryKey : 'true' , isNullable : 'false' , isIndexed : 'false' } ] ,
48+ enableRest : true ,
49+ sealed : true ,
50+ replicate : true ,
51+ tableFields : [
52+ {
53+ fieldName : 'id' ,
54+ fieldType : FieldType . ID ,
55+ primaryKey : true ,
56+ nullable : true ,
57+ indexed : false ,
58+ array : false ,
59+ } ,
60+ ] ,
2061 } ,
2162 } ) ;
22- const { control } = methods ;
63+ const { control, handleSubmit , formState } = methods ;
2364
2465 const { fields, append, remove } = useFieldArray ( {
2566 name : 'tableFields' ,
2667 control,
2768 } ) ;
69+
70+ const addFieldClicked = useCallback ( ( ) => {
71+ append ( {
72+ fieldName : '' ,
73+ fieldType : FieldType . String ,
74+ primaryKey : false ,
75+ nullable : false ,
76+ indexed : false ,
77+ array : false ,
78+ } ) ;
79+ } , [ append ] ) ;
80+
81+ const submitForm = useCallback ( async ( formData : z . infer < typeof addSchema > ) => {
82+ setContent ( existingContent =>
83+ `${ existingContent || openedEntryContents || '' }
84+ type ${ formData . tableName } @table${ formData . replicate ? '' : '(replicate: false) ' } ${
85+ formData . enableRest ? ' @export' : ''
86+ } ${ formData . sealed ? ' @sealed' : '' } {${
87+ formData . tableFields . map ( tableField => `
88+ ${ tableField . fieldName } : ${ tableField . array ? '[' : '' } ${ tableField . fieldType } ${ tableField . array ? ']' : '' } ${
89+ tableField . nullable ? '' : '!'
90+ } ${ tableField . primaryKey ? ' @primaryKey' : '' } ${ tableField . indexed ? ' @indexed' : '' } `) . join ( '' )
91+ }
92+ }
93+ `
94+ ) ;
95+ closeModal ( ) ;
96+ } , [ setContent , closeModal , openedEntryContents ] ) ;
97+
2898 return (
2999 < Form { ...methods } >
30- < form >
100+ < form onSubmit = { handleSubmit ( submitForm ) } >
31101 < FormField
32102 control = { control }
33103 name = "tableName"
34104 render = { ( { field } ) => (
35105 < FormItem className = "my-4" >
36106 < FormLabel > Table Name</ FormLabel >
37107 < FormControl >
38- < Input type = "text" className = "my-1" placeholder = "Enter Table Name" { ...field } />
108+ < Input type = "text" className = "my-1" { ...field } />
39109 </ FormControl >
40110 < FormMessage />
41111 </ FormItem >
42112 ) }
43113 />
44114 < FormField
45115 control = { control }
46- name = "isRestEndpoint "
116+ name = "enableRest "
47117 render = { ( { field } ) => (
48118 < FormItem className = "flex" >
49119 < FormControl >
50- < Input type = "checkbox" className = "w-5" { ...field } />
120+ < Input
121+ type = "checkbox"
122+ className = "w-5"
123+ checked = { field . value }
124+ onChange = { ( e ) => field . onChange ( e . target . checked ) }
125+ />
51126 </ FormControl >
52- < FormLabel className = "flex-1 py-2.5" > Make available as a REST endpoint</ FormLabel >
127+ < FormLabel className = "flex-1 py-2.5" >
128+ Make available as a REST endpoint (add{ ' ' }
129+ < code className = "text-muted-foreground italic ml-1" > @export</ code > )
130+ </ FormLabel >
53131 < FormMessage />
54132 </ FormItem >
55133 ) }
56134 />
57135 < FormField
58136 control = { control }
59- name = "noAdditionalProperties "
137+ name = "replicate "
60138 render = { ( { field } ) => (
61139 < FormItem className = "flex" >
62140 < FormControl >
63- < Input type = "checkbox" className = "w-5" { ...field } />
141+ < Input
142+ type = "checkbox"
143+ className = "w-5"
144+ checked = { field . value }
145+ onChange = { ( e ) => field . onChange ( e . target . checked ) }
146+ />
64147 </ FormControl >
65- < FormLabel className = "flex-1 py-2.5" > Do not allow additional properties</ FormLabel >
148+ < FormLabel className = "flex-1 py-2.5" >
149+ Replicate this table (add
150+ < code className = "text-muted-foreground italic ml-1" > @table(replicate: { String ( field . value ) } )</ code > { ' ' }
151+ to your table)
152+ </ FormLabel >
66153 < FormMessage />
67154 </ FormItem >
68155 ) }
69156 />
70- < hr className = "my-6" />
71- < div className = "flex items-center justify-between mb-4" >
72- < h3 className = "text-lg" > Table Fields</ h3 >
73- < Button
74- variant = "positiveOutline"
75- type = "button"
76- className = "rounded-full"
77- onClick = { ( ) =>
78- append ( {
79- fieldName : '' ,
80- fieldType : 'string' ,
81- isPrimaryKey : 'false' ,
82- isNullable : 'false' ,
83- isIndexed : 'false' ,
84- } ) }
85- >
86- < Plus /> Add Field
87- </ Button >
88- </ div >
157+ < FormField
158+ control = { control }
159+ name = "sealed"
160+ render = { ( { field } ) => (
161+ < FormItem className = "flex" >
162+ < FormControl >
163+ < Input
164+ type = "checkbox"
165+ className = "w-5"
166+ checked = { field . value }
167+ onChange = { ( e ) => field . onChange ( e . target . checked ) }
168+ />
169+ </ FormControl >
170+ < FormLabel className = "flex-1 py-2.5" >
171+ Sealed (add
172+ < code className = "text-muted-foreground italic ml-1" > @sealed</ code > to ignore unspecified properties)
173+ </ FormLabel >
174+ < FormMessage />
175+ </ FormItem >
176+ ) }
177+ />
178+ < hr className = "my-6 border-gray-600" />
179+
180+ < h3 className = "text-lg" > Table Fields</ h3 >
181+
89182 { fields . map ( ( field , index ) => (
90183 < div key = { field . id } className = "p-4 my-2 border rounded-lg" >
91184 < div className = "grid grid-cols-2 gap-4" >
@@ -96,7 +189,7 @@ export function AddSchemaForm() {
96189 < FormItem >
97190 < FormLabel > Field Name</ FormLabel >
98191 < FormControl >
99- < Input type = "text" placeholder = "id" { ...field } />
192+ < Input type = "text" { ...field } />
100193 </ FormControl >
101194 < FormMessage />
102195 </ FormItem >
@@ -111,16 +204,20 @@ export function AddSchemaForm() {
111204 < FormControl >
112205 < Select { ...field } onValueChange = { field . onChange } defaultValue = { field . value } >
113206 < SelectTrigger className = "w-full" >
114- < SelectValue placeholder = "Select the Field Type" />
207+ < SelectValue />
115208 </ SelectTrigger >
116209 < SelectContent >
117- < SelectItem value = "id" > ID</ SelectItem >
118- < SelectItem value = "string" > String</ SelectItem >
119- < SelectItem value = "number" > Number</ SelectItem >
120- < SelectItem value = "boolean" > Boolean</ SelectItem >
121- < SelectItem value = "date" > Date</ SelectItem >
122- < SelectItem value = "array" > Array</ SelectItem >
123- < SelectItem value = "object" > Object</ SelectItem >
210+ < SelectItem value = "Any" > Any</ SelectItem >
211+ < SelectItem value = "BigInt" > BigInt</ SelectItem >
212+ < SelectItem value = "Blob" > Blob</ SelectItem >
213+ < SelectItem value = "Boolean" > Boolean</ SelectItem >
214+ < SelectItem value = "Bytes" > Bytes</ SelectItem >
215+ < SelectItem value = "Date" > Date</ SelectItem >
216+ < SelectItem value = "Float" > Float</ SelectItem >
217+ < SelectItem value = "ID" > ID</ SelectItem >
218+ < SelectItem value = "Int" > Int</ SelectItem >
219+ < SelectItem value = "Long" > Long</ SelectItem >
220+ < SelectItem value = "String" > String</ SelectItem >
124221 </ SelectContent >
125222 </ Select >
126223 </ FormControl >
@@ -133,11 +230,16 @@ export function AddSchemaForm() {
133230 < div className = "flex gap-x-2 md:gap-x-4" >
134231 < FormField
135232 control = { control }
136- name = { `tableFields.${ index } .isIndexed ` }
233+ name = { `tableFields.${ index } .indexed ` }
137234 render = { ( { field } ) => (
138235 < FormItem className = "inline-flex" >
139236 < FormControl >
140- < Input type = "checkbox" className = "w-5" { ...field } />
237+ < Input
238+ type = "checkbox"
239+ className = "w-5"
240+ checked = { field . value }
241+ onChange = { ( e ) => field . onChange ( e . target . checked ) }
242+ />
141243 </ FormControl >
142244 < FormLabel className = "flex-1 py-2.5" > Indexed</ FormLabel >
143245 < FormMessage />
@@ -146,11 +248,16 @@ export function AddSchemaForm() {
146248 />
147249 < FormField
148250 control = { control }
149- name = { `tableFields.${ index } .isPrimaryKey ` }
251+ name = { `tableFields.${ index } .primaryKey ` }
150252 render = { ( { field } ) => (
151253 < FormItem className = "inline-flex" >
152254 < FormControl >
153- < Input type = "checkbox" className = "w-5" { ...field } />
255+ < Input
256+ type = "checkbox"
257+ className = "w-5"
258+ checked = { field . value }
259+ onChange = { ( e ) => field . onChange ( e . target . checked ) }
260+ />
154261 </ FormControl >
155262 < FormLabel className = "flex-1 py-2.5" > Primary Key</ FormLabel >
156263 < FormMessage />
@@ -159,24 +266,70 @@ export function AddSchemaForm() {
159266 />
160267 < FormField
161268 control = { control }
162- name = { `tableFields.${ index } .isNullable ` }
269+ name = { `tableFields.${ index } .nullable ` }
163270 render = { ( { field } ) => (
164271 < FormItem className = "inline-flex" >
165272 < FormControl >
166- < Input type = "checkbox" className = "w-5" { ...field } />
273+ < Input
274+ type = "checkbox"
275+ className = "w-5"
276+ checked = { field . value }
277+ onChange = { ( e ) => field . onChange ( e . target . checked ) }
278+ />
167279 </ FormControl >
168280 < FormLabel className = "flex-1 py-2.5" > Nullable</ FormLabel >
169281 < FormMessage />
170282 </ FormItem >
171283 ) }
172284 />
285+ < FormField
286+ control = { control }
287+ name = { `tableFields.${ index } .array` }
288+ render = { ( { field } ) => (
289+ < FormItem className = "inline-flex" >
290+ < FormControl >
291+ < Input
292+ type = "checkbox"
293+ className = "w-5"
294+ checked = { field . value }
295+ onChange = { ( e ) => field . onChange ( e . target . checked ) }
296+ />
297+ </ FormControl >
298+ < FormLabel className = "flex-1 py-2.5" > Array</ FormLabel >
299+ < FormMessage />
300+ </ FormItem >
301+ ) }
302+ />
173303 </ div >
174- < Button type = "button" variant = "destructiveOutline " className = "rounded-full" onClick = { ( ) => remove ( index ) } >
304+ < Button type = "button" variant = "destructiveGhost " className = "rounded-full" onClick = { ( ) => remove ( index ) } >
175305 < TrashIcon /> Remove Field
176306 </ Button >
177307 </ div >
178308 </ div >
179309 ) ) }
310+
311+ < Button
312+ variant = "ghost"
313+ type = "button"
314+ className = "w-full"
315+ onClick = { addFieldClicked }
316+ >
317+ < Plus /> Add Another Field
318+ </ Button >
319+
320+ < div className = "flex w-full gap-4" >
321+ < Button variant = "ghost" className = "w-full rounded-full" onClick = { closeModal } >
322+ < Ban /> Cancel
323+ </ Button >
324+ < Button
325+ variant = "positive"
326+ type = "submit"
327+ className = "w-full rounded-full"
328+ disabled = { ! formState . isValid }
329+ >
330+ < PlusIcon /> Add Schema
331+ </ Button >
332+ </ div >
180333 </ form >
181334 </ Form >
182335 ) ;
0 commit comments