@orchestrator-ui/orchestrator-ui-components 8.7.3 → 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 +8 -8
- package/.turbo/turbo-lint.log +1 -1
- package/.turbo/turbo-test.log +17 -15
- package/CHANGELOG.md +34 -0
- package/dist/index.d.ts +42 -20
- package/dist/index.js +1612 -1378
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/components/WfoBadges/WfoWorkflowTargetBadge/WfoWorkflowTargetBadge.tsx +2 -2
- package/src/components/WfoContentHeader/WfoContentHeader.tsx +1 -1
- package/src/components/WfoInlineNoteEdit/WfoProcessListNoteEdit.spec.tsx +35 -0
- package/src/components/WfoInlineNoteEdit/WfoProcessListNoteEdit.tsx +7 -9
- package/src/components/WfoProcessList/WfoProcessListDeltaPopover.tsx +1 -1
- package/src/components/WfoProcessList/WfoProcessesList.tsx +7 -5
- package/src/components/WfoPydanticForm/fields/WfoMultiCheckboxField.tsx +2 -1
- package/src/components/WfoSubscription/WfoProcessesTimeline.tsx +21 -7
- package/src/components/WfoSubscription/WfoSubscriptionActions/WfoSubscriptionActions.tsx +25 -9
- package/src/components/WfoSubscription/WfoSubscriptionGeneralSections/WfoSubscriptionDetailSection.tsx +1 -1
- package/src/components/WfoSubscription/styles.ts +6 -0
- package/src/components/WfoSubscription/utils/utils.ts +2 -4
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoExpandingSearchRow.tsx +0 -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 +73 -3
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoValueEditor.tsx +4 -2
- package/src/components/WfoTable/WfoStructuredSearchTable/styles.ts +8 -9
- package/src/components/WfoTable/WfoTable/WfoTable.tsx +80 -45
- package/src/components/WfoTable/WfoTable/WfoTableDataRows.tsx +11 -2
- package/src/components/WfoTable/WfoTable/WfoTableExpandedRowReveal.spec.tsx +120 -0
- package/src/components/WfoTable/WfoTable/WfoTableSkeletonRows.tsx +52 -0
- package/src/components/WfoTable/WfoTable/index.ts +1 -0
- package/src/components/WfoTable/WfoTable/styles.ts +6 -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 +2 -0
- package/src/components/WfoTimeline/styles.ts +1 -1
- package/src/components/WfoWorkflowUserGuide/WfoPageWithUserGuide.tsx +8 -2
- package/src/components/WfoWorkflowUserGuide/WfoWorkflowGuideExpandablePanel.tsx +39 -30
- package/src/components/WfoWorkflowUserGuide/styles.ts +55 -7
- package/src/configuration/constants.ts +1 -1
- 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 +2 -0
- package/src/messages/en-GB.json +5 -1
- package/src/messages/nl-NL.json +6 -2
- package/src/pages/WfoSearchPocPage.tsx +29 -24
- package/src/pages/processes/WfoProductInformationWithLink.tsx +9 -4
- package/src/pages/tasks/WfoTasksListPage.tsx +1 -0
- package/src/types/search.ts +8 -0
- package/src/types/types.ts +11 -11
- package/src/utils/getDefaultTableConfig.ts +2 -0
|
@@ -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
|
|
@@ -2,7 +2,7 @@ import { css } from '@emotion/react';
|
|
|
2
2
|
|
|
3
3
|
import { WfoThemeHelpers } from '@/hooks';
|
|
4
4
|
|
|
5
|
-
export const getWfoStructuredSearchTableStyles = ({ theme }: WfoThemeHelpers) => {
|
|
5
|
+
export const getWfoStructuredSearchTableStyles = ({ theme, isDarkModeActive }: WfoThemeHelpers) => {
|
|
6
6
|
const queryBuilderContainerStyles = css({
|
|
7
7
|
backgroundColor: theme.colors.backgroundBaseSubdued,
|
|
8
8
|
padding: theme.base / 2,
|
|
@@ -63,7 +63,7 @@ export const getWfoStructuredSearchTableStyles = ({ theme }: WfoThemeHelpers) =>
|
|
|
63
63
|
const ruleGroupContainerBlueStyles = css({
|
|
64
64
|
...ruleGroupContainerBase,
|
|
65
65
|
borderRadius: theme.border.radius.small,
|
|
66
|
-
backgroundColor: '#E9F1F9',
|
|
66
|
+
backgroundColor: isDarkModeActive ? theme.colors.backgroundLightPrimary : '#E9F1F9',
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
const ruleGroupContainerWhiteStyles = css({
|
|
@@ -83,7 +83,7 @@ export const getWfoStructuredSearchTableStyles = ({ theme }: WfoThemeHelpers) =>
|
|
|
83
83
|
...ruleGroupContainerBase,
|
|
84
84
|
borderBottomLeftRadius: theme.border.radius.small,
|
|
85
85
|
borderTopLeftRadius: theme.border.radius.small,
|
|
86
|
-
backgroundColor: '#E9F1F9',
|
|
86
|
+
backgroundColor: isDarkModeActive ? theme.colors.backgroundLightPrimary : '#E9F1F9',
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
const removeGroupActionStyles = css({
|
|
@@ -99,11 +99,10 @@ export const getWfoStructuredSearchTableStyles = ({ theme }: WfoThemeHelpers) =>
|
|
|
99
99
|
});
|
|
100
100
|
|
|
101
101
|
const expandingSearchRowStyles = css({
|
|
102
|
-
padding: theme.base / 2
|
|
103
|
-
height: theme.base * 2,
|
|
102
|
+
padding: `${theme.base / 4}px ${theme.base / 2}px`,
|
|
104
103
|
borderRadius: theme.border.radius.medium,
|
|
105
|
-
border:
|
|
106
|
-
backgroundColor:
|
|
104
|
+
border: `thin solid ${theme.colors.highlight}`,
|
|
105
|
+
backgroundColor: theme.colors.highlight,
|
|
107
106
|
});
|
|
108
107
|
const expandingRowBodyStyles = css({
|
|
109
108
|
display: 'flex',
|
|
@@ -166,12 +165,12 @@ export const getWfoStructuredSearchTableStyles = ({ theme }: WfoThemeHelpers) =>
|
|
|
166
165
|
display: 'none',
|
|
167
166
|
});
|
|
168
167
|
const dotStyles = css({
|
|
169
|
-
padding: theme.base / 4
|
|
168
|
+
padding: `${theme.base / 8}px ${theme.base / 4}px`,
|
|
170
169
|
});
|
|
171
170
|
|
|
172
171
|
const expandingRowFieldStyles = css({
|
|
173
172
|
display: 'flex',
|
|
174
|
-
padding: theme.base / 4
|
|
173
|
+
padding: `${theme.base / 8}px ${theme.base / 4}px`,
|
|
175
174
|
alignItems: 'center',
|
|
176
175
|
});
|
|
177
176
|
|
|
@@ -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,12 +79,14 @@ 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>;
|
|
84
86
|
uniqueRowIdToExpandedRowMap: Record<string, ReactNode>;
|
|
85
|
-
shouldOnlyShowOnHover?: boolean;
|
|
86
87
|
};
|
|
88
|
+
// When true, every row's expanded detail row is revealed at once (otherwise all are hidden)
|
|
89
|
+
showExpandedRows?: boolean;
|
|
87
90
|
pagination?: Pagination;
|
|
88
91
|
overrideHeader?: (
|
|
89
92
|
tableHeaderEntries: Array<[string, WfoTableControlColumnConfigItem<T> | WfoTableDataColumnConfigItem<T, keyof T>]>,
|
|
@@ -105,8 +108,10 @@ export const WfoTable = <T extends object>({
|
|
|
105
108
|
hiddenColumns = [],
|
|
106
109
|
columnOrder = [],
|
|
107
110
|
isLoading = false,
|
|
111
|
+
loadingSkeletonRowCount,
|
|
108
112
|
dataSorting = [],
|
|
109
113
|
rowExpandingConfiguration,
|
|
114
|
+
showExpandedRows = false,
|
|
110
115
|
pagination,
|
|
111
116
|
overrideHeader,
|
|
112
117
|
onUpdateDataSorting,
|
|
@@ -123,6 +128,8 @@ export const WfoTable = <T extends object>({
|
|
|
123
128
|
const dataLength = data.length;
|
|
124
129
|
usePageIndexBoundsGuard({ dataLength, isLoading, pagination });
|
|
125
130
|
|
|
131
|
+
const showLoadingSkeleton = !!loadingSkeletonRowCount && isLoading && dataLength === 0;
|
|
132
|
+
|
|
126
133
|
const parentRef = useRef<HTMLDivElement>(null);
|
|
127
134
|
|
|
128
135
|
const columnConfigWithFiller: WfoTableColumnConfig<T> =
|
|
@@ -190,6 +197,77 @@ export const WfoTable = <T extends object>({
|
|
|
190
197
|
const virtualTrHeight = virtualItems[0]?.start ?? 0;
|
|
191
198
|
const bottomSpacerHeight = totalSize - lastVirtualItemEnd;
|
|
192
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
|
+
|
|
193
271
|
return (
|
|
194
272
|
<>
|
|
195
273
|
<div
|
|
@@ -212,50 +290,7 @@ export const WfoTable = <T extends object>({
|
|
|
212
290
|
/>
|
|
213
291
|
</thead>
|
|
214
292
|
}
|
|
215
|
-
{
|
|
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
|
-
: isVirtualized && height ?
|
|
224
|
-
<tbody>
|
|
225
|
-
<tr
|
|
226
|
-
style={{
|
|
227
|
-
height: virtualTrHeight,
|
|
228
|
-
}}
|
|
229
|
-
/>
|
|
230
|
-
|
|
231
|
-
{virtualItems.map((virtualRow) => (
|
|
232
|
-
<WfoTableDataRows
|
|
233
|
-
key={virtualRow.key}
|
|
234
|
-
data={[data[virtualRow.index]]}
|
|
235
|
-
columnConfig={configWithLocalWidths}
|
|
236
|
-
hiddenColumns={hiddenColumns}
|
|
237
|
-
columnOrder={columnOrder}
|
|
238
|
-
rowExpandingConfiguration={rowExpandingConfiguration}
|
|
239
|
-
onRowClick={onRowClick}
|
|
240
|
-
/>
|
|
241
|
-
))}
|
|
242
|
-
<tr
|
|
243
|
-
style={{
|
|
244
|
-
height: bottomSpacerHeight,
|
|
245
|
-
}}
|
|
246
|
-
/>
|
|
247
|
-
</tbody>
|
|
248
|
-
: <tbody css={isLoading && bodyLoadingStyle}>
|
|
249
|
-
<WfoTableDataRows
|
|
250
|
-
data={data}
|
|
251
|
-
columnConfig={configWithLocalWidths}
|
|
252
|
-
hiddenColumns={hiddenColumns}
|
|
253
|
-
columnOrder={columnOrder}
|
|
254
|
-
rowExpandingConfiguration={rowExpandingConfiguration}
|
|
255
|
-
onRowClick={onRowClick}
|
|
256
|
-
/>
|
|
257
|
-
</tbody>
|
|
258
|
-
}
|
|
293
|
+
{<WfoTableBody />}
|
|
259
294
|
</table>
|
|
260
295
|
</div>
|
|
261
296
|
{pagination && (
|
|
@@ -11,7 +11,14 @@ import { getSortedVisibleColumns } from './utils';
|
|
|
11
11
|
|
|
12
12
|
export type WfoTableDataRowsProps<T extends object> = Pick<
|
|
13
13
|
WfoTableProps<T>,
|
|
14
|
-
|
|
14
|
+
| 'data'
|
|
15
|
+
| 'columnConfig'
|
|
16
|
+
| 'hiddenColumns'
|
|
17
|
+
| 'columnOrder'
|
|
18
|
+
| 'rowExpandingConfiguration'
|
|
19
|
+
| 'showExpandedRows'
|
|
20
|
+
| 'onRowClick'
|
|
21
|
+
| 'className'
|
|
15
22
|
>;
|
|
16
23
|
|
|
17
24
|
export const DATA_ROW_CLASS = 'data-row';
|
|
@@ -24,6 +31,7 @@ export const WfoTableDataRows = <T extends object>({
|
|
|
24
31
|
hiddenColumns = [],
|
|
25
32
|
columnOrder = [],
|
|
26
33
|
rowExpandingConfiguration,
|
|
34
|
+
showExpandedRows,
|
|
27
35
|
onRowClick,
|
|
28
36
|
className,
|
|
29
37
|
}: WfoTableDataRowsProps<T>) => {
|
|
@@ -34,6 +42,7 @@ export const WfoTableDataRows = <T extends object>({
|
|
|
34
42
|
dataRowStyle,
|
|
35
43
|
clickableStyle,
|
|
36
44
|
setWidth,
|
|
45
|
+
showExpandedRowStyle,
|
|
37
46
|
toggleExpandedRowOnHoverStyle,
|
|
38
47
|
} = useWithOrchestratorTheme(getWfoTableStyles);
|
|
39
48
|
|
|
@@ -49,7 +58,7 @@ export const WfoTableDataRows = <T extends object>({
|
|
|
49
58
|
rowStyle,
|
|
50
59
|
dataRowStyle,
|
|
51
60
|
onRowClick && clickableStyle,
|
|
52
|
-
rowExpandingConfiguration
|
|
61
|
+
rowExpandingConfiguration && (showExpandedRows ? showExpandedRowStyle : toggleExpandedRowOnHoverStyle),
|
|
53
62
|
]}
|
|
54
63
|
onClick={() => onRowClick?.(row)}
|
|
55
64
|
>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The expanded ("match details") row under each data row hides itself with display: none and
|
|
3
|
+
* is revealed by sibling selectors that WfoTable puts on the data row: always when
|
|
4
|
+
* showExpandedRows is set, and on hover/focus otherwise. These tests pin the whole mechanism
|
|
5
|
+
* down at the DOM level: the detail row must be the data row's next sibling, the reveal rules
|
|
6
|
+
* must be emitted, and their selectors must actually match the detail row.
|
|
7
|
+
*/
|
|
8
|
+
import React from 'react';
|
|
9
|
+
|
|
10
|
+
import { css } from '@emotion/react';
|
|
11
|
+
import '@testing-library/jest-dom';
|
|
12
|
+
import { render, screen } from '@testing-library/react';
|
|
13
|
+
|
|
14
|
+
import { ColumnType, WfoTable, WfoTableColumnConfig } from './WfoTable';
|
|
15
|
+
|
|
16
|
+
jest.mock('next-intl', () => ({
|
|
17
|
+
useTranslations: () => (key: string) => key,
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
type Item = { id: string; name: string };
|
|
21
|
+
|
|
22
|
+
const data: Item[] = [
|
|
23
|
+
{ id: 'row-1', name: 'First row' },
|
|
24
|
+
{ id: 'row-2', name: 'Second row' },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const columnConfig: WfoTableColumnConfig<Item> = {
|
|
28
|
+
name: {
|
|
29
|
+
columnType: ColumnType.DATA,
|
|
30
|
+
label: 'Name',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Mimics WfoExpandingSearchRow: a <tr> that hides itself
|
|
35
|
+
const hideStyle = css({ display: 'none' });
|
|
36
|
+
const DetailRow = ({ text }: { text: string }) => (
|
|
37
|
+
<tr css={hideStyle}>
|
|
38
|
+
<td>{text}</td>
|
|
39
|
+
</tr>
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const rowExpandingConfiguration = {
|
|
43
|
+
uniqueRowId: 'id' as keyof WfoTableColumnConfig<Item>,
|
|
44
|
+
uniqueRowIdToExpandedRowMap: {
|
|
45
|
+
'row-1': <DetailRow text="detail-1" />,
|
|
46
|
+
'row-2': <DetailRow text="detail-2" />,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Emotion may insert rules through the CSSOM, leaving <style> tags without text content, so
|
|
51
|
+
// read the rules from document.styleSheets. Returns [selectorText, display] pairs, with the
|
|
52
|
+
// selector whitespace stripped since the CSSOM normalizes it.
|
|
53
|
+
const getDisplayRules = () =>
|
|
54
|
+
Array.from(document.styleSheets)
|
|
55
|
+
.flatMap((sheet) => Array.from(sheet.cssRules))
|
|
56
|
+
.filter((rule): rule is CSSStyleRule => 'selectorText' in rule)
|
|
57
|
+
.map((rule): [string, string] => [rule.selectorText.replace(/\s+/g, ''), rule.style.display])
|
|
58
|
+
.filter(([, display]) => Boolean(display));
|
|
59
|
+
|
|
60
|
+
const getRowPair = () => {
|
|
61
|
+
const dataRow = screen.getByText('First row').closest('tr');
|
|
62
|
+
const detailRow = dataRow?.nextElementSibling;
|
|
63
|
+
return { dataRow, detailRow };
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// The reveal selectors resolve '&' to the emotion class composed on the data row
|
|
67
|
+
const getDataRowEmotionClass = (dataRow: HTMLTableRowElement) => {
|
|
68
|
+
const emotionClass = Array.from(dataRow.classList).find((className) => className.startsWith('css-'));
|
|
69
|
+
expect(emotionClass).toBeDefined();
|
|
70
|
+
return emotionClass;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
describe('WfoTable expanded row reveal', () => {
|
|
74
|
+
it('renders the detail row as next sibling of its data row, hidden by its own style', () => {
|
|
75
|
+
render(
|
|
76
|
+
<WfoTable<Item> data={data} columnConfig={columnConfig} rowExpandingConfiguration={rowExpandingConfiguration} />,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const { dataRow, detailRow } = getRowPair();
|
|
80
|
+
expect(dataRow).toBeInTheDocument();
|
|
81
|
+
expect(detailRow).toHaveTextContent('detail-1');
|
|
82
|
+
|
|
83
|
+
const detailRowClass = Array.from(detailRow!.classList).find((className) => className.startsWith('css-'));
|
|
84
|
+
expect(getDisplayRules()).toContainEqual([`.${detailRowClass}`, 'none']);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('reveals every detail row through the sibling selector when showExpandedRows is set', () => {
|
|
88
|
+
render(
|
|
89
|
+
<WfoTable<Item>
|
|
90
|
+
data={data}
|
|
91
|
+
columnConfig={columnConfig}
|
|
92
|
+
rowExpandingConfiguration={rowExpandingConfiguration}
|
|
93
|
+
showExpandedRows
|
|
94
|
+
/>,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const { dataRow, detailRow } = getRowPair();
|
|
98
|
+
const emotionClass = getDataRowEmotionClass(dataRow!);
|
|
99
|
+
|
|
100
|
+
expect(getDisplayRules()).toContainEqual([`.${emotionClass}+tr`, 'table-row']);
|
|
101
|
+
expect(detailRow!.matches(`.${emotionClass} + tr`)).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('reveals a detail row on hover/focus of the data row or of the detail row itself when showExpandedRows is not set', () => {
|
|
105
|
+
render(
|
|
106
|
+
<WfoTable<Item> data={data} columnConfig={columnConfig} rowExpandingConfiguration={rowExpandingConfiguration} />,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const { dataRow, detailRow } = getRowPair();
|
|
110
|
+
const emotionClass = getDataRowEmotionClass(dataRow!);
|
|
111
|
+
const displayRules = getDisplayRules();
|
|
112
|
+
|
|
113
|
+
expect(displayRules).toContainEqual([`.${emotionClass}:hover+tr,.${emotionClass}:focus-within+tr`, 'table-row']);
|
|
114
|
+
// The rule that keeps the row open while hovering the revealed row itself (flicker fix)
|
|
115
|
+
expect(displayRules).toContainEqual([`.${emotionClass}+tr:hover,.${emotionClass}+tr:focus-within`, 'table-row']);
|
|
116
|
+
|
|
117
|
+
// :hover cannot be simulated in jsdom; verify the selectors structurally instead
|
|
118
|
+
expect(detailRow!.matches(`.${emotionClass} + tr`)).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -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';
|
|
@@ -160,8 +160,13 @@ export const getWfoTableStyles = ({ theme, isDarkModeActive }: WfoThemeHelpers)
|
|
|
160
160
|
'.eui-xScroll': { display: 'flex', justifyContent: 'flex-start' },
|
|
161
161
|
});
|
|
162
162
|
|
|
163
|
+
const showExpandedRowStyle = css({
|
|
164
|
+
'& + tr': { display: 'table-row' },
|
|
165
|
+
});
|
|
166
|
+
|
|
163
167
|
const toggleExpandedRowOnHoverStyle = css({
|
|
164
168
|
'&:hover + tr, &:focus-within + tr': { display: 'table-row' },
|
|
169
|
+
'& + tr:hover, & + tr:focus-within': { display: 'table-row' },
|
|
165
170
|
});
|
|
166
171
|
|
|
167
172
|
return {
|
|
@@ -181,6 +186,7 @@ export const getWfoTableStyles = ({ theme, isDarkModeActive }: WfoThemeHelpers)
|
|
|
181
186
|
dragAndDropStyle,
|
|
182
187
|
paginationStyle,
|
|
183
188
|
setWidth,
|
|
189
|
+
showExpandedRowStyle,
|
|
184
190
|
toggleExpandedRowOnHoverStyle,
|
|
185
191
|
};
|
|
186
192
|
};
|
|
@@ -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
|
};
|
|
@@ -3,6 +3,8 @@ import { TableColumnKeys } from './columns';
|
|
|
3
3
|
export type StoredTableConfig<T> = {
|
|
4
4
|
hiddenColumns: TableColumnKeys<T>;
|
|
5
5
|
selectedPageSize: number;
|
|
6
|
+
showMatchDetails?: boolean;
|
|
7
|
+
advancedNestedSearch?: boolean;
|
|
6
8
|
};
|
|
7
9
|
|
|
8
10
|
export const isValidLocalStorageTableConfig = <T>(object: StoredTableConfig<T>): object is StoredTableConfig<T> =>
|
|
@@ -57,7 +57,7 @@ export const getTimelineStyles = ({ theme }: WfoThemeHelpers) => {
|
|
|
57
57
|
paddingLeft: theme.font.baseline * 4,
|
|
58
58
|
paddingRight: theme.font.baseline * 4,
|
|
59
59
|
position: 'sticky',
|
|
60
|
-
top:
|
|
60
|
+
top: theme.base / 4,
|
|
61
61
|
zIndex: 2, // Some EUI components have a zIndex
|
|
62
62
|
display: 'flex',
|
|
63
63
|
|
|
@@ -29,9 +29,15 @@ export const WfoPageWithUserGuide = ({ workflowName, children }: WfoFormWithUser
|
|
|
29
29
|
);
|
|
30
30
|
|
|
31
31
|
return (
|
|
32
|
-
<EuiFlexGroup
|
|
32
|
+
<EuiFlexGroup
|
|
33
|
+
gutterSize="s"
|
|
34
|
+
direction={isBigScreen ? 'row' : 'column'}
|
|
35
|
+
alignItems={isBigScreen ? 'flexStart' : 'stretch'}
|
|
36
|
+
>
|
|
33
37
|
{!isBigScreen && workflowGuideExpandablePanel}
|
|
34
|
-
<EuiFlexItem grow={true}
|
|
38
|
+
<EuiFlexItem grow={true} css={{ minWidth: 0 }}>
|
|
39
|
+
{children}
|
|
40
|
+
</EuiFlexItem>
|
|
35
41
|
{isBigScreen && workflowGuideExpandablePanel}
|
|
36
42
|
</EuiFlexGroup>
|
|
37
43
|
);
|