@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.
- package/dist/cjs/DataView/DataView.d.ts +8 -0
- package/dist/cjs/DataView/DataView.js +9 -4
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.d.ts +3 -0
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.js +32 -11
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.js +11 -0
- package/dist/cjs/DataViewTableTree/DataViewTableTree.d.ts +3 -0
- package/dist/cjs/DataViewTableTree/DataViewTableTree.js +17 -6
- package/dist/cjs/DataViewTableTree/DataViewTableTree.test.js +10 -0
- package/dist/cjs/InternalContext/InternalContext.d.ts +2 -0
- package/dist/cjs/InternalContext/InternalContext.js +3 -2
- package/dist/esm/DataView/DataView.d.ts +8 -0
- package/dist/esm/DataView/DataView.js +8 -3
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.d.ts +3 -0
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.js +9 -8
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.js +11 -0
- package/dist/esm/DataViewTableTree/DataViewTableTree.d.ts +3 -0
- package/dist/esm/DataViewTableTree/DataViewTableTree.js +18 -7
- package/dist/esm/DataViewTableTree/DataViewTableTree.test.js +10 -0
- package/dist/esm/InternalContext/InternalContext.d.ts +2 -0
- package/dist/esm/InternalContext/InternalContext.js +3 -2
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/data-view/examples/Components/Components.md +18 -3
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableEmptyExample.tsx +51 -0
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableErrorExample.tsx +38 -0
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableTreeExample.tsx +11 -9
- package/patternfly-docs/content/extensions/data-view/examples/Layout/Layout.md +1 -1
- package/src/DataView/DataView.tsx +14 -4
- package/src/DataView/__snapshots__/DataView.test.tsx.snap +2 -2
- package/src/DataViewTable/__snapshots__/DataViewTable.test.tsx.snap +6 -6
- package/src/DataViewTableBasic/DataViewTableBasic.test.tsx +19 -0
- package/src/DataViewTableBasic/DataViewTableBasic.tsx +45 -32
- package/src/DataViewTableBasic/__snapshots__/DataViewTableBasic.test.tsx.snap +190 -0
- package/src/DataViewTableHeader/__snapshots__/DataViewTableHeader.test.tsx.snap +2 -2
- package/src/DataViewTableTree/DataViewTableTree.test.tsx +19 -0
- package/src/DataViewTableTree/DataViewTableTree.tsx +30 -6
- package/src/DataViewTableTree/__snapshots__/DataViewTableTree.test.tsx.snap +197 -7
- 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
|
|
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
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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
|
-
{
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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={
|
|
57
|
-
{
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
}, [
|
|
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>{
|
|
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
|
};
|