Skip to content

Commit f92c9cb

Browse files
fix(component): [worksheet] prevent paste into disabled parent rows (#1846)
* fix(component): [worksheet] prevent paste into disabled parent rows The paste handler was using `cell.rowIndex + 1` to check against `disabledRows`, but `disabledRows` contains row IDs, not 1-based indices. This meant paste was never blocked on disabled rows unless IDs happened to be sequential numbers. Also, `setSelectedCells` was called before any disabled check, visually updating the cell value. Fix uses `rows[cell.rowIndex]?.id` to compare against `disabledRows` and adds the disabled row check before `setSelectedCells` runs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(component): [worksheet] fix lint errors in useCopyPaste Remove unnecessary non-null assertion and fix prettier formatting in the disabled rows filter callback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(component): [worksheet] remove unnecessary istanbul ignore comment Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test(component): [worksheet] add tests for paste into disabled rows Add two tests to the 'disable rows' describe block: - Verify paste does not modify a disabled parent row - Verify paste still works on non-disabled rows when disabledRows is set Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1a80ed7 commit f92c9cb

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

packages/big-design/src/components/Worksheet/hooks/useCopyPaste/useCopyPaste.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,20 @@ export const useCopyPasteHandler = () => {
121121
if (
122122
copiedCells[0] &&
123123
selectedCells[0] &&
124+
columns[selectedCells[0].columnIndex] &&
125+
!disabledRows.includes(rows[selectedCells[0].rowIndex]?.id) &&
124126
isPasteAllowed(copiedCells[0], selectedCells[0], columns[selectedCells[0].columnIndex])
125127
) {
126128
setSelectedCells([{ ...selectedCells[0], value: copiedCells[0].value }]);
127129

128130
updateItems(
129-
cellsToUpdate.filter((cell) => !disabledRows.includes(cell.rowIndex + 1)),
131+
cellsToUpdate.filter((cell) => !disabledRows.includes(rows[cell.rowIndex]?.id)),
130132
copiedCells
131-
.filter((_, idx) => !disabledRows.includes(cellsToUpdate[idx]?.rowIndex + 1))
133+
.filter((_, idx) => {
134+
const cell = cellsToUpdate[idx];
135+
136+
return cell ? !disabledRows.includes(rows[cell.rowIndex]?.id) : false;
137+
})
132138
.map((cell) => cell.value),
133139
);
134140
}
@@ -142,6 +148,7 @@ export const useCopyPasteHandler = () => {
142148
cellsToUpdate,
143149
disabledRows,
144150
columns,
151+
rows,
145152
],
146153
);
147154

packages/big-design/src/components/Worksheet/spec.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,62 @@ describe('disable rows', () => {
15731573

15741574
expect(screen.getByDisplayValue('test test test')).toBeInTheDocument();
15751575
});
1576+
1577+
test('paste does not modify disabled row', async () => {
1578+
render(
1579+
<Worksheet columns={columns} disabledRows={[3]} items={items} onChange={handleChange} />,
1580+
);
1581+
1582+
const sourceCell = await screen.findByText('Shoes Name Three');
1583+
1584+
if (sourceCell.parentElement) {
1585+
await userEvent.click(sourceCell.parentElement);
1586+
}
1587+
1588+
await userEvent.keyboard('{Meta>}{c}{/Meta}');
1589+
1590+
const targetCell = await screen.findByText('Shoes Name One');
1591+
1592+
if (targetCell.parentElement) {
1593+
await userEvent.click(targetCell.parentElement);
1594+
}
1595+
1596+
await userEvent.keyboard('{Meta>}{v}{/Meta}');
1597+
1598+
expect(handleChange).not.toHaveBeenCalled();
1599+
});
1600+
1601+
test('paste works on non-disabled rows when some rows are disabled', async () => {
1602+
render(
1603+
<Worksheet columns={columns} disabledRows={[1]} items={items} onChange={handleChange} />,
1604+
);
1605+
1606+
const sourceCell = await screen.findByText('Shoes Name Three');
1607+
1608+
if (sourceCell.parentElement) {
1609+
await userEvent.click(sourceCell.parentElement);
1610+
}
1611+
1612+
await userEvent.keyboard('{Meta>}{c}{/Meta}');
1613+
1614+
const targetCell = await screen.findByText('Shoes Name One');
1615+
1616+
if (targetCell.parentElement) {
1617+
await userEvent.click(targetCell.parentElement);
1618+
}
1619+
1620+
await userEvent.keyboard('{Meta>}{v}{/Meta}');
1621+
1622+
expect(handleChange).toHaveBeenCalledWith([
1623+
{
1624+
id: 3,
1625+
numberField: 50,
1626+
otherField2: 3,
1627+
productName: 'Shoes Name Three',
1628+
visibleOnStorefront: false,
1629+
},
1630+
]);
1631+
});
15761632
});
15771633

15781634
describe('expandable', () => {

0 commit comments

Comments
 (0)