@orchestrator-ui/orchestrator-ui-components 8.8.1 → 8.8.2
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 +7 -7
- package/.turbo/turbo-lint.log +1 -1
- package/.turbo/turbo-test.log +12 -12
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +22 -5
- package/dist/index.js +1247 -1135
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/components/WfoPydanticForm/fields/WfoMultiCheckboxField.tsx +2 -1
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoFieldSelector.tsx +12 -8
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoFilterBuilder.tsx +23 -10
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoStructuredSearchTable.tsx +34 -3
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoValueEditor.tsx +4 -2
- package/src/components/WfoTable/WfoTable/WfoTable.tsx +77 -46
- package/src/components/WfoTable/WfoTable/WfoTableSkeletonRows.tsx +52 -0
- package/src/components/WfoTable/WfoTable/index.ts +1 -0
- package/src/components/WfoTable/WfoTableSettingsModal/WfoTableSettingsModal.tsx +21 -18
- package/src/components/WfoTable/WfoTableSettingsModal/styles.ts +17 -0
- package/src/components/WfoTable/utils/tableConfigPersistence.ts +1 -0
- package/src/configuration/version.ts +1 -1
- package/src/hooks/useGetPydanticFormsConfig.tsx +5 -3
- package/src/hooks/useSearch.ts +2 -2
- package/src/hooks/useStoredTableConfig.ts +1 -0
- package/src/messages/en-GB.json +2 -0
- package/src/messages/nl-NL.json +2 -0
- package/src/pages/WfoSearchPocPage.tsx +28 -23
- package/src/pages/processes/WfoProductInformationWithLink.tsx +9 -4
- package/src/types/search.ts +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orchestrator-ui/orchestrator-ui-components",
|
|
3
|
-
"version": "8.8.
|
|
3
|
+
"version": "8.8.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Library of UI Components used to display the workflow orchestrator frontend",
|
|
6
6
|
"author": {
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"next-query-params": "^5.0.0",
|
|
52
52
|
"object-hash": "^3.0.0",
|
|
53
53
|
"prism-themes": "^1.9.0",
|
|
54
|
-
"pydantic-forms": "^3.0
|
|
54
|
+
"pydantic-forms": "^3.1.0",
|
|
55
55
|
"react-diff-view": "^3.2.0",
|
|
56
56
|
"react-draggable": "^4.4.6",
|
|
57
57
|
"react-querybuilder": "^8.18.0",
|
|
@@ -59,7 +59,8 @@
|
|
|
59
59
|
"react-select": "^5.8.0",
|
|
60
60
|
"scroll-into-view": "^1.16.2",
|
|
61
61
|
"unidiff": "^1.0.4",
|
|
62
|
-
"use-query-params": "^2.2.2"
|
|
62
|
+
"use-query-params": "^2.2.2",
|
|
63
|
+
"zod": "^4.4.3"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@elastic/eui": "^113.0.0",
|
|
@@ -24,7 +24,8 @@ export const WfoMultiCheckboxField: PydanticFormControlledElement = ({ pydanticF
|
|
|
24
24
|
|
|
25
25
|
const [checkboxIdToSelectedMap, setCheckboxIdToSelectedMap] = useState<Record<string, boolean>>({});
|
|
26
26
|
|
|
27
|
-
const {
|
|
27
|
+
const { arrayItem, id } = pydanticFormField;
|
|
28
|
+
const options = arrayItem?.options || [];
|
|
28
29
|
|
|
29
30
|
const checkboxes = options?.map((option, index) => ({
|
|
30
31
|
label: option.label,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from 'react';
|
|
1
|
+
import React, { FC, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { FieldSelectorProps } from 'react-querybuilder';
|
|
3
3
|
|
|
4
4
|
import { useTranslations } from 'next-intl';
|
|
@@ -7,7 +7,7 @@ import type { EuiComboBoxOptionOption } from '@elastic/eui';
|
|
|
7
7
|
import { EuiComboBox } from '@elastic/eui';
|
|
8
8
|
|
|
9
9
|
import { usePathAutocomplete } from '@/hooks';
|
|
10
|
-
import { EntityKind,
|
|
10
|
+
import { EntityKind, PathInfo, WfoQueryBuilderContext } from '@/types';
|
|
11
11
|
|
|
12
12
|
// react-querybuilder applies the `.rule` class to the rule container and `.rule-value` to
|
|
13
13
|
// the value-editor cell (see `standardClassnames` in @react-querybuilder/core). We hop from
|
|
@@ -30,9 +30,13 @@ const focusValueEditorAfterRender = (searchInput: HTMLInputElement | null) => {
|
|
|
30
30
|
});
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
interface WfoFieldSelectorProps extends Omit<FieldSelectorProps, 'context'> {
|
|
34
|
+
context: WfoQueryBuilderContext;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const WfoFieldSelector: FC<WfoFieldSelectorProps> = ({ handleOnChange, disabled, rule, context }) => {
|
|
34
38
|
const { field } = rule;
|
|
35
|
-
const prefilledFieldOptions
|
|
39
|
+
const { useAdvancedNestedSearch, prefilledFieldOptions, onFieldSelected } = context;
|
|
36
40
|
const [selectedValue, setSelectedValue] = useState<string>(field);
|
|
37
41
|
const [searchInput, setSearchInput] = useState<HTMLInputElement | null>(null);
|
|
38
42
|
const optionsRef = useRef<EuiComboBoxOptionOption<string>[]>([]);
|
|
@@ -43,13 +47,13 @@ export const WfoFieldSelector = ({ handleOnChange, disabled, rule, context }: Fi
|
|
|
43
47
|
label: path,
|
|
44
48
|
});
|
|
45
49
|
|
|
50
|
+
const isSelectablePath = (path: string) => useAdvancedNestedSearch || !path.includes('.');
|
|
51
|
+
|
|
46
52
|
const getOptionsFromPathInfo = (pathInfos: PathInfo[]): EuiComboBoxOptionOption<string>[] => {
|
|
47
53
|
const pathOptions: EuiComboBoxOptionOption<string>[] = [];
|
|
48
54
|
|
|
49
55
|
pathInfos.forEach((pathInfo) => {
|
|
50
|
-
|
|
51
|
-
// Adds more specific paths
|
|
52
|
-
pathInfo.availablePaths?.forEach((path) => {
|
|
56
|
+
[pathInfo.path, ...(pathInfo.availablePaths ?? [])].filter(isSelectablePath).forEach((path) => {
|
|
53
57
|
pathOptions.push(getOption(path));
|
|
54
58
|
});
|
|
55
59
|
});
|
|
@@ -85,7 +89,7 @@ export const WfoFieldSelector = ({ handleOnChange, disabled, rule, context }: Fi
|
|
|
85
89
|
?? paths.find((path) => path.availablePaths?.includes(selectedValue));
|
|
86
90
|
const operators = matchingPath?.operators ?? prefilledFieldOptions.get(selectedValue) ?? [];
|
|
87
91
|
|
|
88
|
-
|
|
92
|
+
onFieldSelected(selectedValue, operators, matchingPath);
|
|
89
93
|
};
|
|
90
94
|
|
|
91
95
|
const handleFieldSelection = (selectedOptions: EuiComboBoxOptionOption<string>[]) => {
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
-
import {
|
|
1
|
+
import React, { type ComponentType, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
type FieldSelectorProps,
|
|
4
|
+
FullOperator,
|
|
5
|
+
QueryBuilder,
|
|
6
|
+
type RuleGroupType,
|
|
7
|
+
generateID,
|
|
8
|
+
} from 'react-querybuilder';
|
|
3
9
|
import 'react-querybuilder/dist/query-builder.css';
|
|
4
10
|
|
|
5
11
|
import { useTranslations } from 'next-intl';
|
|
@@ -10,7 +16,7 @@ import { SearchParams, WfoAutoExpandableTextArea, WfoTextAnchor } from '@/compon
|
|
|
10
16
|
import { WfoCombinatorSelector } from '@/components/WfoTable/WfoStructuredSearchTable/WfoCombinatorSelector';
|
|
11
17
|
import { useFieldsPathInfo, useWithOrchestratorTheme } from '@/hooks';
|
|
12
18
|
import { EntityKind, OperatorDisplay } from '@/types';
|
|
13
|
-
import type { FieldToOperatorMap, PathInfo } from '@/types';
|
|
19
|
+
import type { FieldToOperatorMap, PathInfo, WfoQueryBuilderContext } from '@/types';
|
|
14
20
|
|
|
15
21
|
import { WfoFieldSelector } from './WfoFieldSelector';
|
|
16
22
|
import { WfoInlineCombinator } from './WfoInlineCombinator';
|
|
@@ -65,6 +71,7 @@ interface WfoFilterBuilderProps {
|
|
|
65
71
|
handleSearch: (searchParams?: SearchParams) => void;
|
|
66
72
|
onToggleFilterBuilder: (isVisible: boolean) => void;
|
|
67
73
|
prefilledFieldOptions: FieldToOperatorMap;
|
|
74
|
+
useAdvancedNestedSearch?: boolean;
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
const initialRuleGroup: RuleGroupType = {
|
|
@@ -87,6 +94,7 @@ export const WfoFilterBuilder = ({
|
|
|
87
94
|
handleSearch,
|
|
88
95
|
prefilledFieldOptions,
|
|
89
96
|
onToggleFilterBuilder,
|
|
97
|
+
useAdvancedNestedSearch = true,
|
|
90
98
|
}: WfoFilterBuilderProps) => {
|
|
91
99
|
const mapOperatorsToRQBOperatorOptions = (operators?: string[]): FullOperator[] => {
|
|
92
100
|
return (operators ?? []).map((operator) => {
|
|
@@ -143,6 +151,14 @@ export const WfoFilterBuilder = ({
|
|
|
143
151
|
);
|
|
144
152
|
const resolvedFieldsPathInfo = useFieldsPathInfo(unresolvedFields, EntityKind.SUBSCRIPTION);
|
|
145
153
|
|
|
154
|
+
const queryBuilderContext: WfoQueryBuilderContext = {
|
|
155
|
+
onFieldSelected: handleFieldSelected,
|
|
156
|
+
prefilledFieldOptions,
|
|
157
|
+
fieldPathInfoMap,
|
|
158
|
+
onValueEditorEnter: handleValueEditorEnter,
|
|
159
|
+
useAdvancedNestedSearch,
|
|
160
|
+
};
|
|
161
|
+
|
|
146
162
|
useEffect(() => {
|
|
147
163
|
resolvedFieldsPathInfo.forEach((pathInfo, field) => {
|
|
148
164
|
if (pathInfo && !fieldPathInfoMap.has(field)) {
|
|
@@ -162,18 +178,15 @@ export const WfoFilterBuilder = ({
|
|
|
162
178
|
latestRuleGroupRef.current = ruleGroup;
|
|
163
179
|
onUpdateQueryBuilder(ruleGroup);
|
|
164
180
|
}}
|
|
165
|
-
context={
|
|
166
|
-
onFieldSelected: handleFieldSelected,
|
|
167
|
-
prefilledFieldOptions,
|
|
168
|
-
fieldPathInfoMap,
|
|
169
|
-
onValueEditorEnter: handleValueEditorEnter,
|
|
170
|
-
}}
|
|
181
|
+
context={queryBuilderContext}
|
|
171
182
|
getOperators={(field) => {
|
|
172
183
|
const operators = fieldToOperatorMap.get(field);
|
|
173
184
|
return mapOperatorsToRQBOperatorOptions(operators);
|
|
174
185
|
}}
|
|
175
186
|
controlElements={{
|
|
176
|
-
|
|
187
|
+
// WfoFieldSelector requires the context this QueryBuilder always provides,
|
|
188
|
+
// while react-querybuilder declares it optional — hence the cast.
|
|
189
|
+
fieldSelector: WfoFieldSelector as ComponentType<FieldSelectorProps>,
|
|
177
190
|
operatorSelector: WfoOperatorSelector,
|
|
178
191
|
valueEditor: WfoValueEditor,
|
|
179
192
|
ruleGroup: WfoRuleGroup,
|
|
@@ -80,6 +80,7 @@ export type WfoStructuredSearchTableProps<T extends object> = Omit<
|
|
|
80
80
|
rowExpandingConfiguration: WfoTableProps<T>['rowExpandingConfiguration'];
|
|
81
81
|
defaultHiddenColumns?: TableColumnKeys<T>;
|
|
82
82
|
defaultShowMatchDetails?: boolean;
|
|
83
|
+
defaultAdvancedNestedSearch?: boolean;
|
|
83
84
|
queryText?: string;
|
|
84
85
|
localStorageKey: string;
|
|
85
86
|
exportDataIsLoading?: boolean;
|
|
@@ -101,7 +102,7 @@ export type WfoStructuredSearchTableProps<T extends object> = Omit<
|
|
|
101
102
|
onUpdateQueryBuilder: (ruleGroup: RuleGroupType | false) => void;
|
|
102
103
|
handleSearch: (searchParams?: SearchParams) => void;
|
|
103
104
|
pageSize: number;
|
|
104
|
-
setPageSize:
|
|
105
|
+
setPageSize: (updatedPageSize: number) => void;
|
|
105
106
|
totalItems: number | false;
|
|
106
107
|
hasNextPage: boolean;
|
|
107
108
|
prefilledFieldOptions: FieldToOperatorMap;
|
|
@@ -111,6 +112,7 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
111
112
|
tableColumnConfig,
|
|
112
113
|
defaultHiddenColumns = [],
|
|
113
114
|
defaultShowMatchDetails = false,
|
|
115
|
+
defaultAdvancedNestedSearch = true,
|
|
114
116
|
queryText,
|
|
115
117
|
localStorageKey,
|
|
116
118
|
exportDataIsLoading,
|
|
@@ -148,6 +150,7 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
148
150
|
const [rowDetailModalData, setRowDetailModalData] = useState<T | undefined>(undefined);
|
|
149
151
|
const [showInformationModal, setShowInformationModal] = useState(false);
|
|
150
152
|
const [showMatchDetails, setShowMatchDetails] = useState(defaultShowMatchDetails);
|
|
153
|
+
const [advancedNestedSearch, setAdvancedNestedSearch] = useState(defaultAdvancedNestedSearch);
|
|
151
154
|
const t = useTranslations('common');
|
|
152
155
|
|
|
153
156
|
useEffect(() => {
|
|
@@ -160,6 +163,10 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
160
163
|
setShowMatchDetails(defaultShowMatchDetails);
|
|
161
164
|
}, [defaultShowMatchDetails]);
|
|
162
165
|
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
setAdvancedNestedSearch(defaultAdvancedNestedSearch);
|
|
168
|
+
}, [defaultAdvancedNestedSearch]);
|
|
169
|
+
|
|
163
170
|
useEffect(() => {
|
|
164
171
|
if (filterString) {
|
|
165
172
|
setIsFilterBuilderVisible(true);
|
|
@@ -199,10 +206,11 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
199
206
|
hiddenColumns: updatedHiddenColumns,
|
|
200
207
|
selectedPageSize: updatedTableConfig.selectedPageSize,
|
|
201
208
|
showMatchDetails,
|
|
209
|
+
advancedNestedSearch,
|
|
202
210
|
});
|
|
203
211
|
};
|
|
204
212
|
|
|
205
|
-
// The
|
|
213
|
+
// The toggles apply live, so persist them immediately alongside the currently committed
|
|
206
214
|
// hidden columns and page size instead of waiting for the modal's "Update" action.
|
|
207
215
|
const handleToggleShowMatchDetails = (checked: boolean) => {
|
|
208
216
|
setShowMatchDetails(checked);
|
|
@@ -210,6 +218,17 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
210
218
|
hiddenColumns,
|
|
211
219
|
selectedPageSize: pageSize ?? DEFAULT_PAGE_SIZE,
|
|
212
220
|
showMatchDetails: checked,
|
|
221
|
+
advancedNestedSearch,
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const handleToggleAdvancedNestedSearch = (checked: boolean) => {
|
|
226
|
+
setAdvancedNestedSearch(checked);
|
|
227
|
+
setTableConfigToLocalStorage(localStorageKey, {
|
|
228
|
+
hiddenColumns,
|
|
229
|
+
selectedPageSize: pageSize ?? DEFAULT_PAGE_SIZE,
|
|
230
|
+
showMatchDetails,
|
|
231
|
+
advancedNestedSearch: checked,
|
|
213
232
|
});
|
|
214
233
|
};
|
|
215
234
|
|
|
@@ -218,6 +237,7 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
218
237
|
setHiddenColumns(defaultTableConfig.hiddenColumns);
|
|
219
238
|
setPageSize(defaultTableConfig.selectedPageSize);
|
|
220
239
|
setShowMatchDetails(defaultTableConfig.showMatchDetails ?? false);
|
|
240
|
+
setAdvancedNestedSearch(defaultTableConfig.advancedNestedSearch ?? false);
|
|
221
241
|
setShowTableSettingsModal(false);
|
|
222
242
|
clearTableConfigFromLocalStorage(localStorageKey);
|
|
223
243
|
};
|
|
@@ -272,6 +292,7 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
272
292
|
handleSearch={handleSearch}
|
|
273
293
|
onToggleFilterBuilder={setIsFilterBuilderVisible}
|
|
274
294
|
prefilledFieldOptions={prefilledFieldOptions}
|
|
295
|
+
useAdvancedNestedSearch={advancedNestedSearch}
|
|
275
296
|
/>
|
|
276
297
|
</>
|
|
277
298
|
)}
|
|
@@ -290,6 +311,7 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
290
311
|
dataSorting={dataSorting}
|
|
291
312
|
data={data}
|
|
292
313
|
isLoading={isLoading}
|
|
314
|
+
loadingSkeletonRowCount={pageSize}
|
|
293
315
|
{...tableProps}
|
|
294
316
|
/>
|
|
295
317
|
|
|
@@ -323,6 +345,15 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
323
345
|
compressed
|
|
324
346
|
/>
|
|
325
347
|
</EuiFormRow>
|
|
348
|
+
<EuiFormRow label={t('advancedNestedSearch')} display="columnCompressed">
|
|
349
|
+
<EuiSwitch
|
|
350
|
+
showLabel={false}
|
|
351
|
+
label={t('advancedNestedSearch')}
|
|
352
|
+
checked={advancedNestedSearch}
|
|
353
|
+
onChange={(event) => handleToggleAdvancedNestedSearch(event.target.checked)}
|
|
354
|
+
compressed
|
|
355
|
+
/>
|
|
356
|
+
</EuiFormRow>
|
|
326
357
|
<EuiFormRow label={t('retrieval')} display="columnCompressed">
|
|
327
358
|
<EuiSelect
|
|
328
359
|
options={[
|
|
@@ -340,7 +371,7 @@ export const WfoStructuredSearchTable = <T extends object>({
|
|
|
340
371
|
<>
|
|
341
372
|
<EuiSpacer size="m" />
|
|
342
373
|
<EuiButton isLoading={exportDataIsLoading} onClick={() => onExportData()} fullWidth>
|
|
343
|
-
{t('export')}
|
|
374
|
+
{totalItems ? t('exportRows', { numberOfRows: totalItems }) : t('export')}
|
|
344
375
|
</EuiButton>
|
|
345
376
|
</>
|
|
346
377
|
)}
|
|
@@ -10,6 +10,7 @@ import { EuiButtonGroup, EuiDatePicker, EuiFieldNumber, EuiFieldText } from '@el
|
|
|
10
10
|
import { WfoRangeEditor } from '@/components/WfoTable/WfoStructuredSearchTable/WfoRangeEditor';
|
|
11
11
|
import { getWfoStructuredSearchTableStyles } from '@/components/WfoTable/WfoStructuredSearchTable/styles';
|
|
12
12
|
import { useWithOrchestratorTheme } from '@/hooks';
|
|
13
|
+
import type { WfoQueryBuilderContext } from '@/types';
|
|
13
14
|
|
|
14
15
|
export interface EditorInputFieldProps<T = string> {
|
|
15
16
|
handleOnChange: ValueEditorProps['handleOnChange'];
|
|
@@ -176,7 +177,8 @@ export const WfoValueEditor = ({
|
|
|
176
177
|
return TextEditor;
|
|
177
178
|
};
|
|
178
179
|
|
|
179
|
-
const
|
|
180
|
+
const queryBuilderContext: WfoQueryBuilderContext | undefined = context;
|
|
181
|
+
const fieldPathInfoMap = queryBuilderContext?.fieldPathInfoMap;
|
|
180
182
|
|
|
181
183
|
const fieldInfo = fieldPathInfoMap && fieldPathInfoMap.has(fieldName) ? fieldPathInfoMap.get(fieldName) : undefined;
|
|
182
184
|
const uiFieldType = fieldInfo?.ui_types?.[0] || UiFieldType.text;
|
|
@@ -198,7 +200,7 @@ export const WfoValueEditor = ({
|
|
|
198
200
|
// the boolean buttons means "select" — its click fires only after this keydown, so
|
|
199
201
|
// searching there would use the pre-toggle value.
|
|
200
202
|
if (!(event.target instanceof HTMLInputElement)) return;
|
|
201
|
-
|
|
203
|
+
queryBuilderContext?.onValueEditorEnter();
|
|
202
204
|
};
|
|
203
205
|
|
|
204
206
|
// react-querybuilder delivers the standard `rule-value` class via this prop; the wrapper
|
|
@@ -13,6 +13,7 @@ import { DEFAULT_PAGE_SIZES } from '../utils/constants';
|
|
|
13
13
|
import { getPageCount } from '../utils/tableUtils';
|
|
14
14
|
import { WfoTableDataRows } from './WfoTableDataRows';
|
|
15
15
|
import { WfoTableHeaderRow } from './WfoTableHeaderRow';
|
|
16
|
+
import { WfoTableSkeletonRows } from './WfoTableSkeletonRows';
|
|
16
17
|
import { getWfoTableStyles } from './styles';
|
|
17
18
|
import { getColumnWidthsFromConfig, getSortedVisibleColumns, usePageIndexBoundsGuard } from './utils';
|
|
18
19
|
|
|
@@ -78,6 +79,7 @@ export type WfoTableProps<T extends object> = {
|
|
|
78
79
|
hiddenColumns?: TableColumnKeys<T>;
|
|
79
80
|
columnOrder?: TableColumnKeys<T>;
|
|
80
81
|
isLoading?: boolean;
|
|
82
|
+
loadingSkeletonRowCount?: number;
|
|
81
83
|
dataSorting?: WfoDataSorting<T>[];
|
|
82
84
|
rowExpandingConfiguration?: {
|
|
83
85
|
uniqueRowId: keyof WfoTableColumnConfig<T>;
|
|
@@ -106,6 +108,7 @@ export const WfoTable = <T extends object>({
|
|
|
106
108
|
hiddenColumns = [],
|
|
107
109
|
columnOrder = [],
|
|
108
110
|
isLoading = false,
|
|
111
|
+
loadingSkeletonRowCount,
|
|
109
112
|
dataSorting = [],
|
|
110
113
|
rowExpandingConfiguration,
|
|
111
114
|
showExpandedRows = false,
|
|
@@ -125,6 +128,8 @@ export const WfoTable = <T extends object>({
|
|
|
125
128
|
const dataLength = data.length;
|
|
126
129
|
usePageIndexBoundsGuard({ dataLength, isLoading, pagination });
|
|
127
130
|
|
|
131
|
+
const showLoadingSkeleton = !!loadingSkeletonRowCount && isLoading && dataLength === 0;
|
|
132
|
+
|
|
128
133
|
const parentRef = useRef<HTMLDivElement>(null);
|
|
129
134
|
|
|
130
135
|
const columnConfigWithFiller: WfoTableColumnConfig<T> =
|
|
@@ -192,6 +197,77 @@ export const WfoTable = <T extends object>({
|
|
|
192
197
|
const virtualTrHeight = virtualItems[0]?.start ?? 0;
|
|
193
198
|
const bottomSpacerHeight = totalSize - lastVirtualItemEnd;
|
|
194
199
|
|
|
200
|
+
const WfoTableBody = () => {
|
|
201
|
+
if (showLoadingSkeleton) {
|
|
202
|
+
return (
|
|
203
|
+
<tbody css={bodyLoadingStyle} aria-busy={true}>
|
|
204
|
+
<WfoTableSkeletonRows
|
|
205
|
+
rowCount={loadingSkeletonRowCount}
|
|
206
|
+
columnConfig={configWithLocalWidths}
|
|
207
|
+
hiddenColumns={hiddenColumns}
|
|
208
|
+
columnOrder={columnOrder}
|
|
209
|
+
/>
|
|
210
|
+
</tbody>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (dataLength === 0) {
|
|
215
|
+
return (
|
|
216
|
+
<tbody css={isLoading && bodyLoadingStyle}>
|
|
217
|
+
<tr css={rowStyle}>
|
|
218
|
+
<td colSpan={sortedVisibleColumns.length} css={[cellStyle, emptyTableMessageStyle]}>
|
|
219
|
+
{isLoading ? t('loading') : t('noItemsFound')}
|
|
220
|
+
</td>
|
|
221
|
+
</tr>
|
|
222
|
+
</tbody>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (isVirtualized && height) {
|
|
227
|
+
return (
|
|
228
|
+
<tbody>
|
|
229
|
+
<tr
|
|
230
|
+
style={{
|
|
231
|
+
height: virtualTrHeight,
|
|
232
|
+
}}
|
|
233
|
+
/>
|
|
234
|
+
|
|
235
|
+
{virtualItems.map((virtualRow) => (
|
|
236
|
+
<WfoTableDataRows
|
|
237
|
+
key={virtualRow.key}
|
|
238
|
+
data={[data[virtualRow.index]]}
|
|
239
|
+
columnConfig={configWithLocalWidths}
|
|
240
|
+
hiddenColumns={hiddenColumns}
|
|
241
|
+
columnOrder={columnOrder}
|
|
242
|
+
rowExpandingConfiguration={rowExpandingConfiguration}
|
|
243
|
+
showExpandedRows={showExpandedRows}
|
|
244
|
+
onRowClick={onRowClick}
|
|
245
|
+
/>
|
|
246
|
+
))}
|
|
247
|
+
<tr
|
|
248
|
+
style={{
|
|
249
|
+
height: bottomSpacerHeight,
|
|
250
|
+
}}
|
|
251
|
+
/>
|
|
252
|
+
</tbody>
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return (
|
|
257
|
+
<tbody css={isLoading && bodyLoadingStyle}>
|
|
258
|
+
<WfoTableDataRows
|
|
259
|
+
data={data}
|
|
260
|
+
columnConfig={configWithLocalWidths}
|
|
261
|
+
hiddenColumns={hiddenColumns}
|
|
262
|
+
columnOrder={columnOrder}
|
|
263
|
+
rowExpandingConfiguration={rowExpandingConfiguration}
|
|
264
|
+
showExpandedRows={showExpandedRows}
|
|
265
|
+
onRowClick={onRowClick}
|
|
266
|
+
/>
|
|
267
|
+
</tbody>
|
|
268
|
+
);
|
|
269
|
+
};
|
|
270
|
+
|
|
195
271
|
return (
|
|
196
272
|
<>
|
|
197
273
|
<div
|
|
@@ -214,52 +290,7 @@ export const WfoTable = <T extends object>({
|
|
|
214
290
|
/>
|
|
215
291
|
</thead>
|
|
216
292
|
}
|
|
217
|
-
{
|
|
218
|
-
<tbody css={isLoading && bodyLoadingStyle}>
|
|
219
|
-
<tr css={rowStyle}>
|
|
220
|
-
<td colSpan={sortedVisibleColumns.length} css={[cellStyle, emptyTableMessageStyle]}>
|
|
221
|
-
{isLoading ? t('loading') : t('noItemsFound')}
|
|
222
|
-
</td>
|
|
223
|
-
</tr>
|
|
224
|
-
</tbody>
|
|
225
|
-
: isVirtualized && height ?
|
|
226
|
-
<tbody>
|
|
227
|
-
<tr
|
|
228
|
-
style={{
|
|
229
|
-
height: virtualTrHeight,
|
|
230
|
-
}}
|
|
231
|
-
/>
|
|
232
|
-
|
|
233
|
-
{virtualItems.map((virtualRow) => (
|
|
234
|
-
<WfoTableDataRows
|
|
235
|
-
key={virtualRow.key}
|
|
236
|
-
data={[data[virtualRow.index]]}
|
|
237
|
-
columnConfig={configWithLocalWidths}
|
|
238
|
-
hiddenColumns={hiddenColumns}
|
|
239
|
-
columnOrder={columnOrder}
|
|
240
|
-
rowExpandingConfiguration={rowExpandingConfiguration}
|
|
241
|
-
showExpandedRows={showExpandedRows}
|
|
242
|
-
onRowClick={onRowClick}
|
|
243
|
-
/>
|
|
244
|
-
))}
|
|
245
|
-
<tr
|
|
246
|
-
style={{
|
|
247
|
-
height: bottomSpacerHeight,
|
|
248
|
-
}}
|
|
249
|
-
/>
|
|
250
|
-
</tbody>
|
|
251
|
-
: <tbody css={isLoading && bodyLoadingStyle}>
|
|
252
|
-
<WfoTableDataRows
|
|
253
|
-
data={data}
|
|
254
|
-
columnConfig={configWithLocalWidths}
|
|
255
|
-
hiddenColumns={hiddenColumns}
|
|
256
|
-
columnOrder={columnOrder}
|
|
257
|
-
rowExpandingConfiguration={rowExpandingConfiguration}
|
|
258
|
-
showExpandedRows={showExpandedRows}
|
|
259
|
-
onRowClick={onRowClick}
|
|
260
|
-
/>
|
|
261
|
-
</tbody>
|
|
262
|
-
}
|
|
293
|
+
{<WfoTableBody />}
|
|
263
294
|
</table>
|
|
264
295
|
</div>
|
|
265
296
|
{pagination && (
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { EuiSkeletonText } from '@elastic/eui';
|
|
4
|
+
|
|
5
|
+
import { useWithOrchestratorTheme } from '@/hooks';
|
|
6
|
+
import { toOptionalArrayEntry } from '@/utils';
|
|
7
|
+
|
|
8
|
+
import { ColumnType, WfoTableProps } from './WfoTable';
|
|
9
|
+
import { getWfoTableStyles } from './styles';
|
|
10
|
+
import { getSortedVisibleColumns } from './utils';
|
|
11
|
+
|
|
12
|
+
export type WfoTableSkeletonRowsProps<T extends object> = Pick<
|
|
13
|
+
WfoTableProps<T>,
|
|
14
|
+
'columnConfig' | 'hiddenColumns' | 'columnOrder'
|
|
15
|
+
> & {
|
|
16
|
+
rowCount: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const WfoTableSkeletonRows = <T extends object>({
|
|
20
|
+
rowCount,
|
|
21
|
+
columnConfig,
|
|
22
|
+
hiddenColumns = [],
|
|
23
|
+
columnOrder = [],
|
|
24
|
+
}: WfoTableSkeletonRowsProps<T>) => {
|
|
25
|
+
const { cellStyle, cellContentStyle, rowStyle, setWidth } = useWithOrchestratorTheme(getWfoTableStyles);
|
|
26
|
+
|
|
27
|
+
const sortedVisibleColumns = getSortedVisibleColumns(columnConfig, columnOrder, hiddenColumns);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
{[...Array(rowCount)].map((_, rowIndex) => (
|
|
32
|
+
<tr key={`skeleton-row-${rowIndex}`} css={rowStyle}>
|
|
33
|
+
{sortedVisibleColumns.map(([key, columnConfig]) => (
|
|
34
|
+
<td
|
|
35
|
+
key={key}
|
|
36
|
+
css={[
|
|
37
|
+
...toOptionalArrayEntry(cellStyle, !columnConfig.disableDefaultCellStyle),
|
|
38
|
+
setWidth(columnConfig.width),
|
|
39
|
+
]}
|
|
40
|
+
>
|
|
41
|
+
{columnConfig.columnType === ColumnType.DATA && (
|
|
42
|
+
<div css={cellContentStyle}>
|
|
43
|
+
<EuiSkeletonText lines={1} size="m" isLoading />
|
|
44
|
+
</div>
|
|
45
|
+
)}
|
|
46
|
+
</td>
|
|
47
|
+
))}
|
|
48
|
+
</tr>
|
|
49
|
+
))}
|
|
50
|
+
</>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
@@ -11,6 +11,7 @@ export * from './WfoMultilineCell';
|
|
|
11
11
|
export * from './WfoTable';
|
|
12
12
|
export * from './WfoTableHeaderCell';
|
|
13
13
|
export * from './WfoTableDataRows';
|
|
14
|
+
export * from './WfoTableSkeletonRows';
|
|
14
15
|
|
|
15
16
|
export * from './WfoTruncateCell';
|
|
16
17
|
export * from './WfoDataCell';
|
|
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { useTranslations } from 'next-intl';
|
|
4
4
|
|
|
5
|
-
import { EuiForm, EuiFormRow, EuiHorizontalRule, EuiSelect, EuiSpacer, EuiSwitch } from '@elastic/eui';
|
|
5
|
+
import { EuiForm, EuiFormRow, EuiHorizontalRule, EuiSelect, EuiSpacer, EuiSwitch, useEuiScrollBar } from '@elastic/eui';
|
|
6
6
|
|
|
7
7
|
import { WfoSettingsModal } from '@/components';
|
|
8
8
|
import { getWfoTableSettingsModalStyles } from '@/components/WfoTable/WfoTableSettingsModal/styles';
|
|
@@ -37,7 +37,8 @@ export const TableSettingsModal = <T,>({
|
|
|
37
37
|
extraSettings,
|
|
38
38
|
}: TableSettingsModalProps<T>) => {
|
|
39
39
|
const t = useTranslations('main');
|
|
40
|
-
const { formRowStyle, selectFieldStyle } = useWithOrchestratorTheme(getWfoTableSettingsModalStyles);
|
|
40
|
+
const { formRowStyle, columnsListStyle, selectFieldStyle } = useWithOrchestratorTheme(getWfoTableSettingsModalStyles);
|
|
41
|
+
const scrollBarStyle = useEuiScrollBar();
|
|
41
42
|
|
|
42
43
|
const [columns, setColumns] = useState(tableConfig.columns);
|
|
43
44
|
const [selectedPageSize, setSelectedPageSize] = useState(tableConfig.selectedPageSize);
|
|
@@ -72,22 +73,24 @@ export const TableSettingsModal = <T,>({
|
|
|
72
73
|
}
|
|
73
74
|
>
|
|
74
75
|
<EuiForm>
|
|
75
|
-
{
|
|
76
|
-
|
|
77
|
-
<
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
76
|
+
<div css={[columnsListStyle, scrollBarStyle]}>
|
|
77
|
+
{columns.map(({ field, name, isVisible }) => (
|
|
78
|
+
<div key={field.toString()}>
|
|
79
|
+
<EuiFormRow display="columnCompressed" label={name} css={formRowStyle}>
|
|
80
|
+
<EuiSwitch
|
|
81
|
+
showLabel={false}
|
|
82
|
+
label={name}
|
|
83
|
+
checked={isVisible}
|
|
84
|
+
onChange={() => {
|
|
85
|
+
handleUpdateColumnVisibility(field);
|
|
86
|
+
}}
|
|
87
|
+
compressed
|
|
88
|
+
/>
|
|
89
|
+
</EuiFormRow>
|
|
90
|
+
<EuiHorizontalRule margin="xs" />
|
|
91
|
+
</div>
|
|
92
|
+
))}
|
|
93
|
+
</div>
|
|
91
94
|
<EuiSpacer size="xs" />
|
|
92
95
|
|
|
93
96
|
<EuiFormRow css={formRowStyle} hasEmptyLabelSpace label={t('numberOfRows')} display="columnCompressed">
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { transparentize } from '@elastic/eui';
|
|
1
2
|
import { css } from '@emotion/react';
|
|
2
3
|
|
|
3
4
|
import { WfoThemeHelpers } from '@/hooks';
|
|
@@ -13,8 +14,24 @@ export const getWfoTableSettingsModalStyles = (wfoThemeHelpers: WfoThemeHelpers)
|
|
|
13
14
|
},
|
|
14
15
|
});
|
|
15
16
|
|
|
17
|
+
const { theme } = wfoThemeHelpers;
|
|
18
|
+
|
|
19
|
+
const columnsListStyle = css({
|
|
20
|
+
maxHeight: theme.base * 16,
|
|
21
|
+
overflowY: 'auto',
|
|
22
|
+
paddingLeft: theme.base / 4,
|
|
23
|
+
marginBottom: theme.base / 2,
|
|
24
|
+
backgroundImage: `linear-gradient(to top, ${theme.colors.textGhost} ${theme.base}px, transparent),
|
|
25
|
+
radial-gradient(farthest-side at 50% 100%, ${transparentize(theme.colors.shadow, 0.24)}, transparent)`,
|
|
26
|
+
backgroundPosition: `center bottom, center bottom -${theme.base / 2}px`,
|
|
27
|
+
backgroundSize: `100% ${theme.base * 2}px, 100% ${theme.base}px`,
|
|
28
|
+
backgroundRepeat: 'no-repeat',
|
|
29
|
+
backgroundAttachment: 'local, scroll',
|
|
30
|
+
});
|
|
31
|
+
|
|
16
32
|
return {
|
|
17
33
|
formRowStyle,
|
|
34
|
+
columnsListStyle,
|
|
18
35
|
selectFieldStyle: formFieldBaseStyle,
|
|
19
36
|
};
|
|
20
37
|
};
|
|
@@ -4,6 +4,7 @@ export type StoredTableConfig<T> = {
|
|
|
4
4
|
hiddenColumns: TableColumnKeys<T>;
|
|
5
5
|
selectedPageSize: number;
|
|
6
6
|
showMatchDetails?: boolean;
|
|
7
|
+
advancedNestedSearch?: boolean;
|
|
7
8
|
};
|
|
8
9
|
|
|
9
10
|
export const isValidLocalStorageTableConfig = <T>(object: StoredTableConfig<T>): object is StoredTableConfig<T> =>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const ORCHESTRATOR_UI_LIBRARY_VERSION = '8.8.
|
|
1
|
+
export const ORCHESTRATOR_UI_LIBRARY_VERSION = '8.8.2';
|
|
@@ -163,11 +163,13 @@ const useGetComponentMatcherExtender = (): ComponentMatcherExtender => {
|
|
|
163
163
|
isControlledElement: true,
|
|
164
164
|
},
|
|
165
165
|
matcher(field) {
|
|
166
|
+
const fieldOptions = field.arrayItem?.options;
|
|
167
|
+
|
|
166
168
|
return (
|
|
167
169
|
field.type === PydanticFormFieldType.ARRAY
|
|
168
|
-
&& _.isArray(
|
|
169
|
-
&&
|
|
170
|
-
&&
|
|
170
|
+
&& _.isArray(fieldOptions)
|
|
171
|
+
&& fieldOptions?.length > 0
|
|
172
|
+
&& fieldOptions?.length <= 5
|
|
171
173
|
);
|
|
172
174
|
},
|
|
173
175
|
validator: zodValidationPresets.multiSelect,
|