@@ -17,9 +17,12 @@ import {
17
17
EuiTitle ,
18
18
EuiCompressedFieldNumber ,
19
19
EuiSpacer ,
20
+ EuiCompressedSelect ,
21
+ EuiButtonIcon ,
22
+ EuiCompressedFieldText ,
20
23
} from '@elastic/eui' ;
21
- import { Field , FieldProps } from 'formik' ;
22
- import React , { useState } from 'react' ;
24
+ import { Field , FieldProps , FieldArray , } from 'formik' ;
25
+ import React , { useEffect , useState } from 'react' ;
23
26
import ContentPanel from '../../../../components/ContentPanel/ContentPanel' ;
24
27
import { BASE_DOCS_LINK } from '../../../../utils/constants' ;
25
28
import {
@@ -28,13 +31,22 @@ import {
28
31
validatePositiveInteger ,
29
32
} from '../../../../utils/utils' ;
30
33
import { FormattedFormRow } from '../../../../components/FormattedFormRow/FormattedFormRow' ;
34
+ import { SparseDataOptionValue } from '../../utils/constants' ;
31
35
32
36
interface AdvancedSettingsProps { }
33
37
34
38
export function AdvancedSettings ( props : AdvancedSettingsProps ) {
35
39
const [ showAdvancedSettings , setShowAdvancedSettings ] =
36
40
useState < boolean > ( false ) ;
37
41
42
+ // Options for the sparse data handling dropdown
43
+ const sparseDataOptions = [
44
+ { value : SparseDataOptionValue . IGNORE , text : 'Ignore missing value' } ,
45
+ { value : SparseDataOptionValue . PREVIOUS_VALUE , text : 'Previous value' } ,
46
+ { value : SparseDataOptionValue . SET_TO_ZERO , text : 'Set to zero' } ,
47
+ { value : SparseDataOptionValue . CUSTOM_VALUE , text : 'Custom value' } ,
48
+ ] ;
49
+
38
50
return (
39
51
< ContentPanel
40
52
title = {
@@ -58,41 +70,148 @@ export function AdvancedSettings(props: AdvancedSettingsProps) {
58
70
>
59
71
{ showAdvancedSettings ? < EuiSpacer size = "m" /> : null }
60
72
{ showAdvancedSettings ? (
61
- < Field name = "shingleSize" validate = { validatePositiveInteger } >
62
- { ( { field, form } : FieldProps ) => (
63
- < FormattedFormRow
64
- title = "Shingle size"
65
- hint = { [
66
- `Set the number of intervals to consider in a detection
73
+ < >
74
+ < Field name = "shingleSize" validate = { validatePositiveInteger } >
75
+ { ( { field, form } : FieldProps ) => (
76
+ < FormattedFormRow
77
+ title = "Shingle size"
78
+ hint = { [
79
+ `Set the number of intervals to consider in a detection
67
80
window for your model. The anomaly detector expects the
68
- shingle size to be in the range of 1 and 60 . The default
81
+ shingle size to be in the range of 1 and 128 . The default
69
82
shingle size is 8. We recommend that you don’t choose 1
70
83
unless you have two or more features. Smaller values might
71
84
increase recall but also false positives. Larger values
72
85
might be useful for ignoring noise in a signal.` ,
73
- ] }
74
- hintLink = { `${ BASE_DOCS_LINK } /ad` }
75
- isInvalid = { isInvalid ( field . name , form ) }
76
- error = { getError ( field . name , form ) }
77
- >
78
- < EuiFlexGroup gutterSize = "s" alignItems = "center" >
79
- < EuiFlexItem grow = { false } >
80
- < EuiCompressedFieldNumber
81
- id = "shingleSize"
82
- placeholder = "Shingle size"
83
- data-test-subj = "shingleSize"
84
- { ...field }
85
- />
86
- </ EuiFlexItem >
87
- < EuiFlexItem >
88
- < EuiText >
89
- < p className = "minutes" > intervals</ p >
90
- </ EuiText >
91
- </ EuiFlexItem >
92
- </ EuiFlexGroup >
93
- </ FormattedFormRow >
94
- ) }
95
- </ Field >
86
+ ] }
87
+ hintLink = { `${ BASE_DOCS_LINK } /ad` }
88
+ isInvalid = { isInvalid ( field . name , form ) }
89
+ error = { getError ( field . name , form ) }
90
+ >
91
+ < EuiFlexGroup gutterSize = "s" alignItems = "center" >
92
+ < EuiFlexItem grow = { false } >
93
+ < EuiCompressedFieldNumber
94
+ id = "shingleSize"
95
+ placeholder = "Shingle size"
96
+ data-test-subj = "shingleSize"
97
+ { ...field }
98
+ />
99
+ </ EuiFlexItem >
100
+ < EuiFlexItem >
101
+ < EuiText >
102
+ < p className = "minutes" > intervals</ p >
103
+ </ EuiText >
104
+ </ EuiFlexItem >
105
+ </ EuiFlexGroup >
106
+ </ FormattedFormRow >
107
+ ) }
108
+ </ Field >
109
+
110
+ < Field
111
+ name = "imputationOption.imputationMethod"
112
+ id = "imputationOption.imputationMethod"
113
+ >
114
+ { ( { field, form } : FieldProps ) => {
115
+ // Add an empty row if CUSTOM_VALUE is selected and no rows exist
116
+ useEffect ( ( ) => {
117
+ if (
118
+ field . value === SparseDataOptionValue . CUSTOM_VALUE &&
119
+ ( ! form . values . imputationOption ?. custom_value ||
120
+ form . values . imputationOption . custom_value . length === 0 )
121
+ ) {
122
+ form . setFieldValue ( 'imputationOption.custom_value' , [
123
+ { featureName : '' , value : undefined } ,
124
+ ] ) ;
125
+ }
126
+ } , [ field . value , form ] ) ;
127
+
128
+ return (
129
+ < >
130
+ < FormattedFormRow
131
+ title = "Sparse data handling"
132
+ hint = { [ `Choose how to handle missing data points.` ] }
133
+ hintLink = { `${ BASE_DOCS_LINK } /ad` }
134
+ isInvalid = { isInvalid ( field . name , form ) }
135
+ error = { getError ( field . name , form ) }
136
+ >
137
+ < EuiCompressedSelect { ...field } options = { sparseDataOptions } />
138
+ </ FormattedFormRow >
139
+
140
+ { /* Conditionally render the "Custom value" title and the input fields when 'Custom value' is selected */ }
141
+ { field . value === SparseDataOptionValue . CUSTOM_VALUE && (
142
+ < >
143
+ < EuiSpacer size = "m" />
144
+ < EuiText size = "xs" >
145
+ < h5 > Custom value</ h5 >
146
+ </ EuiText >
147
+ < EuiSpacer size = "s" />
148
+ < FieldArray name = "imputationOption.custom_value" >
149
+ { ( arrayHelpers ) => (
150
+ < >
151
+ { form . values . imputationOption . custom_value ?. map ( ( _ , index ) => (
152
+ < EuiFlexGroup
153
+ key = { index }
154
+ gutterSize = "s"
155
+ alignItems = "center"
156
+ >
157
+ < EuiFlexItem grow = { false } >
158
+ < Field
159
+ name = { `imputationOption.custom_value.${ index } .featureName` }
160
+ id = { `imputationOption.custom_value.${ index } .featureName` }
161
+ >
162
+ { ( { field } : FieldProps ) => (
163
+ < EuiCompressedFieldText
164
+ placeholder = "Feature name"
165
+ { ...field }
166
+ />
167
+ ) }
168
+ </ Field >
169
+ </ EuiFlexItem >
170
+ < EuiFlexItem grow = { false } >
171
+ < Field
172
+ name = { `imputationOption.custom_value.${ index } .data` }
173
+ id = { `imputationOption.custom_value.${ index } .data` }
174
+ >
175
+ { /* the value is set to field.value || '' to avoid displaying 0 as a default value. */ }
176
+ { ( { field, form } : FieldProps ) => (
177
+ < EuiCompressedFieldNumber
178
+ fullWidth
179
+ placeholder = "Custom value"
180
+ { ...field }
181
+ value = { field . value || '' }
182
+ />
183
+ ) }
184
+ </ Field >
185
+ </ EuiFlexItem >
186
+ < EuiFlexItem grow = { false } >
187
+ < EuiButtonIcon
188
+ iconType = "trash"
189
+ color = "danger"
190
+ aria-label = "Delete row"
191
+ onClick = { ( ) => arrayHelpers . remove ( index ) }
192
+ />
193
+ </ EuiFlexItem >
194
+ </ EuiFlexGroup >
195
+ ) ) }
196
+ < EuiSpacer size = "s" />
197
+ { /* add new rows with empty values when the add button is clicked. */ }
198
+ < EuiButtonIcon
199
+ iconType = "plusInCircle"
200
+ onClick = { ( ) =>
201
+ arrayHelpers . push ( { featureName : '' , value : 0 } )
202
+ }
203
+ aria-label = "Add row"
204
+ />
205
+ </ >
206
+ ) }
207
+ </ FieldArray >
208
+ </ >
209
+ ) }
210
+ </ >
211
+ ) ;
212
+ } }
213
+ </ Field >
214
+ </ >
96
215
) : null }
97
216
</ ContentPanel >
98
217
) ;
0 commit comments