Skip to content

Commit ca34ade

Browse files
authored
Add model parameter type dropdown (#1473)
* implementation of the model parameter type dropdown feature * fixed bugs for indexes instead of names; changed isStatic use * Fixed prettier formatting
1 parent 445f483 commit ca34ade

File tree

1 file changed

+61
-28
lines changed

1 file changed

+61
-28
lines changed

packages/jupyter-ai/src/components/settings/model-parameters-input.tsx

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React, { useState, useEffect, useRef } from 'react';
22
import {
33
Box,
44
Button,
55
TextField,
66
Alert,
77
IconButton,
8-
Autocomplete
8+
Autocomplete,
9+
Select,
10+
MenuItem,
11+
FormControl,
12+
InputLabel
913
} from '@mui/material';
1014
import DeleteIcon from '@mui/icons-material/Delete';
1115
import Save from '@mui/icons-material/Save';
@@ -19,6 +23,15 @@ type ModelParameter = {
1923
isStatic?: boolean;
2024
};
2125

26+
const PARAMETER_TYPES = [
27+
'string',
28+
'integer',
29+
'number',
30+
'boolean',
31+
'array',
32+
'object'
33+
] as const;
34+
2235
export type ModelParametersInputProps = {
2336
modelId?: string | null;
2437
};
@@ -32,6 +45,7 @@ export function ModelParametersInput(
3245
const [validationError, setValidationError] = useState<string>('');
3346
const [isLoading, setIsLoading] = useState(false);
3447
const alert = useStackingAlert();
48+
const argumentValueRefs = useRef<Record<number, HTMLInputElement | null>>({});
3549

3650
const inferParameterType = (value: any): string => {
3751
if (typeof value === 'boolean') {
@@ -117,23 +131,36 @@ export function ModelParametersInput(
117131
};
118132

119133
const handleParameterChange = (
120-
name: string,
134+
index: number,
121135
field: keyof ModelParameter,
122136
value: string
123137
) => {
124138
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+
}
128148
: param
129149
)
130150
);
131151
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+
}
132159
};
133160

134161
// Handle parameter name selection from dropdown
135162
const handleParameterNameSelect = (
136-
currentName: string,
163+
index: number,
137164
paramName: string | null
138165
) => {
139166
if (!paramName) {
@@ -142,8 +169,8 @@ export function ModelParametersInput(
142169
const paramSchema = availableParameters?.parameters?.[paramName];
143170

144171
setParameters(prev =>
145-
prev.map(param =>
146-
param.name === currentName
172+
prev.map((param, i) =>
173+
i === index
147174
? {
148175
...param,
149176
name: paramName,
@@ -156,8 +183,8 @@ export function ModelParametersInput(
156183
setValidationError('');
157184
};
158185

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));
161188
setValidationError('');
162189
};
163190

@@ -290,7 +317,7 @@ export function ModelParametersInput(
290317
options={getParameterOptions(param.name)}
291318
value={param.name || null}
292319
onChange={(_, newValue) => {
293-
handleParameterNameSelect(param.name, newValue);
320+
handleParameterNameSelect(index, newValue);
294321
}}
295322
freeSolo
296323
size="small"
@@ -331,32 +358,38 @@ export function ModelParametersInput(
331358
}}
332359
/>
333360
)}
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>
348378
<TextField
349379
label="Argument value"
350380
placeholder="e.g. 0.7, https://localhost:8989"
351381
value={param.value}
352382
onChange={e =>
353-
handleParameterChange(param.name, 'value', e.target.value)
383+
handleParameterChange(index, 'value', e.target.value)
354384
}
355385
size="small"
356386
sx={{ flex: 1 }}
387+
inputRef={el => {
388+
argumentValueRefs.current[index] = el;
389+
}}
357390
/>
358391
<IconButton
359-
onClick={() => handleDeleteParameter(param.name)}
392+
onClick={() => handleDeleteParameter(index)}
360393
color="error"
361394
size="small"
362395
sx={{ ml: 1 }}

0 commit comments

Comments
 (0)