diff --git a/src/backends/types.ts b/src/backends/types.ts index 4a6fd260..2e05d9ed 100644 --- a/src/backends/types.ts +++ b/src/backends/types.ts @@ -117,11 +117,11 @@ export type AgentEngineSettingField = | { key: string; label: string; - // TODO: Frontend rendering for 'number' fields is not yet implemented (Story #2). - // The catalog definition is registered here; the dashboard will render it once - // numeric field support is added. type: 'number'; description?: string; + min?: number; + max?: number; + step?: number; }; export interface AgentEngineSettingsDefinition { diff --git a/web/src/components/settings/engine-settings-fields.tsx b/web/src/components/settings/engine-settings-fields.tsx index a3a4c31b..c3490a79 100644 --- a/web/src/components/settings/engine-settings-fields.tsx +++ b/web/src/components/settings/engine-settings-fields.tsx @@ -1,3 +1,4 @@ +import { Input } from '@/components/ui/input.js'; import { Label } from '@/components/ui/label.js'; import { Select, @@ -29,11 +30,11 @@ type EngineSettingField = | { key: string; label: string; - // TODO: Frontend rendering for 'number' fields is not yet implemented (Story #2). - // The field type is defined here for type compatibility with the backend catalog; - // the dashboard will render it once numeric field support is added. type: 'number'; description?: string; + min?: number; + max?: number; + step?: number; }; interface EngineDefinition { @@ -60,6 +61,79 @@ function normalizeValue( return Object.keys(value).length > 0 ? value : undefined; } +interface FieldControlProps { + field: EngineSettingField; + rawValue: unknown; + inheritLabel: string; + onUpdate: (key: string, value: unknown) => void; +} + +function FieldControl({ field, rawValue, inheritLabel, onUpdate }: FieldControlProps) { + if (field.type === 'select') { + return ( + + ); + } + + if (field.type === 'number') { + return ( + { + const trimmed = e.target.value.trim(); + if (trimmed === '') { + onUpdate(field.key, undefined); + } else { + const parsed = Number(trimmed); + if (!Number.isNaN(parsed)) { + onUpdate(field.key, parsed); + } + } + }} + /> + ); + } + + // boolean + return ( + + ); +} + export function EngineSettingsFields({ engine, value, @@ -105,59 +179,20 @@ export function EngineSettingsFields({
- {engine.settings.fields.map((field) => { - // TODO: 'number' field rendering is not yet implemented (Story #2). - if (field.type === 'number') return null; - - const rawValue = activeEngineValues[field.key]; - - return ( -
- - {field.type === 'select' ? ( - - ) : ( - - )} - {field.description && ( -

{field.description}

- )} -
- ); - })} + {engine.settings.fields.map((field) => ( +
+ + + {field.description && ( +

{field.description}

+ )} +
+ ))}
)}