@orchestrator-ui/orchestrator-ui-components 7.0.1 → 7.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchestrator-ui/orchestrator-ui-components",
3
- "version": "7.0.1",
3
+ "version": "7.1.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Library of UI Components used to display the workflow orchestrator frontend",
6
6
  "author": {
@@ -44,6 +44,7 @@
44
44
  "@emotion/react": "^11.11.4",
45
45
  "@monaco-editor/react": "^4.7.0",
46
46
  "@rtk-query/graphql-request-base-query": "^2.3.1",
47
+ "@tanstack/react-virtual": "^3.13.13",
47
48
  "graphql-request": "^6.1.0",
48
49
  "invariant": "^2.2.4",
49
50
  "lodash": "^4.17.21",
@@ -1,9 +1,10 @@
1
- import React, { useState } from 'react';
1
+ import React, { useRef, useState } from 'react';
2
2
  import type { CSSProperties, ReactNode } from 'react';
3
3
 
4
4
  import { useTranslations } from 'next-intl';
5
5
 
6
6
  import { EuiSpacer, EuiTablePagination, useEuiScrollBar } from '@elastic/eui';
7
+ import { useVirtualizer } from '@tanstack/react-virtual';
7
8
 
8
9
  import { useWithOrchestratorTheme } from '@/hooks';
9
10
 
@@ -28,6 +29,10 @@ export type Pagination = {
28
29
  onChangePage?: (pageIndex: number) => void;
29
30
  };
30
31
 
32
+ export type LocalColumnWidths = {
33
+ [key: string]: string;
34
+ };
35
+
31
36
  export enum ColumnType {
32
37
  DATA = 'data',
33
38
  CONTROL = 'control',
@@ -102,11 +107,11 @@ export type WfoTableProps<T extends object> = {
102
107
  onUpdateDataSearch?: (updatedDataSearch: WfoDataSearch<T>) => void;
103
108
  appendFillerColumn?: boolean;
104
109
  className?: string;
110
+ isVirtualized?: boolean;
111
+ height?: number;
105
112
  };
106
113
 
107
- export type LocalColumnWidths = {
108
- [key: string]: string;
109
- };
114
+ const ROW_HEIGHT = 44;
110
115
 
111
116
  export const WfoTable = <T extends object>({
112
117
  data,
@@ -123,10 +128,14 @@ export const WfoTable = <T extends object>({
123
128
  onRowClick,
124
129
  appendFillerColumn = true,
125
130
  className,
131
+ isVirtualized = false,
132
+ height,
126
133
  }: WfoTableProps<T>) => {
127
134
  const [localColumnWidths, setLocalColumnWidths] =
128
135
  useState<LocalColumnWidths>(getColumnWidthsFromConfig(columnConfig));
129
136
 
137
+ const parentRef = useRef<HTMLDivElement>(null);
138
+
130
139
  const columnConfigWithFiller: WfoTableColumnConfig<T> = appendFillerColumn
131
140
  ? {
132
141
  ...columnConfig,
@@ -181,9 +190,31 @@ export const WfoTable = <T extends object>({
181
190
  return mergedConfig;
182
191
  }, {} as WfoTableColumnConfig<T>);
183
192
 
193
+ const rowVirtualizer = useVirtualizer({
194
+ count: data.length,
195
+ getScrollElement: () => parentRef.current,
196
+ estimateSize: () => ROW_HEIGHT,
197
+ overscan: 10,
198
+ });
199
+
200
+ const virtualItems = rowVirtualizer.getVirtualItems();
201
+ const totalSize = rowVirtualizer.getTotalSize();
202
+ const lastVirtualItemEnd =
203
+ virtualItems.length > 0 ? virtualItems[virtualItems.length - 1].end : 0;
204
+ const virtualTrHeight = virtualItems[0]?.start ?? 0;
205
+ const bottomSpacerHeight = totalSize - lastVirtualItemEnd;
206
+
184
207
  return (
185
208
  <>
186
- <div css={[tableContainerStyle, useEuiScrollBar()]}>
209
+ <div
210
+ ref={parentRef}
211
+ css={[tableContainerStyle, useEuiScrollBar()]}
212
+ style={
213
+ isVirtualized && height
214
+ ? { maxHeight: height, overflow: 'auto' }
215
+ : {}
216
+ }
217
+ >
187
218
  <table className={className} css={tableStyle}>
188
219
  {overrideHeader ? (
189
220
  overrideHeader(sortedVisibleColumns)
@@ -213,6 +244,33 @@ export const WfoTable = <T extends object>({
213
244
  </td>
214
245
  </tr>
215
246
  </tbody>
247
+ ) : isVirtualized && height ? (
248
+ <tbody>
249
+ <tr
250
+ style={{
251
+ height: virtualTrHeight,
252
+ }}
253
+ />
254
+
255
+ {virtualItems.map((virtualRow) => (
256
+ <WfoTableDataRows
257
+ key={virtualRow.key}
258
+ data={[data[virtualRow.index]]}
259
+ columnConfig={configWithLocalWidths}
260
+ hiddenColumns={hiddenColumns}
261
+ columnOrder={columnOrder}
262
+ rowExpandingConfiguration={
263
+ rowExpandingConfiguration
264
+ }
265
+ onRowClick={onRowClick}
266
+ />
267
+ ))}
268
+ <tr
269
+ style={{
270
+ height: bottomSpacerHeight,
271
+ }}
272
+ />
273
+ </tbody>
216
274
  ) : (
217
275
  <tbody css={isLoading && bodyLoadingStyle}>
218
276
  <WfoTableDataRows
@@ -0,0 +1,62 @@
1
+ import React, { useRef } from 'react';
2
+
3
+ import { useVirtualizer } from '@tanstack/react-virtual';
4
+
5
+ type Props<T> = {
6
+ data: T[];
7
+ height: number;
8
+ renderRow: (row: T, index: number) => React.ReactNode;
9
+ };
10
+
11
+ const ESTIMATED_ROW_HEIGHT = 44;
12
+ const OVERSCAN_COUNT = 10;
13
+
14
+ export const WfoVirtualizedTableBody = <T,>({
15
+ data,
16
+ height,
17
+ renderRow,
18
+ }: Props<T>) => {
19
+ const parentRef = useRef<HTMLDivElement>(null);
20
+
21
+ const rowVirtualizer = useVirtualizer({
22
+ count: data.length,
23
+ getScrollElement: () => parentRef.current,
24
+ estimateSize: () => ESTIMATED_ROW_HEIGHT,
25
+ overscan: OVERSCAN_COUNT,
26
+ });
27
+
28
+ const virtualItems = rowVirtualizer.getVirtualItems();
29
+ const totalSize = rowVirtualizer.getTotalSize();
30
+
31
+ const lastVirtualItemEnd =
32
+ virtualItems.length > 0 ? virtualItems[virtualItems.length - 1].end : 0;
33
+ const virtualTopSpacerHeight = virtualItems[0]?.start ?? 0;
34
+ const bottomSpacerHeight = totalSize - lastVirtualItemEnd;
35
+
36
+ return (
37
+ <div
38
+ ref={parentRef}
39
+ style={{
40
+ height,
41
+ overflowY: 'auto',
42
+ overflowX: 'hidden',
43
+ }}
44
+ >
45
+ <table style={{ width: '100%' }}>
46
+ <tbody style={{ position: 'relative' }}>
47
+ <tr style={{ height: virtualTopSpacerHeight }} />
48
+
49
+ {virtualItems.map((virtualRow) =>
50
+ renderRow(data[virtualRow.index], virtualRow.index),
51
+ )}
52
+
53
+ <tr
54
+ style={{
55
+ height: bottomSpacerHeight,
56
+ }}
57
+ />
58
+ </tbody>
59
+ </table>
60
+ </div>
61
+ );
62
+ };
@@ -41,9 +41,13 @@ export const getWfoTableStyles = ({ theme, isDarkThemeActive }: WfoTheme) => {
41
41
  });
42
42
 
43
43
  const headerStyle = css({
44
+ position: 'sticky',
45
+ top: 0,
46
+ zIndex: 3,
44
47
  backgroundColor: theme.colors.lightShade,
45
48
  fontSize: theme.size.m,
46
49
  textAlign: 'left',
50
+
47
51
  'tr>:first-child': {
48
52
  borderTopLeftRadius: radius,
49
53
  },
@@ -85,7 +89,7 @@ export const getWfoTableStyles = ({ theme, isDarkThemeActive }: WfoTheme) => {
85
89
 
86
90
  const sortableHeaderCellStyle = css({
87
91
  paddingRight: 0,
88
- [`&:hover`]: {
92
+ '&:hover': {
89
93
  [`.${SORTABLE_ICON_CLASS}`]: {
90
94
  visibility: 'visible',
91
95
  },
@@ -1 +1 @@
1
- export const ORCHESTRATOR_UI_LIBRARY_VERSION = '7.0.1';
1
+ export const ORCHESTRATOR_UI_LIBRARY_VERSION = '7.1.0';