Please describe the task that needs to be done
Description
Problem
MappingLinksService.extractMappingLinks() performs a full mapping tree traversal on every render cycle triggered by MappingLinksProvider. Each invocation:
- Recursively walks the entire mapping tree
- Parses every XPath expression via
XPathService.extractFieldPaths()
- Resolves each extracted field path to an
IField via DocumentService.getFieldFromPathSegments()
- Computes visual NodePaths (inserting choice wrapper segments) for both source and target sides
This runs whenever any of these dependencies change:
mappingTree (object reference)
selectedNodePath (user clicks a node)
sourceParameterMap / sourceBodyDocument
In practice, even a simple node selection triggers the full extraction pipeline, including XPath parsing and field resolution that haven't changed since the last XPath edit.
Proposed Solution
Introduce a reactive NodePath index — a cache layer between the mapping model and the visualization — that separates what the mapping links are from how they're rendered:
-
NodePath index: A derived data structure that maps each IExpressionHolder to its resolved source NodePaths and target NodePath. Rebuilt only when XPath expressions or document structure actually change — not on selection or scroll.
-
Rendering stays lightweight: MappingLinksProvider reads from the pre-built index and only applies per-render concerns (selection highlighting, coordinate resolution via getNearestVisiblePort()).
-
Model stays clean: The index lives outside IExpressionHolder and the mapping model — it's a derived/computed cache, not a model extension. This avoids leaking visualization concerns into the mapping data.
Key Design Constraints
- The index must invalidate when:
- An XPath expression changes (user edits in
XPathInputAction)
- A mapping item is added, removed, or restructured
- Source/target document structure changes
- The index must not invalidate on:
- Node selection changes
- Scroll / viewport changes
- Visual collapse/expand of tree nodes
- Keep
IExpressionHolder holding only expression: string — no NodePath data in the model
Where to Store the Cache — Extend DocumentTreeStore
DocumentTreeStore (store/document-tree.store.ts) already holds the visual state that determines what mapping lines are drawn and where:
- Connection ports (
nodesConnectionPorts) — where lines attach
- Expansion state — which lines are visible (collapsed nodes hide their descendant lines)
- Selection — which lines are highlighted
The NodePath index is the same category: what lines exist, derived from user-edited XPath expressions. All of these are user-action-driven state serving the same purpose — supporting mapping line rendering.
Adding the cache here follows the existing pattern (e.g. nodesConnectionPorts is set from outside the store via setNodesConnectionPorts()). The new state would be rebuilt when XPath expressions or document structure change, and consumed by MappingLinksProvider for rendering.
Relevant Files
| File |
Role |
packages/ui/src/store/document-tree.store.ts |
Zustand store for visual tree state — new home for the NodePath index |
packages/ui/src/services/visualization/mapping-links.service.ts |
Current full-recalc logic (extractMappingLinks, computeVisualSourceNodePath, computeVisualTargetNodePath) |
packages/ui/src/providers/data-mapping-links.provider.tsx |
React provider triggering recalc via useEffect |
packages/ui/src/models/datamapper/mapping.ts |
IExpressionHolder interface, mapping item types |
packages/ui/src/models/datamapper/visualization.ts |
IMappingLink interface consumed by rendering |
packages/ui/src/components/View/MappingLinkContainer.tsx |
Rendering layer consuming IMappingLink |
packages/ui/src/components/Document/actions/XPathInputAction.tsx |
XPath edit entry point |
Expected Benefit
- Node selection, scroll, and collapse/expand no longer trigger XPath parsing and field resolution
- Mapping line rendering becomes proportional to the number of visible links, not the total number of expressions
- Cleaner separation: model holds data, index derives visualization-ready paths, renderer draws lines
Please describe the task that needs to be done
Description
Problem
MappingLinksService.extractMappingLinks()performs a full mapping tree traversal on every render cycle triggered byMappingLinksProvider. Each invocation:XPathService.extractFieldPaths()IFieldviaDocumentService.getFieldFromPathSegments()This runs whenever any of these dependencies change:
mappingTree(object reference)selectedNodePath(user clicks a node)sourceParameterMap/sourceBodyDocumentIn practice, even a simple node selection triggers the full extraction pipeline, including XPath parsing and field resolution that haven't changed since the last XPath edit.
Proposed Solution
Introduce a reactive NodePath index — a cache layer between the mapping model and the visualization — that separates what the mapping links are from how they're rendered:
NodePath index: A derived data structure that maps each
IExpressionHolderto its resolved source NodePaths and target NodePath. Rebuilt only when XPath expressions or document structure actually change — not on selection or scroll.Rendering stays lightweight:
MappingLinksProviderreads from the pre-built index and only applies per-render concerns (selection highlighting, coordinate resolution viagetNearestVisiblePort()).Model stays clean: The index lives outside
IExpressionHolderand the mapping model — it's a derived/computed cache, not a model extension. This avoids leaking visualization concerns into the mapping data.Key Design Constraints
XPathInputAction)IExpressionHolderholding onlyexpression: string— no NodePath data in the modelWhere to Store the Cache — Extend
DocumentTreeStoreDocumentTreeStore(store/document-tree.store.ts) already holds the visual state that determines what mapping lines are drawn and where:nodesConnectionPorts) — where lines attachThe NodePath index is the same category: what lines exist, derived from user-edited XPath expressions. All of these are user-action-driven state serving the same purpose — supporting mapping line rendering.
Adding the cache here follows the existing pattern (e.g.
nodesConnectionPortsis set from outside the store viasetNodesConnectionPorts()). The new state would be rebuilt when XPath expressions or document structure change, and consumed byMappingLinksProviderfor rendering.Relevant Files
packages/ui/src/store/document-tree.store.tspackages/ui/src/services/visualization/mapping-links.service.tsextractMappingLinks,computeVisualSourceNodePath,computeVisualTargetNodePath)packages/ui/src/providers/data-mapping-links.provider.tsxuseEffectpackages/ui/src/models/datamapper/mapping.tsIExpressionHolderinterface, mapping item typespackages/ui/src/models/datamapper/visualization.tsIMappingLinkinterface consumed by renderingpackages/ui/src/components/View/MappingLinkContainer.tsxIMappingLinkpackages/ui/src/components/Document/actions/XPathInputAction.tsxExpected Benefit