Make selection dialog checkboxes select like a row click

GTable's row checkbox emits a "row-select" event, but SelectionDialog only
handled "row-click" — so toggling a checkbox was dropped. Clicking a folder's
checkbox did nothing (it reverted to its indeterminate/prior state) while
clicking the row selected the whole directory, an inconsistent, broken-looking
result. Forward "row-select" to the same "onClick" emit so a checkbox toggle
drives identical selection to a row click for both files and folders.
This commit is contained in:
Alireza Heidari
2026-07-22 18:58:51 +02:00
parent 83dcb747b8
commit 28af5a03ae
2 changed files with 45 additions and 1 deletions
@@ -87,4 +87,36 @@ describe("SelectionDialog.vue", () => {
expect(rowCheckbox.checked).toBe(false);
expect(rowCheckbox.indeterminate).toBe(true);
});
it("emits onClick for the row when its checkbox is toggled", async () => {
await wrapper.setProps({
optionsShow: true,
selectable: true,
items: [
{ id: "1", label: "folder1", isLeaf: false, selectionState: SELECTION_STATES.MIXED },
{ id: "2", label: "file2", isLeaf: true, selectionState: SELECTION_STATES.UNSELECTED },
],
});
const rowCheckbox = wrapper.find("tbody tr[aria-rowindex='1'] .g-table-select-column input");
await rowCheckbox.trigger("change");
expect(wrapper.emitted().onClick).toBeTruthy();
expect(wrapper.emitted().onClick[0][0].id).toBe("1");
});
it("emits onClick exactly once when a selectable row is clicked", async () => {
await wrapper.setProps({
optionsShow: true,
selectable: true,
items: [{ id: "1", label: "file1", isLeaf: true, selectionState: SELECTION_STATES.UNSELECTED }],
});
// GTable emits both "row-select" and "row-click" for a selectable row;
// SelectionDialog must not toggle selection twice.
await wrapper.find("tbody tr[aria-rowindex='1']").trigger("click");
expect(wrapper.emitted().onClick).toBeTruthy();
expect(wrapper.emitted().onClick.length).toBe(1);
});
});
@@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BAlert, BButton, BLink, BPagination } from "bootstrap-vue";
import { computed, ref, watch } from "vue";
import type { RowClickEvent, TableField } from "@/components/Common/GTable.types";
import type { RowClickEvent, RowSelectEvent, TableField } from "@/components/Common/GTable.types";
import { type ItemsProvider, SELECTION_STATES } from "@/components/SelectionDialog/selectionTypes";
import type Filtering from "@/utils/filtering";
@@ -160,6 +160,17 @@ function onSortChanged(newSortBy: string, newSortDesc: boolean) {
}
function onRowClick(event: RowClickEvent<SelectionItem>) {
// For a selectable table GTable also emits "row-select" on a row click
// (handled by onRowSelect), so emitting here too would toggle selection
// twice. Only emit for non-selectable dialogs.
if (!props.selectable) {
emit("onClick", event.item);
}
}
// Selection for a selectable table: a row click and a checkbox toggle both
// arrive here as a single "row-select", so the checkbox behaves like the row.
function onRowSelect(event: RowSelectEvent<SelectionItem>) {
emit("onClick", event.item);
}
@@ -307,6 +318,7 @@ defineExpose({
:selected-items="selectedItems"
:show-select-all="props.selectable"
@row-click="onRowClick"
@row-select="onRowSelect"
@select-all="onSelectAll"
@sort-changed="onSortChanged">
<template v-slot:cell(label)="data">