Skip to content

Commit 732c112

Browse files
authored
feat(initial-selected): add option to directly set selected items (#490)
* feat(initial-selected): add option to directly set selected items * fix(test): failing test connected to setting selected items
1 parent 6b5ee26 commit 732c112

File tree

6 files changed

+89
-6
lines changed

6 files changed

+89
-6
lines changed

cypress/component/DataViewToolbar.cy.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ describe('DataViewToolbar', () => {
3434
cy.get('[data-ouia-component-id="DataViewToolbar-bulk-select"]').should('exist');
3535
cy.get('[data-ouia-component-id="ResponsiveActions-menu"]').should('exist');
3636
});
37-
});
37+
});

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import { useDataViewSelection } from '@patternfly/react-data-view/dist/dynamic/Hooks';
33
import { BulkSelect, BulkSelectValue } from '@patternfly/react-component-groups/dist/dynamic/BulkSelect';
4+
import { Button } from '@patternfly/react-core';
45
import { DataView } from '@patternfly/react-data-view/dist/dynamic/DataView';
56
import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';
67
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
@@ -30,13 +31,18 @@ const ouiaId = 'LayoutExample';
3031

3132
export const BasicExample: React.FunctionComponent = () => {
3233
const selection = useDataViewSelection({ matchOption: (a, b) => a[0] === b[0] });
33-
const { selected, onSelect } = selection;
34+
const { selected, onSelect, setSelected } = selection;
3435

3536
const handleBulkSelect = (value: BulkSelectValue) => {
3637
value === BulkSelectValue.none && onSelect(false);
3738
value === BulkSelectValue.all && onSelect(true, rows);
3839
};
3940

41+
// Example: Select first two rows programmatically using setSelected
42+
const handleSelectFirstTwo = () => {
43+
setSelected(rows.slice(0, 2));
44+
};
45+
4046
return (
4147
<DataView selection={selection}>
4248
<DataViewToolbar
@@ -49,9 +55,14 @@ export const BasicExample: React.FunctionComponent = () => {
4955
selectedCount={selected.length}
5056
onSelect={handleBulkSelect}
5157
/>
52-
}
58+
}
59+
actions={
60+
<Button variant="secondary" onClick={handleSelectFirstTwo}>
61+
Select First Two
62+
</Button>
63+
}
5364
/>
5465
<DataViewTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={rows} />
5566
</DataView>
5667
);
57-
}
68+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ The `useDataViewSelection` hook manages the selection state of the data view.
105105
- `selected` array of currently selected records.
106106
- `isSelected` function returning the selection state for the record.
107107
- `onSelect` callback to modify the selection state. This accepts the `isSelecting` flag (indicates if records are being selected or deselected) and `items` (affected records).
108+
- `setSelected` function to directly set the selected items array. This is useful for programmatically setting a specific selection state without needing to use the `onSelect` callback.
108109

109110
### Selection example
110111

packages/module/src/Hooks/selection.test.tsx

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ describe('useDataViewSelection', () => {
99
selected: [],
1010
onSelect: expect.any(Function),
1111
isSelected: expect.any(Function),
12+
setSelected: expect.any(Function),
1213
})
1314
});
1415

@@ -19,6 +20,7 @@ describe('useDataViewSelection', () => {
1920
selected: initialSelected,
2021
onSelect: expect.any(Function),
2122
isSelected: expect.any(Function),
23+
setSelected: expect.any(Function),
2224
})
2325
});
2426

@@ -49,4 +51,66 @@ describe('useDataViewSelection', () => {
4951
expect(result.current.isSelected({ id: 1, name: 'test1' })).toBe(true);
5052
expect(result.current.isSelected({ id: 3, name: 'test2' })).toBe(false);
5153
});
52-
});
54+
55+
it('should have setSelected function in return object', () => {
56+
const { result } = renderHook(() => useDataViewSelection({ matchOption: (a, b) => a.id === b.id }))
57+
expect(result.current).toEqual({
58+
selected: [],
59+
onSelect: expect.any(Function),
60+
isSelected: expect.any(Function),
61+
setSelected: expect.any(Function),
62+
})
63+
});
64+
65+
it('should set selected items directly using setSelected - objects', async () => {
66+
const initialSelected = [ { id: 1, name: 'test1' } ];
67+
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a.id === b.id }))
68+
69+
const newSelected = [ { id: 2, name: 'test2' }, { id: 3, name: 'test3' } ];
70+
71+
await act(async () => {
72+
result.current.setSelected(newSelected);
73+
});
74+
75+
expect(result.current.selected).toEqual(newSelected);
76+
});
77+
78+
it('should set selected items directly using setSelected - strings', async () => {
79+
const initialSelected = [ 'test1', 'test2' ];
80+
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a === b }))
81+
82+
const newSelected = [ 'test3', 'test4', 'test5' ];
83+
84+
await act(async () => {
85+
result.current.setSelected(newSelected);
86+
});
87+
88+
expect(result.current.selected).toEqual(newSelected);
89+
});
90+
91+
it('should clear all selections using setSelected with empty array', async () => {
92+
const initialSelected = [ { id: 1, name: 'test1' }, { id: 2, name: 'test2' } ];
93+
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a.id === b.id }))
94+
95+
await act(async () => {
96+
result.current.setSelected([]);
97+
});
98+
99+
expect(result.current.selected).toEqual([]);
100+
});
101+
102+
it('should update isSelected correctly after using setSelected', async () => {
103+
const initialSelected = [ { id: 1, name: 'test1' } ];
104+
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a.id === b.id }))
105+
106+
const newSelected = [ { id: 2, name: 'test2' }, { id: 3, name: 'test3' } ];
107+
108+
await act(async () => {
109+
result.current.setSelected(newSelected);
110+
});
111+
112+
expect(result.current.isSelected({ id: 1, name: 'test1' })).toBe(false);
113+
expect(result.current.isSelected({ id: 2, name: 'test2' })).toBe(true);
114+
expect(result.current.isSelected({ id: 3, name: 'test3' })).toBe(true);
115+
});
116+
});

packages/module/src/Hooks/selection.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@ export const useDataViewSelection = (props?: UseDataViewSelectionProps) => {
2424

2525
const isSelected = (item: any): boolean => Boolean(selected.find(selected => matchOption(selected, item)));
2626

27+
const setSelectedItems = (items: any[]) => {
28+
setSelected(items);
29+
};
30+
2731
return {
2832
selected,
2933
onSelect,
30-
isSelected
34+
isSelected,
35+
setSelected: setSelectedItems
3136
};
3237
};

packages/module/src/InternalContext/InternalContext.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export interface DataViewSelection {
66
onSelect: (isSelecting: boolean, items?: any[] | any) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
77
/** Checks if a specific item is currently selected */
88
isSelected: (item: any) => boolean; // eslint-disable-line @typescript-eslint/no-explicit-any
9+
/** Directly sets the selected items */
10+
setSelected?: (items: any[]) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
911
/** Determines if selection is disabled for a given item */
1012
isSelectDisabled?: (item: any) => boolean; // eslint-disable-line @typescript-eslint/no-explicit-any
1113
}

0 commit comments

Comments
 (0)