@orchestrator-ui/orchestrator-ui-components 8.5.0 → 8.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/.turbo/turbo-build.log +10 -14
  2. package/.turbo/turbo-lint.log +2 -4
  3. package/.turbo/turbo-test.log +16 -15
  4. package/CHANGELOG.md +17 -0
  5. package/dist/index.d.ts +188 -80
  6. package/dist/index.js +3509 -2731
  7. package/dist/index.js.map +1 -1
  8. package/package.json +3 -1
  9. package/src/components/WfoAutoExpandableTextArea/WfoAutoExpandableTextArea.tsx +54 -0
  10. package/src/components/WfoAutoExpandableTextArea/index.ts +1 -0
  11. package/src/components/WfoAutoExpandableTextArea/styles.ts +18 -0
  12. package/src/components/WfoPageTemplate/paths.ts +1 -0
  13. package/src/components/WfoPydanticForm/fields/WfoCron.spec.ts +88 -0
  14. package/src/components/WfoPydanticForm/fields/WfoCron.tsx +233 -0
  15. package/src/components/WfoPydanticForm/fields/index.ts +1 -0
  16. package/src/components/WfoPydanticForm/fields/styles.ts +92 -0
  17. package/src/components/WfoSearchPage/WfoSearchResults/WfoSearchResultItem.tsx +2 -1
  18. package/src/components/WfoSearchPage/utils.ts +37 -1
  19. package/src/components/WfoSubscription/WfoInUseByRelations.tsx +6 -2
  20. package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActionExpandableMenuItem.tsx +19 -14
  21. package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActions.tsx +13 -1
  22. package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActionsMenuItem.tsx +3 -0
  23. package/src/components/WfoSubscription/WfoSubscriptionProductBlock/WfoSubscriptionProductBlock.tsx +1 -1
  24. package/src/components/WfoSubscriptionsList/WfoSubscriptionsList.tsx +5 -0
  25. package/src/components/WfoSubscriptionsList/subscriptionResultMappers.ts +3 -1
  26. package/src/components/WfoTable/WfoAdvancedTable/WfoAdvancedTable.tsx +2 -12
  27. package/src/components/WfoTable/WfoStructuredSearchTable/WfoAddGroupAction.tsx +1 -1
  28. package/src/components/WfoTable/WfoStructuredSearchTable/WfoCombinatorSelector.tsx +3 -0
  29. package/src/components/WfoTable/WfoStructuredSearchTable/WfoExpandingSearchRow.tsx +21 -14
  30. package/src/components/WfoTable/WfoStructuredSearchTable/WfoFieldSelector.tsx +84 -4
  31. package/src/components/WfoTable/WfoStructuredSearchTable/WfoFilterBuilder.tsx +119 -104
  32. package/src/components/WfoTable/WfoStructuredSearchTable/WfoInlineCombinator.tsx +17 -0
  33. package/src/components/WfoTable/WfoStructuredSearchTable/WfoOperatorSelector.tsx +32 -7
  34. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRemoveRuleAction.tsx +3 -3
  35. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRuleGroup.tsx +11 -7
  36. package/src/components/WfoTable/WfoStructuredSearchTable/WfoSearchFieldWithActions.tsx +56 -0
  37. package/src/components/WfoTable/WfoStructuredSearchTable/WfoStructuredSearchTable.tsx +92 -87
  38. package/src/components/WfoTable/WfoStructuredSearchTable/WfoValueEditor.tsx +41 -11
  39. package/src/components/WfoTable/WfoStructuredSearchTable/styles.ts +74 -21
  40. package/src/components/WfoTable/WfoStructuredSearchTable/utils.ts +45 -0
  41. package/src/components/WfoTable/WfoTable/WfoTable.tsx +1 -0
  42. package/src/components/WfoTable/WfoTable/WfoTableDataRows.tsx +16 -4
  43. package/src/components/WfoTable/WfoTable/styles.ts +8 -0
  44. package/src/components/WfoTable/WfoTable/utils.spec.ts +62 -1
  45. package/src/components/WfoTable/WfoTable/utils.ts +4 -1
  46. package/src/components/WfoTable/WfoTableSettingsModal/WfoTableSettingsModal.spec.ts +45 -0
  47. package/src/components/WfoTable/WfoTableSettingsModal/WfoTableSettingsModal.tsx +9 -0
  48. package/src/components/WfoTable/WfoTableSettingsModal/index.ts +1 -0
  49. package/src/components/WfoTable/WfoTableSettingsModal/utils.ts +17 -0
  50. package/src/components/index.ts +1 -0
  51. package/src/configuration/version.ts +1 -1
  52. package/src/hooks/index.ts +1 -0
  53. package/src/hooks/useGetPydanticFormsConfig.tsx +12 -0
  54. package/src/hooks/useLanguageCode.ts +11 -0
  55. package/src/messages/en-GB.json +20 -0
  56. package/src/messages/nl-NL.json +20 -0
  57. package/src/pages/WfoSearchPocPage.tsx +165 -30
  58. package/src/rtk/endpoints/subscriptionList.ts +1 -0
  59. package/src/theme/baseStyles/formFieldsBaseStyle.ts +0 -1
  60. package/src/types/search.ts +4 -1
  61. package/src/types/types.ts +1 -1
  62. package/src/utils/getDefaultTableConfig.ts +6 -1
  63. package/src/utils/index.ts +1 -0
  64. package/src/utils/integer.spec.ts +20 -0
  65. package/src/utils/integer.ts +3 -0
@@ -1,17 +1,19 @@
1
- import React, { useState } from 'react';
2
- import { FullOperator, QueryBuilder, type RuleGroupType } from 'react-querybuilder';
1
+ import React, { useRef, useState } from 'react';
2
+ import { FullOperator, QueryBuilder, type RuleGroupType, generateID } from 'react-querybuilder';
3
3
  import 'react-querybuilder/dist/query-builder.css';
4
4
 
5
5
  import { useTranslations } from 'next-intl';
6
6
 
7
- import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiTextArea } from '@elastic/eui';
7
+ import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
8
8
 
9
- import { SearchParams, WfoTextAnchor } from '@/components';
9
+ import { SearchParams, WfoAutoExpandableTextArea, WfoTextAnchor } from '@/components';
10
10
  import { WfoCombinatorSelector } from '@/components/WfoTable/WfoStructuredSearchTable/WfoCombinatorSelector';
11
11
  import { useWithOrchestratorTheme } from '@/hooks';
12
- import { OperatorDisplay, PathInfo } from '@/types';
12
+ import { OperatorDisplay } from '@/types';
13
+ import type { FieldToOperatorMap } from '@/types';
13
14
 
14
15
  import { WfoFieldSelector } from './WfoFieldSelector';
16
+ import { WfoInlineCombinator } from './WfoInlineCombinator';
15
17
  import { WfoOperatorSelector } from './WfoOperatorSelector';
16
18
  import { WfoRemoveRuleAction } from './WfoRemoveRuleAction';
17
19
  import { WfoRule } from './WfoRule';
@@ -48,7 +50,6 @@ const OPERATOR_MAP: Record<string, OperatorDisplay> = {
48
50
  /* TODO: Add the missing operators
49
51
  ['has_component', 'not_has_component'];
50
52
  */
51
- type FieldPathInfoMap = Map<string, PathInfo>;
52
53
 
53
54
  interface WfoFilterBuilderProps {
54
55
  filterString?: string;
@@ -57,6 +58,8 @@ interface WfoFilterBuilderProps {
57
58
  queryBuilderRuleGroup?: RuleGroupType;
58
59
  onUpdateQueryBuilder: (ruleGroup: RuleGroupType | false) => void;
59
60
  handleSearch: (searchParams?: SearchParams) => void;
61
+ onToggleFilterBuilder: (isVisible: boolean) => void;
62
+ prefilledFieldOptions: FieldToOperatorMap;
60
63
  }
61
64
 
62
65
  const initialRuleGroup: RuleGroupType = {
@@ -65,6 +68,11 @@ const initialRuleGroup: RuleGroupType = {
65
68
  combinator: 'and',
66
69
  };
67
70
 
71
+ const onAddGroupHandler = (ruleGroup: RuleGroupType): RuleGroupType => {
72
+ const [firstRule] = ruleGroup.rules;
73
+ return firstRule ? { ...ruleGroup, rules: [...ruleGroup.rules, { ...firstRule, id: generateID() }] } : ruleGroup;
74
+ };
75
+
68
76
  export const WfoFilterBuilder = ({
69
77
  filterString,
70
78
  onUpdateFilterString,
@@ -72,9 +80,11 @@ export const WfoFilterBuilder = ({
72
80
  queryBuilderRuleGroup = initialRuleGroup,
73
81
  onUpdateQueryBuilder,
74
82
  handleSearch,
83
+ prefilledFieldOptions,
84
+ onToggleFilterBuilder,
75
85
  }: WfoFilterBuilderProps) => {
76
- const getOperatorsFromPathInfo = (fieldInfo?: PathInfo): FullOperator[] => {
77
- return (fieldInfo?.operators ?? []).map((operator) => {
86
+ const mapOperatorsToRQBOperatorOptions = (operators?: string[]): FullOperator[] => {
87
+ return (operators ?? []).map((operator) => {
78
88
  const { symbol, description } = OPERATOR_MAP[operator] || { symbol: operator, description: operator };
79
89
  const rqbOperator = SEARCH_OPERATOR_TO_RQB_OPERATOR_MAP[operator] ?? operator;
80
90
  return { name: rqbOperator, label: `${symbol} ${description}`, value: rqbOperator };
@@ -82,108 +92,113 @@ export const WfoFilterBuilder = ({
82
92
  };
83
93
 
84
94
  const t = useTranslations('common');
85
- const { queryBuilderContainerStyles, toggleButtonStyles, textAreaStyles } = useWithOrchestratorTheme(
86
- getWfoStructuredSearchTableStyles,
87
- );
88
- const [isFilterBuilderVisible, setIsFilterBuilderVisible] = useState<boolean>(false);
89
- const [fieldPathInfoMap, setFieldPathInfoMap] = useState<FieldPathInfoMap>(new Map());
90
-
91
- const handleFieldSelected = (field: string, pathInfo: PathInfo | undefined) => {
92
- if (pathInfo) {
93
- setFieldPathInfoMap((previousMap) => {
94
- return new Map(previousMap).set(field, pathInfo);
95
- });
96
- }
95
+ const { queryBuilderContainerStyles } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
96
+ const [fieldToOperatorMap, setFieldToOperatorMap] = useState<FieldToOperatorMap>(prefilledFieldOptions);
97
+
98
+ // Enter in a value editor commits its value on blur, and that state update has not
99
+ // flushed yet when the search runs in the same keydown. onQueryChange fires
100
+ // synchronously during the blur, so this ref always holds the freshest rule group,
101
+ // which is passed to handleSearch explicitly (same pattern as the remove-filter link).
102
+ const latestRuleGroupRef = useRef<RuleGroupType | undefined>(queryBuilderRuleGroup);
103
+ latestRuleGroupRef.current = queryBuilderRuleGroup;
104
+
105
+ const handleValueEditorEnter = () => {
106
+ handleSearch({ ruleGroup: latestRuleGroupRef.current });
107
+ };
108
+
109
+ const handleFieldSelected = (field: string, operators: string[]) => {
110
+ setFieldToOperatorMap((previousMap) => {
111
+ return new Map(previousMap).set(field, operators);
112
+ });
97
113
  };
98
114
 
99
115
  return (
100
116
  <EuiFlexGroup css={queryBuilderContainerStyles}>
101
- {(isFilterBuilderVisible && (
102
- <EuiFlexGroup direction={'column'}>
103
- <EuiFlexItem>
104
- <QueryBuilder
105
- query={queryBuilderRuleGroup}
106
- onQueryChange={(ruleGroup: RuleGroupType) => {
107
- onUpdateQueryBuilder(ruleGroup);
108
- }}
109
- context={{ onFieldSelected: handleFieldSelected, fieldPathInfoMap }}
110
- getOperators={(field) => {
111
- const pathInfo = fieldPathInfoMap.get(field);
112
- return getOperatorsFromPathInfo(pathInfo);
113
- }}
114
- controlElements={{
115
- fieldSelector: WfoFieldSelector,
116
- operatorSelector: WfoOperatorSelector,
117
- valueEditor: WfoValueEditor,
118
- ruleGroup: WfoRuleGroup,
119
- rule: WfoRule,
120
- combinatorSelector: WfoCombinatorSelector,
121
- addRuleAction: null,
122
- addGroupAction: null,
123
- removeGroupAction: null,
124
- removeRuleAction: WfoRemoveRuleAction,
125
- }}
126
- addRuleToNewGroups
127
- maxLevels={5}
128
- />
129
- </EuiFlexItem>
130
- <EuiFlexItem>
131
- <EuiTextArea
132
- css={textAreaStyles}
133
- id={'searchbox-textarea'}
134
- value={filterString}
135
- onChange={(e) => {
136
- const filterString = e.target.value;
137
- onUpdateFilterString(filterString);
138
- }}
139
- fullWidth={true}
140
- isClearable={true}
141
- resize={'vertical'}
142
- isInvalid={!isValidFilterString}
143
- />
144
- </EuiFlexItem>
145
-
146
- <EuiFlexGroup direction={'rowReverse'} alignItems={'center'}>
147
- <EuiButton
148
- onClick={() => {
117
+ <EuiFlexGroup direction={'column'}>
118
+ <EuiFlexItem>
119
+ <QueryBuilder
120
+ query={queryBuilderRuleGroup}
121
+ enableMountQueryChange={false}
122
+ onQueryChange={(ruleGroup: RuleGroupType) => {
123
+ latestRuleGroupRef.current = ruleGroup;
124
+ onUpdateQueryBuilder(ruleGroup);
125
+ }}
126
+ context={{
127
+ onFieldSelected: handleFieldSelected,
128
+ prefilledFieldOptions,
129
+ onValueEditorEnter: handleValueEditorEnter,
130
+ }}
131
+ getOperators={(field) => {
132
+ const operators = fieldToOperatorMap.get(field);
133
+ return mapOperatorsToRQBOperatorOptions(operators);
134
+ }}
135
+ controlElements={{
136
+ fieldSelector: WfoFieldSelector,
137
+ operatorSelector: WfoOperatorSelector,
138
+ valueEditor: WfoValueEditor,
139
+ ruleGroup: WfoRuleGroup,
140
+ rule: WfoRule,
141
+ combinatorSelector: WfoCombinatorSelector,
142
+ inlineCombinator: WfoInlineCombinator,
143
+ addRuleAction: null,
144
+ addGroupAction: null,
145
+ removeGroupAction: null,
146
+ removeRuleAction: WfoRemoveRuleAction,
147
+ }}
148
+ addRuleToNewGroups
149
+ onAddGroup={onAddGroupHandler}
150
+ maxLevels={5}
151
+ showCombinatorsBetweenRules
152
+ resetOnFieldChange={false}
153
+ />
154
+ </EuiFlexItem>
155
+ <EuiFlexItem>
156
+ <WfoAutoExpandableTextArea
157
+ id={'searchbox-textarea'}
158
+ value={filterString ?? ''}
159
+ onChange={(e) => {
160
+ const filterString = e.target.value;
161
+ onUpdateFilterString(filterString);
162
+ }}
163
+ onKeyDown={(event) => {
164
+ // Enter applies the filter like the Apply button (and like it, does nothing
165
+ // while the filter string is invalid); Shift+Enter inserts a newline.
166
+ if (event.key !== 'Enter' || event.shiftKey) return;
167
+ event.preventDefault();
168
+ if (isValidFilterString) {
149
169
  handleSearch();
150
- }}
151
- id={'button-apply-filter'}
152
- data-test-id={'button-apply-filter'}
153
- fill
154
- type="submit"
155
- aria-label={t('applyFilter')}
156
- disabled={!isValidFilterString}
157
- >
158
- {t('applyFilter')}
159
- </EuiButton>
160
- <WfoTextAnchor
161
- text={t('removeFilter')}
162
- onClick={() => {
163
- onUpdateQueryBuilder(false);
164
- // we call with ruleGroup: false explictly to
165
- // avoid state not having caught up yet when searching
166
- handleSearch({ ruleGroup: false });
167
- setIsFilterBuilderVisible(false);
168
- }}
169
- />
170
- </EuiFlexGroup>
170
+ }
171
+ }}
172
+ isInvalid={!isValidFilterString}
173
+ />
174
+ </EuiFlexItem>
175
+
176
+ <EuiFlexGroup direction={'rowReverse'} alignItems={'center'}>
177
+ <EuiButton
178
+ onClick={() => {
179
+ handleSearch();
180
+ }}
181
+ id={'button-apply-filter'}
182
+ data-test-id={'button-apply-filter'}
183
+ fill
184
+ type="submit"
185
+ aria-label={t('applyFilter')}
186
+ disabled={!isValidFilterString}
187
+ >
188
+ {t('applyFilter')}
189
+ </EuiButton>
190
+ <WfoTextAnchor
191
+ text={t('removeFilter')}
192
+ onClick={() => {
193
+ onUpdateQueryBuilder(false);
194
+ // we call with ruleGroup: false explictly to
195
+ // avoid state not having caught up yet when searching
196
+ handleSearch({ ruleGroup: false });
197
+ onToggleFilterBuilder(false);
198
+ }}
199
+ />
171
200
  </EuiFlexGroup>
172
- )) || (
173
- <EuiButton
174
- css={toggleButtonStyles}
175
- onClick={() => setIsFilterBuilderVisible(true)}
176
- id={'button-toggle-filter-builder'}
177
- data-test-id={'button-toggle-filter-builder'}
178
- fill
179
- type="submit"
180
- iconType="filter"
181
- iconSide="left"
182
- aria-label={t('createFilter')}
183
- >
184
- {t('createFilter')}
185
- </EuiButton>
186
- )}
201
+ </EuiFlexGroup>
187
202
  </EuiFlexGroup>
188
203
  );
189
204
  };
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import type { CombinatorSelectorProps } from 'react-querybuilder';
3
+
4
+ import { getWfoStructuredSearchTableStyles } from '@/components/WfoTable/WfoStructuredSearchTable/styles';
5
+ import { useWithOrchestratorTheme } from '@/hooks';
6
+
7
+ import { WfoCombinatorSelector } from './WfoCombinatorSelector';
8
+
9
+ export const WfoInlineCombinator = (props: CombinatorSelectorProps) => {
10
+ const { inlineCombinatorStyles } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
11
+
12
+ return (
13
+ <div css={inlineCombinatorStyles}>
14
+ <WfoCombinatorSelector {...props} />
15
+ </div>
16
+ );
17
+ };
@@ -1,5 +1,6 @@
1
- import React, { useEffect, useMemo } from 'react';
1
+ import React, { useEffect, useMemo, useRef } from 'react';
2
2
  import type { FullOperator, OperatorSelectorProps, OptionGroup } from 'react-querybuilder';
3
+ import { defaultOperators } from 'react-querybuilder';
3
4
 
4
5
  import { EuiSelect } from '@elastic/eui';
5
6
 
@@ -7,6 +8,8 @@ const isOptionGroup = (operator: FullOperator | OptionGroup<FullOperator>): oper
7
8
  'options' in operator;
8
9
 
9
10
  export const WfoOperatorSelector = (props: OperatorSelectorProps) => {
11
+ const { value, handleOnChange } = props;
12
+
10
13
  const flatOptions = (props.options as Array<FullOperator | OptionGroup<FullOperator>>).flatMap((option) =>
11
14
  isOptionGroup(option) ? option.options : [option],
12
15
  );
@@ -16,17 +19,39 @@ export const WfoOperatorSelector = (props: OperatorSelectorProps) => {
16
19
  [flatOptions],
17
20
  );
18
21
 
22
+ const optionsKey = selectOptions.map((option) => option.value).join('|');
23
+ const previousOptionsKeyRef = useRef(optionsKey);
24
+
19
25
  useEffect(() => {
20
- if (props.options && !props.value && selectOptions.length > 0) {
21
- props.handleOnChange(selectOptions[0].value);
26
+ const optionsChanged = previousOptionsKeyRef.current !== optionsKey;
27
+ previousOptionsKeyRef.current = optionsKey;
28
+
29
+ // Reset to the first option only when the field's operator list changes — i.e. the
30
+ // user picked a (different) field, and resetOnFieldChange=false on QueryBuilder
31
+ // preserved an operator that is not valid for it. The `optionsChanged` guard keeps
32
+ // rules restored from CEL (URL or textarea) intact on mount: parseCEL can produce
33
+ // operators outside the prefilled operator lists (e.g. beginsWith), and resetting
34
+ // those here would silently rewrite the user's filter string.
35
+ if (!optionsChanged || selectOptions.length === 0) return;
36
+ const currentValueIsValid = selectOptions.some((option) => option.value === value);
37
+ if (!currentValueIsValid) {
38
+ handleOnChange(selectOptions[0].value);
22
39
  }
23
- }, [props, props.options, props.value, selectOptions]);
40
+ }, [optionsKey, selectOptions, value, handleOnChange]);
41
+
42
+ // A restored operator that falls outside the field's list must still be visible in
43
+ // the dropdown; without it EuiSelect renders an empty selection for the rule.
44
+ const currentValueIsListed = !value || selectOptions.some((option) => option.value === value);
45
+ const displayOptions =
46
+ currentValueIsListed ? selectOptions : (
47
+ [...selectOptions, { value, text: defaultOperators.find((operator) => operator.name === value)?.label ?? value }]
48
+ );
24
49
 
25
50
  return (
26
51
  <EuiSelect
27
- options={selectOptions}
28
- value={props.value}
29
- onChange={(e) => props.handleOnChange(e.target.value)}
52
+ options={displayOptions}
53
+ value={value}
54
+ onChange={(e) => handleOnChange(e.target.value)}
30
55
  disabled={props.disabled}
31
56
  />
32
57
  );
@@ -6,15 +6,15 @@ import { useTranslations } from 'next-intl';
6
6
  import { EuiFlexItem } from '@elastic/eui';
7
7
 
8
8
  import { useOrchestratorTheme } from '@/hooks';
9
- import { WfoXMarkSmall } from '@/icons/WfoXMarkSmall';
9
+ import { WfoTrashFilled } from '@/icons';
10
10
 
11
11
  export const WfoRemoveRuleAction = (props: ActionProps) => {
12
12
  const { theme } = useOrchestratorTheme();
13
13
 
14
14
  const t = useTranslations('search.page');
15
15
  return (
16
- <EuiFlexItem onClick={props.handleOnClick} css={{ cursor: 'pointer' }}>
17
- <WfoXMarkSmall color={theme.colors.primary} aria-label={t('removeRule')} />
16
+ <EuiFlexItem onClick={props.handleOnClick} css={{ cursor: 'pointer', paddingRight: theme.size.s }}>
17
+ <WfoTrashFilled color={theme.colors.textPrimary} aria-label={t('removeRule')} />
18
18
  </EuiFlexItem>
19
19
  );
20
20
  };
@@ -13,35 +13,39 @@ import { WfoRemoveGroupAction } from './WfoRemoveGroupAction';
13
13
 
14
14
  export const WfoRuleGroup = (props: RuleGroupProps) => {
15
15
  const ruleGroupProps = useRuleGroup(props);
16
- const ruleId = ruleGroupProps.ruleGroup.id;
16
+ const rulePath = ruleGroupProps.path;
17
+ const isRootGroup: boolean = !rulePath || rulePath.length === 0;
17
18
 
18
19
  const {
19
20
  ruleGroupContainerBlueStyles,
20
21
  ruleGroupContainerWhiteStyles,
21
22
  innerGroupContainerWhiteStyles,
22
23
  innerGroupContainerBlueStyles,
24
+ ruleGroupBodyGridStyles,
23
25
  } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
24
26
  const getGroupContainerStyles = () => {
25
27
  if (ruleGroupProps.path.length % 2) {
26
- return ruleId !== 'root' ? innerGroupContainerWhiteStyles : ruleGroupContainerWhiteStyles;
28
+ return !isRootGroup ? innerGroupContainerWhiteStyles : ruleGroupContainerWhiteStyles;
27
29
  } else {
28
- return ruleId !== 'root' ? innerGroupContainerBlueStyles : ruleGroupContainerBlueStyles;
30
+ return !isRootGroup ? innerGroupContainerBlueStyles : ruleGroupContainerBlueStyles;
29
31
  }
30
32
  };
31
33
 
32
34
  const { addRule, path, schema, disabled, ruleGroup, addGroup } = ruleGroupProps;
33
35
 
34
36
  return (
35
- <EuiFlexGroup gutterSize={'none'} alignItems="center">
37
+ <EuiFlexGroup gutterSize={'none'} responsive={false} alignItems="center">
36
38
  <EuiFlexItem>
37
- <EuiFlexGroup direction="column" gutterSize="s" css={getGroupContainerStyles()}>
39
+ <EuiFlexGroup direction="column" css={getGroupContainerStyles()}>
38
40
  <EuiFlexItem>
39
41
  <EuiFlexGroup gutterSize="none">
40
42
  <RuleGroupHeaderComponents {...ruleGroupProps} />
41
43
  </EuiFlexGroup>
42
44
  </EuiFlexItem>
43
45
  <EuiFlexItem>
44
- <RuleGroupBodyComponents {...ruleGroupProps} />
46
+ <div css={ruleGroupBodyGridStyles}>
47
+ <RuleGroupBodyComponents {...ruleGroupProps} />
48
+ </div>
45
49
  </EuiFlexItem>
46
50
  <EuiFlexItem>
47
51
  <WfoAddRuleAction
@@ -67,7 +71,7 @@ export const WfoRuleGroup = (props: RuleGroupProps) => {
67
71
  </EuiFlexItem>
68
72
  </EuiFlexGroup>
69
73
  </EuiFlexItem>
70
- {ruleId !== 'root' && <WfoRemoveGroupAction onClick={ruleGroupProps.removeGroup} />}
74
+ {!isRootGroup && <WfoRemoveGroupAction onClick={ruleGroupProps.removeGroup} />}
71
75
  </EuiFlexGroup>
72
76
  );
73
77
  };
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+
3
+ import { useTranslations } from 'next-intl';
4
+
5
+ import { EuiButtonIcon, EuiFieldSearch, EuiFlexItem, EuiFormRow } from '@elastic/eui';
6
+
7
+ import { useWithOrchestratorTheme } from '@/hooks';
8
+ import { getFormFieldsBaseStyle } from '@/theme';
9
+
10
+ export type SearchFieldWithActionsProps = {
11
+ queryText?: string;
12
+ onChangeQueryText: (queryText: string) => void;
13
+ onSearchQueryText: (queryText: string) => void;
14
+ onShowInformation: () => void;
15
+ onShowTableSettings: () => void;
16
+ };
17
+
18
+ // Search field with the info and table-settings actions, rendered as EuiFlexItems inside an EuiFlexGroup.
19
+ export const WfoSearchFieldWithActions = ({
20
+ queryText,
21
+ onChangeQueryText,
22
+ onSearchQueryText,
23
+ onShowInformation,
24
+ onShowTableSettings,
25
+ }: SearchFieldWithActionsProps) => {
26
+ const t = useTranslations('common');
27
+ const { formFieldBaseStyle } = useWithOrchestratorTheme(getFormFieldsBaseStyle);
28
+
29
+ return (
30
+ <>
31
+ <EuiFlexItem>
32
+ <EuiFormRow fullWidth>
33
+ <EuiFieldSearch
34
+ css={formFieldBaseStyle}
35
+ value={queryText}
36
+ placeholder={`${t('search')}...`}
37
+ onChange={(e) => onChangeQueryText(e.target.value)}
38
+ onSearch={(queryText) => onSearchQueryText(queryText)}
39
+ fullWidth
40
+ />
41
+ </EuiFormRow>
42
+ </EuiFlexItem>
43
+ <EuiFlexItem grow={false}>
44
+ <EuiButtonIcon
45
+ onClick={onShowInformation}
46
+ iconSize={'l'}
47
+ iconType={'info'}
48
+ aria-label={t('searchModalTitle')}
49
+ />
50
+ </EuiFlexItem>
51
+ <EuiFlexItem grow={false}>
52
+ <EuiButtonIcon onClick={onShowTableSettings} iconSize={'l'} iconType={'gear'} aria-label={t('tableSettings')} />
53
+ </EuiFlexItem>
54
+ </>
55
+ );
56
+ };