@@ -35,7 +35,7 @@ export function CreateInstanceDialog({ open, onOpenChange }: CreateInstanceDialo
3535 const queryClient = useQueryClient ( )
3636
3737 const createMutation = useMutation ( {
38- mutationFn : ( data : { name ?: string ; config ?: string ; gowa_version ?: string } ) =>
38+ mutationFn : ( data : { name ?: string ; config ?: string ; gowa_version ?: string } ) =>
3939 apiClient . createInstance ( data ) ,
4040 onSuccess : ( ) => {
4141 queryClient . invalidateQueries ( { queryKey : [ 'instances' ] } )
@@ -61,11 +61,11 @@ export function CreateInstanceDialog({ open, onOpenChange }: CreateInstanceDialo
6161
6262 const validateForm = ( ) => {
6363 const newErrors : { name ?: string } = { }
64-
64+
6565 if ( name . trim ( ) && ( name . trim ( ) . length < 1 || name . trim ( ) . length > 100 ) ) {
6666 newErrors . name = 'Name must be between 1 and 100 characters'
6767 }
68-
68+
6969 setErrors ( newErrors )
7070 return Object . keys ( newErrors ) . length === 0
7171 }
@@ -81,156 +81,159 @@ export function CreateInstanceDialog({ open, onOpenChange }: CreateInstanceDialo
8181
8282 const handleSubmit = ( e : React . FormEvent ) => {
8383 e . preventDefault ( )
84-
84+
8585 if ( ! validateForm ( ) ) {
8686 return
8787 }
8888
8989 const data : { name ?: string ; config ?: string ; gowa_version ?: string } = { }
90-
90+
9191 if ( name . trim ( ) ) {
9292 data . name = name . trim ( )
9393 }
94-
94+
9595 data . gowa_version = version
96-
96+
9797 // Build configuration
9898 let finalConfig : InstanceConfig = {
9999 args : [ 'rest' , '--port=PORT' ] ,
100100 flags : flags
101101 }
102-
102+
103103 // Update the JSON view
104104 setJsonConfig ( JSON . stringify ( finalConfig , null , 2 ) )
105-
105+
106106 data . config = JSON . stringify ( finalConfig )
107107
108108 createMutation . mutate ( data )
109109 }
110110
111111 return (
112112 < Dialog open = { open } onOpenChange = { onOpenChange } >
113- < DialogContent className = "sm:max-w-[600px] max-h-[90vh] overflow-y-auto" >
114- < DialogHeader >
115- < DialogTitle > Create New Instance</ DialogTitle >
116- < DialogDescription >
117- Create a new application instance. A random name will be generated if none is provided.
118- </ DialogDescription >
119- </ DialogHeader >
120-
121- < form onSubmit = { handleSubmit } className = "space-y-4" >
122- < div className = "space-y-2" >
123- < label htmlFor = "name" className = "text-sm font-medium text-gray-700" >
124- Name (optional)
125- </ label >
126- < Input
127- id = "name"
128- placeholder = "Enter instance name..."
129- value = { name }
130- onChange = { ( e ) => setName ( e . target . value ) }
131- className = { errors . name ? 'border-red-500' : '' }
113+ < DialogContent className = "sm:max-w-[600px] max-h-[90vh] flex flex-col" >
114+ < div className = "overflow-y-auto flex-1" >
115+ < DialogHeader >
116+ < DialogTitle > Create New Instance</ DialogTitle >
117+ < DialogDescription >
118+ Create a new application instance. A random name will be generated if none is provided.
119+ </ DialogDescription >
120+ </ DialogHeader >
121+
122+ < form onSubmit = { handleSubmit } className = "space-y-4" id = "createForm" >
123+ < div className = "space-y-2" >
124+ < label htmlFor = "name" className = "text-sm font-medium text-gray-700" >
125+ Name (optional)
126+ </ label >
127+ < Input
128+ id = "name"
129+ placeholder = "Enter instance name..."
130+ value = { name }
131+ onChange = { ( e ) => setName ( e . target . value ) }
132+ className = { errors . name ? 'border-red-500' : '' }
133+ />
134+ { errors . name && (
135+ < p className = "text-sm text-red-600" > { errors . name } </ p >
136+ ) }
137+ </ div >
138+
139+ < VersionSelector
140+ value = { version }
141+ onChange = { setVersion }
142+ disabled = { createMutation . isPending }
132143 />
133- { errors . name && (
134- < p className = "text-sm text-red-600" > { errors . name } </ p >
135- ) }
136- </ div >
137144
138- < VersionSelector
139- value = { version }
140- onChange = { setVersion }
141- disabled = { createMutation . isPending }
142- />
143-
144- { /* Collapsible Configuration Section */ }
145- < div className = "space-y-3" >
146- < div className = "border border-gray-200 rounded-md" >
147- < Button
148- type = "button"
149- variant = "ghost"
150- size = "sm"
151- onClick = { ( ) => setShowConfiguration ( ! showConfiguration ) }
152- className = "w-full flex items-center justify-between p-3 h-auto font-medium text-gray-700 hover:bg-gray-50"
153- >
154- < div className = "flex items-center gap-2" >
155- < Settings className = "h-4 w-4" />
156- < span > Configuration</ span >
157- < span className = "text-xs bg-gray-100 px-2 py-1 rounded text-gray-500" >
158- Optional
159- </ span >
160- </ div >
161- { showConfiguration ? (
162- < ChevronUp className = "h-4 w-4" />
163- ) : (
164- < ChevronDown className = "h-4 w-4" />
165- ) }
166- </ Button >
167-
168- { showConfiguration && (
169- < div className = "border-t border-gray-200 p-4 space-y-4" >
170- < div className = "flex items-center justify-between" >
171- < span className = "text-sm text-gray-600" >
172- Advanced GOWA settings
145+ { /* Collapsible Configuration Section */ }
146+ < div className = "space-y-3" >
147+ < div className = "rounded-md border border-gray-200" >
148+ < Button
149+ type = "button"
150+ variant = "ghost"
151+ size = "sm"
152+ onClick = { ( ) => setShowConfiguration ( ! showConfiguration ) }
153+ className = "flex justify-between items-center p-3 w-full h-auto font-medium text-gray-700 hover:bg-gray-50"
154+ >
155+ < div className = "flex gap-2 items-center" >
156+ < Settings className = "w-4 h-4" />
157+ < span > Configuration</ span >
158+ < span className = "px-2 py-1 text-xs text-gray-500 bg-gray-100 rounded" >
159+ Optional
173160 </ span >
174- < Button
175- type = "button"
176- variant = "ghost"
177- size = "sm"
178- onClick = { ( ) => setShowJsonView ( ! showJsonView ) }
179- className = "flex items-center gap-1 h-7 px-2 text-xs"
180- >
181- { showJsonView ? (
182- < >
183- < EyeOff className = "h-3 w-3" />
184- Hide JSON
185- </ >
186- ) : (
187- < >
188- < Eye className = "h-3 w-3" />
189- View JSON
190- </ >
191- ) }
192- </ Button >
193161 </ div >
194-
195- { showJsonView ? (
196- < div className = "space-y-2" >
197- < div className = "flex items-center gap-2 mb-2" >
198- < Code className = "h-4 w-4 text-gray-500" />
199- < span className = "text-xs text-gray-500" > JSON Configuration (Read-only)</ span >
200- </ div >
201- < pre className = "bg-gray-50 p-3 rounded-md overflow-x-auto text-xs font-mono border border-gray-200 max-h-96" >
202- { jsonConfig }
203- </ pre >
204- < p className = "text-xs text-gray-500 mt-1" >
205- This is the raw configuration that will be saved. Use the form above to make changes.
206- </ p >
207- </ div >
162+ { showConfiguration ? (
163+ < ChevronUp className = "w-4 h-4" />
208164 ) : (
209- < div className = "max-h-96 overflow-y-auto" >
210- < CliFlagsComponent flags = { flags } onChange = { setFlags } />
211- </ div >
165+ < ChevronDown className = "w-4 h-4" />
212166 ) }
213- </ div >
214- ) }
167+ </ Button >
168+
169+ { showConfiguration && (
170+ < div className = "p-4 space-y-4 border-t border-gray-200" >
171+ < div className = "flex justify-between items-center" >
172+ < span className = "text-sm text-gray-600" >
173+ Advanced GOWA settings
174+ </ span >
175+ < Button
176+ type = "button"
177+ variant = "ghost"
178+ size = "sm"
179+ onClick = { ( ) => setShowJsonView ( ! showJsonView ) }
180+ className = "flex gap-1 items-center px-2 h-7 text-xs"
181+ >
182+ { showJsonView ? (
183+ < >
184+ < EyeOff className = "w-3 h-3" />
185+ Hide JSON
186+ </ >
187+ ) : (
188+ < >
189+ < Eye className = "w-3 h-3" />
190+ View JSON
191+ </ >
192+ ) }
193+ </ Button >
194+ </ div >
195+
196+ { showJsonView ? (
197+ < div className = "space-y-2" >
198+ < div className = "flex gap-2 items-center mb-2" >
199+ < Code className = "w-4 h-4 text-gray-500" />
200+ < span className = "text-xs text-gray-500" > JSON Configuration (Read-only)</ span >
201+ </ div >
202+ < pre className = "overflow-x-auto p-3 font-mono text-xs bg-gray-50 rounded-md border border-gray-200" >
203+ { jsonConfig }
204+ </ pre >
205+ < p className = "mt-1 text-xs text-gray-500" >
206+ This is the raw configuration that will be saved. Use the form above to make changes.
207+ </ p >
208+ </ div >
209+ ) : (
210+ < div >
211+ < CliFlagsComponent flags = { flags } onChange = { setFlags } />
212+ </ div >
213+ ) }
214+ </ div >
215+ ) }
216+ </ div >
215217 </ div >
216- </ div >
217-
218- < DialogFooter >
219- < Button type = "button" variant = "outline" onClick = { handleClose } >
220- Cancel
221- </ Button >
222- < Button
223- type = "submit"
224- disabled = { createMutation . isPending }
225- >
226- { createMutation . isPending && (
227- < Loader2 className = "h-4 w-4 mr-2 animate-spin" />
228- ) }
229- Create Instance
230- </ Button >
231- </ DialogFooter >
232- </ form >
218+
219+ </ form >
220+ </ div >
221+ < DialogFooter className = "border-t" >
222+ < Button type = "button" variant = "outline" onClick = { handleClose } >
223+ Cancel
224+ </ Button >
225+ < Button
226+ form = "createForm"
227+ type = "submit"
228+ disabled = { createMutation . isPending }
229+ >
230+ { createMutation . isPending && (
231+ < Loader2 className = "mr-2 w-4 h-4 animate-spin" />
232+ ) }
233+ Create Instance
234+ </ Button >
235+ </ DialogFooter >
233236 </ DialogContent >
234237 </ Dialog >
235238 )
236- }
239+ }
0 commit comments