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]

Reply via email to