diff --git a/web/src/lib/core/Table/OTable.spec.ts b/web/src/lib/core/Table/OTable.spec.ts index 8e13306337..32552b9d3f 100644 --- a/web/src/lib/core/Table/OTable.spec.ts +++ b/web/src/lib/core/Table/OTable.spec.ts @@ -779,11 +779,56 @@ describe("OTable", () => { data: makeRows(5), columns: makeColumns(), selection: "multiple", + onRowClick: vi.fn(), }, }); - // The checkbox might be a nested component; trigger the row click - const row = wrapper.find('[data-test="o2-table-row-0"]'); - await row.trigger("click"); + await wrapper.find('[data-test="o2-table-select-0"] button').trigger("click"); + expect(wrapper.emitted("update:selectedIds")?.[0][0]).toEqual(["1"]); + expect(wrapper.emitted("row-click")).toBeFalsy(); + }); + + it("toggles selection without a row-click when the select cell padding is clicked", async () => { + wrapper = mount(OTable, { + props: { + data: makeRows(5), + columns: makeColumns(), + selection: "multiple", + onRowClick: vi.fn(), + }, + }); + const cell = wrapper.findAll('[data-test="o2-table-select-cell"]')[1]; + await cell.trigger("click"); + expect(wrapper.emitted("update:selectedIds")?.[0][0]).toEqual(["2"]); + await cell.trigger("click"); + expect(wrapper.emitted("update:selectedIds")?.[1][0]).toEqual([]); + expect(wrapper.emitted("row-click")).toBeFalsy(); + }); + + it("ignores select cell clicks on rows that are not selectable", async () => { + wrapper = mount(OTable, { + props: { + data: makeRows(3), + columns: makeColumns(), + selection: "multiple", + isRowSelectable: (row: TestRow) => row.id !== 1, + onRowClick: vi.fn(), + }, + }); + await wrapper.findAll('[data-test="o2-table-select-cell"]')[0].trigger("click"); + expect(wrapper.emitted("update:selectedIds")).toBeFalsy(); + expect(wrapper.emitted("row-click")).toBeFalsy(); + }); + + it("toggles all rows when the header select cell padding is clicked", async () => { + wrapper = mount(OTable, { + props: { + data: makeRows(3), + columns: makeColumns(), + selection: "multiple", + }, + }); + await wrapper.find('[data-test="o2-table-th-select"]').trigger("click"); + expect(wrapper.emitted("update:selectedIds")?.[0][0]).toEqual(["1", "2", "3"]); }); }); diff --git a/web/src/lib/core/Table/sub-components/OTableBodyRow.vue b/web/src/lib/core/Table/sub-components/OTableBodyRow.vue index f5087018df..d4237878b7 100644 --- a/web/src/lib/core/Table/sub-components/OTableBodyRow.vue +++ b/web/src/lib/core/Table/sub-components/OTableBodyRow.vue @@ -148,6 +148,12 @@ function onClick(event: MouseEvent) { emit("row-click", props.row.original, event); } +// Clicks on the checkbox itself are stopped by OCheckbox, so this only sees misses on the cell padding. +function onSelectCellClick() { + if (props.isRowSelectable && !props.isRowSelectable(props.row.original)) return; + emit("toggle-selection", props.row.original); +} + function onDblclick(event: MouseEvent) { emit("row-dblclick", props.row.original, event); } @@ -216,7 +222,7 @@ function onRowMouseleave() { :class="[ 'text-left align-middle', bordered ? 'border-table-row-divider border-b' : '', - isRowSelectable && !isRowSelectable(row.original) ? 'cursor-not-allowed' : '', + isRowSelectable && !isRowSelectable(row.original) ? 'cursor-not-allowed' : 'cursor-pointer', ]" :style="{ width: TABLE_CHECKBOX_COL_WIDTH + 'px', @@ -225,6 +231,7 @@ function onRowMouseleave() { paddingLeft: 'var(--spacing-table-edge)', }" data-test="o2-table-select-cell" + @click.stop="onSelectCellClick" >
void, ev if (event) toggleHandler?.(event); } +// Clicks on the checkbox itself are stopped by OCheckbox, so this only sees misses on the cell padding. +function onSelectAllCellClick() { + if (props.showSelectAll === false) return; + emit("toggle-all-rows"); +} + function handleDragStart(event: any) { emit("drag-start", event); } @@ -485,7 +491,10 @@ function getStandardStickyTotalStyle(header: any): Record { {