From 5f3d4503637c850c63d7dd96f9705c77645ed287 Mon Sep 17 00:00:00 2001
From: Matt Gallo
Date: Thu, 17 Aug 2023 16:03:03 -0400
Subject: [PATCH 1/3] feat(DataTable): render select all button is onSelectAll
is provided
---
.../__snapshots__/PublicAPI-test.js.snap | 14 ++++
.../src/components/DataTable/DataTable.tsx | 4 +
.../components/DataTable/TableBatchActions.js | 29 +++++++
.../DataTable/__tests__/DataTable-test.js | 55 ++++++++-----
.../__snapshots__/DataTable-test.js.snap | 80 ++++++++++++-------
.../DataTable-batch-actions.stories.js | 10 ++-
.../data-table/action/_data-table-action.scss | 4 +
7 files changed, 147 insertions(+), 49 deletions(-)
diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
index 6eed0b2fc2e6..8aa8038a1631 100644
--- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
+++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
@@ -1874,9 +1874,15 @@ Map {
"isRequired": true,
"type": "func",
},
+ "onSelectAll": Object {
+ "type": "func",
+ },
"shouldShowBatchActions": Object {
"type": "bool",
},
+ "totalCount": Object {
+ "type": "number",
+ },
"totalSelected": Object {
"isRequired": true,
"type": "number",
@@ -1889,6 +1895,7 @@ Map {
"carbon.table.batch.cancel",
"carbon.table.batch.items.selected",
"carbon.table.batch.item.selected",
+ "carbon.table.batch.selectAll",
],
},
"TableBody": Object {
@@ -7805,9 +7812,15 @@ Map {
"isRequired": true,
"type": "func",
},
+ "onSelectAll": Object {
+ "type": "func",
+ },
"shouldShowBatchActions": Object {
"type": "bool",
},
+ "totalCount": Object {
+ "type": "number",
+ },
"totalSelected": Object {
"isRequired": true,
"type": "number",
@@ -7820,6 +7833,7 @@ Map {
"carbon.table.batch.cancel",
"carbon.table.batch.items.selected",
"carbon.table.batch.item.selected",
+ "carbon.table.batch.selectAll",
],
},
"TableBody" => Object {
diff --git a/packages/react/src/components/DataTable/DataTable.tsx b/packages/react/src/components/DataTable/DataTable.tsx
index e1d578e0a171..28efb0e0a3af 100644
--- a/packages/react/src/components/DataTable/DataTable.tsx
+++ b/packages/react/src/components/DataTable/DataTable.tsx
@@ -170,7 +170,9 @@ export interface DataTableRenderProps {
[key: string]: unknown;
}) => {
onCancel: () => void;
+ onSelectAll: () => void;
shouldShowBatchActions: boolean;
+ totalCount: number;
totalSelected: number;
[key: string]: unknown;
};
@@ -644,6 +646,8 @@ class DataTable extends React.Component<
const { shouldShowBatchActions } = this.state;
const totalSelected = this.getSelectedRows().length;
return {
+ onSelectAll: () => {},
+ totalCount: this.state.rowIds.length || 0,
...props,
shouldShowBatchActions: shouldShowBatchActions && totalSelected > 0,
totalSelected,
diff --git a/packages/react/src/components/DataTable/TableBatchActions.js b/packages/react/src/components/DataTable/TableBatchActions.js
index 9f24cf3152eb..cd9fac394d69 100644
--- a/packages/react/src/components/DataTable/TableBatchActions.js
+++ b/packages/react/src/components/DataTable/TableBatchActions.js
@@ -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]}`;
};
@@ -31,7 +35,9 @@ const TableBatchActions = ({
children,
shouldShowBatchActions,
totalSelected,
+ totalCount,
onCancel,
+ onSelectAll,
translateWithId: t,
...rest
}) => {
@@ -65,6 +71,16 @@ const TableBatchActions = ({
: t('carbon.table.batch.item.selected', { totalSelected })}
+ {onSelectAll && (
+ <>
+ |
+
+ >
+ )}
{children}
@@ -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
diff --git a/packages/react/src/components/DataTable/__tests__/DataTable-test.js b/packages/react/src/components/DataTable/__tests__/DataTable-test.js
index 003b4a791cd7..98a8b4165dca 100644
--- a/packages/react/src/components/DataTable/__tests__/DataTable-test.js
+++ b/packages/react/src/components/DataTable/__tests__/DataTable-test.js
@@ -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',
@@ -334,7 +338,10 @@ describe('DataTable', () => {
}) => (
-
+
Ghost
@@ -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();
+ 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', () => {
diff --git a/packages/react/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap b/packages/react/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap
index 9b94f0ef8686..34d188921d37 100644
--- a/packages/react/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap
+++ b/packages/react/src/components/DataTable/__tests__/__snapshots__/DataTable-test.js.snap
@@ -10,20 +10,20 @@ exports[`DataTable behaves as expected selection -- radio buttons should not hav
>