From 708773f23606837f4d015aa2275c88e5a011d967 Mon Sep 17 00:00:00 2001 From: Rastislav Hepner Date: Mon, 20 Apr 2026 17:56:28 +0200 Subject: [PATCH 1/7] feat(BulkSelect): extend onSelect API with source param --- packages/module/src/BulkSelect/BulkSelect.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/module/src/BulkSelect/BulkSelect.tsx b/packages/module/src/BulkSelect/BulkSelect.tsx index fd702886..2e48e9ed 100644 --- a/packages/module/src/BulkSelect/BulkSelect.tsx +++ b/packages/module/src/BulkSelect/BulkSelect.tsx @@ -22,6 +22,8 @@ export const BulkSelectValue = { export type BulkSelectValue = (typeof BulkSelectValue)[keyof typeof BulkSelectValue]; +export type BulkSelectSource = 'dropdown' | 'checkbox'; + const defaultSelectPageLabel = (pageCount?: number) => `Select page${pageCount ? ` (${pageCount})` : ''}`; const defaultSelectAllLabel = (totalCount?: number) => `Select all${totalCount ? ` (${totalCount})` : ''}`; const defaultSelectedLabel = (selectedCount: number) => `${selectedCount} selected`; @@ -45,7 +47,7 @@ export interface BulkSelectProps extends Omit void; + onSelect: (value: BulkSelectValue, source?: BulkSelectSource) => void; /** Custom OUIA ID */ ouiaId?: string; /** Additional props for MenuToggleCheckbox */ @@ -124,7 +126,7 @@ export const BulkSelect: FC = ({ ouiaId={`${ouiaId}-dropdown`} onSelect={(_e, value) => { setOpen(!isOpen); - onSelect?.(value as BulkSelectValue); + onSelect?.(value as BulkSelectValue, 'dropdown'); }} isOpen={isOpen} onOpenChange={(isOpen: boolean) => setOpen(isOpen)} @@ -147,7 +149,7 @@ export const BulkSelect: FC = ({ ? null : pageSelected || (selectedCount === totalCount && totalCount > 0) } - onChange={(checked) => onSelect?.(!checked || checked === null ? noneOption : allOption)} + onChange={(checked) => onSelect?.(!checked || checked === null ? noneOption : allOption, 'checkbox')} {...menuToggleCheckboxProps} > {selectedCount > 0 ? ( From 4318f77fabebddfa24f450efb49ceaf15fd01d68 Mon Sep 17 00:00:00 2001 From: Rastislav Hepner Date: Mon, 20 Apr 2026 18:26:07 +0200 Subject: [PATCH 2/7] test(BulkSelect): add unit tests for source Assisted-by: Cursor --- .../module/src/BulkSelect/BulkSelect.test.tsx | 82 ++++++++++++++++--- 1 file changed, 70 insertions(+), 12 deletions(-) diff --git a/packages/module/src/BulkSelect/BulkSelect.test.tsx b/packages/module/src/BulkSelect/BulkSelect.test.tsx index b7963fa8..865fdaed 100644 --- a/packages/module/src/BulkSelect/BulkSelect.test.tsx +++ b/packages/module/src/BulkSelect/BulkSelect.test.tsx @@ -1,19 +1,22 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import BulkSelect from './BulkSelect'; +import BulkSelect, { BulkSelectValue } from './BulkSelect'; describe('BulkSelect component', () => { test('should render', () => { - expect(render( - null} - />)).toMatchSnapshot(); + expect( + render( + null} + /> + ) + ).toMatchSnapshot(); }); test('should render with dropdownListProps', async () => { @@ -121,6 +124,7 @@ describe('BulkSelect component', () => { test('should enable Select none when at least one row is selected', async () => { const user = userEvent.setup(); + render( { await user.click(screen.getByLabelText('Bulk select toggle')); expect(screen.getByRole('menuitem', { name: 'Select none (0)' })).not.toBeDisabled(); }); -}); \ No newline at end of file + + test('should call onSelect with source "dropdown" when choosing menu items', async () => { + const user = userEvent.setup(); + const onSelect = jest.fn(); + + render( + + ); + + const openMenu = async () => { + await user.click(screen.getByLabelText('Bulk select toggle')); + }; + + await openMenu(); + await user.click(screen.getByRole('menuitem', { name: 'Select none (0)' })); + expect(onSelect).toHaveBeenLastCalledWith(BulkSelectValue.none, 'dropdown'); + + onSelect.mockClear(); + await openMenu(); + await user.click(screen.getByRole('menuitem', { name: 'Select page (5)' })); + expect(onSelect).toHaveBeenLastCalledWith(BulkSelectValue.page, 'dropdown'); + + onSelect.mockClear(); + await openMenu(); + await user.click(screen.getByRole('menuitem', { name: 'Select all (10)' })); + expect(onSelect).toHaveBeenLastCalledWith(BulkSelectValue.all, 'dropdown'); + }); + + test('should call onSelect with source "checkbox" when using split checkbox', async () => { + const user = userEvent.setup(); + const onSelect = jest.fn(); + render( + + ); + + await user.click(screen.getByRole('checkbox', { name: 'Select page' })); + expect(onSelect).toHaveBeenCalledWith(BulkSelectValue.page, 'checkbox'); + }); +}); From 99e31e49e0e363c5e50f5d17ed1ade774ccd28c7 Mon Sep 17 00:00:00 2001 From: Rastislav Hepner <15527036+raswonders@users.noreply.github.com> Date: Wed, 29 Apr 2026 17:26:57 +0200 Subject: [PATCH 3/7] refactor: define BulkSelectSource as a value Co-authored-by: Karel Hala --- packages/module/src/BulkSelect/BulkSelect.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/module/src/BulkSelect/BulkSelect.tsx b/packages/module/src/BulkSelect/BulkSelect.tsx index 2e48e9ed..e23c7834 100644 --- a/packages/module/src/BulkSelect/BulkSelect.tsx +++ b/packages/module/src/BulkSelect/BulkSelect.tsx @@ -22,8 +22,10 @@ export const BulkSelectValue = { export type BulkSelectValue = (typeof BulkSelectValue)[keyof typeof BulkSelectValue]; -export type BulkSelectSource = 'dropdown' | 'checkbox'; - +export const BulkSelectSource = { + dropdown: 'dropdown', + checkbox: 'checkbox' + } as const; const defaultSelectPageLabel = (pageCount?: number) => `Select page${pageCount ? ` (${pageCount})` : ''}`; const defaultSelectAllLabel = (totalCount?: number) => `Select all${totalCount ? ` (${totalCount})` : ''}`; const defaultSelectedLabel = (selectedCount: number) => `${selectedCount} selected`; From 00ef0b34d572c4fc07eeb9d907f4bf9d5dbc117f Mon Sep 17 00:00:00 2001 From: Rastislav Hepner <15527036+raswonders@users.noreply.github.com> Date: Wed, 29 Apr 2026 17:27:53 +0200 Subject: [PATCH 4/7] refactor: use BulkSelectSource.dropdown instead of literal Co-authored-by: Karel Hala --- packages/module/src/BulkSelect/BulkSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/module/src/BulkSelect/BulkSelect.tsx b/packages/module/src/BulkSelect/BulkSelect.tsx index e23c7834..367a21fd 100644 --- a/packages/module/src/BulkSelect/BulkSelect.tsx +++ b/packages/module/src/BulkSelect/BulkSelect.tsx @@ -128,7 +128,7 @@ export const BulkSelect: FC = ({ ouiaId={`${ouiaId}-dropdown`} onSelect={(_e, value) => { setOpen(!isOpen); - onSelect?.(value as BulkSelectValue, 'dropdown'); + onSelect?.(value as BulkSelectValue, BulkSelectSource.dropdown); }} isOpen={isOpen} onOpenChange={(isOpen: boolean) => setOpen(isOpen)} From fef7412dfcc02276bbbaefb8aa1abcbd9cfea759 Mon Sep 17 00:00:00 2001 From: Rastislav Hepner <15527036+raswonders@users.noreply.github.com> Date: Wed, 29 Apr 2026 17:28:19 +0200 Subject: [PATCH 5/7] refactor: use BulkSelectSource.checkbox instead of literal Co-authored-by: Karel Hala --- packages/module/src/BulkSelect/BulkSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/module/src/BulkSelect/BulkSelect.tsx b/packages/module/src/BulkSelect/BulkSelect.tsx index 367a21fd..f579c8f7 100644 --- a/packages/module/src/BulkSelect/BulkSelect.tsx +++ b/packages/module/src/BulkSelect/BulkSelect.tsx @@ -151,7 +151,7 @@ export const BulkSelect: FC = ({ ? null : pageSelected || (selectedCount === totalCount && totalCount > 0) } - onChange={(checked) => onSelect?.(!checked || checked === null ? noneOption : allOption, 'checkbox')} + onChange={(checked) => onSelect?.(!checked || checked === null ? noneOption : allOption, BulkSelectSource.checkbox)} {...menuToggleCheckboxProps} > {selectedCount > 0 ? ( From 5061bfa3968c80ff4a56bcabf290fe9e04aedfd1 Mon Sep 17 00:00:00 2001 From: Rastislav Hepner Date: Wed, 29 Apr 2026 18:17:25 +0200 Subject: [PATCH 6/7] refactor: add BulkSelectSource type --- packages/module/src/BulkSelect/BulkSelect.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/module/src/BulkSelect/BulkSelect.tsx b/packages/module/src/BulkSelect/BulkSelect.tsx index f579c8f7..5cfdcf2f 100644 --- a/packages/module/src/BulkSelect/BulkSelect.tsx +++ b/packages/module/src/BulkSelect/BulkSelect.tsx @@ -23,9 +23,12 @@ export const BulkSelectValue = { export type BulkSelectValue = (typeof BulkSelectValue)[keyof typeof BulkSelectValue]; export const BulkSelectSource = { - dropdown: 'dropdown', - checkbox: 'checkbox' - } as const; + dropdown: 'dropdown', + checkbox: 'checkbox' +} as const; + +export type BulkSelectSource = (typeof BulkSelectSource)[keyof typeof BulkSelectSource]; + const defaultSelectPageLabel = (pageCount?: number) => `Select page${pageCount ? ` (${pageCount})` : ''}`; const defaultSelectAllLabel = (totalCount?: number) => `Select all${totalCount ? ` (${totalCount})` : ''}`; const defaultSelectedLabel = (selectedCount: number) => `${selectedCount} selected`; @@ -123,7 +126,7 @@ export const BulkSelect: FC = ({ const onToggleClick = () => setOpen(!isOpen); return ( - ( { @@ -167,7 +170,7 @@ export const BulkSelect: FC = ({ {...props} > {splitButtonDropdownItems} - ) + ); }; From 15dc1e1e734a3d8fbb8e2f9e133390198bae2159 Mon Sep 17 00:00:00 2001 From: Rastislav Hepner Date: Wed, 29 Apr 2026 18:24:28 +0200 Subject: [PATCH 7/7] test: update BulkSelect unit tests --- packages/module/src/BulkSelect/BulkSelect.test.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/module/src/BulkSelect/BulkSelect.test.tsx b/packages/module/src/BulkSelect/BulkSelect.test.tsx index 865fdaed..9e2d65e2 100644 --- a/packages/module/src/BulkSelect/BulkSelect.test.tsx +++ b/packages/module/src/BulkSelect/BulkSelect.test.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import BulkSelect, { BulkSelectValue } from './BulkSelect'; +import BulkSelect, { BulkSelectSource, BulkSelectValue } from './BulkSelect'; describe('BulkSelect component', () => { test('should render', () => { @@ -141,7 +141,7 @@ describe('BulkSelect component', () => { expect(screen.getByRole('menuitem', { name: 'Select none (0)' })).not.toBeDisabled(); }); - test('should call onSelect with source "dropdown" when choosing menu items', async () => { + test(`should call onSelect with source ${BulkSelectSource.dropdown} when choosing menu items`, async () => { const user = userEvent.setup(); const onSelect = jest.fn(); @@ -163,20 +163,20 @@ describe('BulkSelect component', () => { await openMenu(); await user.click(screen.getByRole('menuitem', { name: 'Select none (0)' })); - expect(onSelect).toHaveBeenLastCalledWith(BulkSelectValue.none, 'dropdown'); + expect(onSelect).toHaveBeenLastCalledWith(BulkSelectValue.none, BulkSelectSource.dropdown); onSelect.mockClear(); await openMenu(); await user.click(screen.getByRole('menuitem', { name: 'Select page (5)' })); - expect(onSelect).toHaveBeenLastCalledWith(BulkSelectValue.page, 'dropdown'); + expect(onSelect).toHaveBeenLastCalledWith(BulkSelectValue.page, BulkSelectSource.dropdown); onSelect.mockClear(); await openMenu(); await user.click(screen.getByRole('menuitem', { name: 'Select all (10)' })); - expect(onSelect).toHaveBeenLastCalledWith(BulkSelectValue.all, 'dropdown'); + expect(onSelect).toHaveBeenLastCalledWith(BulkSelectValue.all, BulkSelectSource.dropdown); }); - test('should call onSelect with source "checkbox" when using split checkbox', async () => { + test(`should call onSelect with source ${BulkSelectSource.checkbox} when using split checkbox`, async () => { const user = userEvent.setup(); const onSelect = jest.fn(); render( @@ -192,6 +192,6 @@ describe('BulkSelect component', () => { ); await user.click(screen.getByRole('checkbox', { name: 'Select page' })); - expect(onSelect).toHaveBeenCalledWith(BulkSelectValue.page, 'checkbox'); + expect(onSelect).toHaveBeenCalledWith(BulkSelectValue.page, BulkSelectSource.checkbox); }); });