Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cypress/component/DataViewToolbar.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ describe('DataViewToolbar', () => {
cy.get('[data-ouia-component-id="DataViewToolbar-bulk-select"]').should('exist');
cy.get('[data-ouia-component-id="ResponsiveActions-menu"]').should('exist');
});
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { useDataViewSelection } from '@patternfly/react-data-view/dist/dynamic/Hooks';
import { BulkSelect, BulkSelectValue } from '@patternfly/react-component-groups/dist/dynamic/BulkSelect';
import { Button } from '@patternfly/react-core';
import { DataView } from '@patternfly/react-data-view/dist/dynamic/DataView';
import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
Expand Down Expand Up @@ -30,13 +31,18 @@ const ouiaId = 'LayoutExample';

export const BasicExample: React.FunctionComponent = () => {
const selection = useDataViewSelection({ matchOption: (a, b) => a[0] === b[0] });
const { selected, onSelect } = selection;
const { selected, onSelect, setSelected } = selection;

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

// Example: Select first two rows programmatically using setSelected
const handleSelectFirstTwo = () => {
setSelected(rows.slice(0, 2));
};

return (
<DataView selection={selection}>
<DataViewToolbar
Expand All @@ -49,9 +55,14 @@ export const BasicExample: React.FunctionComponent = () => {
selectedCount={selected.length}
onSelect={handleBulkSelect}
/>
}
}
actions={
<Button variant="secondary" onClick={handleSelectFirstTwo}>
Select First Two
</Button>
}
/>
<DataViewTable aria-label='Repositories table' ouiaId={ouiaId} columns={columns} rows={rows} />
</DataView>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ The `useDataViewSelection` hook manages the selection state of the data view.
- `selected` array of currently selected records.
- `isSelected` function returning the selection state for the record.
- `onSelect` callback to modify the selection state. This accepts the `isSelecting` flag (indicates if records are being selected or deselected) and `items` (affected records).
- `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.

### Selection example

Expand Down
66 changes: 65 additions & 1 deletion packages/module/src/Hooks/selection.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe('useDataViewSelection', () => {
selected: [],
onSelect: expect.any(Function),
isSelected: expect.any(Function),
setSelected: expect.any(Function),
})
});

Expand All @@ -19,6 +20,7 @@ describe('useDataViewSelection', () => {
selected: initialSelected,
onSelect: expect.any(Function),
isSelected: expect.any(Function),
setSelected: expect.any(Function),
})
});

Expand Down Expand Up @@ -49,4 +51,66 @@ describe('useDataViewSelection', () => {
expect(result.current.isSelected({ id: 1, name: 'test1' })).toBe(true);
expect(result.current.isSelected({ id: 3, name: 'test2' })).toBe(false);
});
});

it('should have setSelected function in return object', () => {
const { result } = renderHook(() => useDataViewSelection({ matchOption: (a, b) => a.id === b.id }))
expect(result.current).toEqual({
selected: [],
onSelect: expect.any(Function),
isSelected: expect.any(Function),
setSelected: expect.any(Function),
})
});

it('should set selected items directly using setSelected - objects', async () => {
const initialSelected = [ { id: 1, name: 'test1' } ];
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a.id === b.id }))

const newSelected = [ { id: 2, name: 'test2' }, { id: 3, name: 'test3' } ];

await act(async () => {
result.current.setSelected(newSelected);
});

expect(result.current.selected).toEqual(newSelected);
});

it('should set selected items directly using setSelected - strings', async () => {
const initialSelected = [ 'test1', 'test2' ];
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a === b }))

const newSelected = [ 'test3', 'test4', 'test5' ];

await act(async () => {
result.current.setSelected(newSelected);
});

expect(result.current.selected).toEqual(newSelected);
});

it('should clear all selections using setSelected with empty array', async () => {
const initialSelected = [ { id: 1, name: 'test1' }, { id: 2, name: 'test2' } ];
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a.id === b.id }))

await act(async () => {
result.current.setSelected([]);
});

expect(result.current.selected).toEqual([]);
});

it('should update isSelected correctly after using setSelected', async () => {
const initialSelected = [ { id: 1, name: 'test1' } ];
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a.id === b.id }))

const newSelected = [ { id: 2, name: 'test2' }, { id: 3, name: 'test3' } ];

await act(async () => {
result.current.setSelected(newSelected);
});

expect(result.current.isSelected({ id: 1, name: 'test1' })).toBe(false);
expect(result.current.isSelected({ id: 2, name: 'test2' })).toBe(true);
expect(result.current.isSelected({ id: 3, name: 'test3' })).toBe(true);
});
});
7 changes: 6 additions & 1 deletion packages/module/src/Hooks/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@ export const useDataViewSelection = (props?: UseDataViewSelectionProps) => {

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

const setSelectedItems = (items: any[]) => {
setSelected(items);
};

return {
selected,
onSelect,
isSelected
isSelected,
setSelected: setSelectedItems
};
};
2 changes: 2 additions & 0 deletions packages/module/src/InternalContext/InternalContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export interface DataViewSelection {
onSelect: (isSelecting: boolean, items?: any[] | any) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
/** Checks if a specific item is currently selected */
isSelected: (item: any) => boolean; // eslint-disable-line @typescript-eslint/no-explicit-any
/** Directly sets the selected items */
setSelected?: (items: any[]) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
/** Determines if selection is disabled for a given item */
isSelectDisabled?: (item: any) => boolean; // eslint-disable-line @typescript-eslint/no-explicit-any
}
Expand Down