Skip to content

GraphSelectionModel: handle single-selection no-op when first selectable cell is already selected (addCells and setCells) #1056

Description

@coderabbitai

Summary

In GraphSelectionModel (single-selection mode), when the first selectable cell in the incoming list is already the currently selected cell, both addCells and setCells should be a no-op. Currently neither method short-circuits in this case:

  • addCellsfirstSelectable && !this.isSelected(firstSelectable) evaluates to false, so toAdd = [] but toRemove = this.cells is non-empty. changeSelection([], this.cells) fires, clearing the selection instead of doing nothing.
  • setCells – always passes [firstSelectable] into changeSelection, triggering a remove+re-add cycle even when the cell is already selected. The end state is correct, but a spurious UNDO/CHANGE event pair is emitted.

Any fix must be applied symmetrically to both methods to avoid API inconsistency.

Steps to reproduce

  1. Enable single-selection mode on a GraphSelectionModel.
  2. Select a cell via addCell or setCell.
  3. Call addCell or setCell again with the same cell.
  4. Observe: addCells clears the selection; setCells fires unnecessary events.

Expected behaviour

Both calls should be a no-op (selection unchanged, no events fired) when the first selectable candidate is already the selected cell.

Proposed fix sketch

// addCells – single-selection branch
const firstSelectable = this.getFirstSelectableCell(cells);
if (firstSelectable && this.isSelected(firstSelectable)) {
  return; // already the selected cell; no-op
}
this.changeSelection(firstSelectable ? [firstSelectable] : [], this.cells);
return;

// setCells – single-selection branch (symmetric guard)
const firstSelectable = this.getFirstSelectableCell(cells);
if (firstSelectable && this.isSelected(firstSelectable) && this.cells.length === 1) {
  return; // already the only selected cell; no-op
}
this.changeSelection(firstSelectable ? [firstSelectable] : [], this.cells);
return;

References

/cc @redfish4ktc

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions