@patternfly/react-data-view 5.1.2 → 5.1.4
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/DataViewTableBasic/DataViewTableBasic.d.ts +2 -0
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.js +30 -8
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.js +4 -0
- package/dist/cjs/DataViewTableTree/DataViewTableTree.d.ts +2 -0
- package/dist/cjs/DataViewTableTree/DataViewTableTree.js +4 -4
- package/dist/cjs/DataViewTableTree/DataViewTableTree.test.js +4 -0
- package/dist/cjs/DataViewToolbar/DataViewToolbar.d.ts +2 -0
- package/dist/cjs/DataViewToolbar/DataViewToolbar.js +2 -1
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.d.ts +2 -0
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.js +7 -5
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.js +4 -0
- package/dist/esm/DataViewTableTree/DataViewTableTree.d.ts +2 -0
- package/dist/esm/DataViewTableTree/DataViewTableTree.js +5 -5
- package/dist/esm/DataViewTableTree/DataViewTableTree.test.js +4 -0
- package/dist/esm/DataViewToolbar/DataViewToolbar.d.ts +2 -0
- package/dist/esm/DataViewToolbar/DataViewToolbar.js +2 -1
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/data-view/examples/Components/Components.md +9 -1
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableEmptyExample.tsx +48 -0
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableExample.tsx +22 -2
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableTreeExample.tsx +11 -9
- package/src/DataViewTable/__snapshots__/DataViewTable.test.tsx.snap +6 -6
- package/src/DataViewTableBasic/DataViewTableBasic.test.tsx +7 -0
- package/src/DataViewTableBasic/DataViewTableBasic.tsx +14 -4
- package/src/DataViewTableBasic/__snapshots__/DataViewTableBasic.test.tsx.snap +85 -0
- package/src/DataViewTableTree/DataViewTableTree.test.tsx +7 -0
- package/src/DataViewTableTree/DataViewTableTree.tsx +14 -3
- package/src/DataViewTableTree/__snapshots__/DataViewTableTree.test.tsx.snap +91 -6
- package/src/DataViewToolbar/DataViewToolbar.tsx +4 -1
|
@@ -6,6 +6,8 @@ export interface DataViewTableBasicProps extends Omit<TableProps, 'onSelect' | '
|
|
|
6
6
|
columns: DataViewTh[];
|
|
7
7
|
/** Current page rows */
|
|
8
8
|
rows: DataViewTr[];
|
|
9
|
+
/** Empty state to be displayed */
|
|
10
|
+
emptyState?: React.ReactNode;
|
|
9
11
|
/** Custom OUIA ID */
|
|
10
12
|
ouiaId?: string;
|
|
11
13
|
}
|
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
26
|
var t = {};
|
|
4
27
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
@@ -10,27 +33,25 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
33
|
}
|
|
11
34
|
return t;
|
|
12
35
|
};
|
|
13
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
-
};
|
|
16
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
37
|
exports.DataViewTableBasic = void 0;
|
|
18
|
-
const react_1 =
|
|
38
|
+
const react_1 = __importStar(require("react"));
|
|
19
39
|
const react_table_1 = require("@patternfly/react-table");
|
|
20
40
|
const InternalContext_1 = require("../InternalContext");
|
|
21
41
|
const DataViewTableHeader_1 = require("../DataViewTableHeader");
|
|
22
42
|
const DataViewTable_1 = require("../DataViewTable");
|
|
23
43
|
const DataViewTableBasic = (_a) => {
|
|
24
|
-
var { columns, rows, ouiaId = 'DataViewTableBasic' } = _a, props = __rest(_a, ["columns", "rows", "ouiaId"]);
|
|
44
|
+
var { columns, rows, ouiaId = 'DataViewTableBasic', emptyState = null } = _a, props = __rest(_a, ["columns", "rows", "ouiaId", "emptyState"]);
|
|
25
45
|
const { selection } = (0, InternalContext_1.useInternalContext)();
|
|
26
46
|
const { onSelect, isSelected, isSelectDisabled } = selection !== null && selection !== void 0 ? selection : {};
|
|
47
|
+
const isSelectable = (0, react_1.useMemo)(() => Boolean(onSelect && isSelected), [onSelect, isSelected]);
|
|
27
48
|
return (react_1.default.createElement(react_table_1.Table, Object.assign({ "aria-label": "Data table", ouiaId: ouiaId }, props),
|
|
28
49
|
react_1.default.createElement(DataViewTableHeader_1.DataViewTableHeader, { columns: columns, ouiaId: ouiaId }),
|
|
29
|
-
react_1.default.createElement(react_table_1.Tbody, null, rows.map((row, rowIndex) => {
|
|
50
|
+
react_1.default.createElement(react_table_1.Tbody, null, (rows === null || rows === void 0 ? void 0 : rows.length) > 0 ? rows.map((row, rowIndex) => {
|
|
30
51
|
var _a;
|
|
31
52
|
const rowIsObject = (0, DataViewTable_1.isDataViewTrObject)(row);
|
|
32
53
|
return (react_1.default.createElement(react_table_1.Tr, Object.assign({ key: rowIndex, ouiaId: `${ouiaId}-tr-${rowIndex}` }, (rowIsObject && ((_a = row === null || row === void 0 ? void 0 : row.props) !== null && _a !== void 0 ? _a : {}))),
|
|
33
|
-
|
|
54
|
+
isSelectable && (react_1.default.createElement(react_table_1.Td, { key: `select-${rowIndex}`, select: {
|
|
34
55
|
rowIndex,
|
|
35
56
|
onSelect: (_event, isSelecting) => {
|
|
36
57
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(isSelecting, rowIsObject ? row : [row]);
|
|
@@ -43,7 +64,8 @@ const DataViewTableBasic = (_a) => {
|
|
|
43
64
|
const cellIsObject = (0, DataViewTable_1.isDataViewTdObject)(cell);
|
|
44
65
|
return (react_1.default.createElement(react_table_1.Td, Object.assign({ key: colIndex }, (cellIsObject && ((_a = cell === null || cell === void 0 ? void 0 : cell.props) !== null && _a !== void 0 ? _a : {})), { "data-ouia-component-id": `${ouiaId}-td-${rowIndex}-${colIndex}` }), cellIsObject ? cell.cell : cell));
|
|
45
66
|
})));
|
|
46
|
-
})
|
|
67
|
+
}) : (react_1.default.createElement(react_table_1.Tr, { key: "empty", ouiaId: `${ouiaId}-tr-empty` },
|
|
68
|
+
react_1.default.createElement(react_table_1.Td, { colSpan: columns.length + Number(isSelectable) }, emptyState))))));
|
|
47
69
|
};
|
|
48
70
|
exports.DataViewTableBasic = DataViewTableBasic;
|
|
49
71
|
exports.default = exports.DataViewTableBasic;
|
|
@@ -24,4 +24,8 @@ describe('DataViewTable component', () => {
|
|
|
24
24
|
const { container } = (0, react_2.render)(react_1.default.createElement(DataViewTableBasic_1.DataViewTableBasic, { "aria-label": 'Repositories table', ouiaId: ouiaId, columns: columns, rows: rows }));
|
|
25
25
|
expect(container).toMatchSnapshot();
|
|
26
26
|
});
|
|
27
|
+
test('should render with an empty state', () => {
|
|
28
|
+
const { container } = (0, react_2.render)(react_1.default.createElement(DataViewTableBasic_1.DataViewTableBasic, { "aria-label": 'Repositories table', ouiaId: ouiaId, columns: columns, emptyState: "No data found", rows: [] }));
|
|
29
|
+
expect(container).toMatchSnapshot();
|
|
30
|
+
});
|
|
27
31
|
});
|
|
@@ -6,6 +6,8 @@ export interface DataViewTableTreeProps extends Omit<TableProps, 'onSelect' | 'r
|
|
|
6
6
|
columns: DataViewTh[];
|
|
7
7
|
/** Current page rows */
|
|
8
8
|
rows: DataViewTrTree[];
|
|
9
|
+
/** Empty state to be displayed */
|
|
10
|
+
emptyState?: React.ReactNode;
|
|
9
11
|
/** Optional icon for the leaf rows */
|
|
10
12
|
leafIcon?: React.ReactNode;
|
|
11
13
|
/** Optional icon for the expanded parent rows */
|
|
@@ -55,7 +55,7 @@ const isNodeChecked = (node, isSelected) => {
|
|
|
55
55
|
return allSelected;
|
|
56
56
|
};
|
|
57
57
|
const DataViewTableTree = (_a) => {
|
|
58
|
-
var { columns, rows, leafIcon = null, expandedIcon = null, collapsedIcon = null, ouiaId = 'DataViewTableTree' } = _a, props = __rest(_a, ["columns", "rows", "leafIcon", "expandedIcon", "collapsedIcon", "ouiaId"]);
|
|
58
|
+
var { columns, rows, emptyState = null, leafIcon = null, expandedIcon = null, collapsedIcon = null, ouiaId = 'DataViewTableTree' } = _a, props = __rest(_a, ["columns", "rows", "emptyState", "leafIcon", "expandedIcon", "collapsedIcon", "ouiaId"]);
|
|
59
59
|
const { selection } = (0, InternalContext_1.useInternalContext)();
|
|
60
60
|
const { onSelect, isSelected, isSelectDisabled } = selection !== null && selection !== void 0 ? selection : {};
|
|
61
61
|
const [expandedNodeIds, setExpandedNodeIds] = react_1.default.useState([]);
|
|
@@ -92,7 +92,6 @@ const DataViewTableTree = (_a) => {
|
|
|
92
92
|
'aria-posinset': posinset,
|
|
93
93
|
'aria-setsize': (_b = (_a = node.children) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0,
|
|
94
94
|
isChecked,
|
|
95
|
-
ouiaId: `${ouiaId}-tree-toggle-${node.id}`,
|
|
96
95
|
checkboxId: `checkbox_id_${(_c = node.id) === null || _c === void 0 ? void 0 : _c.toLowerCase().replace(/\s+/g, '_')}`,
|
|
97
96
|
icon,
|
|
98
97
|
},
|
|
@@ -101,7 +100,7 @@ const DataViewTableTree = (_a) => {
|
|
|
101
100
|
? renderRows(node.children, level + 1, 1, rowIndex + 1, !isExpanded || isHidden)
|
|
102
101
|
: [];
|
|
103
102
|
return [
|
|
104
|
-
react_1.default.createElement(react_table_1.TreeRowWrapper, { key: node.id, row: { props: treeRow.props } }, node.row.map((cell, colIndex) => {
|
|
103
|
+
react_1.default.createElement(react_table_1.TreeRowWrapper, { key: node.id, row: { props: treeRow.props }, ouiaId: `${ouiaId}-tr-${rowIndex}` }, node.row.map((cell, colIndex) => {
|
|
105
104
|
var _a;
|
|
106
105
|
const cellIsObject = (0, DataViewTable_1.isDataViewTdObject)(cell);
|
|
107
106
|
return (react_1.default.createElement(react_table_1.Td, Object.assign({ key: colIndex, treeRow: colIndex === 0 ? treeRow : undefined }, (cellIsObject && ((_a = cell === null || cell === void 0 ? void 0 : cell.props) !== null && _a !== void 0 ? _a : {})), { "data-ouia-component-id": `${ouiaId}-td-${rowIndex}-${colIndex}` }), cellIsObject ? cell.cell : cell));
|
|
@@ -114,7 +113,8 @@ const DataViewTableTree = (_a) => {
|
|
|
114
113
|
}, [rows, expandedNodeIds, expandedDetailsNodeNames, leafIcon, expandedIcon, collapsedIcon, isSelected, onSelect, isSelectDisabled, ouiaId]);
|
|
115
114
|
return (react_1.default.createElement(react_table_1.Table, Object.assign({ isTreeTable: true, "aria-label": "Data table", ouiaId: ouiaId }, props),
|
|
116
115
|
react_1.default.createElement(DataViewTableHeader_1.DataViewTableHeader, { isTreeTable: true, columns: columns, ouiaId: ouiaId }),
|
|
117
|
-
react_1.default.createElement(react_table_1.Tbody, null, nodes
|
|
116
|
+
react_1.default.createElement(react_table_1.Tbody, null, nodes.length > 0 ? nodes : (react_1.default.createElement(react_table_1.Tr, { key: "empty", ouiaId: `${ouiaId}-tr-empty` },
|
|
117
|
+
react_1.default.createElement(react_table_1.Td, { colSpan: columns.length }, emptyState))))));
|
|
118
118
|
};
|
|
119
119
|
exports.DataViewTableTree = DataViewTableTree;
|
|
120
120
|
exports.default = exports.DataViewTableTree;
|
|
@@ -72,4 +72,8 @@ describe('DataViewTableTree component', () => {
|
|
|
72
72
|
react_1.default.createElement(DataViewTable_1.DataViewTable, { isTreeTable: true, "aria-label": 'Repositories table', ouiaId: ouiaId, columns: columns, rows: rows, leafIcon: react_1.default.createElement(react_icons_1.LeafIcon, null), expandedIcon: react_1.default.createElement(react_icons_1.FolderOpenIcon, { "aria-hidden": true }), collapsedIcon: react_1.default.createElement(react_icons_1.FolderIcon, { "aria-hidden": true }) })));
|
|
73
73
|
expect(container).toMatchSnapshot();
|
|
74
74
|
});
|
|
75
|
+
test('should render tree table with an empty state', () => {
|
|
76
|
+
const { container } = (0, react_2.render)(react_1.default.createElement(DataViewTable_1.DataViewTable, { isTreeTable: true, "aria-label": 'Repositories table', ouiaId: ouiaId, columns: columns, emptyState: "No data found", rows: [] }));
|
|
77
|
+
expect(container).toMatchSnapshot();
|
|
78
|
+
});
|
|
75
79
|
});
|
|
@@ -8,6 +8,8 @@ export interface DataViewToolbarProps extends PropsWithChildren {
|
|
|
8
8
|
bulkSelect?: React.ReactNode;
|
|
9
9
|
/** React component to display pagination */
|
|
10
10
|
pagination?: React.ReactNode;
|
|
11
|
+
/** React component to display actions */
|
|
12
|
+
actions?: React.ReactNode;
|
|
11
13
|
}
|
|
12
14
|
export declare const DataViewToolbar: React.FC<DataViewToolbarProps>;
|
|
13
15
|
export default DataViewToolbar;
|
|
@@ -18,10 +18,11 @@ exports.DataViewToolbar = void 0;
|
|
|
18
18
|
const react_1 = __importDefault(require("react"));
|
|
19
19
|
const react_core_1 = require("@patternfly/react-core");
|
|
20
20
|
const DataViewToolbar = (_a) => {
|
|
21
|
-
var { className, ouiaId = 'DataViewToolbar', bulkSelect, pagination, children } = _a, props = __rest(_a, ["className", "ouiaId", "bulkSelect", "pagination", "children"]);
|
|
21
|
+
var { className, ouiaId = 'DataViewToolbar', bulkSelect, actions = null, pagination, children } = _a, props = __rest(_a, ["className", "ouiaId", "bulkSelect", "actions", "pagination", "children"]);
|
|
22
22
|
return (react_1.default.createElement(react_core_1.Toolbar, Object.assign({ ouiaId: ouiaId, className: className }, props),
|
|
23
23
|
react_1.default.createElement(react_core_1.ToolbarContent, null,
|
|
24
24
|
bulkSelect && (react_1.default.createElement(react_core_1.ToolbarItem, { "data-ouia-component-id": `${ouiaId}-bulk-select` }, bulkSelect)),
|
|
25
|
+
actions,
|
|
25
26
|
pagination && (react_1.default.createElement(react_core_1.ToolbarItem, { variant: react_core_1.ToolbarItemVariant.pagination, "data-ouia-component-id": `${ouiaId}-pagination` }, pagination)),
|
|
26
27
|
children)));
|
|
27
28
|
};
|
|
@@ -6,6 +6,8 @@ export interface DataViewTableBasicProps extends Omit<TableProps, 'onSelect' | '
|
|
|
6
6
|
columns: DataViewTh[];
|
|
7
7
|
/** Current page rows */
|
|
8
8
|
rows: DataViewTr[];
|
|
9
|
+
/** Empty state to be displayed */
|
|
10
|
+
emptyState?: React.ReactNode;
|
|
9
11
|
/** Custom OUIA ID */
|
|
10
12
|
ouiaId?: string;
|
|
11
13
|
}
|
|
@@ -9,22 +9,23 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import React from 'react';
|
|
12
|
+
import React, { useMemo } from 'react';
|
|
13
13
|
import { Table, Tbody, Td, Tr, } from '@patternfly/react-table';
|
|
14
14
|
import { useInternalContext } from '../InternalContext';
|
|
15
15
|
import { DataViewTableHeader } from '../DataViewTableHeader';
|
|
16
16
|
import { isDataViewTdObject, isDataViewTrObject } from '../DataViewTable';
|
|
17
17
|
export const DataViewTableBasic = (_a) => {
|
|
18
|
-
var { columns, rows, ouiaId = 'DataViewTableBasic' } = _a, props = __rest(_a, ["columns", "rows", "ouiaId"]);
|
|
18
|
+
var { columns, rows, ouiaId = 'DataViewTableBasic', emptyState = null } = _a, props = __rest(_a, ["columns", "rows", "ouiaId", "emptyState"]);
|
|
19
19
|
const { selection } = useInternalContext();
|
|
20
20
|
const { onSelect, isSelected, isSelectDisabled } = selection !== null && selection !== void 0 ? selection : {};
|
|
21
|
+
const isSelectable = useMemo(() => Boolean(onSelect && isSelected), [onSelect, isSelected]);
|
|
21
22
|
return (React.createElement(Table, Object.assign({ "aria-label": "Data table", ouiaId: ouiaId }, props),
|
|
22
23
|
React.createElement(DataViewTableHeader, { columns: columns, ouiaId: ouiaId }),
|
|
23
|
-
React.createElement(Tbody, null, rows.map((row, rowIndex) => {
|
|
24
|
+
React.createElement(Tbody, null, (rows === null || rows === void 0 ? void 0 : rows.length) > 0 ? rows.map((row, rowIndex) => {
|
|
24
25
|
var _a;
|
|
25
26
|
const rowIsObject = isDataViewTrObject(row);
|
|
26
27
|
return (React.createElement(Tr, Object.assign({ key: rowIndex, ouiaId: `${ouiaId}-tr-${rowIndex}` }, (rowIsObject && ((_a = row === null || row === void 0 ? void 0 : row.props) !== null && _a !== void 0 ? _a : {}))),
|
|
27
|
-
|
|
28
|
+
isSelectable && (React.createElement(Td, { key: `select-${rowIndex}`, select: {
|
|
28
29
|
rowIndex,
|
|
29
30
|
onSelect: (_event, isSelecting) => {
|
|
30
31
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(isSelecting, rowIsObject ? row : [row]);
|
|
@@ -37,6 +38,7 @@ export const DataViewTableBasic = (_a) => {
|
|
|
37
38
|
const cellIsObject = isDataViewTdObject(cell);
|
|
38
39
|
return (React.createElement(Td, Object.assign({ key: colIndex }, (cellIsObject && ((_a = cell === null || cell === void 0 ? void 0 : cell.props) !== null && _a !== void 0 ? _a : {})), { "data-ouia-component-id": `${ouiaId}-td-${rowIndex}-${colIndex}` }), cellIsObject ? cell.cell : cell));
|
|
39
40
|
})));
|
|
40
|
-
})
|
|
41
|
+
}) : (React.createElement(Tr, { key: "empty", ouiaId: `${ouiaId}-tr-empty` },
|
|
42
|
+
React.createElement(Td, { colSpan: columns.length + Number(isSelectable) }, emptyState))))));
|
|
41
43
|
};
|
|
42
44
|
export default DataViewTableBasic;
|
|
@@ -19,4 +19,8 @@ describe('DataViewTable component', () => {
|
|
|
19
19
|
const { container } = render(React.createElement(DataViewTableBasic, { "aria-label": 'Repositories table', ouiaId: ouiaId, columns: columns, rows: rows }));
|
|
20
20
|
expect(container).toMatchSnapshot();
|
|
21
21
|
});
|
|
22
|
+
test('should render with an empty state', () => {
|
|
23
|
+
const { container } = render(React.createElement(DataViewTableBasic, { "aria-label": 'Repositories table', ouiaId: ouiaId, columns: columns, emptyState: "No data found", rows: [] }));
|
|
24
|
+
expect(container).toMatchSnapshot();
|
|
25
|
+
});
|
|
22
26
|
});
|
|
@@ -6,6 +6,8 @@ export interface DataViewTableTreeProps extends Omit<TableProps, 'onSelect' | 'r
|
|
|
6
6
|
columns: DataViewTh[];
|
|
7
7
|
/** Current page rows */
|
|
8
8
|
rows: DataViewTrTree[];
|
|
9
|
+
/** Empty state to be displayed */
|
|
10
|
+
emptyState?: React.ReactNode;
|
|
9
11
|
/** Optional icon for the leaf rows */
|
|
10
12
|
leafIcon?: React.ReactNode;
|
|
11
13
|
/** Optional icon for the expanded parent rows */
|
|
@@ -10,7 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import React, { useMemo } from 'react';
|
|
13
|
-
import { Table, Tbody, Td, TreeRowWrapper, } from '@patternfly/react-table';
|
|
13
|
+
import { Table, Tbody, Td, Tr, TreeRowWrapper, } from '@patternfly/react-table';
|
|
14
14
|
import { useInternalContext } from '../InternalContext';
|
|
15
15
|
import { DataViewTableHeader } from '../DataViewTableHeader';
|
|
16
16
|
import { isDataViewTdObject } from '../DataViewTable';
|
|
@@ -29,7 +29,7 @@ const isNodeChecked = (node, isSelected) => {
|
|
|
29
29
|
return allSelected;
|
|
30
30
|
};
|
|
31
31
|
export const DataViewTableTree = (_a) => {
|
|
32
|
-
var { columns, rows, leafIcon = null, expandedIcon = null, collapsedIcon = null, ouiaId = 'DataViewTableTree' } = _a, props = __rest(_a, ["columns", "rows", "leafIcon", "expandedIcon", "collapsedIcon", "ouiaId"]);
|
|
32
|
+
var { columns, rows, emptyState = null, leafIcon = null, expandedIcon = null, collapsedIcon = null, ouiaId = 'DataViewTableTree' } = _a, props = __rest(_a, ["columns", "rows", "emptyState", "leafIcon", "expandedIcon", "collapsedIcon", "ouiaId"]);
|
|
33
33
|
const { selection } = useInternalContext();
|
|
34
34
|
const { onSelect, isSelected, isSelectDisabled } = selection !== null && selection !== void 0 ? selection : {};
|
|
35
35
|
const [expandedNodeIds, setExpandedNodeIds] = React.useState([]);
|
|
@@ -66,7 +66,6 @@ export const DataViewTableTree = (_a) => {
|
|
|
66
66
|
'aria-posinset': posinset,
|
|
67
67
|
'aria-setsize': (_b = (_a = node.children) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0,
|
|
68
68
|
isChecked,
|
|
69
|
-
ouiaId: `${ouiaId}-tree-toggle-${node.id}`,
|
|
70
69
|
checkboxId: `checkbox_id_${(_c = node.id) === null || _c === void 0 ? void 0 : _c.toLowerCase().replace(/\s+/g, '_')}`,
|
|
71
70
|
icon,
|
|
72
71
|
},
|
|
@@ -75,7 +74,7 @@ export const DataViewTableTree = (_a) => {
|
|
|
75
74
|
? renderRows(node.children, level + 1, 1, rowIndex + 1, !isExpanded || isHidden)
|
|
76
75
|
: [];
|
|
77
76
|
return [
|
|
78
|
-
React.createElement(TreeRowWrapper, { key: node.id, row: { props: treeRow.props } }, node.row.map((cell, colIndex) => {
|
|
77
|
+
React.createElement(TreeRowWrapper, { key: node.id, row: { props: treeRow.props }, ouiaId: `${ouiaId}-tr-${rowIndex}` }, node.row.map((cell, colIndex) => {
|
|
79
78
|
var _a;
|
|
80
79
|
const cellIsObject = isDataViewTdObject(cell);
|
|
81
80
|
return (React.createElement(Td, Object.assign({ key: colIndex, treeRow: colIndex === 0 ? treeRow : undefined }, (cellIsObject && ((_a = cell === null || cell === void 0 ? void 0 : cell.props) !== null && _a !== void 0 ? _a : {})), { "data-ouia-component-id": `${ouiaId}-td-${rowIndex}-${colIndex}` }), cellIsObject ? cell.cell : cell));
|
|
@@ -88,6 +87,7 @@ export const DataViewTableTree = (_a) => {
|
|
|
88
87
|
}, [rows, expandedNodeIds, expandedDetailsNodeNames, leafIcon, expandedIcon, collapsedIcon, isSelected, onSelect, isSelectDisabled, ouiaId]);
|
|
89
88
|
return (React.createElement(Table, Object.assign({ isTreeTable: true, "aria-label": "Data table", ouiaId: ouiaId }, props),
|
|
90
89
|
React.createElement(DataViewTableHeader, { isTreeTable: true, columns: columns, ouiaId: ouiaId }),
|
|
91
|
-
React.createElement(Tbody, null, nodes
|
|
90
|
+
React.createElement(Tbody, null, nodes.length > 0 ? nodes : (React.createElement(Tr, { key: "empty", ouiaId: `${ouiaId}-tr-empty` },
|
|
91
|
+
React.createElement(Td, { colSpan: columns.length }, emptyState))))));
|
|
92
92
|
};
|
|
93
93
|
export default DataViewTableTree;
|
|
@@ -67,4 +67,8 @@ describe('DataViewTableTree component', () => {
|
|
|
67
67
|
React.createElement(DataViewTable, { isTreeTable: true, "aria-label": 'Repositories table', ouiaId: ouiaId, columns: columns, rows: rows, leafIcon: React.createElement(LeafIcon, null), expandedIcon: React.createElement(FolderOpenIcon, { "aria-hidden": true }), collapsedIcon: React.createElement(FolderIcon, { "aria-hidden": true }) })));
|
|
68
68
|
expect(container).toMatchSnapshot();
|
|
69
69
|
});
|
|
70
|
+
test('should render tree table with an empty state', () => {
|
|
71
|
+
const { container } = render(React.createElement(DataViewTable, { isTreeTable: true, "aria-label": 'Repositories table', ouiaId: ouiaId, columns: columns, emptyState: "No data found", rows: [] }));
|
|
72
|
+
expect(container).toMatchSnapshot();
|
|
73
|
+
});
|
|
70
74
|
});
|
|
@@ -8,6 +8,8 @@ export interface DataViewToolbarProps extends PropsWithChildren {
|
|
|
8
8
|
bulkSelect?: React.ReactNode;
|
|
9
9
|
/** React component to display pagination */
|
|
10
10
|
pagination?: React.ReactNode;
|
|
11
|
+
/** React component to display actions */
|
|
12
|
+
actions?: React.ReactNode;
|
|
11
13
|
}
|
|
12
14
|
export declare const DataViewToolbar: React.FC<DataViewToolbarProps>;
|
|
13
15
|
export default DataViewToolbar;
|
|
@@ -12,10 +12,11 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
import React from 'react';
|
|
13
13
|
import { Toolbar, ToolbarContent, ToolbarItem, ToolbarItemVariant } from '@patternfly/react-core';
|
|
14
14
|
export const DataViewToolbar = (_a) => {
|
|
15
|
-
var { className, ouiaId = 'DataViewToolbar', bulkSelect, pagination, children } = _a, props = __rest(_a, ["className", "ouiaId", "bulkSelect", "pagination", "children"]);
|
|
15
|
+
var { className, ouiaId = 'DataViewToolbar', bulkSelect, actions = null, pagination, children } = _a, props = __rest(_a, ["className", "ouiaId", "bulkSelect", "actions", "pagination", "children"]);
|
|
16
16
|
return (React.createElement(Toolbar, Object.assign({ ouiaId: ouiaId, className: className }, props),
|
|
17
17
|
React.createElement(ToolbarContent, null,
|
|
18
18
|
bulkSelect && (React.createElement(ToolbarItem, { "data-ouia-component-id": `${ouiaId}-bulk-select` }, bulkSelect)),
|
|
19
|
+
actions,
|
|
19
20
|
pagination && (React.createElement(ToolbarItem, { variant: ToolbarItemVariant.pagination, "data-ouia-component-id": `${ouiaId}-pagination` }, pagination)),
|
|
20
21
|
children)));
|
|
21
22
|
};
|
package/package.json
CHANGED
|
@@ -14,7 +14,8 @@ sortValue: 4
|
|
|
14
14
|
propComponents: ['DataViewToolbar', 'DataViewTableBasic', 'DataViewTableTree']
|
|
15
15
|
sourceLink: https://github.com/patternfly/react-data-view/blob/main/packages/module/patternfly-docs/content/extensions/data-view/examples/Components/Components.md
|
|
16
16
|
---
|
|
17
|
-
import {
|
|
17
|
+
import { Button, EmptyState, EmptyStateActions, EmptyStateBody, EmptyStateFooter, EmptyStateHeader, EmptyStateIcon } from '@patternfly/react-core';
|
|
18
|
+
import { CubesIcon, FolderIcon, FolderOpenIcon, LeafIcon, ExclamationCircleIcon } from '@patternfly/react-icons';
|
|
18
19
|
import { BulkSelect } from '@patternfly/react-component-groups';
|
|
19
20
|
import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';
|
|
20
21
|
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
|
|
@@ -71,3 +72,10 @@ It is also possible to disable row selection using the `isSelectDisabled` functi
|
|
|
71
72
|
```js file="./DataViewTableTreeExample.tsx"
|
|
72
73
|
|
|
73
74
|
```
|
|
75
|
+
|
|
76
|
+
### Empty state example
|
|
77
|
+
The data view table also supports displaying a custom empty state. You can pass it using the `emptyState` property and it will be displayed in case there are no rows to be rendered.
|
|
78
|
+
|
|
79
|
+
```js file="./DataViewTableEmptyExample.tsx"
|
|
80
|
+
|
|
81
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DataViewTable, DataViewTr, DataViewTh } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
|
|
3
|
+
import { CubesIcon } from '@patternfly/react-icons';
|
|
4
|
+
import { Button, EmptyState, EmptyStateActions, EmptyStateBody, EmptyStateFooter, EmptyStateHeader, EmptyStateIcon } from '@patternfly/react-core';
|
|
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 = 'TableExample';
|
|
23
|
+
|
|
24
|
+
const emptyState = (
|
|
25
|
+
<EmptyState>
|
|
26
|
+
<EmptyStateHeader titleText="No data found" headingLevel="h4" icon={<EmptyStateIcon icon={CubesIcon} />} />
|
|
27
|
+
<EmptyStateBody>There are no matching data to be displayed.</EmptyStateBody>
|
|
28
|
+
<EmptyStateFooter>
|
|
29
|
+
<EmptyStateActions>
|
|
30
|
+
<Button variant="primary">Primary action</Button>
|
|
31
|
+
</EmptyStateActions>
|
|
32
|
+
<EmptyStateActions>
|
|
33
|
+
<Button variant="link">Multiple</Button>
|
|
34
|
+
<Button variant="link">Action Buttons</Button>
|
|
35
|
+
</EmptyStateActions>
|
|
36
|
+
</EmptyStateFooter>
|
|
37
|
+
</EmptyState>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export const BasicExample: React.FunctionComponent = () => (
|
|
41
|
+
<DataViewTable
|
|
42
|
+
aria-label='Repositories table'
|
|
43
|
+
ouiaId={ouiaId}
|
|
44
|
+
columns={columns}
|
|
45
|
+
rows={rows}
|
|
46
|
+
emptyState={emptyState}
|
|
47
|
+
/>
|
|
48
|
+
);
|
package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableExample.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { DataViewTable, DataViewTr, DataViewTh } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
|
|
3
3
|
import { ExclamationCircleIcon } from '@patternfly/react-icons';
|
|
4
4
|
import { Button } from '@patternfly/react-core';
|
|
5
|
+
import { ActionsColumn } from '@patternfly/react-table';
|
|
5
6
|
|
|
6
7
|
interface Repository {
|
|
7
8
|
id: number;
|
|
@@ -21,6 +22,24 @@ const repositories: Repository[] = [
|
|
|
21
22
|
{ id: 6, name: 'Repository six', branches: 'Branch six', prs: 'Pull request six', workspaces: 'Workspace six', lastCommit: 'Timestamp six' }
|
|
22
23
|
];
|
|
23
24
|
|
|
25
|
+
const rowActions = [
|
|
26
|
+
{
|
|
27
|
+
title: 'Some action',
|
|
28
|
+
onClick: () => console.log('clicked on Some action') // eslint-disable-line no-console
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: <div>Another action</div>,
|
|
32
|
+
onClick: () => console.log('clicked on Another action') // eslint-disable-line no-console
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
isSeparator: true
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
title: 'Third action',
|
|
39
|
+
onClick: () => console.log('clicked on Third action') // eslint-disable-line no-console
|
|
40
|
+
}
|
|
41
|
+
];
|
|
42
|
+
|
|
24
43
|
// you can also pass props to Tr by returning { row: DataViewTd[], props: TrProps } }
|
|
25
44
|
const rows: DataViewTr[] = repositories.map(({ id, name, branches, prs, workspaces, lastCommit }) => [
|
|
26
45
|
{ id, cell: workspaces, props: { favorites: { isFavorited: true } } },
|
|
@@ -28,7 +47,8 @@ const rows: DataViewTr[] = repositories.map(({ id, name, branches, prs, workspac
|
|
|
28
47
|
branches,
|
|
29
48
|
prs,
|
|
30
49
|
workspaces,
|
|
31
|
-
lastCommit
|
|
50
|
+
lastCommit,
|
|
51
|
+
{ cell: <ActionsColumn items={rowActions}/>, props: { isActionCell: true } },
|
|
32
52
|
]);
|
|
33
53
|
|
|
34
54
|
const columns: DataViewTh[] = [
|
|
@@ -37,7 +57,7 @@ const columns: DataViewTh[] = [
|
|
|
37
57
|
{ cell: <>Branches<ExclamationCircleIcon className='pf-v5-u-ml-sm' color='var(--pf-v5-global--danger-color--100)'/></> },
|
|
38
58
|
'Pull requests',
|
|
39
59
|
{ cell: 'Workspaces', props: { info: { tooltip: 'More information' } } },
|
|
40
|
-
{ cell: 'Last commit', props: { sort: { sortBy: {}, columnIndex: 4 } } }
|
|
60
|
+
{ cell: 'Last commit', props: { sort: { sortBy: {}, columnIndex: 4 } } },
|
|
41
61
|
];
|
|
42
62
|
|
|
43
63
|
const ouiaId = 'TableExample';
|
|
@@ -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
|
}
|
|
@@ -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
|
>
|
|
@@ -34,4 +34,11 @@ describe('DataViewTable component', () => {
|
|
|
34
34
|
);
|
|
35
35
|
expect(container).toMatchSnapshot();
|
|
36
36
|
});
|
|
37
|
+
|
|
38
|
+
test('should render with an empty state', () => {
|
|
39
|
+
const { container } = render(
|
|
40
|
+
<DataViewTableBasic aria-label='Repositories table' ouiaId={ouiaId} columns={columns} emptyState="No data found" rows={[]} />
|
|
41
|
+
);
|
|
42
|
+
expect(container).toMatchSnapshot();
|
|
43
|
+
});
|
|
37
44
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Table,
|
|
4
4
|
TableProps,
|
|
@@ -15,6 +15,8 @@ export interface DataViewTableBasicProps extends Omit<TableProps, 'onSelect' | '
|
|
|
15
15
|
columns: DataViewTh[];
|
|
16
16
|
/** Current page rows */
|
|
17
17
|
rows: DataViewTr[];
|
|
18
|
+
/** Empty state to be displayed */
|
|
19
|
+
emptyState?: React.ReactNode;
|
|
18
20
|
/** Custom OUIA ID */
|
|
19
21
|
ouiaId?: string;
|
|
20
22
|
}
|
|
@@ -23,20 +25,22 @@ export const DataViewTableBasic: React.FC<DataViewTableBasicProps> = ({
|
|
|
23
25
|
columns,
|
|
24
26
|
rows,
|
|
25
27
|
ouiaId = 'DataViewTableBasic',
|
|
28
|
+
emptyState = null,
|
|
26
29
|
...props
|
|
27
30
|
}: DataViewTableBasicProps) => {
|
|
28
31
|
const { selection } = useInternalContext();
|
|
29
32
|
const { onSelect, isSelected, isSelectDisabled } = selection ?? {};
|
|
33
|
+
const isSelectable = useMemo(() => Boolean(onSelect && isSelected), [ onSelect, isSelected ])
|
|
30
34
|
|
|
31
35
|
return (
|
|
32
36
|
<Table aria-label="Data table" ouiaId={ouiaId} {...props}>
|
|
33
37
|
<DataViewTableHeader columns={columns} ouiaId={ouiaId} />
|
|
34
38
|
<Tbody>
|
|
35
|
-
{rows.map((row, rowIndex) => {
|
|
39
|
+
{rows?.length > 0 ? rows.map((row, rowIndex) => {
|
|
36
40
|
const rowIsObject = isDataViewTrObject(row);
|
|
37
41
|
return (
|
|
38
42
|
<Tr key={rowIndex} ouiaId={`${ouiaId}-tr-${rowIndex}`} {...(rowIsObject && (row?.props ?? {}))}>
|
|
39
|
-
{
|
|
43
|
+
{isSelectable && (
|
|
40
44
|
<Td
|
|
41
45
|
key={`select-${rowIndex}`}
|
|
42
46
|
select={{
|
|
@@ -62,7 +66,13 @@ export const DataViewTableBasic: React.FC<DataViewTableBasicProps> = ({
|
|
|
62
66
|
)
|
|
63
67
|
})}
|
|
64
68
|
</Tr>
|
|
65
|
-
)})
|
|
69
|
+
)}) : (
|
|
70
|
+
<Tr key="empty" ouiaId={`${ouiaId}-tr-empty`}>
|
|
71
|
+
<Td colSpan={columns.length + Number(isSelectable)}>
|
|
72
|
+
{emptyState}
|
|
73
|
+
</Td>
|
|
74
|
+
</Tr>
|
|
75
|
+
)}
|
|
66
76
|
</Tbody>
|
|
67
77
|
</Table>
|
|
68
78
|
);
|
|
@@ -322,3 +322,88 @@ 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
|
+
<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"
|
|
335
|
+
>
|
|
336
|
+
<thead
|
|
337
|
+
class="pf-v5-c-table__thead"
|
|
338
|
+
data-ouia-component-id="TableExample-thead"
|
|
339
|
+
>
|
|
340
|
+
<tr
|
|
341
|
+
class="pf-v5-c-table__tr"
|
|
342
|
+
data-ouia-component-id="TableExample-tr-head"
|
|
343
|
+
data-ouia-component-type="PF5/TableRow"
|
|
344
|
+
data-ouia-safe="true"
|
|
345
|
+
>
|
|
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"
|
|
391
|
+
>
|
|
392
|
+
<tr
|
|
393
|
+
class="pf-v5-c-table__tr"
|
|
394
|
+
data-ouia-component-id="TableExample-tr-empty"
|
|
395
|
+
data-ouia-component-type="PF5/TableRow"
|
|
396
|
+
data-ouia-safe="true"
|
|
397
|
+
>
|
|
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>
|
|
408
|
+
</div>
|
|
409
|
+
`;
|
|
@@ -82,4 +82,11 @@ 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
|
+
<DataViewTable isTreeTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} emptyState="No data found" rows={[]} />
|
|
89
|
+
);
|
|
90
|
+
expect(container).toMatchSnapshot();
|
|
91
|
+
});
|
|
85
92
|
});
|
|
@@ -5,6 +5,7 @@ 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';
|
|
@@ -34,6 +35,8 @@ export interface DataViewTableTreeProps extends Omit<TableProps, 'onSelect' | 'r
|
|
|
34
35
|
columns: DataViewTh[];
|
|
35
36
|
/** Current page rows */
|
|
36
37
|
rows: DataViewTrTree[];
|
|
38
|
+
/** Empty state to be displayed */
|
|
39
|
+
emptyState?: React.ReactNode;
|
|
37
40
|
/** Optional icon for the leaf rows */
|
|
38
41
|
leafIcon?: React.ReactNode;
|
|
39
42
|
/** Optional icon for the expanded parent rows */
|
|
@@ -47,6 +50,7 @@ export interface DataViewTableTreeProps extends Omit<TableProps, 'onSelect' | 'r
|
|
|
47
50
|
export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
|
|
48
51
|
columns,
|
|
49
52
|
rows,
|
|
53
|
+
emptyState = null,
|
|
50
54
|
leafIcon = null,
|
|
51
55
|
expandedIcon = null,
|
|
52
56
|
collapsedIcon = null,
|
|
@@ -99,7 +103,6 @@ export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
|
|
|
99
103
|
'aria-posinset': posinset,
|
|
100
104
|
'aria-setsize': node.children?.length ?? 0,
|
|
101
105
|
isChecked,
|
|
102
|
-
ouiaId: `${ouiaId}-tree-toggle-${node.id}`,
|
|
103
106
|
checkboxId: `checkbox_id_${node.id?.toLowerCase().replace(/\s+/g, '_')}`,
|
|
104
107
|
icon,
|
|
105
108
|
},
|
|
@@ -110,7 +113,7 @@ export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
|
|
|
110
113
|
: [];
|
|
111
114
|
|
|
112
115
|
return [
|
|
113
|
-
<TreeRowWrapper key={node.id} row={{ props: treeRow.props }}>
|
|
116
|
+
<TreeRowWrapper key={node.id} row={{ props: treeRow.props }} ouiaId={`${ouiaId}-tr-${rowIndex}`}>
|
|
114
117
|
{node.row.map((cell, colIndex) => {
|
|
115
118
|
const cellIsObject = isDataViewTdObject(cell);
|
|
116
119
|
return (
|
|
@@ -136,7 +139,15 @@ export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
|
|
|
136
139
|
return (
|
|
137
140
|
<Table isTreeTable aria-label="Data table" ouiaId={ouiaId} {...props}>
|
|
138
141
|
<DataViewTableHeader isTreeTable columns={columns} ouiaId={ouiaId} />
|
|
139
|
-
<Tbody>
|
|
142
|
+
<Tbody>
|
|
143
|
+
{nodes.length > 0 ? nodes : (
|
|
144
|
+
<Tr key="empty" ouiaId={`${ouiaId}-tr-empty`}>
|
|
145
|
+
<Td colSpan={columns.length}>
|
|
146
|
+
{emptyState}
|
|
147
|
+
</Td>
|
|
148
|
+
</Tr>
|
|
149
|
+
)}
|
|
150
|
+
</Tbody>
|
|
140
151
|
</Table>
|
|
141
152
|
);
|
|
142
153
|
};
|
|
@@ -80,7 +80,7 @@ exports[`DataViewTableTree component should render the tree table correctly 1`]
|
|
|
80
80
|
aria-posinset="1"
|
|
81
81
|
aria-setsize="2"
|
|
82
82
|
class="pf-v5-c-table__tr"
|
|
83
|
-
data-ouia-component-id="
|
|
83
|
+
data-ouia-component-id="TreeTableExample-tr-0"
|
|
84
84
|
data-ouia-component-type="PF5/TableRow"
|
|
85
85
|
data-ouia-safe="true"
|
|
86
86
|
>
|
|
@@ -244,7 +244,7 @@ exports[`DataViewTableTree component should render the tree table correctly 1`]
|
|
|
244
244
|
aria-posinset="1"
|
|
245
245
|
aria-setsize="0"
|
|
246
246
|
class="pf-v5-c-table__tr"
|
|
247
|
-
data-ouia-component-id="
|
|
247
|
+
data-ouia-component-id="TreeTableExample-tr-1"
|
|
248
248
|
data-ouia-component-type="PF5/TableRow"
|
|
249
249
|
data-ouia-safe="true"
|
|
250
250
|
hidden=""
|
|
@@ -376,7 +376,7 @@ exports[`DataViewTableTree component should render the tree table correctly 1`]
|
|
|
376
376
|
aria-posinset="2"
|
|
377
377
|
aria-setsize="0"
|
|
378
378
|
class="pf-v5-c-table__tr"
|
|
379
|
-
data-ouia-component-id="
|
|
379
|
+
data-ouia-component-id="TreeTableExample-tr-2"
|
|
380
380
|
data-ouia-component-type="PF5/TableRow"
|
|
381
381
|
data-ouia-safe="true"
|
|
382
382
|
hidden=""
|
|
@@ -508,7 +508,7 @@ exports[`DataViewTableTree component should render the tree table correctly 1`]
|
|
|
508
508
|
aria-posinset="2"
|
|
509
509
|
aria-setsize="1"
|
|
510
510
|
class="pf-v5-c-table__tr"
|
|
511
|
-
data-ouia-component-id="
|
|
511
|
+
data-ouia-component-id="TreeTableExample-tr-3"
|
|
512
512
|
data-ouia-component-type="PF5/TableRow"
|
|
513
513
|
data-ouia-safe="true"
|
|
514
514
|
>
|
|
@@ -672,7 +672,7 @@ exports[`DataViewTableTree component should render the tree table correctly 1`]
|
|
|
672
672
|
aria-posinset="1"
|
|
673
673
|
aria-setsize="0"
|
|
674
674
|
class="pf-v5-c-table__tr"
|
|
675
|
-
data-ouia-component-id="
|
|
675
|
+
data-ouia-component-id="TreeTableExample-tr-4"
|
|
676
676
|
data-ouia-component-type="PF5/TableRow"
|
|
677
677
|
data-ouia-safe="true"
|
|
678
678
|
hidden=""
|
|
@@ -804,7 +804,7 @@ exports[`DataViewTableTree component should render the tree table correctly 1`]
|
|
|
804
804
|
aria-posinset="3"
|
|
805
805
|
aria-setsize="0"
|
|
806
806
|
class="pf-v5-c-table__tr"
|
|
807
|
-
data-ouia-component-id="
|
|
807
|
+
data-ouia-component-id="TreeTableExample-tr-5"
|
|
808
808
|
data-ouia-component-type="PF5/TableRow"
|
|
809
809
|
data-ouia-safe="true"
|
|
810
810
|
>
|
|
@@ -935,3 +935,88 @@ exports[`DataViewTableTree component should render the tree table correctly 1`]
|
|
|
935
935
|
</div>
|
|
936
936
|
</div>
|
|
937
937
|
`;
|
|
938
|
+
|
|
939
|
+
exports[`DataViewTableTree component should render tree table with an empty state 1`] = `
|
|
940
|
+
<div>
|
|
941
|
+
<table
|
|
942
|
+
aria-label="Repositories table"
|
|
943
|
+
class="pf-v5-c-table pf-m-tree-view-grid-md pf-m-tree-view"
|
|
944
|
+
data-ouia-component-id="TreeTableExample"
|
|
945
|
+
data-ouia-component-type="PF5/Table"
|
|
946
|
+
data-ouia-safe="true"
|
|
947
|
+
role="treegrid"
|
|
948
|
+
>
|
|
949
|
+
<thead
|
|
950
|
+
class="pf-v5-c-table__thead"
|
|
951
|
+
data-ouia-component-id="TreeTableExample-thead"
|
|
952
|
+
>
|
|
953
|
+
<tr
|
|
954
|
+
class="pf-v5-c-table__tr"
|
|
955
|
+
data-ouia-component-id="TreeTableExample-tr-head"
|
|
956
|
+
data-ouia-component-type="PF5/TableRow"
|
|
957
|
+
data-ouia-safe="true"
|
|
958
|
+
>
|
|
959
|
+
<th
|
|
960
|
+
class="pf-v5-c-table__th"
|
|
961
|
+
data-ouia-component-id="TreeTableExample-th-0"
|
|
962
|
+
scope="col"
|
|
963
|
+
tabindex="-1"
|
|
964
|
+
>
|
|
965
|
+
Repositories
|
|
966
|
+
</th>
|
|
967
|
+
<th
|
|
968
|
+
class="pf-v5-c-table__th"
|
|
969
|
+
data-ouia-component-id="TreeTableExample-th-1"
|
|
970
|
+
scope="col"
|
|
971
|
+
tabindex="-1"
|
|
972
|
+
>
|
|
973
|
+
Branches
|
|
974
|
+
</th>
|
|
975
|
+
<th
|
|
976
|
+
class="pf-v5-c-table__th"
|
|
977
|
+
data-ouia-component-id="TreeTableExample-th-2"
|
|
978
|
+
scope="col"
|
|
979
|
+
tabindex="-1"
|
|
980
|
+
>
|
|
981
|
+
Pull requests
|
|
982
|
+
</th>
|
|
983
|
+
<th
|
|
984
|
+
class="pf-v5-c-table__th"
|
|
985
|
+
data-ouia-component-id="TreeTableExample-th-3"
|
|
986
|
+
scope="col"
|
|
987
|
+
tabindex="-1"
|
|
988
|
+
>
|
|
989
|
+
Workspaces
|
|
990
|
+
</th>
|
|
991
|
+
<th
|
|
992
|
+
class="pf-v5-c-table__th"
|
|
993
|
+
data-ouia-component-id="TreeTableExample-th-4"
|
|
994
|
+
scope="col"
|
|
995
|
+
tabindex="-1"
|
|
996
|
+
>
|
|
997
|
+
Last commit
|
|
998
|
+
</th>
|
|
999
|
+
</tr>
|
|
1000
|
+
</thead>
|
|
1001
|
+
<tbody
|
|
1002
|
+
class="pf-v5-c-table__tbody"
|
|
1003
|
+
role="rowgroup"
|
|
1004
|
+
>
|
|
1005
|
+
<tr
|
|
1006
|
+
class="pf-v5-c-table__tr"
|
|
1007
|
+
data-ouia-component-id="TreeTableExample-tr-empty"
|
|
1008
|
+
data-ouia-component-type="PF5/TableRow"
|
|
1009
|
+
data-ouia-safe="true"
|
|
1010
|
+
>
|
|
1011
|
+
<td
|
|
1012
|
+
class="pf-v5-c-table__td"
|
|
1013
|
+
colspan="5"
|
|
1014
|
+
tabindex="-1"
|
|
1015
|
+
>
|
|
1016
|
+
No data found
|
|
1017
|
+
</td>
|
|
1018
|
+
</tr>
|
|
1019
|
+
</tbody>
|
|
1020
|
+
</table>
|
|
1021
|
+
</div>
|
|
1022
|
+
`;
|
|
@@ -10,9 +10,11 @@ export interface DataViewToolbarProps extends PropsWithChildren {
|
|
|
10
10
|
bulkSelect?: React.ReactNode;
|
|
11
11
|
/** React component to display pagination */
|
|
12
12
|
pagination?: React.ReactNode;
|
|
13
|
+
/** React component to display actions */
|
|
14
|
+
actions?: React.ReactNode;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
export const DataViewToolbar: React.FC<DataViewToolbarProps> = ({ className, ouiaId = 'DataViewToolbar', bulkSelect, pagination, children, ...props }: DataViewToolbarProps) => (
|
|
17
|
+
export const DataViewToolbar: React.FC<DataViewToolbarProps> = ({ className, ouiaId = 'DataViewToolbar', bulkSelect, actions = null, pagination, children, ...props }: DataViewToolbarProps) => (
|
|
16
18
|
<Toolbar ouiaId={ouiaId} className={className} {...props}>
|
|
17
19
|
<ToolbarContent>
|
|
18
20
|
{bulkSelect && (
|
|
@@ -20,6 +22,7 @@ export const DataViewToolbar: React.FC<DataViewToolbarProps> = ({ className, oui
|
|
|
20
22
|
{bulkSelect}
|
|
21
23
|
</ToolbarItem>
|
|
22
24
|
)}
|
|
25
|
+
{actions}
|
|
23
26
|
{pagination && (
|
|
24
27
|
<ToolbarItem variant={ToolbarItemVariant.pagination} data-ouia-component-id={`${ouiaId}-pagination`}>
|
|
25
28
|
{pagination}
|