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": +
+
+ +

+ + 2 selected +

+ +
+
+ , + "container":
+
+ +

+ + 2 selected +

+ +
+
, + "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