@patternfly/react-data-view 5.1.4 → 5.2.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 (35) hide show
  1. package/dist/cjs/DataView/DataView.d.ts +8 -0
  2. package/dist/cjs/DataView/DataView.js +9 -4
  3. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.d.ts +3 -2
  4. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.js +6 -7
  5. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.js +8 -1
  6. package/dist/cjs/DataViewTableTree/DataViewTableTree.d.ts +3 -2
  7. package/dist/cjs/DataViewTableTree/DataViewTableTree.js +16 -5
  8. package/dist/cjs/DataViewTableTree/DataViewTableTree.test.js +7 -1
  9. package/dist/cjs/InternalContext/InternalContext.d.ts +2 -0
  10. package/dist/cjs/InternalContext/InternalContext.js +3 -2
  11. package/dist/esm/DataView/DataView.d.ts +8 -0
  12. package/dist/esm/DataView/DataView.js +8 -3
  13. package/dist/esm/DataViewTableBasic/DataViewTableBasic.d.ts +3 -2
  14. package/dist/esm/DataViewTableBasic/DataViewTableBasic.js +6 -7
  15. package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.js +8 -1
  16. package/dist/esm/DataViewTableTree/DataViewTableTree.d.ts +3 -2
  17. package/dist/esm/DataViewTableTree/DataViewTableTree.js +16 -5
  18. package/dist/esm/DataViewTableTree/DataViewTableTree.test.js +7 -1
  19. package/dist/esm/InternalContext/InternalContext.d.ts +2 -0
  20. package/dist/esm/InternalContext/InternalContext.js +3 -2
  21. package/package.json +1 -1
  22. package/patternfly-docs/content/extensions/data-view/examples/Components/Components.md +10 -3
  23. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableEmptyExample.tsx +11 -8
  24. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableErrorExample.tsx +38 -0
  25. package/patternfly-docs/content/extensions/data-view/examples/Layout/Layout.md +1 -1
  26. package/src/DataView/DataView.tsx +14 -4
  27. package/src/DataView/__snapshots__/DataView.test.tsx.snap +2 -2
  28. package/src/DataViewTableBasic/DataViewTableBasic.test.tsx +13 -1
  29. package/src/DataViewTableBasic/DataViewTableBasic.tsx +42 -39
  30. package/src/DataViewTableBasic/__snapshots__/DataViewTableBasic.test.tsx.snap +178 -73
  31. package/src/DataViewTableHeader/__snapshots__/DataViewTableHeader.test.tsx.snap +2 -2
  32. package/src/DataViewTableTree/DataViewTableTree.test.tsx +13 -1
  33. package/src/DataViewTableTree/DataViewTableTree.tsx +24 -11
  34. package/src/DataViewTableTree/__snapshots__/DataViewTableTree.test.tsx.snap +176 -71
  35. package/src/InternalContext/InternalContext.tsx +7 -3
@@ -7,7 +7,7 @@ exports[`DataView component should render correctly 1`] = `
7
7
  <div>
8
8
  <div
9
9
  class="pf-v5-l-stack"
10
- data-ouia-component-id="DataView-stack}"
10
+ data-ouia-component-id="DataView-stack"
11
11
  >
12
12
  <div
13
13
  class="pf-v5-l-stack__item"
@@ -45,7 +45,7 @@ exports[`DataView component should render correctly 1`] = `
45
45
  "container": <div>
46
46
  <div
47
47
  class="pf-v5-l-stack"
48
- data-ouia-component-id="DataView-stack}"
48
+ data-ouia-component-id="DataView-stack"
49
49
  >
50
50
  <div
51
51
  class="pf-v5-l-stack__item"
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { render } from '@testing-library/react';
3
3
  import { DataViewTableBasic } from './DataViewTableBasic';
4
+ import DataView from '../DataView/DataView';
4
5
 
5
6
  interface Repository {
6
7
  name: string;
@@ -37,7 +38,18 @@ describe('DataViewTable component', () => {
37
38
 
38
39
  test('should render with an empty state', () => {
39
40
  const { container } = render(
40
- <DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} emptyState="No data found" rows={[]} />
41
+ <DataView activeState="empty">
42
+ <DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} states={{ empty:"No data found" }} rows={[]} />
43
+ </DataView>
44
+ );
45
+ expect(container).toMatchSnapshot();
46
+ });
47
+
48
+ test('should render with an error state', () => {
49
+ const { container } = render(
50
+ <DataView activeState="error">
51
+ <DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} states={{ error:"Some error" }} rows={[]} />
52
+ </DataView>
41
53
  );
42
54
  expect(container).toMatchSnapshot();
43
55
  });
@@ -9,14 +9,15 @@ import {
9
9
  import { useInternalContext } from '../InternalContext';
10
10
  import { DataViewTableHeader } from '../DataViewTableHeader';
11
11
  import { DataViewTh, DataViewTr, isDataViewTdObject, isDataViewTrObject } from '../DataViewTable';
12
+ import { DataViewState } from '../DataView/DataView';
12
13
 
13
14
  export interface DataViewTableBasicProps extends Omit<TableProps, 'onSelect' | 'rows'> {
14
15
  /** Columns definition */
15
16
  columns: DataViewTh[];
16
17
  /** Current page rows */
17
18
  rows: DataViewTr[];
18
- /** Empty state to be displayed */
19
- emptyState?: React.ReactNode;
19
+ /** States to be displayed when active */
20
+ states?: Partial<Record<DataViewState, React.ReactNode>>
20
21
  /** Custom OUIA ID */
21
22
  ouiaId?: string;
22
23
  }
@@ -25,54 +26,56 @@ export const DataViewTableBasic: React.FC<DataViewTableBasicProps> = ({
25
26
  columns,
26
27
  rows,
27
28
  ouiaId = 'DataViewTableBasic',
28
- emptyState = null,
29
+ states = {},
29
30
  ...props
30
31
  }: DataViewTableBasicProps) => {
31
- const { selection } = useInternalContext();
32
+ const { selection, activeState } = useInternalContext();
32
33
  const { onSelect, isSelected, isSelectDisabled } = selection ?? {};
33
- const isSelectable = useMemo(() => Boolean(onSelect && isSelected), [ onSelect, isSelected ])
34
+ const isSelectable = useMemo(() => Boolean(onSelect && isSelected), [ onSelect, isSelected ]);
34
35
 
35
36
  return (
36
37
  <Table aria-label="Data table" ouiaId={ouiaId} {...props}>
37
38
  <DataViewTableHeader columns={columns} ouiaId={ouiaId} />
38
39
  <Tbody>
39
- {rows?.length > 0 ? rows.map((row, rowIndex) => {
40
- const rowIsObject = isDataViewTrObject(row);
41
- return (
42
- <Tr key={rowIndex} ouiaId={`${ouiaId}-tr-${rowIndex}`} {...(rowIsObject && (row?.props ?? {}))}>
43
- {isSelectable && (
44
- <Td
45
- key={`select-${rowIndex}`}
46
- select={{
47
- rowIndex,
48
- onSelect: (_event, isSelecting) => {
49
- onSelect?.(isSelecting, rowIsObject ? row : [ row ])
50
- },
51
- isSelected: isSelected?.(row) || false,
52
- isDisabled: isSelectDisabled?.(row) || false,
53
- }}
54
- />
55
- )}
56
- {(rowIsObject ? row.row : row).map((cell, colIndex) => {
57
- const cellIsObject = isDataViewTdObject(cell);
58
- return (
59
- <Td
60
- key={colIndex}
61
- {...(cellIsObject && (cell?.props ?? {}))}
62
- data-ouia-component-id={`${ouiaId}-td-${rowIndex}-${colIndex}`}
63
- >
64
- {cellIsObject ? cell.cell : cell}
65
- </Td>
66
- )
67
- })}
68
- </Tr>
69
- )}) : (
70
- <Tr key="empty" ouiaId={`${ouiaId}-tr-empty`}>
40
+ {activeState && Object.keys(states).includes(activeState) ? (
41
+ <Tr key={activeState} ouiaId={`${ouiaId}-tr-${activeState}`}>
71
42
  <Td colSpan={columns.length + Number(isSelectable)}>
72
- {emptyState}
43
+ {states[activeState]}
73
44
  </Td>
74
45
  </Tr>
75
- )}
46
+ ) : (
47
+ rows.map((row, rowIndex) => {
48
+ const rowIsObject = isDataViewTrObject(row);
49
+ return (
50
+ <Tr key={rowIndex} ouiaId={`${ouiaId}-tr-${rowIndex}`} {...(rowIsObject && row?.props)}>
51
+ {isSelectable && (
52
+ <Td
53
+ key={`select-${rowIndex}`}
54
+ select={{
55
+ rowIndex,
56
+ onSelect: (_event, isSelecting) => {
57
+ onSelect?.(isSelecting, rowIsObject ? row : [ row ]);
58
+ },
59
+ isSelected: isSelected?.(row) || false,
60
+ isDisabled: isSelectDisabled?.(row) || false,
61
+ }}
62
+ />
63
+ )}
64
+ {(rowIsObject ? row.row : row).map((cell, colIndex) => {
65
+ const cellIsObject = isDataViewTdObject(cell);
66
+ return (
67
+ <Td
68
+ key={colIndex}
69
+ {...(cellIsObject && (cell?.props ?? {}))}
70
+ data-ouia-component-id={`${ouiaId}-td-${rowIndex}-${colIndex}`}
71
+ >
72
+ {cellIsObject ? cell.cell : cell}
73
+ </Td>
74
+ );
75
+ })}
76
+ </Tr>
77
+ );
78
+ }))}
76
79
  </Tbody>
77
80
  </Table>
78
81
  );
@@ -325,85 +325,190 @@ exports[`DataViewTable component should render correctly 1`] = `
325
325
 
326
326
  exports[`DataViewTable component should render with an empty state 1`] = `
327
327
  <div>
328
- <table
329
- aria-label="Repositories table"
330
- class="pf-v5-c-table pf-m-grid-md"
331
- data-ouia-component-id="TableExample"
332
- data-ouia-component-type="PF5/Table"
333
- data-ouia-safe="true"
334
- role="grid"
328
+ <div
329
+ class="pf-v5-l-stack"
330
+ data-ouia-component-id="DataView-stack"
335
331
  >
336
- <thead
337
- class="pf-v5-c-table__thead"
338
- data-ouia-component-id="TableExample-thead"
332
+ <div
333
+ class="pf-v5-l-stack__item"
334
+ data-ouia-component-id="DataView-stack-item-0"
339
335
  >
340
- <tr
341
- class="pf-v5-c-table__tr"
342
- data-ouia-component-id="TableExample-tr-head"
343
- data-ouia-component-type="PF5/TableRow"
336
+ <table
337
+ aria-label="Repositories table"
338
+ class="pf-v5-c-table pf-m-grid-md"
339
+ data-ouia-component-id="TableExample"
340
+ data-ouia-component-type="PF5/Table"
344
341
  data-ouia-safe="true"
342
+ role="grid"
345
343
  >
346
- <th
347
- class="pf-v5-c-table__th"
348
- data-ouia-component-id="TableExample-th-0"
349
- scope="col"
350
- tabindex="-1"
351
- >
352
- Repositories
353
- </th>
354
- <th
355
- class="pf-v5-c-table__th"
356
- data-ouia-component-id="TableExample-th-1"
357
- scope="col"
358
- tabindex="-1"
359
- >
360
- Branches
361
- </th>
362
- <th
363
- class="pf-v5-c-table__th"
364
- data-ouia-component-id="TableExample-th-2"
365
- scope="col"
366
- tabindex="-1"
367
- >
368
- Pull requests
369
- </th>
370
- <th
371
- class="pf-v5-c-table__th"
372
- data-ouia-component-id="TableExample-th-3"
373
- scope="col"
374
- tabindex="-1"
375
- >
376
- Workspaces
377
- </th>
378
- <th
379
- class="pf-v5-c-table__th"
380
- data-ouia-component-id="TableExample-th-4"
381
- scope="col"
382
- tabindex="-1"
383
- >
384
- Last commit
385
- </th>
386
- </tr>
387
- </thead>
388
- <tbody
389
- class="pf-v5-c-table__tbody"
390
- role="rowgroup"
344
+ <thead
345
+ class="pf-v5-c-table__thead"
346
+ data-ouia-component-id="TableExample-thead"
347
+ >
348
+ <tr
349
+ class="pf-v5-c-table__tr"
350
+ data-ouia-component-id="TableExample-tr-head"
351
+ data-ouia-component-type="PF5/TableRow"
352
+ data-ouia-safe="true"
353
+ >
354
+ <th
355
+ class="pf-v5-c-table__th"
356
+ data-ouia-component-id="TableExample-th-0"
357
+ scope="col"
358
+ tabindex="-1"
359
+ >
360
+ Repositories
361
+ </th>
362
+ <th
363
+ class="pf-v5-c-table__th"
364
+ data-ouia-component-id="TableExample-th-1"
365
+ scope="col"
366
+ tabindex="-1"
367
+ >
368
+ Branches
369
+ </th>
370
+ <th
371
+ class="pf-v5-c-table__th"
372
+ data-ouia-component-id="TableExample-th-2"
373
+ scope="col"
374
+ tabindex="-1"
375
+ >
376
+ Pull requests
377
+ </th>
378
+ <th
379
+ class="pf-v5-c-table__th"
380
+ data-ouia-component-id="TableExample-th-3"
381
+ scope="col"
382
+ tabindex="-1"
383
+ >
384
+ Workspaces
385
+ </th>
386
+ <th
387
+ class="pf-v5-c-table__th"
388
+ data-ouia-component-id="TableExample-th-4"
389
+ scope="col"
390
+ tabindex="-1"
391
+ >
392
+ Last commit
393
+ </th>
394
+ </tr>
395
+ </thead>
396
+ <tbody
397
+ class="pf-v5-c-table__tbody"
398
+ role="rowgroup"
399
+ >
400
+ <tr
401
+ class="pf-v5-c-table__tr"
402
+ data-ouia-component-id="TableExample-tr-empty"
403
+ data-ouia-component-type="PF5/TableRow"
404
+ data-ouia-safe="true"
405
+ >
406
+ <td
407
+ class="pf-v5-c-table__td"
408
+ colspan="5"
409
+ tabindex="-1"
410
+ >
411
+ No data found
412
+ </td>
413
+ </tr>
414
+ </tbody>
415
+ </table>
416
+ </div>
417
+ </div>
418
+ </div>
419
+ `;
420
+
421
+ exports[`DataViewTable component should render with an error state 1`] = `
422
+ <div>
423
+ <div
424
+ class="pf-v5-l-stack"
425
+ data-ouia-component-id="DataView-stack"
426
+ >
427
+ <div
428
+ class="pf-v5-l-stack__item"
429
+ data-ouia-component-id="DataView-stack-item-0"
391
430
  >
392
- <tr
393
- class="pf-v5-c-table__tr"
394
- data-ouia-component-id="TableExample-tr-empty"
395
- data-ouia-component-type="PF5/TableRow"
431
+ <table
432
+ aria-label="Repositories table"
433
+ class="pf-v5-c-table pf-m-grid-md"
434
+ data-ouia-component-id="TableExample"
435
+ data-ouia-component-type="PF5/Table"
396
436
  data-ouia-safe="true"
437
+ role="grid"
397
438
  >
398
- <td
399
- class="pf-v5-c-table__td"
400
- colspan="5"
401
- tabindex="-1"
402
- >
403
- No data found
404
- </td>
405
- </tr>
406
- </tbody>
407
- </table>
439
+ <thead
440
+ class="pf-v5-c-table__thead"
441
+ data-ouia-component-id="TableExample-thead"
442
+ >
443
+ <tr
444
+ class="pf-v5-c-table__tr"
445
+ data-ouia-component-id="TableExample-tr-head"
446
+ data-ouia-component-type="PF5/TableRow"
447
+ data-ouia-safe="true"
448
+ >
449
+ <th
450
+ class="pf-v5-c-table__th"
451
+ data-ouia-component-id="TableExample-th-0"
452
+ scope="col"
453
+ tabindex="-1"
454
+ >
455
+ Repositories
456
+ </th>
457
+ <th
458
+ class="pf-v5-c-table__th"
459
+ data-ouia-component-id="TableExample-th-1"
460
+ scope="col"
461
+ tabindex="-1"
462
+ >
463
+ Branches
464
+ </th>
465
+ <th
466
+ class="pf-v5-c-table__th"
467
+ data-ouia-component-id="TableExample-th-2"
468
+ scope="col"
469
+ tabindex="-1"
470
+ >
471
+ Pull requests
472
+ </th>
473
+ <th
474
+ class="pf-v5-c-table__th"
475
+ data-ouia-component-id="TableExample-th-3"
476
+ scope="col"
477
+ tabindex="-1"
478
+ >
479
+ Workspaces
480
+ </th>
481
+ <th
482
+ class="pf-v5-c-table__th"
483
+ data-ouia-component-id="TableExample-th-4"
484
+ scope="col"
485
+ tabindex="-1"
486
+ >
487
+ Last commit
488
+ </th>
489
+ </tr>
490
+ </thead>
491
+ <tbody
492
+ class="pf-v5-c-table__tbody"
493
+ role="rowgroup"
494
+ >
495
+ <tr
496
+ class="pf-v5-c-table__tr"
497
+ data-ouia-component-id="TableExample-tr-error"
498
+ data-ouia-component-type="PF5/TableRow"
499
+ data-ouia-safe="true"
500
+ >
501
+ <td
502
+ class="pf-v5-c-table__td"
503
+ colspan="5"
504
+ tabindex="-1"
505
+ >
506
+ Some error
507
+ </td>
508
+ </tr>
509
+ </tbody>
510
+ </table>
511
+ </div>
512
+ </div>
408
513
  </div>
409
514
  `;
@@ -69,7 +69,7 @@ exports[`DataViewTableHeader component should render selection column when selec
69
69
  <div>
70
70
  <div
71
71
  class="pf-v5-l-stack"
72
- data-ouia-component-id="DataView-stack}"
72
+ data-ouia-component-id="DataView-stack"
73
73
  >
74
74
  <div
75
75
  class="pf-v5-l-stack__item"
@@ -155,7 +155,7 @@ exports[`DataViewTableHeader component should render the tree table correctly wh
155
155
  <div>
156
156
  <div
157
157
  class="pf-v5-l-stack"
158
- data-ouia-component-id="DataView-stack}"
158
+ data-ouia-component-id="DataView-stack"
159
159
  >
160
160
  <div
161
161
  class="pf-v5-l-stack__item"
@@ -85,7 +85,19 @@ describe('DataViewTableTree component', () => {
85
85
 
86
86
  test('should render tree table with an empty state', () => {
87
87
  const { container } = render(
88
- <DataViewTable isTreeTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} emptyState="No data found" rows={[]} />
88
+ <DataView activeState="empty">
89
+ <DataViewTable isTreeTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} states={{ empty: "No data found" }} rows={[]} />
90
+
91
+ </DataView>
92
+ );
93
+ expect(container).toMatchSnapshot();
94
+ });
95
+
96
+ test('should render tree table with an error state', () => {
97
+ const { container } = render(
98
+ <DataView activeState="error">
99
+ <DataViewTable isTreeTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} states={{ error: "Some error" }} rows={[]} />
100
+ </DataView>
89
101
  );
90
102
  expect(container).toMatchSnapshot();
91
103
  });
@@ -11,6 +11,7 @@ import {
11
11
  import { useInternalContext } from '../InternalContext';
12
12
  import { DataViewTableHeader } from '../DataViewTableHeader';
13
13
  import { DataViewTh, DataViewTrTree, isDataViewTdObject } from '../DataViewTable';
14
+ import { DataViewState } from '../DataView/DataView';
14
15
 
15
16
  const getDescendants = (node: DataViewTrTree): DataViewTrTree[] => (!node.children || !node.children.length) ? [ node ] : node.children.flatMap(getDescendants);
16
17
 
@@ -35,8 +36,8 @@ export interface DataViewTableTreeProps extends Omit<TableProps, 'onSelect' | 'r
35
36
  columns: DataViewTh[];
36
37
  /** Current page rows */
37
38
  rows: DataViewTrTree[];
38
- /** Empty state to be displayed */
39
- emptyState?: React.ReactNode;
39
+ /** States to be displayed when active */
40
+ states?: Partial<Record<DataViewState, React.ReactNode>>
40
41
  /** Optional icon for the leaf rows */
41
42
  leafIcon?: React.ReactNode;
42
43
  /** Optional icon for the expanded parent rows */
@@ -50,20 +51,20 @@ export interface DataViewTableTreeProps extends Omit<TableProps, 'onSelect' | 'r
50
51
  export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
51
52
  columns,
52
53
  rows,
53
- emptyState = null,
54
+ states = {},
54
55
  leafIcon = null,
55
56
  expandedIcon = null,
56
57
  collapsedIcon = null,
57
58
  ouiaId = 'DataViewTableTree',
58
59
  ...props
59
60
  }: DataViewTableTreeProps) => {
60
- const { selection } = useInternalContext();
61
+ const { selection, activeState } = useInternalContext();
61
62
  const { onSelect, isSelected, isSelectDisabled } = selection ?? {};
62
63
  const [ expandedNodeIds, setExpandedNodeIds ] = React.useState<string[]>([]);
63
64
  const [ expandedDetailsNodeNames, setExpandedDetailsNodeIds ] = React.useState<string[]>([]);
64
65
 
65
66
  const nodes = useMemo(() => {
66
-
67
+
67
68
  const renderRows = (
68
69
  [ node, ...remainingNodes ]: DataViewTrTree[],
69
70
  level = 1,
@@ -134,19 +135,31 @@ export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
134
135
  };
135
136
 
136
137
  return renderRows(rows);
137
- }, [ rows, expandedNodeIds, expandedDetailsNodeNames, leafIcon, expandedIcon, collapsedIcon, isSelected, onSelect, isSelectDisabled, ouiaId ]);
138
+ }, [
139
+ rows,
140
+ expandedNodeIds,
141
+ expandedDetailsNodeNames,
142
+ leafIcon,
143
+ expandedIcon,
144
+ collapsedIcon,
145
+ isSelected,
146
+ onSelect,
147
+ isSelectDisabled,
148
+ ouiaId
149
+ ]);
138
150
 
139
151
  return (
140
152
  <Table isTreeTable aria-label="Data table" ouiaId={ouiaId} {...props}>
141
153
  <DataViewTableHeader isTreeTable columns={columns} ouiaId={ouiaId} />
142
- <Tbody>
143
- {nodes.length > 0 ? nodes : (
144
- <Tr key="empty" ouiaId={`${ouiaId}-tr-empty`}>
154
+ <Tbody>{
155
+ activeState && Object.keys(states).includes(activeState) ? (
156
+ <Tr key={activeState} ouiaId={`${ouiaId}-tr-${activeState}`}>
145
157
  <Td colSpan={columns.length}>
146
- {emptyState}
158
+ {states[activeState]}
147
159
  </Td>
148
160
  </Tr>
149
- )}
161
+ ) : nodes
162
+ }
150
163
  </Tbody>
151
164
  </Table>
152
165
  );