From 4e688a335f284a874ba9938ac41445d2c705bfe1 Mon Sep 17 00:00:00 2001
From: Filip Hlavac
Date: Fri, 7 Jun 2024 15:12:45 +0200
Subject: [PATCH 1/7] feat(BulkSelect): Add BulkSelect
---
packages/module/src/BulkSelect/BulkSelect.tsx | 95 +++++++++++++++++++
packages/module/src/BulkSelect/index.ts | 2 +
packages/module/src/index.ts | 3 +
3 files changed, 100 insertions(+)
create mode 100644 packages/module/src/BulkSelect/BulkSelect.tsx
create mode 100644 packages/module/src/BulkSelect/index.ts
diff --git a/packages/module/src/BulkSelect/BulkSelect.tsx b/packages/module/src/BulkSelect/BulkSelect.tsx
new file mode 100644
index 00000000..fa00c56a
--- /dev/null
+++ b/packages/module/src/BulkSelect/BulkSelect.tsx
@@ -0,0 +1,95 @@
+import React, { useMemo, useState } from 'react';
+import { Dropdown, DropdownItem, DropdownList, DropdownProps, MenuToggle, MenuToggleCheckbox, MenuToggleElement, Text } from '@patternfly/react-core';
+
+export const BulkSelectValue = {
+ all: 'all',
+ none: 'none',
+ page: 'page',
+ nonePage: 'nonePage'
+} as const;
+
+export type BulkSelectValue = typeof BulkSelectValue[keyof typeof BulkSelectValue];
+
+export interface BulkSelectProps extends Omit {
+ /** BulkSelect className */
+ className?: string;
+ /** Indicates whether selectable items are paginated */
+ isDataPaginated?: boolean;
+ /** Indicates whether "Select all" option should be available */
+ canSelectAll?: boolean;
+ /** Number of entries present in current page */
+ pageCount?: number;
+ /** Number of selected entries */
+ selectedCount: number;
+ /** Number of all entries */
+ totalCount?: number;
+ /** Indicates if ALL current page items are selected */
+ pageSelected?: boolean;
+ /** Indicates if ONLY some current page items are selected */
+ pagePartiallySelected?: boolean;
+ /** Callback called on item select */
+ onSelect: (value: BulkSelectValue) => void;
+ /** Custom OUIA ID */
+ ouiaId?: string;
+}
+
+export const BulkSelect: React.FC = ({ isDataPaginated = true, canSelectAll, pageSelected, pagePartiallySelected, pageCount, selectedCount = 0, totalCount, ouiaId = 'BulkSelect', onSelect, ...props }: BulkSelectProps) => {
+ const [ isOpen, setOpen ] = useState(false);
+
+ const splitButtonDropdownItems = useMemo(() =>
+ <>
+
+ Select none (0)
+
+ {isDataPaginated &&
+ {`Select page${pageCount ? ` (${pageCount})` : ''}`}
+ }
+ {canSelectAll &&
+ {`Select all${totalCount ? ` (${totalCount})` : ''}`}
+ }
+ >, [ isDataPaginated, canSelectAll, ouiaId, pageCount, totalCount ]
+ );
+
+ const allOption = isDataPaginated ? BulkSelectValue.page : BulkSelectValue.all;
+ const noneOption = isDataPaginated ? BulkSelectValue.nonePage : BulkSelectValue.none;
+
+ return (
+ {
+ setOpen(!isOpen);
+ onSelect?.(value as BulkSelectValue);
+ }}
+ isOpen={isOpen}
+ onOpenChange={(isOpen: boolean) => setOpen(isOpen)}
+ toggle={(toggleRef: React.Ref) => (
+ setOpen(!isOpen)}
+ aria-label="Bulk select toggle"
+ data-ouia-component-id={`${ouiaId}-toggle`}
+ splitButtonOptions={{
+ items: [
+ 0 ? null : pageSelected || selectedCount === totalCount}
+ onChange={(checked) => onSelect?.(!checked || (checked === null) ? noneOption : allOption)}
+ />,
+ selectedCount > 0 ? {`${selectedCount} selected`} : null
+ ]
+ }}
+ />
+ )}
+ {...props}
+ >
+ {splitButtonDropdownItems}
+
+ );}
+
+export default BulkSelect;
+
+
diff --git a/packages/module/src/BulkSelect/index.ts b/packages/module/src/BulkSelect/index.ts
new file mode 100644
index 00000000..1ffd7343
--- /dev/null
+++ b/packages/module/src/BulkSelect/index.ts
@@ -0,0 +1,2 @@
+export { default } from './BulkSelect';
+export * from './BulkSelect';
diff --git a/packages/module/src/index.ts b/packages/module/src/index.ts
index 03a83e87..eefe1ab4 100644
--- a/packages/module/src/index.ts
+++ b/packages/module/src/index.ts
@@ -12,6 +12,9 @@ export * from './Ansible';
export { default as Battery } from './Battery';
export * from './Battery';
+export { default as BulkSelect } from './BulkSelect';
+export * from './BulkSelect';
+
export { default as CloseButton } from './CloseButton';
export * from './CloseButton';
From 19178485948f0e03b072f60c9e45cc28e100c00c Mon Sep 17 00:00:00 2001
From: Filip Hlavac
Date: Fri, 7 Jun 2024 15:13:00 +0200
Subject: [PATCH 2/7] Add BulkSelect docs
---
.../examples/BulkSelect/BulkSelect.md | 37 +++++++++++++++++++
.../BulkSelect/BulkSelectAllExample.tsx | 28 ++++++++++++++
.../examples/BulkSelect/BulkSelectExample.tsx | 26 +++++++++++++
3 files changed, 91 insertions(+)
create mode 100644 packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelect.md
create mode 100644 packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelectAllExample.tsx
create mode 100644 packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelectExample.tsx
diff --git a/packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelect.md b/packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelect.md
new file mode 100644
index 00000000..79165d23
--- /dev/null
+++ b/packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelect.md
@@ -0,0 +1,37 @@
+---
+# Sidenav top-level section
+# should be the same for all markdown files
+section: extensions
+subsection: Component groups
+# Sidenav secondary level section
+# should be the same for all markdown files
+id: Bulk select
+# Tab (react | react-demos | html | html-demos | design-guidelines | accessibility)
+source: react
+# If you use typescript, the name of the interface to display props for
+# These are found through the sourceProps function provided in patternfly-docs.source.js
+propComponents: ['BulkSelect']
+sourceLink: https://github.com/patternfly/react-component-groups/blob/main/packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelect.md
+---
+import { useState } from 'react';
+import { BulkSelect, BulkSelectValue } from '@patternfly/react-component-groups/dist/dynamic/BulkSelect';
+
+The **bulk select** provides a way of selecting data records in batches. You can select all data at once, all data on current page or deselect all.
+
+## Examples
+
+### Basic paginated bulk select
+
+To display a default bulk select, you need to pass number of selected items using `selectedCount`, the `onSelect` callback accepting bulk select option values and selecting data accordingly, `pageCount` defining number of items on the current page, `pageSelected` and `pagePartiallySelected` boolean flags to define the state os the bulk select checkbox..
+
+```js file="./BulkSelectExample.tsx"
+
+```
+
+### Bulk select with all option
+
+To display an option for seleting all data at once, pass `canSelectAll` flag together with `totalCount` of data entries. You can also remove the page select option by setting `isDataPaginated` to `false`,
+
+```js file="./BulkSelectAllExample.tsx"
+
+```
diff --git a/packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelectAllExample.tsx b/packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelectAllExample.tsx
new file mode 100644
index 00000000..b1dda1a1
--- /dev/null
+++ b/packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelectAllExample.tsx
@@ -0,0 +1,28 @@
+import React, { useState } from 'react';
+import { BulkSelect, BulkSelectValue } from '@patternfly/react-component-groups/dist/dynamic/BulkSelect';
+
+const allData = [ "Item 1", "Item 2" , "Item 3", "Item4", "Item 5" ];
+const pageData = [ "Item 1", "Item 2" ];
+
+export const BasicExample: React.FunctionComponent = () => {
+ const [ selected, setSelected ] = useState(pageData);
+
+ const handleBulkSelect = (value: BulkSelectValue) => {
+ value === BulkSelectValue.none && setSelected([]);
+ value === BulkSelectValue.all && setSelected(allData);
+ value === BulkSelectValue.nonePage && setSelected(selected.filter(item => !pageData.includes(item)));
+ value === BulkSelectValue.page && setSelected(pageData);
+ };
+
+ return (
+ selected.includes(item))}
+ pagePartiallySelected={pageData.some(item => selected.includes(item)) && !pageData.every(item => selected.includes(item))}
+ />
+ );
+}
\ No newline at end of file
diff --git a/packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelectExample.tsx b/packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelectExample.tsx
new file mode 100644
index 00000000..a69a21df
--- /dev/null
+++ b/packages/module/patternfly-docs/content/extensions/component-groups/examples/BulkSelect/BulkSelectExample.tsx
@@ -0,0 +1,26 @@
+import React, { useState } from 'react';
+import { BulkSelect, BulkSelectValue } from '@patternfly/react-component-groups/dist/dynamic/BulkSelect';
+
+const allData = [ "Item 1", "Item 2" , "Item 3", "Item4", "Item 5" ];
+const pageData = [ "Item 1", "Item 2" ];
+
+export const BasicExample: React.FunctionComponent = () => {
+ const [ selected, setSelected ] = useState([]);
+
+ const handleBulkSelect = (value: BulkSelectValue) => {
+ value === BulkSelectValue.none && setSelected([]);
+ value === BulkSelectValue.all && setSelected(allData);
+ value === BulkSelectValue.nonePage && setSelected(selected.filter(item => !pageData.includes(item)));
+ value === BulkSelectValue.page && setSelected(pageData);
+ };
+
+ return (
+ selected.includes(item))}
+ pagePartiallySelected={pageData.some(item => selected.includes(item)) && !pageData.every(item => selected.includes(item))}
+ />
+ );
+}
\ No newline at end of file
From 63169f44f76b36b8100035e092876857bb65bad4 Mon Sep 17 00:00:00 2001
From: Filip Hlavac
Date: Fri, 7 Jun 2024 15:13:05 +0200
Subject: [PATCH 3/7] Test BulkSelect
---
cypress/component/BulkSelect.cy.tsx | 95 +++++++++
.../module/src/BulkSelect/BulkSelect.test.tsx | 18 ++
.../__snapshots__/BulkSelect.test.tsx.snap | 180 ++++++++++++++++++
3 files changed, 293 insertions(+)
create mode 100644 cypress/component/BulkSelect.cy.tsx
create mode 100644 packages/module/src/BulkSelect/BulkSelect.test.tsx
create mode 100644 packages/module/src/BulkSelect/__snapshots__/BulkSelect.test.tsx.snap
diff --git a/cypress/component/BulkSelect.cy.tsx b/cypress/component/BulkSelect.cy.tsx
new file mode 100644
index 00000000..6070e2f9
--- /dev/null
+++ b/cypress/component/BulkSelect.cy.tsx
@@ -0,0 +1,95 @@
+import React, { useState } from 'react';
+import BulkSelect, { BulkSelectProps, BulkSelectValue } from '../../packages/module/dist/dynamic/BulkSelect';
+
+interface DataItem {
+ name: string
+};
+
+const BulkSelectTestComponent = ({ canSelectAll }: Omit) => {
+ const [ selected, setSelected ] = useState([]);
+
+ const allData = [ { name: '1' }, { name: '2' }, { name: '3' }, { name: '4' }, { name: '5' }, { name: '6' } ];
+ const pageData = [ { name: '1' }, { name: '2' }, { name: '3' }, { name: '4' }, { name: '5' } ];
+ const pageDataNames = pageData.map((item) => item.name);
+
+ const handleBulkSelect = (value: BulkSelectValue) => {
+ value === BulkSelectValue.none && setSelected([]);
+ value === BulkSelectValue.page && setSelected(pageData);
+ value === BulkSelectValue.all && setSelected(allData);
+ value === BulkSelectValue.nonePage && setSelected(selected.filter(item => !pageDataNames.includes(item.name)))};
+
+ return (
+ 0 && selected.length <= 5}
+ pagePartiallySelected={selected.length > 0 && selected.length < 5}
+ onSelect={handleBulkSelect}
+ />
+ );
+};
+
+describe('BulkSelect', () => {
+ it('renders the bulk select', () => {
+ cy.mount(
+
+ );
+ cy.get('[data-ouia-component-id="BulkSelect-checkbox"]').should('exist');
+ cy.get('[data-ouia-component-id="BulkSelect-toggle"]').click();
+ cy.get('[data-ouia-component-id="BulkSelect-select-all"]').should('not.exist');
+ cy.get('[data-ouia-component-id="BulkSelect-select-page"]').should('exist');
+ cy.get('[data-ouia-component-id="BulkSelect-select-none"]').should('exist');
+
+ cy.contains('0 selected').should('not.exist');
+ });
+
+ it('renders the bulk select without all', () => {
+ cy.mount(
+
+ );
+ cy.get('[data-ouia-component-id="BulkSelect-checkbox"]').should('exist');
+ cy.get('[data-ouia-component-id="BulkSelect-toggle"]').click();
+ cy.get('[data-ouia-component-id="BulkSelect-select-all"]').should('exist');
+ cy.get('[data-ouia-component-id="BulkSelect-select-page"]').should('exist');
+ cy.get('[data-ouia-component-id="BulkSelect-select-none"]').should('exist');
+
+ cy.contains('0 selected').should('not.exist');
+ });
+
+ it('renders the bulk select with data', () => {
+ cy.mount(
+
+ );
+
+ // Initial state
+ cy.get('input[type="checkbox"]').each(($checkbox) => {
+ cy.wrap($checkbox).should('not.be.checked');
+ });
+
+ // Checkbox select
+ cy.get('[data-ouia-component-id="BulkSelect-checkbox"]').first().click();
+ cy.get('input[type="checkbox"]').should('be.checked');
+ cy.contains('5 selected').should('exist');
+
+ // Select none
+ cy.get('[data-ouia-component-id="BulkSelect-toggle"]').first().click({ force: true });
+ cy.get('[data-ouia-component-id="BulkSelect-select-none"]').first().click();
+ cy.contains('0 selected').should('not.exist');
+
+ // Select all
+ cy.get('[data-ouia-component-id="BulkSelect-toggle"]').first().click({ force: true });
+ cy.get('[data-ouia-component-id="BulkSelect-select-all"]').first().click();
+ cy.contains('6 selected').should('exist');
+
+ // Checkbox deselect
+ cy.get('[data-ouia-component-id="BulkSelect-checkbox"]').first().click({ force: true });
+ cy.contains('1 selected').should('exist');
+
+ // Select page
+ cy.get('[data-ouia-component-id="BulkSelect-toggle"]').first().click({ force: true });
+ cy.get('[data-ouia-component-id="BulkSelect-select-page"]').first().click();
+ cy.contains('5 selected').should('exist');
+ });
+});
\ No newline at end of file
diff --git a/packages/module/src/BulkSelect/BulkSelect.test.tsx b/packages/module/src/BulkSelect/BulkSelect.test.tsx
new file mode 100644
index 00000000..cb1e678f
--- /dev/null
+++ b/packages/module/src/BulkSelect/BulkSelect.test.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+import BulkSelect from './BulkSelect';
+
+describe('BulkSelect component', () => {
+ test('should render', () => {
+ expect(render(
+ null}
+ />)).toMatchSnapshot();
+ });
+});
\ No newline at end of file
diff --git a/packages/module/src/BulkSelect/__snapshots__/BulkSelect.test.tsx.snap b/packages/module/src/BulkSelect/__snapshots__/BulkSelect.test.tsx.snap
new file mode 100644
index 00000000..92c481c7
--- /dev/null
+++ b/packages/module/src/BulkSelect/__snapshots__/BulkSelect.test.tsx.snap
@@ -0,0 +1,180 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`BulkSelect component should render 1`] = `
+{
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+ ,
+ "container":
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
From 1adc87b10c766e735220716bb5e1f4e62bb83c74 Mon Sep 17 00:00:00 2001
From: Filip Hlavac
Date: Fri, 7 Jun 2024 15:59:38 +0200
Subject: [PATCH 4/7] Update the cypress tests
---
cypress/component/BulkSelect.cy.tsx | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/cypress/component/BulkSelect.cy.tsx b/cypress/component/BulkSelect.cy.tsx
index 6070e2f9..1a1e3da1 100644
--- a/cypress/component/BulkSelect.cy.tsx
+++ b/cypress/component/BulkSelect.cy.tsx
@@ -5,12 +5,13 @@ interface DataItem {
name: string
};
-const BulkSelectTestComponent = ({ canSelectAll }: Omit) => {
+const BulkSelectTestComponent = ({ canSelectAll, isDataPaginated }: Omit) => {
const [ selected, setSelected ] = useState([]);
const allData = [ { name: '1' }, { name: '2' }, { name: '3' }, { name: '4' }, { name: '5' }, { name: '6' } ];
const pageData = [ { name: '1' }, { name: '2' }, { name: '3' }, { name: '4' }, { name: '5' } ];
const pageDataNames = pageData.map((item) => item.name);
+ const pageSelected = pageDataNames.every(item => selected.find(selectedItem => selectedItem.name === item));
const handleBulkSelect = (value: BulkSelectValue) => {
value === BulkSelectValue.none && setSelected([]);
@@ -20,19 +21,20 @@ const BulkSelectTestComponent = ({ canSelectAll }: Omit 0 && selected.length <= 5}
- pagePartiallySelected={selected.length > 0 && selected.length < 5}
+ pageSelected={pageSelected}
+ pagePartiallySelected={pageDataNames.some(item => selected.find(selectedItem => selectedItem.name === item)) && !pageSelected}
onSelect={handleBulkSelect}
/>
);
};
describe('BulkSelect', () => {
- it('renders the bulk select', () => {
+ it('renders the bulk select without all', () => {
cy.mount(
);
@@ -45,14 +47,14 @@ describe('BulkSelect', () => {
cy.contains('0 selected').should('not.exist');
});
- it('renders the bulk select without all', () => {
+ it('renders the bulk select with all and without page', () => {
cy.mount(
-
+
);
cy.get('[data-ouia-component-id="BulkSelect-checkbox"]').should('exist');
cy.get('[data-ouia-component-id="BulkSelect-toggle"]').click();
cy.get('[data-ouia-component-id="BulkSelect-select-all"]').should('exist');
- cy.get('[data-ouia-component-id="BulkSelect-select-page"]').should('exist');
+ cy.get('[data-ouia-component-id="BulkSelect-select-page"]').should('not.exist');
cy.get('[data-ouia-component-id="BulkSelect-select-none"]').should('exist');
cy.contains('0 selected').should('not.exist');
@@ -76,7 +78,7 @@ describe('BulkSelect', () => {
// Select none
cy.get('[data-ouia-component-id="BulkSelect-toggle"]').first().click({ force: true });
cy.get('[data-ouia-component-id="BulkSelect-select-none"]').first().click();
- cy.contains('0 selected').should('not.exist');
+ cy.get('input[type="checkbox"]').should('not.be.checked');
// Select all
cy.get('[data-ouia-component-id="BulkSelect-toggle"]').first().click({ force: true });
From 68a6579556af6c20ab8846948eb72f38d8054778 Mon Sep 17 00:00:00 2001
From: Filip Hlavac
Date: Mon, 10 Jun 2024 12:25:24 +0200
Subject: [PATCH 5/7] Add menuToggleCheckboxProps and configurable ID
---
packages/module/src/BulkSelect/BulkSelect.tsx | 86 ++++++++++++++-----
.../__snapshots__/BulkSelect.test.tsx.snap | 10 +--
2 files changed, 67 insertions(+), 29 deletions(-)
diff --git a/packages/module/src/BulkSelect/BulkSelect.tsx b/packages/module/src/BulkSelect/BulkSelect.tsx
index fa00c56a..2611701d 100644
--- a/packages/module/src/BulkSelect/BulkSelect.tsx
+++ b/packages/module/src/BulkSelect/BulkSelect.tsx
@@ -1,5 +1,15 @@
import React, { useMemo, useState } from 'react';
-import { Dropdown, DropdownItem, DropdownList, DropdownProps, MenuToggle, MenuToggleCheckbox, MenuToggleElement, Text } from '@patternfly/react-core';
+import {
+ Dropdown,
+ DropdownItem,
+ DropdownList,
+ DropdownProps,
+ MenuToggle,
+ MenuToggleCheckbox,
+ MenuToggleCheckboxProps,
+ MenuToggleElement,
+ Text
+} from '@patternfly/react-core';
export const BulkSelectValue = {
all: 'all',
@@ -7,8 +17,8 @@ export const BulkSelectValue = {
page: 'page',
nonePage: 'nonePage'
} as const;
-
-export type BulkSelectValue = typeof BulkSelectValue[keyof typeof BulkSelectValue];
+
+export type BulkSelectValue = typeof BulkSelectValue[keyof typeof BulkSelectValue];
export interface BulkSelectProps extends Omit {
/** BulkSelect className */
@@ -31,23 +41,44 @@ export interface BulkSelectProps extends Omit void;
/** Custom OUIA ID */
ouiaId?: string;
+ /** Additional props for MenuToggleCheckbox */
+ menuToggleCheckboxProps?: Omit;
}
-export const BulkSelect: React.FC = ({ isDataPaginated = true, canSelectAll, pageSelected, pagePartiallySelected, pageCount, selectedCount = 0, totalCount, ouiaId = 'BulkSelect', onSelect, ...props }: BulkSelectProps) => {
+export const BulkSelect: React.FC = ({
+ isDataPaginated = true,
+ canSelectAll,
+ pageSelected,
+ pagePartiallySelected,
+ pageCount,
+ selectedCount = 0,
+ totalCount,
+ ouiaId = 'BulkSelect',
+ onSelect,
+ menuToggleCheckboxProps,
+ ...props
+}: BulkSelectProps) => {
const [ isOpen, setOpen ] = useState(false);
- const splitButtonDropdownItems = useMemo(() =>
- <>
-
- Select none (0)
-
- {isDataPaginated &&
- {`Select page${pageCount ? ` (${pageCount})` : ''}`}
- }
- {canSelectAll &&
- {`Select all${totalCount ? ` (${totalCount})` : ''}`}
- }
- >, [ isDataPaginated, canSelectAll, ouiaId, pageCount, totalCount ]
+ const splitButtonDropdownItems = useMemo(
+ () => (
+ <>
+
+ Select none (0)
+
+ {isDataPaginated && (
+
+ {`Select page${pageCount ? ` (${pageCount})` : ''}`}
+
+ )}
+ {canSelectAll && (
+
+ {`Select all${totalCount ? ` (${totalCount})` : ''}`}
+
+ )}
+ >
+ ),
+ [ isDataPaginated, canSelectAll, ouiaId, pageCount, totalCount ]
);
const allOption = isDataPaginated ? BulkSelectValue.page : BulkSelectValue.all;
@@ -73,13 +104,23 @@ export const BulkSelect: React.FC = ({ isDataPaginated = true,
items: [
0 ? null : pageSelected || selectedCount === totalCount}
- onChange={(checked) => onSelect?.(!checked || (checked === null) ? noneOption : allOption)}
+ isChecked={
+ (isDataPaginated && pagePartiallySelected) ||
+ (!isDataPaginated && selectedCount > 0)
+ ? null
+ : pageSelected || selectedCount === totalCount
+ }
+ onChange={(checked) => onSelect?.(!checked || checked === null ? noneOption : allOption)}
+ {...menuToggleCheckboxProps}
/>,
- selectedCount > 0 ? {`${selectedCount} selected`} : null
+ selectedCount > 0 ? (
+
+ {`${selectedCount} selected`}
+
+ ) : null
]
}}
/>
@@ -88,8 +129,7 @@ export const BulkSelect: React.FC = ({ isDataPaginated = true,
>
{splitButtonDropdownItems}
- );}
+ );
+};
export default BulkSelect;
-
-
diff --git a/packages/module/src/BulkSelect/__snapshots__/BulkSelect.test.tsx.snap b/packages/module/src/BulkSelect/__snapshots__/BulkSelect.test.tsx.snap
index 92c481c7..6ea114cf 100644
--- a/packages/module/src/BulkSelect/__snapshots__/BulkSelect.test.tsx.snap
+++ b/packages/module/src/BulkSelect/__snapshots__/BulkSelect.test.tsx.snap
@@ -10,7 +10,7 @@ exports[`BulkSelect component should render 1`] = `
>
@@ -30,7 +30,6 @@ exports[`BulkSelect component should render 1`] = `
data-ouia-safe="true"
data-pf-content="true"
>
-
2 selected