@patternfly/react-data-view 5.1.3 → 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 (37) 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 -0
  4. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.js +32 -11
  5. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.js +11 -0
  6. package/dist/cjs/DataViewTableTree/DataViewTableTree.d.ts +3 -0
  7. package/dist/cjs/DataViewTableTree/DataViewTableTree.js +17 -6
  8. package/dist/cjs/DataViewTableTree/DataViewTableTree.test.js +10 -0
  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 -0
  14. package/dist/esm/DataViewTableBasic/DataViewTableBasic.js +9 -8
  15. package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.js +11 -0
  16. package/dist/esm/DataViewTableTree/DataViewTableTree.d.ts +3 -0
  17. package/dist/esm/DataViewTableTree/DataViewTableTree.js +18 -7
  18. package/dist/esm/DataViewTableTree/DataViewTableTree.test.js +10 -0
  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 +18 -3
  23. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableEmptyExample.tsx +51 -0
  24. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableErrorExample.tsx +38 -0
  25. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableTreeExample.tsx +11 -9
  26. package/patternfly-docs/content/extensions/data-view/examples/Layout/Layout.md +1 -1
  27. package/src/DataView/DataView.tsx +14 -4
  28. package/src/DataView/__snapshots__/DataView.test.tsx.snap +2 -2
  29. package/src/DataViewTable/__snapshots__/DataViewTable.test.tsx.snap +6 -6
  30. package/src/DataViewTableBasic/DataViewTableBasic.test.tsx +19 -0
  31. package/src/DataViewTableBasic/DataViewTableBasic.tsx +45 -32
  32. package/src/DataViewTableBasic/__snapshots__/DataViewTableBasic.test.tsx.snap +190 -0
  33. package/src/DataViewTableHeader/__snapshots__/DataViewTableHeader.test.tsx.snap +2 -2
  34. package/src/DataViewTableTree/DataViewTableTree.test.tsx +19 -0
  35. package/src/DataViewTableTree/DataViewTableTree.tsx +30 -6
  36. package/src/DataViewTableTree/__snapshots__/DataViewTableTree.test.tsx.snap +197 -7
  37. package/src/InternalContext/InternalContext.tsx +7 -3
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { DataView, DataViewState } from '@patternfly/react-data-view/dist/dynamic/DataView';
3
+ import { DataViewTable, DataViewTr, DataViewTh } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
4
+ import { ErrorState } from '@patternfly/react-component-groups';
5
+
6
+ interface Repository {
7
+ id: number;
8
+ name: string;
9
+ branches: string | null;
10
+ prs: string | null;
11
+ workspaces: string;
12
+ lastCommit: string;
13
+ }
14
+
15
+ const repositories: Repository[] = [];
16
+
17
+ // you can also pass props to Tr by returning { row: DataViewTd[], props: TrProps } }
18
+ const rows: DataViewTr[] = repositories.map((repository) => Object.values(repository));
19
+
20
+ const columns: DataViewTh[] = [ 'Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit' ];
21
+
22
+ const ouiaId = 'TableErrorExample';
23
+
24
+ const error = (
25
+ <ErrorState errorTitle='Unable to load data' errorDescription='There was an error retrieving data. Check your connection and reload the page.' />
26
+ );
27
+
28
+ export const BasicExample: React.FunctionComponent = () => (
29
+ <DataView activeState={DataViewState.error}>
30
+ <DataViewTable
31
+ aria-label='Repositories table'
32
+ ouiaId={ouiaId}
33
+ columns={columns}
34
+ rows={rows}
35
+ states={{ error }}
36
+ />
37
+ </DataView>
38
+ );
@@ -42,19 +42,13 @@ const buildRows = (repositories: Repository[]): DataViewTrTree[] => repositories
42
42
  ...(repo.children
43
43
  ? {
44
44
  children: buildRows(repo.children) // build rows for children
45
- }
45
+ }
46
46
  : {})
47
47
  }));
48
48
 
49
49
  const rows: DataViewTrTree[] = buildRows(repositories);
50
50
 
51
- const columns: DataViewTh[] = [
52
- 'Repositories',
53
- 'Branches',
54
- 'Pull requests',
55
- 'Workspaces',
56
- 'Last commit'
57
- ];
51
+ const columns: DataViewTh[] = [ 'Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit' ];
58
52
 
59
53
  const ouiaId = 'TreeTableExample';
60
54
 
@@ -63,7 +57,15 @@ export const BasicExample: React.FunctionComponent = () => {
63
57
 
64
58
  return (
65
59
  <DataView selection={selection}>
66
- <DataViewTable isTreeTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={rows} leafIcon={<LeafIcon/>} expandedIcon={<FolderOpenIcon aria-hidden />} collapsedIcon={<FolderIcon aria-hidden />} />
60
+ <DataViewTable
61
+ isTreeTable
62
+ ouiaId={ouiaId}
63
+ columns={columns}
64
+ rows={rows}
65
+ leafIcon={<LeafIcon/>}
66
+ expandedIcon={<FolderOpenIcon aria-hidden />}
67
+ collapsedIcon={<FolderIcon aria-hidden />}
68
+ />
67
69
  </DataView>
68
70
  );
69
71
  }
@@ -11,7 +11,7 @@ source: react
11
11
  # If you use typescript, the name of the interface to display props for
12
12
  # These are found through the sourceProps function provided in patternfly-docs.source.js
13
13
  sortValue: 2
14
- propComponents: ['DataView']
14
+ propComponents: ['DataView', 'DataViewState']
15
15
  sourceLink: https://github.com/patternfly/react-data-view/blob/main/packages/module/patternfly-docs/content/extensions/data-view/examples/Layout/Layout.md
16
16
  ---
17
17
  import { useMemo } from 'react';
@@ -2,13 +2,23 @@ import React from 'react';
2
2
  import { Stack, StackItem } from '@patternfly/react-core';
3
3
  import { DataViewSelection, InternalContextProvider } from '../InternalContext';
4
4
 
5
+ export const DataViewState = {
6
+ empty: 'empty',
7
+ loading: 'loading',
8
+ error: 'error'
9
+ } as const;
10
+
11
+ export type DataViewState = typeof DataViewState[keyof typeof DataViewState];
12
+
5
13
  export interface DataViewProps {
6
14
  /** Content rendered inside the data view */
7
15
  children: React.ReactNode;
8
16
  /** Custom OUIA ID */
9
17
  ouiaId?: string;
10
18
  /** Selection context configuration */
11
- selection?: DataViewSelection
19
+ selection?: DataViewSelection;
20
+ /** Currently active state */
21
+ activeState?: DataViewState;
12
22
  }
13
23
 
14
24
  export type DataViewImpementationProps = Omit<DataViewProps, 'onSelect' | 'isItemSelected' | 'isItemSelectDisabled'>;
@@ -16,7 +26,7 @@ export type DataViewImpementationProps = Omit<DataViewProps, 'onSelect' | 'isIte
16
26
  const DataViewImplementation: React.FC<DataViewImpementationProps> = ({
17
27
  children, ouiaId = 'DataView', ...props
18
28
  }: DataViewImpementationProps) => (
19
- <Stack data-ouia-component-id={`${ouiaId}-stack}`} {...props}>
29
+ <Stack data-ouia-component-id={`${ouiaId}-stack`} {...props}>
20
30
  {React.Children.map(children, (child, index) => (
21
31
  <StackItem data-ouia-component-id={`${ouiaId}-stack-item-${index}`}>
22
32
  {child}
@@ -25,8 +35,8 @@ const DataViewImplementation: React.FC<DataViewImpementationProps> = ({
25
35
  </Stack>
26
36
  )
27
37
 
28
- export const DataView: React.FC<DataViewProps> = ({ children, selection, ...props }: DataViewProps) => (
29
- <InternalContextProvider selection={selection}>
38
+ export const DataView: React.FC<DataViewProps> = ({ children, selection, activeState, ...props }: DataViewProps) => (
39
+ <InternalContextProvider selection={selection} activeState={activeState} >
30
40
  <DataViewImplementation {...props}>{children}</DataViewImplementation>
31
41
  </InternalContextProvider>
32
42
  );
@@ -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"
@@ -395,7 +395,7 @@ exports[`DataViewTable component should render a tree table correctly 1`] = `
395
395
  aria-posinset="1"
396
396
  aria-setsize="2"
397
397
  class="pf-v5-c-table__tr"
398
- data-ouia-component-id="OUIA-Generated-TableRow-9"
398
+ data-ouia-component-id="TableExample-tr-0"
399
399
  data-ouia-component-type="PF5/TableRow"
400
400
  data-ouia-safe="true"
401
401
  >
@@ -519,7 +519,7 @@ exports[`DataViewTable component should render a tree table correctly 1`] = `
519
519
  aria-posinset="1"
520
520
  aria-setsize="0"
521
521
  class="pf-v5-c-table__tr"
522
- data-ouia-component-id="OUIA-Generated-TableRow-10"
522
+ data-ouia-component-id="TableExample-tr-1"
523
523
  data-ouia-component-type="PF5/TableRow"
524
524
  data-ouia-safe="true"
525
525
  hidden=""
@@ -611,7 +611,7 @@ exports[`DataViewTable component should render a tree table correctly 1`] = `
611
611
  aria-posinset="2"
612
612
  aria-setsize="0"
613
613
  class="pf-v5-c-table__tr"
614
- data-ouia-component-id="OUIA-Generated-TableRow-11"
614
+ data-ouia-component-id="TableExample-tr-2"
615
615
  data-ouia-component-type="PF5/TableRow"
616
616
  data-ouia-safe="true"
617
617
  hidden=""
@@ -703,7 +703,7 @@ exports[`DataViewTable component should render a tree table correctly 1`] = `
703
703
  aria-posinset="2"
704
704
  aria-setsize="1"
705
705
  class="pf-v5-c-table__tr"
706
- data-ouia-component-id="OUIA-Generated-TableRow-12"
706
+ data-ouia-component-id="TableExample-tr-3"
707
707
  data-ouia-component-type="PF5/TableRow"
708
708
  data-ouia-safe="true"
709
709
  >
@@ -827,7 +827,7 @@ exports[`DataViewTable component should render a tree table correctly 1`] = `
827
827
  aria-posinset="1"
828
828
  aria-setsize="0"
829
829
  class="pf-v5-c-table__tr"
830
- data-ouia-component-id="OUIA-Generated-TableRow-13"
830
+ data-ouia-component-id="TableExample-tr-4"
831
831
  data-ouia-component-type="PF5/TableRow"
832
832
  data-ouia-safe="true"
833
833
  hidden=""
@@ -919,7 +919,7 @@ exports[`DataViewTable component should render a tree table correctly 1`] = `
919
919
  aria-posinset="3"
920
920
  aria-setsize="0"
921
921
  class="pf-v5-c-table__tr"
922
- data-ouia-component-id="OUIA-Generated-TableRow-14"
922
+ data-ouia-component-id="TableExample-tr-5"
923
923
  data-ouia-component-type="PF5/TableRow"
924
924
  data-ouia-safe="true"
925
925
  >
@@ -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;
@@ -34,4 +35,22 @@ describe('DataViewTable component', () => {
34
35
  );
35
36
  expect(container).toMatchSnapshot();
36
37
  });
38
+
39
+ test('should render with an empty state', () => {
40
+ const { container } = render(
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>
53
+ );
54
+ expect(container).toMatchSnapshot();
55
+ });
37
56
  });
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useMemo } from 'react';
2
2
  import {
3
3
  Table,
4
4
  TableProps,
@@ -9,12 +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[];
19
+ /** States to be displayed when active */
20
+ states?: Partial<Record<DataViewState, React.ReactNode>>
18
21
  /** Custom OUIA ID */
19
22
  ouiaId?: string;
20
23
  }
@@ -23,46 +26,56 @@ export const DataViewTableBasic: React.FC<DataViewTableBasicProps> = ({
23
26
  columns,
24
27
  rows,
25
28
  ouiaId = 'DataViewTableBasic',
29
+ states = {},
26
30
  ...props
27
31
  }: DataViewTableBasicProps) => {
28
- const { selection } = useInternalContext();
32
+ const { selection, activeState } = useInternalContext();
29
33
  const { onSelect, isSelected, isSelectDisabled } = selection ?? {};
34
+ const isSelectable = useMemo(() => Boolean(onSelect && isSelected), [ onSelect, isSelected ]);
30
35
 
31
36
  return (
32
37
  <Table aria-label="Data table" ouiaId={ouiaId} {...props}>
33
38
  <DataViewTableHeader columns={columns} ouiaId={ouiaId} />
34
39
  <Tbody>
35
- {rows.map((row, rowIndex) => {
36
- const rowIsObject = isDataViewTrObject(row);
37
- return (
38
- <Tr key={rowIndex} ouiaId={`${ouiaId}-tr-${rowIndex}`} {...(rowIsObject && (row?.props ?? {}))}>
39
- {onSelect && isSelected && (
40
- <Td
41
- key={`select-${rowIndex}`}
42
- select={{
43
- rowIndex,
44
- onSelect: (_event, isSelecting) => {
45
- onSelect?.(isSelecting, rowIsObject ? row : [ row ])
46
- },
47
- isSelected: isSelected?.(row) || false,
48
- isDisabled: isSelectDisabled?.(row) || false,
49
- }}
50
- />
51
- )}
52
- {(rowIsObject ? row.row : row).map((cell, colIndex) => {
53
- const cellIsObject = isDataViewTdObject(cell);
54
- return (
40
+ {activeState && Object.keys(states).includes(activeState) ? (
41
+ <Tr key={activeState} ouiaId={`${ouiaId}-tr-${activeState}`}>
42
+ <Td colSpan={columns.length + Number(isSelectable)}>
43
+ {states[activeState]}
44
+ </Td>
45
+ </Tr>
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 && (
55
52
  <Td
56
- key={colIndex}
57
- {...(cellIsObject && (cell?.props ?? {}))}
58
- data-ouia-component-id={`${ouiaId}-td-${rowIndex}-${colIndex}`}
59
- >
60
- {cellIsObject ? cell.cell : cell}
61
- </Td>
62
- )
63
- })}
64
- </Tr>
65
- )})}
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
+ }))}
66
79
  </Tbody>
67
80
  </Table>
68
81
  );
@@ -322,3 +322,193 @@ exports[`DataViewTable component should render correctly 1`] = `
322
322
  </table>
323
323
  </div>
324
324
  `;
325
+
326
+ exports[`DataViewTable component should render with an empty state 1`] = `
327
+ <div>
328
+ <div
329
+ class="pf-v5-l-stack"
330
+ data-ouia-component-id="DataView-stack"
331
+ >
332
+ <div
333
+ class="pf-v5-l-stack__item"
334
+ data-ouia-component-id="DataView-stack-item-0"
335
+ >
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"
341
+ data-ouia-safe="true"
342
+ role="grid"
343
+ >
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"
430
+ >
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"
436
+ data-ouia-safe="true"
437
+ role="grid"
438
+ >
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>
513
+ </div>
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"
@@ -82,4 +82,23 @@ describe('DataViewTableTree component', () => {
82
82
  );
83
83
  expect(container).toMatchSnapshot();
84
84
  });
85
+
86
+ test('should render tree table with an empty state', () => {
87
+ const { container } = render(
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>
101
+ );
102
+ expect(container).toMatchSnapshot();
103
+ });
85
104
  });
@@ -5,11 +5,13 @@ import {
5
5
  Tbody,
6
6
  Td,
7
7
  TdProps,
8
+ Tr,
8
9
  TreeRowWrapper,
9
10
  } from '@patternfly/react-table';
10
11
  import { useInternalContext } from '../InternalContext';
11
12
  import { DataViewTableHeader } from '../DataViewTableHeader';
12
13
  import { DataViewTh, DataViewTrTree, isDataViewTdObject } from '../DataViewTable';
14
+ import { DataViewState } from '../DataView/DataView';
13
15
 
14
16
  const getDescendants = (node: DataViewTrTree): DataViewTrTree[] => (!node.children || !node.children.length) ? [ node ] : node.children.flatMap(getDescendants);
15
17
 
@@ -34,6 +36,8 @@ export interface DataViewTableTreeProps extends Omit<TableProps, 'onSelect' | 'r
34
36
  columns: DataViewTh[];
35
37
  /** Current page rows */
36
38
  rows: DataViewTrTree[];
39
+ /** States to be displayed when active */
40
+ states?: Partial<Record<DataViewState, React.ReactNode>>
37
41
  /** Optional icon for the leaf rows */
38
42
  leafIcon?: React.ReactNode;
39
43
  /** Optional icon for the expanded parent rows */
@@ -47,19 +51,20 @@ export interface DataViewTableTreeProps extends Omit<TableProps, 'onSelect' | 'r
47
51
  export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
48
52
  columns,
49
53
  rows,
54
+ states = {},
50
55
  leafIcon = null,
51
56
  expandedIcon = null,
52
57
  collapsedIcon = null,
53
58
  ouiaId = 'DataViewTableTree',
54
59
  ...props
55
60
  }: DataViewTableTreeProps) => {
56
- const { selection } = useInternalContext();
61
+ const { selection, activeState } = useInternalContext();
57
62
  const { onSelect, isSelected, isSelectDisabled } = selection ?? {};
58
63
  const [ expandedNodeIds, setExpandedNodeIds ] = React.useState<string[]>([]);
59
64
  const [ expandedDetailsNodeNames, setExpandedDetailsNodeIds ] = React.useState<string[]>([]);
60
65
 
61
66
  const nodes = useMemo(() => {
62
-
67
+
63
68
  const renderRows = (
64
69
  [ node, ...remainingNodes ]: DataViewTrTree[],
65
70
  level = 1,
@@ -99,7 +104,6 @@ export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
99
104
  'aria-posinset': posinset,
100
105
  'aria-setsize': node.children?.length ?? 0,
101
106
  isChecked,
102
- ouiaId: `${ouiaId}-tree-toggle-${node.id}`,
103
107
  checkboxId: `checkbox_id_${node.id?.toLowerCase().replace(/\s+/g, '_')}`,
104
108
  icon,
105
109
  },
@@ -110,7 +114,7 @@ export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
110
114
  : [];
111
115
 
112
116
  return [
113
- <TreeRowWrapper key={node.id} row={{ props: treeRow.props }}>
117
+ <TreeRowWrapper key={node.id} row={{ props: treeRow.props }} ouiaId={`${ouiaId}-tr-${rowIndex}`}>
114
118
  {node.row.map((cell, colIndex) => {
115
119
  const cellIsObject = isDataViewTdObject(cell);
116
120
  return (
@@ -131,12 +135,32 @@ export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
131
135
  };
132
136
 
133
137
  return renderRows(rows);
134
- }, [ 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
+ ]);
135
150
 
136
151
  return (
137
152
  <Table isTreeTable aria-label="Data table" ouiaId={ouiaId} {...props}>
138
153
  <DataViewTableHeader isTreeTable columns={columns} ouiaId={ouiaId} />
139
- <Tbody>{nodes}</Tbody>
154
+ <Tbody>{
155
+ activeState && Object.keys(states).includes(activeState) ? (
156
+ <Tr key={activeState} ouiaId={`${ouiaId}-tr-${activeState}`}>
157
+ <Td colSpan={columns.length}>
158
+ {states[activeState]}
159
+ </Td>
160
+ </Tr>
161
+ ) : nodes
162
+ }
163
+ </Tbody>
140
164
  </Table>
141
165
  );
142
166
  };