Skip to content

Commit

Permalink
Fixed parent row showing indeterminate checkboxes when all children a…
Browse files Browse the repository at this point in the history
…re selected (#2389)

Co-authored-by: Rohan <[email protected]>
  • Loading branch information
smmr-dn and r100-stack authored Jan 13, 2025
1 parent 9184ccd commit 156e489
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/polite-camels-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@itwin/itwinui-react': patch
---

Fixed bug in the `Table` where parent rows showing indeterminate checkboxes when all sub-rows are selected.
27 changes: 27 additions & 0 deletions packages/itwinui-react/src/core/Table/Table.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2217,6 +2217,33 @@ it('should handle sub-rows selection', async () => {
);
});

it('should show parent row being selected when all sub-rows are selected', async () => {
const data = mockedSubRowsData();
const { container } = renderComponent({
data,
isSelectable: true,
});

const rows = container.querySelectorAll('.iui-table-body .iui-table-row');
expect(rows.length).toBe(3);

await expandAll(container);

let checkboxes = container.querySelectorAll<HTMLInputElement>(
'.iui-table-body .iui-checkbox',
);
expect(checkboxes.length).toBe(10);
// Select all sub-rows of row 2
await userEvent.click(checkboxes[7]);
await userEvent.click(checkboxes[8]);

checkboxes = container.querySelectorAll<HTMLInputElement>(
'.iui-table-body .iui-checkbox',
);

expect(checkboxes[6].checked).toBe(true);
});

it('should show indeterminate checkbox when some sub-rows are selected', async () => {
const onSelect = vi.fn();
const data = mockedSubRowsData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,14 @@ const onSelectHandler = <T extends Record<string, unknown>>(
return false;
}

// In case when sub-rows are not present but sub-components are,
// the length of sub-rows for each row is 1 (because a sub-component is a sub-row).
// Therefore, we also need to check for sub-components whenever checking for sub-rows.
const hasSubComponents = !!row.initialSubRows[0]?.original[iuiId as any];
const hasSubRows = row.subRows.length > 0 && !hasSubComponents;
let isAllSubSelected = true;
if (row.initialSubRows[0]?.original[iuiId as any] === undefined) {

if (hasSubRows) {
row.initialSubRows.forEach((subRow) => {
const result = handleRow(subRow);
if (!result) {
Expand All @@ -48,18 +54,21 @@ const onSelectHandler = <T extends Record<string, unknown>>(
});
}

// A row is considered selected if it is selected AND one of the following:
// - `selectSubRows` is false, OR
// - the row has no sub-rows, OR
// - the row has sub-rows and all of them are selected
if (
newState.selectedRowIds[row.id] &&
(!instance.selectSubRows ||
!row.initialSubRows.length ||
isAllSubSelected)
) {
// A row is considered selected if it satisfies one of the following:
// - Case 1: If the row is directly selected, AND one of the following:
// + `selectSubRows` is false, OR
// + the row has no sub-rows.
// - Case 2: If the row is not directly selected,
// check if it has sub-rows and all of them are selected.

const isRowSelected = newState.selectedRowIds[row.id];
const case1 = isRowSelected && (!instance.selectSubRows || !hasSubRows);
const case2 = hasSubRows && isAllSubSelected;

if (case1 || case2) {
newSelectedRowIds[row.id as IdType<T>] = true;
}

return !!newSelectedRowIds[row.id];
};
instance.initialRows.forEach((row) => handleRow(row));
Expand Down

0 comments on commit 156e489

Please sign in to comment.