Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(DataTable): add batch actions select all button addition #14476

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
14 changes: 14 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1888,9 +1888,15 @@ Map {
"isRequired": true,
"type": "func",
},
"onSelectAll": Object {
"type": "func",
},
"shouldShowBatchActions": Object {
"type": "bool",
},
"totalCount": Object {
"type": "number",
},
"totalSelected": Object {
"isRequired": true,
"type": "number",
Expand All @@ -1903,6 +1909,7 @@ Map {
"carbon.table.batch.cancel",
"carbon.table.batch.items.selected",
"carbon.table.batch.item.selected",
"carbon.table.batch.selectAll",
],
},
"TableBody": Object {
Expand Down Expand Up @@ -7748,9 +7755,15 @@ Map {
"isRequired": true,
"type": "func",
},
"onSelectAll": Object {
"type": "func",
},
"shouldShowBatchActions": Object {
"type": "bool",
},
"totalCount": Object {
"type": "number",
},
"totalSelected": Object {
"isRequired": true,
"type": "number",
Expand All @@ -7763,6 +7776,7 @@ Map {
"carbon.table.batch.cancel",
"carbon.table.batch.items.selected",
"carbon.table.batch.item.selected",
"carbon.table.batch.selectAll",
],
},
"TableBody" => Object {
Expand Down
4 changes: 4 additions & 0 deletions packages/react/src/components/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ export interface DataTableRenderProps<RowType, ColTypes extends any[]> {
[key: string]: unknown;
}) => {
onCancel: () => void;
onSelectAll?: () => void | undefined;
shouldShowBatchActions: boolean;
totalCount: number;
totalSelected: number;
[key: string]: unknown;
};
Expand Down Expand Up @@ -678,6 +680,8 @@ class DataTable<RowType, ColTypes extends any[]> extends React.Component<
const { shouldShowBatchActions } = this.state;
const totalSelected = this.getSelectedRows().length;
return {
onSelectAll: undefined,
totalCount: this.state.rowIds.length || 0,
...props,
shouldShowBatchActions: shouldShowBatchActions && totalSelected > 0,
totalSelected,
Expand Down
29 changes: 29 additions & 0 deletions packages/react/src/components/DataTable/TableBatchActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ const translationKeys = {
'carbon.table.batch.cancel': 'Cancel',
'carbon.table.batch.items.selected': 'items selected',
'carbon.table.batch.item.selected': 'item selected',
'carbon.table.batch.selectAll': 'Select all',
};

const translateWithId = (id, state) => {
if (id === 'carbon.table.batch.cancel') {
return translationKeys[id];
}
if (id === 'carbon.table.batch.selectAll') {
return `${translationKeys[id]} (${state.totalCount})`;
}
return `${state.totalSelected} ${translationKeys[id]}`;
};

Expand All @@ -31,7 +35,9 @@ const TableBatchActions = ({
children,
shouldShowBatchActions,
totalSelected,
totalCount,
onCancel,
onSelectAll,
translateWithId: t,
...rest
}) => {
Expand Down Expand Up @@ -65,6 +71,16 @@ const TableBatchActions = ({
: t('carbon.table.batch.item.selected', { totalSelected })}
</Text>
</p>
{onSelectAll && (
<>
<span className={`${prefix}--batch-summary__divider`}>&#x7c;</span>
<Button
onClick={onSelectAll}
tabIndex={shouldShowBatchActions ? 0 : -1}>
{t('carbon.table.batch.selectAll', { totalCount })}
</Button>
</>
)}
</div>
<TableActionList>
{children}
Expand All @@ -91,12 +107,25 @@ TableBatchActions.propTypes = {
*/
onCancel: PropTypes.func.isRequired,

/**
* Hook required to listen for when the user initiates a select all
* request through this component. This _only_ controls the rendering
* of the `Select All` button and does not include built in functionality
*/
onSelectAll: PropTypes.func,

/**
* Boolean specifier for whether or not the batch action bar should be
* displayed
*/
shouldShowBatchActions: PropTypes.bool,

/**
* Numeric representation of the total number of items in a table.
* This number is used in the select all button text
*/
totalCount: PropTypes.number,

/**
* Numeric representation of the total number of items selected in a table.
* This number is used to derive the selection message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,28 +35,32 @@ import { render, screen, within } from '@testing-library/react';
const getLastCallFor = (mocker) =>
mocker.mock.calls[mocker.mock.calls.length - 1];

const onSelectAllFn = jest.fn();

const rows = [
{
id: 'b',
fieldA: 'Field 2:A',
fieldB: 'Field 2:B',
},
{
id: 'a',
fieldA: 'Field 1:A',
fieldB: 'Field 1:B',
},
{
id: 'c',
fieldA: 'Field 3:A',
fieldB: 'Field 3:B',
},
];

describe('DataTable', () => {
let mockProps;

beforeEach(() => {
mockProps = {
rows: [
{
id: 'b',
fieldA: 'Field 2:A',
fieldB: 'Field 2:B',
},
{
id: 'a',
fieldA: 'Field 1:A',
fieldB: 'Field 1:B',
},
{
id: 'c',
fieldA: 'Field 3:A',
fieldB: 'Field 3:B',
},
],
rows,
headers: [
{
key: 'fieldA',
Expand Down Expand Up @@ -334,7 +338,10 @@ describe('DataTable', () => {
}) => (
<TableContainer title="DataTable with selection">
<TableToolbar>
<TableBatchActions {...getBatchActionProps()}>
<TableBatchActions
{...getBatchActionProps({
onSelectAll: onSelectAllFn,
})}>
<TableBatchAction onClick={jest.fn()}>
Ghost
</TableBatchAction>
Expand Down Expand Up @@ -452,6 +459,18 @@ describe('DataTable', () => {
const { selectedRows } = getLastCallFor(mockProps.render)[0];
expect(selectedRows.length).toBe(0);
});

it('should call the onSelectAll prop if supplied to TableBatchAction component', async () => {
render(<DataTable {...mockProps} />);
const selectAllCheckbox = screen.getAllByRole('checkbox')[0];

await userEvent.click(selectAllCheckbox);
expect(selectAllCheckbox).toBeChecked();

const selectAllButton = screen.getByText(`Select all (${rows.length})`);
await userEvent.click(selectAllButton);
expect(onSelectAllFn).toHaveBeenCalledTimes(1);
});
});

describe('selection with filtering', () => {
Expand Down
Loading
Loading