@orchestrator-ui/orchestrator-ui-components 8.4.5 → 8.5.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 (69) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/.turbo/turbo-test.log +7 -7
  4. package/CHANGELOG.md +11 -0
  5. package/dist/index.d.ts +1890 -562
  6. package/dist/index.js +3814 -2103
  7. package/dist/index.js.map +1 -1
  8. package/package.json +2 -1
  9. package/src/components/WfoPydanticForm/WfoPydanticForm.tsx +23 -1
  10. package/src/components/WfoSearchBar/WfoSearchField.tsx +0 -1
  11. package/src/components/WfoSearchPage/WfoFilterGroup/WfoFilterGroup.tsx +5 -5
  12. package/src/components/WfoSearchPage/WfoSearch/WfoSearch.tsx +12 -5
  13. package/src/components/WfoSearchPage/constants.ts +0 -4
  14. package/src/components/WfoSearchPage/utils.ts +75 -20
  15. package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActionExpandableMenuItem.tsx +36 -18
  16. package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActionsMenuItem.tsx +38 -2
  17. package/src/components/WfoSubscription/utils/index.ts +3 -0
  18. package/src/components/WfoSubscription/utils/utils.spec.ts +39 -4
  19. package/src/components/WfoSubscription/utils/utils.ts +10 -4
  20. package/src/components/WfoTable/WfoStructuredSearchTable/WfoAddGroupAction.tsx +19 -0
  21. package/src/components/WfoTable/WfoStructuredSearchTable/WfoAddRuleAction.tsx +23 -0
  22. package/src/components/WfoTable/WfoStructuredSearchTable/WfoCombinatorSelector.tsx +30 -0
  23. package/src/components/WfoTable/WfoStructuredSearchTable/WfoExpandingSearchRow.tsx +38 -0
  24. package/src/components/WfoTable/WfoStructuredSearchTable/WfoFieldSelector.tsx +84 -0
  25. package/src/components/WfoTable/WfoStructuredSearchTable/WfoFilterBuilder.tsx +189 -0
  26. package/src/components/WfoTable/WfoStructuredSearchTable/WfoOperatorSelector.tsx +33 -0
  27. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRangeEditor.tsx +64 -0
  28. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRemoveGroupAction.tsx +21 -0
  29. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRemoveRuleAction.tsx +20 -0
  30. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRule.tsx +16 -0
  31. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRuleGroup.tsx +73 -0
  32. package/src/components/WfoTable/WfoStructuredSearchTable/WfoStructuredSearchTable.tsx +323 -0
  33. package/src/components/WfoTable/WfoStructuredSearchTable/WfoValueEditor.tsx +159 -0
  34. package/src/components/WfoTable/WfoStructuredSearchTable/index.ts +2 -0
  35. package/src/components/WfoTable/WfoStructuredSearchTable/styles.ts +146 -0
  36. package/src/components/WfoTable/WfoTable/WfoDragHandler.tsx +4 -2
  37. package/src/components/WfoTable/index.ts +2 -6
  38. package/src/components/WfoTitleWithWebsocketBadge/WfoTitleWithWebsocketBadge.tsx +14 -6
  39. package/src/components/WfoWorkflowSteps/WfoStep/WfoStep.tsx +1 -0
  40. package/src/components/WfoWorkflowSteps/WfoStepList/WfoStepList.tsx +3 -0
  41. package/src/components/WfoWorkflowSteps/WfoWorkflowStepList/WfoWorkflowStepList.tsx +32 -12
  42. package/src/components/WfoWorkflowUserGuide/WfoPageWithUserGuide.tsx +38 -0
  43. package/src/components/WfoWorkflowUserGuide/WfoWorkflowGuideExpandablePanel.tsx +151 -0
  44. package/src/components/WfoWorkflowUserGuide/index.ts +2 -0
  45. package/src/components/WfoWorkflowUserGuide/styles.ts +87 -0
  46. package/src/components/index.ts +1 -0
  47. package/src/configuration/version.ts +1 -1
  48. package/src/contexts/OrchestratorConfigContext.tsx +1 -0
  49. package/src/hooks/index.ts +1 -0
  50. package/src/hooks/usePathAutoComplete.ts +3 -4
  51. package/src/hooks/useSearch.ts +20 -15
  52. package/src/hooks/useSearchPagination.ts +11 -8
  53. package/src/hooks/useUrlParams.ts +3 -5
  54. package/src/icons/WfoTrashFilled.tsx +13 -0
  55. package/src/icons/WfoXMarkSmall.tsx +2 -2
  56. package/src/icons/index.ts +1 -0
  57. package/src/messages/en-GB.json +94 -8
  58. package/src/messages/nl-NL.json +23 -5
  59. package/src/pages/WfoSearchPocPage.tsx +402 -0
  60. package/src/pages/index.ts +1 -0
  61. package/src/pages/processes/WfoProcessDetail.tsx +10 -10
  62. package/src/pages/processes/WfoProcessDetailPage.tsx +1 -0
  63. package/src/pages/processes/WfoStartProcessPage.tsx +15 -19
  64. package/src/rtk/api.ts +1 -0
  65. package/src/rtk/endpoints/index.ts +1 -0
  66. package/src/rtk/endpoints/search.ts +45 -10
  67. package/src/rtk/endpoints/workflowGuides.ts +25 -0
  68. package/src/types/search.ts +21 -5
  69. package/src/types/types.ts +10 -1
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import type { CombinatorSelectorProps } from 'react-querybuilder';
3
+
4
+ import { EuiButtonGroup } from '@elastic/eui';
5
+
6
+ import { getWfoStructuredSearchTableStyles } from '@/components/WfoTable/WfoStructuredSearchTable/styles';
7
+ import { useWithOrchestratorTheme } from '@/hooks';
8
+
9
+ export const WfoCombinatorSelector = (props: CombinatorSelectorProps) => {
10
+ const { buttonGroupStyles } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
11
+ const options = props.options.map((option) => ({
12
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
13
+ // @ts-ignore This seems to be a typing error in the react-querybuilde library. Option.name does exist
14
+ id: option.name,
15
+ label: option.label,
16
+ }));
17
+
18
+ return (
19
+ <EuiButtonGroup
20
+ css={buttonGroupStyles}
21
+ legend="Combinator"
22
+ type="single"
23
+ options={options}
24
+ idSelected={props.value || options[0].id}
25
+ onChange={(id) => props.handleOnChange(id)}
26
+ buttonSize="m"
27
+ color="primary"
28
+ />
29
+ );
30
+ };
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+
3
+ import { useWithOrchestratorTheme } from '@/hooks';
4
+ import type { MatchingField } from '@/types';
5
+
6
+ import { getWfoStructuredSearchTableStyles } from './styles';
7
+
8
+ interface WfoExpandingSearchRowProps {
9
+ score?: number;
10
+ perfectMatch?: number;
11
+ matchingField?: MatchingField | null;
12
+ }
13
+
14
+ export const WfoExpandingSearchRow = ({ score, matchingField }: WfoExpandingSearchRowProps) => {
15
+ const { expandingSearchRowStyles, expandingRowBodyStyles } = useWithOrchestratorTheme(
16
+ getWfoStructuredSearchTableStyles,
17
+ );
18
+
19
+ if (!matchingField) return null;
20
+
21
+ const { path, text } = matchingField;
22
+
23
+ return (
24
+ <tr>
25
+ <td colSpan={999} css={expandingSearchRowStyles}>
26
+ <div css={expandingRowBodyStyles}>
27
+ <div>
28
+ <span>{path}</span> {text}
29
+ </div>
30
+ <span>•</span>
31
+ <div>
32
+ <span>score</span> {score !== undefined && `${(score * 100).toFixed(1)}%`}
33
+ </div>
34
+ </div>
35
+ </td>
36
+ </tr>
37
+ );
38
+ };
@@ -0,0 +1,84 @@
1
+ import React, { useState } from 'react';
2
+ import { FieldSelectorProps } from 'react-querybuilder';
3
+
4
+ import { useTranslations } from 'next-intl';
5
+
6
+ import type { EuiComboBoxOptionOption } from '@elastic/eui';
7
+ import { EuiComboBox } from '@elastic/eui';
8
+
9
+ import { usePathAutocomplete } from '@/hooks';
10
+ import { EntityKind, PathInfo } from '@/types';
11
+
12
+ export const WfoFieldSelector = ({ handleOnChange, disabled, rule, context }: FieldSelectorProps) => {
13
+ const { field } = rule;
14
+ const [selectedValue, setSelectedValue] = useState<string>(field);
15
+ const t = useTranslations('search.page');
16
+ const getOption = (path: string) => ({
17
+ value: path,
18
+ label: path,
19
+ });
20
+ const getOptionsFromPathInfo = (pathInfos: PathInfo[]): EuiComboBoxOptionOption<string>[] => {
21
+ const pathOptions: EuiComboBoxOptionOption<string>[] = [];
22
+
23
+ pathInfos.forEach((pathInfo) => {
24
+ pathOptions.push(getOption(pathInfo.path));
25
+ // Adds more specific paths
26
+ pathInfo.availablePaths?.forEach((path) => {
27
+ pathOptions.push(getOption(path));
28
+ });
29
+ });
30
+ return (
31
+ pathOptions.length > 0 ? pathOptions
32
+ : selectedValue ? [getOption(selectedValue)]
33
+ : []
34
+ );
35
+ };
36
+
37
+ const {
38
+ paths,
39
+ loading: isLoading,
40
+ error: errorMessage,
41
+ } = usePathAutocomplete(selectedValue, EntityKind.SUBSCRIPTION);
42
+
43
+ const options = getOptionsFromPathInfo(paths);
44
+
45
+ const storeFieldOperators = (selectedValue: string) => {
46
+ const matchingPath =
47
+ paths.find((path) => path.path === selectedValue)
48
+ ?? paths.find((path) => path.availablePaths?.includes(selectedValue));
49
+
50
+ context?.onFieldSelected?.(selectedValue, matchingPath);
51
+ };
52
+
53
+ const handleFieldSelection = (selectedOptions: EuiComboBoxOptionOption<string>[]) => {
54
+ const selectedOption = selectedOptions[0];
55
+ const selectedValue = selectedOption?.value || '';
56
+ setSelectedValue(selectedValue);
57
+ storeFieldOperators(selectedValue);
58
+
59
+ handleOnChange(selectedValue);
60
+ };
61
+
62
+ return (
63
+ <EuiComboBox
64
+ placeholder={t('searchFieldsPlaceholder')}
65
+ options={options}
66
+ fullWidth={true}
67
+ selectedOptions={options.filter((option) => option.value === selectedValue)}
68
+ onChange={(selectedOptions) => {
69
+ handleFieldSelection(selectedOptions);
70
+ }}
71
+ onSearchChange={(inputValue) => {
72
+ if (inputValue.length > 0) {
73
+ setSelectedValue(inputValue);
74
+ }
75
+ }}
76
+ singleSelection={{ asPlainText: true }}
77
+ isLoading={isLoading}
78
+ isClearable
79
+ isInvalid={!!errorMessage}
80
+ isDisabled={disabled}
81
+ rowHeight={30}
82
+ />
83
+ );
84
+ };
@@ -0,0 +1,189 @@
1
+ import React, { useState } from 'react';
2
+ import { FullOperator, QueryBuilder, type RuleGroupType } from 'react-querybuilder';
3
+ import 'react-querybuilder/dist/query-builder.css';
4
+
5
+ import { useTranslations } from 'next-intl';
6
+
7
+ import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiTextArea } from '@elastic/eui';
8
+
9
+ import { SearchParams, WfoTextAnchor } from '@/components';
10
+ import { WfoCombinatorSelector } from '@/components/WfoTable/WfoStructuredSearchTable/WfoCombinatorSelector';
11
+ import { useWithOrchestratorTheme } from '@/hooks';
12
+ import { OperatorDisplay, PathInfo } from '@/types';
13
+
14
+ import { WfoFieldSelector } from './WfoFieldSelector';
15
+ import { WfoOperatorSelector } from './WfoOperatorSelector';
16
+ import { WfoRemoveRuleAction } from './WfoRemoveRuleAction';
17
+ import { WfoRule } from './WfoRule';
18
+ import { WfoRuleGroup } from './WfoRuleGroup';
19
+ import { WfoValueEditor } from './WfoValueEditor';
20
+ import { getWfoStructuredSearchTableStyles } from './styles';
21
+
22
+ // Maps PathInfo operator names to react-querybuilder's native operator names,
23
+ // which is what parseCEL produces and formatQuery(cel) expects.
24
+ const SEARCH_OPERATOR_TO_RQB_OPERATOR_MAP: Record<string, string> = {
25
+ eq: '=',
26
+ neq: '!=',
27
+ lt: '<',
28
+ lte: '<=',
29
+ gt: '>',
30
+ gte: '>=',
31
+ between: 'between',
32
+ like: 'contains',
33
+ };
34
+
35
+ const OPERATOR_MAP: Record<string, OperatorDisplay> = {
36
+ eq: { symbol: '=', description: 'equals' },
37
+ neq: { symbol: '≠', description: 'not equals' },
38
+ lt: { symbol: '<', description: 'less than' },
39
+ lte: { symbol: '≤', description: 'less than or equal to' },
40
+ gt: { symbol: '>', description: 'greater than' },
41
+ gte: { symbol: '≥', description: 'greater than or equal to' },
42
+ between: { symbol: '⟷', description: 'between (range)' },
43
+ has_component: { symbol: '✓', description: 'has component' },
44
+ not_has_component: { symbol: '✗', description: 'does not have component' },
45
+ like: { symbol: '∋', description: 'contains' },
46
+ };
47
+
48
+ /* TODO: Add the missing operators
49
+ ['has_component', 'not_has_component'];
50
+ */
51
+ type FieldPathInfoMap = Map<string, PathInfo>;
52
+
53
+ interface WfoFilterBuilderProps {
54
+ filterString?: string;
55
+ onUpdateFilterString: (filterString: string) => void;
56
+ isValidFilterString?: boolean;
57
+ queryBuilderRuleGroup?: RuleGroupType;
58
+ onUpdateQueryBuilder: (ruleGroup: RuleGroupType | false) => void;
59
+ handleSearch: (searchParams?: SearchParams) => void;
60
+ }
61
+
62
+ const initialRuleGroup: RuleGroupType = {
63
+ id: 'root',
64
+ rules: [{ id: 'rule-0', field: '~', operator: '=', value: '' }],
65
+ combinator: 'and',
66
+ };
67
+
68
+ export const WfoFilterBuilder = ({
69
+ filterString,
70
+ onUpdateFilterString,
71
+ isValidFilterString = true,
72
+ queryBuilderRuleGroup = initialRuleGroup,
73
+ onUpdateQueryBuilder,
74
+ handleSearch,
75
+ }: WfoFilterBuilderProps) => {
76
+ const getOperatorsFromPathInfo = (fieldInfo?: PathInfo): FullOperator[] => {
77
+ return (fieldInfo?.operators ?? []).map((operator) => {
78
+ const { symbol, description } = OPERATOR_MAP[operator] || { symbol: operator, description: operator };
79
+ const rqbOperator = SEARCH_OPERATOR_TO_RQB_OPERATOR_MAP[operator] ?? operator;
80
+ return { name: rqbOperator, label: `${symbol} ${description}`, value: rqbOperator };
81
+ });
82
+ };
83
+
84
+ 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
+ }
97
+ };
98
+
99
+ return (
100
+ <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={() => {
149
+ 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>
171
+ </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
+ )}
187
+ </EuiFlexGroup>
188
+ );
189
+ };
@@ -0,0 +1,33 @@
1
+ import React, { useEffect, useMemo } from 'react';
2
+ import type { FullOperator, OperatorSelectorProps, OptionGroup } from 'react-querybuilder';
3
+
4
+ import { EuiSelect } from '@elastic/eui';
5
+
6
+ const isOptionGroup = (operator: FullOperator | OptionGroup<FullOperator>): operator is OptionGroup<FullOperator> =>
7
+ 'options' in operator;
8
+
9
+ export const WfoOperatorSelector = (props: OperatorSelectorProps) => {
10
+ const flatOptions = (props.options as Array<FullOperator | OptionGroup<FullOperator>>).flatMap((option) =>
11
+ isOptionGroup(option) ? option.options : [option],
12
+ );
13
+
14
+ const selectOptions = useMemo(
15
+ () => flatOptions.map((option) => ({ value: option.name, text: option.label })),
16
+ [flatOptions],
17
+ );
18
+
19
+ useEffect(() => {
20
+ if (props.options && !props.value && selectOptions.length > 0) {
21
+ props.handleOnChange(selectOptions[0].value);
22
+ }
23
+ }, [props, props.options, props.value, selectOptions]);
24
+
25
+ return (
26
+ <EuiSelect
27
+ options={selectOptions}
28
+ value={props.value}
29
+ onChange={(e) => props.handleOnChange(e.target.value)}
30
+ disabled={props.disabled}
31
+ />
32
+ );
33
+ };
@@ -0,0 +1,64 @@
1
+ import React, { useEffect, useState } from 'react';
2
+
3
+ import { EuiFlexGroup } from '@elastic/eui';
4
+
5
+ export interface WfoRangeElementProps {
6
+ handleOnChange: (value: string | number | undefined, rangeIndex?: number) => void;
7
+ value: string;
8
+ operator?: string;
9
+ rangeIndex?: number;
10
+ }
11
+
12
+ interface WfoRangeEditorProps {
13
+ handleOnChange: (value: string | number | undefined, rangeIndex?: number) => void;
14
+ operator: string;
15
+ value: string;
16
+ Element: React.ComponentType<WfoRangeElementProps>;
17
+ }
18
+
19
+ export const WfoRangeEditor = ({ handleOnChange, operator, Element, value: currentValue }: WfoRangeEditorProps) => {
20
+ const [currentOperator, setCurrentOperator] = useState(operator);
21
+ const startValue = currentValue ? currentValue?.toString().split(',') : [];
22
+ const [value, setValue] = useState<string[]>(startValue);
23
+
24
+ useEffect(() => {
25
+ if (operator !== currentOperator && (operator === 'between' || currentOperator === 'between')) {
26
+ setValue([]);
27
+ handleOnChange('');
28
+ setCurrentOperator(operator);
29
+ }
30
+ }, [currentOperator, handleOnChange, operator]);
31
+
32
+ const handleChange = (value: string | number | undefined, rangeIndex: number = 0) => {
33
+ if (operator === 'between') {
34
+ setValue((currentDates) => {
35
+ // remove value if set to undefined
36
+ if (value === null) {
37
+ return currentDates.filter((_, index) => index !== rangeIndex);
38
+ }
39
+ // add value at supplied index
40
+ currentDates[rangeIndex] = value as string;
41
+
42
+ // call the parent if 2 values are present
43
+ if (currentDates.length === 2) {
44
+ handleOnChange(`${currentDates[0]},${currentDates[1]}`);
45
+ }
46
+
47
+ return currentDates;
48
+ });
49
+ } else {
50
+ handleOnChange(value);
51
+ }
52
+ };
53
+
54
+ if (operator === 'between') {
55
+ return (
56
+ <EuiFlexGroup direction="row" gutterSize="s">
57
+ <Element handleOnChange={handleChange} rangeIndex={0} value={value[0]} />
58
+ <Element handleOnChange={handleChange} rangeIndex={1} value={value[1]} />
59
+ </EuiFlexGroup>
60
+ );
61
+ }
62
+
63
+ return <Element handleOnChange={handleOnChange} value={value[0]} />;
64
+ };
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+
3
+ import { useTranslations } from 'next-intl';
4
+
5
+ import { EuiFlexItem } from '@elastic/eui';
6
+
7
+ import { getWfoStructuredSearchTableStyles } from '@/components/WfoTable/WfoStructuredSearchTable/styles';
8
+ import { useWithOrchestratorTheme } from '@/hooks';
9
+ import { useOrchestratorTheme } from '@/hooks';
10
+ import { WfoTrashFilled } from '@/icons';
11
+
12
+ export const WfoRemoveGroupAction = ({ onClick }: { onClick: () => void }) => {
13
+ const { removeGroupActionStyles } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
14
+ const { theme } = useOrchestratorTheme();
15
+ const t = useTranslations('search.page');
16
+ return (
17
+ <EuiFlexItem grow={0} css={removeGroupActionStyles} onClick={() => onClick()}>
18
+ <WfoTrashFilled color={theme.colors.textPrimary} aria-label={t('removeGroup')} />
19
+ </EuiFlexItem>
20
+ );
21
+ };
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import type { ActionProps } from 'react-querybuilder';
3
+
4
+ import { useTranslations } from 'next-intl';
5
+
6
+ import { EuiFlexItem } from '@elastic/eui';
7
+
8
+ import { useOrchestratorTheme } from '@/hooks';
9
+ import { WfoXMarkSmall } from '@/icons/WfoXMarkSmall';
10
+
11
+ export const WfoRemoveRuleAction = (props: ActionProps) => {
12
+ const { theme } = useOrchestratorTheme();
13
+
14
+ const t = useTranslations('search.page');
15
+ return (
16
+ <EuiFlexItem onClick={props.handleOnClick} css={{ cursor: 'pointer' }}>
17
+ <WfoXMarkSmall color={theme.colors.primary} aria-label={t('removeRule')} />
18
+ </EuiFlexItem>
19
+ );
20
+ };
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import type { RuleProps } from 'react-querybuilder';
3
+ import { Rule } from 'react-querybuilder';
4
+
5
+ import { getWfoStructuredSearchTableStyles } from '@/components/WfoTable/WfoStructuredSearchTable/styles';
6
+ import { useWithOrchestratorTheme } from '@/hooks';
7
+
8
+ export const WfoRule = (props: RuleProps) => {
9
+ const { ruleContainerStyles } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
10
+
11
+ return (
12
+ <div css={ruleContainerStyles}>
13
+ <Rule {...props} />
14
+ </div>
15
+ );
16
+ };
@@ -0,0 +1,73 @@
1
+ import React from 'react';
2
+ import type { RuleGroupProps } from 'react-querybuilder';
3
+ import { RuleGroupBodyComponents, RuleGroupHeaderComponents, useRuleGroup } from 'react-querybuilder';
4
+
5
+ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
6
+
7
+ import { getWfoStructuredSearchTableStyles } from '@/components/WfoTable/WfoStructuredSearchTable/styles';
8
+ import { useWithOrchestratorTheme } from '@/hooks';
9
+
10
+ import { WfoAddGroupAction } from './WfoAddGroupAction';
11
+ import { WfoAddRuleAction } from './WfoAddRuleAction';
12
+ import { WfoRemoveGroupAction } from './WfoRemoveGroupAction';
13
+
14
+ export const WfoRuleGroup = (props: RuleGroupProps) => {
15
+ const ruleGroupProps = useRuleGroup(props);
16
+ const ruleId = ruleGroupProps.ruleGroup.id;
17
+
18
+ const {
19
+ ruleGroupContainerBlueStyles,
20
+ ruleGroupContainerWhiteStyles,
21
+ innerGroupContainerWhiteStyles,
22
+ innerGroupContainerBlueStyles,
23
+ } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
24
+ const getGroupContainerStyles = () => {
25
+ if (ruleGroupProps.path.length % 2) {
26
+ return ruleId !== 'root' ? innerGroupContainerWhiteStyles : ruleGroupContainerWhiteStyles;
27
+ } else {
28
+ return ruleId !== 'root' ? innerGroupContainerBlueStyles : ruleGroupContainerBlueStyles;
29
+ }
30
+ };
31
+
32
+ const { addRule, path, schema, disabled, ruleGroup, addGroup } = ruleGroupProps;
33
+
34
+ return (
35
+ <EuiFlexGroup gutterSize={'none'} alignItems="center">
36
+ <EuiFlexItem>
37
+ <EuiFlexGroup direction="column" gutterSize="s" css={getGroupContainerStyles()}>
38
+ <EuiFlexItem>
39
+ <EuiFlexGroup gutterSize="none">
40
+ <RuleGroupHeaderComponents {...ruleGroupProps} />
41
+ </EuiFlexGroup>
42
+ </EuiFlexItem>
43
+ <EuiFlexItem>
44
+ <RuleGroupBodyComponents {...ruleGroupProps} />
45
+ </EuiFlexItem>
46
+ <EuiFlexItem>
47
+ <WfoAddRuleAction
48
+ handleOnClick={addRule}
49
+ path={path}
50
+ level={path.length}
51
+ schema={schema}
52
+ disabled={disabled ?? false}
53
+ ruleOrGroup={ruleGroup}
54
+ rules={ruleGroup.rules}
55
+ />
56
+ </EuiFlexItem>
57
+ <EuiFlexItem>
58
+ <WfoAddGroupAction
59
+ handleOnClick={addGroup}
60
+ path={path}
61
+ level={path.length}
62
+ schema={schema}
63
+ disabled={disabled ?? false}
64
+ ruleOrGroup={ruleGroup}
65
+ rules={ruleGroup.rules}
66
+ />
67
+ </EuiFlexItem>
68
+ </EuiFlexGroup>
69
+ </EuiFlexItem>
70
+ {ruleId !== 'root' && <WfoRemoveGroupAction onClick={ruleGroupProps.removeGroup} />}
71
+ </EuiFlexGroup>
72
+ );
73
+ };