Skip to content

Commit 0011c47

Browse files
authored
Merge pull request #992 from bitovi/search-criteria
Search Criteria Support in the Web UI - Updated
2 parents e172f1a + 038762c commit 0011c47

File tree

6 files changed

+318
-54
lines changed

6 files changed

+318
-54
lines changed

CHANGELOG.rst

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ Added
1616

1717
Contributed by @Jappzy and @cded from @Bitovi
1818

19+
* Added the search rule criteria in the UI with the possibility of multiple patterns. #992, #964, #492
20+
21+
Contributed by @Jappzy and @cded from @Bitovi
22+
1923
Changed
2024
~~~~~~~
2125
* Updated nodejs from `14.16.1` to `14.20.1`, fixing the local build under ARM processor architecture. #880

apps/st2-rules/rules-details.component.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ export default class RulesDetails extends React.Component {
207207
}
208208

209209
this.props.onComponentUpdate && this.props.onComponentUpdate();
210+
211+
this.setState({ editing: null });
210212
}
211213

212214
handleSection(section) {
@@ -440,8 +442,8 @@ export default class RulesDetails extends React.Component {
440442
? (
441443
Object.keys(rule.criteria || {})
442444
.map(name => {
443-
const { type, pattern } = rule.criteria[name];
444-
return <DetailsCriteriaLine key={`${name}//${type}//${pattern}`} name={name} type={type} pattern={pattern} />;
445+
const { type, pattern, condition } = rule.criteria[name];
446+
return <DetailsCriteriaLine key={`${name}//${type}//${pattern}`} name={name} type={type} pattern={pattern} condition={condition} />;
445447
})
446448
) : (
447449
<DetailsLineNote>

modules/st2-criteria/criteria.component.js

+233-29
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ const types = {
5151
'timediff_gt': 'Later Than',
5252
'exists': 'Exists',
5353
'nexists': 'Doesn\'t Exist',
54+
'search': 'Search',
55+
};
56+
57+
const searchConditions = {
58+
'any': 'Any',
59+
'all': 'All',
60+
'any2any': 'Any2Any',
61+
'all2any': 'All2Any',
5462
};
5563

5664
export default class Criteria extends React.Component {
@@ -67,30 +75,163 @@ export default class Criteria extends React.Component {
6775
disabled: false,
6876
}
6977

70-
handleChangeKey(oldKey, key) {
78+
handleChangeSearchCondition(key, condition) {
79+
const { data, onChange } = this.props;
80+
81+
return onChange({
82+
...data,
83+
[key]: {
84+
...data[key],
85+
condition,
86+
},
87+
});
88+
}
89+
90+
91+
handleChangeSearchItemKey(key, oldItemKey, itemKey) {
7192
const { onChange } = this.props;
7293

73-
const data = { ...this.props.data };
74-
delete data[oldKey];
94+
if(oldItemKey !== itemKey) {
95+
const data = { ...this.props.data };
96+
const dataItem = { ...data[key].pattern };
97+
delete dataItem[oldItemKey];
98+
99+
return onChange({
100+
...data,
101+
[key]: {
102+
...data[key],
103+
pattern: {
104+
...dataItem,
105+
[itemKey]: {
106+
...data[key].pattern[oldItemKey],
107+
},
108+
},
109+
},
110+
});
111+
}
112+
return onChange(this.props.data);
113+
114+
}
115+
116+
handleChangeSearchPattern(key, itemKey, pattern) {
117+
const { data, onChange } = this.props;
75118

76119
return onChange({
77120
...data,
78-
[key]: this.props.data[oldKey],
121+
[key]: {
122+
...data[key],
123+
pattern: {
124+
...data[key].pattern,
125+
[itemKey]: {
126+
...data[key].pattern[itemKey],
127+
pattern,
128+
},
129+
},
130+
},
79131
});
80132
}
81133

82-
handleChangeType(key, type) {
134+
handleChangeSearchType(key, itemKey, type) {
83135
const { data, onChange } = this.props;
84136

85137
return onChange({
86138
...data,
87139
[key]: {
88140
...data[key],
89-
type,
141+
pattern: {
142+
...data[key].pattern,
143+
[itemKey]: {
144+
...data[key].pattern[itemKey],
145+
type,
146+
},
147+
},
90148
},
91149
});
92150
}
93151

152+
handleAddSearchPatternItem(key) {
153+
const { data, onChange } = this.props;
154+
155+
return onChange({
156+
...data,
157+
[key]: {
158+
...data[key],
159+
pattern: {
160+
...data[key].pattern,
161+
['']: {
162+
type: Object.keys(types)[0],
163+
},
164+
},
165+
},
166+
});
167+
}
168+
169+
handleRemoveSearchPatternItem(key, itemKey) {
170+
const { onChange } = this.props;
171+
172+
const data = { ...this.props.data };
173+
const dataPattern = {...this.props.data[key].pattern};
174+
delete dataPattern[itemKey];
175+
176+
return onChange({
177+
...data,
178+
[key]: {
179+
...data[key],
180+
pattern: {
181+
...dataPattern,
182+
},
183+
},
184+
});
185+
}
186+
187+
handleChangeKey(oldKey, key) {
188+
const { onChange } = this.props;
189+
190+
if(oldKey!== key) {
191+
const data = { ...this.props.data };
192+
delete data[oldKey];
193+
194+
return onChange({
195+
...data,
196+
[key]: this.props.data[oldKey],
197+
});
198+
}
199+
return onChange(this.props.data);
200+
}
201+
202+
handleChangeType(key, type) {
203+
const { data, onChange } = this.props;
204+
205+
if (type === 'search') {
206+
// save default values for search criteria
207+
return onChange({
208+
...data,
209+
[key]: {
210+
...data[key],
211+
type,
212+
condition: 'all',
213+
pattern: {
214+
['']: {
215+
type: Object.keys(types)[0],
216+
},
217+
},
218+
},
219+
});
220+
}
221+
else {
222+
// reset pattern from object to empty string if type != 'search'
223+
this.handleChangePattern(key, '');
224+
return onChange({
225+
...data,
226+
[key]: {
227+
...data[key],
228+
type,
229+
pattern: '',
230+
},
231+
});
232+
}
233+
}
234+
94235
handleChangePattern(key, pattern) {
95236
const { data, onChange } = this.props;
96237

@@ -131,16 +272,23 @@ export default class Criteria extends React.Component {
131272
return (
132273
<div {...props} className={cx(style.component, flat && [ 'st2-auto-form--flat', style.flat ], className)}>
133274
<div>
134-
{ _.map(data, ({ type, pattern }, key) => (
275+
{ _.map(data, ({ type, pattern, condition }, key) => (
135276
<div className={style.line} key={key}>
136-
<AutoFormCombobox
137-
className={style.entity}
138-
disabled={disabled}
139-
data={key}
140-
spec={spec}
141-
onChange={(value) => this.handleChangeKey(key, value)}
142-
/>
277+
<div className={style.criteriaLabel}>
278+
<AutoFormCombobox
279+
name='Key'
280+
className={style.entity}
281+
disabled={disabled}
282+
data={key}
283+
spec={spec}
284+
onChange={(value) => this.handleChangeKey(key, value)}
285+
/>
286+
{ disabled ? null :
287+
<i className={cx('icon-cross', style.remove)} onClick={() => this.handleRemove(key)} />
288+
}
289+
</div>
143290
<AutoFormSelect
291+
name='Type'
144292
className={style.entity}
145293
disabled={disabled}
146294
data={type}
@@ -150,28 +298,84 @@ export default class Criteria extends React.Component {
150298
}}
151299
onChange={(value) => this.handleChangeType(key, value)}
152300
/>
153-
<AutoFormInput
154-
className={style.entity}
155-
disabled={disabled}
156-
data={pattern}
157-
spec={{
158-
required: true,
159-
}}
160-
onChange={(value) => this.handleChangePattern(key, value)}
161-
/>
162-
{ disabled ? null :
163-
<i className={cx('icon-cross', style.remove)} onClick={() => this.handleRemove(key)} />
164-
}
301+
{ type === 'search' ? (
302+
<>
303+
<AutoFormSelect
304+
name='Condition'
305+
className={style.entity}
306+
disabled={disabled}
307+
data={condition}
308+
spec={{
309+
required: true,
310+
enum: searchConditions,
311+
}}
312+
onChange={(value) => this.handleChangeSearchCondition(key, value)}
313+
/>
314+
<div className={style.break} />
315+
<h5>Search Patterns <i className={cx('icon-plus', style.remove)} onClick={() => this.handleAddSearchPatternItem(key)} /></h5>
316+
<div className={style.break} />
317+
{ _.map(pattern, ({ type, pattern }, itemKey) => (
318+
<div style={{display: 'flex'}} key={itemKey}>
319+
<AutoFormCombobox
320+
name={'Item name'}
321+
className={style.entity}
322+
disabled={disabled}
323+
data={itemKey}
324+
spec={{
325+
required: true,
326+
enum: [],
327+
}}
328+
onChange={(value) => this.handleChangeSearchItemKey(key, itemKey, value)}
329+
/>
330+
<AutoFormSelect
331+
name={'Type'}
332+
className={style.entity}
333+
disabled={disabled}
334+
data={type}
335+
spec={{
336+
required: true,
337+
enum: types,
338+
}}
339+
onChange={(value) => this.handleChangeSearchType(key, itemKey, value)}
340+
/>
341+
<AutoFormInput
342+
name={'Pattern'}
343+
className={style.entity}
344+
disabled={disabled}
345+
data={pattern || ''}
346+
spec={{
347+
required: true,
348+
}}
349+
onChange={(value) => this.handleChangeSearchPattern(key, itemKey, value)}
350+
/>
351+
<i
352+
className={cx('icon-cross', style.remove, style.subPatternRemove)} onClick={() => this.handleRemoveSearchPatternItem(key, itemKey)}
353+
/>
354+
</div>
355+
))}
356+
</>
357+
) : (
358+
<AutoFormInput
359+
name={'Pattern'}
360+
className={style.entity}
361+
disabled={disabled}
362+
data={pattern}
363+
spec={{
364+
required: true,
365+
}}
366+
onChange={(value) => this.handleChangePattern(key, value)}
367+
/>
368+
)}
165369
</div>
166370
)) }
167371
</div>
168372
{ disabled ? null : (
169373
<div className={style.buttons}>
170374
<input
171-
type="button"
172-
className="st2-forms__button st2-forms__button--small"
375+
type='button'
376+
className='st2-forms__button st2-forms__button--small'
173377
onClick={() => this.handleAdd()}
174-
value="Add criteria"
378+
value='Add criteria'
175379
/>
176380
</div>
177381
) }

modules/st2-criteria/style.css

+20
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,23 @@
6363

6464
flex: initial;
6565
}
66+
67+
.break {
68+
flex-basis: 100%;
69+
height: 0;
70+
}
71+
72+
.criteriaLabel {
73+
position: relative;
74+
75+
i {
76+
position: absolute;
77+
top: 2px;
78+
left: -25px;
79+
}
80+
}
81+
82+
.subPatternRemove {
83+
margin-top: 20px;
84+
margin-left: 5px;
85+
}

0 commit comments

Comments
 (0)