You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kie.apache.org by ti...@apache.org on 2024/09/30 17:15:08 UTC

(incubator-kie-tools) branch main updated: kie-issues#1298: Decision Services & multiple DRDs: make it possible o add external Decisions to a Decision Service (#2508)

This is an automated email from the ASF dual-hosted git repository.

tiagobento 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 e53f6b56e9b kie-issues#1298: Decision Services & multiple DRDs: make it possible o add external Decisions to a Decision Service (#2508)
e53f6b56e9b is described below

commit e53f6b56e9b78aa942951c0ee231579ed526f118
Author: Daniel José dos Santos <da...@users.noreply.github.com>
AuthorDate: Mon Sep 30 14:15:03 2024 -0300

    kie-issues#1298: Decision Services & multiple DRDs: make it possible o add external Decisions to a Decision Service (#2508)
    
    Co-authored-by: Tiago Bento <15...@users.noreply.github.com>
    Co-authored-by: Tiago Bento <ti...@gmail.com>
    Co-authored-by: Luiz João Motta <lm...@ibm.com>
---
 packages/dmn-editor-envelope/src/DmnEditorRoot.tsx | 230 ++++++++++++++++-----
 packages/dmn-editor/src/DmnEditor.tsx              |   4 +-
 .../dmn-editor/src/autolayout/AutolayoutButton.tsx |   5 +-
 .../src/boxedExpressions/BoxedExpressionScreen.tsx |   4 +-
 packages/dmn-editor/src/diagram/Diagram.tsx        |  42 ++--
 .../dmn-editor/src/diagram/DiagramCommands.tsx     |  49 +++--
 packages/dmn-editor/src/diagram/DrgNodesPanel.tsx  |   3 +-
 packages/dmn-editor/src/diagram/Palette.tsx        |  11 +-
 packages/dmn-editor/src/diagram/nodes/Nodes.tsx    |   2 +-
 .../src/externalNodes/DmnObjectListItem.tsx        | 136 +++++++++---
 .../src/externalNodes/ExternalNodesPanel.tsx       |   5 +-
 .../src/includedModels/IncludedModels.tsx          |   4 +-
 .../dmn-editor/src/mutations/addConnectedNode.ts   |   5 +-
 .../src/mutations/addDecisionToDecisionService.ts  |  49 ++++-
 packages/dmn-editor/src/mutations/addEdge.ts       |   9 +-
 .../mutations/addExistingDecisionServiceToDrd.ts   |  19 +-
 .../dmn-editor/src/mutations/addStandaloneNode.ts  |   5 +-
 .../src/mutations/applyAutoLayoutToDrd.ts          |   5 +-
 .../mutations/deleteDecisionFromDecisionService.ts |  44 +++-
 packages/dmn-editor/src/mutations/deleteEdge.ts    |   5 +-
 packages/dmn-editor/src/mutations/deleteImport.ts  |  11 +-
 packages/dmn-editor/src/mutations/deleteNode.ts    | 103 +++++++--
 ...pulateInputDataAndDecisionsOnDecisionService.ts |  83 +++++++-
 .../src/normalization/autoGenerateDrd.ts           |   1 +
 .../propertiesPanel/DecisionServiceProperties.tsx  |  37 +++-
 .../src/propertiesPanel/UnknownProperties.tsx      |   2 +-
 packages/dmn-editor/src/store/Store.ts             |  21 +-
 ...ainingDecisionServiceHrefsByDecisionHrefs.ts.ts |  59 +++---
 .../src/store/computed/computeDataTypes.ts         |   2 +-
 .../src/store/computed/computeDiagramData.ts       |  46 +++--
 ...teDirectlyIncludedExternalModelsByNamespace.ts} |   2 +-
 packages/dmn-editor/src/store/computed/initial.ts  |   2 +-
 .../dmn-editor/stories/dev/DevWebApp.stories.tsx   |   7 +-
 .../EmptyWithAvailableExternalModels.mdx           |  10 +
 .../EmptyWithAvailableExternalModels.stories.tsx   | 134 ++++++++++++
 .../availableModelsToInclude.ts                    |  76 +++++++
 .../externalModels.ts                              | 217 +++++++++++++++++++
 packages/dmn-editor/tests-e2e/__fixtures__/base.ts |  10 +
 .../tests-e2e/__fixtures__/includedModels.ts       |  54 +++++
 .../dmn-editor/tests-e2e/__fixtures__/nodes.ts     |  16 +-
 .../dmn-editor/tests-e2e/__fixtures__/palette.ts   |  15 ++
 .../dmn-editor/tests-e2e/__fixtures__/stories.ts   |  38 ++++
 .../add-external-node-inside-decision-service.png  | Bin 0 -> 45507 bytes
 ...l-node-inside-decision-service-after-delete.png | Bin 0 -> 45816 bytes
 ...-node-inside-decision-service-before-delete.png | Bin 0 -> 43833 bytes
 ...l-decision-from-ds-to-another-ds-after-move.png | Bin 0 -> 48290 bytes
 ...-decision-from-ds-to-another-ds-before-move.png | Bin 0 -> 50580 bytes
 ...n-inside-decision-service-after-move-to-out.png | Bin 0 -> 48391 bytes
 ...-inside-decision-service-before-move-to-out.png | Bin 0 -> 45828 bytes
 ...al-decision-out-from-decision-service-after.png | Bin 0 -> 34971 bytes
 ...l-decision-out-from-decision-service-before.png | Bin 0 -> 45828 bytes
 ...node-inside-decision-service-after-resizing.png | Bin 0 -> 48367 bytes
 ...ode-inside-decision-service-before-resizing.png | Bin 0 -> 43833 bytes
 .../add-external-node-inside-decision-service.png  | Bin 0 -> 45507 bytes
 ...l-node-inside-decision-service-after-delete.png | Bin 0 -> 45816 bytes
 ...-node-inside-decision-service-before-delete.png | Bin 0 -> 43833 bytes
 ...l-decision-from-ds-to-another-ds-after-move.png | Bin 0 -> 48290 bytes
 ...-decision-from-ds-to-another-ds-before-move.png | Bin 0 -> 50580 bytes
 ...n-inside-decision-service-after-move-to-out.png | Bin 0 -> 48391 bytes
 ...-inside-decision-service-before-move-to-out.png | Bin 0 -> 45828 bytes
 ...al-decision-out-from-decision-service-after.png | Bin 0 -> 34971 bytes
 ...l-decision-out-from-decision-service-before.png | Bin 0 -> 45828 bytes
 ...node-inside-decision-service-after-resizing.png | Bin 0 -> 48367 bytes
 ...ode-inside-decision-service-before-resizing.png | Bin 0 -> 43833 bytes
 .../add-external-node-inside-decision-service.png  | Bin 0 -> 49315 bytes
 ...l-node-inside-decision-service-after-delete.png | Bin 0 -> 46737 bytes
 ...-node-inside-decision-service-before-delete.png | Bin 0 -> 46307 bytes
 ...l-decision-from-ds-to-another-ds-after-move.png | Bin 0 -> 53698 bytes
 ...-decision-from-ds-to-another-ds-before-move.png | Bin 0 -> 55964 bytes
 ...n-inside-decision-service-after-move-to-out.png | Bin 0 -> 49226 bytes
 ...-inside-decision-service-before-move-to-out.png | Bin 0 -> 46921 bytes
 ...al-decision-out-from-decision-service-after.png | Bin 0 -> 53315 bytes
 ...l-decision-out-from-decision-service-before.png | Bin 0 -> 46921 bytes
 ...node-inside-decision-service-after-resizing.png | Bin 0 -> 49381 bytes
 ...ode-inside-decision-service-before-resizing.png | Bin 0 -> 46307 bytes
 .../tests-e2e/drgElements/addExternalNode.spec.ts  |  76 +++++++
 .../drgElements/deleteExternalNode.spec.ts         |  80 +++++++
 .../tests-e2e/drgElements/moveExternalNode.spec.ts | 227 ++++++++++++++++++++
 .../drgElements/resizeExternalNode.spec.ts         |  87 ++++++++
 79 files changed, 1789 insertions(+), 263 deletions(-)

diff --git a/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx b/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx
index 608d6d77d42..d1c5bc75c47 100644
--- a/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx
+++ b/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx
@@ -19,7 +19,7 @@
 
 import * as __path from "path";
 import * as React from "react";
-import { useEffect, useMemo, useState } from "react";
+import { useCallback, useEffect, useMemo, useState } from "react";
 import * as DmnEditor from "@kie-tools/dmn-editor/dist/DmnEditor";
 import { normalize, Normalized } from "@kie-tools/dmn-editor/dist/normalization/normalize";
 import { DMN_LATEST_VERSION, DmnLatestModel, DmnMarshaller, getMarshaller } from "@kie-tools/dmn-marshaller";
@@ -72,12 +72,12 @@ export type DmnEditorRootState = {
   marshaller: DmnMarshaller<typeof DMN_LATEST_VERSION> | undefined;
   stack: Normalized<DmnLatestModel>[];
   pointer: number;
-  openFilenormalizedPosixPathRelativeToTheWorkspaceRoot: string | undefined;
+  openFileNormalizedPosixPathRelativeToTheWorkspaceRoot: string | undefined;
   externalModelsByNamespace: DmnEditor.ExternalModelsIndex;
   isReadOnly: boolean;
   externalModelsManagerDoneBootstraping: boolean;
   keyboardShortcutsRegisterIds: number[];
-  keyboardShortcutsRegistred: boolean;
+  keyboardShortcutsRegistered: boolean;
   error: Error | undefined;
 };
 
@@ -95,11 +95,11 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
       marshaller: undefined,
       stack: [],
       pointer: -1,
-      openFilenormalizedPosixPathRelativeToTheWorkspaceRoot: undefined,
+      openFileNormalizedPosixPathRelativeToTheWorkspaceRoot: undefined,
       isReadOnly: props.isReadOnly,
       externalModelsManagerDoneBootstraping: false,
       keyboardShortcutsRegisterIds: [],
-      keyboardShortcutsRegistred: false,
+      keyboardShortcutsRegistered: false,
       error: undefined,
     };
   }
@@ -129,7 +129,7 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
   }
 
   public async setContent(
-    openFilenormalizedPosixPathRelativeToTheWorkspaceRoot: string,
+    openFileNormalizedPosixPathRelativeToTheWorkspaceRoot: string,
     content: string
   ): Promise<void> {
     const marshaller = this.getMarshaller(content);
@@ -142,7 +142,7 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
       savedStackPointer = [...prev.stack];
       return {
         stack: [normalize(marshaller.parser.parse())],
-        openFilenormalizedPosixPathRelativeToTheWorkspaceRoot,
+        openFileNormalizedPosixPathRelativeToTheWorkspaceRoot,
         pointer: 0,
       };
     });
@@ -150,17 +150,17 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
     // Wait the external manager models to load.
     await this.externalModelsManagerDoneBootstraping.promise;
 
-    // Set the valeus to render the DMN Editor.
+    // Set the values to render the DMN Editor.
     this.setState((prev) => {
       // External change to the same file.
       if (
-        prev.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot ===
-        openFilenormalizedPosixPathRelativeToTheWorkspaceRoot
+        prev.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot ===
+        openFileNormalizedPosixPathRelativeToTheWorkspaceRoot
       ) {
         const newStack = savedStackPointer.slice(0, prev.pointer + 1);
         return {
           marshaller,
-          openFilenormalizedPosixPathRelativeToTheWorkspaceRoot,
+          openFileNormalizedPosixPathRelativeToTheWorkspaceRoot,
           stack: [...newStack, normalize(marshaller.parser.parse())],
           isReadOnly: prev.isReadOnly,
           pointer: newStack.length,
@@ -172,7 +172,7 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
       else {
         return {
           marshaller,
-          openFilenormalizedPosixPathRelativeToTheWorkspaceRoot,
+          openFileNormalizedPosixPathRelativeToTheWorkspaceRoot,
           stack: [normalize(marshaller.parser.parse())],
           isReadOnly: prev.isReadOnly,
           pointer: 0,
@@ -216,13 +216,13 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
       },
       () =>
         this.props.onNewEdit({
-          id: `${this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot}__${generateUuid()}`,
+          id: `${this.state.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot}__${generateUuid()}`,
         })
     );
   };
 
   private onRequestExternalModelsAvailableToInclude: DmnEditor.OnRequestExternalModelsAvailableToInclude = async () => {
-    if (!this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot) {
+    if (!this.state.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot) {
       return [];
     }
 
@@ -233,9 +233,9 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
 
     return list.normalizedPosixPathsRelativeToTheWorkspaceRoot.flatMap((p) =>
       // Do not show this DMN on the list
-      p === this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot
+      p === this.state.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot
         ? []
-        : __path.relative(__path.dirname(this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot!), p)
+        : __path.relative(__path.dirname(this.state.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot!), p)
     );
   };
 
@@ -244,7 +244,7 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
   ) => {
     const normalizedPosixPathRelativeToTheWorkspaceRoot = __path
       .resolve(
-        __path.dirname(this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot!),
+        __path.dirname(this.state.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot!),
         normalizedPosixPathRelativeToTheOpenFile
       )
       .substring(1); // Remove leading slash.
@@ -290,7 +290,7 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
   };
 
   private onOpenFileFromPathRelativeToTheOpenFile = (normalizedPosixPathRelativeToTheOpenFile: string) => {
-    if (!this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot) {
+    if (!this.state.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot) {
       return;
     }
 
@@ -304,7 +304,7 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
     prevState: Readonly<DmnEditorRootState>,
     snapshot?: any
   ): void {
-    if (this.props.keyboardShortcutsService === undefined || this.state.keyboardShortcutsRegistred === true) {
+    if (this.props.keyboardShortcutsService === undefined || this.state.keyboardShortcutsRegistered === true) {
       return;
     }
 
@@ -428,7 +428,7 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
 
     this.setState((prev) => ({
       ...prev,
-      keyboardShortcutsRegistred: true,
+      keyboardShortcutsRegistered: true,
       keyboardShortcutsRegisterIds: [
         bigMoveDown,
         bigMoveLeft,
@@ -497,7 +497,7 @@ export class DmnEditorRoot extends React.Component<DmnEditorRootProps, DmnEditor
             <ExternalModelsManager
               workspaceRootAbsolutePosixPath={this.props.workspaceRootAbsolutePosixPath}
               thisDmnsNormalizedPosixPathRelativeToTheWorkspaceRoot={
-                this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot
+                this.state.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot
               }
               model={this.model}
               onChange={this.setExternalModelsByNamespace}
@@ -532,10 +532,7 @@ function ExternalModelsManager({
   externalModelsManagerDoneBootstraping: PromiseImperativeHandle<void>;
 }) {
   const namespaces = useMemo(
-    () =>
-      (model.definitions.import ?? [])
-        .map((i) => getNamespaceOfDmnImport({ dmnImport: i }))
-        .join(NAMESPACES_EFFECT_SEPARATOR),
+    () => getIncludedNamespacesFromModel(model.definitions.import),
     [model.definitions.import]
   );
 
@@ -563,6 +560,38 @@ function ExternalModelsManager({
     };
   }, [thisDmnsNormalizedPosixPathRelativeToTheWorkspaceRoot]);
 
+  const getDmnsByNamespace = useCallback((resources: (ResourceContent | undefined)[]) => {
+    const ret = new Map<string, ResourceContent>();
+    for (let i = 0; i < resources.length; i++) {
+      const resource = resources[i];
+      if (!resource) {
+        continue;
+      }
+
+      const content = resource.content ?? "";
+      const ext = __path.extname(resource.normalizedPosixPathRelativeToTheWorkspaceRoot);
+      if (ext === ".dmn") {
+        const namespace = domParser.getDomDocument(content).documentElement.getAttribute("namespace");
+        if (namespace) {
+          // Check for multiplicity of namespaces on DMN models
+          if (ret.has(namespace)) {
+            console.warn(
+              `DMN EDITOR ROOT: Multiple DMN models encountered with the same namespace '${namespace}': '${
+                resource.normalizedPosixPathRelativeToTheWorkspaceRoot
+              }' and '${
+                ret.get(namespace)!.normalizedPosixPathRelativeToTheWorkspaceRoot
+              }'. The latter will be considered.`
+            );
+          }
+
+          ret.set(namespace, resource);
+        }
+      }
+    }
+
+    return ret;
+  }, []);
+
   // This effect actually populates `externalModelsByNamespace` through the `onChange` call.
   useEffect(() => {
     let canceled = false;
@@ -594,6 +623,8 @@ function ExternalModelsManager({
         const externalModelsIndex: DmnEditor.ExternalModelsIndex = {};
 
         const namespacesSet = new Set(namespaces.split(NAMESPACES_EFFECT_SEPARATOR));
+        const loadedDmnsByPathRelativeToTheWorkspaceRoot = new Set<string>();
+        const dmnsByNamespace = getDmnsByNamespace(resources);
 
         for (let i = 0; i < resources.length; i++) {
           const resource = resources[i];
@@ -601,46 +632,54 @@ function ExternalModelsManager({
             continue;
           }
 
-          const content = resource.content ?? "";
-
+          const ext = __path.extname(resource.normalizedPosixPathRelativeToTheWorkspaceRoot);
           const normalizedPosixPathRelativeToTheOpenFile = __path.relative(
             __path.dirname(thisDmnsNormalizedPosixPathRelativeToTheWorkspaceRoot),
             resource.normalizedPosixPathRelativeToTheWorkspaceRoot
           );
 
-          const ext = __path.extname(resource.normalizedPosixPathRelativeToTheWorkspaceRoot);
-          if (ext === ".dmn") {
-            const namespace = domParser.getDomDocument(content).documentElement.getAttribute("namespace");
-            if (namespace && namespacesSet.has(namespace)) {
-              // Check for multiplicity of namespaces on DMN models
-              if (externalModelsIndex[namespace]) {
-                console.warn(
-                  `DMN EDITOR ROOT: Multiple DMN models encountered with the same namespace '${namespace}': '${
-                    resource.normalizedPosixPathRelativeToTheWorkspaceRoot
-                  }' and '${
-                    externalModelsIndex[namespace]!.normalizedPosixPathRelativeToTheOpenFile
-                  }'. The latter will be considered.`
-                );
-              }
+          const resourceContent = resource.content ?? "";
 
-              externalModelsIndex[namespace] = {
-                normalizedPosixPathRelativeToTheOpenFile,
-                model: normalize(getMarshaller(content, { upgradeTo: "latest" }).parser.parse()),
-                type: "dmn",
-                svg: "",
-              };
+          // DMN Files
+          if (ext === ".dmn") {
+            const namespaceOfTheResourceFile = domParser
+              .getDomDocument(resourceContent)
+              .documentElement.getAttribute("namespace");
+
+            if (namespaceOfTheResourceFile && namespacesSet.has(namespaceOfTheResourceFile)) {
+              checkIfNamespaceIsAlreadyLoaded({
+                externalModelsIndex,
+                namespaceOfTheResourceFile,
+                normalizedPosixPathRelativeToTheWorkspaceRoot: resource.normalizedPosixPathRelativeToTheWorkspaceRoot,
+              });
+
+              loadModel({
+                includedModelContent: resourceContent,
+                includedModelNamespace: namespaceOfTheResourceFile,
+                externalModelsIndex,
+                thisDmnsNormalizedPosixPathRelativeToTheWorkspaceRoot,
+                loadedDmnsByPathRelativeToTheWorkspaceRoot,
+                normalizedPosixPathRelativeToTheWorkspaceRoot: resource.normalizedPosixPathRelativeToTheWorkspaceRoot,
+                resourcesByNamespace: dmnsByNamespace,
+              });
             }
-          } else if (ext === ".pmml") {
+          }
+
+          // PMML Files
+          else if (ext === ".pmml") {
             const namespace = getPmmlNamespace({ normalizedPosixPathRelativeToTheOpenFile });
             if (namespace && namespacesSet.has(namespace)) {
               // No need to check for namespaces being equal becuase there can't be two files with the same relativePath.
               externalModelsIndex[namespace] = {
                 normalizedPosixPathRelativeToTheOpenFile,
-                model: XML2PMML(content),
+                model: XML2PMML(resourceContent),
                 type: "pmml",
               };
             }
-          } else {
+          }
+
+          // Unknown files
+          else {
             throw new Error(`Unknown extension '${ext}'.`);
           }
         }
@@ -663,6 +702,7 @@ function ExternalModelsManager({
     externalUpdatesCount,
     workspaceRootAbsolutePosixPath,
     externalModelsManagerDoneBootstraping,
+    getDmnsByNamespace,
   ]);
 
   return <></>;
@@ -682,3 +722,93 @@ function DmnMarshallerFallbackError({ error }: { error: Error }) {
     </Flex>
   );
 }
+
+function getIncludedNamespacesFromModel(imports: Normalized<DmnLatestModel["definitions"]["import"]>) {
+  return (imports ?? []).map((i) => getNamespaceOfDmnImport({ dmnImport: i })).join(NAMESPACES_EFFECT_SEPARATOR);
+}
+
+function loadModel(args: {
+  thisDmnsNormalizedPosixPathRelativeToTheWorkspaceRoot: string;
+  resourcesByNamespace: Map<string, ResourceContent>;
+  normalizedPosixPathRelativeToTheWorkspaceRoot: string;
+  includedModelNamespace: string;
+  loadedDmnsByPathRelativeToTheWorkspaceRoot: Set<string>;
+  includedModelContent: string;
+  externalModelsIndex: DmnEditor.ExternalModelsIndex;
+}) {
+  const normalizedPosixPathRelativeToTheOpenFile = __path.relative(
+    __path.dirname(args.thisDmnsNormalizedPosixPathRelativeToTheWorkspaceRoot),
+    args.normalizedPosixPathRelativeToTheWorkspaceRoot
+  );
+
+  const includedModel = normalize(getMarshaller(args.includedModelContent, { upgradeTo: "latest" }).parser.parse());
+  args.externalModelsIndex[args.includedModelNamespace] = {
+    normalizedPosixPathRelativeToTheOpenFile,
+    model: includedModel,
+    type: "dmn",
+    svg: "",
+  };
+
+  args.loadedDmnsByPathRelativeToTheWorkspaceRoot.add(args.normalizedPosixPathRelativeToTheWorkspaceRoot);
+
+  loadDependentModels({
+    ...args,
+    model: includedModel,
+  });
+}
+
+// Load all included models from the model and the included models of those models, recursively.
+function loadDependentModels(args: {
+  model: Normalized<DmnLatestModel>;
+  externalModelsIndex: DmnEditor.ExternalModelsIndex;
+  resourcesByNamespace: Map<string, ResourceContent>;
+  loadedDmnsByPathRelativeToTheWorkspaceRoot: Set<string>;
+  thisDmnsNormalizedPosixPathRelativeToTheWorkspaceRoot: string;
+}) {
+  const includedNamespaces = new Set(
+    getIncludedNamespacesFromModel(args.model.definitions.import).split(NAMESPACES_EFFECT_SEPARATOR)
+  );
+
+  for (const includedNamespace of includedNamespaces) {
+    if (!args.resourcesByNamespace.has(includedNamespace)) {
+      console.warn(
+        `DMN EDITOR ROOT: The included namespace '${includedNamespace}' for the model '${args.model.definitions["@_id"]}' can not be found.`
+      );
+      continue;
+    }
+
+    const resource = args.resourcesByNamespace.get(includedNamespace)!;
+    if (args.loadedDmnsByPathRelativeToTheWorkspaceRoot.has(resource.normalizedPosixPathRelativeToTheWorkspaceRoot)) {
+      continue;
+    }
+
+    checkIfNamespaceIsAlreadyLoaded({
+      externalModelsIndex: args.externalModelsIndex,
+      namespaceOfTheResourceFile: includedNamespace,
+      normalizedPosixPathRelativeToTheWorkspaceRoot: resource.normalizedPosixPathRelativeToTheWorkspaceRoot,
+    });
+
+    loadModel({
+      ...args,
+      includedModelContent: resource.content ?? "",
+      normalizedPosixPathRelativeToTheWorkspaceRoot: resource.normalizedPosixPathRelativeToTheWorkspaceRoot,
+      includedModelNamespace: includedNamespace,
+    });
+  }
+}
+
+function checkIfNamespaceIsAlreadyLoaded(args: {
+  externalModelsIndex: DmnEditor.ExternalModelsIndex;
+  namespaceOfTheResourceFile: string;
+  normalizedPosixPathRelativeToTheWorkspaceRoot: string;
+}) {
+  if (args.externalModelsIndex[args.namespaceOfTheResourceFile]) {
+    console.warn(
+      `DMN EDITOR ROOT: Multiple DMN models encountered with the same namespace '${args.namespaceOfTheResourceFile}': '${
+        args.normalizedPosixPathRelativeToTheWorkspaceRoot
+      }' and '${
+        args.externalModelsIndex[args.namespaceOfTheResourceFile]!.normalizedPosixPathRelativeToTheOpenFile
+      }'. The latter will be considered.`
+    );
+  }
+}
diff --git a/packages/dmn-editor/src/DmnEditor.tsx b/packages/dmn-editor/src/DmnEditor.tsx
index 7739a0cbf7c..766c08146cb 100644
--- a/packages/dmn-editor/src/DmnEditor.tsx
+++ b/packages/dmn-editor/src/DmnEditor.tsx
@@ -399,7 +399,9 @@ export const DmnEditorInternal = ({
         </Tab>
 
         <Tab eventKey={DmnEditorTab.INCLUDED_MODELS} title={tabTitle.includedModels}>
-          {navigationTab === DmnEditorTab.INCLUDED_MODELS && <IncludedModels />}
+          <div data-testid={"kie-tools--dmn-editor--included-models-container"}>
+            {navigationTab === DmnEditorTab.INCLUDED_MODELS && <IncludedModels />}
+          </div>
         </Tab>
       </Tabs>
     </div>
diff --git a/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx b/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx
index c1a09f169eb..0b1be461482 100644
--- a/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx
+++ b/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx
@@ -57,7 +57,10 @@ export function AutolayoutButton() {
         __readonly_parentNodesById,
         __readonly_drdIndex: s.computed(s).getDrdIndex(),
         __readonly_dmnObjectNamespace: s.dmn.model.definitions["@_namespace"],
-        __readonly_externalDmnsIndex: s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).dmns,
+        __readonly_externalDmnsIndex: s
+          .computed(s)
+          .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
+        __readonly_externalModelsByNamespace: externalModelsByNamespace,
       });
     });
   }, [dmnEditorStoreApi, externalModelsByNamespace]);
diff --git a/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx b/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx
index 3a0c4e08fa8..5e4fb2ab5e9 100644
--- a/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx
+++ b/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx
@@ -94,12 +94,12 @@ export function BoxedExpressionScreen({ container }: { container: React.RefObjec
   const isPropertiesPanelOpen = useDmnEditorStore((s) => s.boxedExpressionEditor.propertiesPanel.isOpen);
 
   const externalDmnsByNamespace = useDmnEditorStore(
-    (s) => s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).dmns
+    (s) => s.computed(s).getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns
   );
   const dataTypesTree = useDmnEditorStore((s) => s.computed(s).getDataTypes(externalModelsByNamespace).dataTypesTree);
   const importsByNamespace = useDmnEditorStore((s) => s.computed(s).importsByNamespace());
   const externalPmmlsByNamespace = useDmnEditorStore(
-    (s) => s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).pmmls
+    (s) => s.computed(s).getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).pmmls
   );
   const isAlternativeInputDataShape = useDmnEditorStore((s) => s.computed(s).isAlternativeInputDataShape());
   const drdIndex = useDmnEditorStore((s) => s.computed(s).getDrdIndex());
diff --git a/packages/dmn-editor/src/diagram/Diagram.tsx b/packages/dmn-editor/src/diagram/Diagram.tsx
index 123aba83e25..876c22ba4bb 100644
--- a/packages/dmn-editor/src/diagram/Diagram.tsx
+++ b/packages/dmn-editor/src/diagram/Diagram.tsx
@@ -246,6 +246,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
               shapeId: targetNode.data.shape["@_id"],
             },
             keepWaypoints: false,
+            externalModelsByNamespace,
           });
         });
       },
@@ -337,6 +338,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                   })["@_height"],
                 },
               },
+              externalModelsByNamespace,
             });
             state.diagram._selectedNodes = [newNodeId];
             state.focus.consumableId = newNodeId;
@@ -352,7 +354,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           const state = dmnEditorStoreApi.getState();
           const externalDmnsIndex = state
             .computed(state)
-            .getExternalModelTypesByNamespace(externalModelsByNamespace).dmns;
+            .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns;
 
           const externalNodeDmn = externalDmnsIndex.get(externalNode.externalDrgElementNamespace);
           const externalDrgElement = (externalNodeDmn?.model.definitions.drgElement ?? []).find(
@@ -429,7 +431,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                 __readonly_drdIndex: drdIndex,
                 __readonly_externalDmnsIndex: dereferencedState
                   .computed(dereferencedState)
-                  .getExternalModelTypesByNamespace(externalModelsByNamespace).dmns,
+                  .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
                 __readonly_indexedDrd: dereferencedState.computed(dereferencedState).indexedDrd(),
                 __readonly_indexedDrdContainingDecisionServiceDepiction: indexedDrdContainingDecisionServiceDepiction!,
                 __readonly_containedDecisionHrefsRelativeToThisDmn: containedDecisionHrefsRelativeToThisDmn,
@@ -481,7 +483,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
             const drdIndex = dereferencedState.computed(dereferencedState).getDrdIndex();
             const externalDmnsIndex = dereferencedState
               .computed(dereferencedState)
-              .getExternalModelTypesByNamespace(externalModelsByNamespace).dmns;
+              .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns;
 
             const {
               strategyForAddingDecisionServiceToDrd,
@@ -528,7 +530,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                 __readonly_drdIndex: drdIndex,
                 __readonly_externalDmnsIndex: dereferencedState
                   .computed(dereferencedState)
-                  .getExternalModelTypesByNamespace(externalModelsByNamespace).dmns,
+                  .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
                 __readonly_indexedDrd: dereferencedState.computed(dereferencedState).indexedDrd(),
                 __readonly_indexedDrdContainingDecisionServiceDepiction: indexedDrdContainingDecisionServiceDepiction!,
                 __readonly_containedDecisionHrefsRelativeToThisDmn: containedDecisionHrefsRelativeToThisDmn,
@@ -670,6 +672,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                 })["@_height"],
               },
             },
+            externalModelsByNamespace,
           });
 
           state.diagram._selectedNodes = [newDmnObejctHref];
@@ -754,7 +757,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                       __readonly_dmnObjectNamespace: node.data.dmnObjectNamespace,
                       __readonly_externalDmnsIndex: state
                         .computed(state)
-                        .getExternalModelTypesByNamespace(externalModelsByNamespace).dmns,
+                        .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
                       change: {
                         isExternal: !!node.data.dmnObjectQName.prefix,
                         nodeType: node.type as NodeType,
@@ -872,10 +875,11 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                   __readonly_dmnObjectQName: node.data.dmnObjectQName,
                   __readonly_dmnObjectId: node.data.dmnObject?.["@_id"],
                   __readonly_nodeNature: nodeNatures[node.type as NodeType],
-                  mode: NodeDeletionMode.FROM_DRG_AND_ALL_DRDS,
-                  __readonly_externalModelTypesByNamespace: state
+                  __readonly_mode: NodeDeletionMode.FROM_DRG_AND_ALL_DRDS,
+                  __readonly_externalDmnsIndex: state
                     .computed(state)
-                    .getExternalModelTypesByNamespace(externalModelsByNamespace),
+                    .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
+                  __readonly_externalModelsByNamespace: externalModelsByNamespace,
                 });
                 state.dispatch(state).diagram.setNodeStatus(node.id, {
                   selected: false,
@@ -897,7 +901,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           }
         });
       },
-      [reactFlowInstance, dmnEditorStoreApi, externalModelsByNamespace]
+      [dmnEditorStoreApi, externalModelsByNamespace]
     );
 
     const resetToBeforeEditingBegan = useCallback(() => {
@@ -990,8 +994,9 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                 for (let i = 0; i < selectedNodes.length; i++) {
                   deleteDecisionFromDecisionService({
                     definitions: state.dmn.model.definitions,
-                    decisionId: selectedNodes[i].data.dmnObject!["@_id"]!, // We can assume that all selected nodes are Decisions because the contaiment was validated above.
+                    decisionHref: selectedNodes[i].id, // We can assume that all selected nodes are Decisions because the contaiment was validated above.
                     decisionServiceId: p.data.dmnObject!["@_id"]!,
+                    externalModelsByNamespace,
                   });
                 }
               } else {
@@ -1007,12 +1012,13 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                 addDecisionToDecisionService({
                   definitions: state.dmn.model.definitions,
                   drdIndex: state.computed(state).getDrdIndex(),
-                  decisionId: selectedNodes[i].data.dmnObject!["@_id"]!, // We can assume that all selected nodes are Decisions because the contaiment was validated above.
+                  decisionHref: selectedNodes[i].id, // We can assume that all selected nodes are Decisions because the contaiment was validated above.
                   decisionServiceId: state
                     .computed(state)
                     .getDiagramData(externalModelsByNamespace)
                     .nodesById.get(dropTargetNode.id)!.data.dmnObject!["@_id"]!,
                   snapGrid: state.diagram.snapGrid,
+                  externalModelsByNamespace,
                 });
               }
             } else {
@@ -1026,7 +1032,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           resetToBeforeEditingBegan();
         }
       },
-      [dmnEditorStoreApi, externalModelsByNamespace, resetToBeforeEditingBegan]
+      [dmnEditorStoreApi, externalModelsByNamespace, resetToBeforeEditingBegan, thisDmn.model.definitions]
     );
 
     const onEdgesChange = useCallback<RF.OnEdgesChange>(
@@ -1047,6 +1053,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                     drdIndex: state.computed(state).getDrdIndex(),
                     edge: { id: change.id, dmnObject: edge.data.dmnObject },
                     mode: EdgeDeletionMode.FROM_DRG_AND_ALL_DRDS,
+                    externalModelsByNamespace,
                   });
                   state.dispatch(state).diagram.setEdgeStatus(change.id, {
                     selected: false,
@@ -1125,6 +1132,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
               shapeId: targetNode.data.shape["@_id"],
             },
             keepWaypoints: true,
+            externalModelsByNamespace,
           });
 
           // The DMN Edge changed nodes, so we need to delete the old one, but keep the waypoints on the same DRD.
@@ -1134,6 +1142,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
               drdIndex: state.computed(state).getDrdIndex(),
               edge: { id: oldEdge.id, dmnObject: oldEdge.data!.dmnObject },
               mode: EdgeDeletionMode.FROM_DRG_AND_ALL_DRDS,
+              externalModelsByNamespace,
             });
 
             const deletedWaypoints = deletedDmnEdgeOnCurrentDrd?.["di:waypoint"];
@@ -1380,7 +1389,7 @@ function DmnDiagramWithoutDrd() {
 
                 const externalModelTypesByNamespace = dereferencedState
                   .computed(dereferencedState)
-                  .getExternalModelTypesByNamespace(externalModelsByNamespace);
+                  .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace);
 
                 autoGenerateDrd({
                   model: dereferencedState.dmn.model,
@@ -1434,7 +1443,8 @@ function DmnDiagramWithoutDrd() {
                     __readonly_dmnObjectNamespace: dereferencedState.dmn.model.definitions["@_namespace"],
                     __readonly_externalDmnsIndex: dereferencedState
                       .computed(dereferencedState)
-                      .getExternalModelTypesByNamespace(externalModelsByNamespace).dmns,
+                      .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
+                    __readonly_externalModelsByNamespace: externalModelsByNamespace,
                   });
                   s.dmn.model = dereferencedState.dmn.model;
                 });
@@ -1463,6 +1473,7 @@ function DmnDiagramEmptyState({
   isReadOnly?: boolean;
 }) {
   const dmnEditorStoreApi = useDmnEditorStoreApi();
+  const { externalModelsByNamespace } = useExternalModels();
 
   return (
     <Bullseye
@@ -1524,6 +1535,7 @@ function DmnDiagramEmptyState({
                             })["@_height"],
                           },
                         },
+                        externalModelsByNamespace,
                       });
 
                       const drgElementIndex = (state.dmn.model.definitions.drgElement ?? []).length - 1;
@@ -1584,6 +1596,7 @@ function DmnDiagramEmptyState({
                           type: NODE_TYPES.inputData,
                           bounds: inputDataNodeBounds,
                         },
+                        externalModelsByNamespace,
                       });
 
                       const { href: decisionNodeHref } = addConnectedNode({
@@ -1609,6 +1622,7 @@ function DmnDiagramEmptyState({
                             })["@_height"],
                           },
                         },
+                        externalModelsByNamespace,
                       });
 
                       state.diagram._selectedNodes = [decisionNodeHref];
diff --git a/packages/dmn-editor/src/diagram/DiagramCommands.tsx b/packages/dmn-editor/src/diagram/DiagramCommands.tsx
index af73112a7e5..e7354f80d9f 100644
--- a/packages/dmn-editor/src/diagram/DiagramCommands.tsx
+++ b/packages/dmn-editor/src/diagram/DiagramCommands.tsx
@@ -134,6 +134,7 @@ export function DiagramCommands(props: {}) {
               drdIndex: state.computed(state).getDrdIndex(),
               edge: { id: edge.id, dmnObject: edge.data!.dmnObject },
               mode: EdgeDeletionMode.FROM_DRG_AND_ALL_DRDS,
+              externalModelsByNamespace,
             });
             state.dispatch(state).diagram.setEdgeStatus(edge.id, {
               selected: false,
@@ -156,10 +157,11 @@ export function DiagramCommands(props: {}) {
                   __readonly_dmnObjectQName: node.data.dmnObjectQName,
                   __readonly_dmnObjectId: node.data.dmnObject?.["@_id"],
                   __readonly_nodeNature: nodeNatures[node.type as NodeType],
-                  mode: NodeDeletionMode.FROM_DRG_AND_ALL_DRDS,
-                  __readonly_externalModelTypesByNamespace: state
+                  __readonly_mode: NodeDeletionMode.FROM_DRG_AND_ALL_DRDS,
+                  __readonly_externalDmnsIndex: state
                     .computed(state)
-                    .getExternalModelTypesByNamespace(externalModelsByNamespace),
+                    .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
+                  __readonly_externalModelsByNamespace: externalModelsByNamespace,
                 });
                 state.dispatch(state).diagram.setNodeStatus(node.id, {
                   selected: false,
@@ -239,12 +241,25 @@ export function DiagramCommands(props: {}) {
             definitions: state.dmn.model.definitions,
             drdIndex: state.computed(state).getDrdIndex(),
           });
-          diagramElements.push(...clipboard.shapes.map((s) => ({ ...s, __$$element: "dmndi:DMNShape" as const })));
-          diagramElements.push(...clipboard.edges.map((s) => ({ ...s, __$$element: "dmndi:DMNEdge" as const })));
+          diagramElements.push(
+            ...clipboard.shapes.map((s) => ({
+              ...s,
+              __$$element: "dmndi:DMNShape" as const,
+            }))
+          );
+          diagramElements.push(
+            ...clipboard.edges.map((s) => ({
+              ...s,
+              __$$element: "dmndi:DMNEdge" as const,
+            }))
+          );
 
           widths.push(...clipboard.widths);
 
-          repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions: state.dmn.model.definitions });
+          repopulateInputDataAndDecisionsOnAllDecisionServices({
+            definitions: state.dmn.model.definitions,
+            externalModelsByNamespace,
+          });
 
           state.diagram._selectedNodes = [...clipboard.drgElements, ...clipboard.artifacts].map((s) =>
             buildXmlHref({ id: s["@_id"]! })
@@ -256,7 +271,7 @@ export function DiagramCommands(props: {}) {
         });
       });
     };
-  }, [dmnEditorStoreApi, commandsRef]);
+  }, [dmnEditorStoreApi, commandsRef, externalModelsByNamespace]);
 
   // Select/deselect all nodes
   useEffect(() => {
@@ -317,12 +332,13 @@ export function DiagramCommands(props: {}) {
               padding: CONTAINER_NODES_DESIRABLE_PADDING,
             }),
           },
+          externalModelsByNamespace,
         });
 
         state.dispatch(state).diagram.setNodeStatus(newNodeId, { selected: true });
       });
     };
-  }, [dmnEditorStoreApi, commandsRef, rf]);
+  }, [dmnEditorStoreApi, commandsRef, rf, externalModelsByNamespace]);
 
   // Toggle hierarchy highlights
   useEffect(() => {
@@ -369,7 +385,7 @@ export function DiagramCommands(props: {}) {
               canRemoveNodeFromDrdOnly({
                 __readonly_externalDmnsIndex: state
                   .computed(state)
-                  .getExternalModelTypesByNamespace(externalModelsByNamespace).dmns,
+                  .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
                 definitions: state.dmn.model.definitions,
                 __readonly_drdIndex: state.computed(state).getDrdIndex(),
                 __readonly_dmnObjectNamespace:
@@ -380,7 +396,7 @@ export function DiagramCommands(props: {}) {
               canRemoveNodeFromDrdOnly({
                 __readonly_externalDmnsIndex: state
                   .computed(state)
-                  .getExternalModelTypesByNamespace(externalModelsByNamespace).dmns,
+                  .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
                 definitions: state.dmn.model.definitions,
                 __readonly_drdIndex: state.computed(state).getDrdIndex(),
                 __readonly_dmnObjectNamespace:
@@ -393,8 +409,12 @@ export function DiagramCommands(props: {}) {
               drdIndex: state.computed(state).getDrdIndex(),
               edge: { id: edge.id, dmnObject: edge.data!.dmnObject },
               mode: EdgeDeletionMode.FROM_CURRENT_DRD_ONLY,
+              externalModelsByNamespace,
+            });
+            state.dispatch(state).diagram.setEdgeStatus(edge.id, {
+              selected: false,
+              draggingWaypoint: false,
             });
-            state.dispatch(state).diagram.setEdgeStatus(edge.id, { selected: false, draggingWaypoint: false });
           }
         }
 
@@ -406,15 +426,16 @@ export function DiagramCommands(props: {}) {
           const { deletedDmnShapeOnCurrentDrd: deletedShape } = deleteNode({
             definitions: state.dmn.model.definitions,
             __readonly_drgEdges: [], // Deleting from DRD only.
-            __readonly_externalModelTypesByNamespace: state
+            __readonly_externalDmnsIndex: state
               .computed(state)
-              .getExternalModelTypesByNamespace(externalModelsByNamespace),
+              .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
             __readonly_drdIndex: state.computed(state).getDrdIndex(),
             __readonly_dmnObjectNamespace: node.data.dmnObjectNamespace ?? state.dmn.model.definitions["@_namespace"],
             __readonly_dmnObjectQName: node.data.dmnObjectQName,
             __readonly_dmnObjectId: node.data.dmnObject?.["@_id"],
             __readonly_nodeNature: nodeNatures[node.type as NodeType],
-            mode: NodeDeletionMode.FROM_CURRENT_DRD_ONLY,
+            __readonly_mode: NodeDeletionMode.FROM_CURRENT_DRD_ONLY,
+            __readonly_externalModelsByNamespace: externalModelsByNamespace,
           });
 
           if (deletedShape) {
diff --git a/packages/dmn-editor/src/diagram/DrgNodesPanel.tsx b/packages/dmn-editor/src/diagram/DrgNodesPanel.tsx
index 66b9903f8a4..2391eda1e09 100644
--- a/packages/dmn-editor/src/diagram/DrgNodesPanel.tsx
+++ b/packages/dmn-editor/src/diagram/DrgNodesPanel.tsx
@@ -61,8 +61,7 @@ export function DrgNodesPanel() {
   const containingDecisionServiceHrefsByDecisionHrefsRelativeToThisDmn = useMemo(
     () =>
       computeContainingDecisionServiceHrefsByDecisionHrefs({
-        drgElements: thisDmnsDrgElements,
-        drgElementsNamespace: thisDmnsNamespace,
+        drgElementsByNamespace: new Map([[thisDmnsNamespace, thisDmnsDrgElements]]),
         thisDmnsNamespace: thisDmnsNamespace,
       }),
     [thisDmnsDrgElements, thisDmnsNamespace]
diff --git a/packages/dmn-editor/src/diagram/Palette.tsx b/packages/dmn-editor/src/diagram/Palette.tsx
index 05fe4938571..1bfed0c65d0 100644
--- a/packages/dmn-editor/src/diagram/Palette.tsx
+++ b/packages/dmn-editor/src/diagram/Palette.tsx
@@ -49,6 +49,7 @@ import { useInViewSelect } from "../responsiveness/useInViewSelect";
 import { useDmnEditor } from "../DmnEditorContext";
 import { getDrdId } from "./drd/drdId";
 import { useSettings } from "../settings/DmnEditorSettingsContext";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 export const MIME_TYPE_FOR_DMN_EDITOR_NEW_NODE_FROM_PALETTE = "application/kie-dmn-editor--new-node-from-palette";
 
@@ -65,6 +66,7 @@ export function Palette({ pulse }: { pulse: boolean }) {
   const rfStoreApi = RF.useStoreApi();
   const isAlternativeInputDataShape = useDmnEditorStore((s) => s.computed(s).isAlternativeInputDataShape());
   const drdIndex = useDmnEditorStore((s) => s.computed(s).getDrdIndex());
+  const { externalModelsByNamespace } = useExternalModels();
   const settings = useSettings();
 
   const groupNodes = useCallback(() => {
@@ -88,11 +90,12 @@ export function Palette({ pulse }: { pulse: boolean }) {
             padding: CONTAINER_NODES_DESIRABLE_PADDING,
           }),
         },
+        externalModelsByNamespace,
       });
 
       state.dispatch(state).diagram.setNodeStatus(newNodeId, { selected: true });
     });
-  }, [dmnEditorStoreApi, rfStoreApi]);
+  }, [dmnEditorStoreApi, externalModelsByNamespace, rfStoreApi]);
 
   const drd = thisDmn.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[drdIndex];
 
@@ -265,7 +268,11 @@ export function Palette({ pulse }: { pulse: boolean }) {
           <br />
           <aside className={"kie-dmn-editor--external-nodes-panel-toggle"}>
             {diagram.openLhsPanel === DiagramLhsPanel.EXTERNAL_NODES && (
-              <div className={"kie-dmn-editor--palette-nodes-popover"} style={{ maxHeight }}>
+              <div
+                className={"kie-dmn-editor--palette-nodes-popover"}
+                style={{ maxHeight }}
+                data-testid={"kie-tools--dmn-editor--external-nodes-popover"}
+              >
                 <ExternalNodesPanel />
               </div>
             )}
diff --git a/packages/dmn-editor/src/diagram/nodes/Nodes.tsx b/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
index 3c0e362f9bd..9da807bfcc8 100644
--- a/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
@@ -939,7 +939,7 @@ export const DecisionServiceNode = React.memo(
               __readonly_dmnObjectNamespace: dmnObjectNamespace,
               __readonly_externalDmnsIndex: state
                 .computed(state)
-                .getExternalModelTypesByNamespace(externalModelsByNamespace).dmns,
+                .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns,
               shapeIndex: shape.index,
               localYPosition: e.y,
               snapGrid: state.diagram.snapGrid,
diff --git a/packages/dmn-editor/src/externalNodes/DmnObjectListItem.tsx b/packages/dmn-editor/src/externalNodes/DmnObjectListItem.tsx
index 85423717aba..b21e543428b 100644
--- a/packages/dmn-editor/src/externalNodes/DmnObjectListItem.tsx
+++ b/packages/dmn-editor/src/externalNodes/DmnObjectListItem.tsx
@@ -31,6 +31,8 @@ import { useDmnEditorStore } from "../store/StoreContext";
 import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 import { DMN15_SPEC } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/Dmn15Spec";
 import { Normalized } from "../normalization/normalize";
+import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip";
+import { NODE_TYPES } from "../diagram/nodes/NodeTypes";
 
 export function DmnObjectListItem({
   dmnObject,
@@ -50,14 +52,70 @@ export function DmnObjectListItem({
   );
   const isAlternativeInputDataShape = useDmnEditorStore((s) => s.computed(s).isAlternativeInputDataShape());
 
-  const displayName = dmnObject
-    ? buildFeelQNameFromNamespace({
-        namedElement: dmnObject,
-        importsByNamespace,
-        namespace,
-        relativeToNamespace,
-      }).full
-    : dmnObjectHref;
+  // The dmnObject represented here can be a node from a 3rd model that is not included in this model.
+  // For example, consider a "Local Decision Service" with an encapsulated "Decision-A" from "Model A",
+  // but that "Decision-A" have an "Input-B" that is from "Model B", which is not included in local model.
+  //
+  // Model Name: Local Model.dmn
+  // Nodes: Local Decision Service
+  // Included Models: Model-A.dmn
+  //
+  // Model Name: Model-A.dmn
+  // Nodes: Decision-A
+  // Included Models: Model-B.dmn
+  //
+  // Model Name: Model-B.dmn
+  // Nodes: Input-B
+  // Included Models: [none]
+  //
+  // So, the "Local Model" only "knows" the nodes from "Model-A" and NOT from "Model-B".
+  // That's why we have different logic to build description for "known dmnObjects" and "unknown dmnObjects".
+  const isNamespaceDirectlyIncluded = useMemo(
+    () => namespace === relativeToNamespace || importsByNamespace.has(namespace),
+    [importsByNamespace, namespace, relativeToNamespace]
+  );
+
+  const transitivelyIncludedNamespaceDescription = useMemo(() => {
+    return `${namespace.substring(0, 11)}...${namespace.substring(namespace.length - 4)}`;
+  }, [namespace]);
+
+  const displayName = useMemo(
+    () =>
+      dmnObject && isNamespaceDirectlyIncluded
+        ? buildFeelQNameFromNamespace({
+            namedElement: dmnObject,
+            importsByNamespace,
+            namespace,
+            relativeToNamespace,
+          }).full
+        : dmnObject?.["@_name"],
+    [dmnObject, importsByNamespace, isNamespaceDirectlyIncluded, namespace, relativeToNamespace]
+  );
+
+  const nodeTypeTooltipDescription = useMemo(() => {
+    if (dmnObject === undefined) {
+      throw new Error("nodeTypeDescription can't be defined without a DMN object");
+    }
+    const nodeType = getNodeTypeFromDmnObject(dmnObject);
+    if (nodeType === undefined) {
+      throw new Error("Can't determine nodeTypeDescription with undefined node type");
+    }
+    if (nodeType === NODE_TYPES.decision) {
+      return "Decision";
+    } else if (nodeType === NODE_TYPES.inputData) {
+      return "Input Data";
+    } else {
+      return "Unknown";
+    }
+  }, [dmnObject]);
+
+  const toolTip = useMemo(() => {
+    return dmnObject && isNamespaceDirectlyIncluded ? (
+      <p>{displayName}</p>
+    ) : (
+      <div>{`This ${nodeTypeTooltipDescription} node is from an external model that is not included in this one. Namespace: ${namespace}`}</div>
+    );
+  }, [displayName, dmnObject, isNamespaceDirectlyIncluded, namespace, nodeTypeTooltipDescription]);
 
   const isValid = useDmnEditorStore((s) =>
     DMN15_SPEC.namedElement.isValidName(
@@ -81,32 +139,42 @@ export function DmnObjectListItem({
   return !dmnObject ? (
     <>{dmnObjectHref}</>
   ) : (
-    <Flex
-      alignItems={{ default: "alignItemsCenter" }}
-      justifyContent={{ default: "justifyContentFlexStart" }}
-      spaceItems={{ default: "spaceItemsNone" }}
-    >
-      <div style={{ width: "40px", height: "40px", marginRight: 0 }}>
-        <Icon />
-      </div>
-      <div style={{ color: isValid ? undefined : "red" }}>{`${displayName}`}</div>
-      <div>
-        {dmnObject.__$$element !== "knowledgeSource" ? (
-          <>
-            &nbsp;
-            <TypeRefLabel
-              typeRef={dmnObject.variable?.["@_typeRef"]}
-              relativeToNamespace={namespace}
-              isCollection={
-                allTopLevelDataTypesByFeelName.get(dmnObject.variable?.["@_typeRef"] ?? DmnBuiltInDataType.Undefined)
-                  ?.itemDefinition["@_isCollection"]
-              }
-            />
-          </>
-        ) : (
-          <></>
+    <Tooltip content={toolTip} isContentLeftAligned={true}>
+      <Flex
+        alignItems={{ default: "alignItemsCenter" }}
+        justifyContent={{ default: "justifyContentFlexStart" }}
+        spaceItems={{ default: "spaceItemsNone" }}
+      >
+        <div style={{ width: "40px", height: "40px", marginRight: 0 }}>
+          <Icon />
+        </div>
+        {!isNamespaceDirectlyIncluded && (
+          <div
+            style={{
+              backgroundColor: "#f0f0f0",
+              color: "#6a6e72",
+            }}
+          >{`${transitivelyIncludedNamespaceDescription}.`}</div>
         )}
-      </div>
-    </Flex>
+        <div style={{ color: isValid ? undefined : "red" }}>{`${displayName}`}</div>
+        <div>
+          {dmnObject.__$$element !== "knowledgeSource" ? (
+            <>
+              &nbsp;
+              <TypeRefLabel
+                typeRef={dmnObject.variable?.["@_typeRef"]}
+                relativeToNamespace={namespace}
+                isCollection={
+                  allTopLevelDataTypesByFeelName.get(dmnObject.variable?.["@_typeRef"] ?? DmnBuiltInDataType.Undefined)
+                    ?.itemDefinition["@_isCollection"]
+                }
+              />
+            </>
+          ) : (
+            <></>
+          )}
+        </div>
+      </Flex>
+    </Tooltip>
   );
 }
diff --git a/packages/dmn-editor/src/externalNodes/ExternalNodesPanel.tsx b/packages/dmn-editor/src/externalNodes/ExternalNodesPanel.tsx
index f30a5c7b437..2cb1ceb5dbf 100644
--- a/packages/dmn-editor/src/externalNodes/ExternalNodesPanel.tsx
+++ b/packages/dmn-editor/src/externalNodes/ExternalNodesPanel.tsx
@@ -54,7 +54,7 @@ export function ExternalNodesPanel() {
   const importsByNamespace = useDmnEditorStore((s) => s.computed(s).importsByNamespace());
   const { externalModelsByNamespace } = useExternalModels();
   const externalDmnsByNamespace = useDmnEditorStore(
-    (s) => s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).dmns
+    (s) => s.computed(s).getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns
   );
   const dmnShapesByHref = useDmnEditorStore((s) => s.computed(s).indexedDrd().dmnShapesByHref);
   const { onRequestToResolvePath } = useDmnEditor();
@@ -136,7 +136,7 @@ export function ExternalNodesPanel() {
               const _import = importsByNamespace.get(namespace);
               if (!_import) {
                 console.debug(
-                  `DMN EDITOR: Couldn't find import for namespace '${namespace}', although there's an external DMN referncing it.`
+                  `DMN EDITOR: Couldn't find import for namespace '${namespace}', although there's an external DMN referencing it.`
                 );
                 return [];
               }
@@ -159,6 +159,7 @@ export function ExternalNodesPanel() {
                           externalDrgElementId: drgElement["@_id"]!,
                         })
                       }
+                      data-testid={`kie-tools--dmn-editor--external-node-${_import["@_name"] === "" ? _import["@_id"] : _import["@_name"]}-${drgElement["@_name"]}`}
                     >
                       <Flex
                         alignItems={{ default: "alignItemsCenter" }}
diff --git a/packages/dmn-editor/src/includedModels/IncludedModels.tsx b/packages/dmn-editor/src/includedModels/IncludedModels.tsx
index 6f18ab766d2..cb929054328 100644
--- a/packages/dmn-editor/src/includedModels/IncludedModels.tsx
+++ b/packages/dmn-editor/src/includedModels/IncludedModels.tsx
@@ -251,6 +251,7 @@ export function IncludedModels() {
   return (
     <>
       <Modal
+        data-testid={"kie-tools--dmn-editor--included-models-modal"}
         isOpen={isModalOpen}
         onClose={() => cancel()}
         title={"Include model"}
@@ -466,11 +467,12 @@ function IncludedModelCard({
       dmnEditorStoreApi.setState((state) => {
         const externalModelTypesByNamespace = state
           .computed(state)
-          .getExternalModelTypesByNamespace(externalModelsByNamespace);
+          .getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace);
         deleteImport({
           definitions: state.dmn.model.definitions,
           __readonly_index: index,
           __readonly_externalModelTypesByNamespace: externalModelTypesByNamespace,
+          __readonly_externalModelsByNamespace: externalModelsByNamespace,
         });
       });
     },
diff --git a/packages/dmn-editor/src/mutations/addConnectedNode.ts b/packages/dmn-editor/src/mutations/addConnectedNode.ts
index 75868d7f355..6bd26ba3173 100644
--- a/packages/dmn-editor/src/mutations/addConnectedNode.ts
+++ b/packages/dmn-editor/src/mutations/addConnectedNode.ts
@@ -38,6 +38,7 @@ import { getCentralizedDecisionServiceDividerLine } from "./updateDecisionServic
 import { repopulateInputDataAndDecisionsOnAllDecisionServices } from "./repopulateInputDataAndDecisionsOnDecisionService";
 import { buildXmlHref } from "../xml/xmlHrefs";
 import { Normalized } from "../normalization/normalize";
+import { ExternalModelsIndex } from "../DmnEditor";
 
 export function addConnectedNode({
   definitions,
@@ -45,12 +46,14 @@ export function addConnectedNode({
   sourceNode,
   newNode,
   edgeType,
+  externalModelsByNamespace,
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
   drdIndex: number;
   sourceNode: { type: NodeType; href: string; bounds: DC__Bounds; shapeId: string | undefined };
   newNode: { type: NodeType; bounds: DC__Bounds };
   edgeType: EdgeType;
+  externalModelsByNamespace: ExternalModelsIndex | undefined;
 }) {
   const newDmnObjectId = generateUuid();
   const newDmnObjectHref = buildXmlHref({ id: newDmnObjectId });
@@ -171,7 +174,7 @@ export function addConnectedNode({
     "di:waypoint": [getDmnBoundsCenterPoint(sourceNode.bounds), getDmnBoundsCenterPoint(newNode.bounds)],
   });
 
-  repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions });
+  repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions, externalModelsByNamespace });
 
   return { id: newDmnObjectId, href: newDmnObjectHref };
 }
diff --git a/packages/dmn-editor/src/mutations/addDecisionToDecisionService.ts b/packages/dmn-editor/src/mutations/addDecisionToDecisionService.ts
index 6bd3055581f..18c45243d80 100644
--- a/packages/dmn-editor/src/mutations/addDecisionToDecisionService.ts
+++ b/packages/dmn-editor/src/mutations/addDecisionToDecisionService.ts
@@ -25,25 +25,52 @@ import { SnapGrid } from "../store/Store";
 import { MIN_NODE_SIZES } from "../diagram/nodes/DefaultSizes";
 import { NODE_TYPES } from "../diagram/nodes/NodeTypes";
 import { Normalized } from "../normalization/normalize";
+import { ExternalModelsIndex } from "../DmnEditor";
+import { buildXmlHref, parseXmlHref } from "../xml/xmlHrefs";
+import { DmnLatestModel } from "@kie-tools/dmn-marshaller/dist";
+import { xmlHrefToQName } from "../xml/xmlHrefToQName";
 
 export function addDecisionToDecisionService({
   definitions,
-  decisionId,
+  decisionHref,
   decisionServiceId,
   drdIndex,
   snapGrid,
+  externalModelsByNamespace,
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
-  decisionId: string;
+  decisionHref: string;
   decisionServiceId: string;
   drdIndex: number;
   snapGrid: SnapGrid;
+  externalModelsByNamespace: ExternalModelsIndex | undefined;
 }) {
-  console.debug(`DMN MUTATION: Adding Decision '${decisionId}' to Decision Service '${decisionServiceId}'`);
+  console.debug(`DMN MUTATION: Adding Decision '${decisionHref}' to Decision Service '${decisionServiceId}'`);
 
-  const decision = definitions.drgElement?.find((s) => s["@_id"] === decisionId);
-  if (decision?.__$$element !== "decision") {
-    throw new Error(`DMN MUTATION: DRG Element with id '${decisionId}' is either not a Decision or doesn't exist.`);
+  const href = parseXmlHref(decisionHref);
+
+  if (href.namespace) {
+    const externalModel = externalModelsByNamespace?.[href.namespace];
+    if (!externalModel) {
+      throw new Error(`DMN MUTATION: Namespace '${href.namespace}' not found.`);
+    }
+
+    if (externalModel?.type !== "dmn") {
+      throw new Error(`DMN MUTATION: External model with namespace ${href.namespace} is not a DMN.`);
+    }
+
+    const externalDrgs = externalModel.model.definitions.drgElement;
+    const decision = externalDrgs?.find((drgElement) => drgElement["@_id"] === href.id);
+    if (decision?.__$$element !== "decision") {
+      throw new Error(
+        `DMN MUTATION: DRG Element with id '${href.id}' is either not a Decision or doesn't exist in the external model '${href.namespace}'`
+      );
+    }
+  } else {
+    const decision = definitions.drgElement?.find((s) => s["@_id"] === href.id);
+    if (decision?.__$$element !== "decision") {
+      throw new Error(`DMN MUTATION: DRG Element with id '${href.id}' is either not a Decision or doesn't exist.`);
+    }
   }
 
   const decisionService = definitions.drgElement?.find((s) => s["@_id"] === decisionServiceId);
@@ -54,8 +81,10 @@ export function addDecisionToDecisionService({
   }
 
   const diagram = addOrGetDrd({ definitions, drdIndex });
+  const dmnElementRef = xmlHrefToQName(decisionHref, definitions);
+
   const decisionShape = diagram.diagramElements.find(
-    (s) => s["@_dmnElementRef"] === decisionId && s.__$$element === "dmndi:DMNShape"
+    (s) => s["@_dmnElementRef"] === dmnElementRef && s.__$$element === "dmndi:DMNShape"
   ) as Normalized<DMNDI15__DMNShape>;
 
   const decisionServiceShape = diagram.diagramElements.find(
@@ -65,15 +94,15 @@ export function addDecisionToDecisionService({
   const section = getSectionForDecisionInsideDecisionService({ decisionShape, decisionServiceShape, snapGrid });
   if (section === "encapsulated") {
     decisionService.encapsulatedDecision ??= [];
-    decisionService.encapsulatedDecision.push({ "@_href": `#${decisionId}` });
+    decisionService.encapsulatedDecision.push({ "@_href": `${decisionHref}` });
   } else if (section === "output") {
     decisionService.outputDecision ??= [];
-    decisionService.outputDecision.push({ "@_href": `#${decisionId}` });
+    decisionService.outputDecision.push({ "@_href": `${decisionHref}` });
   } else {
     throw new Error(`DMN MUTATION: Invalid section to add decision to: '${section}' `);
   }
 
-  repopulateInputDataAndDecisionsOnDecisionService({ definitions, decisionService });
+  repopulateInputDataAndDecisionsOnDecisionService({ definitions, decisionService, externalModelsByNamespace });
 }
 
 export function getSectionForDecisionInsideDecisionService({
diff --git a/packages/dmn-editor/src/mutations/addEdge.ts b/packages/dmn-editor/src/mutations/addEdge.ts
index 14e549433f9..7be83b0f2ce 100644
--- a/packages/dmn-editor/src/mutations/addEdge.ts
+++ b/packages/dmn-editor/src/mutations/addEdge.ts
@@ -41,6 +41,7 @@ import { repopulateInputDataAndDecisionsOnAllDecisionServices } from "./repopula
 import { DmnDiagramNodeData } from "../diagram/nodes/Nodes";
 import { AutoPositionedEdgeMarker } from "../diagram/edges/AutoPositionedEdgeMarker";
 import { Normalized } from "../normalization/normalize";
+import { ExternalModelsIndex } from "../DmnEditor";
 
 export function addEdge({
   definitions,
@@ -49,6 +50,7 @@ export function addEdge({
   targetNode,
   edge,
   keepWaypoints,
+  externalModelsByNamespace,
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
   drdIndex: number;
@@ -74,6 +76,7 @@ export function addEdge({
     autoPositionedEdgeMarker: AutoPositionedEdgeMarker | undefined;
   };
   keepWaypoints: boolean;
+  externalModelsByNamespace: ExternalModelsIndex | undefined;
 }) {
   if (!_checkIsValidConnection(sourceNode, targetNode, edge.type)) {
     throw new Error(`DMN MUTATION: Invalid structure: (${sourceNode.type}) --${edge.type}--> (${targetNode.type}) `);
@@ -188,7 +191,10 @@ export function addEdge({
   // Replace with the new one.
   diagramElements.push(newDmnEdge);
 
-  repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions });
+  repopulateInputDataAndDecisionsOnAllDecisionServices({
+    definitions,
+    externalModelsByNamespace,
+  });
 
   return { newDmnEdge };
 }
@@ -229,6 +235,7 @@ function removeFirstMatchIfPresent<T>(arr: T[], predicate: Parameters<Array<T>["
 function tryKeepingEdgeId(existingEdgeId: string | undefined, newEdgeId: string) {
   return existingEdgeId ?? newEdgeId;
 }
+
 function withoutDiscreteAutoPosinitioningMarker(edgeId: string) {
   const marker = getDiscreteAutoPositioningEdgeIdMarker(edgeId);
   return marker ? edgeId.replace(`${marker}`, "") : edgeId;
diff --git a/packages/dmn-editor/src/mutations/addExistingDecisionServiceToDrd.ts b/packages/dmn-editor/src/mutations/addExistingDecisionServiceToDrd.ts
index 84817732264..dd7ab5281a9 100644
--- a/packages/dmn-editor/src/mutations/addExistingDecisionServiceToDrd.ts
+++ b/packages/dmn-editor/src/mutations/addExistingDecisionServiceToDrd.ts
@@ -30,7 +30,7 @@ import { Normalized } from "../normalization/normalize";
 import { Computed, SnapGrid, State } from "../store/Store";
 import { computeContainingDecisionServiceHrefsByDecisionHrefs } from "../store/computed/computeContainingDecisionServiceHrefsByDecisionHrefs.ts";
 import { computeDiagramData } from "../store/computed/computeDiagramData";
-import { computeExternalModelsByType } from "../store/computed/computeExternalModelsByType";
+import { computeDirectlyIncludedExternalModelsByNamespace } from "../store/computed/computeDirectlyIncludedExternalModelsByNamespace";
 import { computeIndexedDrd } from "../store/computed/computeIndexes";
 import { xmlHrefToQName } from "../xml/xmlHrefToQName";
 import { buildXmlHref, parseXmlHref } from "../xml/xmlHrefs";
@@ -66,7 +66,7 @@ export function getStrategyToAddExistingDecisionServiceToDrd({
   __readonly_definitions: Normalized<DMN15__tDefinitions>;
   __readonly_decisionServiceNamespace: string;
   __readonly_drgElement: Normalized<DMN15__tDecisionService>;
-  __readonly_externalDmnsIndex: ReturnType<Computed["getExternalModelTypesByNamespace"]>["dmns"];
+  __readonly_externalDmnsIndex: ReturnType<Computed["getDirectlyIncludedExternalModelsByNamespace"]>["dmns"];
   __readonly_namespace: string;
   __readonly_indexedDrd: ReturnType<Computed["indexedDrd"]>;
   __readonly_drdIndex: number;
@@ -92,11 +92,15 @@ export function getStrategyToAddExistingDecisionServiceToDrd({
     id: __readonly_drgElement["@_id"]!,
   });
 
+  const drgElementsByNamespace = new Map([[__readonly_namespace, __readonly_definitions.drgElement]]);
+  __readonly_externalDmnsIndex.forEach((value, key) => {
+    drgElementsByNamespace.set(key, value.model.definitions.drgElement);
+  });
+
   const containingDecisionServiceHrefsByDecisionHrefsRelativeToThisDmn =
     computeContainingDecisionServiceHrefsByDecisionHrefs({
       thisDmnsNamespace: __readonly_namespace,
-      drgElementsNamespace: __readonly_decisionServiceNamespace,
-      drgElements: decisionServiceDmnDefinitions.drgElement,
+      drgElementsByNamespace,
     });
 
   const doesThisDrdHaveConflictingDecisionService = containedDecisionHrefsRelativeToThisDmn.some((decisionHref) =>
@@ -195,7 +199,7 @@ export async function addAutoGeneratedDecisionServiceToDrd({
 }: {
   state: State;
   __readonly_decisionServiceNamespace: string;
-  __readonly_externalDmnsIndex: ReturnType<Computed["getExternalModelTypesByNamespace"]>["dmns"];
+  __readonly_externalDmnsIndex: ReturnType<Computed["getDirectlyIncludedExternalModelsByNamespace"]>["dmns"];
   __readonly_drdIndex: number;
   __readonly_snapGrid: SnapGrid;
   __readonly_decisionServiceHrefRelativeToThisDmn: string;
@@ -265,7 +269,7 @@ export async function addAutoGeneratedDecisionServiceToDrd({
   }
 
   // Compute the external model types by namespace after autogenerating the Decision Service
-  const externalModelTypesByNamespace = computeExternalModelsByType(
+  const externalModelTypesByNamespace = computeDirectlyIncludedExternalModelsByNamespace(
     state.dmn.model.definitions.import,
     __readonly_externalModelsByNamespace
   );
@@ -308,6 +312,7 @@ export async function addAutoGeneratedDecisionServiceToDrd({
     __readonly_drdIndex: dummyDrdIndex,
     __readonly_dmnObjectNamespace: __readonly_decisionServiceNamespace,
     __readonly_externalDmnsIndex: externalModelTypesByNamespace.dmns,
+    __readonly_externalModelsByNamespace,
   });
 
   // Save DS shape before applying the autolayout
@@ -390,7 +395,7 @@ export function addExistingDecisionServiceToDrd({
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
   __readonly_decisionServiceNamespace: string;
-  __readonly_externalDmnsIndex: ReturnType<Computed["getExternalModelTypesByNamespace"]>["dmns"];
+  __readonly_externalDmnsIndex: ReturnType<Computed["getDirectlyIncludedExternalModelsByNamespace"]>["dmns"];
   __readonly_namespace: string;
   __readonly_indexedDrd: ReturnType<Computed["indexedDrd"]>;
   __readonly_indexedDrdContainingDecisionServiceDepiction: ReturnType<Computed["indexedDrd"]>;
diff --git a/packages/dmn-editor/src/mutations/addStandaloneNode.ts b/packages/dmn-editor/src/mutations/addStandaloneNode.ts
index 2b348f07def..aad8ac660df 100644
--- a/packages/dmn-editor/src/mutations/addStandaloneNode.ts
+++ b/packages/dmn-editor/src/mutations/addStandaloneNode.ts
@@ -28,15 +28,18 @@ import { getCentralizedDecisionServiceDividerLine } from "./updateDecisionServic
 import { repopulateInputDataAndDecisionsOnAllDecisionServices } from "./repopulateInputDataAndDecisionsOnDecisionService";
 import { buildXmlHref } from "../xml/xmlHrefs";
 import { Normalized } from "../normalization/normalize";
+import { ExternalModelsIndex } from "../DmnEditor";
 
 export function addStandaloneNode({
   definitions,
   drdIndex,
   newNode,
+  externalModelsByNamespace,
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
   drdIndex: number;
   newNode: { type: NodeType; bounds: DC__Bounds };
+  externalModelsByNamespace: ExternalModelsIndex | undefined;
 }) {
   const newNodeId = generateUuid();
   const nature = nodeNatures[newNode.type];
@@ -133,7 +136,7 @@ export function addStandaloneNode({
       : {}),
   });
 
-  repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions });
+  repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions, externalModelsByNamespace });
 
   return { id: newNodeId, href: buildXmlHref({ id: newNodeId }), shapeId };
 }
diff --git a/packages/dmn-editor/src/mutations/applyAutoLayoutToDrd.ts b/packages/dmn-editor/src/mutations/applyAutoLayoutToDrd.ts
index 0f3786a1b83..baf78e2994e 100644
--- a/packages/dmn-editor/src/mutations/applyAutoLayoutToDrd.ts
+++ b/packages/dmn-editor/src/mutations/applyAutoLayoutToDrd.ts
@@ -33,7 +33,7 @@ import { updateDecisionServiceDividerLine } from "../mutations/updateDecisionSer
 import { Normalized } from "../normalization/normalize";
 import { State } from "../store/Store";
 import { AutolayoutParentNode, FAKE_MARKER, visitNodeAndNested } from "../autolayout/autoLayoutInfo";
-import { ExternalDmnsIndex } from "../DmnEditor";
+import { ExternalDmnsIndex, ExternalModelsIndex } from "../DmnEditor";
 
 export function applyAutoLayoutToDrd({
   state,
@@ -46,6 +46,7 @@ export function applyAutoLayoutToDrd({
   __readonly_drdIndex,
   __readonly_dmnObjectNamespace,
   __readonly_externalDmnsIndex,
+  __readonly_externalModelsByNamespace,
 }: {
   state: State;
   __readonly_autoLayoutedInfo: {
@@ -67,6 +68,7 @@ export function applyAutoLayoutToDrd({
   __readonly_drdIndex: number;
   __readonly_dmnObjectNamespace: string | undefined;
   __readonly_externalDmnsIndex: ExternalDmnsIndex;
+  __readonly_externalModelsByNamespace: ExternalModelsIndex | undefined;
 }) {
   // 7. Update all nodes positions skipping empty groups, which will be positioned manually after all nodes are done being repositioned.
   const autolayoutedElkNodesById = new Map<string, Elk.ElkNode>();
@@ -220,6 +222,7 @@ export function applyAutoLayoutToDrd({
         shapeId: targetNode.data.shape["@_id"],
       },
       keepWaypoints: false,
+      externalModelsByNamespace: __readonly_externalModelsByNamespace,
     });
   }
 }
diff --git a/packages/dmn-editor/src/mutations/deleteDecisionFromDecisionService.ts b/packages/dmn-editor/src/mutations/deleteDecisionFromDecisionService.ts
index cb9e1273299..81f09c3c518 100644
--- a/packages/dmn-editor/src/mutations/deleteDecisionFromDecisionService.ts
+++ b/packages/dmn-editor/src/mutations/deleteDecisionFromDecisionService.ts
@@ -20,21 +20,45 @@
 import { DMN15__tDefinitions } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { repopulateInputDataAndDecisionsOnDecisionService } from "./repopulateInputDataAndDecisionsOnDecisionService";
 import { Normalized } from "../normalization/normalize";
+import { buildXmlHref, parseXmlHref } from "../xml/xmlHrefs";
+import { ExternalModelsIndex } from "../DmnEditor";
 
 export function deleteDecisionFromDecisionService({
   definitions,
-  decisionId,
+  decisionHref,
   decisionServiceId,
+  externalModelsByNamespace,
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
-  decisionId: string;
+  decisionHref: string;
   decisionServiceId: string;
+  externalModelsByNamespace: ExternalModelsIndex | undefined;
 }) {
-  console.debug(`DMN MUTATION: Deleting Decision '${decisionId}' from Decision Service '${decisionServiceId}'`);
+  console.debug(`DMN MUTATION: Deleting Decision '${decisionHref}' from Decision Service '${decisionServiceId}'`);
 
-  const decision = definitions.drgElement?.find((s) => s["@_id"] === decisionId);
-  if (decision?.__$$element !== "decision") {
-    throw new Error(`DMN MUTATION: DRG Element with id '${decisionId}' is either not a Decision or doesn't exist.`);
+  const href = parseXmlHref(decisionHref);
+  if (href.namespace) {
+    const externalModel = externalModelsByNamespace?.[href.namespace];
+    if (!externalModel) {
+      throw new Error(`DMN MUTATION: Namespace '${href.namespace}' not found.`);
+    }
+
+    if (externalModel?.type !== "dmn") {
+      throw new Error(`DMN MUTATION: External model with namespace ${href.namespace} is not a DMN.`);
+    }
+
+    const externalDrgs = externalModel.model.definitions.drgElement;
+    const decision = externalDrgs?.find((drgElement) => drgElement["@_id"] === href.id);
+    if (decision?.__$$element !== "decision") {
+      throw new Error(
+        `DMN MUTATION: DRG Element with id '${href.id}' is either not a Decision or doesn't exist in the external model '${href.namespace}'`
+      );
+    }
+  } else {
+    const decision = definitions.drgElement?.find((s) => s["@_id"] === href.id);
+    if (decision?.__$$element !== "decision") {
+      throw new Error(`DMN MUTATION: DRG Element with id '${href.id}' is either not a Decision or doesn't exist.`);
+    }
   }
 
   const decisionService = definitions.drgElement?.find((s) => s["@_id"] === decisionServiceId);
@@ -44,12 +68,10 @@ export function deleteDecisionFromDecisionService({
     );
   }
 
-  decisionService.outputDecision = (decisionService.outputDecision ?? []).filter(
-    (s) => s["@_href"] !== `#${decisionId}`
-  );
+  decisionService.outputDecision = (decisionService.outputDecision ?? []).filter((od) => od["@_href"] !== decisionHref);
   decisionService.encapsulatedDecision = (decisionService.encapsulatedDecision ?? []).filter(
-    (s) => s["@_href"] !== `#${decisionId}`
+    (ed) => ed["@_href"] !== decisionHref
   );
 
-  repopulateInputDataAndDecisionsOnDecisionService({ definitions, decisionService });
+  repopulateInputDataAndDecisionsOnDecisionService({ definitions, decisionService, externalModelsByNamespace });
 }
diff --git a/packages/dmn-editor/src/mutations/deleteEdge.ts b/packages/dmn-editor/src/mutations/deleteEdge.ts
index 3cc43c8126c..58a3af9e627 100644
--- a/packages/dmn-editor/src/mutations/deleteEdge.ts
+++ b/packages/dmn-editor/src/mutations/deleteEdge.ts
@@ -27,6 +27,7 @@ import { addOrGetDrd } from "./addOrGetDrd";
 import { DmnDiagramEdgeData } from "../diagram/edges/Edges";
 import { repopulateInputDataAndDecisionsOnAllDecisionServices } from "./repopulateInputDataAndDecisionsOnDecisionService";
 import { Normalized } from "../normalization/normalize";
+import { ExternalModelsIndex } from "../DmnEditor";
 
 export enum EdgeDeletionMode {
   FROM_DRG_AND_ALL_DRDS,
@@ -38,11 +39,13 @@ export function deleteEdge({
   drdIndex,
   edge,
   mode,
+  externalModelsByNamespace,
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
   drdIndex: number;
   edge: { id: string; dmnObject: DmnDiagramEdgeData["dmnObject"] };
   mode: EdgeDeletionMode;
+  externalModelsByNamespace: ExternalModelsIndex | undefined;
 }) {
   if (edge.dmnObject.namespace !== definitions["@_namespace"]) {
     console.debug("DMN MUTATION: Can't delete an edge that's from an external node.");
@@ -99,7 +102,7 @@ export function deleteEdge({
     }
   }
 
-  repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions });
+  repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions, externalModelsByNamespace });
 
   return { deletedDmnEdgeOnCurrentDrd };
 }
diff --git a/packages/dmn-editor/src/mutations/deleteImport.ts b/packages/dmn-editor/src/mutations/deleteImport.ts
index 34aa40bcc7a..4195c39afa2 100644
--- a/packages/dmn-editor/src/mutations/deleteImport.ts
+++ b/packages/dmn-editor/src/mutations/deleteImport.ts
@@ -28,15 +28,18 @@ import { deleteEdge, EdgeDeletionMode } from "./deleteEdge";
 import { computeIndexedDrd } from "../store/computed/computeIndexes";
 import { Computed, defaultStaticState } from "../store/Store";
 import { TypeOrReturnType } from "../store/ComputedStateCache";
+import { ExternalModelsIndex } from "../DmnEditor";
 
 export function deleteImport({
   definitions,
   __readonly_index,
   __readonly_externalModelTypesByNamespace,
+  __readonly_externalModelsByNamespace,
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
   __readonly_index: number;
-  __readonly_externalModelTypesByNamespace: TypeOrReturnType<Computed["getExternalModelTypesByNamespace"]>;
+  __readonly_externalModelTypesByNamespace: TypeOrReturnType<Computed["getDirectlyIncludedExternalModelsByNamespace"]>;
+  __readonly_externalModelsByNamespace: ExternalModelsIndex | undefined;
 }) {
   definitions.import ??= [];
   const [deletedImport] = definitions.import.splice(__readonly_index, 1);
@@ -67,8 +70,9 @@ export function deleteImport({
         __readonly_dmnObjectId: node.data.dmnObject?.["@_id"],
         __readonly_dmnObjectQName: node.data.dmnObjectQName,
         __readonly_dmnObjectNamespace: node.data.dmnObjectNamespace!,
-        __readonly_externalModelTypesByNamespace,
-        mode: NodeDeletionMode.FROM_DRG_AND_ALL_DRDS,
+        __readonly_externalDmnsIndex: __readonly_externalModelTypesByNamespace.dmns,
+        __readonly_mode: NodeDeletionMode.FROM_DRG_AND_ALL_DRDS,
+        __readonly_externalModelsByNamespace,
       });
     });
 
@@ -78,6 +82,7 @@ export function deleteImport({
         drdIndex: 0,
         edge: { id: edge.id, dmnObject: edge.data!.dmnObject },
         mode: EdgeDeletionMode.FROM_DRG_AND_ALL_DRDS,
+        externalModelsByNamespace: __readonly_externalModelsByNamespace,
       });
     });
   });
diff --git a/packages/dmn-editor/src/mutations/deleteNode.ts b/packages/dmn-editor/src/mutations/deleteNode.ts
index 5f4affe9fa4..5782ec13b86 100644
--- a/packages/dmn-editor/src/mutations/deleteNode.ts
+++ b/packages/dmn-editor/src/mutations/deleteNode.ts
@@ -31,7 +31,7 @@ import { Computed } from "../store/Store";
 import { computeContainingDecisionServiceHrefsByDecisionHrefs } from "../store/computed/computeContainingDecisionServiceHrefsByDecisionHrefs.ts";
 import { xmlHrefToQName } from "../xml/xmlHrefToQName";
 import { Normalized } from "../normalization/normalize";
-import { NodeDmnObjects } from "../diagram/nodes/Nodes";
+import { ExternalDmnsIndex, ExternalModelsIndex } from "../DmnEditor";
 
 export enum NodeDeletionMode {
   FROM_DRG_AND_ALL_DRDS,
@@ -46,37 +46,52 @@ export function deleteNode({
   __readonly_dmnObjectId,
   __readonly_dmnObjectNamespace,
   __readonly_dmnObjectQName,
-  __readonly_externalModelTypesByNamespace,
-  mode,
+  __readonly_externalDmnsIndex,
+  __readonly_mode,
+  __readonly_externalModelsByNamespace,
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
   __readonly_drgEdges: DrgEdge[];
   __readonly_drdIndex: number;
   __readonly_nodeNature: NodeNature;
-  __readonly_externalModelTypesByNamespace: ReturnType<Computed["getExternalModelTypesByNamespace"]>;
+  __readonly_externalDmnsIndex: ExternalDmnsIndex;
   __readonly_dmnObjectId: string | undefined;
   __readonly_dmnObjectNamespace: string;
   __readonly_dmnObjectQName: XmlQName;
-  mode: NodeDeletionMode;
+  __readonly_mode: NodeDeletionMode;
+  __readonly_externalModelsByNamespace: ExternalModelsIndex | undefined;
 }): {
   deletedDmnObject: Unpacked<Normalized<DMN15__tDefinitions>["drgElement" | "artifact"]> | undefined;
   deletedDmnShapeOnCurrentDrd: Normalized<DMNDI15__DMNShape> | undefined;
 } {
   if (
-    mode === NodeDeletionMode.FROM_CURRENT_DRD_ONLY &&
+    __readonly_mode === NodeDeletionMode.FROM_CURRENT_DRD_ONLY &&
     !canRemoveNodeFromDrdOnly({
       definitions,
       __readonly_drdIndex,
       __readonly_dmnObjectNamespace,
       __readonly_dmnObjectId,
-      __readonly_externalDmnsIndex: __readonly_externalModelTypesByNamespace.dmns,
+      __readonly_externalDmnsIndex,
     })
   ) {
     console.warn("DMN MUTATION: Cannot hide a Decision that's contained by a Decision Service from a DRD.");
     return { deletedDmnObject: undefined, deletedDmnShapeOnCurrentDrd: undefined };
   }
 
-  if (mode === NodeDeletionMode.FROM_DRG_AND_ALL_DRDS) {
+  if (
+    !isContainedInAnExternalExpandedDecisionService({
+      definitions,
+      __readonly_drdIndex,
+      __readonly_dmnObjectNamespace,
+      __readonly_dmnObjectId,
+      __readonly_externalDmnsIndex,
+    })
+  ) {
+    console.warn("DMN MUTATION: Cannot delete a Decision that's contained by a expanded external Decision Service.");
+    return { deletedDmnObject: undefined, deletedDmnShapeOnCurrentDrd: undefined };
+  }
+
+  if (__readonly_mode === NodeDeletionMode.FROM_DRG_AND_ALL_DRDS) {
     // Delete Edges
     // A DRD doesn't necessarily renders all edges of the DRG, so we need to look for what DRG edges to delete when deleting a node from any DRD.
     const nodeId = buildXmlHref({
@@ -96,6 +111,7 @@ export function deleteNode({
             id: drgEdge.id,
             dmnObject: drgEdge.dmnObject,
           },
+          externalModelsByNamespace: __readonly_externalModelsByNamespace,
         });
       }
     }
@@ -119,7 +135,7 @@ export function deleteNode({
   if (!__readonly_dmnObjectQName.prefix) {
     // Delete the dmnObject itself
     if (__readonly_nodeNature === NodeNature.ARTIFACT) {
-      if (mode === NodeDeletionMode.FROM_DRG_AND_ALL_DRDS) {
+      if (__readonly_mode === NodeDeletionMode.FROM_DRG_AND_ALL_DRDS) {
         const nodeIndex = (definitions.artifact ?? []).findIndex((a) => a["@_id"] === __readonly_dmnObjectId);
         deletedDmnObject = definitions.artifact?.splice(nodeIndex, 1)?.[0];
       } else {
@@ -128,7 +144,7 @@ export function deleteNode({
     } else if (__readonly_nodeNature === NodeNature.DRG_ELEMENT) {
       const nodeIndex = (definitions.drgElement ?? []).findIndex((d) => d["@_id"] === __readonly_dmnObjectId);
       deletedDmnObject =
-        mode === NodeDeletionMode.FROM_DRG_AND_ALL_DRDS
+        __readonly_mode === NodeDeletionMode.FROM_DRG_AND_ALL_DRDS
           ? definitions.drgElement?.splice(nodeIndex, 1)?.[0]
           : definitions.drgElement?.[nodeIndex];
     } else if (__readonly_nodeNature === NodeNature.UNKNOWN) {
@@ -160,7 +176,7 @@ export function deleteNode({
 
   const drdCount = (definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"] ?? []).length;
   for (let i = 0; i < drdCount; i++) {
-    if (mode === NodeDeletionMode.FROM_CURRENT_DRD_ONLY && i !== __readonly_drdIndex) {
+    if (__readonly_mode === NodeDeletionMode.FROM_CURRENT_DRD_ONLY && i !== __readonly_drdIndex) {
       continue;
     }
 
@@ -180,14 +196,62 @@ export function deleteNode({
     );
   }
 
-  repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions });
+  repopulateInputDataAndDecisionsOnAllDecisionServices({
+    definitions,
+    externalModelsByNamespace: __readonly_externalModelsByNamespace,
+  });
 
   return {
-    deletedDmnObject: mode === NodeDeletionMode.FROM_DRG_AND_ALL_DRDS ? deletedDmnObject : undefined,
+    deletedDmnObject: __readonly_mode === NodeDeletionMode.FROM_DRG_AND_ALL_DRDS ? deletedDmnObject : undefined,
     deletedDmnShapeOnCurrentDrd,
   };
 }
 
+export function isContainedInAnExternalExpandedDecisionService({
+  definitions,
+  __readonly_drdIndex,
+  __readonly_dmnObjectNamespace,
+  __readonly_dmnObjectId,
+  __readonly_externalDmnsIndex,
+}: {
+  definitions: Normalized<DMN15__tDefinitions>;
+  __readonly_dmnObjectNamespace: string;
+  __readonly_dmnObjectId: string | undefined;
+  __readonly_drdIndex: number;
+  __readonly_externalDmnsIndex: ReturnType<Computed["getDirectlyIncludedExternalModelsByNamespace"]>["dmns"];
+}) {
+  const { diagramElements } = addOrGetDrd({ definitions, drdIndex: __readonly_drdIndex });
+
+  const dmnObjectHref = buildXmlHref({
+    namespace: __readonly_dmnObjectNamespace === definitions["@_namespace"] ? undefined : __readonly_dmnObjectNamespace,
+    id: __readonly_dmnObjectId!,
+  });
+
+  const drgElementsByNamespace = new Map();
+  __readonly_externalDmnsIndex.forEach((value, key) => {
+    drgElementsByNamespace.set(key, value.model.definitions.drgElement);
+  });
+
+  const containingDecisionServiceHrefsByDecisionHrefsRelativeToThisDmn =
+    computeContainingDecisionServiceHrefsByDecisionHrefs({
+      thisDmnsNamespace: definitions["@_namespace"],
+      drgElementsByNamespace,
+    });
+
+  const isContainingDecisionServiceInExpandedFormPresentInTheDrd = (
+    containingDecisionServiceHrefsByDecisionHrefsRelativeToThisDmn.get(dmnObjectHref) ?? []
+  ).some((dsHref) =>
+    diagramElements.some(
+      (e) =>
+        e.__$$element === "dmndi:DMNShape" &&
+        e["@_dmnElementRef"] === xmlHrefToQName(dsHref, definitions) &&
+        !(e["@_isCollapsed"] ?? false)
+    )
+  );
+
+  return !isContainingDecisionServiceInExpandedFormPresentInTheDrd;
+}
+
 export function canRemoveNodeFromDrdOnly({
   definitions,
   __readonly_drdIndex,
@@ -199,7 +263,7 @@ export function canRemoveNodeFromDrdOnly({
   __readonly_dmnObjectNamespace: string;
   __readonly_dmnObjectId: string | undefined;
   __readonly_drdIndex: number;
-  __readonly_externalDmnsIndex: ReturnType<Computed["getExternalModelTypesByNamespace"]>["dmns"];
+  __readonly_externalDmnsIndex: ReturnType<Computed["getDirectlyIncludedExternalModelsByNamespace"]>["dmns"];
 }) {
   const { diagramElements } = addOrGetDrd({ definitions, drdIndex: __readonly_drdIndex });
 
@@ -208,16 +272,15 @@ export function canRemoveNodeFromDrdOnly({
     id: __readonly_dmnObjectId!,
   });
 
-  const drgElements =
-    definitions["@_namespace"] === __readonly_dmnObjectNamespace
-      ? definitions.drgElement ?? []
-      : __readonly_externalDmnsIndex.get(__readonly_dmnObjectNamespace)?.model.definitions.drgElement ?? [];
+  const drgElementsByNamespace = new Map([[definitions["@_namespace"], definitions.drgElement]]);
+  __readonly_externalDmnsIndex.forEach((value, key) => {
+    drgElementsByNamespace.set(key, value.model.definitions.drgElement);
+  });
 
   const containingDecisionServiceHrefsByDecisionHrefsRelativeToThisDmn =
     computeContainingDecisionServiceHrefsByDecisionHrefs({
       thisDmnsNamespace: definitions["@_namespace"],
-      drgElementsNamespace: __readonly_dmnObjectNamespace,
-      drgElements,
+      drgElementsByNamespace,
     });
 
   const containingDecisionServiceHrefs =
diff --git a/packages/dmn-editor/src/mutations/repopulateInputDataAndDecisionsOnDecisionService.ts b/packages/dmn-editor/src/mutations/repopulateInputDataAndDecisionsOnDecisionService.ts
index 3b5bb781e1b..35f4e6c2102 100644
--- a/packages/dmn-editor/src/mutations/repopulateInputDataAndDecisionsOnDecisionService.ts
+++ b/packages/dmn-editor/src/mutations/repopulateInputDataAndDecisionsOnDecisionService.ts
@@ -22,11 +22,15 @@ import {
   DMN15__tDefinitions,
 } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { Normalized } from "../normalization/normalize";
+import { ExternalModelsIndex } from "../DmnEditor";
+import { buildXmlHref, parseXmlHref } from "../xml/xmlHrefs";
 
 export function repopulateInputDataAndDecisionsOnAllDecisionServices({
   definitions,
+  externalModelsByNamespace,
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
+  externalModelsByNamespace: ExternalModelsIndex | undefined;
 }) {
   for (let i = 0; i < (definitions.drgElement ?? []).length; i++) {
     const drgElement = definitions.drgElement![i];
@@ -34,6 +38,7 @@ export function repopulateInputDataAndDecisionsOnAllDecisionServices({
       repopulateInputDataAndDecisionsOnDecisionService({
         definitions,
         decisionService: drgElement,
+        externalModelsByNamespace,
       });
     }
   }
@@ -42,9 +47,11 @@ export function repopulateInputDataAndDecisionsOnAllDecisionServices({
 export function repopulateInputDataAndDecisionsOnDecisionService({
   definitions,
   decisionService,
+  externalModelsByNamespace,
 }: {
   definitions: Normalized<DMN15__tDefinitions>;
   decisionService: Normalized<DMN15__tDecisionService>;
+  externalModelsByNamespace: ExternalModelsIndex | undefined;
 }) {
   // Save previous values to preserve order
   const inputDatas = new Set<string>([...(decisionService.inputData ?? [])].map((e) => e["@_href"])); // Using Set for uniqueness
@@ -59,21 +66,75 @@ export function repopulateInputDataAndDecisionsOnDecisionService({
     ...(decisionService.encapsulatedDecision ?? []).map((s) => s["@_href"]),
   ]);
 
-  // Map all DS Input Data and Decision requirements to their href
+  /** Map all DS Input Data and Decision requirements to their href */
   const requirements = new Map<string, "decisionIr" | "inputDataIr">();
-  for (let i = 0; i < definitions.drgElement!.length; i++) {
-    const drgElement = definitions.drgElement![i];
-    if (!hrefsToDecisionsInsideDecisionService.has(`#${drgElement["@_id"]}`) || drgElement.__$$element !== "decision") {
-      continue;
+
+  for (const decisionHrefString of hrefsToDecisionsInsideDecisionService) {
+    const decisionHref = parseXmlHref(decisionHrefString);
+
+    // local decision
+    if (!decisionHref.namespace || decisionHref.namespace === definitions["@_namespace"]) {
+      const localDecision = definitions.drgElement?.find((drgElement) => drgElement["@_id"] === decisionHref.id);
+      if (localDecision?.__$$element !== "decision") {
+        throw new Error(`DMN MUTATION: Node inside Decision Service is not a Decision. ID: ${localDecision?.["@_id"]}`);
+      }
+
+      (localDecision.informationRequirement ?? []).forEach((ir) => {
+        if (ir.requiredDecision) {
+          requirements.set(ir.requiredDecision["@_href"], "decisionIr");
+        } else if (ir.requiredInput) {
+          requirements.set(ir.requiredInput["@_href"], "inputDataIr");
+        }
+      });
     }
+    // external decision
+    else {
+      const externalModel = externalModelsByNamespace?.[decisionHref.namespace];
+      if (externalModel?.type !== "dmn") {
+        throw new Error(`DMN MUTATION: External model with namespace ${decisionHref.namespace} is not a DMN.`);
+      }
 
-    (drgElement.informationRequirement ?? []).flatMap((ir) => {
-      if (ir.requiredDecision) {
-        requirements.set(ir.requiredDecision["@_href"], "decisionIr");
-      } else if (ir.requiredInput) {
-        requirements.set(ir.requiredInput["@_href"], "inputDataIr");
+      const externalDecision = externalModel.model.definitions.drgElement?.find(
+        (drgElement) => drgElement["@_id"] === decisionHref.id
+      );
+      if (externalDecision?.__$$element !== "decision") {
+        throw new Error(
+          `DMN MUTATION: Node inside Decision Service is not a Decision. ID: ${externalDecision?.["@_id"]}`
+        );
       }
-    });
+
+      (externalDecision.informationRequirement ?? []).forEach((ir) => {
+        if (ir.requiredDecision) {
+          const requirementHref = parseXmlHref(ir.requiredDecision["@_href"]);
+          // If the requiredDecision has namespace, it means that it is pointing to a node in a 3rd model,
+          // not this one (the local model) neither the model in the `href.namespace`.
+          if (requirementHref.namespace) {
+            requirements.set(ir.requiredDecision["@_href"], "decisionIr");
+          } else {
+            requirements.set(
+              buildXmlHref({ namespace: externalModel.model.definitions["@_namespace"], id: requirementHref.id }),
+              "decisionIr"
+            );
+          }
+        } else if (ir.requiredInput) {
+          // If the requiredInput has namespace, it means that it is pointing to a node in a 3rd model,
+          // not this one (the local model) neither the model in the `href.namespace`.
+          const requirementHref = parseXmlHref(ir.requiredInput["@_href"]);
+          if (requirementHref.namespace) {
+            requirements.set(ir.requiredInput["@_href"], "inputDataIr");
+          } else {
+            requirements.set(
+              buildXmlHref({ namespace: externalModel.model.definitions["@_namespace"], id: requirementHref.id }),
+              "inputDataIr"
+            );
+          }
+        } else {
+          throw new Error(
+            `DMN MUTATION: Invalid information requirement referenced by external DecisionService: '${externalDecision["@_id"]}'`
+          );
+        }
+      });
+    }
   }
 
   // START - Remove outdated requirements
diff --git a/packages/dmn-editor/src/normalization/autoGenerateDrd.ts b/packages/dmn-editor/src/normalization/autoGenerateDrd.ts
index 2053b0c7f9f..5b2ef11a65e 100644
--- a/packages/dmn-editor/src/normalization/autoGenerateDrd.ts
+++ b/packages/dmn-editor/src/normalization/autoGenerateDrd.ts
@@ -206,6 +206,7 @@ export async function autoGenerateDrd(args: {
         index: targetNode.data.index,
         shapeId: targetNode.data.shape["@_id"],
       },
+      externalModelsByNamespace: args.externalModelsByNamespace,
     });
   }
 }
diff --git a/packages/dmn-editor/src/propertiesPanel/DecisionServiceProperties.tsx b/packages/dmn-editor/src/propertiesPanel/DecisionServiceProperties.tsx
index 21f29fed530..39822a2f402 100644
--- a/packages/dmn-editor/src/propertiesPanel/DecisionServiceProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/DecisionServiceProperties.tsx
@@ -23,6 +23,7 @@ import {
   DMN15__tDecision,
   DMN15__tDecisionService,
   DMN15__tInputData,
+  DMN15__tDefinitions,
 } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { ClipboardCopy } from "@patternfly/react-core/dist/js/components/ClipboardCopy";
 import { FormGroup } from "@patternfly/react-core/dist/js/components/Form";
@@ -44,6 +45,8 @@ import { buildFeelQNameFromNamespace } from "../feel/buildFeelQName";
 import { Alert, AlertVariant } from "@patternfly/react-core/dist/js/components/Alert/Alert";
 import { Normalized } from "../normalization/normalize";
 import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
+import { ExternalDmn } from "../DmnEditor";
+import { Unpacked } from "../tsExt/tsExt";
 import { useSettings } from "../settings/DmnEditorSettingsContext";
 
 export type AllKnownDrgElementsByHref = Map<
@@ -66,14 +69,24 @@ export function DecisionServiceProperties({
 
   const thisDmn = useDmnEditorStore((s) => s.dmn);
   const { externalModelsByNamespace } = useExternalModels();
-  const externalDmnsByNamespace = useDmnEditorStore(
-    (s) => s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).dmns
-  );
+
+  const allExternalDmns = Object.entries(externalModelsByNamespace ?? {}).reduce((acc, [namespace, externalModel]) => {
+    if (!externalModel) {
+      console.warn(`DMN EDITOR: Could not find model with namespace '${namespace}'. Ignoring.`);
+      return acc;
+    }
+
+    if (externalModel.type === "dmn") {
+      acc.push(externalModel);
+    }
+
+    return acc;
+  }, new Array<Normalized<ExternalDmn>>());
 
   const allDrgElementsByHref = useMemo(() => {
     const ret: AllKnownDrgElementsByHref = new Map();
 
-    const allDmns = [{ model: thisDmn.model }, ...externalDmnsByNamespace.values()];
+    const allDmns = [{ model: thisDmn.model }, ...allExternalDmns.values()];
 
     for (let i = 0; i < allDmns.length; i++) {
       const anyDmn = allDmns[i]!;
@@ -90,7 +103,7 @@ export function DecisionServiceProperties({
     }
 
     return ret;
-  }, [externalDmnsByNamespace, thisDmn]);
+  }, [allExternalDmns, thisDmn]);
 
   const thisDmnsNamespace = useDmnEditorStore((s) => s.dmn.model.definitions["@_namespace"]);
   const isReadOnly = settings.isReadOnly || (!!namespace && namespace !== thisDmnsNamespace);
@@ -410,14 +423,17 @@ function DecisionServiceEquivalentFunction({
 
       const dmnObject = allDrgElementsByHref.get(potentialExternalHref);
 
-      return dmnObject
+      const isNamespaceDirectlyIncluded =
+        importsByNamespace.has(resolvedNamespace) || resolvedNamespace === thisDmnsNamespace;
+
+      return dmnObject && isNamespaceDirectlyIncluded
         ? buildFeelQNameFromNamespace({
             namedElement: dmnObject,
             importsByNamespace,
             namespace: resolvedNamespace,
             relativeToNamespace: thisDmnsNamespace,
           }).full
-        : potentialExternalHref;
+        : buildDisplayNameForDmnObject(dmnObject, resolvedNamespace);
     },
     [allDrgElementsByHref, decisionServiceNamespace, importsByNamespace, thisDmnsNamespace]
   );
@@ -449,3 +465,10 @@ function DecisionServiceEquivalentFunction({
     </Alert>
   );
 }
+
+function buildDisplayNameForDmnObject(
+  dmnObject: Unpacked<Normalized<DMN15__tDefinitions>["drgElement"]> | undefined,
+  namespace: string
+) {
+  return `${namespace.substring(0, 11)}...${namespace.substring(namespace.length - 4)}.${dmnObject?.["@_name"]}`;
+}
diff --git a/packages/dmn-editor/src/propertiesPanel/UnknownProperties.tsx b/packages/dmn-editor/src/propertiesPanel/UnknownProperties.tsx
index 83dfedb4ab0..32782b41c2e 100644
--- a/packages/dmn-editor/src/propertiesPanel/UnknownProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/UnknownProperties.tsx
@@ -34,7 +34,7 @@ export function UnknownProperties(props: { shape: Normalized<DMNDI15__DMNShape>;
   const thisDmn = useDmnEditorStore((s) => s.dmn);
   const { externalModelsByNamespace } = useExternalModels();
   const externalDmnsByNamespace = useDmnEditorStore(
-    (s) => s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).dmns
+    (s) => s.computed(s).getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns
   );
   const { onRequestToJumpToPath } = useDmnEditor();
 
diff --git a/packages/dmn-editor/src/store/Store.ts b/packages/dmn-editor/src/store/Store.ts
index 4b89906cc84..702fb19b3ec 100644
--- a/packages/dmn-editor/src/store/Store.ts
+++ b/packages/dmn-editor/src/store/Store.ts
@@ -30,7 +30,7 @@ import { ComputedStateCache } from "./ComputedStateCache";
 import { computeAllFeelVariableUniqueNames } from "./computed/computeAllFeelVariableUniqueNames";
 import { computeDataTypes } from "./computed/computeDataTypes";
 import { computeDiagramData } from "./computed/computeDiagramData";
-import { computeExternalModelsByType } from "./computed/computeExternalModelsByType";
+import { computeDirectlyIncludedExternalModelsByNamespace } from "./computed/computeDirectlyIncludedExternalModelsByNamespace";
 import { computeImportsByNamespace } from "./computed/computeImportsByNamespace";
 import { computeIndexedDrd } from "./computed/computeIndexes";
 import { computeIsDropTargetNodeValidForSelection } from "./computed/computeIsDropTargetNodeValidForSelection";
@@ -142,9 +142,9 @@ export type Computed = {
 
   isDropTargetNodeValidForSelection(e: ExternalModelsIndex | undefined): boolean;
 
-  getExternalModelTypesByNamespace: (
+  getDirectlyIncludedExternalModelsByNamespace: (
     e: ExternalModelsIndex | undefined
-  ) => ReturnType<typeof computeExternalModelsByType>;
+  ) => ReturnType<typeof computeDirectlyIncludedExternalModelsByNamespace>;
 
   /**
    * Get a valid DRD index.
@@ -401,7 +401,7 @@ export function createDmnEditorStore(model: DmnLatestModel, computedCache: Compu
             computedCache.cached("getDataTypes", computeDataTypes, [
               s.dmn.model.definitions["@_namespace"],
               s.dmn.model.definitions.itemDefinition,
-              s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace),
+              s.computed(s).getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace),
               s.computed(s).importsByNamespace(),
             ]),
 
@@ -411,17 +411,18 @@ export function createDmnEditorStore(model: DmnLatestModel, computedCache: Compu
               s.dmn.model.definitions.import,
             ]),
 
-          getExternalModelTypesByNamespace: (externalModelsByNamespace: ExternalModelsIndex | undefined) =>
-            computedCache.cached("getExternalModelTypesByNamespace", computeExternalModelsByType, [
-              s.dmn.model.definitions.import,
-              externalModelsByNamespace,
-            ]),
+          getDirectlyIncludedExternalModelsByNamespace: (externalModelsByNamespace: ExternalModelsIndex | undefined) =>
+            computedCache.cached(
+              "getDirectlyIncludedExternalModelsByNamespace",
+              computeDirectlyIncludedExternalModelsByNamespace,
+              [s.dmn.model.definitions.import, externalModelsByNamespace]
+            ),
 
           getDiagramData: (externalModelsByNamespace: ExternalModelsIndex | undefined) =>
             computedCache.cached("getDiagramData", computeDiagramData, [
               s.diagram,
               s.dmn.model.definitions,
-              s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace),
+              s.computed(s).getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace),
               s.computed(s).indexedDrd(),
               s.computed(s).isAlternativeInputDataShape(),
             ]),
diff --git a/packages/dmn-editor/src/store/computed/computeContainingDecisionServiceHrefsByDecisionHrefs.ts.ts b/packages/dmn-editor/src/store/computed/computeContainingDecisionServiceHrefsByDecisionHrefs.ts.ts
index 6365fa7fb88..3ab2a584842 100644
--- a/packages/dmn-editor/src/store/computed/computeContainingDecisionServiceHrefsByDecisionHrefs.ts.ts
+++ b/packages/dmn-editor/src/store/computed/computeContainingDecisionServiceHrefsByDecisionHrefs.ts.ts
@@ -23,45 +23,44 @@ import { State } from "../Store";
 
 export function computeContainingDecisionServiceHrefsByDecisionHrefs({
   thisDmnsNamespace,
-  drgElementsNamespace,
-  drgElements,
+  drgElementsByNamespace,
 }: {
   thisDmnsNamespace: string;
-  drgElementsNamespace: string;
-  drgElements: State["dmn"]["model"]["definitions"]["drgElement"];
+  drgElementsByNamespace: Map<string, State["dmn"]["model"]["definitions"]["drgElement"]>;
 }) {
-  drgElements ??= [];
   const decisionServiceHrefsByDecisionHrefs = new Map<string, string[]>();
 
-  for (const drgElement of drgElements) {
-    const drgElementHref = buildXmlHref({
-      namespace: drgElementsNamespace === thisDmnsNamespace ? "" : drgElementsNamespace,
-      id: drgElement["@_id"]!,
-    });
-
-    // Decision
-    if (drgElement.__$$element === "decision") {
-      decisionServiceHrefsByDecisionHrefs.set(
-        drgElementHref,
-        decisionServiceHrefsByDecisionHrefs.get(drgElementHref) ?? []
-      );
-    }
-    // DS
-    else if (drgElement.__$$element === "decisionService") {
-      const { containedDecisionHrefsRelativeToThisDmn } = getDecisionServicePropertiesRelativeToThisDmn({
-        thisDmnsNamespace,
-        decisionServiceNamespace: drgElementsNamespace,
-        decisionService: drgElement,
+  for (const [drgElementsNamespace, drgElements] of drgElementsByNamespace) {
+    for (const drgElement of drgElements ?? []) {
+      const drgElementHref = buildXmlHref({
+        namespace: drgElementsNamespace === thisDmnsNamespace ? "" : drgElementsNamespace,
+        id: drgElement["@_id"]!,
       });
 
-      for (const containedDecisionHref of containedDecisionHrefsRelativeToThisDmn) {
-        decisionServiceHrefsByDecisionHrefs.set(containedDecisionHref, [
-          ...(decisionServiceHrefsByDecisionHrefs.get(containedDecisionHref) ?? []),
+      // Decision
+      if (drgElement.__$$element === "decision") {
+        decisionServiceHrefsByDecisionHrefs.set(
           drgElementHref,
-        ]);
+          decisionServiceHrefsByDecisionHrefs.get(drgElementHref) ?? []
+        );
+      }
+      // DS
+      else if (drgElement.__$$element === "decisionService") {
+        const { containedDecisionHrefsRelativeToThisDmn } = getDecisionServicePropertiesRelativeToThisDmn({
+          thisDmnsNamespace,
+          decisionServiceNamespace: drgElementsNamespace,
+          decisionService: drgElement,
+        });
+
+        for (const containedDecisionHref of containedDecisionHrefsRelativeToThisDmn) {
+          decisionServiceHrefsByDecisionHrefs.set(containedDecisionHref, [
+            ...(decisionServiceHrefsByDecisionHrefs.get(containedDecisionHref) ?? []),
+            drgElementHref,
+          ]);
+        }
+      } else {
+        // Ignore other elements
       }
-    } else {
-      // Ignore other elements
     }
   }
 
diff --git a/packages/dmn-editor/src/store/computed/computeDataTypes.ts b/packages/dmn-editor/src/store/computed/computeDataTypes.ts
index baa3c388179..4670400ad60 100644
--- a/packages/dmn-editor/src/store/computed/computeDataTypes.ts
+++ b/packages/dmn-editor/src/store/computed/computeDataTypes.ts
@@ -29,7 +29,7 @@ import { Normalized } from "../../normalization/normalize";
 export function computeDataTypes(
   namespace: State["dmn"]["model"]["definitions"]["@_namespace"],
   itemDefinitions: State["dmn"]["model"]["definitions"]["itemDefinition"],
-  externalModelTypesByNamespace: TypeOrReturnType<Computed["getExternalModelTypesByNamespace"]>,
+  externalModelTypesByNamespace: TypeOrReturnType<Computed["getDirectlyIncludedExternalModelsByNamespace"]>,
   thisDmnsImportsByNamespace: TypeOrReturnType<Computed["importsByNamespace"]>
 ) {
   const allDataTypesById: DataTypeIndex = new Map();
diff --git a/packages/dmn-editor/src/store/computed/computeDiagramData.ts b/packages/dmn-editor/src/store/computed/computeDiagramData.ts
index 69552fa0412..0c15d4839cd 100644
--- a/packages/dmn-editor/src/store/computed/computeDiagramData.ts
+++ b/packages/dmn-editor/src/store/computed/computeDiagramData.ts
@@ -64,7 +64,7 @@ type AckNode = (
 export function computeDiagramData(
   diagram: State["diagram"],
   definitions: State["dmn"]["model"]["definitions"],
-  externalModelTypesByNamespace: TypeOrReturnType<Computed["getExternalModelTypesByNamespace"]>,
+  externalModelTypesByNamespace: TypeOrReturnType<Computed["getDirectlyIncludedExternalModelsByNamespace"]>,
   indexedDrd: TypeOrReturnType<Computed["indexedDrd"]>,
   isAlternativeInputDataShape: boolean
 ) {
@@ -218,17 +218,17 @@ export function computeDiagramData(
     };
 
     if (dmnObject?.__$$element === "decisionService") {
-      const { containedDecisionHrefsRelativeToThisDmn } = getDecisionServicePropertiesRelativeToThisDmn({
-        thisDmnsNamespace: definitions["@_namespace"],
-        decisionServiceNamespace: dmnObjectNamespace ?? definitions["@_namespace"],
-        decisionService: dmnObject,
-      });
-
-      for (let i = 0; i < containedDecisionHrefsRelativeToThisDmn.length; i++) {
-        parentIdsById.set(containedDecisionHrefsRelativeToThisDmn[i], data);
-      }
+      if (!shape["@_isCollapsed"]) {
+        const { containedDecisionHrefsRelativeToThisDmn } = getDecisionServicePropertiesRelativeToThisDmn({
+          thisDmnsNamespace: definitions["@_namespace"],
+          decisionServiceNamespace: dmnObjectNamespace ?? definitions["@_namespace"],
+          decisionService: dmnObject,
+        });
 
-      if (shape["@_isCollapsed"]) {
+        for (let i = 0; i < containedDecisionHrefsRelativeToThisDmn.length; i++) {
+          parentIdsById.set(containedDecisionHrefsRelativeToThisDmn[i], data);
+        }
+      } else {
         newNode.style = {
           ...newNode.style,
           ...DECISION_SERVICE_COLLAPSED_DIMENSIONS,
@@ -280,11 +280,26 @@ export function computeDiagramData(
         namespace,
         (externalDmn.model.definitions.drgElement ?? []).reduce(
           (acc, e, index) => acc.set(e["@_id"]!, { element: e, index }),
-          new Map<string, { index: number; element: Unpacked<Normalized<DMN15__tDefinitions>["drgElement"]> }>()
+          new Map<
+            string,
+            {
+              index: number;
+              element: Unpacked<Normalized<DMN15__tDefinitions>["drgElement"]>;
+            }
+          >()
         )
       );
     },
-    new Map<string, Map<string, { index: number; element: Unpacked<Normalized<DMN15__tDefinitions>["drgElement"]> }>>()
+    new Map<
+      string,
+      Map<
+        string,
+        {
+          index: number;
+          element: Unpacked<Normalized<DMN15__tDefinitions>["drgElement"]>;
+        }
+      >
+    >()
   );
 
   const externalNodes = [...indexedDrd.dmnShapesByHref.entries()].flatMap(([href, shape]) => {
@@ -360,7 +375,10 @@ export function computeDiagramData(
     const parentNodeData = parentIdsById.get(sortedNodes[i].id);
     if (parentNodeData) {
       sortedNodes[i].data.parentRfNode = nodesById.get(
-        buildXmlHref({ namespace: parentNodeData.dmnObjectNamespace, id: parentNodeData.dmnObjectQName.localPart })
+        buildXmlHref({
+          namespace: parentNodeData.dmnObjectNamespace,
+          id: parentNodeData.dmnObjectQName.localPart,
+        })
       );
       sortedNodes[i].extent = undefined; // Allows the node to be dragged freely outside of parent's bounds.
       sortedNodes[i].zIndex = NODE_LAYERS.NESTED_NODES;
diff --git a/packages/dmn-editor/src/store/computed/computeExternalModelsByType.ts b/packages/dmn-editor/src/store/computed/computeDirectlyIncludedExternalModelsByNamespace.ts
similarity index 96%
rename from packages/dmn-editor/src/store/computed/computeExternalModelsByType.ts
rename to packages/dmn-editor/src/store/computed/computeDirectlyIncludedExternalModelsByNamespace.ts
index b62fec76e2b..eb38842ab14 100644
--- a/packages/dmn-editor/src/store/computed/computeExternalModelsByType.ts
+++ b/packages/dmn-editor/src/store/computed/computeDirectlyIncludedExternalModelsByNamespace.ts
@@ -21,7 +21,7 @@ import { ExternalDmnsIndex, ExternalModelsIndex, ExternalPmmlsIndex } from "../.
 import { getNamespaceOfDmnImport } from "../../includedModels/importNamespaces";
 import { State } from "../Store";
 
-export function computeExternalModelsByType(
+export function computeDirectlyIncludedExternalModelsByNamespace(
   imports: State["dmn"]["model"]["definitions"]["import"],
   externalModelsByNamespace: ExternalModelsIndex | undefined
 ) {
diff --git a/packages/dmn-editor/src/store/computed/initial.ts b/packages/dmn-editor/src/store/computed/initial.ts
index 7efe970d57e..63d2ad32cb6 100644
--- a/packages/dmn-editor/src/store/computed/initial.ts
+++ b/packages/dmn-editor/src/store/computed/initial.ts
@@ -45,7 +45,7 @@ export const INITIAL_COMPUTED_CACHE: Cache<Computed> = {
     value: undefined,
     dependencies: [],
   },
-  getExternalModelTypesByNamespace: {
+  getDirectlyIncludedExternalModelsByNamespace: {
     value: undefined,
     dependencies: [],
   },
diff --git a/packages/dmn-editor/stories/dev/DevWebApp.stories.tsx b/packages/dmn-editor/stories/dev/DevWebApp.stories.tsx
index bec763d7f81..56d74dee53c 100644
--- a/packages/dmn-editor/stories/dev/DevWebApp.stories.tsx
+++ b/packages/dmn-editor/stories/dev/DevWebApp.stories.tsx
@@ -18,20 +18,19 @@
  */
 
 import * as React from "react";
-import type { Meta, StoryObj } from "@storybook/react";
 import { useCallback, useMemo, useRef, useState } from "react";
+import type { Meta, StoryObj } from "@storybook/react";
 import "@patternfly/react-core/dist/styles/base.css";
 import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
 import { Page, PageSection } from "@patternfly/react-core/dist/js/components/Page";
-import { DmnLatestModel, getMarshaller, DmnMarshaller } from "@kie-tools/dmn-marshaller";
-import { Normalized, normalize } from "@kie-tools/dmn-editor/dist/normalization/normalize";
+import { DmnLatestModel, DmnMarshaller, getMarshaller } from "@kie-tools/dmn-marshaller";
+import { normalize, Normalized } from "@kie-tools/dmn-editor/dist/normalization/normalize";
 import { availableModelsByPath, modelsByNamespace } from "./availableModelsToInclude";
 import { generateEmptyDmn15 } from "../misc/empty/Empty.stories";
 import { loanPreQualificationDmn } from "../useCases/loanPreQualification/LoanPreQualification.stories";
 import { DmnEditorWrapper } from "../dmnEditorStoriesWrapper";
 import {
   DmnEditorProps,
-  DmnEditorRef,
   ExternalModelsIndex,
   OnDmnModelChange,
   OnRequestExternalModelByPath,
diff --git a/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/EmptyWithAvailableExternalModels.mdx b/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/EmptyWithAvailableExternalModels.mdx
new file mode 100644
index 00000000000..f7e21c174ae
--- /dev/null
+++ b/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/EmptyWithAvailableExternalModels.mdx
@@ -0,0 +1,10 @@
+import EmptyWithAvailableExternalModelsStories from "./EmptyWithAvailableExternalModels.stories";
+import { Meta } from "@storybook/blocks";
+
+<Meta title="MDX/Misc/EmptyWithAvailableExternalModelsStories" of={EmptyWithAvailableExternalModelsStories} />
+
+## Empty With Available External Models
+
+When user starts with an empty diagram, a wizard for quick content initialization is displayed.
+The wizard enables to create simple diagram with one input and one output or a diagram with one decision table expression.
+This model also have some external models available to be included.
diff --git a/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/EmptyWithAvailableExternalModels.stories.tsx b/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/EmptyWithAvailableExternalModels.stories.tsx
new file mode 100644
index 00000000000..388de3a4ff7
--- /dev/null
+++ b/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/EmptyWithAvailableExternalModels.stories.tsx
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as React from "react";
+import { useCallback, useMemo, useState } from "react";
+import type { Meta, StoryObj } from "@storybook/react";
+import { DmnLatestModel, DmnMarshaller, getMarshaller } from "@kie-tools/dmn-marshaller";
+import { ns as dmn15ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/meta";
+import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
+import { DMN15_SPEC } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/Dmn15Spec";
+import {
+  DmnEditor,
+  DmnEditorProps,
+  ExternalModelsIndex,
+  OnRequestExternalModelByPath,
+  OnRequestExternalModelsAvailableToInclude,
+  OnDmnModelChange,
+} from "@kie-tools/dmn-editor/dist/DmnEditor";
+import { normalize, Normalized } from "@kie-tools/dmn-editor/dist/normalization/normalize";
+
+import { DmnEditorWrapper, StorybookDmnEditorProps } from "../../dmnEditorStoriesWrapper";
+
+import { availableModelsByPath, modelsByNamespace } from "./availableModelsToInclude";
+
+export const generateEmptyDmn15 = () => `<?xml version="1.0" encoding="UTF-8"?>
+<definitions
+  xmlns="${dmn15ns.get("")}"
+  expressionLanguage="${DMN15_SPEC.expressionLanguage.default}"
+  namespace="https://kie.apache.org/dmn/${generateUuid()}"
+  id="${generateUuid()}"
+  name="DMN${generateUuid()}">
+</definitions>`;
+
+const initialModel = generateEmptyDmn15();
+
+function EmptyStoryWithIncludedModels(args: DmnEditorProps) {
+  const [state, setState] = useState<{
+    marshaller: DmnMarshaller;
+    stack: Normalized<DmnLatestModel>[];
+    pointer: number;
+  }>(() => {
+    const initialDmnMarshaller = getMarshaller(initialModel, { upgradeTo: "latest" });
+    return {
+      marshaller: initialDmnMarshaller,
+      stack: [normalize(initialDmnMarshaller.parser.parse())],
+      pointer: 0,
+    };
+  });
+
+  const currentModel = state.stack[state.pointer];
+
+  const externalModelsByNamespace = useMemo<ExternalModelsIndex>(() => {
+    return (currentModel.definitions.import ?? []).reduce((acc, i) => {
+      acc[i["@_namespace"]] = modelsByNamespace[i["@_namespace"]];
+      return acc;
+    }, {} as ExternalModelsIndex);
+  }, [currentModel.definitions.import]);
+
+  const onRequestExternalModelByPath = useCallback<OnRequestExternalModelByPath>(async (path) => {
+    return availableModelsByPath[path] ?? null;
+  }, []);
+
+  const onRequestExternalModelsAvailableToInclude = useCallback<OnRequestExternalModelsAvailableToInclude>(async () => {
+    return Object.keys(availableModelsByPath);
+  }, []);
+
+  const onModelChange = useCallback<OnDmnModelChange>((model) => {
+    setState((prev) => {
+      const newStack = prev.stack.slice(0, prev.pointer + 1);
+      return {
+        ...prev,
+        stack: [...newStack, model],
+        pointer: newStack.length,
+      };
+    });
+  }, []);
+
+  return (
+    <>
+      {DmnEditorWrapper({
+        model: currentModel,
+        originalVersion: args.originalVersion,
+        onModelChange,
+        onRequestExternalModelByPath,
+        onRequestExternalModelsAvailableToInclude,
+        externalModelsByNamespace: externalModelsByNamespace,
+        externalContextName: args.externalContextName,
+        externalContextDescription: args.externalContextDescription,
+        validationMessages: args.validationMessages,
+        evaluationResults: args.evaluationResults,
+        issueTrackerHref: args.issueTrackerHref,
+      })}
+    </>
+  );
+}
+
+const meta: Meta<DmnEditorProps> = {
+  title: "Misc/EmptyWithAvailableExternalModels",
+  component: DmnEditor,
+  includeStories: /^[A-Z]/,
+};
+
+export default meta;
+type Story = StoryObj<typeof EmptyStoryWithIncludedModels>;
+
+export const EmptyWithAvailableExternalModels: Story = {
+  render: (args) => EmptyStoryWithIncludedModels(args),
+  args: {
+    model: getMarshaller(initialModel, { upgradeTo: "latest" }).parser.parse(),
+    originalVersion: "1.5",
+    evaluationResults: {},
+    externalContextDescription: "External context description",
+    externalContextName: "Storybook - DMN Editor",
+    externalModelsByNamespace: {},
+    issueTrackerHref: "",
+    validationMessages: {},
+  },
+};
diff --git a/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/availableModelsToInclude.ts b/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/availableModelsToInclude.ts
new file mode 100644
index 00000000000..46bb7291be0
--- /dev/null
+++ b/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/availableModelsToInclude.ts
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { getMarshaller } from "@kie-tools/dmn-marshaller";
+import { normalize } from "@kie-tools/dmn-editor/dist/normalization/normalize";
+import { XML2PMML } from "@kie-tools/pmml-editor-marshaller";
+import * as DmnEditor from "@kie-tools/dmn-editor/dist/DmnEditor";
+import { getPmmlNamespace } from "@kie-tools/dmn-editor/dist/pmml/pmml";
+import { sumBkm, sumDiffDs, testTreePmml } from "./externalModels";
+
+export const sumBkmModel = normalize(getMarshaller(sumBkm, { upgradeTo: "latest" }).parser.parse());
+export const sumDiffDsModel = normalize(getMarshaller(sumDiffDs, { upgradeTo: "latest" }).parser.parse());
+export const testTreePmmlModel = XML2PMML(testTreePmml);
+
+export const availableModels: DmnEditor.ExternalModel[] = [
+  {
+    type: "dmn",
+    model: sumBkmModel,
+    svg: "",
+    normalizedPosixPathRelativeToTheOpenFile: "dev-webapp/available-models-to-include/sumBkm.dmn",
+  },
+  {
+    type: "dmn",
+    model: sumDiffDsModel,
+    svg: "",
+    normalizedPosixPathRelativeToTheOpenFile: "dev-webapp/available-models-to-include/sumDiffDs.dmn",
+  },
+  {
+    type: "dmn",
+    model: normalize(
+      getMarshaller(`<definitions xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/" />`, {
+        upgradeTo: "latest",
+      }).parser.parse()
+    ),
+    svg: "",
+    normalizedPosixPathRelativeToTheOpenFile: "dev-webapp/available-models-to-include/empty.dmn",
+  },
+  {
+    type: "pmml",
+    model: testTreePmmlModel,
+    normalizedPosixPathRelativeToTheOpenFile: "dev-webapp/available-models-to-include/testTree.pmml",
+  },
+];
+
+export const availableModelsByPath: Record<string, DmnEditor.ExternalModel> = Object.values(availableModels).reduce(
+  (acc, v) => {
+    acc[v.normalizedPosixPathRelativeToTheOpenFile] = v;
+    return acc;
+  },
+  {} as Record<string, DmnEditor.ExternalModel>
+);
+
+export const modelsByNamespace = Object.values(availableModels).reduce((acc, v) => {
+  if (v.type === "dmn") {
+    acc[v.model.definitions["@_namespace"]] = v;
+  } else if (v.type === "pmml") {
+    acc[getPmmlNamespace({ normalizedPosixPathRelativeToTheOpenFile: v.normalizedPosixPathRelativeToTheOpenFile })] = v;
+  }
+  return acc;
+}, {} as DmnEditor.ExternalModelsIndex);
diff --git a/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/externalModels.ts b/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/externalModels.ts
new file mode 100644
index 00000000000..0c293ed34b9
--- /dev/null
+++ b/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/externalModels.ts
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export const sumBkm = `<definitions 
+  xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/"
+  xmlns:dmndi="https://www.omg.org/spec/DMN/20230324/DMNDI/" 
+  xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/" 
+  xmlns:di="http://www.omg.org/spec/DMN/20180521/DI/" 
+  xmlns:kie="https://kie.apache.org/dmn/extensions/1.0"
+  expressionLanguage="https://www.omg.org/spec/DMN/20211108/FEEL/"
+  typeLanguage="http://www.omg.org/spec/DMN/20211108/FEEL/"
+  namespace="https://kie.apache.org/dmn/_923784BD-CD31-488A-9C31-C1A83C5483C0" 
+  id="_0E6F4D88-B955-404B-A31A-72BB7E1E6A77" 
+  name="Sum BKM">
+<businessKnowledgeModel name="Sum BKM" id="_3646600D-035F-47B9-8DC6-3FABE844234F">
+  <variable name="New BKM" id="_94BAC9FD-8519-49F9-855A-F4FCBACD2A04" typeRef="number" />
+  <functionDefinition label="Sum BKM" kind="FEEL" typeRef="number">
+    <formalParameter id="_F3A70A69-09FF-417C-8F6C-BD9129231377" name="a" typeRef="number" />
+    <formalParameter id="_E51B1C6E-896B-41C0-B03E-85B3CD7B6655" name="b" typeRef="number" />
+    <literalExpression id="_FA1EE22B-CC6B-499F-95EE-68158A2F233B" label="Expression Name" typeRef="&lt;Undefined&gt;">
+      <text>a + b</text>
+    </literalExpression>
+  </functionDefinition>
+</businessKnowledgeModel>
+<dmndi:DMNDI>
+  <dmndi:DMNDiagram>
+    <dmndi:DMNShape id="_3506A087-AB60-428D-9C75-1E5F5D6F0947" dmnElementRef="_3646600D-035F-47B9-8DC6-3FABE844234F" isCollapsed="false" isListedInputData="false">
+      <dc:Bounds x="40" y="60" width="160" height="80" />
+    </dmndi:DMNShape>
+    <di:extension>
+      <kie:ComponentsWidthsExtension>
+        <kie:ComponentWidths dmnElementRef="_FA1EE22B-CC6B-499F-95EE-68158A2F233B">
+          <kie:width>190</kie:width>
+        </kie:ComponentWidths>
+      </kie:ComponentsWidthsExtension>
+    </di:extension>
+  </dmndi:DMNDiagram>
+</dmndi:DMNDI>
+</definitions>
+`;
+
+export const sumDiffDs = `<definitions 
+  xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/" 
+  xmlns:dmndi="https://www.omg.org/spec/DMN/20230324/DMNDI/"
+  xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/" 
+  xmlns:di="http://www.omg.org/spec/DMN/20180521/DI/" 
+  xmlns:kie="https://kie.apache.org/dmn/extensions/1.0"
+  expressionLanguage="https://www.omg.org/spec/DMN/20211108/FEEL/" 
+  typeLanguage="http://www.omg.org/spec/DMN/20211108/FEEL/"
+  namespace="https://kie.apache.org/dmn/_D19B0015-2CBD-4BA8-84A9-5F554D84A9E1" 
+  id="_F360CECB-5DF2-4546-A7A9-E5ECF0F5A872" 
+  name="Sum and Diff DS">
+<decisionService name="Sum and Diff DS" id="_721B7634-7227-42B4-AAA4-17DE60A7A967">
+  <variable name="New Decision Service" id="_A996D4BD-CF69-4CC5-89C0-37CF2BD6BA6E" typeRef="context" />
+  <inputData href="#_18FAE913-2B2A-479D-A53A-14A2D57C46E4" />
+  <inputData href="#_0D6E83A0-171F-4D7C-B0DF-8464DDE05FD1" />
+  <outputDecision href="#_1991FB34-1253-4A54-AD3D-89697938DDFA" />
+  <outputDecision href="#_05621ED4-9236-47F1-B93A-164A4527B136" />
+</decisionService>
+<decision name="Sum" id="_05621ED4-9236-47F1-B93A-164A4527B136">
+  <variable name="New Decision" id="_88ECA891-3837-40E6-BCBF-77BF24B26FD0" typeRef="number" />
+  <informationRequirement id="_81BD49F4-E279-48A4-AC71-89CE92EEDE9C">
+    <requiredInput href="#_18FAE913-2B2A-479D-A53A-14A2D57C46E4" />
+  </informationRequirement>
+  <informationRequirement id="_115B4C89-EBA8-4136-A70E-9D303D8E92C5">
+    <requiredInput href="#_0D6E83A0-171F-4D7C-B0DF-8464DDE05FD1" />
+  </informationRequirement>
+  <literalExpression id="_2812E0EA-FD32-480F-89CD-D0FE5FA02172" label="Sum" typeRef="&lt;Undefined&gt;">
+    <text>a + b</text>
+  </literalExpression>
+</decision>
+<inputData name="a" id="_18FAE913-2B2A-479D-A53A-14A2D57C46E4">
+  <variable name="New Input Data" id="_250DB850-97F5-45C8-AFBB-207218BDAF7E" typeRef="number" />
+</inputData>
+<inputData name="b" id="_0D6E83A0-171F-4D7C-B0DF-8464DDE05FD1">
+  <variable name="New Input Data" id="_0FD3E491-93E4-4AC1-AB46-19A6C6A3E4F1" typeRef="number" />
+</inputData>
+<decision name="Diff" id="_1991FB34-1253-4A54-AD3D-89697938DDFA">
+  <variable name="New Decision" id="_47AD6FB1-1892-4E27-B46D-0AF95B18602E" typeRef="number" />
+  <informationRequirement id="_5CA8EA11-FDFF-410A-AB4F-AA7ACB9F7FDC">
+    <requiredInput href="#_18FAE913-2B2A-479D-A53A-14A2D57C46E4" />
+  </informationRequirement>
+  <informationRequirement id="_D9E5FB0F-1A8C-4733-BBAB-E4A55113F806">
+    <requiredInput href="#_0D6E83A0-171F-4D7C-B0DF-8464DDE05FD1" />
+  </informationRequirement>
+  <literalExpression id="_C6BBFC2E-695F-4668-8A0E-D175FE7302C7" label="Diff" typeRef="&lt;Undefined&gt;">
+    <text>a - b</text>
+  </literalExpression>
+</decision>
+<itemDefinition id="_842F4E16-C9A2-47D4-A221-081673B98C2D" name="SumDiffContext" isCollection="false">
+  <itemComponent id="_4882D4FB-2146-4198-8640-33B951B893A7" name="Sum" isCollection="false">
+    <typeRef>number</typeRef>
+  </itemComponent>
+  <itemComponent id="_3EF27B7D-3378-429E-B6DB-B856F5EB0AE7" name="Diff" isCollection="false">
+    <typeRef>number</typeRef>
+  </itemComponent>
+</itemDefinition>
+<itemDefinition id="_2B4E9593-3239-4E04-A213-345F0AA0AF9E" name="Fine" isCollection="false">
+  <itemComponent id="_3EF27B7D-3378-429E-B6DB-B856F5EB0AEE" name="Value" isCollection="false">
+    <typeRef>number</typeRef>
+    <allowedValues id="_5BD13D9D-412F-4E6B-914A-3D8AAAC6A701">
+      <text>100,500,1000</text>
+    </allowedValues>
+  </itemComponent>
+</itemDefinition>
+<dmndi:DMNDI>
+  <dmndi:DMNDiagram>
+    <dmndi:DMNShape id="_495CB0A7-017A-4A2F-A4D7-3133C82708E0" dmnElementRef="_721B7634-7227-42B4-AAA4-17DE60A7A967" isCollapsed="false" isListedInputData="false">
+      <dc:Bounds x="80" y="120" width="520" height="320" />
+      <dmndi:DMNDecisionServiceDividerLine>
+        <di:waypoint x="80" y="280" />
+        <di:waypoint x="500" y="280" />
+      </dmndi:DMNDecisionServiceDividerLine>
+    </dmndi:DMNShape>
+    <dmndi:DMNShape id="_80C42026-FF56-44C6-84F9-F7A03686F5E8" dmnElementRef="_05621ED4-9236-47F1-B93A-164A4527B136" isCollapsed="false" isListedInputData="false">
+      <dc:Bounds x="140" y="180" width="160" height="80" />
+    </dmndi:DMNShape>
+    <dmndi:DMNShape id="_218ED5E8-FB01-417F-A1F6-867D60BCBF19" dmnElementRef="_18FAE913-2B2A-479D-A53A-14A2D57C46E4" isCollapsed="false" isListedInputData="false">
+      <dc:Bounds x="80" y="480" width="160" height="80" />
+    </dmndi:DMNShape>
+    <dmndi:DMNShape id="_7C134BBF-2B96-4C9A-B985-D1FE10DC30D2" dmnElementRef="_0D6E83A0-171F-4D7C-B0DF-8464DDE05FD1" isCollapsed="false" isListedInputData="false">
+      <dc:Bounds x="440" y="480" width="160" height="80" />
+    </dmndi:DMNShape>
+    <dmndi:DMNEdge id="_768C5D6E-9A41-4AA3-921C-A545E8F11597" dmnElementRef="_81BD49F4-E279-48A4-AC71-89CE92EEDE9C" sourceElement="_218ED5E8-FB01-417F-A1F6-867D60BCBF19" targetElement="_80C42026-FF56-44C6-84F9-F7A03686F5E8">
+      <di:waypoint x="160" y="520" />
+      <di:waypoint x="220" y="260" />
+    </dmndi:DMNEdge>
+    <dmndi:DMNEdge id="_79E2E532-8D84-40C9-91DA-07EA606798E5" dmnElementRef="_115B4C89-EBA8-4136-A70E-9D303D8E92C5" sourceElement="_7C134BBF-2B96-4C9A-B985-D1FE10DC30D2" targetElement="_80C42026-FF56-44C6-84F9-F7A03686F5E8">
+      <di:waypoint x="520" y="520" />
+      <di:waypoint x="220" y="260" />
+    </dmndi:DMNEdge>
+    <dmndi:DMNShape id="_1553EB6C-2BE8-4BC3-8972-A87308B98C86" dmnElementRef="_1991FB34-1253-4A54-AD3D-89697938DDFA" isCollapsed="false" isListedInputData="false">
+      <dc:Bounds x="380" y="180" width="160" height="80" />
+    </dmndi:DMNShape>
+    <dmndi:DMNEdge id="_C6979483-DBBA-4AC0-AB28-E12EFEF08654" dmnElementRef="_5CA8EA11-FDFF-410A-AB4F-AA7ACB9F7FDC" sourceElement="_218ED5E8-FB01-417F-A1F6-867D60BCBF19" targetElement="_1553EB6C-2BE8-4BC3-8972-A87308B98C86">
+      <di:waypoint x="160" y="520" />
+      <di:waypoint x="460" y="260" />
+    </dmndi:DMNEdge>
+    <dmndi:DMNEdge id="_378C5213-084B-4A1D-ADCC-CEFE41F7E9FC" dmnElementRef="_D9E5FB0F-1A8C-4733-BBAB-E4A55113F806" sourceElement="_7C134BBF-2B96-4C9A-B985-D1FE10DC30D2" targetElement="_1553EB6C-2BE8-4BC3-8972-A87308B98C86">
+      <di:waypoint x="520" y="520" />
+      <di:waypoint x="460" y="260" />
+    </dmndi:DMNEdge>
+    <di:extension>
+      <kie:ComponentsWidthsExtension>
+        <kie:ComponentWidths dmnElementRef="_2812E0EA-FD32-480F-89CD-D0FE5FA02172">
+          <kie:width>190</kie:width>
+        </kie:ComponentWidths>
+        <kie:ComponentWidths dmnElementRef="_C6BBFC2E-695F-4668-8A0E-D175FE7302C7">
+          <kie:width>190</kie:width>
+        </kie:ComponentWidths>
+      </kie:ComponentsWidthsExtension>
+    </di:extension>
+  </dmndi:DMNDiagram>
+</dmndi:DMNDI>
+</definitions>
+`;
+// Copied from kogito-examples/kogito-quarkus-examples/dmn-pmml-quarkus-example/src/main/resources
+export const testTreePmml = `<PMML version="4.2" xsi:schemaLocation="http://www.dmg.org/PMML-4_2 http://www.dmg.org/v4-2-1/pmml-4-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xmlns="http://www.dmg.org/PMML-4_2">
+<Header>
+ <Application name="Drools-PMML" version="7.0.0-SNAPSHOT" />
+</Header>
+
+<DataDictionary numberOfFields="3">
+ <DataField name="temperature" dataType="double" optype="continuous" />
+ <DataField name="humidity" dataType="double" optype="continuous" />   
+ <DataField name="decision" dataType="string" optype="categorical"> 
+   <Value value="sunglasses" />
+   <Value value="umbrella" />
+   <Value value="nothing" />     
+ </DataField>
+</DataDictionary>
+
+<TreeModel modelName="DecisionTree" functionName="classification">
+ <MiningSchema>
+   <MiningField name="temperature"  usageType="active" />
+   <MiningField name="humidity"  usageType="active" />
+   <MiningField name="decision" usageType="predicted" />
+ </MiningSchema>
+ <Output>
+   <OutputField name="weatherdecision" targetField="decision" />
+ </Output>
+ 
+ <Node score="nothing" id="1">
+   <True />
+   <Node score="sunglasses" id="2">
+     <CompoundPredicate booleanOperator="and">
+       <SimplePredicate field="temperature" operator="greaterThan" value="25" />
+       <SimplePredicate field="humidity" operator="lessOrEqual" value="20" />
+     </CompoundPredicate>
+   </Node>
+   <Node score="umbrella" id="3">
+     <SimplePredicate field="humidity" operator="greaterThan" value="50" />
+   </Node>
+   <Node score="nothing" id="4">
+     <True />
+   </Node>
+ </Node>
+</TreeModel>
+</PMML>
+`;
diff --git a/packages/dmn-editor/tests-e2e/__fixtures__/base.ts b/packages/dmn-editor/tests-e2e/__fixtures__/base.ts
index 1143c264a87..5c81eb6b0b9 100644
--- a/packages/dmn-editor/tests-e2e/__fixtures__/base.ts
+++ b/packages/dmn-editor/tests-e2e/__fixtures__/base.ts
@@ -41,6 +41,8 @@ import { BeePropertiesPanel } from "./propertiesPanel/beePropertiesPanel";
 import { BoxedExpressionEditor } from "@kie-tools/boxed-expression-component/tests-e2e/__fixtures__/boxedExpression";
 import { Monaco } from "@kie-tools/boxed-expression-component/tests-e2e/__fixtures__/monaco";
 import { ProjectName } from "@kie-tools/playwright-base/projectNames";
+import { Stories } from "./stories";
+import { IncludedModels } from "./includedModels";
 
 type DmnEditorFixtures = {
   bee: BoxedExpressionEditor;
@@ -65,6 +67,8 @@ type DmnEditorFixtures = {
   knowledgeSourcePropertiesPanel: KnowledgeSourcePropertiesPanel;
   multipleNodesPropertiesPanel: MultipleNodesPropertiesPanel;
   textAnnotationPropertiesPanel: TextAnnotationPropertiesPanel;
+  stories: Stories;
+  includedModels: IncludedModels;
 };
 
 export const test = base.extend<DmnEditorFixtures>({
@@ -134,6 +138,12 @@ export const test = base.extend<DmnEditorFixtures>({
   textAnnotationPropertiesPanel: async ({ diagram, page }, use) => {
     await use(new TextAnnotationPropertiesPanel(diagram, page));
   },
+  stories: async ({ baseURL, page }, use) => {
+    await use(new Stories(page, baseURL));
+  },
+  includedModels: async ({ page }, use) => {
+    await use(new IncludedModels(page));
+  },
 });
 
 export { expect } from "@playwright/test";
diff --git a/packages/dmn-editor/tests-e2e/__fixtures__/includedModels.ts b/packages/dmn-editor/tests-e2e/__fixtures__/includedModels.ts
new file mode 100644
index 00000000000..5301356a574
--- /dev/null
+++ b/packages/dmn-editor/tests-e2e/__fixtures__/includedModels.ts
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Page } from "@playwright/test";
+
+export class IncludedModels {
+  constructor(private readonly page: Page) {}
+
+  public get() {
+    return this.page.getByTestId("kie-tools--dmn-editor--included-models-container");
+  }
+
+  private getModal() {
+    return this.page.getByTestId("kie-tools--dmn-editor--included-models-modal");
+  }
+
+  public getIncludeModelButton() {
+    return this.get().getByRole("button", { name: "Include model" });
+  }
+
+  public async fillModelToInclude(args: { modelName: string }) {
+    await this.getModal().getByPlaceholder("Select a model to include...").click();
+    await this.getModal().getByPlaceholder("Select a model to include...").fill(args.modelName);
+  }
+
+  public async selectModel(args: { modelName: string }) {
+    await this.page.getByText(args.modelName).click();
+  }
+
+  public async fillModelName(args: { modelName: string }) {
+    await this.getModal().getByPlaceholder("<Default>").click();
+    await this.getModal().getByPlaceholder("<Default>").fill(args.modelName);
+  }
+
+  public async includeModel() {
+    return await this.page.getByRole("button", { name: "Include model" }).click();
+  }
+}
diff --git a/packages/dmn-editor/tests-e2e/__fixtures__/nodes.ts b/packages/dmn-editor/tests-e2e/__fixtures__/nodes.ts
index 82c5546c765..bdaa359a059 100644
--- a/packages/dmn-editor/tests-e2e/__fixtures__/nodes.ts
+++ b/packages/dmn-editor/tests-e2e/__fixtures__/nodes.ts
@@ -140,9 +140,19 @@ export class Nodes {
   }
 
   public async move(args: { name: string; targetPosition: { x: number; y: number } }) {
-    await this.get({ name: args.name }).dragTo(this.diagram.get(), {
-      targetPosition: args.targetPosition,
-    });
+    if (args.name.includes(DefaultNodeName.DECISION_SERVICE)) {
+      // Decision Services only have some draggable areas near the borders.
+      // If you drag it to the center, you'll drag the divide line.
+      // Also, neither the entire upper area nor the entire downer area is draggable.
+      await this.get({ name: args.name }).dragTo(this.diagram.get(), {
+        targetPosition: args.targetPosition,
+        sourcePosition: { x: 20, y: 20 },
+      });
+    } else {
+      await this.get({ name: args.name }).dragTo(this.diagram.get(), {
+        targetPosition: args.targetPosition,
+      });
+    }
   }
 
   public async rename(args: { current: string; new: string }) {
diff --git a/packages/dmn-editor/tests-e2e/__fixtures__/palette.ts b/packages/dmn-editor/tests-e2e/__fixtures__/palette.ts
index 4fdaedf0d6a..5b55375104a 100644
--- a/packages/dmn-editor/tests-e2e/__fixtures__/palette.ts
+++ b/packages/dmn-editor/tests-e2e/__fixtures__/palette.ts
@@ -40,6 +40,21 @@ export class Palette {
     }
   }
 
+  public async dragExternalNode(args: {
+    includedModelName: string;
+    nodeName: string;
+    targetPosition: { x: number; y: number };
+  }) {
+    await this.page
+      .getByTestId("kie-tools--dmn-editor--external-nodes-popover")
+      .getByTestId(`kie-tools--dmn-editor--external-node-${args.includedModelName}-${args.nodeName}`)
+      .dragTo(this.diagram.get(), { targetPosition: args.targetPosition });
+  }
+
+  public async toggleExternalNodesPanel() {
+    await this.page.getByRole("button", { name: "External nodes" }).click();
+  }
+
   private getNewNodeProperties(type: NodeType) {
     switch (type) {
       case NodeType.INPUT_DATA:
diff --git a/packages/dmn-editor/tests-e2e/__fixtures__/stories.ts b/packages/dmn-editor/tests-e2e/__fixtures__/stories.ts
new file mode 100644
index 00000000000..301188efe55
--- /dev/null
+++ b/packages/dmn-editor/tests-e2e/__fixtures__/stories.ts
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Page } from "@playwright/test";
+
+export class Stories {
+  constructor(
+    private readonly page: Page,
+    private readonly baseURL?: string
+  ) {}
+
+  private getIframeURL(iframeId: string) {
+    return `iframe.html?id=${iframeId}&viewMode=story`;
+  }
+
+  public async openEmptyWithAvailableExternalModels() {
+    await this.page.goto(
+      `${this.baseURL}/${this.getIframeURL(`misc-emptywithavailableexternalmodels--empty-with-available-external-models`)}` ??
+        ""
+    );
+  }
+}
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/add-external-node-inside-decision-service.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/add-external-node-inside-decision-service.png
new file mode 100644
index 00000000000..fbaeb34075e
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/add-external-node-inside-decision-service.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/delete-external-node-inside-decision-service-after-delete.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/delete-external-node-inside-decision-service-after-delete.png
new file mode 100644
index 00000000000..6e352cbf62e
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/delete-external-node-inside-decision-service-after-delete.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/delete-external-node-inside-decision-service-before-delete.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/delete-external-node-inside-decision-service-before-delete.png
new file mode 100644
index 00000000000..ca04d943acf
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/delete-external-node-inside-decision-service-before-delete.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-from-ds-to-another-ds-after-move.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-from-ds-to-another-ds-after-move.png
new file mode 100644
index 00000000000..e9eddcaace8
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-from-ds-to-another-ds-after-move.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-from-ds-to-another-ds-before-move.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-from-ds-to-another-ds-before-move.png
new file mode 100644
index 00000000000..5e600c04fce
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-from-ds-to-another-ds-before-move.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-inside-decision-service-after-move-to-out.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-inside-decision-service-after-move-to-out.png
new file mode 100644
index 00000000000..e54b0c1908f
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-inside-decision-service-after-move-to-out.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-inside-decision-service-before-move-to-out.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-inside-decision-service-before-move-to-out.png
new file mode 100644
index 00000000000..d6029255909
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-inside-decision-service-before-move-to-out.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-out-from-decision-service-after.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-out-from-decision-service-after.png
new file mode 100644
index 00000000000..d986c13f00b
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-out-from-decision-service-after.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-out-from-decision-service-before.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-out-from-decision-service-before.png
new file mode 100644
index 00000000000..d6029255909
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/move-external-decision-out-from-decision-service-before.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/resize-external-node-inside-decision-service-after-resizing.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/resize-external-node-inside-decision-service-after-resizing.png
new file mode 100644
index 00000000000..e3065c65ff8
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/resize-external-node-inside-decision-service-after-resizing.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/resize-external-node-inside-decision-service-before-resizing.png b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/resize-external-node-inside-decision-service-before-resizing.png
new file mode 100644
index 00000000000..ca04d943acf
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/drgElements/resize-external-node-inside-decision-service-before-resizing.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/add-external-node-inside-decision-service.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/add-external-node-inside-decision-service.png
new file mode 100644
index 00000000000..fbaeb34075e
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/add-external-node-inside-decision-service.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/delete-external-node-inside-decision-service-after-delete.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/delete-external-node-inside-decision-service-after-delete.png
new file mode 100644
index 00000000000..6e352cbf62e
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/delete-external-node-inside-decision-service-after-delete.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/delete-external-node-inside-decision-service-before-delete.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/delete-external-node-inside-decision-service-before-delete.png
new file mode 100644
index 00000000000..ca04d943acf
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/delete-external-node-inside-decision-service-before-delete.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-from-ds-to-another-ds-after-move.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-from-ds-to-another-ds-after-move.png
new file mode 100644
index 00000000000..e9eddcaace8
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-from-ds-to-another-ds-after-move.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-from-ds-to-another-ds-before-move.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-from-ds-to-another-ds-before-move.png
new file mode 100644
index 00000000000..5e600c04fce
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-from-ds-to-another-ds-before-move.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-inside-decision-service-after-move-to-out.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-inside-decision-service-after-move-to-out.png
new file mode 100644
index 00000000000..e54b0c1908f
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-inside-decision-service-after-move-to-out.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-inside-decision-service-before-move-to-out.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-inside-decision-service-before-move-to-out.png
new file mode 100644
index 00000000000..d6029255909
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-inside-decision-service-before-move-to-out.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-out-from-decision-service-after.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-out-from-decision-service-after.png
new file mode 100644
index 00000000000..d986c13f00b
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-out-from-decision-service-after.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-out-from-decision-service-before.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-out-from-decision-service-before.png
new file mode 100644
index 00000000000..d6029255909
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/move-external-decision-out-from-decision-service-before.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/resize-external-node-inside-decision-service-after-resizing.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/resize-external-node-inside-decision-service-after-resizing.png
new file mode 100644
index 00000000000..e3065c65ff8
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/resize-external-node-inside-decision-service-after-resizing.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/resize-external-node-inside-decision-service-before-resizing.png b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/resize-external-node-inside-decision-service-before-resizing.png
new file mode 100644
index 00000000000..ca04d943acf
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/drgElements/resize-external-node-inside-decision-service-before-resizing.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/add-external-node-inside-decision-service.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/add-external-node-inside-decision-service.png
new file mode 100644
index 00000000000..792fed153c2
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/add-external-node-inside-decision-service.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/delete-external-node-inside-decision-service-after-delete.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/delete-external-node-inside-decision-service-after-delete.png
new file mode 100644
index 00000000000..cfef54c3c49
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/delete-external-node-inside-decision-service-after-delete.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/delete-external-node-inside-decision-service-before-delete.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/delete-external-node-inside-decision-service-before-delete.png
new file mode 100644
index 00000000000..b7fd36e9d74
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/delete-external-node-inside-decision-service-before-delete.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-from-ds-to-another-ds-after-move.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-from-ds-to-another-ds-after-move.png
new file mode 100644
index 00000000000..1dbeb169713
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-from-ds-to-another-ds-after-move.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-from-ds-to-another-ds-before-move.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-from-ds-to-another-ds-before-move.png
new file mode 100644
index 00000000000..dae01161904
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-from-ds-to-another-ds-before-move.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-inside-decision-service-after-move-to-out.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-inside-decision-service-after-move-to-out.png
new file mode 100644
index 00000000000..2c658212a6f
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-inside-decision-service-after-move-to-out.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-inside-decision-service-before-move-to-out.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-inside-decision-service-before-move-to-out.png
new file mode 100644
index 00000000000..ff393609e88
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-inside-decision-service-before-move-to-out.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-out-from-decision-service-after.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-out-from-decision-service-after.png
new file mode 100644
index 00000000000..cea16561ae7
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-out-from-decision-service-after.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-out-from-decision-service-before.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-out-from-decision-service-before.png
new file mode 100644
index 00000000000..ff393609e88
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/move-external-decision-out-from-decision-service-before.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/resize-external-node-inside-decision-service-after-resizing.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/resize-external-node-inside-decision-service-after-resizing.png
new file mode 100644
index 00000000000..44dc6063f39
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/resize-external-node-inside-decision-service-after-resizing.png differ
diff --git a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/resize-external-node-inside-decision-service-before-resizing.png b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/resize-external-node-inside-decision-service-before-resizing.png
new file mode 100644
index 00000000000..b7fd36e9d74
Binary files /dev/null and b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/drgElements/resize-external-node-inside-decision-service-before-resizing.png differ
diff --git a/packages/dmn-editor/tests-e2e/drgElements/addExternalNode.spec.ts b/packages/dmn-editor/tests-e2e/drgElements/addExternalNode.spec.ts
new file mode 100644
index 00000000000..0a4e2a9bab9
--- /dev/null
+++ b/packages/dmn-editor/tests-e2e/drgElements/addExternalNode.spec.ts
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { expect, test } from "../__fixtures__/base";
+import { TabName } from "../__fixtures__/editor";
+import { DefaultNodeName, NodeType } from "../__fixtures__/nodes";
+
+test.beforeEach(async ({ stories }) => {
+  await stories.openEmptyWithAvailableExternalModels();
+});
+
+test.describe("Add external node - Decision", () => {
+  test("add to a Decision Service", async ({ editor, palette, diagram, nodes, includedModels }) => {
+    await editor.changeTab({ tab: TabName.INCLUDED_MODELS });
+
+    await includedModels.getIncludeModelButton().click();
+    await includedModels.fillModelToInclude({ modelName: "sumDiffDs.dmn" });
+    await includedModels.selectModel({ modelName: "sumDiffDs.dmn" });
+    await includedModels.fillModelName({ modelName: "MY_MODEL" });
+    await includedModels.includeModel();
+
+    await editor.changeTab({ tab: TabName.EDITOR });
+    await palette.dragNewNode({ type: NodeType.DECISION_SERVICE, targetPosition: { x: 400, y: 200 } });
+
+    await palette.toggleExternalNodesPanel();
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Sum",
+      targetPosition: {
+        x: 200,
+        y: 200,
+      },
+    });
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Diff",
+      targetPosition: {
+        x: 300,
+        y: 300,
+      },
+    });
+
+    // We're hiding the panel now.
+    await palette.toggleExternalNodesPanel();
+
+    await diagram.resetFocus();
+    await nodes.move({ name: "Sum", targetPosition: { x: 500, y: 300 } });
+    await nodes.move({ name: "Diff", targetPosition: { x: 500, y: 430 } });
+
+    await diagram.resetFocus();
+
+    // We move it to make it sure that the nodes are added inside the Decision Services
+    // and are really attached to it, not only "visually over it".
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE, targetPosition: { x: 120, y: 120 } });
+
+    await expect(diagram.get()).toHaveScreenshot("add-external-node-inside-decision-service.png");
+  });
+});
diff --git a/packages/dmn-editor/tests-e2e/drgElements/deleteExternalNode.spec.ts b/packages/dmn-editor/tests-e2e/drgElements/deleteExternalNode.spec.ts
new file mode 100644
index 00000000000..6b7dc780eb2
--- /dev/null
+++ b/packages/dmn-editor/tests-e2e/drgElements/deleteExternalNode.spec.ts
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { expect, test } from "../__fixtures__/base";
+import { TabName } from "../__fixtures__/editor";
+import { DefaultNodeName, NodeType } from "../__fixtures__/nodes";
+
+test.beforeEach(async ({ stories }) => {
+  await stories.openEmptyWithAvailableExternalModels();
+});
+
+test.describe("Delete external node - Decision", () => {
+  test("delete an external node from Decision Service", async ({ editor, palette, diagram, nodes, includedModels }) => {
+    await editor.changeTab({ tab: TabName.INCLUDED_MODELS });
+
+    await includedModels.getIncludeModelButton().click();
+    await includedModels.fillModelToInclude({ modelName: "sumDiffDs.dmn" });
+    await includedModels.selectModel({ modelName: "sumDiffDs.dmn" });
+    await includedModels.fillModelName({ modelName: "MY_MODEL" });
+    await includedModels.includeModel();
+
+    await editor.changeTab({ tab: TabName.EDITOR });
+    await palette.dragNewNode({ type: NodeType.DECISION_SERVICE, targetPosition: { x: 400, y: 200 } });
+
+    await palette.toggleExternalNodesPanel();
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Sum",
+      targetPosition: {
+        x: 200,
+        y: 200,
+      },
+    });
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Diff",
+      targetPosition: {
+        x: 300,
+        y: 300,
+      },
+    });
+
+    // We're hiding the panel now.
+    await palette.toggleExternalNodesPanel();
+
+    await diagram.resetFocus();
+    await nodes.move({ name: "Sum", targetPosition: { x: 500, y: 300 } });
+    await nodes.move({ name: "Diff", targetPosition: { x: 500, y: 430 } });
+
+    await expect(diagram.get()).toHaveScreenshot("delete-external-node-inside-decision-service-before-delete.png");
+
+    await nodes.delete({ name: "Sum" });
+
+    await diagram.resetFocus();
+
+    // We move it to make it sure that the nodes are added inside the Decision Services
+    // and are really attached to it, not only "visually over it".
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE, targetPosition: { x: 120, y: 120 } });
+
+    await expect(diagram.get()).toHaveScreenshot("delete-external-node-inside-decision-service-after-delete.png");
+  });
+});
diff --git a/packages/dmn-editor/tests-e2e/drgElements/moveExternalNode.spec.ts b/packages/dmn-editor/tests-e2e/drgElements/moveExternalNode.spec.ts
new file mode 100644
index 00000000000..c553643934a
--- /dev/null
+++ b/packages/dmn-editor/tests-e2e/drgElements/moveExternalNode.spec.ts
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { expect, test } from "../__fixtures__/base";
+import { TabName } from "../__fixtures__/editor";
+import { DefaultNodeName, NodeType } from "../__fixtures__/nodes";
+
+test.beforeEach(async ({ stories }) => {
+  await stories.openEmptyWithAvailableExternalModels();
+});
+
+test.describe("Move external node - Decision", () => {
+  test("move an external node from Decision Service to out", async ({
+    editor,
+    palette,
+    diagram,
+    nodes,
+    includedModels,
+  }) => {
+    await editor.changeTab({ tab: TabName.INCLUDED_MODELS });
+
+    await includedModels.getIncludeModelButton().click();
+    await includedModels.fillModelToInclude({ modelName: "sumDiffDs.dmn" });
+    await includedModels.selectModel({ modelName: "sumDiffDs.dmn" });
+    await includedModels.fillModelName({ modelName: "MY_MODEL" });
+    await includedModels.includeModel();
+
+    await editor.changeTab({ tab: TabName.EDITOR });
+    await palette.dragNewNode({ type: NodeType.DECISION_SERVICE, targetPosition: { x: 400, y: 200 } });
+
+    await palette.toggleExternalNodesPanel();
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Sum",
+      targetPosition: {
+        x: 200,
+        y: 200,
+      },
+    });
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Diff",
+      targetPosition: {
+        x: 300,
+        y: 300,
+      },
+    });
+
+    // We're hiding the panel now.
+    await palette.toggleExternalNodesPanel();
+
+    await diagram.resetFocus();
+    await nodes.move({ name: "Sum", targetPosition: { x: 500, y: 300 } });
+    await nodes.move({ name: "Diff", targetPosition: { x: 500, y: 430 } });
+
+    // We move it to make it sure that the nodes are added inside the Decision Services
+    // and are really attached to it, not only "visually over it".
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE, targetPosition: { x: 100, y: 400 } });
+
+    await expect(diagram.get()).toHaveScreenshot(
+      "move-external-decision-inside-decision-service-before-move-to-out.png"
+    );
+
+    await diagram.resetFocus();
+
+    await nodes.move({ name: "Sum", targetPosition: { x: 400, y: 120 } });
+    await nodes.move({ name: "Diff", targetPosition: { x: 400, y: 400 } });
+
+    // Move again to make sure that nodes are not attached anymore to Decision Service.
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE, targetPosition: { x: 600, y: 100 } });
+
+    await expect(diagram.get()).toHaveScreenshot(
+      "move-external-decision-inside-decision-service-after-move-to-out.png"
+    );
+  });
+
+  test("move an external decision from one Decision Service to another Decision Service", async ({
+    editor,
+    page,
+    palette,
+    diagram,
+    nodes,
+    includedModels,
+  }) => {
+    await editor.changeTab({ tab: TabName.INCLUDED_MODELS });
+
+    await includedModels.getIncludeModelButton().click();
+    await includedModels.fillModelToInclude({ modelName: "sumDiffDs.dmn" });
+    await includedModels.selectModel({ modelName: "sumDiffDs.dmn" });
+    await includedModels.fillModelName({ modelName: "MY_MODEL" });
+    await includedModels.includeModel();
+
+    await editor.changeTab({ tab: TabName.EDITOR });
+    await palette.dragNewNode({
+      type: NodeType.DECISION_SERVICE,
+      targetPosition: { x: 250, y: 50 },
+      thenRenameTo: DefaultNodeName.DECISION_SERVICE + " 1",
+    });
+    await palette.dragNewNode({
+      type: NodeType.DECISION_SERVICE,
+      targetPosition: { x: 650, y: 50 },
+      thenRenameTo: DefaultNodeName.DECISION_SERVICE + " 2",
+    });
+
+    await palette.toggleExternalNodesPanel();
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Sum",
+      targetPosition: {
+        x: 600,
+        y: 400,
+      },
+    });
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Diff",
+      targetPosition: {
+        x: 200,
+        y: 400,
+      },
+    });
+
+    // We're hiding the panel now.
+    await palette.toggleExternalNodesPanel();
+
+    await diagram.resetFocus();
+    await nodes.move({ name: "Sum", targetPosition: { x: 350, y: 150 } });
+    await nodes.move({ name: "Diff", targetPosition: { x: 350, y: 250 } });
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE + " 1", targetPosition: { x: 200, y: 300 } });
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE + " 2", targetPosition: { x: 600, y: 300 } });
+
+    await expect(diagram.get()).toHaveScreenshot("move-external-decision-from-ds-to-another-ds-before-move.png");
+
+    await diagram.resetFocus();
+
+    await nodes.move({ name: "Sum", targetPosition: { x: 680, y: 350 } });
+    await nodes.move({ name: "Diff", targetPosition: { x: 680, y: 500 } });
+
+    // We move it to make it sure that the nodes are added inside the Decision Services
+    // and are really attached to it, not only "visually over it".
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE + " 1", targetPosition: { x: 100, y: 100 } });
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE + " 2", targetPosition: { x: 400, y: 400 } });
+
+    await expect(diagram.get()).toHaveScreenshot("move-external-decision-from-ds-to-another-ds-after-move.png");
+  });
+
+  test("move an external decision out from Decision Service", async ({
+    editor,
+    page,
+    palette,
+    diagram,
+    nodes,
+    includedModels,
+  }) => {
+    await editor.changeTab({ tab: TabName.INCLUDED_MODELS });
+
+    await includedModels.getIncludeModelButton().click();
+    await includedModels.fillModelToInclude({ modelName: "sumDiffDs.dmn" });
+    await includedModels.selectModel({ modelName: "sumDiffDs.dmn" });
+    await includedModels.fillModelName({ modelName: "MY_MODEL" });
+    await includedModels.includeModel();
+
+    await editor.changeTab({ tab: TabName.EDITOR });
+    await palette.dragNewNode({ type: NodeType.DECISION_SERVICE, targetPosition: { x: 400, y: 200 } });
+
+    await palette.toggleExternalNodesPanel();
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Sum",
+      targetPosition: {
+        x: 200,
+        y: 200,
+      },
+    });
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Diff",
+      targetPosition: {
+        x: 300,
+        y: 300,
+      },
+    });
+
+    // We're hiding the panel now.
+    await palette.toggleExternalNodesPanel();
+
+    await diagram.resetFocus();
+    await nodes.move({ name: "Sum", targetPosition: { x: 500, y: 300 } });
+    await nodes.move({ name: "Diff", targetPosition: { x: 500, y: 430 } });
+
+    // We move it to make it sure that the nodes are added inside the Decision Services
+    // and are really attached to it, not only "visually over it".
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE, targetPosition: { x: 100, y: 400 } });
+
+    await expect(diagram.get()).toHaveScreenshot("move-external-decision-out-from-decision-service-before.png");
+
+    await nodes.move({ name: "Sum", targetPosition: { x: 530, y: 100 } });
+    await nodes.move({ name: "Diff", targetPosition: { x: 530, y: 200 } });
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE, targetPosition: { x: 120, y: 200 } });
+
+    await diagram.resetFocus();
+
+    await expect(diagram.get()).toHaveScreenshot("move-external-decision-out-from-decision-service-after.png");
+  });
+});
diff --git a/packages/dmn-editor/tests-e2e/drgElements/resizeExternalNode.spec.ts b/packages/dmn-editor/tests-e2e/drgElements/resizeExternalNode.spec.ts
new file mode 100644
index 00000000000..cfe758c7506
--- /dev/null
+++ b/packages/dmn-editor/tests-e2e/drgElements/resizeExternalNode.spec.ts
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { expect, test } from "../__fixtures__/base";
+import { TabName } from "../__fixtures__/editor";
+import { DefaultNodeName, NodeType } from "../__fixtures__/nodes";
+
+test.beforeEach(async ({ stories }) => {
+  await stories.openEmptyWithAvailableExternalModels();
+});
+
+test.describe("Resize external node - Decision", () => {
+  test("resize an external node inside Decision Service", async ({
+    editor,
+    palette,
+    diagram,
+    nodes,
+    includedModels,
+  }) => {
+    await editor.changeTab({ tab: TabName.INCLUDED_MODELS });
+
+    await includedModels.getIncludeModelButton().click();
+    await includedModels.fillModelToInclude({ modelName: "sumDiffDs.dmn" });
+    await includedModels.selectModel({ modelName: "sumDiffDs.dmn" });
+    await includedModels.fillModelName({ modelName: "MY_MODEL" });
+    await includedModels.includeModel();
+
+    await editor.changeTab({ tab: TabName.EDITOR });
+    await palette.dragNewNode({ type: NodeType.DECISION_SERVICE, targetPosition: { x: 400, y: 200 } });
+
+    await palette.toggleExternalNodesPanel();
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Sum",
+      targetPosition: {
+        x: 200,
+        y: 200,
+      },
+    });
+
+    await palette.dragExternalNode({
+      includedModelName: "MY_MODEL",
+      nodeName: "Diff",
+      targetPosition: {
+        x: 300,
+        y: 300,
+      },
+    });
+
+    // We're hiding the panel now.
+    await palette.toggleExternalNodesPanel();
+
+    await diagram.resetFocus();
+    await nodes.move({ name: "Sum", targetPosition: { x: 500, y: 300 } });
+    await nodes.move({ name: "Diff", targetPosition: { x: 500, y: 430 } });
+
+    await expect(diagram.get()).toHaveScreenshot("resize-external-node-inside-decision-service-before-resizing.png");
+
+    await nodes.resize({ nodeName: "Sum", xOffset: 50, yOffset: 10 });
+    await nodes.resize({ nodeName: "Diff", xOffset: 100, yOffset: 20 });
+
+    await diagram.resetFocus();
+
+    // We move it to make it sure that the nodes are added inside the Decision Services
+    // and are really attached to it, not only "visually over it".
+    await nodes.move({ name: DefaultNodeName.DECISION_SERVICE, targetPosition: { x: 120, y: 120 } });
+
+    await expect(diagram.get()).toHaveScreenshot("resize-external-node-inside-decision-service-after-resizing.png");
+  });
+});


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org