@orchestrator-ui/orchestrator-ui-components 8.4.4 → 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.
- package/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-lint.log +1 -1
- package/.turbo/turbo-test.log +7 -7
- package/CHANGELOG.md +17 -0
- package/dist/index.d.ts +1890 -562
- package/dist/index.js +3814 -2103
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/components/WfoPydanticForm/WfoPydanticForm.tsx +23 -1
- package/src/components/WfoSearchBar/WfoSearchField.tsx +0 -1
- package/src/components/WfoSearchPage/WfoFilterGroup/WfoFilterGroup.tsx +5 -5
- package/src/components/WfoSearchPage/WfoSearch/WfoSearch.tsx +12 -5
- package/src/components/WfoSearchPage/constants.ts +0 -4
- package/src/components/WfoSearchPage/utils.ts +75 -20
- package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActionExpandableMenuItem.tsx +36 -18
- package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActionsMenuItem.tsx +38 -2
- package/src/components/WfoSubscription/utils/index.ts +3 -0
- package/src/components/WfoSubscription/utils/utils.spec.ts +39 -4
- package/src/components/WfoSubscription/utils/utils.ts +10 -4
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoAddGroupAction.tsx +19 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoAddRuleAction.tsx +23 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoCombinatorSelector.tsx +30 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoExpandingSearchRow.tsx +38 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoFieldSelector.tsx +84 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoFilterBuilder.tsx +189 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoOperatorSelector.tsx +33 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoRangeEditor.tsx +64 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoRemoveGroupAction.tsx +21 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoRemoveRuleAction.tsx +20 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoRule.tsx +16 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoRuleGroup.tsx +73 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoStructuredSearchTable.tsx +323 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoValueEditor.tsx +159 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/index.ts +2 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/styles.ts +146 -0
- package/src/components/WfoTable/WfoTable/WfoDragHandler.tsx +4 -2
- package/src/components/WfoTable/index.ts +2 -6
- package/src/components/WfoTitleWithWebsocketBadge/WfoTitleWithWebsocketBadge.tsx +14 -6
- package/src/components/WfoWorkflowSteps/WfoStep/WfoStep.tsx +1 -0
- package/src/components/WfoWorkflowSteps/WfoStepList/WfoStepList.tsx +3 -0
- package/src/components/WfoWorkflowSteps/WfoWorkflowStepList/WfoWorkflowStepList.tsx +32 -12
- package/src/components/WfoWorkflowUserGuide/WfoPageWithUserGuide.tsx +38 -0
- package/src/components/WfoWorkflowUserGuide/WfoWorkflowGuideExpandablePanel.tsx +151 -0
- package/src/components/WfoWorkflowUserGuide/index.ts +2 -0
- package/src/components/WfoWorkflowUserGuide/styles.ts +87 -0
- package/src/components/index.ts +1 -0
- package/src/configuration/version.ts +1 -1
- package/src/contexts/OrchestratorConfigContext.tsx +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/usePathAutoComplete.ts +3 -4
- package/src/hooks/useSearch.ts +20 -15
- package/src/hooks/useSearchPagination.ts +11 -8
- package/src/hooks/useUrlParams.ts +3 -5
- package/src/icons/WfoTrashFilled.tsx +13 -0
- package/src/icons/WfoXMarkSmall.tsx +2 -2
- package/src/icons/index.ts +1 -0
- package/src/messages/en-GB.json +94 -8
- package/src/messages/nl-NL.json +23 -5
- package/src/pages/WfoSearchPocPage.tsx +402 -0
- package/src/pages/index.ts +1 -0
- package/src/pages/processes/WfoProcessDetail.tsx +10 -10
- package/src/pages/processes/WfoProcessDetailPage.tsx +1 -0
- package/src/pages/processes/WfoStartProcessPage.tsx +15 -19
- package/src/rtk/api.ts +1 -0
- package/src/rtk/endpoints/index.ts +1 -0
- package/src/rtk/endpoints/search.ts +45 -10
- package/src/rtk/endpoints/workflowGuides.ts +25 -0
- package/src/types/search.ts +21 -5
- 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
|
+
};
|