Skip to content

Commit 89e4783

Browse files
committed
feat(initial-selected): add option to directly set selected items
1 parent 4a0dd2c commit 89e4783

File tree

6 files changed

+86
-5
lines changed

6 files changed

+86
-5
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
@@ -104,6 +104,7 @@ The `useDataViewSelection` hook manages the selection state of the data view.
104104
- `selected` array of currently selected records.
105105
- `isSelected` function returning the selection state for the record.
106106
- `onSelect` callback to modify the selection state. This accepts the `isSelecting` flag (indicates if records are being selected or deselected) and `items` (affected records).
107+
- `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.
107108

108109
### Selection example
109110

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

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

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)