@@ -205,39 +205,87 @@ export const DevboxCreatePage = ({
205205 currentField === "resource_size" ,
206206 ) ;
207207
208- useInput ( ( input , key ) => {
209- // Handle result screen
210- if ( result ) {
211- if ( input === "q" || key . escape || key . return ) {
212- if ( onCreate ) {
213- onCreate ( result ) ;
208+ // Main form input handler - active when not in metadata section
209+ useInput (
210+ ( input , key ) => {
211+ // Handle result screen
212+ if ( result ) {
213+ if ( input === "q" || key . escape || key . return ) {
214+ if ( onCreate ) {
215+ onCreate ( result ) ;
216+ }
217+ onBack ( ) ;
214218 }
215- onBack ( ) ;
219+ return ;
220+ }
221+
222+ // Handle error screen
223+ if ( error ) {
224+ if ( input === "r" || key . return ) {
225+ // Retry - clear error and return to form
226+ setError ( null ) ;
227+ } else if ( input === "q" || key . escape ) {
228+ // Quit - go back to list
229+ onBack ( ) ;
230+ }
231+ return ;
216232 }
217- return ;
218- }
219233
220- // Handle error screen
221- if ( error ) {
222- if ( input === "r" || key . return ) {
223- // Retry - clear error and return to form
224- setError ( null ) ;
225- } else if ( input === "q" || key . escape ) {
226- // Quit - go back to list
234+ // Handle creating state
235+ if ( creating ) {
236+ return ;
237+ }
238+
239+ // Back to list
240+ if ( input === "q" || key . escape ) {
227241 onBack ( ) ;
242+ return ;
228243 }
229- return ;
230- }
231244
232- // Handle creating state
233- if ( creating ) {
234- return ;
235- }
245+ // Submit form with Ctrl+S
246+ if ( input === "s" && key . ctrl ) {
247+ handleCreate ( ) ;
248+ return ;
249+ }
236250
237- // Handle metadata section FIRST (before general escape handler)
238- if ( inMetadataSection ) {
251+ // Enter key on metadata field to enter metadata section
252+ if ( currentField === "metadata" && key . return ) {
253+ setInMetadataSection ( true ) ;
254+ setSelectedMetadataIndex ( 0 ) ;
255+ return ;
256+ }
257+
258+ // Handle Enter on any field to submit
259+ if ( key . return ) {
260+ handleCreate ( ) ;
261+ return ;
262+ }
263+
264+ // Handle select field navigation using shared hooks
265+ if ( handleArchitectureNav ( input , key ) ) return ;
266+ if ( handleResourceSizeNav ( input , key ) ) return ;
267+
268+ // Navigation (up/down arrows and tab/shift+tab)
269+ if ( ( key . upArrow || ( key . tab && key . shift ) ) && currentFieldIndex > 0 ) {
270+ setCurrentField ( fields [ currentFieldIndex - 1 ] . key ) ;
271+ return ;
272+ }
273+
274+ if (
275+ ( key . downArrow || ( key . tab && ! key . shift ) ) &&
276+ currentFieldIndex < fields . length - 1
277+ ) {
278+ setCurrentField ( fields [ currentFieldIndex + 1 ] . key ) ;
279+ return ;
280+ }
281+ } ,
282+ { isActive : ! inMetadataSection } ,
283+ ) ;
284+
285+ // Metadata section input handler - active when in metadata section
286+ useInput (
287+ ( input , key ) => {
239288 const metadataKeys = Object . keys ( formData . metadata ) ;
240- // Selection model: 0 = "Add new", 1..n = Existing items, n+1 = "Done"
241289 const maxIndex = metadataKeys . length + 1 ;
242290
243291 // Handle input mode (typing key or value)
@@ -258,35 +306,31 @@ export const DevboxCreatePage = ({
258306 setMetadataKey ( "" ) ;
259307 setMetadataValue ( "" ) ;
260308 setMetadataInputMode ( null ) ;
261- setSelectedMetadataIndex ( 0 ) ; // Back to "add new" row
309+ setSelectedMetadataIndex ( 0 ) ;
262310 return ;
263311 } else if ( key . escape ) {
264- // Cancel input
265312 setMetadataKey ( "" ) ;
266313 setMetadataValue ( "" ) ;
267314 setMetadataInputMode ( null ) ;
268315 return ;
269316 } else if ( key . tab ) {
270- // Tab between key and value
271317 setMetadataInputMode ( metadataInputMode === "key" ? "value" : "key" ) ;
272318 return ;
273319 }
274- return ; // Don't process other keys while in input mode
320+ return ;
275321 }
276322
277- // Navigation mode
323+ // Navigation mode in metadata section
278324 if ( key . upArrow && selectedMetadataIndex > 0 ) {
279325 setSelectedMetadataIndex ( selectedMetadataIndex - 1 ) ;
280326 } else if ( key . downArrow && selectedMetadataIndex < maxIndex ) {
281327 setSelectedMetadataIndex ( selectedMetadataIndex + 1 ) ;
282328 } else if ( key . return ) {
283329 if ( selectedMetadataIndex === 0 ) {
284- // Add new
285330 setMetadataKey ( "" ) ;
286331 setMetadataValue ( "" ) ;
287332 setMetadataInputMode ( "key" ) ;
288333 } else if ( selectedMetadataIndex === maxIndex ) {
289- // Done - exit metadata section
290334 setInMetadataSection ( false ) ;
291335 setSelectedMetadataIndex ( 0 ) ;
292336 setMetadataKey ( "" ) ;
@@ -296,87 +340,37 @@ export const DevboxCreatePage = ({
296340 selectedMetadataIndex >= 1 &&
297341 selectedMetadataIndex <= metadataKeys . length
298342 ) {
299- // Edit existing (selectedMetadataIndex - 1 gives array index)
300343 const keyToEdit = metadataKeys [ selectedMetadataIndex - 1 ] ;
301344 setMetadataKey ( keyToEdit || "" ) ;
302345 setMetadataValue ( formData . metadata [ keyToEdit ] || "" ) ;
303-
304- // Remove old entry
305346 const newMetadata = { ...formData . metadata } ;
306347 delete newMetadata [ keyToEdit ] ;
307348 setFormData ( { ...formData , metadata : newMetadata } ) ;
308-
309349 setMetadataInputMode ( "key" ) ;
310350 }
311351 } else if (
312352 ( input === "d" || key . delete ) &&
313353 selectedMetadataIndex >= 1 &&
314354 selectedMetadataIndex <= metadataKeys . length
315355 ) {
316- // Delete selected item (selectedMetadataIndex - 1 gives array index)
317356 const keyToDelete = metadataKeys [ selectedMetadataIndex - 1 ] ;
318357 const newMetadata = { ...formData . metadata } ;
319358 delete newMetadata [ keyToDelete ] ;
320359 setFormData ( { ...formData , metadata : newMetadata } ) ;
321- // Stay at same position or move to add new if we deleted the last item
322360 const newLength = Object . keys ( newMetadata ) . length ;
323361 if ( selectedMetadataIndex > newLength ) {
324362 setSelectedMetadataIndex ( Math . max ( 0 , newLength ) ) ;
325363 }
326364 } else if ( key . escape || input === "q" ) {
327- // Exit metadata section
328365 setInMetadataSection ( false ) ;
329366 setSelectedMetadataIndex ( 0 ) ;
330367 setMetadataKey ( "" ) ;
331368 setMetadataValue ( "" ) ;
332369 setMetadataInputMode ( null ) ;
333370 }
334- return ;
335- }
336-
337- // Back to list (only when not in metadata section)
338- if ( input === "q" || key . escape ) {
339- onBack ( ) ;
340- return ;
341- }
342-
343- // Submit form
344- if ( input === "s" && key . ctrl ) {
345- handleCreate ( ) ;
346- return ;
347- }
348-
349- // Handle Enter on create field
350- if ( currentField === "create" && key . return ) {
351- handleCreate ( ) ;
352- return ;
353- }
354-
355- // Handle select field navigation using shared hooks
356- if ( handleArchitectureNav ( input , key ) ) return ;
357- if ( handleResourceSizeNav ( input , key ) ) return ;
358-
359- // Navigation (up/down arrows and tab/shift+tab)
360- if ( ( key . upArrow || ( key . tab && key . shift ) ) && currentFieldIndex > 0 ) {
361- setCurrentField ( fields [ currentFieldIndex - 1 ] . key ) ;
362- return ;
363- }
364-
365- if (
366- ( key . downArrow || ( key . tab && ! key . shift ) ) &&
367- currentFieldIndex < fields . length - 1
368- ) {
369- setCurrentField ( fields [ currentFieldIndex + 1 ] . key ) ;
370- return ;
371- }
372-
373- // Enter key on metadata field to enter metadata section
374- if ( currentField === "metadata" && key . return ) {
375- setInMetadataSection ( true ) ;
376- setSelectedMetadataIndex ( 0 ) ; // Start at "add new" row
377- return ;
378- }
379- } ) ;
371+ } ,
372+ { isActive : inMetadataSection } ,
373+ ) ;
380374
381375 // Validate custom resource configuration
382376 const validateCustomResources = ( ) : string | null => {
@@ -589,6 +583,7 @@ export const DevboxCreatePage = ({
589583 onChange = { ( value ) =>
590584 setFormData ( { ...formData , [ field . key ] : value } )
591585 }
586+ onSubmit = { handleCreate }
592587 isActive = { isActive }
593588 placeholder = { field . placeholder }
594589 />
0 commit comments