1
+ import { createContext , Fragment , useContext , useState } from 'react' ;
1
2
import styled from '@emotion/styled' ;
2
3
import { uuid4 } from '@sentry/core' ;
3
4
@@ -9,9 +10,29 @@ import {PurpleTextButton} from 'sentry/components/workflowEngine/ui/purpleTextBu
9
10
import { IconAdd , IconDelete } from 'sentry/icons' ;
10
11
import { t } from 'sentry/locale' ;
11
12
import { space } from 'sentry/styles/space' ;
12
- import { MatchType } from 'sentry/views/automations/components/actionFilters/constants' ;
13
+ import { DataConditionType } from 'sentry/types/workflowEngine/dataConditions' ;
14
+ import {
15
+ Attributes ,
16
+ MatchType ,
17
+ } from 'sentry/views/automations/components/actionFilters/constants' ;
13
18
import { useDataConditionNodeContext } from 'sentry/views/automations/components/dataConditionNodes' ;
14
19
20
+ interface SubfilterProps {
21
+ onUpdate : ( comparison : Record < string , any > ) => void ;
22
+ subfilter : Record < string , any > ;
23
+ subfilter_id : string ;
24
+ }
25
+
26
+ const SubfilterContext = createContext < SubfilterProps | null > ( null ) ;
27
+
28
+ function useSubfilterContext ( ) : SubfilterProps {
29
+ const context = useContext ( SubfilterContext ) ;
30
+ if ( ! context ) {
31
+ throw new Error ( 'useSubfilterContext was called outside of Subfilter' ) ;
32
+ }
33
+ return context ;
34
+ }
35
+
15
36
export function SubfiltersList ( ) {
16
37
const { condition, condition_id, onUpdate} = useDataConditionNodeContext ( ) ;
17
38
@@ -54,14 +75,20 @@ export function SubfiltersList() {
54
75
< div >
55
76
{ subfilters . map ( ( subfilter : Record < string , any > , i : number ) => {
56
77
return (
57
- < SubfilterRow
58
- subfilter = { subfilter }
59
- subfilter_id = { `${ condition_id } .comparison.filters.${ subfilter . id } ` }
60
- onRemove = { ( ) => removeSubfilter ( subfilter . id ) }
61
- onUpdate = { comparison => updateSubfilter ( subfilter . id , comparison ) }
78
+ < SubfilterContext . Provider
79
+ value = { {
80
+ subfilter,
81
+ subfilter_id : `${ condition_id } .comparison.filters.${ subfilter . id } ` ,
82
+ onUpdate : comparison => updateSubfilter ( subfilter . id , comparison ) ,
83
+ } }
62
84
key = { subfilter . id }
63
- isLastRow = { i === subfilterCount - 1 }
64
- />
85
+ >
86
+ < SubfilterRow
87
+ onRemove = { ( ) => removeSubfilter ( subfilter . id ) }
88
+ isFirstRow = { i === 0 }
89
+ isLastRow = { i === subfilterCount - 1 }
90
+ />
91
+ </ SubfilterContext . Provider >
65
92
) ;
66
93
} ) }
67
94
</ div >
@@ -73,62 +100,18 @@ export function SubfiltersList() {
73
100
}
74
101
75
102
interface SubfilterRowProps {
103
+ isFirstRow : boolean ;
104
+ isLastRow : boolean ;
76
105
onRemove : ( ) => void ;
77
- onUpdate : ( comparison : Record < string , any > ) => void ;
78
- subfilter : Record < string , any > ;
79
- subfilter_id : string ;
80
- isLastRow ?: boolean ;
81
106
}
82
107
83
- function SubfilterRow ( {
84
- subfilter,
85
- subfilter_id,
86
- onRemove,
87
- onUpdate,
88
- isLastRow,
89
- } : SubfilterRowProps ) {
108
+ function SubfilterRow ( { onRemove, isFirstRow, isLastRow} : SubfilterRowProps ) {
90
109
return (
91
110
< RowWrapper >
92
111
< Branch lastChild = { isLastRow } />
93
112
< StyledRowLine >
94
- < AutomationBuilderInputField
95
- name = { `${ subfilter_id } .key` }
96
- placeholder = { t ( 'key' ) }
97
- value = { subfilter . key }
98
- onChange = { ( value : string ) => {
99
- onUpdate ( {
100
- key : value ,
101
- } ) ;
102
- } }
103
- />
104
- < AutomationBuilderSelectField
105
- name = { `${ subfilter_id } .match` }
106
- value = { subfilter . match }
107
- options = { [
108
- {
109
- label : 'is' ,
110
- value : MatchType . EQUAL ,
111
- } ,
112
- {
113
- label : 'is not' ,
114
- value : MatchType . NOT_EQUAL ,
115
- } ,
116
- ] }
117
- onChange = { ( value : MatchType ) => {
118
- onUpdate ( { match : value } ) ;
119
- } }
120
- />
121
- < AutomationBuilderInputField
122
- name = { `${ subfilter_id } .value` }
123
- placeholder = { t ( 'value' ) }
124
- value = { `${ subfilter . value } ` }
125
- onChange = { ( value : string ) => {
126
- onUpdate ( {
127
- value,
128
- } ) ;
129
- } }
130
- />
131
- { ! isLastRow && t ( 'and' ) }
113
+ { ! isFirstRow && t ( 'and' ) }
114
+ < ComparisonTypeField />
132
115
< Button
133
116
aria-label = { t ( 'Delete Subfilter' ) }
134
117
size = "sm"
@@ -141,6 +124,137 @@ function SubfilterRow({
141
124
) ;
142
125
}
143
126
127
+ interface BranchProps {
128
+ lastChild ?: boolean ;
129
+ }
130
+
131
+ function Branch ( { lastChild} : BranchProps ) {
132
+ return (
133
+ < svg
134
+ width = "26"
135
+ height = "38"
136
+ viewBox = "0 0 26 38"
137
+ fill = "none"
138
+ xmlns = "http://www.w3.org/2000/svg"
139
+ >
140
+ < line x1 = "0.5" x2 = "0.5" y2 = { lastChild ? '19' : '38' } stroke = "#80708F" />
141
+ < circle cx = "23.5" cy = "18.5" r = "2.5" fill = "#80708F" />
142
+ < line x1 = "22" y1 = "18.5" x2 = "1" y2 = "18.5" stroke = "#80708F" />
143
+ </ svg >
144
+ ) ;
145
+ }
146
+
147
+ function ComparisonTypeField ( ) {
148
+ const { subfilter, subfilter_id} = useSubfilterContext ( ) ;
149
+ const [ type , setType ] = useState < DataConditionType | undefined > ( undefined ) ;
150
+
151
+ if ( ! type ) {
152
+ return (
153
+ < AutomationBuilderSelectField
154
+ name = { `${ subfilter_id } .comparison_type` }
155
+ value = { subfilter . comparison_type }
156
+ placeholder = { t ( 'Select value type' ) }
157
+ options = { [
158
+ {
159
+ label : t ( 'Attribute' ) ,
160
+ value : DataConditionType . EVENT_ATTRIBUTE ,
161
+ } ,
162
+ {
163
+ label : t ( 'Tag' ) ,
164
+ value : DataConditionType . TAGGED_EVENT ,
165
+ } ,
166
+ ] }
167
+ onChange = { ( value : DataConditionType ) => {
168
+ setType ( value ) ;
169
+ } }
170
+ />
171
+ ) ;
172
+ }
173
+
174
+ return (
175
+ < Fragment >
176
+ { type === DataConditionType . EVENT_ATTRIBUTE ? < AttributeField /> : < KeyField /> }
177
+ < MatchField />
178
+ < ValueField />
179
+ </ Fragment >
180
+ ) ;
181
+ }
182
+
183
+ function AttributeField ( ) {
184
+ const { subfilter, subfilter_id, onUpdate} = useSubfilterContext ( ) ;
185
+ return (
186
+ < AutomationBuilderSelectField
187
+ name = { `${ subfilter_id } .attribute` }
188
+ placeholder = { t ( 'Select attribute' ) }
189
+ value = { subfilter . attribute }
190
+ options = { Object . values ( Attributes ) . map ( attribute => ( {
191
+ value : attribute ,
192
+ label : attribute ,
193
+ } ) ) }
194
+ onChange = { ( value : string ) => {
195
+ onUpdate ( {
196
+ attribute : value ,
197
+ } ) ;
198
+ } }
199
+ />
200
+ ) ;
201
+ }
202
+
203
+ function KeyField ( ) {
204
+ const { subfilter, subfilter_id, onUpdate} = useSubfilterContext ( ) ;
205
+ return (
206
+ < AutomationBuilderInputField
207
+ name = { `${ subfilter_id } .key` }
208
+ placeholder = { t ( 'Enter tag' ) }
209
+ value = { subfilter . key }
210
+ onChange = { ( value : string ) => {
211
+ onUpdate ( {
212
+ key : value ,
213
+ } ) ;
214
+ } }
215
+ />
216
+ ) ;
217
+ }
218
+
219
+ function MatchField ( ) {
220
+ const { subfilter, subfilter_id, onUpdate} = useSubfilterContext ( ) ;
221
+ return (
222
+ < AutomationBuilderSelectField
223
+ name = { `${ subfilter_id } .match` }
224
+ value = { subfilter . match }
225
+ options = { [
226
+ {
227
+ label : 'is' ,
228
+ value : MatchType . EQUAL ,
229
+ } ,
230
+ {
231
+ label : 'is not' ,
232
+ value : MatchType . NOT_EQUAL ,
233
+ } ,
234
+ ] }
235
+ onChange = { ( value : MatchType ) => {
236
+ onUpdate ( { match : value } ) ;
237
+ } }
238
+ />
239
+ ) ;
240
+ }
241
+
242
+ function ValueField ( ) {
243
+ const { subfilter, subfilter_id, onUpdate} = useSubfilterContext ( ) ;
244
+ return (
245
+ < AutomationBuilderInputField
246
+ name = { `${ subfilter_id } .value` }
247
+ placeholder = { t ( 'value' ) }
248
+ value = { `${ subfilter . value } ` }
249
+ onChange = { ( value : string ) => {
250
+ onUpdate ( {
251
+ value,
252
+ } ) ;
253
+ } }
254
+ />
255
+ ) ;
256
+ }
257
+
144
258
const RowWrapper = styled ( 'div' ) `
145
259
display: flex;
146
260
align-items: center;
@@ -164,23 +278,3 @@ const StyledRowLine = styled(RowLine)`
164
278
}
165
279
}
166
280
` ;
167
-
168
- interface BranchProps {
169
- lastChild ?: boolean ;
170
- }
171
-
172
- function Branch ( { lastChild} : BranchProps ) {
173
- return (
174
- < svg
175
- width = "26"
176
- height = "38"
177
- viewBox = "0 0 26 38"
178
- fill = "none"
179
- xmlns = "http://www.w3.org/2000/svg"
180
- >
181
- < line x1 = "0.5" x2 = "0.5" y2 = { lastChild ? '19' : '38' } stroke = "#80708F" />
182
- < circle cx = "23.5" cy = "18.5" r = "2.5" fill = "#80708F" />
183
- < line x1 = "22" y1 = "18.5" x2 = "1" y2 = "18.5" stroke = "#80708F" />
184
- </ svg >
185
- ) ;
186
- }
0 commit comments