@@ -16,6 +16,8 @@ import {
16
16
EuiModalFooter ,
17
17
EuiModalHeader ,
18
18
EuiModalHeaderTitle ,
19
+ EuiSelect ,
20
+ EuiSelectOption ,
19
21
EuiSpacer ,
20
22
EuiText ,
21
23
} from '@elastic/eui' ;
@@ -25,6 +27,7 @@ import {
25
27
IngestPipelineConfig ,
26
28
JSONPATH_ROOT_SELECTOR ,
27
29
ML_INFERENCE_DOCS_LINK ,
30
+ MapArrayFormValue ,
28
31
PROCESSOR_CONTEXT ,
29
32
SimulateIngestPipelineResponse ,
30
33
WorkflowConfig ,
@@ -38,7 +41,7 @@ import {
38
41
} from '../../../../utils' ;
39
42
import { simulatePipeline , useAppDispatch } from '../../../../store' ;
40
43
import { getCore } from '../../../../services' ;
41
- import { MapField } from '../input_fields' ;
44
+ import { MapArrayField } from '../input_fields' ;
42
45
43
46
interface InputTransformModalProps {
44
47
uiConfig : WorkflowConfig ;
@@ -50,6 +53,10 @@ interface InputTransformModalProps {
50
53
onFormChange : ( ) => void ;
51
54
}
52
55
56
+ // TODO: InputTransformModal and OutputTransformModal are very similar, and can
57
+ // likely be refactored and have more reusable components. Leave as-is until the
58
+ // UI is more finalized.
59
+
53
60
/**
54
61
* A modal to configure advanced JSON-to-JSON transforms into a model's expected input
55
62
*/
@@ -59,10 +66,19 @@ export function InputTransformModal(props: InputTransformModalProps) {
59
66
60
67
// source input / transformed output state
61
68
const [ sourceInput , setSourceInput ] = useState < string > ( '[]' ) ;
62
- const [ transformedOutput , setTransformedOutput ] = useState < string > ( '[] ' ) ;
69
+ const [ transformedOutput , setTransformedOutput ] = useState < string > ( '{} ' ) ;
63
70
64
71
// get the current input map
65
- const map = getIn ( values , `ingest.enrich.${ props . config . id } .inputMap` ) ;
72
+ const map = getIn ( values , props . inputMapFieldPath ) as MapArrayFormValue ;
73
+
74
+ // selected output state
75
+ const outputOptions = map . map ( ( _ , idx ) => ( {
76
+ value : idx ,
77
+ text : `Prediction ${ idx + 1 } ` ,
78
+ } ) ) as EuiSelectOption [ ] ;
79
+ const [ selectedOutputOption , setSelectedOutputOption ] = useState <
80
+ number | undefined
81
+ > ( ( outputOptions [ 0 ] ?. value as number ) ?? undefined ) ;
66
82
67
83
return (
68
84
< EuiModal onClose = { props . onClose } style = { { width : '70vw' } } >
@@ -149,34 +165,62 @@ export function InputTransformModal(props: InputTransformModalProps) {
149
165
root object selector "${ JSONPATH_ROOT_SELECTOR } "` }
150
166
</ EuiText >
151
167
< EuiSpacer size = "s" />
152
- < MapField
168
+ < MapArrayField
153
169
field = { props . inputMapField }
154
170
fieldPath = { props . inputMapFieldPath }
155
- label = "Input map "
171
+ label = "Input Map "
156
172
helpText = { `An array specifying how to map fields from the ingested document to the model’s input.` }
157
173
helpLink = { ML_INFERENCE_DOCS_LINK }
158
174
keyPlaceholder = "Model input field"
159
175
valuePlaceholder = "Document field"
160
176
onFormChange = { props . onFormChange }
177
+ // If the map we are adding is the first one, populate the selected option to index 0
178
+ onMapAdd = { ( curArray ) => {
179
+ if ( isEmpty ( curArray ) ) {
180
+ setSelectedOutputOption ( 0 ) ;
181
+ }
182
+ } }
183
+ // If the map we are deleting is the one we last used to test, reset the state and
184
+ // default to the first map in the list.
185
+ onMapDelete = { ( idxToDelete ) => {
186
+ if ( selectedOutputOption === idxToDelete ) {
187
+ setSelectedOutputOption ( 0 ) ;
188
+ setTransformedOutput ( '{}' ) ;
189
+ }
190
+ } }
161
191
/>
162
192
</ >
163
193
</ EuiFlexItem >
164
194
< EuiFlexItem >
165
195
< >
166
- < EuiText > Expected output</ EuiText >
196
+ < EuiSelect
197
+ prepend = { < EuiText > Expected output for</ EuiText > }
198
+ compressed = { true }
199
+ options = { outputOptions }
200
+ value = { selectedOutputOption }
201
+ onChange = { ( e ) => {
202
+ setSelectedOutputOption ( Number ( e . target . value ) ) ;
203
+ setTransformedOutput ( '{}' ) ;
204
+ } }
205
+ />
206
+ < EuiSpacer size = "s" />
167
207
< EuiButton
168
208
style = { { width : '100px' } }
169
209
disabled = { isEmpty ( map ) || isEmpty ( JSON . parse ( sourceInput ) ) }
170
210
onClick = { async ( ) => {
171
211
switch ( props . context ) {
172
212
case PROCESSOR_CONTEXT . INGEST : {
173
- if ( ! isEmpty ( map ) && ! isEmpty ( JSON . parse ( sourceInput ) ) ) {
213
+ if (
214
+ ! isEmpty ( map ) &&
215
+ ! isEmpty ( JSON . parse ( sourceInput ) ) &&
216
+ selectedOutputOption !== undefined
217
+ ) {
174
218
let sampleSourceInput = { } ;
175
219
try {
176
220
sampleSourceInput = JSON . parse ( sourceInput ) [ 0 ] ;
177
221
const output = generateTransform (
178
222
sampleSourceInput ,
179
- map
223
+ map [ selectedOutputOption ]
180
224
) ;
181
225
setTransformedOutput (
182
226
JSON . stringify ( output , undefined , 2 )
0 commit comments