@patternfly/react-data-view 6.1.0 → 6.3.0-prerelease.3
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 +2 -2
- package/dist/cjs/DataView/DataView.js +4 -7
- package/dist/cjs/DataView/DataView.test.js +3 -6
- package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.d.ts +2 -2
- package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.js +10 -15
- package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.test.js +3 -3
- package/dist/cjs/DataViewEventsContext/DataViewEventsContext.d.ts +3 -3
- package/dist/cjs/DataViewEventsContext/DataViewEventsContext.js +3 -25
- package/dist/cjs/DataViewEventsContext/DataViewEventsContext.test.js +11 -16
- package/dist/cjs/DataViewFilters/DataViewFilters.d.ts +2 -2
- package/dist/cjs/DataViewFilters/DataViewFilters.js +12 -40
- package/dist/cjs/DataViewFilters/DataViewFilters.test.js +11 -5
- package/dist/cjs/DataViewTable/DataViewTable.d.ts +2 -2
- package/dist/cjs/DataViewTable/DataViewTable.js +2 -5
- package/dist/cjs/DataViewTable/DataViewTable.test.js +4 -7
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.d.ts +2 -2
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.js +15 -41
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.js +6 -12
- package/dist/cjs/DataViewTableHead/DataViewTableHead.d.ts +2 -2
- package/dist/cjs/DataViewTableHead/DataViewTableHead.js +5 -28
- package/dist/cjs/DataViewTableHead/DataViewTableHead.test.js +5 -13
- package/dist/cjs/DataViewTableTree/DataViewTableTree.d.ts +2 -2
- package/dist/cjs/DataViewTableTree/DataViewTableTree.js +10 -34
- package/dist/cjs/DataViewTableTree/DataViewTableTree.test.js +6 -13
- package/dist/cjs/DataViewTextFilter/DataViewTextFilter.d.ts +2 -2
- package/dist/cjs/DataViewTextFilter/DataViewTextFilter.js +2 -6
- package/dist/cjs/DataViewTextFilter/DataViewTextFilter.test.js +3 -3
- package/dist/cjs/DataViewToolbar/DataViewToolbar.d.ts +4 -2
- package/dist/cjs/DataViewToolbar/DataViewToolbar.js +5 -34
- package/dist/cjs/DataViewToolbar/DataViewToolbar.test.js +3 -3
- package/dist/cjs/Hooks/filters.js +1 -1
- package/dist/cjs/Hooks/filters.test.js +25 -0
- package/dist/cjs/InternalContext/InternalContext.d.ts +3 -3
- package/dist/cjs/InternalContext/InternalContext.js +3 -25
- package/dist/cjs/InternalContext/InternalContext.test.js +9 -21
- package/dist/esm/DataView/DataView.d.ts +2 -2
- package/dist/esm/DataView/DataView.js +4 -4
- package/dist/esm/DataView/DataView.test.js +2 -5
- package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.d.ts +2 -2
- package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.js +10 -12
- package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.test.js +2 -2
- package/dist/esm/DataViewEventsContext/DataViewEventsContext.d.ts +3 -3
- package/dist/esm/DataViewEventsContext/DataViewEventsContext.js +3 -2
- package/dist/esm/DataViewEventsContext/DataViewEventsContext.test.js +11 -13
- package/dist/esm/DataViewFilters/DataViewFilters.d.ts +2 -2
- package/dist/esm/DataViewFilters/DataViewFilters.js +12 -17
- package/dist/esm/DataViewFilters/DataViewFilters.test.js +11 -5
- package/dist/esm/DataViewTable/DataViewTable.d.ts +2 -2
- package/dist/esm/DataViewTable/DataViewTable.js +2 -2
- package/dist/esm/DataViewTable/DataViewTable.test.js +3 -3
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.d.ts +2 -2
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.js +15 -18
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.js +5 -8
- package/dist/esm/DataViewTableHead/DataViewTableHead.d.ts +2 -2
- package/dist/esm/DataViewTableHead/DataViewTableHead.js +5 -5
- package/dist/esm/DataViewTableHead/DataViewTableHead.test.js +4 -9
- package/dist/esm/DataViewTableTree/DataViewTableTree.d.ts +2 -2
- package/dist/esm/DataViewTableTree/DataViewTableTree.js +10 -11
- package/dist/esm/DataViewTableTree/DataViewTableTree.test.js +5 -9
- package/dist/esm/DataViewTextFilter/DataViewTextFilter.d.ts +2 -2
- package/dist/esm/DataViewTextFilter/DataViewTextFilter.js +2 -3
- package/dist/esm/DataViewTextFilter/DataViewTextFilter.test.js +2 -2
- package/dist/esm/DataViewToolbar/DataViewToolbar.d.ts +4 -2
- package/dist/esm/DataViewToolbar/DataViewToolbar.js +5 -11
- package/dist/esm/DataViewToolbar/DataViewToolbar.test.js +2 -2
- package/dist/esm/Hooks/filters.js +1 -1
- package/dist/esm/Hooks/filters.test.js +25 -0
- package/dist/esm/InternalContext/InternalContext.d.ts +3 -3
- package/dist/esm/InternalContext/InternalContext.js +3 -2
- package/dist/esm/InternalContext/InternalContext.test.js +7 -16
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/patternfly-docs/content/extensions/data-view/examples/DataView/AbstractLayoutExample.tsx +3 -3
- package/patternfly-docs/content/extensions/data-view/examples/DataView/DataView.md +1 -1
- package/patternfly-docs/content/extensions/data-view/examples/DataView/EventsExample.tsx +4 -4
- package/patternfly-docs/content/extensions/data-view/examples/DataView/PredefinedLayoutFullExample.tsx +5 -5
- package/patternfly-docs/content/extensions/data-view/examples/Table/DataViewTableEmptyExample.tsx +6 -6
- package/patternfly-docs/content/extensions/data-view/examples/Table/DataViewTableErrorExample.tsx +2 -2
- package/patternfly-docs/content/extensions/data-view/examples/Table/DataViewTableExample.tsx +2 -2
- package/patternfly-docs/content/extensions/data-view/examples/Table/DataViewTableLoadingExample.tsx +4 -4
- package/patternfly-docs/content/extensions/data-view/examples/Table/DataViewTableTreeExample.tsx +2 -2
- package/patternfly-docs/content/extensions/data-view/examples/Table/SortingExample.tsx +3 -3
- package/patternfly-docs/content/extensions/data-view/examples/Table/Table.md +1 -1
- package/patternfly-docs/content/extensions/data-view/examples/Toolbar/AllSelectedExample.tsx +116 -0
- package/patternfly-docs/content/extensions/data-view/examples/Toolbar/Toolbar.md +13 -1
- package/patternfly-docs/pages/index.js +1 -0
- package/release.config.js +10 -2
- package/src/DataView/DataView.test.tsx +10 -8
- package/src/DataView/DataView.tsx +4 -4
- package/src/DataViewCheckboxFilter/DataViewCheckboxFilter.test.tsx +0 -1
- package/src/DataViewCheckboxFilter/DataViewCheckboxFilter.tsx +10 -10
- package/src/DataViewEventsContext/DataViewEventsContext.test.tsx +4 -4
- package/src/DataViewEventsContext/DataViewEventsContext.tsx +1 -1
- package/src/DataViewFilters/DataViewFilters.test.tsx +29 -10
- package/src/DataViewFilters/DataViewFilters.tsx +12 -12
- package/src/DataViewTable/DataViewTable.test.tsx +0 -1
- package/src/DataViewTable/DataViewTable.tsx +2 -2
- package/src/DataViewTableBasic/DataViewTableBasic.test.tsx +0 -1
- package/src/DataViewTableBasic/DataViewTableBasic.tsx +2 -2
- package/src/DataViewTableHead/DataViewTableHead.test.tsx +0 -1
- package/src/DataViewTableHead/DataViewTableHead.tsx +2 -2
- package/src/DataViewTableTree/DataViewTableTree.test.tsx +0 -1
- package/src/DataViewTableTree/DataViewTableTree.tsx +5 -5
- package/src/DataViewTextFilter/DataViewTextFilter.test.tsx +0 -1
- package/src/DataViewTextFilter/DataViewTextFilter.tsx +2 -2
- package/src/DataViewToolbar/DataViewToolbar.test.tsx +0 -1
- package/src/DataViewToolbar/DataViewToolbar.tsx +9 -2
- package/src/Hooks/filters.test.tsx +27 -0
- package/src/Hooks/filters.ts +1 -1
- package/src/InternalContext/InternalContext.test.tsx +0 -1
- package/src/InternalContext/InternalContext.tsx +2 -2
- package/tsconfig.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-nested-ternary */
|
|
2
|
-
import
|
|
2
|
+
import { FunctionComponent, useMemo } from 'react';
|
|
3
3
|
import { useDataViewSort } from '@patternfly/react-data-view/dist/dynamic/Hooks';
|
|
4
4
|
import { DataViewTable, DataViewTr, DataViewTh } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
|
|
5
5
|
import { ThProps } from '@patternfly/react-table';
|
|
@@ -41,7 +41,7 @@ const sortData = (data: Repository[], sortBy: string | undefined, direction: 'as
|
|
|
41
41
|
|
|
42
42
|
const ouiaId = 'TableExample';
|
|
43
43
|
|
|
44
|
-
export const MyTable:
|
|
44
|
+
export const MyTable: FunctionComponent = () => {
|
|
45
45
|
const [ searchParams, setSearchParams ] = useSearchParams();
|
|
46
46
|
const { sortBy, direction, onSort } = useDataViewSort({ searchParams, setSearchParams });
|
|
47
47
|
const sortByIndex = useMemo(() => COLUMNS.findIndex(item => item.key === sortBy), [ sortBy ]);
|
|
@@ -79,7 +79,7 @@ export const MyTable: React.FunctionComponent = () => {
|
|
|
79
79
|
);
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
-
export const BasicExample:
|
|
82
|
+
export const BasicExample: FunctionComponent = () => (
|
|
83
83
|
<BrowserRouter>
|
|
84
84
|
<MyTable/>
|
|
85
85
|
</BrowserRouter>
|
|
@@ -15,7 +15,7 @@ sortValue: 3
|
|
|
15
15
|
propComponents: ['DataViewTableBasic', 'DataViewTableTree', 'DataViewTrTree', 'DataViewTrObject']
|
|
16
16
|
sourceLink: https://github.com/patternfly/react-data-view/blob/main/packages/module/patternfly-docs/content/extensions/data-view/examples/Table/Table.md
|
|
17
17
|
---
|
|
18
|
-
import { useMemo } from 'react';
|
|
18
|
+
import { FunctionComponent, useMemo } from 'react';
|
|
19
19
|
import { BrowserRouter, useSearchParams } from 'react-router-dom';
|
|
20
20
|
import { Button, EmptyState, EmptyStateActions, EmptyStateBody, EmptyStateFooter } from '@patternfly/react-core';
|
|
21
21
|
import { CubesIcon, FolderIcon, FolderOpenIcon, LeafIcon, ExclamationCircleIcon } from '@patternfly/react-icons';
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { Pagination, ToggleGroup, ToggleGroupItem, Tooltip } from '@patternfly/react-core';
|
|
3
|
+
import { useDataViewPagination, useDataViewSelection } from '@patternfly/react-data-view/dist/dynamic/Hooks';
|
|
4
|
+
import { DataView } from '@patternfly/react-data-view/dist/dynamic/DataView';
|
|
5
|
+
import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';
|
|
6
|
+
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
|
|
7
|
+
import { BulkSelect, BulkSelectValue } from '@patternfly/react-component-groups';
|
|
8
|
+
|
|
9
|
+
const TOGGLE_ALL = 'all';
|
|
10
|
+
const TOGGLE_SELECTED = 'selected';
|
|
11
|
+
|
|
12
|
+
const perPageOptions = [
|
|
13
|
+
{ title: '5', value: 5 },
|
|
14
|
+
{ title: '10', value: 10 }
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
interface Repository {
|
|
18
|
+
name: string;
|
|
19
|
+
branches: string | null;
|
|
20
|
+
prs: string | null;
|
|
21
|
+
workspaces: string;
|
|
22
|
+
lastCommit: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const repositories: Repository[] = [
|
|
26
|
+
{ name: 'Repository one', branches: 'Branch one', prs: 'Pull request one', workspaces: 'Workspace one', lastCommit: 'Timestamp one' },
|
|
27
|
+
{ name: 'Repository two', branches: 'Branch two', prs: 'Pull request two', workspaces: 'Workspace two', lastCommit: 'Timestamp two' },
|
|
28
|
+
{ name: 'Repository three', branches: 'Branch three', prs: 'Pull request three', workspaces: 'Workspace three', lastCommit: 'Timestamp three' },
|
|
29
|
+
{ name: 'Repository four', branches: 'Branch four', prs: 'Pull request four', workspaces: 'Workspace four', lastCommit: 'Timestamp four' },
|
|
30
|
+
{ name: 'Repository five', branches: 'Branch five', prs: 'Pull request five', workspaces: 'Workspace five', lastCommit: 'Timestamp five' },
|
|
31
|
+
{ name: 'Repository six', branches: 'Branch six', prs: 'Pull request six', workspaces: 'Workspace six', lastCommit: 'Timestamp six' }
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const rows = repositories.map(item => Object.values(item));
|
|
35
|
+
|
|
36
|
+
const columns = [ 'Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit' ];
|
|
37
|
+
|
|
38
|
+
const ouiaId = 'LayoutExample';
|
|
39
|
+
|
|
40
|
+
export const BasicExample: React.FunctionComponent = () => {
|
|
41
|
+
const pagination = useDataViewPagination({ perPage: 5 });
|
|
42
|
+
const selection = useDataViewSelection({ matchOption: (a, b) => a[0] === b[0] });
|
|
43
|
+
const [ selectedToggle, setSelectedToggle ] = useState(TOGGLE_ALL);
|
|
44
|
+
const { selected, onSelect } = selection;
|
|
45
|
+
const { page, perPage, onSetPage } = pagination;
|
|
46
|
+
|
|
47
|
+
const pageRows = useMemo(() => (selectedToggle === TOGGLE_SELECTED ? selected : rows).slice((page - 1) * perPage, ((page - 1) * perPage) + perPage), [ page, perPage, selectedToggle, selected ]);
|
|
48
|
+
|
|
49
|
+
const handleBulkSelect = (value: BulkSelectValue) => {
|
|
50
|
+
value === BulkSelectValue.none && onSelect(false);
|
|
51
|
+
value === BulkSelectValue.all && onSelect(true, rows);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const handleItemClick = (event: React.MouseEvent<any> | React.KeyboardEvent | MouseEvent, _isSelected: boolean) => {
|
|
55
|
+
const id = event.currentTarget.id;
|
|
56
|
+
|
|
57
|
+
if (id === TOGGLE_SELECTED && selected.length === 0) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (selectedToggle !== id) {
|
|
62
|
+
setSelectedToggle(id);
|
|
63
|
+
onSetPage(undefined, 1);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (selected.length === 0) {
|
|
69
|
+
setSelectedToggle(TOGGLE_ALL);
|
|
70
|
+
}
|
|
71
|
+
}, [ selected ]);
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<DataView selection={selection}>
|
|
75
|
+
<DataViewToolbar
|
|
76
|
+
ouiaId='DataViewHeader'
|
|
77
|
+
bulkSelect={
|
|
78
|
+
<BulkSelect
|
|
79
|
+
canSelectAll
|
|
80
|
+
isDataPaginated={false}
|
|
81
|
+
totalCount={repositories.length}
|
|
82
|
+
selectedCount={selected.length}
|
|
83
|
+
onSelect={handleBulkSelect}
|
|
84
|
+
/>
|
|
85
|
+
}
|
|
86
|
+
toggleGroup={
|
|
87
|
+
<ToggleGroup aria-label="Toggle group to switch between all / selected table rows">
|
|
88
|
+
<ToggleGroupItem
|
|
89
|
+
text="All"
|
|
90
|
+
buttonId={TOGGLE_ALL}
|
|
91
|
+
isSelected={selectedToggle === TOGGLE_ALL}
|
|
92
|
+
onChange={handleItemClick}
|
|
93
|
+
/>
|
|
94
|
+
<ToggleGroupItem
|
|
95
|
+
id="selected-row-switch"
|
|
96
|
+
text="Selected"
|
|
97
|
+
buttonId={TOGGLE_SELECTED}
|
|
98
|
+
isSelected={selectedToggle === TOGGLE_SELECTED}
|
|
99
|
+
onChange={handleItemClick}
|
|
100
|
+
aria-disabled={selected.length === 0}
|
|
101
|
+
/>
|
|
102
|
+
</ToggleGroup>
|
|
103
|
+
}
|
|
104
|
+
pagination={<Pagination perPageOptions={perPageOptions} itemCount={repositories.length} {...pagination} />}
|
|
105
|
+
/>
|
|
106
|
+
|
|
107
|
+
{selected.length === 0 && (<Tooltip
|
|
108
|
+
id="selected-row-switch-tooltip"
|
|
109
|
+
content="Select at least one row to enable this filter"
|
|
110
|
+
triggerRef={() => document.getElementById('selected-row-switch') as HTMLButtonElement}
|
|
111
|
+
/>)}
|
|
112
|
+
|
|
113
|
+
<DataViewTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={pageRows} />
|
|
114
|
+
</DataView>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
@@ -15,8 +15,9 @@ sortValue: 2
|
|
|
15
15
|
propComponents: ['DataViewToolbar', 'DataViewFilters', 'DataViewTextFilter', 'DataViewCheckboxFilter']
|
|
16
16
|
sourceLink: https://github.com/patternfly/react-data-view/blob/main/packages/module/patternfly-docs/content/extensions/data-view/examples/Toolbar/Toolbar.md
|
|
17
17
|
---
|
|
18
|
-
import { useMemo } from 'react';
|
|
18
|
+
import { useMemo, useState, useEffect } from 'react';
|
|
19
19
|
import { BrowserRouter, useSearchParams } from 'react-router-dom';
|
|
20
|
+
import { Pagination, ToggleGroup, ToggleGroupItem } from '@patternfly/react-core';
|
|
20
21
|
import { useDataViewPagination, useDataViewSelection, useDataViewFilters } from '@patternfly/react-data-view/dist/dynamic/Hooks';
|
|
21
22
|
import { DataView } from '@patternfly/react-data-view/dist/dynamic/DataView';
|
|
22
23
|
import { BulkSelect, BulkSelectValue, ErrorState, ResponsiveAction, ResponsiveActions, SkeletonTableHead, SkeletonTableBody } from '@patternfly/react-component-groups';
|
|
@@ -140,3 +141,14 @@ This example demonstrates the setup and usage of filters within the data view. I
|
|
|
140
141
|
```js file="./FiltersExample.tsx"
|
|
141
142
|
|
|
142
143
|
```
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
## All/selected data switch
|
|
147
|
+
All/selected data switch allows users to toggle between displaying the entire table (All) and only the rows they have selected (Selected). If the user deselects the last selected row, the filter automatically switches back to All, displaying all table rows again. Until at least one row is selected, a tooltip with guidance is displayed, and the Selected button does not perform any action. The Selected button is intentionally not disabled for accessibility reasons but instead has `aria-disabled` set.
|
|
148
|
+
|
|
149
|
+
### All/selected example
|
|
150
|
+
This example demonstrates the setup and usage of All/selected row switch.
|
|
151
|
+
|
|
152
|
+
```js file="./AllSelectedExample.tsx"
|
|
153
|
+
|
|
154
|
+
```
|
package/release.config.js
CHANGED
|
@@ -4,11 +4,19 @@ module.exports = {
|
|
|
4
4
|
preset: 'angular'
|
|
5
5
|
},
|
|
6
6
|
plugins: [
|
|
7
|
-
|
|
7
|
+
[
|
|
8
|
+
'@semantic-release/commit-analyzer',
|
|
9
|
+
{
|
|
10
|
+
preset: 'angular',
|
|
11
|
+
parserOpts: {
|
|
12
|
+
noteKeywords: [ 'BREAKING-CHANGE' ]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
],
|
|
8
16
|
'@semantic-release/release-notes-generator',
|
|
9
17
|
'@semantic-release/github',
|
|
10
18
|
'@semantic-release/npm'
|
|
11
19
|
],
|
|
12
20
|
tagFormat: 'prerelease-v${version}',
|
|
13
|
-
dryRun:
|
|
21
|
+
dryRun: true
|
|
14
22
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import { render } from '@testing-library/react';
|
|
3
2
|
import DataView from './DataView';
|
|
4
3
|
|
|
@@ -11,11 +10,14 @@ const layoutItemStyling = {
|
|
|
11
10
|
|
|
12
11
|
describe('DataView component', () => {
|
|
13
12
|
test('should render correctly', () => {
|
|
14
|
-
expect(
|
|
15
|
-
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
expect(
|
|
14
|
+
render(
|
|
15
|
+
<DataView>
|
|
16
|
+
<div style={layoutItemStyling}>Header</div>
|
|
17
|
+
<div style={layoutItemStyling}>Data representation</div>
|
|
18
|
+
<div style={layoutItemStyling}>Footer</div>
|
|
19
|
+
</DataView>
|
|
20
|
+
)
|
|
21
|
+
).toMatchSnapshot();
|
|
20
22
|
});
|
|
21
|
-
});
|
|
23
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, Children } from 'react';
|
|
2
2
|
import { Stack, StackItem, StackProps } from '@patternfly/react-core';
|
|
3
3
|
import { DataViewSelection, InternalContextProvider } from '../InternalContext';
|
|
4
4
|
|
|
@@ -24,11 +24,11 @@ export interface DataViewProps extends StackProps {
|
|
|
24
24
|
|
|
25
25
|
export type DataViewImpementationProps = Omit<DataViewProps, 'onSelect' | 'isItemSelected' | 'isItemSelectDisabled'>;
|
|
26
26
|
|
|
27
|
-
const DataViewImplementation:
|
|
27
|
+
const DataViewImplementation: FC<DataViewImpementationProps> = ({
|
|
28
28
|
children, ouiaId = 'DataView', ...props
|
|
29
29
|
}: DataViewImpementationProps) => (
|
|
30
30
|
<Stack data-ouia-component-id={`${ouiaId}-stack`} {...props}>
|
|
31
|
-
{
|
|
31
|
+
{Children.map(children, (child, index) => (
|
|
32
32
|
<StackItem data-ouia-component-id={`${ouiaId}-stack-item-${index}`}>
|
|
33
33
|
{child}
|
|
34
34
|
</StackItem>
|
|
@@ -36,7 +36,7 @@ const DataViewImplementation: React.FC<DataViewImpementationProps> = ({
|
|
|
36
36
|
</Stack>
|
|
37
37
|
)
|
|
38
38
|
|
|
39
|
-
export const DataView:
|
|
39
|
+
export const DataView: FC<DataViewProps> = ({ children, selection, activeState, ...props }: DataViewProps) => (
|
|
40
40
|
<InternalContextProvider selection={selection} activeState={activeState} >
|
|
41
41
|
<DataViewImplementation {...props}>{children}</DataViewImplementation>
|
|
42
42
|
</InternalContextProvider>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, useState, useRef, useMemo, useEffect, MouseEvent as ReactMouseEvent } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Badge,
|
|
4
4
|
Menu,
|
|
@@ -48,7 +48,7 @@ export interface DataViewCheckboxFilterProps extends Omit<MenuProps, 'onSelect'
|
|
|
48
48
|
ouiaId?: string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
export const DataViewCheckboxFilter:
|
|
51
|
+
export const DataViewCheckboxFilter: FC<DataViewCheckboxFilterProps> = ({
|
|
52
52
|
filterId,
|
|
53
53
|
title,
|
|
54
54
|
value = [],
|
|
@@ -61,12 +61,12 @@ export const DataViewCheckboxFilter: React.FC<DataViewCheckboxFilterProps> = ({
|
|
|
61
61
|
ouiaId = 'DataViewCheckboxFilter',
|
|
62
62
|
...props
|
|
63
63
|
}: DataViewCheckboxFilterProps) => {
|
|
64
|
-
const [ isOpen, setIsOpen ] =
|
|
65
|
-
const toggleRef =
|
|
66
|
-
const menuRef =
|
|
67
|
-
const containerRef =
|
|
64
|
+
const [ isOpen, setIsOpen ] = useState(false);
|
|
65
|
+
const toggleRef = useRef<HTMLButtonElement>(null);
|
|
66
|
+
const menuRef = useRef<HTMLDivElement>(null);
|
|
67
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
68
68
|
|
|
69
|
-
const normalizeOptions =
|
|
69
|
+
const normalizeOptions = useMemo(
|
|
70
70
|
() =>
|
|
71
71
|
options.map(option =>
|
|
72
72
|
typeof option === 'string'
|
|
@@ -76,7 +76,7 @@ export const DataViewCheckboxFilter: React.FC<DataViewCheckboxFilterProps> = ({
|
|
|
76
76
|
[ options ]
|
|
77
77
|
);
|
|
78
78
|
|
|
79
|
-
const handleToggleClick = (event:
|
|
79
|
+
const handleToggleClick = (event: ReactMouseEvent) => {
|
|
80
80
|
event.stopPropagation();
|
|
81
81
|
setTimeout(() => {
|
|
82
82
|
const firstElement = menuRef.current?.querySelector('li > button:not(:disabled)') as HTMLElement;
|
|
@@ -85,7 +85,7 @@ export const DataViewCheckboxFilter: React.FC<DataViewCheckboxFilterProps> = ({
|
|
|
85
85
|
setIsOpen(prev => !prev);
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
const handleSelect = (event?:
|
|
88
|
+
const handleSelect = (event?: ReactMouseEvent, itemId?: string | number) => {
|
|
89
89
|
const activeItem = String(itemId);
|
|
90
90
|
const isSelected = value.includes(activeItem);
|
|
91
91
|
|
|
@@ -102,7 +102,7 @@ export const DataViewCheckboxFilter: React.FC<DataViewCheckboxFilterProps> = ({
|
|
|
102
102
|
&& setIsOpen(false);
|
|
103
103
|
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
useEffect(() => {
|
|
106
106
|
window.addEventListener('click', handleClickOutside);
|
|
107
107
|
return () => {
|
|
108
108
|
window.removeEventListener('click', handleClickOutside);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
2
|
import { render, fireEvent } from '@testing-library/react';
|
|
3
3
|
import { useDataViewEventsContext, DataViewEventsProvider, EventTypes } from './DataViewEventsContext';
|
|
4
4
|
|
|
@@ -19,7 +19,7 @@ describe('DataViewEventsContext', () => {
|
|
|
19
19
|
const TestComponent = () => {
|
|
20
20
|
const { subscribe, trigger } = useDataViewEventsContext();
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
useEffect(() => {
|
|
23
23
|
const unsubscribe = subscribe(EventTypes.rowClick, callback);
|
|
24
24
|
return () => unsubscribe();
|
|
25
25
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -46,7 +46,7 @@ describe('DataViewEventsContext', () => {
|
|
|
46
46
|
const TestComponent = () => {
|
|
47
47
|
const { subscribe, trigger } = useDataViewEventsContext();
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
useEffect(() => {
|
|
50
50
|
const unsubscribe = subscribe(EventTypes.rowClick, callback);
|
|
51
51
|
unsubscribe();
|
|
52
52
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -75,7 +75,7 @@ describe('DataViewEventsContext', () => {
|
|
|
75
75
|
const TestComponent = () => {
|
|
76
76
|
const { subscribe, trigger } = useDataViewEventsContext();
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
useEffect(() => {
|
|
79
79
|
const unsubscribe1 = subscribe(EventTypes.rowClick, callback1);
|
|
80
80
|
const unsubscribe2 = subscribe(EventTypes.rowClick, callback2);
|
|
81
81
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { render } from '@testing-library/react';
|
|
1
|
+
import { render, fireEvent } from '@testing-library/react';
|
|
3
2
|
import DataViewFilters from './DataViewFilters';
|
|
4
3
|
import DataViewToolbar from '../DataViewToolbar';
|
|
5
4
|
import DataViewTextFilter from '../DataViewTextFilter';
|
|
@@ -8,14 +7,34 @@ describe('DataViewFilters component', () => {
|
|
|
8
7
|
const mockOnChange = jest.fn();
|
|
9
8
|
|
|
10
9
|
it('should render correctly', () => {
|
|
11
|
-
const { container } = render(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
const { container } = render(
|
|
11
|
+
<DataViewToolbar
|
|
12
|
+
filters={
|
|
13
|
+
<DataViewFilters onChange={mockOnChange} values={{}}>
|
|
14
|
+
<DataViewTextFilter filterId="one" title="One" />
|
|
15
|
+
<DataViewTextFilter filterId="two" title="Two" />
|
|
16
|
+
</DataViewFilters>
|
|
17
|
+
}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
19
20
|
expect(container).toMatchSnapshot();
|
|
20
21
|
});
|
|
22
|
+
|
|
23
|
+
it('should call onChange with correct key and value when filter changes', () => {
|
|
24
|
+
const mockOnChange = jest.fn();
|
|
25
|
+
const { getByLabelText } = render(
|
|
26
|
+
<DataViewToolbar
|
|
27
|
+
filters={
|
|
28
|
+
<DataViewFilters onChange={mockOnChange} values={{}}>
|
|
29
|
+
<DataViewTextFilter filterId="one" title="One" />
|
|
30
|
+
<DataViewTextFilter filterId="two" title="Two" />
|
|
31
|
+
</DataViewFilters>
|
|
32
|
+
}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
const input = getByLabelText('One filter');
|
|
36
|
+
input.focus();
|
|
37
|
+
fireEvent.input(input, { target: { value: 'abc' } });
|
|
38
|
+
expect(mockOnChange).toHaveBeenCalledWith('one', { one: 'abc' });
|
|
39
|
+
});
|
|
21
40
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Children, isValidElement, cloneElement, useMemo, useState, useRef, useEffect, ReactElement, ReactNode } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Menu, MenuContent, MenuItem, MenuList, MenuToggle, Popper, ToolbarGroup, ToolbarToggleGroup, ToolbarToggleGroupProps,
|
|
4
4
|
} from '@patternfly/react-core';
|
|
@@ -50,14 +50,14 @@ export const DataViewFilters = <T extends object>({
|
|
|
50
50
|
const attributeContainerRef = useRef<HTMLDivElement>(null);
|
|
51
51
|
|
|
52
52
|
const childrenHash = useMemo(() => JSON.stringify(
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
Children.map(children, (child) =>
|
|
54
|
+
isValidElement(child) ? { type: child.type, key: child.key, props: child.props } : child
|
|
55
55
|
)
|
|
56
56
|
), [ children ]);
|
|
57
57
|
|
|
58
|
-
const filterItems: DataViewFilterIdentifiers[] = useMemo(() =>
|
|
58
|
+
const filterItems: DataViewFilterIdentifiers[] = useMemo(() => Children.toArray(children)
|
|
59
59
|
.map(child =>
|
|
60
|
-
|
|
60
|
+
isValidElement(child) ? { filterId: String((child.props as any).filterId), title: String((child.props as any).title) } : undefined
|
|
61
61
|
).filter((item): item is DataViewFilterIdentifiers => !!item), [ childrenHash ]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
62
62
|
|
|
63
63
|
useEffect(() => {
|
|
@@ -122,17 +122,17 @@ export const DataViewFilters = <T extends object>({
|
|
|
122
122
|
isVisible={isAttributeMenuOpen}
|
|
123
123
|
/>
|
|
124
124
|
</div>
|
|
125
|
-
{
|
|
126
|
-
|
|
127
|
-
?
|
|
125
|
+
{Children.map(children, (child) =>
|
|
126
|
+
isValidElement(child)
|
|
127
|
+
? cloneElement(child as ReactElement<{
|
|
128
128
|
showToolbarItem: boolean;
|
|
129
129
|
onChange: (_e: unknown, values: unknown) => void;
|
|
130
130
|
value: unknown;
|
|
131
131
|
}>, {
|
|
132
|
-
showToolbarItem: activeAttributeMenu === child.props.title,
|
|
133
|
-
onChange: (event, value) => onChange?.(
|
|
134
|
-
value: values?.[child.props.filterId],
|
|
135
|
-
...child.props
|
|
132
|
+
showToolbarItem: activeAttributeMenu === (child.props as any).title,
|
|
133
|
+
onChange: (event, value) => onChange?.((child.props as any).filterId, { [(child.props as any).filterId]: value } as Partial<T>),
|
|
134
|
+
value: values?.[(child.props as any).filterId],
|
|
135
|
+
...(child.props as any)
|
|
136
136
|
})
|
|
137
137
|
: child
|
|
138
138
|
)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, ReactNode } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
TdProps,
|
|
4
4
|
ThProps,
|
|
@@ -50,7 +50,7 @@ export type DataViewTableProps =
|
|
|
50
50
|
isTreeTable?: false;
|
|
51
51
|
} & DataViewTableBasicProps);
|
|
52
52
|
|
|
53
|
-
export const DataViewTable:
|
|
53
|
+
export const DataViewTable: FC<DataViewTableProps> = (props) => (
|
|
54
54
|
props.isTreeTable ? <DataViewTableTree {...props} /> : <DataViewTableBasic {...props} />
|
|
55
55
|
);
|
|
56
56
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, useMemo } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Table,
|
|
4
4
|
TableProps,
|
|
@@ -25,7 +25,7 @@ export interface DataViewTableBasicProps extends Omit<TableProps, 'onSelect' | '
|
|
|
25
25
|
ouiaId?: string;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export const DataViewTableBasic:
|
|
28
|
+
export const DataViewTableBasic: FC<DataViewTableBasicProps> = ({
|
|
29
29
|
columns,
|
|
30
30
|
rows,
|
|
31
31
|
ouiaId = 'DataViewTableBasic',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, useMemo } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Th,
|
|
4
4
|
Thead,
|
|
@@ -18,7 +18,7 @@ export interface DataViewTableHeadProps extends TheadProps {
|
|
|
18
18
|
ouiaId?: string;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export const DataViewTableHead:
|
|
21
|
+
export const DataViewTableHead: FC<DataViewTableHeadProps> = ({
|
|
22
22
|
isTreeTable = false,
|
|
23
23
|
columns,
|
|
24
24
|
ouiaId = 'DataViewTableHead',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, useState, useMemo, ReactNode } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Table,
|
|
4
4
|
TableProps,
|
|
@@ -71,7 +71,7 @@ export interface DataViewTableTreeProps extends Omit<TableProps, 'onSelect' | 'r
|
|
|
71
71
|
ouiaId?: string;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
export const DataViewTableTree:
|
|
74
|
+
export const DataViewTableTree: FC<DataViewTableTreeProps> = ({
|
|
75
75
|
columns,
|
|
76
76
|
rows,
|
|
77
77
|
headStates,
|
|
@@ -84,8 +84,8 @@ export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
|
|
|
84
84
|
}: DataViewTableTreeProps) => {
|
|
85
85
|
const { selection, activeState } = useInternalContext();
|
|
86
86
|
const { onSelect, isSelected, isSelectDisabled } = selection ?? {};
|
|
87
|
-
const [ expandedNodeIds, setExpandedNodeIds ] =
|
|
88
|
-
const [ expandedDetailsNodeNames, setExpandedDetailsNodeIds ] =
|
|
87
|
+
const [ expandedNodeIds, setExpandedNodeIds ] = useState<string[]>([]);
|
|
88
|
+
const [ expandedDetailsNodeNames, setExpandedDetailsNodeIds ] = useState<string[]>([]);
|
|
89
89
|
|
|
90
90
|
const activeHeadState = useMemo(() => activeState ? headStates?.[activeState] : undefined, [ activeState, headStates ]);
|
|
91
91
|
const activeBodyState = useMemo(() => activeState ? bodyStates?.[activeState] : undefined, [ activeState, bodyStates ]);
|
|
@@ -98,7 +98,7 @@ export const DataViewTableTree: React.FC<DataViewTableTreeProps> = ({
|
|
|
98
98
|
posinset = 1,
|
|
99
99
|
rowIndex = 0,
|
|
100
100
|
isHidden = false
|
|
101
|
-
):
|
|
101
|
+
): ReactNode[] => {
|
|
102
102
|
if (!node) {
|
|
103
103
|
return [];
|
|
104
104
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC } from 'react';
|
|
2
2
|
import { SearchInput, SearchInputProps, ToolbarFilter, ToolbarFilterProps } from '@patternfly/react-core';
|
|
3
3
|
|
|
4
4
|
/** extends SearchInputProps */
|
|
@@ -19,7 +19,7 @@ export interface DataViewTextFilterProps extends SearchInputProps {
|
|
|
19
19
|
ouiaId?: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export const DataViewTextFilter:
|
|
22
|
+
export const DataViewTextFilter: FC<DataViewTextFilterProps> = ({
|
|
23
23
|
filterId,
|
|
24
24
|
title,
|
|
25
25
|
value = '',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, PropsWithChildren, useRef } from 'react';
|
|
2
2
|
import { Button, Toolbar, ToolbarContent, ToolbarItem, ToolbarItemVariant, ToolbarProps } from '@patternfly/react-core';
|
|
3
3
|
|
|
4
4
|
/** extends ToolbarProps */
|
|
@@ -13,13 +13,15 @@ export interface DataViewToolbarProps extends Omit<PropsWithChildren<ToolbarProp
|
|
|
13
13
|
pagination?: React.ReactNode;
|
|
14
14
|
/** React node to display actions */
|
|
15
15
|
actions?: React.ReactNode;
|
|
16
|
+
/** React node to display toggle group */
|
|
17
|
+
toggleGroup?: React.ReactNode;
|
|
16
18
|
/** React node to display filters */
|
|
17
19
|
filters?: React.ReactNode;
|
|
18
20
|
/** React node to display custom filter labels */
|
|
19
21
|
customLabelGroupContent?: React.ReactNode;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
export const DataViewToolbar:
|
|
24
|
+
export const DataViewToolbar: FC<DataViewToolbarProps> = ({ className, ouiaId = 'DataViewToolbar', bulkSelect, actions, toggleGroup, pagination, filters, customLabelGroupContent, clearAllFilters, children, ...props }: DataViewToolbarProps) => {
|
|
23
25
|
const defaultClearFilters = useRef(
|
|
24
26
|
<ToolbarItem>
|
|
25
27
|
<Button ouiaId={`${ouiaId}-clear-all-filters`} variant="link" onClick={clearAllFilters} isInline>
|
|
@@ -45,6 +47,11 @@ export const DataViewToolbar: React.FC<DataViewToolbarProps> = ({ className, oui
|
|
|
45
47
|
{actions}
|
|
46
48
|
</ToolbarItem>
|
|
47
49
|
)}
|
|
50
|
+
{toggleGroup && (
|
|
51
|
+
<ToolbarItem>
|
|
52
|
+
{toggleGroup}
|
|
53
|
+
</ToolbarItem>
|
|
54
|
+
)}
|
|
48
55
|
{pagination && (
|
|
49
56
|
<ToolbarItem variant={ToolbarItemVariant.pagination} data-ouia-component-id={`${ouiaId}-pagination`}>
|
|
50
57
|
{pagination}
|