[Studio UI] Implement batch edit for advanced many-to-many relation columns - #4041
[Studio UI] Implement batch edit for advanced many-to-many relation columns#4041idaiv wants to merge 7 commits into
Conversation
…olumns (#1053) When "Enable Batch Edit for Columns" is turned on in the class definition of advanced many-to-many relation fields, the relation grid now supports batch editing of custom columns and batch deletion. Features: - Row selection checkboxes in the relation grid (multi-select) - "Apply to all" / "Apply to selection" dropdown button in toolbar, matching the listing grid's UX pattern - Batch edit: opens a modal with column picker and value editors supporting text, number, bool, select, and multiselect column types - Batch delete: removes selected rows or all rows from the relation - Selection count indicator with checkbox to deselect all - Empty/clear button hidden when batch edit is active (replaced by the dropdown's Delete action) Applies to both advancedManyToManyRelation and advancedManyToManyObjectRelation field types. All shared components (ManyToManyRelation, ManyToManyRelationGrid, toolbar) only gain optional passthrough props that default to off — no behavior change for other relation types. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Verdict: Needs changes. The PR adds batch editing and deletion to both advanced many-to-many relation variants, but row targeting and multi-column updates are currently incorrect.
Changes:
- Adds selection-based batch actions to both advanced relation types.
- Adds a modal supporting several custom-column editors.
- Extends shared relation grid and toolbar components with optional passthrough props.
Review contract:
- Intent: Implement optional batch editing and deletion for advanced relation columns.
- Root cause/boundary: Correctly placed in relation components, but duplicated handlers and a non-atomic modal API cause defects.
- Call sites: Both advanced relation variants are covered; shared behavior remains opt-in.
- Compatibility: New shared props are optional, so no breaking API change was identified.
- Tests: No automated coverage was added for selection, filtering, duplicate assignments, or multi-column updates.
- Docs/changelog: None included; confirm release-note requirements.
- Key risks: Incorrect row identifiers, overwritten multi-column edits, inherited-field mutation, stale selections, and unconfirmed deletion.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
assets/js/src/core/modules/element/dynamic-types/definitions/objects/data-related/components/many-to-many-object-relation/many-to-many-object-relation.tsx |
Adds optional batch-selection passthrough props. |
assets/js/src/core/modules/element/dynamic-types/definitions/objects/data-related/components/advanced-many-to-many-relation/batch-edit/batch-edit-modal.tsx |
Adds the column-picker and value-editor modal. |
assets/js/src/core/modules/element/dynamic-types/definitions/objects/data-related/components/advanced-many-to-many-relation/batch-edit/batch-edit-action.tsx |
Adds batch action controls and deletion. |
assets/js/src/core/modules/element/dynamic-types/definitions/objects/data-related/components/advanced-many-to-many-relation/advanced-many-to-many-relation.tsx |
Integrates batch behavior for mixed relations. |
assets/js/src/core/modules/element/dynamic-types/definitions/objects/data-related/components/advanced-many-to-many-object-relation/advanced-many-to-many-object-relation.tsx |
Integrates batch behavior for object relations. |
assets/js/src/core/components/many-to-many-relation/many-to-many-relation.tsx |
Forwards selection state into the shared grid. |
assets/js/src/core/components/many-to-many-relation/grid.tsx |
Enables controlled multi-row selection. |
assets/js/src/core/components/many-to-many-relation/components/toolbar/toolbar.tsx |
Adds an extension point for toolbar actions. |
Suppressed comments (2)
assets/js/src/core/modules/element/dynamic-types/definitions/objects/data-related/components/advanced-many-to-many-relation/advanced-many-to-many-relation.tsx:74
- Selection is controlled but never cleared or pruned when
props.valuechanges. If a selected row is removed with its row action or the relation is reordered, the toolbar retains stale selection keys and subsequent batch actions can no-op or target a different row. Reset selection when the source value changes.
const [selectedRows, setSelectedRows] = useState<RowSelectionState>({})
assets/js/src/core/modules/element/dynamic-types/definitions/objects/data-related/components/advanced-many-to-many-object-relation/advanced-many-to-many-object-relation.tsx:68
- Selection is controlled but never cleared or pruned when
props.valuechanges. Removing or reordering a selected relation leaves stale keys in the toolbar, so later batch operations can no-op or affect a different row. Reset selection when the source value changes.
const [selectedRows, setSelectedRows] = useState<RowSelectionState>({})
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Fixes all issues flagged in PR #4041 review: HIGH: - Row selection keyed by element ID, not array index — shared hook resolves selected element IDs to value array positions via Set lookup - Multi-column batch apply only kept last column — onApply now receives all entries as a single array and applies them in one map pass - Delete without confirmation — added confirm dialog matching the existing relation clear UX MEDIUM: - Inherited fields now disable batch edit (added inherited check) - Text columns without explicit type no longer filtered out - Boolean entries initialize to false instead of undefined LOW: - Remove button in batch edit modal has accessible title - Extracted shared useBatchEditActions hook to deduplicate logic between both advanced relation variants Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… column picker panel Replaces the simple Modal+Select approach with the same UX pattern used by the listing grid's batch edit: - WindowModal instead of regular Modal (draggable, no mask) - Left panel with ColumnPicker tree for "Fields to add" (with header, collapse control, and search) - "+ Add a column" toggle button in footer to show/hide the panel - ModalTitle component for proper header styling Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rows were keyed by element id. With allowMultipleAssignments one element can occupy several rows, so the id is not unique: the grid emitted duplicate row ids, and resolving a selection by id matched every occurrence rather than the row the user ticked — batch edit and delete then hit the wrong rows. Rows are now keyed by originalIndex, the position in the unfiltered value that use-value stamps before search and column filters run, so a key identifies one occurrence and survives filtering. The relation grid's `value` prop is typed as the display value it has always been handed, which is what makes originalIndex available. Selection keys are therefore already positions, so the hook no longer maps ids and instead discards keys that fall outside the current value. Adds use-batch-edit-actions.test.ts covering the cases the review called out: editing and deleting the right occurrence of a duplicated element, out-of-range keys, multi-column updates landing in a single onChange, multiselect joining, apply-to-all, and selection being cleared so it cannot go stale. Also resolves the Sonar finding in the batch edit modal by using a default parameter instead of reassigning the type inside getDefaultValue. Refs #1053 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|



Summary
advancedManyToManyRelationandadvancedManyToManyObjectRelationTest plan
🤖 Generated with Claude Code