Skip to content

Commit 6d40b67

Browse files
committed
feat: adding DataViewTreeFilter
1 parent 72f979c commit 6d40b67

File tree

6 files changed

+454
-3
lines changed

6 files changed

+454
-3
lines changed

packages/module/patternfly-docs/content/extensions/data-view/examples/Toolbar/Toolbar.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ source: react
1212
# If you use typescript, the name of the interface to display props for
1313
# These are found through the sourceProps function provided in patternfly-docs.source.js
1414
sortValue: 2
15-
propComponents: ['DataViewToolbar', 'DataViewFilters', 'DataViewTextFilter', 'DataViewCheckboxFilter']
15+
propComponents: ['DataViewToolbar', 'DataViewFilters', 'DataViewTextFilter', 'DataViewCheckboxFilter', 'DataViewTreeFilter']
1616
sourceLink: https://github.com/patternfly/react-data-view/blob/main/packages/module/patternfly-docs/content/extensions/data-view/examples/Toolbar/Toolbar.md
1717
---
1818
import { useMemo, useState, useEffect } from 'react';
@@ -26,6 +26,7 @@ import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataView
2626
import { DataViewFilters } from '@patternfly/react-data-view/dist/dynamic/DataViewFilters';
2727
import { DataViewTextFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewTextFilter';
2828
import { DataViewCheckboxFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewCheckboxFilter';
29+
import { DataViewTreeFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewTreeFilter';
2930

3031
The **data view toolbar** component renders a default opinionated data view toolbar above or below the data section.
3132

@@ -143,6 +144,12 @@ This example demonstrates the setup and usage of filters within the data view. I
143144

144145
```
145146

147+
### Tree filter example
148+
This example demonstrates the usage of a tree filter with hierarchical data. The tree filter allows users to select items from a nested structure, making it ideal for categorized or grouped filtering options.
149+
150+
```js file="./TreeFilterExample.tsx"
151+
152+
```
146153

147154
## All/selected data switch
148155
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.
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
import React, { useMemo } from 'react';
2+
import { Pagination } from '@patternfly/react-core';
3+
import { BrowserRouter, useSearchParams } from 'react-router-dom';
4+
import { TreeViewDataItem } from '@patternfly/react-core';
5+
import { useDataViewFilters, useDataViewPagination } from '@patternfly/react-data-view/dist/dynamic/Hooks';
6+
import { DataView } from '@patternfly/react-data-view/dist/dynamic/DataView';
7+
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
8+
import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';
9+
import { DataViewFilters } from '@patternfly/react-data-view/dist/dynamic/DataViewFilters';
10+
import { DataViewTreeFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewTreeFilter';
11+
12+
const perPageOptions = [
13+
{ title: '5', value: 5 },
14+
{ title: '10', value: 10 }
15+
];
16+
17+
interface Repository {
18+
name: string;
19+
workspace: string;
20+
tags: string[];
21+
os: string;
22+
lastSeen: string;
23+
}
24+
25+
interface RepositoryFilters {
26+
name: string;
27+
workspace: string[];
28+
os: string[];
29+
tags: string[];
30+
}
31+
32+
const repositories: Repository[] = [
33+
{ name: 'Server-001', workspace: 'Development Workspace', tags: ['web', 'frontend'], os: 'Ubuntu 22.04', lastSeen: '2 hours ago' },
34+
{ name: 'Server-002', workspace: 'Development Workspace', tags: ['api', 'backend'], os: 'RHEL 9', lastSeen: '5 hours ago' },
35+
{ name: 'Server-003', workspace: 'Development Workspace', tags: ['database'], os: 'Windows Server 2022', lastSeen: '1 day ago' },
36+
{ name: 'Server-004', workspace: 'Production Workspace', tags: ['web', 'frontend'], os: 'Ubuntu 22.04', lastSeen: '30 minutes ago' },
37+
{ name: 'Server-005', workspace: 'Production Workspace', tags: ['api', 'backend'], os: 'Debian 12', lastSeen: '1 hour ago' },
38+
{ name: 'Server-006', workspace: 'Production Workspace', tags: ['monitoring'], os: 'macOS Ventura', lastSeen: '3 hours ago' },
39+
{ name: 'Server-007', workspace: 'Production Workspace', tags: ['cache'], os: 'macOS Sonoma', lastSeen: '2 days ago' },
40+
{ name: 'Server-008', workspace: 'Testing Workspace', tags: ['test', 'frontend'], os: 'CentOS 8', lastSeen: '6 hours ago' },
41+
{ name: 'Server-009', workspace: 'Testing Workspace', tags: ['test', 'backend'], os: 'Fedora 38', lastSeen: '4 hours ago' }
42+
];
43+
44+
const treeOptions: TreeViewDataItem[] = [
45+
{
46+
name: 'Development Workspace',
47+
id: 'workspace-dev',
48+
checkProps: { 'aria-label': 'dev-workspace-check', checked: false }
49+
},
50+
{
51+
name: 'Production Workspace',
52+
id: 'workspace-prod',
53+
checkProps: { 'aria-label': 'prod-workspace-check', checked: false }
54+
},
55+
{
56+
name: 'Testing Workspace',
57+
id: 'workspace-test',
58+
checkProps: { 'aria-label': 'test-workspace-check', checked: false }
59+
}
60+
];
61+
62+
const osOptions: TreeViewDataItem[] = [
63+
{
64+
name: 'Linux',
65+
id: 'os-linux',
66+
checkProps: { 'aria-label': 'linux-check', checked: false },
67+
children: [
68+
{
69+
name: 'Ubuntu 22.04',
70+
id: 'os-ubuntu',
71+
checkProps: { checked: false }
72+
},
73+
{
74+
name: 'RHEL 9',
75+
id: 'os-rhel',
76+
checkProps: { checked: false }
77+
},
78+
{
79+
name: 'Debian 12',
80+
id: 'os-debian',
81+
checkProps: { checked: false }
82+
},
83+
{
84+
name: 'CentOS 8',
85+
id: 'os-centos',
86+
checkProps: { checked: false }
87+
},
88+
{
89+
name: 'Fedora 38',
90+
id: 'os-fedora',
91+
checkProps: { checked: false }
92+
}
93+
],
94+
defaultExpanded: true
95+
},
96+
{
97+
name: 'Windows',
98+
id: 'os-windows',
99+
checkProps: { 'aria-label': 'windows-check', checked: false },
100+
children: [
101+
{
102+
name: 'Windows Server 2022',
103+
id: 'os-windows-2022',
104+
checkProps: { checked: false }
105+
}
106+
]
107+
},
108+
{
109+
name: 'macOS',
110+
id: 'os-macos',
111+
checkProps: { 'aria-label': 'macos-check', checked: false },
112+
children: [
113+
{
114+
name: 'macOS Ventura',
115+
id: 'os-macos-ventura',
116+
checkProps: { checked: false }
117+
},
118+
{
119+
name: 'macOS Sonoma',
120+
id: 'os-macos-sonoma',
121+
checkProps: { checked: false }
122+
}
123+
]
124+
}
125+
];
126+
127+
const tagOptions: TreeViewDataItem[] = [
128+
{
129+
name: 'Environment',
130+
id: 'tags-env',
131+
checkProps: { 'aria-label': 'env-check', checked: false },
132+
children: [
133+
{
134+
name: 'web',
135+
id: 'tag-web',
136+
checkProps: { checked: false }
137+
},
138+
{
139+
name: 'api',
140+
id: 'tag-api',
141+
checkProps: { checked: false }
142+
},
143+
{
144+
name: 'database',
145+
id: 'tag-database',
146+
checkProps: { checked: false }
147+
}
148+
],
149+
defaultExpanded: true
150+
},
151+
{
152+
name: 'Layer',
153+
id: 'tags-layer',
154+
checkProps: { 'aria-label': 'layer-check', checked: false },
155+
children: [
156+
{
157+
name: 'frontend',
158+
id: 'tag-frontend',
159+
checkProps: { checked: false }
160+
},
161+
{
162+
name: 'backend',
163+
id: 'tag-backend',
164+
checkProps: { checked: false }
165+
}
166+
]
167+
},
168+
{
169+
name: 'Other',
170+
id: 'tags-other',
171+
checkProps: { 'aria-label': 'other-check', checked: false },
172+
children: [
173+
{
174+
name: 'monitoring',
175+
id: 'tag-monitoring',
176+
checkProps: { checked: false }
177+
},
178+
{
179+
name: 'cache',
180+
id: 'tag-cache',
181+
checkProps: { checked: false }
182+
},
183+
{
184+
name: 'test',
185+
id: 'tag-test',
186+
checkProps: { checked: false }
187+
}
188+
]
189+
}
190+
];
191+
192+
const columns = ['Name', 'Workspace', 'Tags', 'OS', 'Last seen'];
193+
194+
const ouiaId = 'TreeFilterExample';
195+
196+
const MyTable: React.FunctionComponent = () => {
197+
const [searchParams, setSearchParams] = useSearchParams();
198+
const { filters, onSetFilters, clearAllFilters } = useDataViewFilters<RepositoryFilters>({
199+
initialFilters: { name: '', workspace: [], os: [], tags: [] },
200+
searchParams,
201+
setSearchParams
202+
});
203+
const pagination = useDataViewPagination({ perPage: 5 });
204+
const { page, perPage } = pagination;
205+
206+
const filteredData = useMemo(
207+
() =>
208+
repositories.filter(
209+
(item) =>
210+
(!filters.name || item.name?.toLocaleLowerCase().includes(filters.name?.toLocaleLowerCase())) &&
211+
(!filters.workspace || filters.workspace.length === 0 || filters.workspace.includes(item.workspace)) &&
212+
(!filters.os || filters.os.length === 0 || filters.os.includes(item.os)) &&
213+
(!filters.tags || filters.tags.length === 0 || filters.tags.some(tag => item.tags.includes(tag)))
214+
),
215+
[filters]
216+
);
217+
218+
const pageRows = useMemo(
219+
() =>
220+
filteredData
221+
.slice((page - 1) * perPage, (page - 1) * perPage + perPage)
222+
.map((item) => [item.name, item.workspace, item.tags.join(', '), item.os, item.lastSeen]),
223+
[page, perPage, filteredData]
224+
);
225+
226+
return (
227+
<DataView>
228+
<DataViewToolbar
229+
ouiaId="TreeFilterExampleHeader"
230+
clearAllFilters={clearAllFilters}
231+
pagination={<Pagination perPageOptions={perPageOptions} itemCount={filteredData.length} {...pagination} />}
232+
filters={
233+
<DataViewFilters onChange={(_e, values) => onSetFilters(values)} values={filters}>
234+
<DataViewTreeFilter
235+
filterId="workspace"
236+
title="Workspace"
237+
items={treeOptions}
238+
/>
239+
<DataViewTreeFilter
240+
filterId="os"
241+
title="Operating System"
242+
items={osOptions}
243+
/>
244+
<DataViewTreeFilter
245+
filterId="tags"
246+
title="Tags"
247+
items={tagOptions}
248+
/>
249+
</DataViewFilters>
250+
}
251+
/>
252+
<DataViewTable aria-label="Repositories table" ouiaId={ouiaId} columns={columns} rows={pageRows} />
253+
<DataViewToolbar
254+
ouiaId="TreeFilterExampleFooter"
255+
pagination={
256+
<Pagination isCompact perPageOptions={perPageOptions} itemCount={filteredData.length} {...pagination} />
257+
}
258+
/>
259+
</DataView>
260+
);
261+
};
262+
263+
export const TreeFilterExample: React.FunctionComponent = () => (
264+
<BrowserRouter>
265+
<MyTable />
266+
</BrowserRouter>
267+
);

packages/module/patternfly-docs/generated/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ module.exports = {
22
'/extensions/data-view/toolbar/react': {
33
id: "Toolbar",
44
title: "Data view toolbar",
5-
toc: [[{"text":"Toolbar example"}],{"text":"Toolbar actions"},[{"text":"Actions example"}],{"text":"Pagination"},[{"text":"Pagination state"},{"text":"Pagination example"}],{"text":"Selection"},[{"text":"Selection state"},{"text":"Selection example"}],{"text":"Filters"},[{"text":"Filters state"},{"text":"Filtering example"}],{"text":"All/selected data switch"},[{"text":"All/selected example"}]],
6-
examples: ["Toolbar example","Actions example","Pagination example","Selection example","Filtering example","All/selected example"],
5+
toc: [[{"text":"Toolbar example"}],{"text":"Toolbar actions"},[{"text":"Actions example"}],{"text":"Pagination"},[{"text":"Pagination state"},{"text":"Pagination example"}],{"text":"Selection"},[{"text":"Selection state"},{"text":"Selection example"}],{"text":"Filters"},[{"text":"Filters state"},{"text":"Filtering example"},{"text":"Tree filter example"}],{"text":"All/selected data switch"},[{"text":"All/selected example"}]],
6+
examples: ["Toolbar example","Actions example","Pagination example","Selection example","Filtering example","Tree filter example","All/selected example"],
77
section: "extensions",
88
subsection: "Data view",
99
source: "react",

0 commit comments

Comments
 (0)