Skip to content

Commit 1ca0400

Browse files
Simplify model i/o when interface defined (#676) (#677)
(cherry picked from commit 47d59fe) Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com> Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 943623d commit 1ca0400

File tree

3 files changed

+168
-238
lines changed

3 files changed

+168
-238
lines changed

public/pages/workflow_detail/workflow_inputs/input_fields/model_field.tsx

+34-32
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,15 @@ export function ModelField(props: ModelFieldProps) {
124124
labelAppend={
125125
props.modelCategory ? (
126126
<ModelInfoPopover modelCategory={props.modelCategory} />
127-
) : <EuiText size="xs">
128-
<EuiLink href={ML_CHOOSE_MODEL_LINK} target="_blank">
129-
Learn more
130-
</EuiLink>
131-
</EuiText>
127+
) : (
128+
<EuiText size="xs">
129+
<EuiLink href={ML_CHOOSE_MODEL_LINK} target="_blank">
130+
Learn more
131+
</EuiLink>
132+
</EuiText>
133+
)
132134
}
133-
helpText={props.helpText || 'The model ID.'}
135+
helpText={props.helpText}
134136
isInvalid={isInvalid}
135137
error={props.showError && getIn(errors, `${field.name}.id`)}
136138
>
@@ -142,33 +144,33 @@ export function ModelField(props: ModelFieldProps) {
142144
disabled={isEmpty(deployedModels)}
143145
options={deployedModels.map(
144146
(option) =>
145-
({
146-
value: option.id,
147-
inputDisplay: (
148-
<>
149-
<EuiText size="s">{option.name}</EuiText>
150-
</>
151-
),
152-
dropdownDisplay: (
153-
<>
154-
<EuiHealth
155-
color={
156-
isEmpty(option.interface)
157-
? 'warning'
158-
: 'success'
159-
}
160-
>
147+
({
148+
value: option.id,
149+
inputDisplay: (
150+
<>
161151
<EuiText size="s">{option.name}</EuiText>
162-
</EuiHealth>
163-
<EuiText size="xs" color="subdued">
164-
{isEmpty(option.interface)
165-
? 'Not ready - no model interface'
166-
: 'Deployed'}
167-
</EuiText>
168-
</>
169-
),
170-
disabled: false,
171-
} as EuiSuperSelectOption<string>)
152+
</>
153+
),
154+
dropdownDisplay: (
155+
<>
156+
<EuiHealth
157+
color={
158+
isEmpty(option.interface)
159+
? 'warning'
160+
: 'success'
161+
}
162+
>
163+
<EuiText size="s">{option.name}</EuiText>
164+
</EuiHealth>
165+
<EuiText size="xs" color="subdued">
166+
{isEmpty(option.interface)
167+
? 'Not ready - no model interface'
168+
: 'Deployed'}
169+
</EuiText>
170+
</>
171+
),
172+
disabled: false,
173+
} as EuiSuperSelectOption<string>)
172174
)}
173175
valueOfSelected={field.value?.id || ''}
174176
onChange={(option: string) => {

public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs/model_inputs.tsx

+82-115
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import {
3535
EMPTY_INPUT_MAP_ENTRY,
3636
WorkflowConfig,
3737
getCharacterLimitedString,
38-
ModelInputFormField,
3938
INPUT_TRANSFORM_OPTIONS,
4039
} from '../../../../../../common';
4140
import {
@@ -47,7 +46,6 @@ import { AppState, getMappings, useAppDispatch } from '../../../../../store';
4746
import {
4847
getDataSourceId,
4948
getObjsFromJSONLines,
50-
parseModelInputs,
5149
sanitizeJSONPath,
5250
} from '../../../../../utils';
5351
import { ConfigureExpressionModal, ConfigureTemplateModal } from './modals/';
@@ -108,15 +106,15 @@ export function ModelInputs(props: ModelInputsProps) {
108106
number | undefined
109107
>(undefined);
110108

111-
// on initial load of the models, update model interface states
109+
// get the model interface based on the selected ID and list of known models
112110
useEffect(() => {
113111
if (!isEmpty(models)) {
114112
const modelId = getIn(values, modelFieldPath)?.id;
115113
if (modelId) {
116114
setModelInterface(models[modelId]?.interface);
117115
}
118116
}
119-
}, [models]);
117+
}, [models, getIn(values, modelFieldPath)?.id]);
120118

121119
// persisting doc/query/index mapping fields to collect a list
122120
// of options to display in the dropdowns when configuring input / output maps
@@ -217,31 +215,6 @@ export function ModelInputs(props: ModelInputsProps) {
217215
setFieldTouched(inputMapFieldPath, true);
218216
}
219217

220-
// The options for keys can change. We update what options are available, based
221-
// on if there is a model interface found, and additionally filter out any
222-
// options that are already being used in the input map, to discourage duplicate keys.
223-
const [keyOptions, setKeyOptions] = useState<ModelInputFormField[]>([]);
224-
useEffect(() => {
225-
setKeyOptions(parseModelInputs(modelInterface));
226-
}, [modelInterface]);
227-
useEffect(() => {
228-
if (modelInterface !== undefined) {
229-
const modelInputs = parseModelInputs(modelInterface);
230-
if (getIn(values, inputMapFieldPath) !== undefined) {
231-
const existingKeys = getIn(values, inputMapFieldPath).map(
232-
(inputMapEntry: InputMapEntry) => inputMapEntry.key
233-
) as string[];
234-
setKeyOptions(
235-
modelInputs.filter(
236-
(modelInput) => !existingKeys.includes(modelInput.label)
237-
)
238-
);
239-
} else {
240-
setKeyOptions(modelInputs);
241-
}
242-
}
243-
}, [getIn(values, inputMapFieldPath), modelInterface]);
244-
245218
const valueOptions =
246219
props.context === PROCESSOR_CONTEXT.INGEST
247220
? docFields
@@ -255,37 +228,38 @@ export function ModelInputs(props: ModelInputsProps) {
255228
const populatedMap = field.value?.length !== 0;
256229
return (
257230
<>
258-
<EuiPanel>
259-
{props.context === PROCESSOR_CONTEXT.SEARCH_RESPONSE && (
260-
<>
261-
<BooleanField
262-
fieldPath={oneToOnePath}
263-
label="Merge source data"
264-
type="Switch"
265-
inverse={true}
266-
helpText="Merge multiple documents into a single document for model processing. To process only one document, turn off merge source data."
267-
/>
268-
<EuiSpacer size="s" />
269-
{oneToOneChanged && (
270-
<>
271-
<EuiCallOut
272-
size="s"
273-
color="warning"
274-
iconType={'alert'}
275-
title={
276-
<EuiText size="s">
277-
You have changed how source data will be processed.
278-
You may need to update any existing input values to
279-
reflect the updated data structure.
280-
</EuiText>
281-
}
282-
/>
283-
<EuiSpacer size="s" />
284-
</>
285-
)}
286-
</>
287-
)}
288-
{populatedMap ? (
231+
{populatedMap ? (
232+
<EuiPanel>
233+
{props.context === PROCESSOR_CONTEXT.SEARCH_RESPONSE && (
234+
<>
235+
<BooleanField
236+
fieldPath={oneToOnePath}
237+
label="Merge source data"
238+
type="Switch"
239+
inverse={true}
240+
helpText="Merge multiple documents into a single document for model processing. To process only one document, turn off merge source data."
241+
/>
242+
<EuiSpacer size="s" />
243+
{oneToOneChanged && (
244+
<>
245+
<EuiCallOut
246+
size="s"
247+
color="warning"
248+
iconType={'alert'}
249+
title={
250+
<EuiText size="s">
251+
You have changed how source data will be
252+
processed. You may need to update any existing
253+
input values to reflect the updated data
254+
structure.
255+
</EuiText>
256+
}
257+
/>
258+
<EuiSpacer size="s" />
259+
</>
260+
)}
261+
</>
262+
)}
289263
<EuiCompressedFormRow
290264
fullWidth={true}
291265
key={inputMapFieldPath}
@@ -343,20 +317,10 @@ export function ModelInputs(props: ModelInputsProps) {
343317
<EuiFlexItem>
344318
<>
345319
{/**
346-
* We determine if there is an interface based on if there are key options or not,
347-
* as the options would be derived from the underlying interface.
348-
* And if so, these values should be static.
349-
* So, we only display the static text with no mechanism to change it's value.
350-
* Note we still allow more entries, if a user wants to override / add custom
351-
* keys if there is some gaps in the model interface.
320+
* If there is a model interface, display the field name.
321+
* Otherwise, leave as a free-form text box for a user to enter manually.
352322
*/}
353-
{!isEmpty(keyOptions) &&
354-
!isEmpty(
355-
getIn(
356-
values,
357-
`${inputMapFieldPath}.${idx}.key`
358-
)
359-
) ? (
323+
{!isEmpty(modelInterface) ? (
360324
<EuiText
361325
size="s"
362326
style={{ marginTop: '4px' }}
@@ -366,13 +330,6 @@ export function ModelInputs(props: ModelInputsProps) {
366330
`${inputMapFieldPath}.${idx}.key`
367331
)}
368332
</EuiText>
369-
) : !isEmpty(keyOptions) ? (
370-
<SelectWithCustomOptions
371-
fieldPath={`${inputMapFieldPath}.${idx}.key`}
372-
options={keyOptions as any[]}
373-
placeholder={`Name`}
374-
allowCreate={true}
375-
/>
376333
) : (
377334
<TextField
378335
fullWidth={true}
@@ -628,16 +585,21 @@ export function ModelInputs(props: ModelInputsProps) {
628585
)}
629586
</>
630587
</EuiFlexItem>
631-
<EuiFlexItem grow={false}>
632-
<EuiSmallButtonIcon
633-
iconType={'trash'}
634-
color="danger"
635-
aria-label="Delete"
636-
onClick={() => {
637-
deleteMapEntry(field.value, idx);
638-
}}
639-
/>
640-
</EuiFlexItem>
588+
{/**
589+
* Only allow deleting entries if no defined model interface
590+
*/}
591+
{isEmpty(modelInterface) && (
592+
<EuiFlexItem grow={false}>
593+
<EuiSmallButtonIcon
594+
iconType={'trash'}
595+
color="danger"
596+
aria-label="Delete"
597+
onClick={() => {
598+
deleteMapEntry(field.value, idx);
599+
}}
600+
/>
601+
</EuiFlexItem>
602+
)}
641603
</>
642604
</EuiFlexGroup>
643605
</EuiFlexItem>
@@ -646,33 +608,38 @@ export function ModelInputs(props: ModelInputsProps) {
646608
);
647609
}
648610
)}
649-
<EuiFlexItem grow={false}>
650-
<div>
651-
<EuiSmallButtonEmpty
652-
style={{ marginLeft: '-8px', marginTop: '0px' }}
653-
iconType={'plusInCircle'}
654-
iconSide="left"
655-
onClick={() => {
656-
addMapEntry(field.value);
657-
}}
658-
>
659-
{`Add input`}
660-
</EuiSmallButtonEmpty>
661-
</div>
662-
</EuiFlexItem>
611+
{/**
612+
* Only allow adding entries if no defined model interface
613+
*/}
614+
{isEmpty(modelInterface) && (
615+
<EuiFlexItem grow={false}>
616+
<div>
617+
<EuiSmallButtonEmpty
618+
style={{ marginLeft: '-8px', marginTop: '0px' }}
619+
iconType={'plusInCircle'}
620+
iconSide="left"
621+
onClick={() => {
622+
addMapEntry(field.value);
623+
}}
624+
>
625+
{`Add input`}
626+
</EuiSmallButtonEmpty>
627+
</div>
628+
</EuiFlexItem>
629+
)}
663630
</EuiFlexGroup>
664631
</EuiCompressedFormRow>
665-
) : (
666-
<EuiSmallButton
667-
style={{ width: '100px' }}
668-
onClick={() => {
669-
setFieldValue(field.name, [EMPTY_INPUT_MAP_ENTRY]);
670-
}}
671-
>
672-
{'Configure'}
673-
</EuiSmallButton>
674-
)}
675-
</EuiPanel>
632+
</EuiPanel>
633+
) : (
634+
<EuiSmallButton
635+
style={{ width: '100px' }}
636+
onClick={() => {
637+
setFieldValue(field.name, [EMPTY_INPUT_MAP_ENTRY]);
638+
}}
639+
>
640+
{'Configure'}
641+
</EuiSmallButton>
642+
)}
676643
</>
677644
);
678645
}}

0 commit comments

Comments
 (0)