Skip to content

DataMapper: Enable DnD on abstract wrapper field #3168

@igarashitm

Description

@igarashitm

Please describe the task that needs to be done

Goal: Enable drag-and-drop on unselected abstract wrapper fields, providing the same conditional mapping UX as choice wrappers.

Currently, unselected abstract wrappers are not draggable. Choice wrappers already support dragging to auto-generate choose/when/otherwise conditional mappings. Abstract wrappers should behave the same way, since both use the same WrapperSpec / doGenerateNodeDataFromWrapperField() infrastructure and serve the same purpose — selecting one of several candidates.

Related:


Changes

1. Make unselected abstract wrappers draggable

MappingValidationService.isDraggable() returns false for unselected abstract wrappers (AbstractFieldNodeData with !node.abstractField). Remove this block so they are draggable, matching choice wrapper behavior.

2. Add validation for unselected abstract source

Add validation in validateMappingPair() for unselected abstract source, parallel to the existing choice source validation. Unselected abstract wrapper must be dropped onto a target field to create a conditional mapping — other drop targets should show an error message.

3. Add conditional mapping generation

Add abstract wrapper handling in engageMapping(). Generalize createChooseFromChoice() to handle both wrapperKind values, or create a parallel method. Dragging an unselected abstract wrapper onto a target field auto-generates choose/when/otherwise with one when branch per substitution candidate.


DnD scenarios

Source side: dragging an abstract wrapper

# Source Target Expected Behavior Notes
S0 Abstract wrapper (non-collection) Any field choose/when/otherwise Same as non-collection choice
S1 Abstract wrapper (collection) Non-collection field choose/when/otherwise only "Only source is collection → regular mapping" rule
S2 Abstract wrapper (collection) Collection field for-each wrapping choose/when/otherwise Both collections → auto for-each + conditional

Target side

Dropping onto an abstract wrapper always errors out ("Cannot map to an unselected abstract element") — existing validation, no change needed.

Decision flow

Source abstract wrapper → Target field
  │
  ├─ Is source a collection AND target a collection?
  │   NO  → choose/when/otherwise only (S0/S1)
  │   YES ↓
  │
  ├─ canUseCopyOf(abstractField, targetField)
  │   → always false (wrapper never FQN-matches a real field)
  │
  └─ Create ForEachItem, then choose/when/otherwise inside it (S2)

Member-level collection inheritance (parallel to #3167)

Members inside a collection abstract wrapper inherit the repeating nature from the wrapper, the same as collection choice members.

# Source Target Expected Behavior
S3 Abstract member Non-collection field Regular value-of (many-to-one)
S4 Abstract member Collection field Collection-to-collection rules (copy-of / for-each)
T3 Collection field Abstract member Collection-to-collection rules

This affects:

  • Layer icon: members of a collection abstract wrapper should display the collection layer icon
  • For-each availability: "Wrap with for-each" should be available for these members
  • DocumentService.isCollectionField() needs the same enhancement as xs:choice: Members of collection choice inherit collection #3167 (check parent wrapper's maxOccurs)

Note: The isCollectionField() enhancement from #3167 should naturally cover both wrapperKind: 'choice' and wrapperKind: 'abstract' since both use the same wrapper pattern. Coordinate implementation to handle both in one change.


Verification

  • Unselected abstract wrapper is draggable
  • S0: Non-collection abstract wrapper → target creates choose/when/otherwise
  • S1: Collection abstract wrapper → non-collection target creates choose/when/otherwise
  • S2: Collection abstract wrapper → collection target creates for-each wrapping choose/when/otherwise
  • S3/S4: Abstract members show layer icon when wrapper is a collection
  • T3: Collection source → abstract member follows collection rules
  • Target wrapper still blocked by validation (no regression)
  • XSLT generation correct for nested structures
  • Existing abstract field tests still pass

Implementation note

Since abstract and choice use the same WrapperSpec / doGenerateNodeDataFromWrapperField() infrastructure, several changes can be shared:

  • createChooseFromChoice() → generalized to createChooseFromWrapper() for both wrapper kinds
  • Wrapper DnD engagement in engageMapping(): one code path for both ChoiceFieldNodeData and AbstractFieldNodeData
  • isCollectionField() enhancement: one check for both wrapperKind values

Metadata

Metadata

Assignees

No one assigned

    Labels

    DataMapperAll issues related to the DataMapperenhancementNew feature or requestnever-staleMarks an issue to stay always open and not stale.ui/uxThis issue is about improving the UI / UX

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions