This is an automated email from the ASF dual-hosted git repository.
thiagoelg pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git
The following commit(s) were added to refs/heads/main by this push:
new b302cf7ac4c kie-issues#2356: BPMN Editor: Subprocess with an Error
Start Event causes BPMN code generation to fail (#3640)
b302cf7ac4c is described below
commit b302cf7ac4c327959c48ccf870001fa95b83ddbf
Author: SUNILathulya <[email protected]>
AuthorDate: Wed Jul 15 04:13:16 2026 +0530
kie-issues#2356: BPMN Editor: Subprocess with an Error Start Event causes
BPMN code generation to fail (#3640)
---
.../nodes/morphing/useEventNodeMorphingActions.tsx | 31 +++++++++++++---
packages/bpmn-editor/src/mutations/addEdge.ts | 41 ++++++++++++++++++----
.../src/mutations/moveNodesOutOfSubProcess.ts | 21 ++++++++---
.../tests-e2e/flowElements/addStartEvent.spec.ts | 21 +++++++++++
4 files changed, 98 insertions(+), 16 deletions(-)
diff --git
a/packages/bpmn-editor/src/diagram/nodes/morphing/useEventNodeMorphingActions.tsx
b/packages/bpmn-editor/src/diagram/nodes/morphing/useEventNodeMorphingActions.tsx
index 83f5243ff02..d5a4bce9a8c 100644
---
a/packages/bpmn-editor/src/diagram/nodes/morphing/useEventNodeMorphingActions.tsx
+++
b/packages/bpmn-editor/src/diagram/nodes/morphing/useEventNodeMorphingActions.tsx
@@ -30,6 +30,10 @@ import { BPMN20__tProcess } from
"@kie-tools/bpmn-marshaller/dist/schemas/bpmn-2
import { ElementFilter } from "@kie-tools/xml-parser-ts/dist/elementFilter";
import { NODE_COLORS } from "../NodeSvgs";
import { deleteEdge } from "../../../mutations/deleteEdge";
+import { addOrGetErrors } from "../../../mutations/addOrGetErrors";
+import { addOrGetSignals } from "../../../mutations/addOrGetSignals";
+import { addOrGetMessages } from "../../../mutations/addOrGetMessages";
+import { addOrGetEscalations } from "../../../mutations/addOrGetEscalations";
import { setBpmn20Drools10MetaData } from
"@kie-tools/bpmn-marshaller/dist/drools-extension-metaData";
export type Event = Normalized<
@@ -112,15 +116,25 @@ export function useEventNodeMorphingActions(event: Event)
{
};
break;
case "errorEventDefinition":
+ const { errorRef } = addOrGetErrors({
+ definitions: s.bpmn.model.definitions,
+ errorName: "Error_" + generateUuid().substring(0, 8),
+ });
element.eventDefinition[0] = {
"@_id": generateUuid(),
__$$element: "errorEventDefinition",
+ "@_errorRef": errorRef,
};
break;
case "escalationEventDefinition":
+ const { escalationRef } = addOrGetEscalations({
+ definitions: s.bpmn.model.definitions,
+ escalationName: "Escalation_" + generateUuid().substring(0,
8),
+ });
element.eventDefinition[0] = {
"@_id": generateUuid(),
__$$element: "escalationEventDefinition",
+ "@_escalationRef": escalationRef,
};
break;
case "linkEventDefinition":
@@ -131,15 +145,25 @@ export function useEventNodeMorphingActions(event: Event)
{
};
break;
case "messageEventDefinition":
+ const { messageRef } = addOrGetMessages({
+ definitions: s.bpmn.model.definitions,
+ messageName: "Message_" + generateUuid().substring(0, 8),
+ });
element.eventDefinition[0] = {
"@_id": generateUuid(),
__$$element: "messageEventDefinition",
+ "@_messageRef": messageRef,
};
break;
case "signalEventDefinition":
+ const { signalRef } = addOrGetSignals({
+ definitions: s.bpmn.model.definitions,
+ signalName: "Signal_" + generateUuid().substring(0, 8),
+ });
element.eventDefinition[0] = {
"@_id": generateUuid(),
__$$element: "signalEventDefinition",
+ "@_signalRef": signalRef,
};
// Add default extensionElements for intermediateThrowEvent
and endEvent
if (element.__$$element === "intermediateThrowEvent" ||
element.__$$element === "endEvent") {
@@ -159,11 +183,8 @@ export function useEventNodeMorphingActions(event: Event) {
};
break;
}
- element.eventDefinition[0] = {
- "@_id": generateUuid(),
- __$$element: eventDefinitionElement as any,
- };
- return true; // Will continue visiting.
+
+ return false; // Will stop visiting.
}
});
diff --git a/packages/bpmn-editor/src/mutations/addEdge.ts
b/packages/bpmn-editor/src/mutations/addEdge.ts
index 213ccfad102..383af245097 100644
--- a/packages/bpmn-editor/src/mutations/addEdge.ts
+++ b/packages/bpmn-editor/src/mutations/addEdge.ts
@@ -42,6 +42,28 @@ import { Unpacked } from
"@kie-tools/xyflow-react-kie-diagram/dist/tsExt/tsExt";
import { visitFlowElementsAndArtifacts } from "./_elementVisitor";
import { ElementFilter } from "@kie-tools/xml-parser-ts/dist/elementFilter";
+type ElementOwner = Normalized<
+ | ElementFilter<Unpacked<NonNullable<BPMN20__tDefinitions["rootElement"]>>,
"process">
+ | ElementFilter<
+ Unpacked<NonNullable<BPMN20__tProcess["flowElement"]>>,
+ "subProcess" | "adHocSubProcess" | "transaction"
+ >
+>;
+
+function findNodeContainer(definitions: Normalized<BPMN20__tDefinitions>,
nodeId: string): ElementOwner {
+ const { process } = addOrGetProcessAndDiagramElements({ definitions });
+ let container: ElementOwner = process;
+
+ visitFlowElementsAndArtifacts(process, ({ element, owner }) => {
+ if (element["@_id"] === nodeId) {
+ container = owner;
+ return false; // Stop visiting
+ }
+ });
+
+ return container;
+}
+
export function addEdge({
definitions,
__readonly_sourceNode,
@@ -87,14 +109,17 @@ export function addEdge({
let newEdgeId = generateUuid();
const { process, diagramElements } = addOrGetProcessAndDiagramElements({
definitions });
+ const parentContainer = findNodeContainer(definitions,
__readonly_sourceNode.href);
let existingEdgeId: string | undefined = undefined;
// Associations (incl. Compensation Associations)
if (__readonly_edge.type === EDGE_TYPES.association || __readonly_edge.type
=== EDGE_TYPES.compensationAssociation) {
- const targetArtifacts = __readonly_parentArtifacts ?? process.artifact ??
[];
- if (!process.artifact) {
- process.artifact = targetArtifacts;
+ parentContainer.artifact ??= [];
+
+ const targetArtifacts = __readonly_parentArtifacts ??
parentContainer.artifact ?? [];
+ if (!parentContainer.artifact) {
+ parentContainer.artifact = targetArtifacts;
}
const newAssociation: Normalized<BPMN20__tAssociation> = {
@@ -121,9 +146,11 @@ export function addEdge({
// Sequence Flows
else {
- const targetFlowElements = __readonly_parentFlowElements ??
process.flowElement ?? [];
- if (!process.flowElement) {
- process.flowElement = targetFlowElements;
+ parentContainer.flowElement ??= [];
+
+ const targetFlowElements = __readonly_parentFlowElements ??
parentContainer.flowElement ?? [];
+ if (!parentContainer.flowElement) {
+ parentContainer.flowElement = targetFlowElements;
}
const newSequenceFlow: Normalized<BPMN20__tSequenceFlow> = {
@@ -151,7 +178,7 @@ export function addEdge({
}
// <incoming> and <outgoing> elements of Flow Elements
- visitFlowElementsAndArtifacts(process, ({ element }) => {
+ visitFlowElementsAndArtifacts(parentContainer, ({ element }) => {
if (
element.__$$element !== "association" &&
element.__$$element !== "group" &&
diff --git a/packages/bpmn-editor/src/mutations/moveNodesOutOfSubProcess.ts
b/packages/bpmn-editor/src/mutations/moveNodesOutOfSubProcess.ts
index 75e3b312e1d..80f4eaac58c 100644
--- a/packages/bpmn-editor/src/mutations/moveNodesOutOfSubProcess.ts
+++ b/packages/bpmn-editor/src/mutations/moveNodesOutOfSubProcess.ts
@@ -197,17 +197,31 @@ export function moveNodesOutOfSubProcess({
}
}
- // BPMN 2.0 Spec: When moving Start Events from Event Sub-Process to top
level,
- // only convert event types that are NOT supported at top level
+ // BPMN 2.0 Spec: When moving Start Events out of an Event Sub-Process,
+ // only convert event types that are NOT supported by the target container.
+ // Event Sub-Processes allow: Message, Timer, Error, Escalation,
Compensation, Conditional, Signal
// Top-level allows: None, Message, Timer, Conditional, Signal
- // Top-level does NOT allow: Error, Escalation, Compensation, Link, Terminate
+ // Regular embedded Sub-Processes allow: None only
if (isEventSubProcess) {
+ const isTargetEventSubProcess =
+ targetSubProcess?.__$$element === "subProcess" &&
(targetSubProcess["@_triggeredByEvent"] ?? false);
+ const isMovingToTopLevel = __readonly_targetSubProcessId === null;
+
for (const flowElement of flowElementsToMove) {
if (
flowElement.__$$element === "startEvent" &&
flowElement.eventDefinition &&
flowElement.eventDefinition.length > 0
) {
+ if (!isMovingToTopLevel && isTargetEventSubProcess) {
+ continue;
+ }
+
+ if (!isMovingToTopLevel && __readonly_targetSubProcessId &&
!isTargetEventSubProcess) {
+ flowElement.eventDefinition = undefined;
+ continue;
+ }
+
const eventDefType = flowElement.eventDefinition[0].__$$element;
const unsupportedAtTopLevel =
eventDefType === "errorEventDefinition" ||
@@ -220,7 +234,6 @@ export function moveNodesOutOfSubProcess({
// Convert to "None" Start Event because this event type is not
allowed at top level
flowElement.eventDefinition = undefined;
}
- // Otherwise keep the event definition (Message, Timer, Conditional,
Signal are valid at top level)
}
}
}
diff --git a/packages/bpmn-editor/tests-e2e/flowElements/addStartEvent.spec.ts
b/packages/bpmn-editor/tests-e2e/flowElements/addStartEvent.spec.ts
index ac00bcacb95..58a45af413c 100644
--- a/packages/bpmn-editor/tests-e2e/flowElements/addStartEvent.spec.ts
+++ b/packages/bpmn-editor/tests-e2e/flowElements/addStartEvent.spec.ts
@@ -151,6 +151,27 @@ test.describe("Add node - Start Event", () => {
expect(subProcessStartEvent?.__$$element).toBe("startEvent");
expect(subProcessStartEvent?.eventDefinition).toMatchObject([{
__$$element: eventDefinition }]);
});
+
+ test(`should keep ${morphType} Start Event when moved within the same
Event Sub-Process`, async ({
+ jsonModel,
+ nodes,
+ }) => {
+ const startEvent = nodes.getByType(NodeType.START_EVENT);
+ await nodes.morph({ node: startEvent, to: morphType });
+
+ const startEventId = await nodes.getIdByType(NodeType.START_EVENT);
+ await nodes.dragNodeToPosition({
+ id: startEventId,
+ fromPosition: NodePosition.CENTER,
+ toPosition: { x: 200, y: 320 },
+ });
+
+ const subProcesses = await jsonModel.getSubProcesses();
+ expect(subProcesses.length).toBe(1);
+ const subProcessStartEvent = (await
jsonModel.getStartEvents(subProcesses[0].flowElement))[0];
+ expect(subProcessStartEvent?.__$$element).toBe("startEvent");
+ expect(subProcessStartEvent?.eventDefinition).toMatchObject([{
__$$element: eventDefinition }]);
+ });
}
});
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]