Skip to content

Commit 536676f

Browse files
committed
fix: fixing lint errors
1 parent 5c863e2 commit 536676f

File tree

3 files changed

+149
-117
lines changed

3 files changed

+149
-117
lines changed

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

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,6 @@ const repositories: Repository[] = [
4141
{ name: 'Server-009', workspace: 'Testing Workspace', tags: ['test', 'backend'], os: 'Fedora 38', lastSeen: '4 hours ago' }
4242
];
4343

44-
const treeOptions: TreeViewDataItem[] = [
45-
{
46-
name: 'Production Workspace',
47-
id: 'workspace-prod',
48-
checkProps: { 'aria-label': 'prod-workspace-check', checked: false }
49-
},
50-
{
51-
name: 'Testing Workspace',
52-
id: 'workspace-test',
53-
checkProps: { 'aria-label': 'test-workspace-check', checked: false }
54-
}
55-
];
5644

5745
const osOptions: TreeViewDataItem[] = [
5846
{
@@ -231,19 +219,13 @@ const MyTable: React.FunctionComponent = () => {
231219
title="Operating System"
232220
items={osOptions}
233221
defaultExpanded={true}
234-
onSelect={(selectedItems: TreeViewDataItem[]) => {
235-
console.log('Selected OS items:', selectedItems);
236-
}}
237222
/>
238223
<DataViewTreeFilter
239224
filterId="tags"
240225
title="Tags"
241226
items={tagOptions}
242227
defaultExpanded={false}
243228
defaultSelected={['tag-web', 'tag-api']}
244-
onSelect={(selectedItems: TreeViewDataItem[]) => {
245-
console.log('Selected tag items:', selectedItems);
246-
}}
247229
/>
248230
</DataViewFilters>
249231
}

packages/module/src/DataViewTreeFilter/DataViewTreeFilter.tsx

Lines changed: 117 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,64 @@ const useStyles = createUseStyles({
1616
}
1717
})
1818

19+
// Generic helper to collect items from tree based on predicate
20+
const collectTreeItems = (
21+
items: TreeViewDataItem[],
22+
predicate: (item: TreeViewDataItem) => boolean,
23+
leafOnly = false
24+
): TreeViewDataItem[] => {
25+
const collected: TreeViewDataItem[] = [];
26+
27+
const collect = (item: TreeViewDataItem) => {
28+
const isLeaf = !item.children || item.children.length === 0;
29+
30+
if (predicate(item) && (!leafOnly || isLeaf)) {
31+
collected.push(item);
32+
}
33+
34+
item.children?.forEach(child => collect(child));
35+
};
36+
37+
items.forEach(item => collect(item));
38+
return collected;
39+
};
40+
41+
// Helper function to get all checked items (not just leaf nodes)
42+
const getAllCheckedItems = (items: TreeViewDataItem[]): TreeViewDataItem[] =>
43+
collectTreeItems(items, item => item.checkProps?.checked === true, false);
44+
45+
// Get all checked leaf items (returns array of names)
46+
const getAllCheckedLeafItems = (items: TreeViewDataItem[]): string[] =>
47+
collectTreeItems(
48+
items,
49+
item => item.checkProps?.checked === true,
50+
true
51+
).map(item => String(item.name));
52+
53+
// Helper function to expand all nodes in the tree
54+
const expandAllNodes = (items: TreeViewDataItem[]): TreeViewDataItem[] =>
55+
items.map(item => ({
56+
...item,
57+
defaultExpanded: true,
58+
children: item.children ? expandAllNodes(item.children) : undefined
59+
}));
60+
61+
// Helper function to set pre-selected items
62+
const setPreSelectedItems = (items: TreeViewDataItem[], selectedIds: string[]): TreeViewDataItem[] =>
63+
items.map(item => {
64+
const isSelected = selectedIds.includes(String(item.id));
65+
const hasSelectedChildren = item.children?.some(child => selectedIds.includes(String(child.id))) ?? false;
66+
67+
return {
68+
...item,
69+
checkProps: item.checkProps ? {
70+
...item.checkProps,
71+
checked: isSelected || hasSelectedChildren
72+
} : undefined,
73+
children: item.children ? setPreSelectedItems(item.children, selectedIds) : undefined
74+
};
75+
});
76+
1977
export interface DataViewTreeFilterProps {
2078
/** Unique key for the filter attribute */
2179
filterId: string;
@@ -58,62 +116,11 @@ export const DataViewTreeFilter: FC<DataViewTreeFilterProps> = ({
58116
const isInitialMount = useRef(true);
59117
const hasCalledInitialOnChange = useRef(false);
60118

61-
// Helper function to expand all nodes in the tree
62-
const expandAllNodes = (items: TreeViewDataItem[]): TreeViewDataItem[] => {
63-
return items.map(item => ({
64-
...item,
65-
defaultExpanded: true,
66-
children: item.children ? expandAllNodes(item.children) : undefined
67-
}));
68-
};
69-
70-
// Helper function to set pre-selected items
71-
const setPreSelectedItems = (items: TreeViewDataItem[], selectedIds: string[]): TreeViewDataItem[] => {
72-
return items.map(item => {
73-
const isSelected = selectedIds.includes(String(item.id));
74-
const hasSelectedChildren = item.children?.some(child => selectedIds.includes(String(child.id))) ?? false;
75-
76-
return {
77-
...item,
78-
checkProps: item.checkProps ? {
79-
...item.checkProps,
80-
checked: isSelected || hasSelectedChildren
81-
} : undefined,
82-
children: item.children ? setPreSelectedItems(item.children, selectedIds) : undefined
83-
};
84-
});
85-
};
86-
87-
// Generic helper to collect items from tree based on predicate
88-
const collectTreeItems = (
89-
items: TreeViewDataItem[],
90-
predicate: (item: TreeViewDataItem) => boolean,
91-
leafOnly = false
92-
): TreeViewDataItem[] => {
93-
const collected: TreeViewDataItem[] = [];
94-
95-
const collect = (item: TreeViewDataItem) => {
96-
const isLeaf = !item.children || item.children.length === 0;
97-
98-
if (predicate(item) && (!leafOnly || isLeaf)) {
99-
collected.push(item);
100-
}
101-
102-
item.children?.forEach(child => collect(child));
103-
};
104-
105-
items.forEach(item => collect(item));
106-
return collected;
107-
};
108-
109-
// Helper function to get all checked items (not just leaf nodes)
110-
const getAllCheckedItems = (items: TreeViewDataItem[]): TreeViewDataItem[] => {
111-
return collectTreeItems(items, item => item.checkProps?.checked === true, false);
112-
};
113-
114119
// Initialize tree data with defaultExpanded and defaultSelected (only on first mount)
115120
useEffect(() => {
116-
if (!items) return;
121+
if (!items) {
122+
return;
123+
}
117124

118125
let initializedData = [...items];
119126

@@ -160,21 +167,28 @@ export const DataViewTreeFilter: FC<DataViewTreeFilterProps> = ({
160167

161168
// Sync tree checkboxes when value prop changes (when clearAllFilters is called)
162169
useEffect(() => {
163-
if (value.length === 0 && treeData.length > 0) {
164-
const currentCheckedItems = getAllCheckedLeafItems(treeData);
165-
166-
// Only update if there are checked items that need to be unchecked
167-
if (currentCheckedItems.length > 0) {
168-
const uncheckRecursive = (items: TreeViewDataItem[]): TreeViewDataItem[] => {
169-
return items.map(item => ({
170-
...item,
171-
checkProps: item.checkProps ? { ...item.checkProps, checked: false } : undefined,
172-
children: item.children ? uncheckRecursive(item.children) : undefined
173-
}));
174-
};
175-
176-
setTreeData(uncheckRecursive(treeData));
177-
}
170+
if (value.length === 0) {
171+
setTreeData(currentTreeData => {
172+
if (currentTreeData.length === 0) {
173+
return currentTreeData;
174+
}
175+
176+
const currentCheckedItems = getAllCheckedLeafItems(currentTreeData);
177+
178+
// Only update if there are checked items that need to be unchecked
179+
if (currentCheckedItems.length > 0) {
180+
const uncheckRecursive = (items: TreeViewDataItem[]): TreeViewDataItem[] =>
181+
items.map(item => ({
182+
...item,
183+
checkProps: item.checkProps ? { ...item.checkProps, checked: false } : undefined,
184+
children: item.children ? uncheckRecursive(item.children) : undefined
185+
}));
186+
187+
return uncheckRecursive(currentTreeData);
188+
}
189+
190+
return currentTreeData;
191+
});
178192
}
179193
}, [value]);
180194

@@ -202,7 +216,9 @@ export const DataViewTreeFilter: FC<DataViewTreeFilterProps> = ({
202216
}
203217
if (item.children) {
204218
const found = findItemByName(item.children, name);
205-
if (found) return found;
219+
if (found) {
220+
return found;
221+
}
206222
}
207223
}
208224
return null;
@@ -216,31 +232,32 @@ export const DataViewTreeFilter: FC<DataViewTreeFilterProps> = ({
216232
}
217233
if (item.children) {
218234
const found = findParentById(item.children, childId);
219-
if (found) return found;
235+
if (found) {
236+
return found;
237+
}
220238
}
221239
}
222240
return null;
223241
};
224242

225-
// Get all checked leaf items (returns array of names)
226-
const getAllCheckedLeafItems = (items: TreeViewDataItem[]): string[] => {
227-
return collectTreeItems(
228-
items,
229-
item => item.checkProps?.checked === true,
230-
true
231-
).map(item => String(item.name));
232-
};
233-
234243
// Update parent checkbox states based on children (recursive)
235244
const onCheckParentHandle = (childId: string): void => {
236245
const parent = findParentById(treeData, childId);
237-
if (!parent) return;
246+
if (!parent) {
247+
return;
248+
}
238249

239250
if (parent.checkProps) {
240251
const allChildrenChecked = areAllChildrenChecked(parent);
241252
const someChildrenChecked = areSomeChildrenChecked(parent);
242253

243-
parent.checkProps.checked = allChildrenChecked ? true : someChildrenChecked ? null : false;
254+
if (allChildrenChecked) {
255+
parent.checkProps.checked = true;
256+
} else if (someChildrenChecked) {
257+
parent.checkProps.checked = null;
258+
} else {
259+
parent.checkProps.checked = false;
260+
}
244261
}
245262

246263
if (parent.id) {
@@ -281,7 +298,9 @@ export const DataViewTreeFilter: FC<DataViewTreeFilterProps> = ({
281298
// Clear a specific filter by name (when label chip is removed)
282299
const onFilterSelectorClear = (itemName: string) => {
283300
const treeViewItem = findItemByName(treeData, itemName);
284-
if (!treeViewItem) return;
301+
if (!treeViewItem) {
302+
return;
303+
}
285304

286305
onCheckHandle(treeViewItem, false);
287306
if (treeViewItem.id) {
@@ -291,13 +310,12 @@ export const DataViewTreeFilter: FC<DataViewTreeFilterProps> = ({
291310

292311
// Uncheck all items in the tree
293312
const uncheckAllItems = () => {
294-
const uncheckRecursive = (items: TreeViewDataItem[]): TreeViewDataItem[] => {
295-
return items.map(item => ({
313+
const uncheckRecursive = (items: TreeViewDataItem[]): TreeViewDataItem[] =>
314+
items.map(item => ({
296315
...item,
297316
checkProps: item.checkProps ? { ...item.checkProps, checked: false } : undefined,
298317
children: item.children ? uncheckRecursive(item.children) : undefined
299318
}));
300-
};
301319

302320
const updatedTreeData = uncheckRecursive(treeData);
303321
setTreeData(updatedTreeData);
@@ -329,19 +347,19 @@ export const DataViewTreeFilter: FC<DataViewTreeFilterProps> = ({
329347

330348
return (
331349
<ToolbarFilter
332-
key={filterId}
333-
data-ouia-component-id={ouiaId}
334-
labels={value.map(item => ({ key: item, node: item }))}
335-
deleteLabel={(_, label) => {
336-
const labelKey = typeof label === 'string' ? label : label.key;
337-
onChange?.(undefined, value.filter(item => item !== labelKey));
338-
onFilterSelectorClear(labelKey);
339-
}}
340-
deleteLabelGroup={uncheckAllItems}
341-
categoryName={title}
342-
showToolbarItem={showToolbarItem}>
343-
{dropdown}
344-
</ToolbarFilter>
350+
key={filterId}
351+
data-ouia-component-id={ouiaId}
352+
labels={value.map(item => ({ key: item, node: item }))}
353+
deleteLabel={(_, label) => {
354+
const labelKey = typeof label === 'string' ? label : label.key;
355+
onChange?.(undefined, value.filter(item => item !== labelKey));
356+
onFilterSelectorClear(labelKey);
357+
}}
358+
deleteLabelGroup={uncheckAllItems}
359+
categoryName={title}
360+
showToolbarItem={showToolbarItem}>
361+
{dropdown}
362+
</ToolbarFilter>
345363
)
346364
}
347365

packages/module/src/DataViewTreeFilter/__snapshots__/DataViewTreeFilter.test.tsx.snap

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,38 @@ exports[`DataViewTreeFilter component should render correctly 1`] = `
137137
</li>
138138
</ul>
139139
</div>
140+
<div
141+
class="pf-v6-c-label-group__close"
142+
>
143+
<button
144+
aria-label="Close label group"
145+
aria-labelledby="remove_group_pf-random-id-1 pf-random-id-1"
146+
class="pf-v6-c-button pf-m-plain pf-m-small"
147+
data-ouia-component-id="OUIA-Generated-Button-plain-2"
148+
data-ouia-component-type="PF6/Button"
149+
data-ouia-safe="true"
150+
id="remove_group_pf-random-id-1"
151+
type="button"
152+
>
153+
<span
154+
class="pf-v6-c-button__icon"
155+
>
156+
<svg
157+
aria-hidden="true"
158+
class="pf-v6-svg"
159+
fill="currentColor"
160+
height="1em"
161+
role="img"
162+
viewBox="0 0 352 512"
163+
width="1em"
164+
>
165+
<path
166+
d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
167+
/>
168+
</svg>
169+
</span>
170+
</button>
171+
</div>
140172
</div>
141173
</div>
142174
</div>

0 commit comments

Comments
 (0)