@orchestrator-ui/orchestrator-ui-components 8.4.5 → 8.6.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 (77) hide show
  1. package/.turbo/turbo-build.log +10 -14
  2. package/.turbo/turbo-lint.log +2 -4
  3. package/.turbo/turbo-test.log +7 -9
  4. package/CHANGELOG.md +17 -0
  5. package/dist/index.d.ts +1968 -630
  6. package/dist/index.js +4389 -2362
  7. package/dist/index.js.map +1 -1
  8. package/package.json +2 -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/WfoPydanticForm.tsx +23 -1
  14. package/src/components/WfoSearchBar/WfoSearchField.tsx +0 -1
  15. package/src/components/WfoSearchPage/WfoFilterGroup/WfoFilterGroup.tsx +5 -5
  16. package/src/components/WfoSearchPage/WfoSearch/WfoSearch.tsx +12 -5
  17. package/src/components/WfoSearchPage/constants.ts +0 -4
  18. package/src/components/WfoSearchPage/utils.ts +75 -20
  19. package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActionExpandableMenuItem.tsx +36 -18
  20. package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActionsMenuItem.tsx +38 -2
  21. package/src/components/WfoSubscription/utils/index.ts +3 -0
  22. package/src/components/WfoSubscription/utils/utils.spec.ts +39 -4
  23. package/src/components/WfoSubscription/utils/utils.ts +10 -4
  24. package/src/components/WfoTable/WfoStructuredSearchTable/WfoAddGroupAction.tsx +19 -0
  25. package/src/components/WfoTable/WfoStructuredSearchTable/WfoAddRuleAction.tsx +23 -0
  26. package/src/components/WfoTable/WfoStructuredSearchTable/WfoCombinatorSelector.tsx +33 -0
  27. package/src/components/WfoTable/WfoStructuredSearchTable/WfoExpandingSearchRow.tsx +38 -0
  28. package/src/components/WfoTable/WfoStructuredSearchTable/WfoFieldSelector.tsx +138 -0
  29. package/src/components/WfoTable/WfoStructuredSearchTable/WfoFilterBuilder.tsx +198 -0
  30. package/src/components/WfoTable/WfoStructuredSearchTable/WfoInlineCombinator.tsx +17 -0
  31. package/src/components/WfoTable/WfoStructuredSearchTable/WfoOperatorSelector.tsx +33 -0
  32. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRangeEditor.tsx +64 -0
  33. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRemoveGroupAction.tsx +21 -0
  34. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRemoveRuleAction.tsx +20 -0
  35. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRule.tsx +16 -0
  36. package/src/components/WfoTable/WfoStructuredSearchTable/WfoRuleGroup.tsx +76 -0
  37. package/src/components/WfoTable/WfoStructuredSearchTable/WfoSearchFieldWithActions.tsx +56 -0
  38. package/src/components/WfoTable/WfoStructuredSearchTable/WfoStructuredSearchTable.tsx +326 -0
  39. package/src/components/WfoTable/WfoStructuredSearchTable/WfoValueEditor.tsx +159 -0
  40. package/src/components/WfoTable/WfoStructuredSearchTable/index.ts +2 -0
  41. package/src/components/WfoTable/WfoStructuredSearchTable/styles.ts +182 -0
  42. package/src/components/WfoTable/WfoStructuredSearchTable/utils.ts +45 -0
  43. package/src/components/WfoTable/WfoTable/WfoDragHandler.tsx +4 -2
  44. package/src/components/WfoTable/WfoTableSettingsModal/WfoTableSettingsModal.tsx +9 -0
  45. package/src/components/WfoTable/index.ts +2 -6
  46. package/src/components/WfoTitleWithWebsocketBadge/WfoTitleWithWebsocketBadge.tsx +14 -6
  47. package/src/components/WfoWorkflowSteps/WfoStep/WfoStep.tsx +1 -0
  48. package/src/components/WfoWorkflowSteps/WfoStepList/WfoStepList.tsx +3 -0
  49. package/src/components/WfoWorkflowSteps/WfoWorkflowStepList/WfoWorkflowStepList.tsx +32 -12
  50. package/src/components/WfoWorkflowUserGuide/WfoPageWithUserGuide.tsx +38 -0
  51. package/src/components/WfoWorkflowUserGuide/WfoWorkflowGuideExpandablePanel.tsx +151 -0
  52. package/src/components/WfoWorkflowUserGuide/index.ts +2 -0
  53. package/src/components/WfoWorkflowUserGuide/styles.ts +87 -0
  54. package/src/components/index.ts +2 -0
  55. package/src/configuration/version.ts +1 -1
  56. package/src/contexts/OrchestratorConfigContext.tsx +1 -0
  57. package/src/hooks/index.ts +1 -0
  58. package/src/hooks/usePathAutoComplete.ts +3 -4
  59. package/src/hooks/useSearch.ts +20 -15
  60. package/src/hooks/useSearchPagination.ts +11 -8
  61. package/src/hooks/useUrlParams.ts +3 -5
  62. package/src/icons/WfoTrashFilled.tsx +13 -0
  63. package/src/icons/WfoXMarkSmall.tsx +2 -2
  64. package/src/icons/index.ts +1 -0
  65. package/src/messages/en-GB.json +95 -8
  66. package/src/messages/nl-NL.json +24 -5
  67. package/src/pages/WfoSearchPocPage.tsx +528 -0
  68. package/src/pages/index.ts +1 -0
  69. package/src/pages/processes/WfoProcessDetail.tsx +10 -10
  70. package/src/pages/processes/WfoProcessDetailPage.tsx +1 -0
  71. package/src/pages/processes/WfoStartProcessPage.tsx +15 -19
  72. package/src/rtk/api.ts +1 -0
  73. package/src/rtk/endpoints/index.ts +1 -0
  74. package/src/rtk/endpoints/search.ts +45 -10
  75. package/src/rtk/endpoints/workflowGuides.ts +25 -0
  76. package/src/types/search.ts +24 -5
  77. package/src/types/types.ts +10 -1
@@ -0,0 +1,76 @@
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
+ ruleGroupBodyGridStyles,
24
+ } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
25
+ const getGroupContainerStyles = () => {
26
+ if (ruleGroupProps.path.length % 2) {
27
+ return ruleId !== 'root' ? innerGroupContainerWhiteStyles : ruleGroupContainerWhiteStyles;
28
+ } else {
29
+ return ruleId !== 'root' ? innerGroupContainerBlueStyles : ruleGroupContainerBlueStyles;
30
+ }
31
+ };
32
+
33
+ const { addRule, path, schema, disabled, ruleGroup, addGroup } = ruleGroupProps;
34
+
35
+ return (
36
+ <EuiFlexGroup gutterSize={'none'} responsive={false} alignItems="center">
37
+ <EuiFlexItem>
38
+ <EuiFlexGroup direction="column" css={getGroupContainerStyles()}>
39
+ <EuiFlexItem>
40
+ <EuiFlexGroup gutterSize="none">
41
+ <RuleGroupHeaderComponents {...ruleGroupProps} />
42
+ </EuiFlexGroup>
43
+ </EuiFlexItem>
44
+ <EuiFlexItem>
45
+ <div css={ruleGroupBodyGridStyles}>
46
+ <RuleGroupBodyComponents {...ruleGroupProps} />
47
+ </div>
48
+ </EuiFlexItem>
49
+ <EuiFlexItem>
50
+ <WfoAddRuleAction
51
+ handleOnClick={addRule}
52
+ path={path}
53
+ level={path.length}
54
+ schema={schema}
55
+ disabled={disabled ?? false}
56
+ ruleOrGroup={ruleGroup}
57
+ rules={ruleGroup.rules}
58
+ />
59
+ </EuiFlexItem>
60
+ <EuiFlexItem>
61
+ <WfoAddGroupAction
62
+ handleOnClick={addGroup}
63
+ path={path}
64
+ level={path.length}
65
+ schema={schema}
66
+ disabled={disabled ?? false}
67
+ ruleOrGroup={ruleGroup}
68
+ rules={ruleGroup.rules}
69
+ />
70
+ </EuiFlexItem>
71
+ </EuiFlexGroup>
72
+ </EuiFlexItem>
73
+ {ruleId !== 'root' && <WfoRemoveGroupAction onClick={ruleGroupProps.removeGroup} />}
74
+ </EuiFlexGroup>
75
+ );
76
+ };
@@ -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
+ };
@@ -0,0 +1,326 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import type { RuleGroupType } from 'react-querybuilder';
3
+
4
+ import { useTranslations } from 'next-intl';
5
+
6
+ import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSelect, EuiSpacer, EuiText } from '@elastic/eui';
7
+
8
+ import {
9
+ DEFAULT_PAGE_SIZE,
10
+ DEFAULT_PAGE_SIZES,
11
+ TableColumnKeys,
12
+ TableSettingsColumnConfig,
13
+ TableSettingsConfig,
14
+ TableSettingsModal,
15
+ WfoDataSearch,
16
+ WfoDataSorting,
17
+ WfoErrorWithMessage,
18
+ WfoInformationModal,
19
+ WfoKeyValueTable,
20
+ WfoKeyValueTableDataType,
21
+ clearTableConfigFromLocalStorage,
22
+ setTableConfigToLocalStorage,
23
+ } from '@/components';
24
+ import { getRowDetailData } from '@/components/WfoTable/WfoAdvancedTable/getRowDetailData';
25
+ import {
26
+ WfoTableControlColumnConfig,
27
+ WfoTableControlColumnConfigItem,
28
+ WfoTableDataColumnConfigItem,
29
+ } from '@/components/WfoTable/WfoTable';
30
+ import { useOrchestratorTheme } from '@/hooks';
31
+ import { WfoArrowsExpand } from '@/icons';
32
+ import { WfoGraphqlError } from '@/rtk';
33
+ import { FieldToOperatorMap, RetrieverType } from '@/types';
34
+ import { getDefaultTableConfig } from '@/utils';
35
+
36
+ import { ColumnType, WfoTable, WfoTableProps } from '../WfoTable';
37
+ import { WfoFilterBuilder } from './WfoFilterBuilder';
38
+ import { WfoSearchFieldWithActions } from './WfoSearchFieldWithActions';
39
+ import { buildColumnFilter } from './utils';
40
+
41
+ export type WfoStructuredSearchTableDataColumnConfigItem<
42
+ T extends object,
43
+ Property extends keyof T,
44
+ > = WfoTableDataColumnConfigItem<T, Property> & {
45
+ renderDetails?: (cellValue: T[Property], row: T) => React.ReactNode;
46
+ clipboardText?: (cellValue: T[Property], row: T) => string;
47
+ };
48
+ export type WfoStructuredSearchTableDataColumnConfig<T extends object> = {
49
+ [Property in keyof T]: WfoStructuredSearchTableDataColumnConfigItem<T, Property> | WfoTableControlColumnConfigItem<T>;
50
+ };
51
+ export type WfoStructuredSearchTableColumnConfig<T extends object> = Partial<
52
+ WfoTableControlColumnConfig<T> | WfoStructuredSearchTableDataColumnConfig<T>
53
+ >;
54
+ export type SearchParams = {
55
+ queryText?: string | false;
56
+ retrieverType?: RetrieverType;
57
+ ruleGroup?: RuleGroupType | false;
58
+ limit?: number;
59
+ sortBy?: {
60
+ field: string;
61
+ sortOrder: string;
62
+ };
63
+ };
64
+
65
+ export type WfoStructuredSearchTableProps<T extends object> = Omit<
66
+ WfoTableProps<T>,
67
+ 'columnConfig' | 'onUpdateDataSearch'
68
+ > & {
69
+ tableColumnConfig: WfoStructuredSearchTableColumnConfig<T>;
70
+ rowExpandingConfiguration: WfoTableProps<T>['rowExpandingConfiguration'];
71
+ defaultHiddenColumns?: TableColumnKeys<T>;
72
+ queryText?: string;
73
+ localStorageKey: string;
74
+ exportDataIsLoading?: boolean;
75
+ error?: WfoGraphqlError[];
76
+ onChangeQueryText: (queryString: string) => void;
77
+ onSearchQueryText: (queryString: string) => void;
78
+ onShowMore: () => void;
79
+ onUpdateDataSorting: (updateSorting: WfoDataSorting<T>) => void;
80
+ // Resolves a column key to its search field path (e.g. "status" -> "subscription.status"), used
81
+ // when a column header search adds a condition to the filter query.
82
+ getColumnSearchFieldName?: (field: keyof T) => string;
83
+ onExportData?: () => void;
84
+ retrieverType: RetrieverType;
85
+ onUpdateRetrieverType: (newRetrieverType: RetrieverType) => void;
86
+ filterString?: string;
87
+ onUpdateFilterString: (filterString: string) => void;
88
+ isValidFilterString?: boolean;
89
+ queryBuilderRuleGroup?: RuleGroupType;
90
+ onUpdateQueryBuilder: (ruleGroup: RuleGroupType | false) => void;
91
+ handleSearch: (searchParams?: SearchParams) => void;
92
+ pageSize: number;
93
+ setPageSize: React.Dispatch<React.SetStateAction<number>>;
94
+ totalItems: number | false;
95
+ hasNextPage: boolean;
96
+ prefilledFieldOptions: FieldToOperatorMap;
97
+ };
98
+
99
+ export const WfoStructuredSearchTable = <T extends object>({
100
+ tableColumnConfig,
101
+ defaultHiddenColumns = [],
102
+ queryText,
103
+ localStorageKey,
104
+ exportDataIsLoading,
105
+ error,
106
+ onChangeQueryText,
107
+ onSearchQueryText,
108
+ onShowMore,
109
+ onExportData,
110
+ retrieverType,
111
+ onUpdateRetrieverType,
112
+ filterString,
113
+ onUpdateFilterString,
114
+ isValidFilterString,
115
+ queryBuilderRuleGroup,
116
+ onUpdateQueryBuilder,
117
+ onUpdateDataSorting,
118
+ getColumnSearchFieldName,
119
+ handleSearch,
120
+ pageSize,
121
+ setPageSize,
122
+ totalItems,
123
+ rowExpandingConfiguration,
124
+ dataSorting,
125
+ hasNextPage,
126
+ data,
127
+ isLoading,
128
+ prefilledFieldOptions,
129
+ ...tableProps
130
+ }: WfoStructuredSearchTableProps<T>) => {
131
+ const { theme } = useOrchestratorTheme();
132
+
133
+ const [hiddenColumns, setHiddenColumns] = useState<TableColumnKeys<T>>(defaultHiddenColumns);
134
+ const [isFilterBuilderVisible, setIsFilterBuilderVisible] = useState(false);
135
+ const [showTableSettingsModal, setShowTableSettingsModal] = useState(false);
136
+ const [rowDetailModalData, setRowDetailModalData] = useState<T | undefined>(undefined);
137
+ const [showInformationModal, setShowInformationModal] = useState(false);
138
+ const t = useTranslations('common');
139
+
140
+ useEffect(() => {
141
+ if (defaultHiddenColumns) {
142
+ setHiddenColumns(defaultHiddenColumns);
143
+ }
144
+ }, [defaultHiddenColumns]);
145
+
146
+ useEffect(() => {
147
+ if (filterString) {
148
+ setIsFilterBuilderVisible(true);
149
+ }
150
+ }, [filterString]);
151
+
152
+ const detailsIconColumn: WfoStructuredSearchTableColumnConfig<T> = {
153
+ viewDetails: {
154
+ columnType: ColumnType.CONTROL,
155
+ width: '36px',
156
+ renderControl: (row) => (
157
+ <EuiFlexItem css={{ cursor: 'pointer' }} onClick={() => setRowDetailModalData(row)}>
158
+ <WfoArrowsExpand color={theme.colors.borderBasePlain} />
159
+ </EuiFlexItem>
160
+ ),
161
+ },
162
+ };
163
+
164
+ const tableColumnsWithControlColumns: WfoStructuredSearchTableColumnConfig<T> = {
165
+ ...detailsIconColumn,
166
+ ...tableColumnConfig,
167
+ };
168
+
169
+ const tableSettingsColumns: TableSettingsColumnConfig<T>[] = Object.entries(tableColumnConfig).map(
170
+ ([key, { label }]): TableSettingsColumnConfig<T> => {
171
+ const field = key as keyof T;
172
+
173
+ return {
174
+ field,
175
+ name: label,
176
+ isVisible: hiddenColumns.indexOf(field) === -1,
177
+ };
178
+ },
179
+ );
180
+
181
+ const rowDetailData: WfoKeyValueTableDataType[] | undefined =
182
+ rowDetailModalData && getRowDetailData(rowDetailModalData, tableColumnConfig);
183
+
184
+ const handleUpdateTableConfig = (updatedTableConfig: TableSettingsConfig<T>) => {
185
+ const updatedHiddenColumns = updatedTableConfig.columns
186
+ .filter((column) => !column.isVisible)
187
+ .map((hiddenColumn) => hiddenColumn.field);
188
+ setHiddenColumns(updatedHiddenColumns);
189
+ setShowTableSettingsModal(false);
190
+ setPageSize(updatedTableConfig.selectedPageSize);
191
+ setTableConfigToLocalStorage(localStorageKey, {
192
+ hiddenColumns: updatedHiddenColumns,
193
+ selectedPageSize: updatedTableConfig.selectedPageSize,
194
+ });
195
+ };
196
+
197
+ const handleResetToDefaults = () => {
198
+ const defaultTableConfig = getDefaultTableConfig<T>(localStorageKey);
199
+ setHiddenColumns(defaultTableConfig.hiddenColumns);
200
+ setPageSize(defaultTableConfig.selectedPageSize);
201
+ setShowTableSettingsModal(false);
202
+ clearTableConfigFromLocalStorage(localStorageKey);
203
+ };
204
+
205
+ const handleColumnFilterSearch = ({ field, searchText }: WfoDataSearch<T>) => {
206
+ const columnFilter = buildColumnFilter(field, searchText, filterString, getColumnSearchFieldName);
207
+ if (!columnFilter) {
208
+ return;
209
+ }
210
+ onUpdateFilterString(columnFilter.filterString);
211
+ handleSearch({ ruleGroup: columnFilter.ruleGroup });
212
+ };
213
+
214
+ const filterBuilder = (
215
+ <WfoFilterBuilder
216
+ filterString={filterString}
217
+ onUpdateFilterString={onUpdateFilterString}
218
+ isValidFilterString={isValidFilterString}
219
+ queryBuilderRuleGroup={queryBuilderRuleGroup}
220
+ onUpdateQueryBuilder={onUpdateQueryBuilder}
221
+ handleSearch={handleSearch}
222
+ isFilterBuilderVisible={isFilterBuilderVisible}
223
+ onToggleFilterBuilder={setIsFilterBuilderVisible}
224
+ prefilledFieldOptions={prefilledFieldOptions}
225
+ />
226
+ );
227
+
228
+ return (
229
+ <>
230
+ <EuiFlexGroup alignItems="center" gutterSize="s">
231
+ {!isFilterBuilderVisible && <EuiFlexItem grow={false}>{filterBuilder}</EuiFlexItem>}
232
+ <WfoSearchFieldWithActions
233
+ queryText={queryText}
234
+ onChangeQueryText={onChangeQueryText}
235
+ onSearchQueryText={onSearchQueryText}
236
+ onShowInformation={() => setShowInformationModal(true)}
237
+ onShowTableSettings={() => setShowTableSettingsModal(true)}
238
+ />
239
+ </EuiFlexGroup>
240
+
241
+ {isFilterBuilderVisible && (
242
+ <>
243
+ <EuiSpacer size="s" />
244
+ {filterBuilder}
245
+ </>
246
+ )}
247
+
248
+ {error && <WfoErrorWithMessage error={error} />}
249
+
250
+ <EuiSpacer size="m" />
251
+
252
+ <WfoTable<T>
253
+ columnConfig={tableColumnsWithControlColumns}
254
+ hiddenColumns={hiddenColumns}
255
+ rowExpandingConfiguration={rowExpandingConfiguration}
256
+ onUpdateDataSorting={onUpdateDataSorting}
257
+ onUpdateDataSearch={handleColumnFilterSearch}
258
+ dataSorting={dataSorting}
259
+ data={data}
260
+ isLoading={isLoading}
261
+ {...tableProps}
262
+ />
263
+
264
+ {totalItems && (
265
+ <EuiFlexGroup alignItems={'center'} justifyContent={'center'} css={{ padding: theme.base }}>
266
+ <EuiButton onClick={() => onShowMore()} disabled={!hasNextPage || isLoading}>
267
+ {t('loadMore')}
268
+ </EuiButton>
269
+ <div>{`${data.length}/${totalItems} records`}</div>
270
+ </EuiFlexGroup>
271
+ )}
272
+
273
+ {showTableSettingsModal && (
274
+ <TableSettingsModal
275
+ tableConfig={{
276
+ columns: tableSettingsColumns,
277
+ selectedPageSize: pageSize ?? DEFAULT_PAGE_SIZE,
278
+ }}
279
+ pageSizeOptions={DEFAULT_PAGE_SIZES}
280
+ onClose={() => setShowTableSettingsModal(false)}
281
+ onUpdateTableConfig={handleUpdateTableConfig}
282
+ onResetToDefaults={handleResetToDefaults}
283
+ extraSettings={
284
+ <>
285
+ <EuiFormRow label={t('retrieval')} display="columnCompressed">
286
+ <EuiSelect
287
+ options={[
288
+ { value: RetrieverType.Auto, text: t('retrieverAuto') },
289
+ { value: RetrieverType.Fuzzy, text: t('retrieverFuzzy') },
290
+ { value: RetrieverType.Semantic, text: t('retrieverSemantic') },
291
+ { value: RetrieverType.Hybrid, text: t('retrieverHybrid') },
292
+ ]}
293
+ value={retrieverType}
294
+ onChange={(e) => onUpdateRetrieverType(e.target.value as RetrieverType)}
295
+ compressed
296
+ />
297
+ </EuiFormRow>
298
+ {onExportData && (
299
+ <>
300
+ <EuiSpacer size="m" />
301
+ <EuiButton isLoading={exportDataIsLoading} onClick={() => onExportData()} fullWidth>
302
+ {t('export')}
303
+ </EuiButton>
304
+ </>
305
+ )}
306
+ </>
307
+ }
308
+ />
309
+ )}
310
+
311
+ {showInformationModal && (
312
+ <WfoInformationModal title={t('searchModalTitle')} onClose={() => setShowInformationModal(false)}>
313
+ <EuiText>
314
+ <p>TODO: Info about searching</p>
315
+ </EuiText>
316
+ </WfoInformationModal>
317
+ )}
318
+
319
+ {rowDetailData && (
320
+ <WfoInformationModal title={'TODO: Information modal title'} onClose={() => setRowDetailModalData(undefined)}>
321
+ <WfoKeyValueTable keyValues={rowDetailData} showCopyToClipboardIcon />
322
+ </WfoInformationModal>
323
+ )}
324
+ </>
325
+ );
326
+ };
@@ -0,0 +1,159 @@
1
+ import React, { type KeyboardEventHandler, useEffect, useState } from 'react';
2
+ import type { ChangeEventHandler } from 'react';
3
+ import type { ValueEditorProps } from 'react-querybuilder';
4
+
5
+ import moment from 'moment';
6
+ import { useTranslations } from 'next-intl';
7
+
8
+ import { EuiButtonGroup, EuiDatePicker, EuiFieldNumber, EuiFieldText } from '@elastic/eui';
9
+
10
+ import { getWfoStructuredSearchTableStyles } from '@/components/WfoTable/WfoStructuredSearchTable/styles';
11
+ import { useWithOrchestratorTheme } from '@/hooks';
12
+
13
+ import { WfoRangeEditor, WfoRangeElementProps } from './WfoRangeEditor';
14
+
15
+ enum UiFieldType {
16
+ text = 'text',
17
+ number = 'number',
18
+ boolean = 'boolean',
19
+ datetime = 'datetime',
20
+ }
21
+
22
+ export type HandleOnChange<T> = (value: T | undefined, rangeIndex?: number) => void;
23
+
24
+ export interface EditorProps<T> {
25
+ handleOnChange: HandleOnChange<T>;
26
+ value: T;
27
+ operator?: string;
28
+ }
29
+
30
+ const BooleanEditor = ({ handleOnChange, value: currentValue = true }: EditorProps<boolean>) => {
31
+ const [value, setValue] = useState<string>(currentValue.toString());
32
+
33
+ useEffect(() => {
34
+ handleOnChange(true);
35
+ // Sets the initial value to true so we allow empty dep array here
36
+ // eslint-disable-next-line react-hooks/exhaustive-deps
37
+ }, []);
38
+
39
+ const { buttonGroupStyles } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
40
+ const options = [
41
+ {
42
+ id: 'true',
43
+ label: 'True',
44
+ },
45
+ {
46
+ id: 'false',
47
+ label: 'False',
48
+ },
49
+ ];
50
+
51
+ return (
52
+ <EuiButtonGroup
53
+ css={buttonGroupStyles}
54
+ legend="Combinator"
55
+ type="single"
56
+ options={options}
57
+ idSelected={value}
58
+ onChange={(id) => {
59
+ setValue(id);
60
+ handleOnChange(id === 'true');
61
+ }}
62
+ buttonSize="m"
63
+ color="primary"
64
+ />
65
+ );
66
+ };
67
+
68
+ const TextEditor = ({ handleOnChange, value: currentValue = '' }: EditorProps<string>) => {
69
+ const [value, setValue] = useState<string>(currentValue);
70
+
71
+ const handleTextChange: ChangeEventHandler<HTMLInputElement> = (e) => {
72
+ setValue(e.target.value || '');
73
+ };
74
+
75
+ const handleOnBlur = () => {
76
+ handleOnChange(value);
77
+ };
78
+
79
+ const handleOnKeyDown: KeyboardEventHandler<HTMLInputElement> = (e) => {
80
+ if (e.key === 'Enter') {
81
+ e.currentTarget.blur();
82
+ }
83
+ };
84
+
85
+ return <EuiFieldText value={value} onChange={handleTextChange} onBlur={handleOnBlur} onKeyDown={handleOnKeyDown} />;
86
+ };
87
+
88
+ const NumberEditor = ({ handleOnChange, rangeIndex, value: currentValue }: WfoRangeElementProps) => {
89
+ const [value, setValue] = useState<string>(currentValue?.toString() || '');
90
+
91
+ const handleNumberChange: ChangeEventHandler<HTMLInputElement> = (e) => {
92
+ setValue(e.target.value || '');
93
+ };
94
+
95
+ const handleOnBlur = () => {
96
+ const numberValue = parseFloat(value);
97
+ handleOnChange(numberValue, rangeIndex);
98
+ };
99
+
100
+ const handleOnKeyDown: KeyboardEventHandler<HTMLInputElement> = (e) => {
101
+ if (e.key === 'Enter') {
102
+ e.currentTarget.blur();
103
+ }
104
+ };
105
+
106
+ return (
107
+ <EuiFieldNumber
108
+ value={value || undefined}
109
+ onChange={handleNumberChange}
110
+ onBlur={handleOnBlur}
111
+ onKeyDown={handleOnKeyDown}
112
+ />
113
+ );
114
+ };
115
+
116
+ const DatePicker = ({ handleOnChange, rangeIndex, value: currentValue }: WfoRangeElementProps) => {
117
+ const [date, setDate] = useState<string>(currentValue || '');
118
+ const t = useTranslations('search.page');
119
+
120
+ return (
121
+ <EuiDatePicker
122
+ selected={date && date !== '' ? moment.utc(date) : undefined}
123
+ onChange={(date) => {
124
+ const utcDate = date ? moment.utc(date) : undefined;
125
+ setDate(utcDate?.toISOString() || '');
126
+ handleOnChange(utcDate?.toISOString(), rangeIndex);
127
+ }}
128
+ id={rangeIndex ? `date-range-${rangeIndex}` : 'date-range'}
129
+ css={{ width: '330px' }}
130
+ showTimeSelect
131
+ dateFormat="yyyy-MM-dd HH:mm"
132
+ timeFormat="HH:mm"
133
+ placeholderText={t('selectDateAndTime')}
134
+ locale="nl"
135
+ shouldCloseOnSelect={true}
136
+ />
137
+ );
138
+ };
139
+
140
+ export const WfoValueEditor = ({ field: fieldName, context, handleOnChange, operator, value }: ValueEditorProps) => {
141
+ const fieldPathInfoMap = context?.fieldPathInfoMap;
142
+
143
+ const fieldInfo = fieldPathInfoMap && fieldPathInfoMap.has(fieldName) ? fieldPathInfoMap.get(fieldName) : undefined;
144
+ const uiFieldType = fieldInfo?.ui_types[0] || UiFieldType.text;
145
+
146
+ if (uiFieldType === UiFieldType.boolean) {
147
+ return <BooleanEditor handleOnChange={handleOnChange} value={value} />;
148
+ }
149
+
150
+ if (uiFieldType === UiFieldType.datetime) {
151
+ return <WfoRangeEditor handleOnChange={handleOnChange} operator={operator} Element={DatePicker} value={value} />;
152
+ }
153
+
154
+ if (uiFieldType === UiFieldType.number) {
155
+ return <WfoRangeEditor handleOnChange={handleOnChange} operator={operator} Element={NumberEditor} value={value} />;
156
+ }
157
+
158
+ return <TextEditor handleOnChange={handleOnChange} value={value} />;
159
+ };
@@ -0,0 +1,2 @@
1
+ export * from './WfoStructuredSearchTable';
2
+ export * from './WfoExpandingSearchRow';