Skip to content

Conversation

@Abiola-Farounbi
Copy link

@Abiola-Farounbi Abiola-Farounbi commented Feb 8, 2026

Proposed Changes

These changes implement the following requirements for the Decision Service element:

  • Ability to configure a decision service with input and output decision nodes encapsulated within its structure
  • A new model element was added to the palette, featuring two stacked rectangles that can be resized
  • Ability to draw decision services over nodes in a DMN
  • Ability to drag decision nodes into compartments of a decision service from the DMN
  • Resizability of the decision service box and divider
  • Addition of decision services as a new element tag in the XML

Checklist

Ensure you provide everything we need to review your contribution:

Closes #957

@Abiola-Farounbi Abiola-Farounbi marked this pull request as draft February 8, 2026 00:26
@CLAassistant
Copy link

CLAassistant commented Feb 8, 2026

CLA assistant check
All committers have signed the CLA.

@Abiola-Farounbi Abiola-Farounbi marked this pull request as ready for review February 8, 2026 00:31
@Abiola-Farounbi Abiola-Farounbi changed the title feat(drd): Add Decision Services for DMN 1.5 Support #957 feat(drd): Add Decision Services for DMN 1.5 Support Feb 8, 2026
@barmac barmac requested a review from Copilot February 10, 2026 09:14
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces DMN 1.5 Decision Service support in the DRD modeler/viewer, adding the new element to creation tools, rendering, modeling behaviors, and XML/DI handling.

Changes:

  • Add Decision Service creation entry points (palette/context pad) plus label editing + variable name syncing support.
  • Introduce modeling behavior to manage DecisionService compartments (output/encapsulated) and auto-maintain input references.
  • Add rendering + DI factory support and extend test coverage with new fixtures/specs.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/dmn-js-shared/src/features/modeling/behavior/NameChangeBehavior.js Sync DecisionService variable name on label/property name changes.
packages/dmn-js-drd/test/spec/features/palette/PaletteProviderSpec.js Update palette entry count for new Decision Service tool.
packages/dmn-js-drd/test/spec/features/modeling/drd-updater-decision-service.dmn New DMN test diagram covering DecisionService + move-in/out behavior.
packages/dmn-js-drd/test/spec/features/modeling/behavior/decision-service-behavior.dmn New DMN test diagram for DecisionServiceBehavior scenarios.
packages/dmn-js-drd/test/spec/features/modeling/behavior/DecisionServiceBehaviorSpec.js New unit tests for DecisionServiceBehavior (sectioning, refs, inputs).
packages/dmn-js-drd/test/spec/features/modeling/ElementFactorySpec.js Add element factory tests for DecisionService defaults + variable creation.
packages/dmn-js-drd/test/spec/features/modeling/DrdUpdaterSpec.js Extend DrdUpdater tests for move behavior involving DecisionServices.
packages/dmn-js-drd/test/spec/features/modeling/DrdFactorySpec.js Add DI factory test for DMNDecisionServiceDividerLine creation.
packages/dmn-js-drd/test/spec/draw/DrdRendererSpec.js Add smoke test for rendering a DecisionService fixture.
packages/dmn-js-drd/test/fixtures/dmn/decision-service.dmn New rendering fixture containing a DecisionService + divider line.
packages/dmn-js-drd/src/features/rules/DrdRules.js Allow DecisionService create/move/resize and define connection rules.
packages/dmn-js-drd/src/features/palette/PaletteProvider.js Add palette entry to create Decision Service.
packages/dmn-js-drd/src/features/modeling/behavior/index.js Register DecisionServiceBehavior in modeling behaviors module.
packages/dmn-js-drd/src/features/modeling/behavior/DecisionServiceBehavior.js Implement DecisionService compartment logic + input ref auto-update.
packages/dmn-js-drd/src/features/modeling/behavior/CreateConnectionBehavior.js Extend connection ref creation logic for DecisionService-related connections.
packages/dmn-js-drd/src/features/modeling/ElementFactory.js Add DecisionService default sizing, DI divider line, and variable initialization.
packages/dmn-js-drd/src/features/modeling/DrdUpdater.js Update decision services on moves/deletes and on requirement changes.
packages/dmn-js-drd/src/features/modeling/DrdFactory.js Add helper to create DMNDecisionServiceDividerLine DI elements.
packages/dmn-js-drd/src/features/label-editing/LabelUtil.js Enable label editing for DecisionService (name attribute).
packages/dmn-js-drd/src/features/label-editing/LabelEditingProvider.js Adjust label editing positioning behavior for DecisionService.
packages/dmn-js-drd/src/features/context-pad/ContextPadProvider.js Enable context pad append actions for DecisionService.
packages/dmn-js-drd/src/draw/DrdRenderer.js Add visual rendering of DecisionService (box, divider, section labels).
packages/dmn-js-drd/assets/css/dmn-js-drd.css Add palette icon styling for Decision Service entry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +351 to +366
'dmn:DecisionService': function(p, element) {
var rect = drawRect(p, element.width, element.height, 12, {
stroke: getStrokeColor(element, defaultStrokeColor),
strokeWidth: 4,
fill: getFillColor(element, defaultFillColor)
});

var dividerY = element.height / 2;
var line = svgCreate('line');
svgAttr(line, {
x1: 0,
y1: dividerY,
x2: element.width,
y2: dividerY,
stroke: getStrokeColor(element, defaultStrokeColor),
strokeWidth: 2
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The divider line is rendered at element.height / 2, ignoring the imported/stored DI divider line (DMNDecisionServiceDividerLine). This will render DecisionServices incorrectly when the divider is not centered (e.g. after divider resize or when importing DI). Compute the divider position from element.businessObject.di.decisionServiceDividerLine.waypoint (convert absolute -> local coordinates), with a center fallback when DI is missing.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct, we should take the XML values into account.

Comment on lines +55 to +57
DecisionServiceBehavior.prototype._getDividerPosition = function(decisionServiceElement) {
return decisionServiceElement.y + (decisionServiceElement.height / 2);
};
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_getDividerPosition always assumes the divider is centered (height / 2). If the divider line can be moved/resized or if DI imports a non-centered divider, section classification (output vs encapsulated) will be wrong. Derive the divider Y from the DecisionService DI (decisionServiceBo.di.decisionServiceDividerLine.waypoint) and fall back to center only when it is not available.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +72
if (is(businessObject, 'dmn:DecisionService')) {
size = this._getDefaultSize(businessObject);
var dividerY = (attrs.y || 0) + (size.height / 2);
var dividerWaypoints = [
{ x: attrs.x || 0, y: dividerY },
{ x: (attrs.x || 0) + size.width, y: dividerY }
];
businessObject.di.decisionServiceDividerLine = drdFactory.createDiDividerLine(dividerWaypoints);

Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ElementFactory creates and stores decisionServiceDividerLine waypoints once at creation time, but there is no code updating these waypoints when the DecisionService is moved/resized (or when the divider is moved). This will cause exported DMN DI to become stale. Consider updating the divider line waypoints in DrdUpdater.updateBounds / relevant resize handlers whenever the DecisionService bounds (or divider position) changes.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +12
<di:waypoint x="0" y="75" />
<di:waypoint x="200" y="75" />
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DMNDecisionServiceDividerLine waypoints here (x=0..200, y=75) don't line up with the shape bounds (x=330, y=225, width=400, height=335). If divider line waypoints are in diagram coordinates (like other DMNDI waypoints), this fixture will import with an incorrect divider position. Align the divider waypoints with the shape bounds (or clarify/update if divider waypoints are meant to be local coordinates).

Suggested change
<di:waypoint x="0" y="75" />
<di:waypoint x="200" y="75" />
<di:waypoint x="330" y="300" />
<di:waypoint x="530" y="300" />

Copilot uses AI. Check for mistakes.
Comment on lines +110 to +113
if (is(target, 'dmn:DecisionService')) {
return { type: 'dmn:KnowledgeRequirement' };
}

Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canConnect allows Decision -> DecisionService and returns a dmn:KnowledgeRequirement (lines 100-112). However CreateConnectionBehavior determines the required* ref based on the source element type, so this path will create a KnowledgeRequirement with requiredDecision instead of requiredKnowledge. DrdImporter._getSource only looks at requiredKnowledge for KnowledgeRequirements, so the connection will not import/roundtrip correctly. Either disallow this connection type or ensure KnowledgeRequirement refs are always written to requiredKnowledge regardless of source element type.

Suggested change
if (is(target, 'dmn:DecisionService')) {
return { type: 'dmn:KnowledgeRequirement' };
}

Copilot uses AI. Check for mistakes.
barmac and others added 2 commits February 10, 2026 15:15
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
@barmac
Copy link
Member

barmac commented Feb 10, 2026

Thank you for your pull request! Before we merge it, let's make sure that it meets the definition of done.

It looks that the interaction is not quite there yet. We should render the decision service below other elements so that they don't get hidden. I'd also envision that the encapsulated & output decisions should move together with the decision service element. Let me know if anything is unclear.

Screen.Recording.2026-02-10.at.15.28.51.mov
Screen.Recording.2026-02-10.at.15.29.18.mov

@barmac barmac added needs review Review pending in progress Currently worked on and removed needs review Review pending labels Feb 10, 2026
@Abiola-Farounbi
Copy link
Author

Thank you for the feedback @barmac

For the first point, I have addressed the rendering issue by setting the DecisionService Element fill to transparent, which prevents contained decisions from being hidden. This works as expected and maintains visibility of all elements.
For the second point, I tested the interaction and found that the current implementation works as expected when a Decision element is dragged onto the DecisionService (rather than moving the DecisionService over existing Decisions). This was the initial assumption for the feature, as demonstrated in the demo below.

If the accurate interaction is for contained Decisions to move together with the DecisionService when the DecisionService is placed on it, could you recommend the best approach to implement this?
Demo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in progress Currently worked on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Addition of Decision Services for DMN 1.5 Support

3 participants