1
- import React , { useState , useEffect } from 'react' ;
1
+ import React , { useState , useEffect , useRef } from 'react' ;
2
2
import {
3
3
Box ,
4
4
Button ,
5
5
TextField ,
6
6
Alert ,
7
7
IconButton ,
8
- Autocomplete
8
+ Autocomplete ,
9
+ Select ,
10
+ MenuItem ,
11
+ FormControl ,
12
+ InputLabel
9
13
} from '@mui/material' ;
10
14
import DeleteIcon from '@mui/icons-material/Delete' ;
11
15
import Save from '@mui/icons-material/Save' ;
@@ -19,6 +23,15 @@ type ModelParameter = {
19
23
isStatic ?: boolean ;
20
24
} ;
21
25
26
+ const PARAMETER_TYPES = [
27
+ 'string' ,
28
+ 'integer' ,
29
+ 'number' ,
30
+ 'boolean' ,
31
+ 'array' ,
32
+ 'object'
33
+ ] as const ;
34
+
22
35
export type ModelParametersInputProps = {
23
36
modelId ?: string | null ;
24
37
} ;
@@ -32,6 +45,7 @@ export function ModelParametersInput(
32
45
const [ validationError , setValidationError ] = useState < string > ( '' ) ;
33
46
const [ isLoading , setIsLoading ] = useState ( false ) ;
34
47
const alert = useStackingAlert ( ) ;
48
+ const argumentValueRefs = useRef < Record < number , HTMLInputElement | null > > ( { } ) ;
35
49
36
50
const inferParameterType = ( value : any ) : string => {
37
51
if ( typeof value === 'boolean' ) {
@@ -117,23 +131,36 @@ export function ModelParametersInput(
117
131
} ;
118
132
119
133
const handleParameterChange = (
120
- name : string ,
134
+ index : number ,
121
135
field : keyof ModelParameter ,
122
136
value : string
123
137
) => {
124
138
setParameters ( prev =>
125
- prev . map ( param =>
126
- param . name === name
127
- ? { ...param , [ field ] : value , isStatic : false }
139
+ prev . map ( ( param , i ) =>
140
+ i === index
141
+ ? {
142
+ ...param ,
143
+ [ field ] : value ,
144
+ // Only mark as non-static if it wasn't already static
145
+ isStatic :
146
+ param . isStatic && field !== 'value' ? param . isStatic : false
147
+ }
128
148
: param
129
149
)
130
150
) ;
131
151
setValidationError ( '' ) ;
152
+
153
+ // Auto-focus on the argument value input when type is selected
154
+ if ( field === 'type' && value ) {
155
+ setTimeout ( ( ) => {
156
+ argumentValueRefs . current [ index ] ?. focus ( ) ;
157
+ } , 0 ) ;
158
+ }
132
159
} ;
133
160
134
161
// Handle parameter name selection from dropdown
135
162
const handleParameterNameSelect = (
136
- currentName : string ,
163
+ index : number ,
137
164
paramName : string | null
138
165
) => {
139
166
if ( ! paramName ) {
@@ -142,8 +169,8 @@ export function ModelParametersInput(
142
169
const paramSchema = availableParameters ?. parameters ?. [ paramName ] ;
143
170
144
171
setParameters ( prev =>
145
- prev . map ( param =>
146
- param . name === currentName
172
+ prev . map ( ( param , i ) =>
173
+ i === index
147
174
? {
148
175
...param ,
149
176
name : paramName ,
@@ -156,8 +183,8 @@ export function ModelParametersInput(
156
183
setValidationError ( '' ) ;
157
184
} ;
158
185
159
- const handleDeleteParameter = ( name : string ) => {
160
- setParameters ( prev => prev . filter ( param => param . name !== name ) ) ;
186
+ const handleDeleteParameter = ( index : number ) => {
187
+ setParameters ( prev => prev . filter ( ( _ , i ) => i !== index ) ) ;
161
188
setValidationError ( '' ) ;
162
189
} ;
163
190
@@ -290,7 +317,7 @@ export function ModelParametersInput(
290
317
options = { getParameterOptions ( param . name ) }
291
318
value = { param . name || null }
292
319
onChange = { ( _ , newValue ) => {
293
- handleParameterNameSelect ( param . name , newValue ) ;
320
+ handleParameterNameSelect ( index , newValue ) ;
294
321
} }
295
322
freeSolo
296
323
size = "small"
@@ -331,32 +358,38 @@ export function ModelParametersInput(
331
358
} }
332
359
/>
333
360
) }
334
- < TextField
335
- label = "Parameter type"
336
- placeholder = "e.g. float, string"
337
- value = { param . type }
338
- onChange = { e =>
339
- handleParameterChange ( param . name , 'type' , e . target . value )
340
- }
341
- size = "small"
342
- sx = { { flex : 1 } }
343
- disabled = { param . isStatic }
344
- InputProps = { {
345
- readOnly : param . isStatic
346
- } }
347
- />
361
+ < FormControl size = "small" sx = { { flex : 1 } } disabled = { param . isStatic } >
362
+ < InputLabel > Parameter type</ InputLabel >
363
+ < Select
364
+ value = { param . type }
365
+ label = "Parameter type"
366
+ onChange = { e =>
367
+ handleParameterChange ( index , 'type' , e . target . value )
368
+ }
369
+ disabled = { param . isStatic }
370
+ >
371
+ { PARAMETER_TYPES . map ( type => (
372
+ < MenuItem key = { type } value = { type } >
373
+ { type }
374
+ </ MenuItem >
375
+ ) ) }
376
+ </ Select >
377
+ </ FormControl >
348
378
< TextField
349
379
label = "Argument value"
350
380
placeholder = "e.g. 0.7, https://localhost:8989"
351
381
value = { param . value }
352
382
onChange = { e =>
353
- handleParameterChange ( param . name , 'value' , e . target . value )
383
+ handleParameterChange ( index , 'value' , e . target . value )
354
384
}
355
385
size = "small"
356
386
sx = { { flex : 1 } }
387
+ inputRef = { el => {
388
+ argumentValueRefs . current [ index ] = el ;
389
+ } }
357
390
/>
358
391
< IconButton
359
- onClick = { ( ) => handleDeleteParameter ( param . name ) }
392
+ onClick = { ( ) => handleDeleteParameter ( index ) }
360
393
color = "error"
361
394
size = "small"
362
395
sx = { { ml : 1 } }
0 commit comments