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/02/02 17:16:08 UTC

(incubator-kie-tools) branch main updated: kie-issues#451: Implement autolayout on the new React-based DMN Editor for DMN files without Diagram information (part 1) (#2130)

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 b0d1a40320b kie-issues#451: Implement autolayout on the new React-based DMN Editor for DMN files without Diagram information (part 1) (#2130)
b0d1a40320b is described below

commit b0d1a40320bd24bd44020ae2f542dba80f1c2447
Author: Tiago Bento <15...@users.noreply.github.com>
AuthorDate: Fri Feb 2 12:16:04 2024 -0500

    kie-issues#451: Implement autolayout on the new React-based DMN Editor for DMN files without Diagram information (part 1) (#2130)
---
 packages/dmn-editor/package.json                   |   2 +
 packages/dmn-editor/src/DmnEditor.css              |  51 +-
 packages/dmn-editor/src/DmnEditor.tsx              |  99 ++--
 .../dmn-editor/src/autolayout/AutolayoutButton.tsx | 557 ++++++++++++++++++
 .../src/boxedExpressions/BoxedExpression.tsx       | 115 ++--
 packages/dmn-editor/src/dataTypes/DataTypeName.tsx |  25 +-
 .../dmn-editor/src/dataTypes/DataTypePanel.tsx     |  14 +-
 packages/dmn-editor/src/dataTypes/DataTypes.tsx    |  19 +-
 .../src/dataTypes/ItemComponentsTable.tsx          |  12 +-
 packages/dmn-editor/src/dataTypes/TypeRefLabel.tsx |   5 +-
 .../dmn-editor/src/dataTypes/TypeRefSelector.tsx   |  44 +-
 .../dmn-editor/src/dataTypes/useResolvedTypeRef.ts |  24 +-
 packages/dmn-editor/src/diagram/Diagram.tsx        | 623 +++++++++++++--------
 .../dmn-editor/src/diagram/DrdSelectorPanel.tsx    |  15 +-
 packages/dmn-editor/src/diagram/DrgNodesPanel.tsx  |  18 +-
 packages/dmn-editor/src/diagram/Palette.tsx        |  11 +-
 .../src/diagram/connections/ConnectionLine.tsx     |  30 +-
 .../drd/drdId.ts}                                  |  30 +-
 packages/dmn-editor/src/diagram/edges/Edges.tsx    |  65 ++-
 .../dmn-editor/src/diagram/edges/Waypoints.tsx     |   8 +-
 .../edges/getSnappedMultiPointAnchoredEdgePath.tsx |  38 +-
 .../useAlwaysVisibleEdgeUpdatersAtNodeBorders.ts   |  37 +-
 .../src/diagram/edges/useKieEdgePath.tsx           |  46 +-
 .../diagram/edges/usePotentialWaypointControls.ts  |  16 +-
 packages/dmn-editor/src/diagram/graph/graph.ts     |  41 +-
 packages/dmn-editor/src/diagram/maths/DmnMaths.ts  |  17 +-
 packages/dmn-editor/src/diagram/maths/Maths.ts     |  31 +-
 .../memoization/memoization.ts}                    |  35 +-
 .../src/diagram/nodes/DataTypeNodePanel.tsx        |  15 +-
 .../src/diagram/nodes/EditExpressionNodePanel.tsx  |   5 +-
 .../src/diagram/nodes/EditableNodeLabel.tsx        |  80 +--
 .../dmn-editor/src/diagram/nodes/InfoNodePanel.tsx |   2 +-
 packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx |   6 +-
 packages/dmn-editor/src/diagram/nodes/Nodes.tsx    | 559 ++++++++++--------
 packages/dmn-editor/src/draggable/Draggable.tsx    |   3 -
 .../src/externalNodes/DmnObjectListItem.tsx        |   9 +-
 .../src/externalNodes/ExternalNodesPanel.tsx       |  12 +-
 .../dmn-editor/src/feel/InlineFeelNameInput.tsx    |  15 +-
 .../dmn-editor/src/focus/useFocusableElement.ts    |   9 +-
 .../DmnEditorDependenciesContext.tsx               |  17 +-
 .../src/includedModels/IncludedModels.tsx          |  48 +-
 .../dmn-editor/src/mutations/addConnectedNode.ts   |   4 +-
 packages/dmn-editor/src/mutations/addEdge.ts       |  12 +-
 packages/dmn-editor/src/mutations/deleteEdge.ts    |  68 ++-
 packages/dmn-editor/src/mutations/deleteNode.ts    | 163 +++++-
 .../dmn-editor/src/overlaysPanel/OverlaysPanel.tsx |  17 +-
 .../src/propertiesPanel/BeePropertiesPanel.tsx     |  18 +-
 .../src/propertiesPanel/BkmProperties.tsx          |   7 +-
 .../src/propertiesPanel/DecisionProperties.tsx     |   8 +-
 .../propertiesPanel/DecisionServiceProperties.tsx  |  13 +-
 .../src/propertiesPanel/DiagramPropertiesPanel.tsx |  10 +-
 .../DocumentationLinksFormGroup.tsx                |   6 +-
 .../dmn-editor/src/propertiesPanel/FontOptions.tsx |  14 +-
 .../propertiesPanel/GlobalDiagramProperties.tsx    |   4 +-
 .../src/propertiesPanel/GroupProperties.tsx        |   2 +-
 .../src/propertiesPanel/InputDataProperties.tsx    |   8 +-
 .../propertiesPanel/KnowledgeSourceProperties.tsx  |   8 +-
 .../src/propertiesPanel/MultipleNodeProperties.tsx |   2 +-
 .../src/propertiesPanel/ShapeOptions.tsx           |  15 +-
 .../src/propertiesPanel/SingleNodeProperties.tsx   |  11 +-
 .../propertiesPanel/TextAnnotationProperties.tsx   |   2 +-
 .../src/propertiesPanel/UnknownProperties.tsx      |  10 +-
 .../dmn-editor/src/store/ComputedStateCache.ts     |  76 +++
 packages/dmn-editor/src/store/DerivedStore.tsx     | 311 ----------
 packages/dmn-editor/src/store/Store.ts             | 345 +++++++-----
 packages/dmn-editor/src/store/StoreContext.ts      |  47 ++
 .../computed/computeAllFeelVariableUniqueNames.ts} |  39 +-
 .../src/store/computed/computeDataTypes.ts         | 131 +++++
 .../src/store/computed/computeDiagramData.ts       | 432 ++++++++++++++
 .../store/computed/computeExternalModelsByType.ts  |  50 ++
 .../computed/computeImportsByNamespace.ts}         |  35 +-
 .../src/store/computed/computeIndexes.ts           |  68 +++
 .../computeIsDropTargetNodeValidForSelection.ts}   |  34 +-
 .../computed/initial.ts}                           |  60 +-
 packages/dmn-editor/src/store/useDiagramData.tsx   | 474 ----------------
 packages/dmn-editor/src/svg/DmnDiagramSvg.tsx      | 222 ++++----
 packages/dmn-editor/tsconfig.json                  |   6 +-
 .../src/parser/VariablesRepository.ts              |   2 +-
 pnpm-lock.yaml                                     |  11 +
 79 files changed, 3337 insertions(+), 2216 deletions(-)

diff --git a/packages/dmn-editor/package.json b/packages/dmn-editor/package.json
index 8a25ed3216e..8e05a5dfe65 100644
--- a/packages/dmn-editor/package.json
+++ b/packages/dmn-editor/package.json
@@ -46,6 +46,8 @@
     "@visx/text": "^3.3.0",
     "d3-drag": "^3.0.0",
     "d3-selection": "^3.0.0",
+    "elkjs": "^0.9.1",
+    "fast-deep-equal": "^3.1.3",
     "immer": "^10.0.3",
     "moment": "^2.29.4",
     "react": "^17.0.2",
diff --git a/packages/dmn-editor/src/DmnEditor.css b/packages/dmn-editor/src/DmnEditor.css
index 861f8f78c2b..444d2b7217c 100644
--- a/packages/dmn-editor/src/DmnEditor.css
+++ b/packages/dmn-editor/src/DmnEditor.css
@@ -318,17 +318,48 @@
 }
 /* (end) version popover */
 
-/* (begin) overlays panel toggle */
-.kie-dmn-editor--overlay-panel-popover .pf-c-popover__body {
-  padding: 0;
+/* (begin) autolayout panel toggle */
+.kie-dmn-editor--autolayout-panel-toggle {
+  width: 42px;
+  background: #fff;
+  border-radius: 40px;
+  border: 1px solid black;
 }
-.kie-dmn-editor--overlays-panel-toggle {
+.kie-dmn-editor--autolayout-panel-toggle:not(:last-child) {
   margin-right: 16px;
+}
+
+.kie-dmn-editor--autolayout-panel-toggle:hover {
+  box-shadow: -4px 4px 2px 0px rgb(127 127 127);
+}
+.kie-dmn-editor--autolayout-panel-toggle-button {
+  margin: 0;
+  width: 40px;
+  height: 40px;
+  max-width: 40px;
+  border-radius: 40px;
+  border: 0;
+  background: white;
+}
+.kie-dmn-editor--autolayout-panel-toggle-button:hover {
+  filter: brightness(95%);
+}
+.kie-dmn-editor--autolayout-panel-toggle-button:active {
+  filter: brightness(90%);
+}
+/* (end) autolayout panel toggle */
+
+/* (begin) overlays panel toggle */
+.kie-dmn-editor--overlays-panel-toggle {
   width: 42px;
   background: #fff;
   border-radius: 40px;
   border: 1px solid black;
 }
+.kie-dmn-editor--overlays-panel-toggle:not(:last-child) {
+  margin-right: 16px;
+}
+
 .kie-dmn-editor--overlays-panel-toggle:hover {
   box-shadow: -4px 4px 2px 0px rgb(127 127 127);
 }
@@ -395,7 +426,8 @@
   left: 58px;
   overflow: auto;
   box-shadow: 0px 5px 10px 0px lightgray;
-  background: white;
+  background: rgb(255, 255, 255, 90%);
+  backdrop-filter: blur(4px);
   width: 400px;
 }
 .kie-dmn-editor--external-nodes-panel-toggle {
@@ -700,14 +732,13 @@ circle.kie-dmn-editor--diagram-edge-waypoint:hover {
 }
 .kie-dmn-editor--external-nodes-list-item {
   border-radius: 999px;
-  background: white;
 }
 .kie-dmn-editor--external-nodes-list-item:hover {
-  filter: brightness(95%);
+  background-color: rgba(0, 0, 0, 0.1);
   cursor: grab;
 }
 .kie-dmn-editor--external-nodes-list-item:active {
-  filter: brightness(90%);
+  background-color: rgba(0, 0, 0, 0.15);
   cursor: grabbing;
 }
 /* (end) external nodes */
@@ -903,7 +934,9 @@ th {
   fill: rgba(0, 107, 164, 0.1) !important;
 }
 
-.react-flow__node.selected:not(.react-flow__node-node_unknown) > .kie-dmn-editor--node-shape > * {
+.react-flow__node.selected:not(.react-flow__node-node_unknown):not(.react-flow__node-node_textAnnotation)
+  > .kie-dmn-editor--node-shape
+  > * {
   stroke: #006ba4 !important;
 }
 
diff --git a/packages/dmn-editor/src/DmnEditor.tsx b/packages/dmn-editor/src/DmnEditor.tsx
index 522838bb0f6..d1eb175c043 100644
--- a/packages/dmn-editor/src/DmnEditor.tsx
+++ b/packages/dmn-editor/src/DmnEditor.tsx
@@ -20,47 +20,40 @@
 import "@patternfly/react-core/dist/styles/base.css";
 import "reactflow/dist/style.css";
 
-import * as React from "react";
-import * as ReactDOM from "react-dom";
-import * as RF from "reactflow";
-import { useCallback, useEffect, useImperativeHandle, useRef, useState, useMemo } from "react";
+import { AllDmnMarshallers, DmnLatestModel } from "@kie-tools/dmn-marshaller";
+import { PMML } from "@kie-tools/pmml-editor-marshaller";
 import { Drawer, DrawerContent, DrawerContentBody } from "@patternfly/react-core/dist/js/components/Drawer";
+import { Label } from "@patternfly/react-core/dist/js/components/Label";
 import { Tab, TabTitleIcon, TabTitleText, Tabs } from "@patternfly/react-core/dist/js/components/Tabs";
 import { FileIcon } from "@patternfly/react-icons/dist/js/icons/file-icon";
 import { InfrastructureIcon } from "@patternfly/react-icons/dist/js/icons/infrastructure-icon";
 import { PficonTemplateIcon } from "@patternfly/react-icons/dist/js/icons/pficon-template-icon";
+import { original } from "immer";
+import * as React from "react";
+import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
+import * as ReactDOM from "react-dom";
+import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from "react-error-boundary";
+import * as RF from "reactflow";
+import { DmnEditorContextProvider, useDmnEditor } from "./DmnEditorContext";
+import { DmnEditorErrorFallback } from "./DmnEditorErrorFallback";
 import { BoxedExpression } from "./boxedExpressions/BoxedExpression";
 import { DataTypes } from "./dataTypes/DataTypes";
 import { Diagram, DiagramRef } from "./diagram/Diagram";
 import { DmnVersionLabel } from "./diagram/DmnVersionLabel";
+import { DmnEditorExternalModelsContextProvider } from "./includedModels/DmnEditorDependenciesContext";
 import { IncludedModels } from "./includedModels/IncludedModels";
+import { BeePropertiesPanel } from "./propertiesPanel/BeePropertiesPanel";
 import { DiagramPropertiesPanel } from "./propertiesPanel/DiagramPropertiesPanel";
-import {
-  DmnEditorStoreApiContext,
-  DmnEditorTab,
-  StoreApiType,
-  createDmnEditorStore,
-  defaultStaticState,
-  useDmnEditorStore,
-  useDmnEditorStoreApi,
-} from "./store/Store";
+import { ComputedStateCache } from "./store/ComputedStateCache";
+import { Computed, DmnEditorTab, createDmnEditorStore, defaultStaticState } from "./store/Store";
+import { DmnEditorStoreApiContext, StoreApiType, useDmnEditorStore, useDmnEditorStoreApi } from "./store/StoreContext";
+import { DmnDiagramSvg } from "./svg/DmnDiagramSvg";
 import { useEffectAfterFirstRender } from "./useEffectAfterFirstRender";
-import { Label } from "@patternfly/react-core/dist/js/components/Label";
-import { BeePropertiesPanel } from "./propertiesPanel/BeePropertiesPanel";
-import { DmnEditorDerivedStoreContextProvider, useDmnEditorDerivedStore } from "./store/DerivedStore";
-import { DmnEditorContextProvider, useDmnEditor } from "./DmnEditorContext";
-import { DmnEditorExternalModelsContextProvider } from "./includedModels/DmnEditorDependenciesContext";
-import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from "react-error-boundary";
-import { DmnEditorErrorFallback } from "./DmnEditorErrorFallback";
-import { DmnLatestModel, AllDmnMarshallers } from "@kie-tools/dmn-marshaller";
-import { PMML } from "@kie-tools/pmml-editor-marshaller";
-import { original } from "immer";
+import { INITIAL_COMPUTED_CACHE } from "./store/computed/initial";
 
 import "@kie-tools/dmn-marshaller/dist/kie-extensions"; // This is here because of the KIE Extension for DMN.
 import "./DmnEditor.css"; // Leave it for last, as this overrides some of the PF and RF styles.
 
-import { DmnDiagramSvg } from "./svg/DmnDiagramSvg";
-
 const ON_MODEL_CHANGE_DEBOUNCE_TIME_IN_MS = 500;
 
 const SVG_PADDING = 20;
@@ -163,10 +156,15 @@ export const DmnEditorInternal = ({
   onModelChange,
   forwardRef,
 }: DmnEditorProps & { forwardRef?: React.Ref<DmnEditorRef> }) => {
-  const { boxedExpressionEditor, dmn, navigation, dispatch, diagram } = useDmnEditorStore((s) => s);
+  const boxedExpressionEditorActiveDrgElementId = useDmnEditorStore((s) => s.boxedExpressionEditor.activeDrgElementId);
+  const isBeePropertiesPanelOpen = useDmnEditorStore((s) => s.boxedExpressionEditor.propertiesPanel.isOpen);
+  const isDiagramPropertiesPanelOpen = useDmnEditorStore((s) => s.diagram.propertiesPanel.isOpen);
+  const navigationTab = useDmnEditorStore((s) => s.navigation.tab);
+  const dmn = useDmnEditorStore((s) => s.dmn);
+  const isDiagramEditingInProgress = useDmnEditorStore((s) => s.computed(s).isDiagramEditingInProgress());
 
   const dmnEditorStoreApi = useDmnEditorStoreApi();
-  const { isDiagramEditingInProgress, importsByNamespace } = useDmnEditorDerivedStore();
+
   const { dmnModelBeforeEditingRef, dmnEditorRootElementRef } = useDmnEditor();
 
   // Refs
@@ -179,7 +177,10 @@ export const DmnEditorInternal = ({
   useImperativeHandle(
     forwardRef,
     () => ({
-      reset: (model) => dispatch.dmn.reset(model),
+      reset: (model) => {
+        const state = dmnEditorStoreApi.getState();
+        return state.dispatch(state).dmn.reset(model);
+      },
       getDiagramSvg: async () => {
         const nodes = diagramRef.current?.getReactFlowInstance()?.getNodes();
         const edges = diagramRef.current?.getReactFlowInstance()?.getEdges();
@@ -187,12 +188,14 @@ export const DmnEditorInternal = ({
           return undefined;
         }
 
-        const bounds = RF.getRectOfNodes(nodes);
+        const bounds = RF.getNodesBounds(nodes);
 
         const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
         svg.setAttribute("width", bounds.width + SVG_PADDING * 2 + "");
         svg.setAttribute("height", bounds.height + SVG_PADDING * 2 + "");
 
+        const state = dmnEditorStoreApi.getState();
+
         // We're still on React 17.
         // eslint-disable-next-line react/no-deprecated
         ReactDOM.render(
@@ -201,9 +204,9 @@ export const DmnEditorInternal = ({
             <DmnDiagramSvg
               nodes={nodes}
               edges={edges}
-              snapGrid={diagram.snapGrid}
-              importsByNamespace={importsByNamespace}
-              thisDmn={dmnEditorStoreApi.getState().dmn}
+              snapGrid={state.diagram.snapGrid}
+              importsByNamespace={state.computed(state).importsByNamespace()}
+              thisDmn={state.dmn}
             />
           </g>,
           svg
@@ -212,7 +215,7 @@ export const DmnEditorInternal = ({
         return new XMLSerializer().serializeToString(svg);
       },
     }),
-    [diagram.snapGrid, dispatch.dmn, dmnEditorStoreApi, importsByNamespace]
+    [dmnEditorStoreApi]
   );
 
   // Make sure the DMN Editor reacts to props changing.
@@ -225,7 +228,7 @@ export const DmnEditorInternal = ({
       state.dmn.model = model;
       dmnModelBeforeEditingRef.current = model;
     });
-  }, [dmnEditorStoreApi, dispatch.dmn, model]);
+  }, [dmnEditorStoreApi, model]);
 
   useStateAsItWasBeforeConditionBecameTrue(
     dmn.model,
@@ -311,16 +314,16 @@ export const DmnEditorInternal = ({
     <div ref={dmnEditorRootElementRef} className={"kie-dmn-editor--root"}>
       <Tabs
         isFilled={true}
-        activeKey={navigation.tab}
+        activeKey={navigationTab}
         onSelect={onTabChanged}
         role={"region"}
         className={"kie-dmn-editor--tabs"}
       >
         <Tab eventKey={DmnEditorTab.EDITOR} title={tabTitle.editor}>
-          {navigation.tab === DmnEditorTab.EDITOR && (
+          {navigationTab === DmnEditorTab.EDITOR && (
             <>
-              {!boxedExpressionEditor.activeDrgElementId && (
-                <Drawer isExpanded={diagram.propertiesPanel.isOpen} isInline={true} position={"right"}>
+              {!boxedExpressionEditorActiveDrgElementId && (
+                <Drawer isExpanded={isDiagramPropertiesPanelOpen} isInline={true} position={"right"}>
                   <DrawerContent panelContent={diagramPropertiesPanel}>
                     <DrawerContentBody>
                       <div className={"kie-dmn-editor--diagram-container"} ref={diagramContainerRef}>
@@ -331,8 +334,8 @@ export const DmnEditorInternal = ({
                   </DrawerContent>
                 </Drawer>
               )}
-              {boxedExpressionEditor.activeDrgElementId && (
-                <Drawer isExpanded={boxedExpressionEditor.propertiesPanel.isOpen} isInline={true} position={"right"}>
+              {boxedExpressionEditorActiveDrgElementId && (
+                <Drawer isExpanded={isBeePropertiesPanelOpen} isInline={true} position={"right"}>
                   <DrawerContent panelContent={beePropertiesPanel}>
                     <DrawerContentBody>
                       <div className={"kie-dmn-editor--bee-container"} ref={beeContainerRef}>
@@ -347,11 +350,11 @@ export const DmnEditorInternal = ({
         </Tab>
 
         <Tab eventKey={DmnEditorTab.DATA_TYPES} title={tabTitle.dataTypes}>
-          {navigation.tab === DmnEditorTab.DATA_TYPES && <DataTypes />}
+          {navigationTab === DmnEditorTab.DATA_TYPES && <DataTypes />}
         </Tab>
 
         <Tab eventKey={DmnEditorTab.INCLUDED_MODELS} title={tabTitle.includedModels}>
-          {navigation.tab === DmnEditorTab.INCLUDED_MODELS && <IncludedModels />}
+          {navigationTab === DmnEditorTab.INCLUDED_MODELS && <IncludedModels />}
         </Tab>
       </Tabs>
     </div>
@@ -359,7 +362,13 @@ export const DmnEditorInternal = ({
 };
 
 export const DmnEditor = React.forwardRef((props: DmnEditorProps, ref: React.Ref<DmnEditorRef>) => {
-  const storeRef = React.useRef<StoreApiType>(createDmnEditorStore(props.model));
+  const store = useMemo(
+    () => createDmnEditorStore(props.model, new ComputedStateCache<Computed>(INITIAL_COMPUTED_CACHE)),
+    // Purposefully empty. This memoizes the initial value of the store
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+    []
+  );
+  const storeRef = React.useRef<StoreApiType>(store);
 
   const resetState: ErrorBoundaryPropsWithFallback["onReset"] = useCallback(({ args }) => {
     storeRef.current?.setState((state) => {
@@ -373,9 +382,7 @@ export const DmnEditor = React.forwardRef((props: DmnEditorProps, ref: React.Ref
       <ErrorBoundary FallbackComponent={DmnEditorErrorFallback} onReset={resetState}>
         <DmnEditorExternalModelsContextProvider {...props}>
           <DmnEditorStoreApiContext.Provider value={storeRef.current}>
-            <DmnEditorDerivedStoreContextProvider>
-              <DmnEditorInternal forwardRef={ref} {...props} />
-            </DmnEditorDerivedStoreContextProvider>
+            <DmnEditorInternal forwardRef={ref} {...props} />
           </DmnEditorStoreApiContext.Provider>
         </DmnEditorExternalModelsContextProvider>
       </ErrorBoundary>
diff --git a/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx b/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx
new file mode 100644
index 00000000000..f207394ed89
--- /dev/null
+++ b/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx
@@ -0,0 +1,557 @@
+/*
+ * 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 { generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
+import { DC__Bounds } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import OptimizeIcon from "@patternfly/react-icons/dist/js/icons/optimize-icon";
+import ELK, * as Elk from "elkjs/lib/elk.bundled.js";
+import * as React from "react";
+import { PositionalNodeHandleId } from "../diagram/connections/PositionalNodeHandles";
+import { EdgeType, NodeType } from "../diagram/connections/graphStructure";
+import { getAdjMatrix, traverse } from "../diagram/graph/graph";
+import { getContainmentRelationship } from "../diagram/maths/DmnMaths";
+import { DEFAULT_NODE_SIZES, MIN_NODE_SIZES } from "../diagram/nodes/DefaultSizes";
+import { NODE_TYPES } from "../diagram/nodes/NodeTypes";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
+import { addEdge } from "../mutations/addEdge";
+import { repositionNode } from "../mutations/repositionNode";
+import { resizeNode } from "../mutations/resizeNode";
+import { updateDecisionServiceDividerLine } from "../mutations/updateDecisionServiceDividerLine";
+import { useDmnEditorStoreApi } from "../store/StoreContext";
+
+const elk = new ELK();
+
+export const ELK_OPTIONS = {
+  "elk.algorithm": "layered",
+  "elk.direction": "UP",
+  // By making width a lot bigger than height, we make sure disjoint graph components are placed horizontally, never vertically
+  "elk.aspectRatio": "9999999999",
+  // spacing
+  "elk.spacing.nodeNode": "60",
+  "elk.spacing.componentComponent": "200",
+  "layered.spacing.edgeEdgeBetweenLayers": "0",
+  "layered.spacing.edgeNodeBetweenLayers": "0",
+  "layered.spacing.nodeNodeBetweenLayers": "100",
+  // edges
+  "elk.edgeRouting": "ORTHOGONAL",
+  "elk.layered.mergeEdges": "true", // we need this to make sure space is consistent between layers.
+  "elk.layered.mergeHierarchyEdges": "true",
+  // positioning
+  "elk.partitioning.activate": "true",
+  "elk.nodePlacement.favorStraightEdges": "true",
+  "elk.nodePlacement.bk.fixedAlignment": "LEFTDOWN",
+  "elk.nodePlacement.bk.edgeStraightening": "IMPROVE_STRAIGHTNESS",
+  //
+  "layering.strategy": "LONGEST_PATH_SOURCE",
+};
+
+const PARENT_NODE_ELK_OPTIONS = {
+  "elk.padding": "[left=60, top=60, right=80, bottom=60]",
+  "elk.spacing.componentComponent": "60",
+};
+
+export interface AutolayoutParentNode {
+  decisionServiceSection: "output" | "encapsulated" | "n/a";
+  elkNode: Elk.ElkNode;
+  contained: Set<string>;
+  dependents: Set<string>;
+  dependencies: Set<string>;
+  contains: (otherNode: { id: string; bounds: DC__Bounds | undefined }) => {
+    isInside: boolean;
+    decisionServiceSection: AutolayoutParentNode["decisionServiceSection"];
+  };
+  hasDependencyTo: (otherNode: { id: string }) => boolean;
+  isDependencyOf: (otherNode: { id: string }) => boolean;
+}
+
+const FAKE_MARKER = "__$FAKE$__";
+
+export function AutolayoutButton() {
+  const dmnEditorStoreApi = useDmnEditorStoreApi();
+  const { externalModelsByNamespace } = useExternalModels();
+
+  const onApply = React.useCallback(async () => {
+    const parentNodesById = new Map<string, AutolayoutParentNode>();
+    const nodeParentsById = new Map<string, Set<string>>();
+
+    /**
+      Used to tell ELK that dependencies of nodes' children should be considered the node's dependency too.
+      This allows us to not rely on INCLUDE_STRATEGY hierarchy handling on ELK, keeping disjoint graph components separate, rendering side-by-side.
+     */
+    const fakeEdgesForElk = new Set<Elk.ElkExtendedEdge>();
+
+    const state = dmnEditorStoreApi.getState();
+
+    const snapGrid = state.diagram.snapGrid;
+    const nodesById = state.computed(state).getDiagramData(externalModelsByNamespace).nodesById;
+    const edgesById = state.computed(state).getDiagramData(externalModelsByNamespace).edgesById;
+    const nodes = state.computed(state).getDiagramData(externalModelsByNamespace).nodes;
+    const edges = state.computed(state).getDiagramData(externalModelsByNamespace).edges;
+    const drgEdges = state.computed(state).getDiagramData(externalModelsByNamespace).drgEdges;
+
+    const adjMatrix = getAdjMatrix(drgEdges);
+
+    // 1. First we populate the `parentNodesById` map so that we know exactly what parent nodes we're dealing with. Decision Service nodes have two fake nodes to represent Output and Encapsulated sections.
+    for (const node of nodes) {
+      const dependencies = new Set<string>();
+      const dependents = new Set<string>();
+
+      if (node.data?.dmnObject?.__$$element === "decisionService") {
+        const outputs = new Set([...(node.data.dmnObject.outputDecision ?? []).map((s) => s["@_href"])]);
+        const encapsulated = new Set([...(node.data.dmnObject.encapsulatedDecision ?? []).map((s) => s["@_href"])]);
+
+        const idOfFakeNodeForOutputSection = `${node.id}${FAKE_MARKER}dsOutput`;
+        const idOfFakeNodeForEncapsulatedSection = `${node.id}${FAKE_MARKER}dsEncapsulated`;
+
+        const dsSize = MIN_NODE_SIZES[NODE_TYPES.decisionService](snapGrid);
+        parentNodesById.set(node.id, {
+          elkNode: {
+            id: node.id,
+            width: dsSize["@_width"],
+            height: dsSize["@_height"],
+            children: [
+              {
+                id: idOfFakeNodeForOutputSection,
+                width: dsSize["@_width"],
+                height: dsSize["@_height"] / 2,
+                children: [],
+                layoutOptions: {
+                  ...ELK_OPTIONS,
+                  ...PARENT_NODE_ELK_OPTIONS,
+                },
+              },
+              {
+                id: idOfFakeNodeForEncapsulatedSection,
+                width: dsSize["@_width"],
+                height: dsSize["@_height"] / 2,
+                children: [],
+                layoutOptions: {
+                  ...ELK_OPTIONS,
+                  ...PARENT_NODE_ELK_OPTIONS,
+                },
+              },
+            ],
+            layoutOptions: {
+              "elk.algorithm": "layered",
+              "elk.direction": "UP",
+              "elk.aspectRatio": "9999999999",
+              "elk.partitioning.activate": "true",
+              "elk.spacing.nodeNode": "0",
+              "elk.spacing.componentComponent": "0",
+              "layered.spacing.edgeEdgeBetweenLayers": "0",
+              "layered.spacing.edgeNodeBetweenLayers": "0",
+              "layered.spacing.nodeNodeBetweenLayers": "0",
+              "elk.padding": "[left=0, top=0, right=0, bottom=0]",
+            },
+          },
+          decisionServiceSection: "output",
+          dependencies,
+          dependents,
+          contained: outputs,
+          contains: ({ id }) => ({
+            isInside: outputs.has(id) || encapsulated.has(id),
+            decisionServiceSection: outputs.has(id) ? "output" : encapsulated.has(id) ? "encapsulated" : "n/a",
+          }),
+          isDependencyOf: ({ id }) => dependents.has(id),
+          hasDependencyTo: ({ id }) => dependencies.has(id),
+        });
+
+        fakeEdgesForElk.add({
+          id: `${node.id}${FAKE_MARKER}fakeOutputEncapsulatedEdge`,
+          sources: [idOfFakeNodeForEncapsulatedSection],
+          targets: [idOfFakeNodeForOutputSection],
+        });
+      } else if (node.data?.dmnObject?.__$$element === "group") {
+        const groupSize = DEFAULT_NODE_SIZES[NODE_TYPES.group](snapGrid);
+        const groupBounds = node.data.shape["dc:Bounds"];
+        parentNodesById.set(node.id, {
+          decisionServiceSection: "n/a",
+          elkNode: {
+            id: node.id,
+            width: groupBounds?.["@_width"] ?? groupSize["@_width"],
+            height: groupBounds?.["@_height"] ?? groupSize["@_height"],
+            children: [],
+            layoutOptions: {
+              ...ELK_OPTIONS,
+              ...PARENT_NODE_ELK_OPTIONS,
+            },
+          },
+          dependencies,
+          dependents,
+          contained: new Set(),
+          contains: ({ id, bounds }) => ({
+            isInside: getContainmentRelationship({
+              bounds: bounds!,
+              container: groupBounds!,
+              snapGrid,
+              containerMinSizes: MIN_NODE_SIZES[NODE_TYPES.group],
+              boundsMinSizes: MIN_NODE_SIZES[nodesById.get(id)?.type as NodeType],
+            }).isInside,
+            decisionServiceSection: "n/a",
+          }),
+          isDependencyOf: ({ id }) => dependents.has(id),
+          hasDependencyTo: ({ id }) => dependencies.has(id),
+        });
+      }
+    }
+
+    // 2. Then we map all the nodes to elkNodes, including the parents. We mutate parents on the fly when iterating over the nodes list.
+    const elkNodes = nodes.flatMap((node) => {
+      const parent = parentNodesById.get(node.id);
+      if (parent) {
+        return [];
+      }
+
+      const defaultSize = DEFAULT_NODE_SIZES[node.type as NodeType](snapGrid);
+      const elkNode: Elk.ElkNode = {
+        id: node.id,
+        width: node.data.shape["dc:Bounds"]?.["@_width"] ?? defaultSize["@_width"],
+        height: node.data.shape["dc:Bounds"]?.["@_height"] ?? defaultSize["@_height"],
+        children: [],
+        layoutOptions: {
+          "partitioning.partition":
+            // Since textAnnotations and knowledgeSources are not related to the logic, we leave them at the bottom.
+            (node.type as NodeType) === NODE_TYPES.textAnnotation ||
+            (node.type as NodeType) === NODE_TYPES.knowledgeSource
+              ? "0"
+              : "1",
+        },
+      };
+
+      // FIXME: Tiago --> Improve performance here as part of https://github.com/apache/incubator-kie-issues/issues/451.
+      const parents = [...parentNodesById.values()].filter(
+        (p) => p.contains({ id: elkNode.id, bounds: node.data.shape["dc:Bounds"] }).isInside
+      );
+      if (parents.length > 0) {
+        const decisionServiceSection = parents[0].contains({
+          id: elkNode.id,
+          bounds: node.data.shape["dc:Bounds"],
+        }).decisionServiceSection;
+
+        // The only relationship that ELK will know about is the first matching container for this node.
+        if (decisionServiceSection === "n/a") {
+          parents[0].elkNode.children?.push(elkNode);
+        } else if (decisionServiceSection === "output") {
+          parents[0].elkNode.children?.[0].children?.push(elkNode);
+        } else if (decisionServiceSection === "encapsulated") {
+          parents[0].elkNode.children?.[1].children?.push(elkNode);
+        } else {
+          throw new Error(`Unknown decisionServiceSection ${decisionServiceSection}`);
+        }
+
+        for (const p of parents) {
+          p.contained?.add(elkNode.id); // We need to keep track of nodes that are contained by multiple groups, but ELK will only know about one of those containment relationships.
+          nodeParentsById.set(node.id, new Set([...(nodeParentsById.get(node.id) ?? []), p.elkNode.id]));
+        }
+        return [];
+      }
+
+      return [elkNode];
+    });
+
+    // 3. After we have all containment relationships defined, we can proceed to resolving the hierarchical relationships.
+    for (const [_, parentNode] of parentNodesById) {
+      traverse(adjMatrix, parentNode.contained, [...parentNode.contained], "down", (n) => {
+        parentNode.dependencies.add(n);
+      });
+      traverse(adjMatrix, parentNode.contained, [...parentNode.contained], "up", (n) => {
+        parentNode.dependents.add(n);
+      });
+
+      const p = nodesById.get(parentNode.elkNode.id);
+      if (p?.type === NODE_TYPES.group && parentNode.elkNode.children?.length === 0) {
+        continue; // Ignore empty group nodes.
+      } else {
+        elkNodes.push(parentNode.elkNode);
+      }
+    }
+
+    // 4. After we have all containment and hierarchical relationships defined, we can add the fake edges so that ELK creates the structure correctly.
+    for (const node of nodes) {
+      const parentNodes = [...parentNodesById.values()];
+
+      const dependents = parentNodes.filter((p) => p.hasDependencyTo({ id: node.id }));
+      for (const dependent of dependents) {
+        // Not all nodes are present in all DRD
+        if (nodesById.has(node.id) && nodesById.has(dependent.elkNode.id)) {
+          fakeEdgesForElk.add({
+            id: `${generateUuid()}${FAKE_MARKER}__fake`,
+            sources: [node.id],
+            targets: [dependent.elkNode.id],
+          });
+        }
+
+        for (const p of nodeParentsById.get(node.id) ?? []) {
+          // Not all nodes are present in all DRD
+          if (nodesById.has(p) && nodesById.has(dependent.elkNode.id)) {
+            fakeEdgesForElk.add({
+              id: `${generateUuid()}${FAKE_MARKER}__fake`,
+              sources: [p],
+              targets: [dependent.elkNode.id],
+            });
+          }
+        }
+      }
+
+      const dependencies = parentNodes.filter((p) => p.isDependencyOf({ id: node.id }));
+      for (const dependency of dependencies) {
+        // Not all nodes are present in all DRD
+        if (nodesById.has(node.id) && nodesById.has(dependency.elkNode.id)) {
+          fakeEdgesForElk.add({
+            id: `${generateUuid()}${FAKE_MARKER}__fake`,
+            sources: [dependency.elkNode.id],
+            targets: [node.id],
+          });
+        }
+
+        for (const p of nodeParentsById.get(node.id) ?? []) {
+          // Not all nodes are present in all DRD
+          if (nodesById.has(p) && nodesById.has(dependency.elkNode.id)) {
+            fakeEdgesForElk.add({
+              id: `${generateUuid()}${FAKE_MARKER}__fake`,
+              sources: [dependency.elkNode.id],
+              targets: [p],
+            });
+          }
+        }
+      }
+    }
+
+    // 5. Concatenate real and fake edges to pass to ELK.
+    const elkEdges = [
+      ...fakeEdgesForElk,
+      ...[...edgesById.values()].flatMap((e) => {
+        // Not all nodes are present in all DRD
+        if (nodesById.has(e.source) && nodesById.has(e.target)) {
+          return {
+            id: e.id,
+            sources: [e.source],
+            targets: [e.target],
+          };
+        } else {
+          return [];
+        }
+      }),
+    ];
+
+    // 6. Run ELK.
+    const autolayouted = await runElk(elkNodes, elkEdges, ELK_OPTIONS);
+
+    // 7. Update all nodes positions skipping empty groups, which will be positioned manually after all nodes are done being repositioned.
+    dmnEditorStoreApi.setState((s) => {
+      const autolayoutedElkNodesById = new Map<string, Elk.ElkNode>();
+
+      for (const topLevelElkNode of autolayouted.nodes ?? []) {
+        visitNodeAndNested(topLevelElkNode, { x: 100, y: 100 }, (elkNode, positionOffset) => {
+          if (elkNode.id.includes(FAKE_MARKER)) {
+            return;
+          }
+
+          autolayoutedElkNodesById.set(elkNode.id, elkNode);
+
+          const nodeId = elkNode.id;
+          const node = s.computed(s).getDiagramData(externalModelsByNamespace).nodesById.get(nodeId)!;
+
+          repositionNode({
+            definitions: s.dmn.model.definitions,
+            drdIndex: s.diagram.drdIndex,
+            controlWaypointsByEdge: new Map(),
+            change: {
+              nodeType: node.type as NodeType,
+              type: "absolute",
+              position: {
+                x: elkNode.x! + positionOffset.x,
+                y: elkNode.y! + positionOffset.y,
+              },
+              selectedEdges: [...edgesById.keys()],
+              shapeIndex: node.data?.shape.index,
+              sourceEdgeIndexes: edges.flatMap((e) =>
+                e.source === nodeId && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
+              ),
+              targetEdgeIndexes: edges.flatMap((e) =>
+                e.target === nodeId && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
+              ),
+            },
+          });
+        });
+      }
+
+      // 8. Resize all nodes using the sizes calculated by ELK.
+      for (const topLevelElkNode of autolayouted.nodes ?? []) {
+        visitNodeAndNested(topLevelElkNode, { x: 0, y: 0 }, (elkNode) => {
+          if (elkNode.id.includes(FAKE_MARKER)) {
+            return;
+          }
+
+          const nodeId = elkNode.id;
+          const node = s.computed(s).getDiagramData(externalModelsByNamespace).nodesById.get(nodeId)!;
+
+          resizeNode({
+            definitions: s.dmn.model.definitions,
+            drdIndex: s.diagram.drdIndex,
+            dmnShapesByHref: s.computed(s).indexes().dmnShapesByHref,
+            snapGrid,
+            change: {
+              index: node.data.index,
+              isExternal: !!node.data.dmnObjectQName.prefix,
+              nodeType: node.type as NodeType,
+              dimension: {
+                "@_width": elkNode.width!,
+                "@_height": elkNode.height!,
+              },
+              shapeIndex: node.data?.shape.index,
+              sourceEdgeIndexes: edges.flatMap((e) =>
+                e.source === nodeId && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
+              ),
+              targetEdgeIndexes: edges.flatMap((e) =>
+                e.target === nodeId && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
+              ),
+            },
+          });
+        });
+      }
+
+      // 9. Updating Decision Service divider lines after all nodes are repositioned and resized.
+      for (const [parentNodeId] of parentNodesById) {
+        const parentNode = s.computed(s).getDiagramData(externalModelsByNamespace).nodesById.get(parentNodeId);
+        if (parentNode?.type !== NODE_TYPES.decisionService) {
+          continue;
+        }
+
+        const elkNode = autolayoutedElkNodesById.get(parentNodeId);
+        if (!elkNode) {
+          throw new Error(`Couldn't find Decision Service with id ${parentNode.id} at the autolayouted nodes map`);
+        }
+
+        /**
+         * The second children of a Decision Service elkNode is a node representing the Encapsulated section.
+         * It's Y position will be exactly where the divider line should be.
+         */
+        const dividerLinerLocalYPosition = elkNode.children?.[1]?.y;
+        if (!dividerLinerLocalYPosition) {
+          throw new Error(
+            `Couldn't find second child (which represents the Encapuslated Decision section) of Decision Service with id ${parentNode.id} at the autolayouted nodes map`
+          );
+        }
+
+        updateDecisionServiceDividerLine({
+          definitions: s.dmn.model.definitions,
+          drdIndex: s.diagram.drdIndex,
+          dmnShapesByHref: s.computed(s).indexes().dmnShapesByHref,
+          drgElementIndex: parentNode.data.index,
+          shapeIndex: parentNode.data.shape.index,
+          snapGrid,
+          localYPosition: dividerLinerLocalYPosition,
+        });
+      }
+
+      // 10. Update the edges. Edges always go from top to bottom, removing waypoints.
+      for (const elkEdge of autolayouted.edges ?? []) {
+        if (elkEdge.id.includes(FAKE_MARKER)) {
+          continue;
+        }
+
+        const edge = s.computed(s).getDiagramData(externalModelsByNamespace).edgesById.get(elkEdge.id)!;
+
+        const sourceNode = s.computed(s).getDiagramData(externalModelsByNamespace).nodesById.get(elkEdge.sources[0])!;
+        const targetNode = s.computed(s).getDiagramData(externalModelsByNamespace).nodesById.get(elkEdge.targets[0])!;
+
+        // If the target is an external node, we don't have to create the edge.
+        if (targetNode.data.dmnObjectQName.prefix) {
+          continue;
+        }
+
+        addEdge({
+          definitions: s.dmn.model.definitions,
+          drdIndex: s.diagram.drdIndex,
+          edge: {
+            autoPositionedEdgeMarker: undefined,
+            type: edge.type as EdgeType,
+            targetHandle: PositionalNodeHandleId.Bottom,
+            sourceHandle: PositionalNodeHandleId.Top,
+          },
+          sourceNode: {
+            type: sourceNode.type as NodeType,
+            href: sourceNode.id,
+            data: sourceNode.data,
+            bounds: sourceNode.data.shape["dc:Bounds"]!,
+            shapeId: sourceNode.data.shape["@_id"],
+          },
+          targetNode: {
+            type: targetNode.type as NodeType,
+            href: targetNode.id,
+            data: targetNode.data,
+            bounds: targetNode.data.shape["dc:Bounds"]!,
+            index: targetNode.data.index,
+            shapeId: targetNode.data.shape["@_id"],
+          },
+          keepWaypoints: false,
+        });
+      }
+    });
+  }, [dmnEditorStoreApi, externalModelsByNamespace]);
+
+  return (
+    <button className={"kie-dmn-editor--autolayout-panel-toggle-button"} onClick={onApply}>
+      <OptimizeIcon />
+    </button>
+  );
+}
+
+//
+
+export async function runElk(
+  nodes: Elk.ElkNode[],
+  edges: { id: string; sources: string[]; targets: string[] }[],
+  options: Elk.LayoutOptions = {}
+): Promise<{ isHorizontal: boolean; nodes: Elk.ElkNode[] | undefined; edges: Elk.ElkExtendedEdge[] | undefined }> {
+  const isHorizontal = options?.["elk.direction"] === "RIGHT";
+
+  const graph: Elk.ElkNode = {
+    id: "root",
+    layoutOptions: options,
+    children: nodes,
+    edges,
+  };
+
+  const layoutedGraph = await elk.layout(graph);
+  return {
+    isHorizontal,
+    nodes: layoutedGraph.children,
+    edges: layoutedGraph.edges as any[],
+  };
+}
+
+function visitNodeAndNested(
+  elkNode: Elk.ElkNode,
+  positionOffset: { x: number; y: number },
+  visitor: (elkNode: Elk.ElkNode, positionOffset: { x: number; y: number }) => void
+) {
+  visitor(elkNode, positionOffset);
+  for (const nestedNode of elkNode.children ?? []) {
+    visitNodeAndNested(
+      nestedNode,
+      {
+        x: elkNode.x! + positionOffset.x,
+        y: elkNode.y! + positionOffset.y,
+      },
+      visitor
+    );
+  }
+}
diff --git a/packages/dmn-editor/src/boxedExpressions/BoxedExpression.tsx b/packages/dmn-editor/src/boxedExpressions/BoxedExpression.tsx
index 8ca343f7368..b8972cf0ff1 100644
--- a/packages/dmn-editor/src/boxedExpressions/BoxedExpression.tsx
+++ b/packages/dmn-editor/src/boxedExpressions/BoxedExpression.tsx
@@ -17,7 +17,6 @@
  * under the License.
  */
 
-import * as RF from "reactflow";
 import {
   BeeGwtService,
   DmnBuiltInDataType,
@@ -28,38 +27,15 @@ import {
   generateUuid,
 } from "@kie-tools/boxed-expression-component/dist/api";
 import { BoxedExpressionEditor } from "@kie-tools/boxed-expression-component/dist/expressions";
-import { Label } from "@patternfly/react-core/dist/js/components/Label";
-import * as React from "react";
-import { useCallback, useEffect, useMemo, useState } from "react";
-import { updateExpression } from "../mutations/updateExpression";
-import { DmnEditorTab, useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
-import { dmnToBee, getUndefinedExpressionDefinition } from "./dmnToBee";
-import { getDefaultExpressionDefinitionByLogicType } from "./getDefaultExpressionDefinitionByLogicType";
+import { FeelVariables } from "@kie-tools/dmn-feel-antlr4-parser";
+import { DmnLatestModel } from "@kie-tools/dmn-marshaller";
 import {
   DMN15__tBusinessKnowledgeModel,
   DMN15__tDecision,
   DMN15__tItemDefinition,
 } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
-import {
-  EmptyState,
-  EmptyStateBody,
-  EmptyStateIcon,
-  EmptyStatePrimary,
-} from "@patternfly/react-core/dist/js/components/EmptyState";
-import { Button } from "@patternfly/react-core/dist/js/components/Button";
-import { Title } from "@patternfly/react-core/dist/js/components/Title";
-import { ErrorCircleOIcon } from "@patternfly/react-icons/dist/js/icons/error-circle-o-icon";
-import { InfoIcon } from "@patternfly/react-icons/dist/js/icons/info-icon";
-import { builtInFeelTypes } from "../dataTypes/BuiltInFeelTypes";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
-import { isStruct } from "../dataTypes/DataTypeSpec";
-import { DmnDiagramNodeData } from "../diagram/nodes/Nodes";
-import { DataTypeIndex } from "../dataTypes/DataTypes";
-import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
-import { getNodeTypeFromDmnObject } from "../diagram/maths/DmnMaths";
-import { NodeIcon } from "../icons/Icons";
-import { Text, TextContent, TextVariants } from "@patternfly/react-core/dist/js/components/Text";
 import { PMMLDocumentData } from "@kie-tools/pmml-editor-marshaller/dist/api";
+import { PMMLFieldData } from "@kie-tools/pmml-editor-marshaller/dist/api/PMMLFieldData";
 import { PMMLModelData } from "@kie-tools/pmml-editor-marshaller/dist/api/PMMLModelData";
 import {
   AnomalyDetectionModel,
@@ -84,18 +60,71 @@ import {
   TimeSeriesModel,
   TreeModel,
 } from "@kie-tools/pmml-editor-marshaller/dist/marshaller/model/pmml4_4";
-import { PMMLFieldData } from "@kie-tools/pmml-editor-marshaller/dist/api/PMMLFieldData";
-import { getDefaultColumnWidth } from "./getDefaultColumnWidth";
-import { FeelVariables } from "@kie-tools/dmn-feel-antlr4-parser";
-import { DmnLatestModel } from "@kie-tools/dmn-marshaller";
+import { Button } from "@patternfly/react-core/dist/js/components/Button";
+import {
+  EmptyState,
+  EmptyStateBody,
+  EmptyStateIcon,
+  EmptyStatePrimary,
+} from "@patternfly/react-core/dist/js/components/EmptyState";
+import { Label } from "@patternfly/react-core/dist/js/components/Label";
+import { Text, TextContent, TextVariants } from "@patternfly/react-core/dist/js/components/Text";
+import { Title } from "@patternfly/react-core/dist/js/components/Title";
+import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
 import { ArrowRightIcon } from "@patternfly/react-icons/dist/js/icons/arrow-right-icon";
+import { ErrorCircleOIcon } from "@patternfly/react-icons/dist/js/icons/error-circle-o-icon";
+import { InfoIcon } from "@patternfly/react-icons/dist/js/icons/info-icon";
+import * as React from "react";
+import { useCallback, useMemo } from "react";
+import * as RF from "reactflow";
+import { builtInFeelTypes } from "../dataTypes/BuiltInFeelTypes";
+import { isStruct } from "../dataTypes/DataTypeSpec";
+import { DataTypeIndex } from "../dataTypes/DataTypes";
+import { getNodeTypeFromDmnObject } from "../diagram/maths/DmnMaths";
+import { DmnDiagramNodeData } from "../diagram/nodes/Nodes";
+import { NodeIcon } from "../icons/Icons";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
+import { updateExpression } from "../mutations/updateExpression";
+import { DmnEditorTab } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
+import { dmnToBee, getUndefinedExpressionDefinition } from "./dmnToBee";
+import { getDefaultColumnWidth } from "./getDefaultColumnWidth";
+import { getDefaultExpressionDefinitionByLogicType } from "./getDefaultExpressionDefinitionByLogicType";
 
 export function BoxedExpression({ container }: { container: React.RefObject<HTMLElement> }) {
-  const thisDmn = useDmnEditorStore((s) => s.dmn);
-  const diagram = useDmnEditorStore((s) => s.diagram);
-  const dispatch = useDmnEditorStore((s) => s.dispatch);
-  const boxedExpressionEditor = useDmnEditorStore((s) => s.boxedExpressionEditor);
-  const { externalDmnsByNamespace } = useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
+
+  //
+
+  const thisDmn = useDmnEditorStore((s) => {
+    return s.dmn;
+  });
+  const diagram = useDmnEditorStore((s) => {
+    return s.diagram;
+  });
+  const boxedExpressionEditor = useDmnEditorStore((s) => {
+    return s.boxedExpressionEditor;
+  });
+  const externalDmnsByNamespace = useDmnEditorStore((s) => {
+    return s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).dmns;
+  });
+  const dataTypesTree = useDmnEditorStore((s) => {
+    return s.computed(s).getDataTypes(externalModelsByNamespace).dataTypesTree;
+  });
+  const allTopLevelDataTypesByFeelName = useDmnEditorStore((s) => {
+    return s.computed(s).getDataTypes(externalModelsByNamespace).allTopLevelDataTypesByFeelName;
+  });
+  const nodesById = useDmnEditorStore((s) => {
+    return s.computed(s).getDiagramData(externalModelsByNamespace).nodesById;
+  });
+  const importsByNamespace = useDmnEditorStore((s) => {
+    return s.computed(s).importsByNamespace();
+  });
+  const externalPmmlsByNamespace = useDmnEditorStore((s) => {
+    return s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).pmmls;
+  });
+
+  //
   const dmnEditorStoreApi = useDmnEditorStoreApi();
 
   const feelVariables = useMemo(() => {
@@ -150,13 +179,6 @@ export function BoxedExpression({ container }: { container: React.RefObject<HTML
     };
   }, [boxedExpressionEditor.activeDrgElementId, thisDmn.model.definitions.drgElement, widthsById]);
 
-  const [lastValidExpression, setLastValidExpression] = useState<typeof expression>(undefined);
-  useEffect(() => {
-    if (expression) {
-      setLastValidExpression(expression);
-    }
-  }, [expression, setLastValidExpression]);
-
   const setExpression: React.Dispatch<React.SetStateAction<ExpressionDefinition>> = useCallback(
     (expressionAction) => {
       dmnEditorStoreApi.setState((state) => {
@@ -182,9 +204,6 @@ export function BoxedExpression({ container }: { container: React.RefObject<HTML
 
   ////
 
-  const { dataTypesTree, allTopLevelDataTypesByFeelName, nodesById, importsByNamespace, externalPmmlsByNamespace } =
-    useDmnEditorDerivedStore();
-
   const dataTypes = useMemo<DmnDataType[]>(() => {
     const customDataTypes = dataTypesTree.map((d) => ({
       isCustom: true,
@@ -270,7 +289,7 @@ export function BoxedExpression({ container }: { container: React.RefObject<HTML
               className={"kie-dmn-editor--boxed-expression-back"}
               onClick={() => {
                 dmnEditorStoreApi.setState((state) => {
-                  dispatch.boxedExpressionEditor.close(state);
+                  state.dispatch(state).boxedExpressionEditor.close();
                 });
               }}
             >
@@ -330,7 +349,7 @@ export function BoxedExpression({ container }: { container: React.RefObject<HTML
                   variant="link"
                   onClick={() => {
                     dmnEditorStoreApi.setState((state) => {
-                      dispatch.boxedExpressionEditor.close(state);
+                      state.dispatch(state).boxedExpressionEditor.close();
                     });
                   }}
                 >
diff --git a/packages/dmn-editor/src/dataTypes/DataTypeName.tsx b/packages/dmn-editor/src/dataTypes/DataTypeName.tsx
index 0d27eff02f6..f7e7c4219bd 100644
--- a/packages/dmn-editor/src/dataTypes/DataTypeName.tsx
+++ b/packages/dmn-editor/src/dataTypes/DataTypeName.tsx
@@ -23,12 +23,13 @@ import { DMN15__tItemDefinition } from "@kie-tools/dmn-marshaller/dist/schemas/d
 import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
 import { EditableNodeLabel, useEditableNodeLabel } from "../diagram/nodes/EditableNodeLabel";
 import { TypeRefLabel } from "./TypeRefLabel";
-import { useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { renameItemDefinition } from "../mutations/renameItemDefinition";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { UniqueNameIndex } from "../Dmn15Spec";
 import { buildFeelQNameFromNamespace } from "../feel/buildFeelQName";
 import { InlineFeelNameInput, OnInlineFeelNameRenamed } from "../feel/InlineFeelNameInput";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
+import { State } from "../store/Store";
 
 export function DataTypeName({
   isReadonly,
@@ -37,7 +38,7 @@ export function DataTypeName({
   editMode,
   relativeToNamespace,
   shouldCommitOnBlur,
-  allUniqueNames,
+  onGetAllUniqueNames,
   enableAutoFocusing,
 }: {
   isReadonly: boolean;
@@ -46,7 +47,7 @@ export function DataTypeName({
   isActive: boolean;
   relativeToNamespace: string;
   shouldCommitOnBlur?: boolean;
-  allUniqueNames: UniqueNameIndex;
+  onGetAllUniqueNames: (s: State) => UniqueNameIndex;
   enableAutoFocusing?: boolean;
 }) {
   const { isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter } = useEditableNodeLabel(
@@ -54,9 +55,11 @@ export function DataTypeName({
   );
 
   const dmnEditorStoreApi = useDmnEditorStoreApi();
-  const { allDataTypesById, importsByNamespace } = useDmnEditorDerivedStore();
-
-  const dataType = allDataTypesById.get(itemDefinition["@_id"]!);
+  const { externalModelsByNamespace } = useExternalModels();
+  const dataType = useDmnEditorStore((s) =>
+    s.computed(s).getDataTypes(externalModelsByNamespace).allDataTypesById.get(itemDefinition["@_id"]!)
+  );
+  const importsByNamespace = useDmnEditorStore((s) => s.computed(s).importsByNamespace());
 
   const feelQNameToDisplay = buildFeelQNameFromNamespace({
     namedElement: itemDefinition,
@@ -76,11 +79,11 @@ export function DataTypeName({
           definitions: state.dmn.model.definitions,
           newName,
           itemDefinitionId: itemDefinition["@_id"]!,
-          allDataTypesById,
+          allDataTypesById: state.computed(state).getDataTypes(externalModelsByNamespace).allDataTypesById,
         });
       });
     },
-    [allDataTypesById, dmnEditorStoreApi, isReadonly, itemDefinition]
+    [dmnEditorStoreApi, externalModelsByNamespace, isReadonly, itemDefinition]
   );
 
   const _shouldCommitOnBlur = shouldCommitOnBlur ?? true; // Defaults to true
@@ -95,7 +98,7 @@ export function DataTypeName({
           shouldCommitOnBlur={_shouldCommitOnBlur}
           name={feelQNameToDisplay.full}
           onRenamed={onRenamed}
-          allUniqueNames={allUniqueNames}
+          allUniqueNames={onGetAllUniqueNames}
         />
       )}
       {editMode === "double-click" && (
@@ -126,7 +129,7 @@ export function DataTypeName({
               localPart: itemDefinition["@_name"],
               prefix: feelQNameToDisplay.prefix,
             }}
-            allUniqueNames={allUniqueNames}
+            onGetAllUniqueNames={onGetAllUniqueNames}
           />
           {!isEditingLabel && (
             <TypeRefLabel
diff --git a/packages/dmn-editor/src/dataTypes/DataTypePanel.tsx b/packages/dmn-editor/src/dataTypes/DataTypePanel.tsx
index 35e5bec7bfb..99d5e5634da 100644
--- a/packages/dmn-editor/src/dataTypes/DataTypePanel.tsx
+++ b/packages/dmn-editor/src/dataTypes/DataTypePanel.tsx
@@ -27,7 +27,7 @@ import { Title } from "@patternfly/react-core/dist/js/components/Title";
 import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
 import * as React from "react";
 import { useCallback, useMemo, useState } from "react";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { TypeRefSelector } from "./TypeRefSelector";
 import {
   Dropdown,
@@ -42,7 +42,6 @@ import { getNewItemDefinition, isStruct } from "./DataTypeSpec";
 import { TrashIcon } from "@patternfly/react-icons/dist/js/icons/trash-icon";
 import { Label } from "@patternfly/react-core/dist/js/components/Label";
 import { CopyIcon } from "@patternfly/react-icons/dist/js/icons/copy-icon";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { UniqueNameIndex } from "../Dmn15Spec";
 import { buildFeelQNameFromNamespace } from "../feel/buildFeelQName";
 import { buildClipboardFromDataType } from "../clipboard/Clipboard";
@@ -51,6 +50,7 @@ import { original } from "immer";
 import { builtInFeelTypeNames } from "./BuiltInFeelTypes";
 import { useDmnEditor } from "../DmnEditorContext";
 import { useResolvedTypeRef } from "./useResolvedTypeRef";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 export function DataTypePanel({
   isReadonly,
@@ -162,9 +162,11 @@ export function DataTypePanel({
 
   const [dropdownOpenFor, setDropdownOpenFor] = useState<string | undefined>(undefined);
   const [topLevelDropdownOpen, setTopLevelDropdownOpen] = useState<boolean>(false);
-
-  const { importsByNamespace, allTopLevelItemDefinitionUniqueNames, allTopLevelDataTypesByFeelName } =
-    useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
+  const importsByNamespace = useDmnEditorStore((s) => s.computed(s).importsByNamespace());
+  const allTopLevelItemDefinitionUniqueNames = useDmnEditorStore(
+    (s) => s.computed(s).getDataTypes(externalModelsByNamespace).allTopLevelItemDefinitionUniqueNames
+  );
 
   const allUniqueNames = useMemo(
     () =>
@@ -236,7 +238,7 @@ export function DataTypePanel({
                   isActive={false}
                   editMode={"hover"}
                   isReadonly={dataType.namespace !== thisDmnsNamespace}
-                  allUniqueNames={allUniqueNames}
+                  onGetAllUniqueNames={() => allUniqueNames}
                 />
               </div>
             </FlexItem>
diff --git a/packages/dmn-editor/src/dataTypes/DataTypes.tsx b/packages/dmn-editor/src/dataTypes/DataTypes.tsx
index 6573dc0563e..575027f2b30 100644
--- a/packages/dmn-editor/src/dataTypes/DataTypes.tsx
+++ b/packages/dmn-editor/src/dataTypes/DataTypes.tsx
@@ -29,12 +29,12 @@ import {
 import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
 import { InfrastructureIcon } from "@patternfly/react-icons/dist/js/icons/infrastructure-icon";
 import { PlusCircleIcon } from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
-import { State, useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { State } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { DataTypesEmptyState } from "./DataTypesEmptyState";
 import { DataTypePanel } from "./DataTypePanel";
-import { findDataTypeById, getNewItemDefinition, isStruct } from "./DataTypeSpec";
+import { findDataTypeById, isStruct } from "./DataTypeSpec";
 import { DataTypeName } from "./DataTypeName";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { Label } from "@patternfly/react-core/dist/js/components/Label";
 import { DMN15_SPEC } from "../Dmn15Spec";
 import { invalidInlineFeelNameStyle } from "../feel/InlineFeelNameInput";
@@ -56,6 +56,7 @@ import {
 import { getNewDmnIdRandomizer } from "../idRandomizer/dmnIdRandomizer";
 import { addTopLevelItemDefinition as _addTopLevelItemDefinition } from "../mutations/addTopLevelItemDefinition";
 import { DmnBuiltInDataType } from "@kie-tools/boxed-expression-component/dist/api";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 export type DataType = {
   itemDefinition: DMN15__tItemDefinition;
@@ -89,8 +90,14 @@ export function DataTypes() {
   const { activeItemDefinitionId } = useDmnEditorStore((s) => s.dataTypesEditor);
 
   const [filter, setFilter] = useState("");
-
-  const { allDataTypesById, dataTypesTree, allTopLevelItemDefinitionUniqueNames } = useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
+  const allTopLevelItemDefinitionUniqueNames = useDmnEditorStore(
+    (s) => s.computed(s).getDataTypes(externalModelsByNamespace).allTopLevelItemDefinitionUniqueNames
+  );
+  const allDataTypesById = useDmnEditorStore(
+    (s) => s.computed(s).getDataTypes(externalModelsByNamespace).allDataTypesById
+  );
+  const dataTypesTree = useDmnEditorStore((s) => s.computed(s).getDataTypes(externalModelsByNamespace).dataTypesTree);
 
   const activeDataType = useMemo(() => {
     return activeItemDefinitionId ? allDataTypesById.get(activeItemDefinitionId) : undefined;
@@ -249,7 +256,7 @@ export function DataTypes() {
                             isActive={isActive}
                             editMode={"double-click"}
                             enableAutoFocusing={false} // Let the auto-focusing mechanism go for the title component
-                            allUniqueNames={allTopLevelItemDefinitionUniqueNames}
+                            onGetAllUniqueNames={() => allTopLevelItemDefinitionUniqueNames}
                           />
                         )) || (
                           <>
diff --git a/packages/dmn-editor/src/dataTypes/ItemComponentsTable.tsx b/packages/dmn-editor/src/dataTypes/ItemComponentsTable.tsx
index 1fd13b7d0b1..afb24f95c13 100644
--- a/packages/dmn-editor/src/dataTypes/ItemComponentsTable.tsx
+++ b/packages/dmn-editor/src/dataTypes/ItemComponentsTable.tsx
@@ -26,7 +26,7 @@ import { PasteIcon } from "@patternfly/react-icons/dist/js/icons/paste-icon";
 import { PlusCircleIcon } from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
 import * as React from "react";
 import { useCallback, useMemo } from "react";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { TypeRefSelector } from "./TypeRefSelector";
 import {
   Dropdown,
@@ -59,7 +59,6 @@ import { builtInFeelTypeNames } from "./BuiltInFeelTypes";
 import { useDmnEditor } from "../DmnEditorContext";
 import { DMN15__tItemDefinition } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { resolveTypeRef } from "./resolveTypeRef";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 export const BRIGHTNESS_DECREASE_STEP_IN_PERCENTAGE_PER_NESTING_LEVEL = 5;
@@ -91,9 +90,12 @@ export function ItemComponentsTable({
 }) {
   const dmnEditorStoreApi = useDmnEditorStoreApi();
 
-  const { expandedItemComponentIds } = useDmnEditorStore((s) => s.dataTypesEditor);
-  const { allTopLevelDataTypesByFeelName, importsByNamespace } = useDmnEditorDerivedStore();
   const { externalModelsByNamespace } = useExternalModels();
+  const expandedItemComponentIds = useDmnEditorStore((s) => s.dataTypesEditor.expandedItemComponentIds);
+  const allTopLevelDataTypesByFeelName = useDmnEditorStore(
+    (s) => s.computed(s).getDataTypes(externalModelsByNamespace).allTopLevelDataTypesByFeelName
+  );
+  const importsByNamespace = useDmnEditorStore((s) => s.computed(s).importsByNamespace());
 
   const thisDmnsNamespace = useDmnEditorStore((s) => s.dmn.model.definitions["@_namespace"]);
 
@@ -361,7 +363,7 @@ export function ItemComponentsTable({
                               isActive={false}
                               itemDefinition={dt.itemDefinition}
                               isReadonly={dt.namespace !== thisDmnsNamespace}
-                              allUniqueNames={allUniqueNamesAtLevel}
+                              onGetAllUniqueNames={() => allUniqueNamesAtLevel}
                             />
                           </div>
                         </div>
diff --git a/packages/dmn-editor/src/dataTypes/TypeRefLabel.tsx b/packages/dmn-editor/src/dataTypes/TypeRefLabel.tsx
index 5ce941ff73c..31f048e5d38 100644
--- a/packages/dmn-editor/src/dataTypes/TypeRefLabel.tsx
+++ b/packages/dmn-editor/src/dataTypes/TypeRefLabel.tsx
@@ -21,9 +21,8 @@ import * as React from "react";
 import { DmnBuiltInDataType } from "@kie-tools/boxed-expression-component/dist/api";
 import { buildFeelQNameFromXmlQName } from "../feel/buildFeelQName";
 import { useMemo } from "react";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { buildXmlQName, parseXmlQName } from "@kie-tools/xml-parser-ts/dist/qNames";
-import { useDmnEditorStore } from "../store/Store";
+import { useDmnEditorStore } from "../store/StoreContext";
 import { getXmlNamespaceDeclarationName } from "../xml/xmlNamespaceDeclarations";
 import { parseFeelQName } from "../feel/parseFeelQName";
 import { builtInFeelTypeNames } from "./BuiltInFeelTypes";
@@ -37,7 +36,7 @@ export function TypeRefLabel({
   typeRef: string | undefined;
   relativeToNamespace?: string;
 }) {
-  const { importsByNamespace } = useDmnEditorDerivedStore();
+  const importsByNamespace = useDmnEditorStore((s) => s.computed(s).importsByNamespace());
   const thisDmn = useDmnEditorStore((s) => s.dmn);
 
   const feelName = useMemo(() => {
diff --git a/packages/dmn-editor/src/dataTypes/TypeRefSelector.tsx b/packages/dmn-editor/src/dataTypes/TypeRefSelector.tsx
index 13a67bedd69..c6021dc5155 100644
--- a/packages/dmn-editor/src/dataTypes/TypeRefSelector.tsx
+++ b/packages/dmn-editor/src/dataTypes/TypeRefSelector.tsx
@@ -23,14 +23,15 @@ import * as React from "react";
 import { useMemo, useRef, useState } from "react";
 import { TypeRefLabel } from "./TypeRefLabel";
 import { ArrowUpIcon } from "@patternfly/react-icons/dist/js/icons/arrow-up-icon";
-import { DmnEditorTab, useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { DmnEditorTab } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button";
 import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { DataType } from "./DataTypes";
 import { builtInFeelTypeNames, builtInFeelTypes } from "./BuiltInFeelTypes";
 import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
 import { useInViewSelect } from "../responsiveness/useInViewSelect";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 export type OnTypeRefChange = (newDataType: DmnBuiltInDataType) => void;
 export type OnCreateDataType = (newDataTypeName: string) => void;
@@ -47,34 +48,35 @@ export function TypeRefSelector(props: {
   menuAppendTo?: "parent";
 }) {
   const [isOpen, setOpen] = useState(false);
-
-  const { allTopLevelDataTypesByFeelName } = useDmnEditorDerivedStore();
-
-  const selectedDataType = useMemo(() => {
-    return props.typeRef ? allTopLevelDataTypesByFeelName.get(props.typeRef) : undefined;
-  }, [allTopLevelDataTypesByFeelName, props.typeRef]);
+  const { externalModelsByNamespace } = useExternalModels();
+  const selectedDataType = useDmnEditorStore((s) =>
+    props.typeRef
+      ? s.computed(s).getDataTypes(externalModelsByNamespace).allTopLevelDataTypesByFeelName.get(props.typeRef)
+      : undefined
+  );
 
   const dmnEditorStoreApi = useDmnEditorStoreApi();
-  const thisDmnsNamespace = useDmnEditorStore((s) => s.dmn.model.definitions["@_namespace"]);
 
-  const { customDataTypes, externalDataTypes } = useMemo(() => {
+  const { customDataTypes, externalDataTypes } = useDmnEditorStore((state) => {
     const customDataTypes: DataType[] = [];
     const externalDataTypes: DataType[] = [];
 
-    [...allTopLevelDataTypesByFeelName.values()].forEach((s) => {
-      if (s.parentId) {
-        return; // Not top-level.
-      }
-
-      if (s.namespace === thisDmnsNamespace) {
-        customDataTypes.push(s);
-      } else {
-        externalDataTypes.push(s);
+    [...state.computed(state).getDataTypes(externalModelsByNamespace).allTopLevelDataTypesByFeelName.values()].forEach(
+      (s) => {
+        if (s.parentId) {
+          return; // Not top-level.
+        }
+
+        if (s.namespace === state.dmn.model.definitions["@_namespace"]) {
+          customDataTypes.push(s);
+        } else {
+          externalDataTypes.push(s);
+        }
       }
-    });
+    );
 
     return { customDataTypes, externalDataTypes };
-  }, [allTopLevelDataTypesByFeelName, thisDmnsNamespace]);
+  });
 
   const exists = selectedDataType || (props.typeRef && builtInFeelTypeNames.has(props.typeRef));
 
diff --git a/packages/dmn-editor/src/dataTypes/useResolvedTypeRef.ts b/packages/dmn-editor/src/dataTypes/useResolvedTypeRef.ts
index ddbeda853e5..58e4b2508ae 100644
--- a/packages/dmn-editor/src/dataTypes/useResolvedTypeRef.ts
+++ b/packages/dmn-editor/src/dataTypes/useResolvedTypeRef.ts
@@ -19,22 +19,22 @@
 
 import { DmnBuiltInDataType } from "@kie-tools/boxed-expression-component/dist/api";
 import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
-import { useDmnEditorStore } from "../store/Store";
+import { useDmnEditorStore } from "../store/StoreContext";
 import { resolveTypeRef } from "./resolveTypeRef";
 
 export function useResolvedTypeRef(typeRef: string | undefined, relativeToNamespace: string | undefined) {
-  const { allTopLevelDataTypesByFeelName, importsByNamespace } = useDmnEditorDerivedStore();
   const { externalModelsByNamespace } = useExternalModels();
 
-  const thisDmnsNamespace = useDmnEditorStore((s) => s.dmn.model.definitions["@_namespace"]);
-
-  return resolveTypeRef({
-    typeRef: typeRef || DmnBuiltInDataType.Undefined,
-    namespace: relativeToNamespace || thisDmnsNamespace,
-    allTopLevelDataTypesByFeelName,
-    externalModelsByNamespace,
-    thisDmnsImportsByNamespace: importsByNamespace,
-    relativeToNamespace: thisDmnsNamespace,
+  return useDmnEditorStore((s) => {
+    const thisDmnsNamespace = s.dmn.model.definitions["@_namespace"];
+    return resolveTypeRef({
+      typeRef: typeRef || DmnBuiltInDataType.Undefined,
+      namespace: relativeToNamespace || thisDmnsNamespace,
+      allTopLevelDataTypesByFeelName: s.computed(s).getDataTypes(externalModelsByNamespace)
+        .allTopLevelDataTypesByFeelName,
+      externalModelsByNamespace,
+      thisDmnsImportsByNamespace: s.computed(s).importsByNamespace(),
+      relativeToNamespace: thisDmnsNamespace,
+    });
   });
 }
diff --git a/packages/dmn-editor/src/diagram/Diagram.tsx b/packages/dmn-editor/src/diagram/Diagram.tsx
index 13757d1cf4f..d20a79b3234 100644
--- a/packages/dmn-editor/src/diagram/Diagram.tsx
+++ b/packages/dmn-editor/src/diagram/Diagram.tsx
@@ -18,10 +18,9 @@
  */
 
 import * as RF from "reactflow";
-
 import * as React from "react";
 import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
-
+import { DmnBuiltInDataType, ExpressionDefinitionLogicType } from "@kie-tools/boxed-expression-component/dist/api";
 import {
   DC__Bounds,
   DC__Dimension,
@@ -40,11 +39,16 @@ import { Label } from "@patternfly/react-core/dist/js/components/Label";
 import { Popover } from "@patternfly/react-core/dist/js/components/Popover";
 import { Title } from "@patternfly/react-core/dist/js/components/Title";
 import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye";
-import { TableIcon } from "@patternfly/react-icons/dist/js/icons/table-icon";
+import { BlueprintIcon } from "@patternfly/react-icons/dist/js/icons/blueprint-icon";
 import { InfoIcon } from "@patternfly/react-icons/dist/js/icons/info-icon";
+import { MousePointerIcon } from "@patternfly/react-icons/dist/js/icons/mouse-pointer-icon";
+import { TableIcon } from "@patternfly/react-icons/dist/js/icons/table-icon";
 import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
 import { VirtualMachineIcon } from "@patternfly/react-icons/dist/js/icons/virtual-machine-icon";
 import { useDmnEditor } from "../DmnEditorContext";
+import { AutolayoutButton } from "../autolayout/AutolayoutButton";
+import { getDefaultColumnWidth } from "../boxedExpressions/getDefaultColumnWidth";
+import { getDefaultExpressionDefinitionByLogicType } from "../boxedExpressions/getDefaultExpressionDefinitionByLogicType";
 import {
   DMN_EDITOR_DIAGRAM_CLIPBOARD_MIME_TYPE,
   DmnEditorDiagramClipboard,
@@ -64,17 +68,20 @@ import { addOrGetDrd } from "../mutations/addOrGetDrd";
 import { addShape } from "../mutations/addShape";
 import { addStandaloneNode } from "../mutations/addStandaloneNode";
 import { deleteDecisionFromDecisionService } from "../mutations/deleteDecisionFromDecisionService";
-import { deleteEdge } from "../mutations/deleteEdge";
-import { deleteNode } from "../mutations/deleteNode";
+import { EdgeDeletionMode, deleteEdge } from "../mutations/deleteEdge";
+import { NodeDeletionMode, canRemoveNodeFromDrdOnly, deleteNode } from "../mutations/deleteNode";
 import { repopulateInputDataAndDecisionsOnAllDecisionServices } from "../mutations/repopulateInputDataAndDecisionsOnDecisionService";
 import { repositionNode } from "../mutations/repositionNode";
 import { resizeNode } from "../mutations/resizeNode";
+import { updateExpression } from "../mutations/updateExpression";
 import { OverlaysPanel } from "../overlaysPanel/OverlaysPanel";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
-import { DiagramNodesPanel, SnapGrid, StoreApiType, useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { DiagramNodesPanel, SnapGrid } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
+import { Unpacked } from "../tsExt/tsExt";
 import { buildXmlHref, parseXmlHref } from "../xml/xmlHrefs";
 import { getXmlNamespaceDeclarationName } from "../xml/xmlNamespaceDeclarations";
 import { DiagramContainerContextProvider } from "./DiagramContainerContext";
+import { MIME_TYPE_FOR_DMN_EDITOR_DRG_NODE } from "./DrgNodesPanel";
 import { MIME_TYPE_FOR_DMN_EDITOR_NEW_NODE_FROM_PALETTE, Palette } from "./Palette";
 import { offsetShapePosition, snapShapeDimensions, snapShapePosition } from "./SnapGrid";
 import { ConnectionLine } from "./connections/ConnectionLine";
@@ -90,10 +97,11 @@ import {
   InformationRequirementEdge,
   KnowledgeRequirementEdge,
 } from "./edges/Edges";
+import { buildHierarchy } from "./graph/graph";
 import {
   CONTAINER_NODES_DESIRABLE_PADDING,
   getBounds,
-  getBoundsCenterPoint,
+  getDmnBoundsCenterPoint,
   getContainmentRelationship,
   getHandlePosition,
   getNodeTypeFromDmnObject,
@@ -111,15 +119,7 @@ import {
   TextAnnotationNode,
   UnknownNode,
 } from "./nodes/Nodes";
-import { BlueprintIcon } from "@patternfly/react-icons/dist/js/icons/blueprint-icon";
-import { MousePointerIcon } from "@patternfly/react-icons/dist/js/icons/mouse-pointer-icon";
-import { updateExpression } from "../mutations/updateExpression";
-import { getDefaultExpressionDefinitionByLogicType } from "../boxedExpressions/getDefaultExpressionDefinitionByLogicType";
-import { DmnBuiltInDataType, ExpressionDefinitionLogicType } from "@kie-tools/boxed-expression-component/dist/api";
-import { getDefaultColumnWidth } from "../boxedExpressions/getDefaultColumnWidth";
-import { buildHierarchy } from "./graph/graph";
-import { MIME_TYPE_FOR_DMN_EDITOR_DRG_NODE } from "./DrgNodesPanel";
-import { Unpacked } from "../tsExt/tsExt";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 const isFirefox = typeof (window as any).InstallTrigger !== "undefined"; // See https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browsers
 
@@ -129,6 +129,8 @@ const FIT_VIEW_OPTIONS: RF.FitViewOptions = { maxZoom: 1, minZoom: 0.1, duration
 
 const DEFAULT_VIEWPORT = { x: 100, y: 0, zoom: 1 };
 
+const DELETE_NODE_KEY_CODES = ["Backspace", "Delete"];
+
 const nodeTypes: Record<NodeType, any> = {
   [NODE_TYPES.decisionService]: DecisionServiceNode,
   [NODE_TYPES.group]: GroupNode,
@@ -156,26 +158,12 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
     // Contexts
 
     const dmnEditorStoreApi = useDmnEditorStoreApi();
-    const diagram = useDmnEditorStore((s) => s.diagram);
+    const { externalModelsByNamespace } = useExternalModels();
+    const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
     const thisDmn = useDmnEditorStore((s) => s.dmn);
 
     const { dmnModelBeforeEditingRef } = useDmnEditor();
 
-    const {
-      dmnShapesByHref,
-      nodesById,
-      selectedNodesById,
-      selectedEdgesById,
-      edgesById,
-      nodes,
-      edges,
-      isDropTargetNodeValidForSelection,
-      isDiagramEditingInProgress,
-      selectedNodeTypes,
-      externalDmnsByNamespace,
-      drgElementsWithoutVisualRepresentationOnCurrentDrd,
-    } = useDmnEditorDerivedStore();
-
     // State
 
     const [reactFlowInstance, setReactFlowInstance] = useState<
@@ -199,38 +187,38 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
     // Memos
 
     const rfSnapGrid = useMemo<[number, number]>(
-      () => (diagram.snapGrid.isEnabled ? [diagram.snapGrid.x, diagram.snapGrid.y] : [1, 1]),
-      [diagram.snapGrid.isEnabled, diagram.snapGrid.x, diagram.snapGrid.y]
+      () => (snapGrid.isEnabled ? [snapGrid.x, snapGrid.y] : [1, 1]),
+      [snapGrid.isEnabled, snapGrid.x, snapGrid.y]
     );
 
     // Callbacks
 
     const onConnect = useCallback<RF.OnConnect>(
-      (connection) => {
-        console.debug("DMN DIAGRAM: `onConnect`: ", connection);
-
-        const sourceNode = nodesById.get(connection.source!);
-        const targetNode = nodesById.get(connection.target!);
-        if (!sourceNode || !targetNode) {
-          throw new Error("Cannot create connection without target and source nodes!");
-        }
+      ({ source, target, sourceHandle, targetHandle }) => {
+        console.debug("DMN DIAGRAM: `onConnect`: ", { source, target, sourceHandle, targetHandle });
+        dmnEditorStoreApi.setState((state) => {
+          const sourceNode = state.computed(state).getDiagramData(externalModelsByNamespace).nodesById.get(source!);
+          const targetNode = state.computed(state).getDiagramData(externalModelsByNamespace).nodesById.get(target!);
+          if (!sourceNode || !targetNode) {
+            throw new Error("Cannot create connection without target and source nodes!");
+          }
 
-        const sourceBounds = sourceNode.data.shape["dc:Bounds"];
-        const targetBounds = targetNode.data.shape["dc:Bounds"];
-        if (!sourceBounds || !targetBounds) {
-          throw new Error("Cannot create connection without target bounds!");
-        }
+          const sourceBounds = sourceNode.data.shape["dc:Bounds"];
+          const targetBounds = targetNode.data.shape["dc:Bounds"];
+          if (!sourceBounds || !targetBounds) {
+            throw new Error("Cannot create connection without target bounds!");
+          }
 
-        // --------- This is where we draw the line between the diagram and the model.
+          // --------- This is where we draw the line between the diagram and the model.
 
-        dmnEditorStoreApi.setState((state) => {
           addEdge({
             definitions: state.dmn.model.definitions,
             drdIndex: state.diagram.drdIndex,
             edge: {
-              type: connection.sourceHandle as EdgeType,
-              targetHandle: connection.targetHandle as PositionalNodeHandleId,
+              type: sourceHandle as EdgeType,
+              targetHandle: targetHandle as PositionalNodeHandleId,
               sourceHandle: PositionalNodeHandleId.Center,
+              autoPositionedEdgeMarker: undefined,
             },
             sourceNode: {
               type: sourceNode.type as NodeType,
@@ -251,7 +239,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           });
         });
       },
-      [dmnEditorStoreApi, nodesById]
+      [dmnEditorStoreApi, externalModelsByNamespace]
     );
 
     const getFirstNodeFittingBounds = useCallback(
@@ -340,17 +328,19 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           ) as ExternalNode;
 
           // --------- This is where we draw the line between the diagram and the model.
+          dmnEditorStoreApi.setState((state) => {
+            const externalDrgElement = (
+              state
+                .computed(state)
+                .getExternalModelTypesByNamespace(externalModelsByNamespace)
+                .dmns.get(externalNode.externalDrgElementNamespace)?.model.definitions.drgElement ?? []
+            ).find((s) => s["@_id"] === externalNode.externalDrgElementId);
+            if (!externalDrgElement) {
+              throw new Error(`Can't find DRG element with id '${externalNode.externalDrgElementId}'.`);
+            }
 
-          const externalDrgElement = (
-            externalDmnsByNamespace.get(externalNode.externalDrgElementNamespace)?.model.definitions.drgElement ?? []
-          ).find((s) => s["@_id"] === externalNode.externalDrgElementId);
-          if (!externalDrgElement) {
-            throw new Error(`Can't find DRG element with id '${externalNode.externalDrgElementId}'.`);
-          }
-
-          const externalNodeType = getNodeTypeFromDmnObject(externalDrgElement)!;
+            const externalNodeType = getNodeTypeFromDmnObject(externalDrgElement)!;
 
-          dmnEditorStoreApi.setState((state) => {
             const defaultExternalNodeDimensions = DEFAULT_NODE_SIZES[externalNodeType](state.diagram.snapGrid);
 
             const namespaceName = getXmlNamespaceDeclarationName({
@@ -419,19 +409,20 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           console.debug(`DMN DIAGRAM: Adding DRG node`, JSON.stringify(drgElement));
         }
       },
-      [container, reactFlowInstance, dmnEditorStoreApi, externalDmnsByNamespace]
+      [container, reactFlowInstance, dmnEditorStoreApi, externalModelsByNamespace]
     );
 
+    const ongoingConnection = useDmnEditorStore((s) => s.diagram.ongoingConnection);
     useEffect(() => {
       const edgeUpdaterSource = document.querySelectorAll(
         ".react-flow__edgeupdater-source, .react-flow__edgeupdater-target"
       );
-      if (diagram.ongoingConnection) {
+      if (ongoingConnection) {
         edgeUpdaterSource.forEach((e) => e.classList.add("hidden"));
       } else {
         edgeUpdaterSource.forEach((e) => e.classList.remove("hidden"));
       }
-    }, [diagram.ongoingConnection]);
+    }, [ongoingConnection]);
 
     const onConnectStart = useCallback<RF.OnConnectStart>(
       (e, newConnection) => {
@@ -446,50 +437,50 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
     const onConnectEnd = useCallback(
       (e: MouseEvent) => {
         console.debug("DMN DIAGRAM: `onConnectEnd`");
-        dmnEditorStoreApi.setState((state) => {
-          state.diagram.ongoingConnection = undefined;
-        });
 
-        const targetIsPane = (e.target as Element | null)?.classList?.contains("react-flow__pane");
-        if (!targetIsPane || !container.current || !diagram.ongoingConnection || !reactFlowInstance) {
-          return;
-        }
+        dmnEditorStoreApi.setState((state) => {
+          const targetIsPane = (e.target as Element | null)?.classList?.contains("react-flow__pane");
+          if (!targetIsPane || !container.current || !state.diagram.ongoingConnection || !reactFlowInstance) {
+            return;
+          }
 
-        const dropPoint = reactFlowInstance.screenToFlowPosition({
-          x: e.clientX,
-          y: e.clientY,
-        });
+          const dropPoint = reactFlowInstance.screenToFlowPosition({
+            x: e.clientX,
+            y: e.clientY,
+          });
 
-        // only try to create node if source handle is compatible
-        if (!Object.values(NODE_TYPES).find((n) => n === diagram.ongoingConnection!.handleId)) {
-          return;
-        }
+          // only try to create node if source handle is compatible
+          if (!Object.values(NODE_TYPES).find((n) => n === state.diagram.ongoingConnection!.handleId)) {
+            return;
+          }
 
-        if (!diagram.ongoingConnection.nodeId) {
-          return;
-        }
+          if (!state.diagram.ongoingConnection.nodeId) {
+            return;
+          }
 
-        const sourceNode = nodesById.get(diagram.ongoingConnection.nodeId);
-        if (!sourceNode) {
-          return;
-        }
+          const sourceNode = state
+            .computed(state)
+            .getDiagramData(externalModelsByNamespace)
+            .nodesById.get(state.diagram.ongoingConnection.nodeId);
+          if (!sourceNode) {
+            return;
+          }
 
-        const sourceNodeBounds = dmnShapesByHref.get(sourceNode.id)?.["dc:Bounds"];
-        if (!sourceNodeBounds) {
-          return;
-        }
+          const sourceNodeBounds = state.computed(state).indexes().dmnShapesByHref.get(sourceNode.id)?.["dc:Bounds"];
+          if (!sourceNodeBounds) {
+            return;
+          }
 
-        const newNodeType = diagram.ongoingConnection.handleId as NodeType;
-        const sourceNodeType = sourceNode.type as NodeType;
+          const newNodeType = state.diagram.ongoingConnection.handleId as NodeType;
+          const sourceNodeType = sourceNode.type as NodeType;
 
-        const edge = getDefaultEdgeTypeBetween(sourceNodeType as NodeType, newNodeType);
-        if (!edge) {
-          throw new Error(`DMN DIAGRAM: Invalid structure: ${sourceNodeType} --(any)--> ${newNodeType}`);
-        }
+          const edge = getDefaultEdgeTypeBetween(sourceNodeType as NodeType, newNodeType);
+          if (!edge) {
+            throw new Error(`DMN DIAGRAM: Invalid structure: ${sourceNodeType} --(any)--> ${newNodeType}`);
+          }
 
-        // --------- This is where we draw the line between the diagram and the model.
+          // --------- This is where we draw the line between the diagram and the model.
 
-        dmnEditorStoreApi.setState((state) => {
           const { id, href: newDmnObejctHref } = addConnectedNode({
             definitions: state.dmn.model.definitions,
             drdIndex: state.diagram.drdIndex,
@@ -514,8 +505,13 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           state.diagram._selectedNodes = [newDmnObejctHref];
           state.focus.consumableId = id;
         });
+
+        // Indepdent of what happens in the state mutation above, we always need to reset the `ongoingConnection` at the end here.
+        dmnEditorStoreApi.setState((state) => {
+          state.diagram.ongoingConnection = undefined;
+        });
       },
-      [dmnEditorStoreApi, container, diagram.ongoingConnection, reactFlowInstance, nodesById, dmnShapesByHref]
+      [dmnEditorStoreApi, container, reactFlowInstance, externalModelsByNamespace]
     );
 
     const isValidConnection = useCallback<RF.IsValidConnection>(
@@ -526,14 +522,18 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
 
         const ongoingConnectionHierarchy = buildHierarchy({
           nodeId: state.diagram.ongoingConnection?.nodeId,
-          edges: reactFlowInstance?.getEdges() ?? [],
+          edges: state.computed(state).getDiagramData(externalModelsByNamespace).drgEdges,
         });
 
         return (
           // Reflexive edges are not allowed for DMN
           edgeOrConnection.source !== edgeOrConnection.target &&
           // Matches DMNs structure.
-          checkIsValidConnection(nodesById, edgeOrConnection, edgeType) &&
+          checkIsValidConnection(
+            state.computed(state).getDiagramData(externalModelsByNamespace).nodesById,
+            edgeOrConnection,
+            edgeType
+          ) &&
           // Does not form cycles.
           !!edgeOrConnection.target &&
           !ongoingConnectionHierarchy.dependencies.has(edgeOrConnection.target) &&
@@ -541,7 +541,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           !ongoingConnectionHierarchy.dependents.has(edgeOrConnection.source)
         );
       },
-      [dmnEditorStoreApi, reactFlowInstance, nodesById]
+      [dmnEditorStoreApi, externalModelsByNamespace, reactFlowInstance]
     );
 
     const onNodesChange = useCallback<RF.OnNodesChange>(
@@ -557,13 +557,16 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
             switch (change.type) {
               case "add":
                 console.debug(`DMN DIAGRAM: 'onNodesChange' --> add '${change.item.id}'`);
-                state.dispatch.diagram.setNodeStatus(state, change.item.id, { selected: true });
+                state.dispatch(state).diagram.setNodeStatus(change.item.id, { selected: true });
                 break;
               case "dimensions":
                 console.debug(`DMN DIAGRAM: 'onNodesChange' --> dimensions '${change.id}'`);
-                state.dispatch.diagram.setNodeStatus(state, change.id, { resizing: change.resizing });
+                state.dispatch(state).diagram.setNodeStatus(change.id, { resizing: change.resizing });
                 if (change.dimensions) {
-                  const node = nodesById.get(change.id)!;
+                  const node = state
+                    .computed(state)
+                    .getDiagramData(externalModelsByNamespace)
+                    .nodesById.get(change.id)!;
                   // We only need to resize the node if its snapped dimensions change, as snapping is non-destructive.
                   const snappedShape = snapShapeDimensions(
                     state.diagram.snapGrid,
@@ -577,19 +580,25 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                     resizeNode({
                       definitions: state.dmn.model.definitions,
                       drdIndex: state.diagram.drdIndex,
-                      dmnShapesByHref,
+                      dmnShapesByHref: state.computed(state).indexes().dmnShapesByHref,
                       snapGrid: state.diagram.snapGrid,
                       change: {
                         isExternal: !!node.data.dmnObjectQName.prefix,
                         nodeType: node.type as NodeType,
                         index: node.data.index,
                         shapeIndex: node.data.shape.index,
-                        sourceEdgeIndexes: edges.flatMap((e) =>
-                          e.source === change.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
-                        ),
-                        targetEdgeIndexes: edges.flatMap((e) =>
-                          e.target === change.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
-                        ),
+                        sourceEdgeIndexes: state
+                          .computed(state)
+                          .getDiagramData(externalModelsByNamespace)
+                          .edges.flatMap((e) =>
+                            e.source === change.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
+                          ),
+                        targetEdgeIndexes: state
+                          .computed(state)
+                          .getDiagramData(externalModelsByNamespace)
+                          .edges.flatMap((e) =>
+                            e.target === change.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
+                          ),
                         dimension: {
                           "@_width": change.dimensions?.width ?? 0,
                           "@_height": change.dimensions?.height ?? 0,
@@ -601,9 +610,12 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                 break;
               case "position":
                 console.debug(`DMN DIAGRAM: 'onNodesChange' --> position '${change.id}'`);
-                state.dispatch.diagram.setNodeStatus(state, change.id, { dragging: change.dragging });
+                state.dispatch(state).diagram.setNodeStatus(change.id, { dragging: change.dragging });
                 if (change.positionAbsolute) {
-                  const node = nodesById.get(change.id)!;
+                  const node = state
+                    .computed(state)
+                    .getDiagramData(externalModelsByNamespace)
+                    .nodesById.get(change.id)!;
                   const { delta } = repositionNode({
                     definitions: state.dmn.model.definitions,
                     drdIndex: state.diagram.drdIndex,
@@ -611,14 +623,22 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                     change: {
                       type: "absolute",
                       nodeType: node.type as NodeType,
-                      selectedEdges: [...selectedEdgesById.keys()],
+                      selectedEdges: [
+                        ...state.computed(state).getDiagramData(externalModelsByNamespace).selectedEdgesById.keys(),
+                      ],
                       shapeIndex: node.data.shape.index,
-                      sourceEdgeIndexes: edges.flatMap((e) =>
-                        e.source === change.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
-                      ),
-                      targetEdgeIndexes: edges.flatMap((e) =>
-                        e.target === change.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
-                      ),
+                      sourceEdgeIndexes: state
+                        .computed(state)
+                        .getDiagramData(externalModelsByNamespace)
+                        .edges.flatMap((e) =>
+                          e.source === change.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
+                        ),
+                      targetEdgeIndexes: state
+                        .computed(state)
+                        .getDiagramData(externalModelsByNamespace)
+                        .edges.flatMap((e) =>
+                          e.target === change.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
+                        ),
                       position: change.positionAbsolute,
                     },
                   });
@@ -635,7 +655,10 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                     ];
 
                     for (let i = 0; i < nested.length; i++) {
-                      const nestedNode = nodesById.get(nested[i]["@_href"])!;
+                      const nestedNode = state
+                        .computed(state)
+                        .getDiagramData(externalModelsByNamespace)
+                        .nodesById.get(nested[i]["@_href"])!;
                       const snappedNestedNodeShapeWithAppliedDelta = snapShapePosition(
                         state.diagram.snapGrid,
                         offsetShapePosition(nestedNode.data.shape, delta)
@@ -647,14 +670,23 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                         change: {
                           type: "absolute",
                           nodeType: nestedNode.type as NodeType,
-                          selectedEdges: edges.map((e) => e.id),
+                          selectedEdges: state
+                            .computed(state)
+                            .getDiagramData(externalModelsByNamespace)
+                            .edges.map((e) => e.id),
                           shapeIndex: nestedNode.data.shape.index,
-                          sourceEdgeIndexes: edges.flatMap((e) =>
-                            e.source === nestedNode.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
-                          ),
-                          targetEdgeIndexes: edges.flatMap((e) =>
-                            e.target === nestedNode.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
-                          ),
+                          sourceEdgeIndexes: state
+                            .computed(state)
+                            .getDiagramData(externalModelsByNamespace)
+                            .edges.flatMap((e) =>
+                              e.source === nestedNode.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
+                            ),
+                          targetEdgeIndexes: state
+                            .computed(state)
+                            .getDiagramData(externalModelsByNamespace)
+                            .edges.flatMap((e) =>
+                              e.target === nestedNode.id && e.data?.dmnEdge ? [e.data.dmnEdge.index] : []
+                            ),
                           position: snappedNestedNodeShapeWithAppliedDelta,
                         },
                       });
@@ -664,35 +696,38 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                 break;
               case "remove":
                 console.debug(`DMN DIAGRAM: 'onNodesChange' --> remove '${change.id}'`);
-                const node = nodesById.get(change.id)!;
+                const node = state.computed(state).getDiagramData(externalModelsByNamespace).nodesById.get(change.id)!;
                 deleteNode({
+                  drgEdges: state.computed(state).getDiagramData(externalModelsByNamespace).drgEdges,
                   definitions: state.dmn.model.definitions,
                   drdIndex: state.diagram.drdIndex,
+                  dmnObjectNamespace: node.data.dmnObjectNamespace,
                   dmnObjectQName: node.data.dmnObjectQName,
                   dmnObjectId: node.data.dmnObject?.["@_id"],
                   nodeNature: nodeNatures[node.type as NodeType],
+                  mode: NodeDeletionMode.FORM_DRG_AND_ALL_DRDS,
                 });
-                state.dispatch.diagram.setNodeStatus(state, node.id, {
+                state.dispatch(state).diagram.setNodeStatus(node.id, {
                   selected: false,
                   dragging: false,
                   resizing: false,
                 });
                 break;
               case "reset":
-                state.dispatch.diagram.setNodeStatus(state, change.item.id, {
+                state.dispatch(state).diagram.setNodeStatus(change.item.id, {
                   selected: false,
                   dragging: false,
                   resizing: false,
                 });
                 break;
               case "select":
-                state.dispatch.diagram.setNodeStatus(state, change.id, { selected: change.selected });
+                state.dispatch(state).diagram.setNodeStatus(change.id, { selected: change.selected });
                 break;
             }
           }
         });
       },
-      [reactFlowInstance, dmnEditorStoreApi, nodesById, dmnShapesByHref, edges, selectedEdgesById]
+      [reactFlowInstance, dmnEditorStoreApi, externalModelsByNamespace]
     );
 
     const resetToBeforeEditingBegan = useCallback(() => {
@@ -737,29 +772,38 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
 
     const onNodeDragStop = useCallback<RF.NodeDragHandler>(
       (e, node: RF.Node<DmnDiagramNodeData>) => {
-        console.debug("DMN DIAGRAM: `onNodeDragStop`");
-        const nodeBeingDragged = nodesById.get(nodeIdBeingDraggedRef.current!);
-        nodeIdBeingDraggedRef.current = null;
-        if (!nodeBeingDragged) {
-          return;
-        }
+        try {
+          dmnEditorStoreApi.setState((state) => {
+            console.debug("DMN DIAGRAM: `onNodeDragStop`");
+            const nodeBeingDragged = state
+              .computed(state)
+              .getDiagramData(externalModelsByNamespace)
+              .nodesById.get(nodeIdBeingDraggedRef.current!);
+            nodeIdBeingDraggedRef.current = null;
+            if (!nodeBeingDragged) {
+              return;
+            }
 
-        // Validate
-        const dropTargetNode = dmnEditorStoreApi.getState().diagram.dropTargetNode;
-        if (dropTargetNode && containment.has(dropTargetNode.type as NodeType) && !isDropTargetNodeValidForSelection) {
-          console.debug(
-            `DMN DIAGRAM: Invalid containment: '${[...selectedNodeTypes].join("', '")}' inside '${
-              dropTargetNode.type
-            }'. Ignoring nodes dropped.`
-          );
-          resetToBeforeEditingBegan();
-          return;
-        }
+            // Validate
+            const dropTargetNode = dmnEditorStoreApi.getState().diagram.dropTargetNode;
+            if (
+              dropTargetNode &&
+              containment.has(dropTargetNode.type as NodeType) &&
+              !state.computed(state).isDropTargetNodeValidForSelection
+            ) {
+              console.debug(
+                `DMN DIAGRAM: Invalid containment: '${[
+                  ...state.computed(state).getDiagramData(externalModelsByNamespace).selectedNodeTypes,
+                ].join("', '")}' inside '${dropTargetNode.type}'. Ignoring nodes dropped.`
+              );
+              resetToBeforeEditingBegan();
+              return;
+            }
 
-        const selectedNodes = [...selectedNodesById.values()];
+            const selectedNodes = [
+              ...state.computed(state).getDiagramData(externalModelsByNamespace).selectedNodesById.values(),
+            ];
 
-        try {
-          dmnEditorStoreApi.setState((state) => {
             state.diagram.dropTargetNode = undefined;
 
             if (!node.dragging) {
@@ -768,7 +812,10 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
 
             // Un-parent
             if (nodeBeingDragged.data.parentRfNode) {
-              const p = nodesById.get(nodeBeingDragged.data.parentRfNode.id);
+              const p = state
+                .computed(state)
+                .getDiagramData(externalModelsByNamespace)
+                .nodesById.get(nodeBeingDragged.data.parentRfNode.id);
               if (p?.type === NODE_TYPES.decisionService && nodeBeingDragged.type === NODE_TYPES.decision) {
                 for (let i = 0; i < selectedNodes.length; i++) {
                   deleteDecisionFromDecisionService({
@@ -791,7 +838,10 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
                   definitions: state.dmn.model.definitions,
                   drdIndex: state.diagram.drdIndex,
                   decisionId: selectedNodes[i].data.dmnObject!["@_id"]!, // We can assume that all selected nodes are Decisions because the contaiment was validated above.
-                  decisionServiceId: nodesById.get(dropTargetNode.id)!.data.dmnObject!["@_id"]!,
+                  decisionServiceId: state
+                    .computed(state)
+                    .getDiagramData(externalModelsByNamespace)
+                    .nodesById.get(dropTargetNode.id)!.data.dmnObject!["@_id"]!,
                   snapGrid: state.diagram.snapGrid,
                 });
               }
@@ -806,14 +856,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           resetToBeforeEditingBegan();
         }
       },
-      [
-        dmnEditorStoreApi,
-        isDropTargetNodeValidForSelection,
-        nodesById,
-        resetToBeforeEditingBegan,
-        selectedNodeTypes,
-        selectedNodesById,
-      ]
+      [dmnEditorStoreApi, externalModelsByNamespace, resetToBeforeEditingBegan]
     );
 
     const onEdgesChange = useCallback<RF.OnEdgesChange>(
@@ -823,18 +866,19 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
             switch (change.type) {
               case "select":
                 console.debug(`DMN DIAGRAM: 'onEdgesChange' --> select '${change.id}'`);
-                state.dispatch.diagram.setEdgeStatus(state, change.id, { selected: change.selected });
+                state.dispatch(state).diagram.setEdgeStatus(change.id, { selected: change.selected });
                 break;
               case "remove":
                 console.debug(`DMN DIAGRAM: 'onEdgesChange' --> remove '${change.id}'`);
-                const edge = edgesById.get(change.id);
+                const edge = state.computed(state).getDiagramData(externalModelsByNamespace).edgesById.get(change.id);
                 if (edge?.data) {
                   deleteEdge({
                     definitions: state.dmn.model.definitions,
                     drdIndex: state.diagram.drdIndex,
                     edge: { id: change.id, dmnObject: edge.data.dmnObject },
+                    mode: EdgeDeletionMode.FORM_DRG_AND_ALL_DRDS,
                   });
-                  state.dispatch.diagram.setEdgeStatus(state, change.id, { selected: false, draggingWaypoint: false });
+                  state.dispatch(state).diagram.setEdgeStatus(change.id, { selected: false, draggingWaypoint: false });
                 }
                 break;
               case "add":
@@ -844,39 +888,46 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           }
         });
       },
-      [dmnEditorStoreApi, edgesById]
+      [dmnEditorStoreApi, externalModelsByNamespace]
     );
 
     const onEdgeUpdate = useCallback<RF.OnEdgeUpdateFunc<DmnDiagramEdgeData>>(
       (oldEdge, newConnection) => {
         console.debug("DMN DIAGRAM: `onEdgeUpdate`", oldEdge, newConnection);
 
-        const sourceNode = nodesById.get(newConnection.source!);
-        const targetNode = nodesById.get(newConnection.target!);
-        if (!sourceNode || !targetNode) {
-          throw new Error("Cannot create connection without target and source nodes!");
-        }
+        dmnEditorStoreApi.setState((state) => {
+          const sourceNode = state
+            .computed(state)
+            .getDiagramData(externalModelsByNamespace)
+            .nodesById.get(newConnection.source!);
+          const targetNode = state
+            .computed(state)
+            .getDiagramData(externalModelsByNamespace)
+            .nodesById.get(newConnection.target!);
+          if (!sourceNode || !targetNode) {
+            throw new Error("Cannot create connection without target and source nodes!");
+          }
 
-        const sourceBounds = sourceNode.data.shape["dc:Bounds"];
-        const targetBounds = targetNode.data.shape["dc:Bounds"];
-        if (!sourceBounds || !targetBounds) {
-          throw new Error("Cannot create connection without target bounds!");
-        }
+          const sourceBounds = sourceNode.data.shape["dc:Bounds"];
+          const targetBounds = targetNode.data.shape["dc:Bounds"];
+          if (!sourceBounds || !targetBounds) {
+            throw new Error("Cannot create connection without target bounds!");
+          }
 
-        // --------- This is where we draw the line between the diagram and the model.
+          // --------- This is where we draw the line between the diagram and the model.
 
-        const lastWaypoint = oldEdge.data?.dmnEdge
-          ? oldEdge.data!.dmnEdge!["di:waypoint"]![oldEdge.data!.dmnEdge!["di:waypoint"]!.length - 1]!
-          : getBoundsCenterPoint(targetBounds);
-        const firstWaypoint = oldEdge.data?.dmnEdge
-          ? oldEdge.data!.dmnEdge!["di:waypoint"]![0]!
-          : getBoundsCenterPoint(sourceBounds);
+          const lastWaypoint = oldEdge.data?.dmnEdge
+            ? oldEdge.data!.dmnEdge!["di:waypoint"]![oldEdge.data!.dmnEdge!["di:waypoint"]!.length - 1]!
+            : getDmnBoundsCenterPoint(targetBounds);
+          const firstWaypoint = oldEdge.data?.dmnEdge
+            ? oldEdge.data!.dmnEdge!["di:waypoint"]![0]!
+            : getDmnBoundsCenterPoint(sourceBounds);
 
-        dmnEditorStoreApi.setState((state) => {
           const { newDmnEdge } = addEdge({
             definitions: state.dmn.model.definitions,
             drdIndex: state.diagram.drdIndex,
             edge: {
+              autoPositionedEdgeMarker: undefined,
               type: oldEdge.type as EdgeType,
               targetHandle: ((newConnection.targetHandle as PositionalNodeHandleId) ??
                 getHandlePosition({ shapeBounds: targetBounds, waypoint: lastWaypoint })
@@ -903,15 +954,16 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
             keepWaypoints: true,
           });
 
-          // The DMN Edge changed nodes, so we need to delete the old one, but keep the waypoints!
+          // The DMN Edge changed nodes, so we need to delete the old one, but keep the waypoints on the same DRD.
           if (newDmnEdge["@_dmnElementRef"] !== oldEdge.id) {
-            const { dmnEdge: deletedDmnEdge } = deleteEdge({
+            const { deletedDmnEdgeOnCurrentDrd } = deleteEdge({
               definitions: state.dmn.model.definitions,
               drdIndex: state.diagram.drdIndex,
               edge: { id: oldEdge.id, dmnObject: oldEdge.data!.dmnObject },
+              mode: EdgeDeletionMode.FORM_DRG_AND_ALL_DRDS,
             });
 
-            const deletedWaypoints = deletedDmnEdge?.["di:waypoint"];
+            const deletedWaypoints = deletedDmnEdgeOnCurrentDrd?.["di:waypoint"];
 
             if (oldEdge.source !== newConnection.source && deletedWaypoints) {
               newDmnEdge["di:waypoint"] = [newDmnEdge["di:waypoint"]![0], ...deletedWaypoints.slice(1)];
@@ -933,7 +985,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           state.diagram.edgeIdBeingUpdated = undefined;
         });
       },
-      [dmnEditorStoreApi, nodesById]
+      [dmnEditorStoreApi, externalModelsByNamespace]
     );
 
     const onEdgeUpdateStart = useCallback(
@@ -962,8 +1014,10 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
     // Override Reactflow's behavior by intercepting the keydown event using its `capture` variant.
     const handleRfKeyDownCapture = useCallback(
       (e: React.KeyboardEvent) => {
+        const s = dmnEditorStoreApi.getState();
+
         if (e.key === "Escape") {
-          if (isDiagramEditingInProgress && dmnModelBeforeEditingRef.current) {
+          if (s.computed(s).isDiagramEditingInProgress() && dmnModelBeforeEditingRef.current) {
             console.debug(
               "DMN DIAGRAM: Intercepting Escape pressed and preventing propagation. Reverting DMN model to what it was before editing began."
             );
@@ -972,14 +1026,20 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
             e.preventDefault();
 
             resetToBeforeEditingBegan();
-          } else if (!diagram.ongoingConnection) {
+          } else if (!s.diagram.ongoingConnection) {
             dmnEditorStoreApi.setState((state) => {
-              if (selectedNodesById.size > 0 || selectedEdgesById.size > 0) {
+              if (
+                state.computed(s).getDiagramData(externalModelsByNamespace).selectedNodesById.size > 0 ||
+                state.computed(s).getDiagramData(externalModelsByNamespace).selectedEdgesById.size > 0
+              ) {
                 console.debug("DMN DIAGRAM: Esc pressed. Desselecting everything.");
                 state.diagram._selectedNodes = [];
                 state.diagram._selectedEdges = [];
                 e.preventDefault();
-              } else if (selectedNodesById.size <= 0 && selectedEdgesById.size <= 0) {
+              } else if (
+                state.computed(s).getDiagramData(externalModelsByNamespace).selectedNodesById.size <= 0 &&
+                state.computed(s).getDiagramData(externalModelsByNamespace).selectedEdgesById.size <= 0
+              ) {
                 console.debug("DMN DIAGRAM: Esc pressed. Closing all open panels.");
                 state.diagram.propertiesPanel.isOpen = false;
                 state.diagram.overlaysPanel.isOpen = false;
@@ -994,21 +1054,21 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
           }
         }
       },
-      [
-        diagram.ongoingConnection,
-        dmnEditorStoreApi,
-        dmnModelBeforeEditingRef,
-        isDiagramEditingInProgress,
-        resetToBeforeEditingBegan,
-        selectedEdgesById.size,
-        selectedNodesById.size,
-      ]
+      [dmnEditorStoreApi, dmnModelBeforeEditingRef, externalModelsByNamespace, resetToBeforeEditingBegan]
     );
 
     const [showEmptyState, setShowEmptyState] = useState(true);
 
+    const nodes = useDmnEditorStore((s) => s.computed(s).getDiagramData(externalModelsByNamespace).nodes);
+    const edges = useDmnEditorStore((s) => s.computed(s).getDiagramData(externalModelsByNamespace).edges);
+    const drgElementsWithoutVisualRepresentationOnCurrentDrdLength = useDmnEditorStore(
+      (s) =>
+        s.computed(s).getDiagramData(externalModelsByNamespace).drgElementsWithoutVisualRepresentationOnCurrentDrd
+          .length
+    );
+
     const isEmptyStateShowing =
-      showEmptyState && nodes.length === 0 && drgElementsWithoutVisualRepresentationOnCurrentDrd.length === 0;
+      showEmptyState && nodes.length === 0 && drgElementsWithoutVisualRepresentationOnCurrentDrdLength === 0;
 
     return (
       <>
@@ -1060,6 +1120,7 @@ export const Diagram = React.forwardRef<DiagramRef, { container: React.RefObject
             fitViewOptions={FIT_VIEW_OPTIONS}
             attributionPosition={"bottom-right"}
             onInit={setReactFlowInstance}
+            deleteKeyCode={DELETE_NODE_KEY_CODES}
             // (begin)
             // Used to make the Palette work by dropping nodes on the Reactflow Canvas
             onDrop={onDrop}
@@ -1155,7 +1216,7 @@ function DmnDiagramEmptyState({
                     }),
                   });
 
-                  state.dispatch.boxedExpressionEditor.open(state, parseXmlHref(decisionNodeHref).id);
+                  state.dispatch(state).boxedExpressionEditor.open(parseXmlHref(decisionNodeHref).id);
                 });
               }}
             >
@@ -1219,20 +1280,15 @@ function DmnDiagramEmptyState({
 }
 
 export function SetConnectionToReactFlowStore(props: {}) {
-  const diagram = useDmnEditorStore((s) => s.diagram);
+  const ongoingConnection = useDmnEditorStore((s) => s.diagram.ongoingConnection);
   const rfStoreApi = RF.useStoreApi();
   useEffect(() => {
     rfStoreApi.setState({
-      connectionHandleId: diagram.ongoingConnection?.handleId,
-      connectionHandleType: diagram.ongoingConnection?.handleType,
-      connectionNodeId: diagram.ongoingConnection?.nodeId,
+      connectionHandleId: ongoingConnection?.handleId,
+      connectionHandleType: ongoingConnection?.handleType,
+      connectionNodeId: ongoingConnection?.nodeId,
     });
-  }, [
-    diagram.ongoingConnection?.handleId,
-    diagram.ongoingConnection?.handleType,
-    diagram.ongoingConnection?.nodeId,
-    rfStoreApi,
-  ]);
+  }, [ongoingConnection?.handleId, ongoingConnection?.handleType, ongoingConnection?.nodeId, rfStoreApi]);
 
   return <></>;
 }
@@ -1270,15 +1326,19 @@ export function TopRightCornerPanels() {
   return (
     <>
       <RF.Panel position={"top-right"} style={{ display: "flex" }}>
+        <aside className={"kie-dmn-editor--autolayout-panel-toggle"}>
+          <AutolayoutButton />
+        </aside>
         <aside className={"kie-dmn-editor--overlays-panel-toggle"}>
           <Popover
             className={"kie-dmn-editor--overlay-panel-popover"}
             key={`${diagram.overlaysPanel.isOpen}`}
             aria-label="Overlays Panel"
             position={"bottom-end"}
+            enableFlip={false}
+            flipBehavior={["bottom-end"]}
             hideOnOutsideClick={false}
             isVisible={diagram.overlaysPanel.isOpen}
-            enableFlip={true}
             bodyContent={<OverlaysPanel />}
           >
             <button className={"kie-dmn-editor--overlays-panel-toggle-button"} onClick={toggleOverlaysPanel}>
@@ -1301,14 +1361,20 @@ export function TopRightCornerPanels() {
 export function SelectionStatus() {
   const rfStoreApi = RF.useStoreApi();
 
-  const { selectedNodesById, selectedEdgesById } = useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
+  const selectedNodesCount = useDmnEditorStore(
+    (s) => s.computed(s).getDiagramData(externalModelsByNamespace).selectedNodesById.size
+  );
+  const selectedEdgesCount = useDmnEditorStore(
+    (s) => s.computed(s).getDiagramData(externalModelsByNamespace).selectedEdgesById.size
+  );
   const dmnEditorStoreApi = useDmnEditorStoreApi();
 
   useEffect(() => {
-    if (selectedNodesById.size >= 2) {
+    if (selectedNodesCount >= 2) {
       rfStoreApi.setState({ nodesSelectionActive: true });
     }
-  }, [rfStoreApi, selectedNodesById.size]);
+  }, [rfStoreApi, selectedNodesCount]);
 
   const onClose = useCallback(
     (e: React.MouseEvent) => {
@@ -1323,14 +1389,14 @@ export function SelectionStatus() {
 
   return (
     <>
-      {(selectedNodesById.size + selectedEdgesById.size >= 2 && (
+      {(selectedNodesCount + selectedEdgesCount >= 2 && (
         <RF.Panel position={"top-center"}>
           <Label style={{ paddingLeft: "24px" }} onClose={onClose}>
-            {(selectedEdgesById.size === 0 && `${selectedNodesById.size} nodes selected`) ||
-              (selectedNodesById.size === 0 && `${selectedEdgesById.size} edges selected`) ||
-              `${selectedNodesById.size} node${selectedNodesById.size === 1 ? "" : "s"}, ${
-                selectedEdgesById.size
-              } edge${selectedEdgesById.size === 1 ? "" : "s"} selected`}
+            {(selectedEdgesCount === 0 && `${selectedNodesCount} nodes selected`) ||
+              (selectedNodesCount === 0 && `${selectedEdgesCount} edges selected`) ||
+              `${selectedNodesCount} node${selectedNodesCount === 1 ? "" : "s"}, ${selectedEdgesCount} edge${
+                selectedEdgesCount === 1 ? "" : "s"
+              } selected`}
           </Label>
         </RF.Panel>
       )) || <></>}
@@ -1341,10 +1407,11 @@ export function SelectionStatus() {
 export function KeyboardShortcuts(props: {}) {
   const rfStoreApi = RF.useStoreApi();
   const dmnEditorStoreApi = useDmnEditorStoreApi();
-  const diagram = useDmnEditorStore((s) => s.diagram);
+  const { externalModelsByNamespace } = useExternalModels();
 
-  const rf = RF.useReactFlow();
+  const rf = RF.useReactFlow<DmnDiagramNodeData, DmnDiagramEdgeData>();
 
+  // Reset position to origin
   const space = RF.useKeyPress(["Space"]);
   useEffect(() => {
     if (!space) {
@@ -1354,6 +1421,7 @@ export function KeyboardShortcuts(props: {}) {
     rf.setViewport(DEFAULT_VIEWPORT, { duration: 200 });
   }, [rf, space]);
 
+  // Focus on node bounds
   const b = RF.useKeyPress(["b"]);
   useEffect(() => {
     if (!b) {
@@ -1381,6 +1449,7 @@ export function KeyboardShortcuts(props: {}) {
     );
   }, [b, rf]);
 
+  // Cancel action
   const esc = RF.useKeyPress(["Escape"]);
   useEffect(() => {
     if (!esc) {
@@ -1400,8 +1469,9 @@ export function KeyboardShortcuts(props: {}) {
 
       return rfState;
     });
-  }, [dmnEditorStoreApi, esc, rfStoreApi]);
+  }, [esc, dmnEditorStoreApi, rfStoreApi]);
 
+  // Cut
   const cut = RF.useKeyPress(["Meta+x"]);
   useEffect(() => {
     if (!cut) {
@@ -1416,33 +1486,37 @@ export function KeyboardShortcuts(props: {}) {
 
     navigator.clipboard.writeText(JSON.stringify(clipboard)).then(() => {
       dmnEditorStoreApi.setState((state) => {
-        // Delete edges first
+        // Delete edges
         [...copiedEdgesById.values(), ...danglingEdgesById.values()].forEach((edge) => {
           deleteEdge({
             definitions: state.dmn.model.definitions,
             drdIndex: state.diagram.drdIndex,
             edge: { id: edge.id, dmnObject: edge.data!.dmnObject },
+            mode: EdgeDeletionMode.FORM_DRG_AND_ALL_DRDS,
           });
-          state.dispatch.diagram.setEdgeStatus(state, edge.id, {
+          state.dispatch(state).diagram.setEdgeStatus(edge.id, {
             selected: false,
             draggingWaypoint: false,
           });
         });
 
-        // Then delete nodes
+        // Delete nodes
         rfStoreApi
           .getState()
           .getNodes()
           .forEach((node: RF.Node<DmnDiagramNodeData>) => {
             if (copiedNodesById.has(node.id)) {
               deleteNode({
+                drgEdges: state.computed(state).getDiagramData(externalModelsByNamespace).drgEdges,
                 definitions: state.dmn.model.definitions,
                 drdIndex: state.diagram.drdIndex,
+                dmnObjectNamespace: node.data.dmnObjectNamespace,
                 dmnObjectQName: node.data.dmnObjectQName,
                 dmnObjectId: node.data.dmnObject?.["@_id"],
                 nodeNature: nodeNatures[node.type as NodeType],
+                mode: NodeDeletionMode.FORM_DRG_AND_ALL_DRDS,
               });
-              state.dispatch.diagram.setNodeStatus(state, node.id, {
+              state.dispatch(state).diagram.setNodeStatus(node.id, {
                 selected: false,
                 dragging: false,
                 resizing: false,
@@ -1451,8 +1525,9 @@ export function KeyboardShortcuts(props: {}) {
           });
       });
     });
-  }, [cut, dmnEditorStoreApi, rfStoreApi]);
+  }, [cut, dmnEditorStoreApi, rfStoreApi, externalModelsByNamespace]);
 
+  // Copy
   const copy = RF.useKeyPress(["Meta+c"]);
   useEffect(() => {
     if (!copy) {
@@ -1465,6 +1540,7 @@ export function KeyboardShortcuts(props: {}) {
     navigator.clipboard.writeText(JSON.stringify(clipboard));
   }, [copy, dmnEditorStoreApi, rfStoreApi]);
 
+  // Paste
   const paste = RF.useKeyPress(["Meta+v"]);
   useEffect(() => {
     if (!paste) {
@@ -1536,8 +1612,9 @@ export function KeyboardShortcuts(props: {}) {
         }
       });
     });
-  }, [dmnEditorStoreApi, paste]);
+  }, [paste, dmnEditorStoreApi]);
 
+  // Select/deselect all
   const selectAll = RF.useKeyPress(["a", "Meta+a"]);
   useEffect(() => {
     if (!selectAll) {
@@ -1566,8 +1643,9 @@ export function KeyboardShortcuts(props: {}) {
         state.diagram._selectedEdges = allEdgeIds;
       }
     });
-  }, [dmnEditorStoreApi, rfStoreApi, selectAll]);
+  }, [selectAll, dmnEditorStoreApi, rfStoreApi]);
 
+  // Create group wrapping selection
   const g = RF.useKeyPress(["g"]);
   useEffect(() => {
     if (!g) {
@@ -1596,10 +1674,11 @@ export function KeyboardShortcuts(props: {}) {
         },
       });
 
-      state.dispatch.diagram.setNodeStatus(state, newNodeId, { selected: true });
+      state.dispatch(state).diagram.setNodeStatus(newNodeId, { selected: true });
     });
-  }, [dmnEditorStoreApi, g, rf]);
+  }, [g, dmnEditorStoreApi, rf]);
 
+  // Toggle hierarchy highlights
   const h = RF.useKeyPress(["h"]);
   useEffect(() => {
     if (!h) {
@@ -1609,8 +1688,9 @@ export function KeyboardShortcuts(props: {}) {
     dmnEditorStoreApi.setState((state) => {
       state.diagram.overlays.enableNodeHierarchyHighlight = !state.diagram.overlays.enableNodeHierarchyHighlight;
     });
-  }, [dmnEditorStoreApi, h]);
+  }, [h, dmnEditorStoreApi]);
 
+  // Show Properties panel
   const i = RF.useKeyPress(["i"]);
   useEffect(() => {
     if (!i) {
@@ -1620,7 +1700,70 @@ export function KeyboardShortcuts(props: {}) {
     dmnEditorStoreApi.setState((state) => {
       state.diagram.propertiesPanel.isOpen = !state.diagram.propertiesPanel.isOpen;
     });
-  }, [dmnEditorStoreApi, i]);
+  }, [i, dmnEditorStoreApi]);
+
+  // Hide from DRD
+  const x = RF.useKeyPress(["x"]);
+  useEffect(() => {
+    if (!x) {
+      return;
+    }
+
+    const nodesById = rf
+      .getNodes()
+      .reduce((acc, s) => acc.set(s.id, s), new Map<string, RF.Node<DmnDiagramNodeData>>());
+
+    dmnEditorStoreApi.setState((state) => {
+      const selectedNodeIds = new Set(state.diagram._selectedNodes);
+      for (const edge of rf.getEdges()) {
+        if (
+          (selectedNodeIds.has(edge.source) &&
+            canRemoveNodeFromDrdOnly({
+              definitions: state.dmn.model.definitions,
+              drdIndex: state.diagram.drdIndex,
+              dmnObjectNamespace: nodesById.get(edge.source)!.data.dmnObjectNamespace,
+              dmnObjectId: nodesById.get(edge.source)!.data.dmnObject?.["@_id"],
+            })) ||
+          (selectedNodeIds.has(edge.target) &&
+            canRemoveNodeFromDrdOnly({
+              definitions: state.dmn.model.definitions,
+              drdIndex: state.diagram.drdIndex,
+              dmnObjectNamespace: nodesById.get(edge.target)!.data.dmnObjectNamespace,
+              dmnObjectId: nodesById.get(edge.target)!.data.dmnObject?.["@_id"],
+            }))
+        ) {
+          deleteEdge({
+            definitions: state.dmn.model.definitions,
+            drdIndex: state.diagram.drdIndex,
+            edge: { id: edge.id, dmnObject: edge.data!.dmnObject },
+            mode: EdgeDeletionMode.FROM_CURRENT_DRD_ONLY,
+          });
+          state.dispatch(state).diagram.setEdgeStatus(edge.id, { selected: false, draggingWaypoint: false });
+        }
+      }
+
+      for (const node of rf.getNodes().filter((s) => s.selected)) {
+        const { deletedDmnShapeOnCurrentDrd: deletedShape } = deleteNode({
+          drgEdges: [], // Deleting from DRD only.
+          definitions: state.dmn.model.definitions,
+          drdIndex: state.diagram.drdIndex,
+          dmnObjectNamespace: node.data.dmnObjectNamespace,
+          dmnObjectQName: node.data.dmnObjectQName,
+          dmnObjectId: node.data.dmnObject?.["@_id"],
+          nodeNature: nodeNatures[node.type as NodeType],
+          mode: NodeDeletionMode.FROM_CURRENT_DRD_ONLY,
+        });
+
+        if (deletedShape) {
+          state.dispatch(state).diagram.setNodeStatus(node.id, {
+            selected: false,
+            dragging: false,
+            resizing: false,
+          });
+        }
+      }
+    });
+  }, [x, dmnEditorStoreApi, rf]);
 
   return <></>;
 }
diff --git a/packages/dmn-editor/src/diagram/DrdSelectorPanel.tsx b/packages/dmn-editor/src/diagram/DrdSelectorPanel.tsx
index 0340973a26e..1aab48d71dc 100644
--- a/packages/dmn-editor/src/diagram/DrdSelectorPanel.tsx
+++ b/packages/dmn-editor/src/diagram/DrdSelectorPanel.tsx
@@ -18,13 +18,16 @@
  */
 
 import * as React from "react";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { addOrGetDrd, getDefaultDrdName } from "../mutations/addOrGetDrd";
 import { Text, TextContent } from "@patternfly/react-core/dist/js/components/Text";
-import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
+import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
 import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button";
 import { PlusCircleIcon } from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
 import { Divider } from "@patternfly/react-core/dist/js/components/Divider";
+import { ArrowRightIcon } from "@patternfly/react-icons/dist/js/icons/arrow-right-icon";
+import { DiagramNodesPanel } from "../store/Store";
+import { getDrdId } from "./drd/drdId";
 
 export function DrdSelectorPanel() {
   const thisDmn = useDmnEditorStore((s) => s.dmn);
@@ -49,7 +52,11 @@ export function DrdSelectorPanel() {
                 definitions: state.dmn.model.definitions,
                 drdIndex: newIndex,
               });
+
               state.diagram.drdIndex = newIndex;
+              state.diagram.drdSelector.isOpen = false;
+              state.diagram.openNodesPanel = DiagramNodesPanel.DRG_NODES;
+              state.focus.consumableId = getDrdId({ drdIndex: newIndex });
             });
           }}
         >
@@ -59,7 +66,7 @@ export function DrdSelectorPanel() {
       <Divider style={{ marginBottom: "8px" }} />
       <div className={"kie-dmn-editor--drd-list"}>
         {thisDmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.map((drd, i) => (
-          <React.Fragment key={drd["@_id"] ?? i}>
+          <React.Fragment key={drd["@_id"]!}>
             <button
               className={i === diagram.drdIndex ? "active" : undefined}
               onClick={() => {
@@ -69,7 +76,7 @@ export function DrdSelectorPanel() {
                 });
               }}
             >
-              {drd["@_name"] || getDefaultDrdName({ drdIndex: i })}
+              {`${i + 1}. ${drd["@_name"] || getDefaultDrdName({ drdIndex: i })}`}
             </button>
             <br />
           </React.Fragment>
diff --git a/packages/dmn-editor/src/diagram/DrgNodesPanel.tsx b/packages/dmn-editor/src/diagram/DrgNodesPanel.tsx
index 11b3b936795..2957f0eec09 100644
--- a/packages/dmn-editor/src/diagram/DrgNodesPanel.tsx
+++ b/packages/dmn-editor/src/diagram/DrgNodesPanel.tsx
@@ -17,26 +17,26 @@
  * under the License.
  */
 
-import { Divider } from "@patternfly/react-core/dist/js/components/Divider";
+import { DMN15__tDefinitions } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button/Button";
 import { SearchInput } from "@patternfly/react-core/dist/js/components/SearchInput";
 import { Text, TextContent } from "@patternfly/react-core/dist/js/components/Text";
 import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
+import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
 import * as React from "react";
 import { useCallback, useState } from "react";
-import { DiagramNodesPanel, useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
-import { buildXmlHref } from "../xml/xmlHrefs";
 import { DmnObjectListItem } from "../externalNodes/DmnObjectListItem";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
-import { DMN15__tDefinitions } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { DiagramNodesPanel } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { Unpacked } from "../tsExt/tsExt";
-import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button/Button";
-import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
+import { buildXmlHref } from "../xml/xmlHrefs";
+import { Divider } from "@patternfly/react-core/dist/js/components/Divider";
 
 export const MIME_TYPE_FOR_DMN_EDITOR_DRG_NODE = "kie-dmn-editor--drg-node";
 
 export function DrgNodesPanel() {
   const thisDmn = useDmnEditorStore((s) => s.dmn);
-  const { dmnShapesByHref } = useDmnEditorDerivedStore();
+  const dmnShapesByHref = useDmnEditorStore((s) => s.computed(s).indexes().dmnShapesByHref);
 
   const dmnEditorStoreApi = useDmnEditorStoreApi();
 
@@ -98,6 +98,8 @@ export function DrgNodesPanel() {
           </Button>
         </Flex>
 
+        <Divider style={{ marginBottom: "12px" }} />
+
         <SearchInput
           style={{ marginBottom: "12px", height: "36px" }}
           onKeyDown={(e) => e.stopPropagation()}
diff --git a/packages/dmn-editor/src/diagram/Palette.tsx b/packages/dmn-editor/src/diagram/Palette.tsx
index 06c716af6d4..cb3640e19c5 100644
--- a/packages/dmn-editor/src/diagram/Palette.tsx
+++ b/packages/dmn-editor/src/diagram/Palette.tsx
@@ -22,7 +22,8 @@ import * as React from "react";
 import { useCallback } from "react";
 import { NodeType } from "./connections/graphStructure";
 import { NODE_TYPES } from "./nodes/NodeTypes";
-import { DiagramNodesPanel, useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { DiagramNodesPanel } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { addStandaloneNode } from "../mutations/addStandaloneNode";
 import { CONTAINER_NODES_DESIRABLE_PADDING, getBounds } from "./maths/DmnMaths";
 import { Popover } from "@patternfly/react-core/dist/js/components/Popover";
@@ -45,6 +46,7 @@ import { DrgNodesPanel } from "./DrgNodesPanel";
 import { CaretDownIcon } from "@patternfly/react-icons/dist/js/icons/caret-down-icon";
 import { useInViewSelect } from "../responsiveness/useInViewSelect";
 import { useDmnEditor } from "../DmnEditorContext";
+import { getDrdId } from "./drd/drdId";
 
 export const MIME_TYPE_FOR_DMN_EDITOR_NEW_NODE_FROM_PALETTE = "application/kie-dmn-editor--new-node-from-palette";
 
@@ -83,7 +85,7 @@ export function Palette({ pulse }: { pulse: boolean }) {
         },
       });
 
-      state.dispatch.diagram.setNodeStatus(state, newNodeId, { selected: true });
+      state.dispatch(state).diagram.setNodeStatus(newNodeId, { selected: true });
     });
   }, [diagram.drdIndex, dmnEditorStoreApi, rfStoreApi]);
 
@@ -101,9 +103,10 @@ export function Palette({ pulse }: { pulse: boolean }) {
           <div ref={drdSelectorPopoverRef} style={{ position: "absolute", left: "56px", height: "100%", zIndex: -1 }} />
           <InlineFeelNameInput
             validate={() => true}
-            allUniqueNames={new Map()}
+            allUniqueNames={() => new Map()}
             name={drd?.["@_name"] ?? ""}
-            id={diagram.drdIndex + ""}
+            prefix={`${diagram.drdIndex + 1}.`}
+            id={getDrdId({ drdIndex: diagram.drdIndex })}
             onRenamed={(newName) => {
               dmnEditorStoreApi.setState((state) => {
                 const drd = addOrGetDrd({ definitions: state.dmn.model.definitions, drdIndex: diagram.drdIndex });
diff --git a/packages/dmn-editor/src/diagram/connections/ConnectionLine.tsx b/packages/dmn-editor/src/diagram/connections/ConnectionLine.tsx
index 37a657b148b..ea393275710 100644
--- a/packages/dmn-editor/src/diagram/connections/ConnectionLine.tsx
+++ b/packages/dmn-editor/src/diagram/connections/ConnectionLine.tsx
@@ -30,21 +30,24 @@ import {
 import { NODE_TYPES } from "../nodes/NodeTypes";
 import { getPositionalHandlePosition } from "../maths/Maths";
 import { DecisionNodeSvg, BkmNodeSvg, KnowledgeSourceNodeSvg, TextAnnotationNodeSvg } from "../nodes/NodeSvgs";
-import { getNodeCenterPoint, pointsToPath } from "../maths/DmnMaths";
+import { pointsToPath } from "../maths/DmnMaths";
+import { getBoundsCenterPoint } from "../maths/Maths";
 import { NodeType, getDefaultEdgeTypeBetween } from "./graphStructure";
 import { switchExpression } from "@kie-tools-core/switch-expression-ts";
 import { DEFAULT_NODE_SIZES } from "../nodes/DefaultSizes";
-import { useDmnEditorStore } from "../../store/Store";
+import { useDmnEditorStore } from "../../store/StoreContext";
 import { useKieEdgePath } from "../edges/useKieEdgePath";
 import { PositionalNodeHandleId } from "./PositionalNodeHandles";
-import { useDmnEditorDerivedStore } from "../../store/DerivedStore";
+import { useExternalModels } from "../../includedModels/DmnEditorDependenciesContext";
 
 export function ConnectionLine({ toX, toY, fromNode, fromHandle }: RF.ConnectionLineComponentProps) {
-  const diagram = useDmnEditorStore((s) => s.diagram);
-
-  const edgeId = useDmnEditorStore((s) => s.diagram.edgeIdBeingUpdated);
-  const { edgesById } = useDmnEditorDerivedStore();
-  const edge = edgeId ? edgesById.get(edgeId) : undefined;
+  const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+  const { externalModelsByNamespace } = useExternalModels();
+  const edge = useDmnEditorStore((s) =>
+    s.diagram.edgeIdBeingUpdated
+      ? s.computed(s).getDiagramData(externalModelsByNamespace).edgesById.get(s.diagram.edgeIdBeingUpdated)
+      : undefined
+  );
   const kieEdgePath = useKieEdgePath(edge?.source, edge?.target, edge?.data);
 
   // This works because nodes are configured with:
@@ -57,7 +60,12 @@ export function ConnectionLine({ toX, toY, fromNode, fromHandle }: RF.Connection
     (k) => (PositionalNodeHandleId as any)[k] === fromHandle?.id
   );
 
-  const { "@_x": fromX, "@_y": fromY } = getNodeCenterPoint(fromNode);
+  const { "@_x": fromX, "@_y": fromY } = getBoundsCenterPoint({
+    x: fromNode?.positionAbsolute?.x,
+    y: fromNode?.positionAbsolute?.y,
+    width: fromNode?.width,
+    height: fromNode?.height,
+  });
 
   const connectionLinePath =
     edge && kieEdgePath.points
@@ -81,9 +89,9 @@ export function ConnectionLine({ toX, toY, fromNode, fromHandle }: RF.Connection
   // Nodes
   else {
     const nodeType = handleId as NodeType;
-    const { "@_x": toXsnapped, "@_y": toYsnapped } = snapPoint(diagram.snapGrid, { "@_x": toX, "@_y": toY });
+    const { "@_x": toXsnapped, "@_y": toYsnapped } = snapPoint(snapGrid, { "@_x": toX, "@_y": toY });
 
-    const defaultSize = DEFAULT_NODE_SIZES[nodeType](diagram.snapGrid);
+    const defaultSize = DEFAULT_NODE_SIZES[nodeType](snapGrid);
     const [toXauto, toYauto] = getPositionalHandlePosition(
       { x: toXsnapped, y: toYsnapped, width: defaultSize["@_width"], height: defaultSize["@_height"] },
       { x: fromX, y: fromY, width: 1, height: 1 }
diff --git a/packages/dmn-editor/src/focus/useFocusableElement.ts b/packages/dmn-editor/src/diagram/drd/drdId.ts
similarity index 52%
copy from packages/dmn-editor/src/focus/useFocusableElement.ts
copy to packages/dmn-editor/src/diagram/drd/drdId.ts
index d4b0823497b..60196289a50 100644
--- a/packages/dmn-editor/src/focus/useFocusableElement.ts
+++ b/packages/dmn-editor/src/diagram/drd/drdId.ts
@@ -17,32 +17,6 @@
  * under the License.
  */
 
-import { useEffect } from "react";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
-
-export function useFocusableElement(
-  ref: React.RefObject<HTMLInputElement>,
-  id: string | undefined,
-  before?: (cb: () => void) => void
-) {
-  const focus = useDmnEditorStore((s) => s.focus);
-  const dmnEditorStoreApi = useDmnEditorStoreApi();
-
-  useEffect(() => {
-    if (!id) {
-      return;
-    }
-
-    const cb = () => {
-      ref.current?.select();
-
-      dmnEditorStoreApi.setState((state) => {
-        state.focus.consumableId = undefined;
-      });
-    };
-
-    if (focus.consumableId === id && ref.current) {
-      before?.(cb) ?? cb();
-    }
-  }, [before, dmnEditorStoreApi, focus.consumableId, id, ref]);
+export function getDrdId({ drdIndex }: { drdIndex: number }) {
+  return `drd__${drdIndex}`;
 }
diff --git a/packages/dmn-editor/src/diagram/edges/Edges.tsx b/packages/dmn-editor/src/diagram/edges/Edges.tsx
index 27567ccf980..a210dc55170 100644
--- a/packages/dmn-editor/src/diagram/edges/Edges.tsx
+++ b/packages/dmn-editor/src/diagram/edges/Edges.tsx
@@ -17,31 +17,22 @@
  * under the License.
  */
 
-import {
-  DMN15__tDefinitions,
-  DMNDI15__DMNEdge,
-  DMNDI15__DMNShape,
-} from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { DMNDI15__DMNEdge, DMNDI15__DMNShape } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import * as React from "react";
+import { useRef } from "react";
 import * as RF from "reactflow";
-import { Unpacked } from "../../tsExt/tsExt";
+import { DrgEdge } from "../graph/graph";
+import { DEFAULT_INTRACTION_WIDTH } from "../maths/DmnMaths";
+import { propsHaveSameValuesDeep } from "../memoization/memoization";
+import { useIsHovered } from "../useIsHovered";
 import { PotentialWaypoint, Waypoints } from "./Waypoints";
+import { useAlwaysVisibleEdgeUpdatersAtNodeBorders } from "./useAlwaysVisibleEdgeUpdatersAtNodeBorders";
 import { useKieEdgePath } from "./useKieEdgePath";
-import { useIsHovered } from "../useIsHovered";
 import { usePotentialWaypointControls } from "./usePotentialWaypointControls";
-import { useAlwaysVisibleEdgeUpdatersAtNodeBorders } from "./useAlwaysVisibleEdgeUpdatersAtNodeBorders";
-import { DEFAULT_INTRACTION_WIDTH } from "../maths/DmnMaths";
 
 export type DmnDiagramEdgeData = {
   dmnEdge: (DMNDI15__DMNEdge & { index: number }) | undefined;
-  dmnObject: {
-    id: string;
-    type:
-      | Unpacked<DMN15__tDefinitions["artifact"]>["__$$element"]
-      | Unpacked<DMN15__tDefinitions["drgElement"]>["__$$element"];
-    requirementType: "informationRequirement" | "knowledgeRequirement" | "authorityRequirement" | "association";
-    index: number;
-  };
+  dmnObject: DrgEdge["dmnObject"];
   dmnShapeSource: DMNDI15__DMNShape | undefined;
   dmnShapeTarget: DMNDI15__DMNShape | undefined;
 };
@@ -136,6 +127,9 @@ const interactionStrokeProps: Partial<React.SVGAttributes<SVGPathElement>> = {
 };
 
 export const InformationRequirementEdge = React.memo((props: RF.EdgeProps<DmnDiagramEdgeData>) => {
+  const renderCount = useRef<number>(0);
+  renderCount.current++;
+
   const { path, points: waypoints } = useKieEdgePath(props.source, props.target, props.data);
 
   const interactionPathRef = React.useRef<SVGPathElement>(null);
@@ -152,9 +146,7 @@ export const InformationRequirementEdge = React.memo((props: RF.EdgeProps<DmnDia
   const isConnecting = !!RF.useStore((s) => s.connectionNodeId);
   const className = useEdgeClassName(isConnecting, isDraggingWaypoint);
 
-  const sourceNode = RF.useStore((s) => s.nodeInternals.get(props.source)!);
-  const targetNode = RF.useStore((s) => s.nodeInternals.get(props.target)!);
-  useAlwaysVisibleEdgeUpdatersAtNodeBorders(interactionPathRef, sourceNode, targetNode, waypoints);
+  useAlwaysVisibleEdgeUpdatersAtNodeBorders(interactionPathRef, props.source, props.target, waypoints);
 
   return (
     <>
@@ -168,6 +160,7 @@ export const InformationRequirementEdge = React.memo((props: RF.EdgeProps<DmnDia
         onDoubleClick={onDoubleClick}
       />
       <InformationRequirementPath d={path} className={`kie-dmn-editor--edge ${className}`} />
+
       {props.selected && !isConnecting && props.data?.dmnEdge && (
         <Waypoints
           edgeId={props.id}
@@ -179,9 +172,12 @@ export const InformationRequirementEdge = React.memo((props: RF.EdgeProps<DmnDia
       {isHovered && potentialWaypoint && <PotentialWaypoint point={potentialWaypoint.point} />}
     </>
   );
-});
+}, propsHaveSameValuesDeep);
 
 export const KnowledgeRequirementEdge = React.memo((props: RF.EdgeProps<DmnDiagramEdgeData>) => {
+  const renderCount = useRef<number>(0);
+  renderCount.current++;
+
   const { path, points: waypoints } = useKieEdgePath(props.source, props.target, props.data);
 
   const interactionPathRef = React.useRef<SVGPathElement>(null);
@@ -198,9 +194,7 @@ export const KnowledgeRequirementEdge = React.memo((props: RF.EdgeProps<DmnDiagr
   const isConnecting = !!RF.useStore((s) => s.connectionNodeId);
   const className = useEdgeClassName(isConnecting, isDraggingWaypoint);
 
-  const sourceNode = RF.useStore((s) => s.nodeInternals.get(props.source)!);
-  const targetNode = RF.useStore((s) => s.nodeInternals.get(props.target)!);
-  useAlwaysVisibleEdgeUpdatersAtNodeBorders(interactionPathRef, sourceNode, targetNode, waypoints);
+  useAlwaysVisibleEdgeUpdatersAtNodeBorders(interactionPathRef, props.source, props.target, waypoints);
 
   return (
     <>
@@ -214,6 +208,7 @@ export const KnowledgeRequirementEdge = React.memo((props: RF.EdgeProps<DmnDiagr
         onDoubleClick={onDoubleClick}
       />
       <KnowledgeRequirementPath d={path} className={`kie-dmn-editor--edge ${className}`} />
+
       {props.selected && !isConnecting && props.data?.dmnEdge && (
         <Waypoints
           edgeId={props.id}
@@ -225,9 +220,12 @@ export const KnowledgeRequirementEdge = React.memo((props: RF.EdgeProps<DmnDiagr
       {isHovered && potentialWaypoint && <PotentialWaypoint point={potentialWaypoint.point} />}
     </>
   );
-});
+}, propsHaveSameValuesDeep);
 
 export const AuthorityRequirementEdge = React.memo((props: RF.EdgeProps<DmnDiagramEdgeData>) => {
+  const renderCount = useRef<number>(0);
+  renderCount.current++;
+
   const { path, points: waypoints } = useKieEdgePath(props.source, props.target, props.data);
 
   const interactionPathRef = React.useRef<SVGPathElement>(null);
@@ -244,9 +242,7 @@ export const AuthorityRequirementEdge = React.memo((props: RF.EdgeProps<DmnDiagr
   const isConnecting = !!RF.useStore((s) => s.connectionNodeId);
   const className = useEdgeClassName(isConnecting, isDraggingWaypoint);
 
-  const sourceNode = RF.useStore((s) => s.nodeInternals.get(props.source)!);
-  const targetNode = RF.useStore((s) => s.nodeInternals.get(props.target)!);
-  useAlwaysVisibleEdgeUpdatersAtNodeBorders(interactionPathRef, sourceNode, targetNode, waypoints);
+  useAlwaysVisibleEdgeUpdatersAtNodeBorders(interactionPathRef, props.source, props.target, waypoints);
 
   return (
     <>
@@ -265,6 +261,7 @@ export const AuthorityRequirementEdge = React.memo((props: RF.EdgeProps<DmnDiagr
         className={`kie-dmn-editor--edge ${className}`}
         centerToConnectionPoint={false}
       />
+
       {props.selected && !isConnecting && props.data?.dmnEdge && (
         <Waypoints
           edgeId={props.id}
@@ -276,9 +273,12 @@ export const AuthorityRequirementEdge = React.memo((props: RF.EdgeProps<DmnDiagr
       {isHovered && potentialWaypoint && <PotentialWaypoint point={potentialWaypoint.point} />}
     </>
   );
-});
+}, propsHaveSameValuesDeep);
 
 export const AssociationEdge = React.memo((props: RF.EdgeProps<DmnDiagramEdgeData>) => {
+  const renderCount = useRef<number>(0);
+  renderCount.current++;
+
   const { path, points: waypoints } = useKieEdgePath(props.source, props.target, props.data);
 
   const interactionPathRef = React.useRef<SVGPathElement>(null);
@@ -295,9 +295,7 @@ export const AssociationEdge = React.memo((props: RF.EdgeProps<DmnDiagramEdgeDat
   const isConnecting = !!RF.useStore((s) => s.connectionNodeId);
   const className = useEdgeClassName(isConnecting, isDraggingWaypoint);
 
-  const sourceNode = RF.useStore((s) => s.nodeInternals.get(props.source)!);
-  const targetNode = RF.useStore((s) => s.nodeInternals.get(props.target)!);
-  useAlwaysVisibleEdgeUpdatersAtNodeBorders(interactionPathRef, sourceNode, targetNode, waypoints);
+  useAlwaysVisibleEdgeUpdatersAtNodeBorders(interactionPathRef, props.source, props.target, waypoints);
 
   return (
     <>
@@ -311,6 +309,7 @@ export const AssociationEdge = React.memo((props: RF.EdgeProps<DmnDiagramEdgeDat
         onDoubleClick={onDoubleClick}
       />
       <AssociationPath d={path} className={`kie-dmn-editor--edge ${className}`} />
+
       {props.selected && !isConnecting && props.data?.dmnEdge && (
         <Waypoints
           edgeId={props.id}
@@ -322,4 +321,4 @@ export const AssociationEdge = React.memo((props: RF.EdgeProps<DmnDiagramEdgeDat
       {isHovered && potentialWaypoint && <PotentialWaypoint point={potentialWaypoint.point} />}
     </>
   );
-});
+}, propsHaveSameValuesDeep);
diff --git a/packages/dmn-editor/src/diagram/edges/Waypoints.tsx b/packages/dmn-editor/src/diagram/edges/Waypoints.tsx
index eba58d37035..ec3f318c001 100644
--- a/packages/dmn-editor/src/diagram/edges/Waypoints.tsx
+++ b/packages/dmn-editor/src/diagram/edges/Waypoints.tsx
@@ -20,7 +20,7 @@
 import * as React from "react";
 import { DC__Point } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { deleteEdgeWaypoint } from "../../mutations/deleteEdgeWaypoint";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../../store/StoreContext";
 import { drag } from "d3-drag";
 import { select } from "d3-selection";
 import { useEffect } from "react";
@@ -79,7 +79,7 @@ export function Waypoint({
     const selection = select(circleRef.current);
     const dragHandler = drag<SVGCircleElement, unknown>()
       .on("start", () => {
-        setState((state) => dispatch.diagram.setEdgeStatus(state, edgeId, { draggingWaypoint: true }));
+        setState((state) => state.dispatch(state).diagram.setEdgeStatus(edgeId, { draggingWaypoint: true }));
       })
       .on("drag", (e) => {
         setState((state) => {
@@ -94,14 +94,14 @@ export function Waypoint({
       })
       .on("end", (e) => {
         onDragStop(e.sourceEvent);
-        setState((state) => dispatch.diagram.setEdgeStatus(state, edgeId, { draggingWaypoint: false }));
+        setState((state) => state.dispatch(state).diagram.setEdgeStatus(edgeId, { draggingWaypoint: false }));
       });
 
     selection.call(dragHandler);
     return () => {
       selection.on(".drag", null);
     };
-  }, [diagram.drdIndex, diagram.snapGrid, dispatch.diagram, edgeId, edgeIndex, index, onDragStop, setState]);
+  }, [diagram.drdIndex, diagram.snapGrid, edgeId, edgeIndex, index, onDragStop, setState]);
 
   return (
     <circle
diff --git a/packages/dmn-editor/src/diagram/edges/getSnappedMultiPointAnchoredEdgePath.tsx b/packages/dmn-editor/src/diagram/edges/getSnappedMultiPointAnchoredEdgePath.tsx
index 1c36bbcb58a..a1540c58adc 100644
--- a/packages/dmn-editor/src/diagram/edges/getSnappedMultiPointAnchoredEdgePath.tsx
+++ b/packages/dmn-editor/src/diagram/edges/getSnappedMultiPointAnchoredEdgePath.tsx
@@ -26,38 +26,34 @@ import * as RF from "reactflow";
 import { switchExpression } from "@kie-tools-core/switch-expression-ts";
 import { snapPoint } from "../SnapGrid";
 import { PositionalNodeHandleId } from "../connections/PositionalNodeHandles";
-import {
-  getLineRectangleIntersectionPoint,
-  getHandlePosition,
-  getNodeCenterPoint,
-  pointsToPath,
-} from "../maths/DmnMaths";
-import { getDiscretelyAutoPositionedEdgeParamsForRfNodes } from "../maths/Maths";
+import { getLineRectangleIntersectionPoint, getHandlePosition, pointsToPath } from "../maths/DmnMaths";
+import { getBoundsCenterPoint } from "../maths/Maths";
+import { Bounds, getDiscretelyAutoPositionedEdgeParams } from "../maths/Maths";
 import { AutoPositionedEdgeMarker } from "./AutoPositionedEdgeMarker";
 import { SnapGrid } from "../../store/Store";
 
 export function getSnappedMultiPointAnchoredEdgePath({
   snapGrid,
   dmnEdge,
-  sourceNode,
-  targetNode,
+  sourceNodeBounds,
+  targetNodeBounds,
   dmnShapeSource,
   dmnShapeTarget,
 }: {
   snapGrid: SnapGrid;
   dmnEdge: DMNDI15__DMNEdge | undefined;
-  sourceNode: RF.Node<any, string | undefined> | undefined;
-  targetNode: RF.Node<any, string | undefined> | undefined;
+  sourceNodeBounds: Bounds | undefined;
+  targetNodeBounds: Bounds | undefined;
   dmnShapeSource: DMNDI15__DMNShape | undefined;
   dmnShapeTarget: DMNDI15__DMNShape | undefined;
 }) {
-  if (!sourceNode || !targetNode) {
+  if (!sourceNodeBounds || !targetNodeBounds) {
     return { path: undefined, points: [] };
   }
 
   const points: DC__Point[] = new Array(Math.max(2, dmnEdge?.["di:waypoint"]?.length ?? 0));
 
-  const discreteAuto = getDiscretelyAutoPositionedEdgeParamsForRfNodes(sourceNode, targetNode);
+  const discreteAuto = getDiscretelyAutoPositionedEdgeParams(sourceNodeBounds, targetNodeBounds);
 
   if (dmnEdge?.["@_id"]?.endsWith(AutoPositionedEdgeMarker.BOTH)) {
     points[0] = { "@_x": discreteAuto.sx, "@_y": discreteAuto.sy };
@@ -83,9 +79,9 @@ export function getSnappedMultiPointAnchoredEdgePath({
     const secondWaypoint = points[1] ?? dmnEdge["di:waypoint"][1];
     const sourceHandlePoint = getSnappedHandlePosition(
       dmnShapeSource!,
-      sourceNode,
+      sourceNodeBounds,
       firstWaypoint,
-      points.length === 2 ? getNodeCenterPoint(targetNode) : snapPoint(snapGrid, secondWaypoint)
+      points.length === 2 ? getBoundsCenterPoint(targetNodeBounds) : snapPoint(snapGrid, secondWaypoint)
     );
     points[0] ??= sourceHandlePoint;
 
@@ -93,9 +89,9 @@ export function getSnappedMultiPointAnchoredEdgePath({
     const secondToLastWaypoint = points[points.length - 2] ?? dmnEdge["di:waypoint"][dmnEdge["di:waypoint"].length - 2];
     const targetHandlePoint = getSnappedHandlePosition(
       dmnShapeTarget!,
-      targetNode,
+      targetNodeBounds,
       lastWaypoint,
-      points.length === 2 ? getNodeCenterPoint(sourceNode) : snapPoint(snapGrid, secondToLastWaypoint)
+      points.length === 2 ? getBoundsCenterPoint(sourceNodeBounds) : snapPoint(snapGrid, secondToLastWaypoint)
     );
     points[points.length - 1] ??= targetHandlePoint;
   }
@@ -112,17 +108,17 @@ export function getSnappedMultiPointAnchoredEdgePath({
 
 export function getSnappedHandlePosition(
   shape: DMNDI15__DMNShape,
-  snappedNode: RF.Node,
+  snappedNode: Bounds,
   originalHandleWaypoint: DC__Point,
   snappedSecondWaypoint: DC__Point
 ): DC__Point {
   const { handlePosition } = getHandlePosition({ shapeBounds: shape["dc:Bounds"], waypoint: originalHandleWaypoint });
 
-  const centerHandleWaypoint = getNodeCenterPoint(snappedNode);
+  const centerHandleWaypoint = getBoundsCenterPoint(snappedNode);
 
   const nodeRectangle = {
-    x: snappedNode.positionAbsolute?.x ?? 0,
-    y: snappedNode.positionAbsolute?.y ?? 0,
+    x: snappedNode.x ?? 0,
+    y: snappedNode.y ?? 0,
     width: snappedNode.width ?? 0,
     height: snappedNode.height ?? 0,
   };
diff --git a/packages/dmn-editor/src/diagram/edges/useAlwaysVisibleEdgeUpdatersAtNodeBorders.ts b/packages/dmn-editor/src/diagram/edges/useAlwaysVisibleEdgeUpdatersAtNodeBorders.ts
index 606451f2e7a..883dcf6d75c 100644
--- a/packages/dmn-editor/src/diagram/edges/useAlwaysVisibleEdgeUpdatersAtNodeBorders.ts
+++ b/packages/dmn-editor/src/diagram/edges/useAlwaysVisibleEdgeUpdatersAtNodeBorders.ts
@@ -28,10 +28,20 @@ const HOVERED_RADIUS = 10;
 
 export function useAlwaysVisibleEdgeUpdatersAtNodeBorders(
   interactionPathRef: React.RefObject<SVGPathElement>,
-  sourceNode: RF.Node,
-  targetNode: RF.Node,
+  source: string,
+  target: string,
   snappedWaypoints: DC__Point[]
 ) {
+  const sourceNodeX = RF.useStore((s) => (source ? s.nodeInternals.get(source)?.positionAbsolute?.x : undefined));
+  const sourceNodeY = RF.useStore((s) => (source ? s.nodeInternals.get(source)?.positionAbsolute?.y : undefined));
+  const sourceNodeWidth = RF.useStore((s) => (source ? s.nodeInternals.get(source)?.width : undefined));
+  const sourceNodeHeight = RF.useStore((s) => (source ? s.nodeInternals.get(source)?.height : undefined));
+
+  const targetNodeX = RF.useStore((s) => (target ? s.nodeInternals.get(target)?.positionAbsolute?.x : undefined));
+  const targetNodeY = RF.useStore((s) => (target ? s.nodeInternals.get(target)?.positionAbsolute?.y : undefined));
+  const targetNodeWidth = RF.useStore((s) => (target ? s.nodeInternals.get(target)?.width : undefined));
+  const targetNodeHeight = RF.useStore((s) => (target ? s.nodeInternals.get(target)?.height : undefined));
+
   useLayoutEffect(() => {
     const edgeSvgGroup = interactionPathRef.current!.parentElement;
 
@@ -56,19 +66,19 @@ export function useAlwaysVisibleEdgeUpdatersAtNodeBorders(
       edgeUpdaterTarget?.removeEventListener("mouseleave", onLeave);
       edgeUpdaterTarget?.removeEventListener("mouseenter", onEnter);
     };
-  }, [interactionPathRef, sourceNode, targetNode, snappedWaypoints]);
+  }, [interactionPathRef]);
 
   useLayoutEffect(() => {
     const edgeSvgGroup = interactionPathRef.current!.parentElement;
 
     // Get fake scaled bounds to give the Edge Updaters some distance of the node.
     const scaledSourceNode = scaleFromCenter(HOVERED_RADIUS, {
-      position: sourceNode.positionAbsolute,
-      dimensions: sourceNode,
+      position: { x: sourceNodeX ?? 0, y: sourceNodeY ?? 0 },
+      dimensions: { width: sourceNodeWidth, height: sourceNodeHeight },
     });
     const scaledTargetNode = scaleFromCenter(HOVERED_RADIUS, {
-      position: targetNode.positionAbsolute,
-      dimensions: targetNode,
+      position: { x: targetNodeX ?? 0, y: targetNodeY ?? 0 },
+      dimensions: { width: targetNodeWidth, height: targetNodeHeight },
     });
 
     // Get the intersection point between the edge and the nodes. The Edge Updater must be visible at all times!
@@ -106,5 +116,16 @@ export function useAlwaysVisibleEdgeUpdatersAtNodeBorders(
     edgeUpdaterTarget.setAttribute("cx", "" + targetPoint!["@_x"]);
     edgeUpdaterTarget.setAttribute("cy", "" + targetPoint!["@_y"]);
     edgeUpdaterTarget.setAttribute("r", `${RADIUS}`);
-  }, [interactionPathRef, sourceNode, targetNode, snappedWaypoints]);
+  }, [
+    interactionPathRef,
+    snappedWaypoints,
+    sourceNodeHeight,
+    sourceNodeWidth,
+    sourceNodeX,
+    sourceNodeY,
+    targetNodeHeight,
+    targetNodeWidth,
+    targetNodeX,
+    targetNodeY,
+  ]);
 }
diff --git a/packages/dmn-editor/src/diagram/edges/useKieEdgePath.tsx b/packages/dmn-editor/src/diagram/edges/useKieEdgePath.tsx
index 9ee59487744..d9212f9fd31 100644
--- a/packages/dmn-editor/src/diagram/edges/useKieEdgePath.tsx
+++ b/packages/dmn-editor/src/diagram/edges/useKieEdgePath.tsx
@@ -17,24 +17,29 @@
  * under the License.
  */
 
+import { useMemo } from "react";
 import * as RF from "reactflow";
-import { useCallback, useMemo } from "react";
-import { getSnappedMultiPointAnchoredEdgePath } from "./getSnappedMultiPointAnchoredEdgePath";
-import { useDmnEditorStore } from "../../store/Store";
+import { useDmnEditorStore } from "../../store/StoreContext";
 import { DmnDiagramEdgeData } from "./Edges";
+import { getSnappedMultiPointAnchoredEdgePath } from "./getSnappedMultiPointAnchoredEdgePath";
 
 export function useKieEdgePath(
   source: string | undefined,
   target: string | undefined,
   data: DmnDiagramEdgeData | undefined
 ) {
-  const diagram = useDmnEditorStore((s) => s.diagram);
-  const sourceNode = RF.useStore(
-    useCallback((store) => (source ? store.nodeInternals.get(source) : undefined), [source])
-  );
-  const targetNode = RF.useStore(
-    useCallback((store) => (target ? store.nodeInternals.get(target) : undefined), [target])
-  );
+  const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+
+  const sourceNodeX = RF.useStore((s) => (source ? s.nodeInternals.get(source)?.positionAbsolute?.x : undefined));
+  const sourceNodeY = RF.useStore((s) => (source ? s.nodeInternals.get(source)?.positionAbsolute?.y : undefined));
+  const sourceNodeWidth = RF.useStore((s) => (source ? s.nodeInternals.get(source)?.width : undefined));
+  const sourceNodeHeight = RF.useStore((s) => (source ? s.nodeInternals.get(source)?.height : undefined));
+
+  const targetNodeX = RF.useStore((s) => (target ? s.nodeInternals.get(target)?.positionAbsolute?.x : undefined));
+  const targetNodeY = RF.useStore((s) => (target ? s.nodeInternals.get(target)?.positionAbsolute?.y : undefined));
+  const targetNodeWidth = RF.useStore((s) => (target ? s.nodeInternals.get(target)?.width : undefined));
+  const targetNodeHeight = RF.useStore((s) => (target ? s.nodeInternals.get(target)?.height : undefined));
+
   const dmnEdge = data?.dmnEdge;
   const dmnShapeSource = data?.dmnShapeSource;
   const dmnShapeTarget = data?.dmnShapeTarget;
@@ -42,13 +47,26 @@ export function useKieEdgePath(
   return useMemo(
     () =>
       getSnappedMultiPointAnchoredEdgePath({
-        snapGrid: diagram.snapGrid,
+        snapGrid,
         dmnEdge,
-        sourceNode,
-        targetNode,
+        sourceNodeBounds: { x: sourceNodeX, y: sourceNodeY, width: sourceNodeWidth, height: sourceNodeHeight },
+        targetNodeBounds: { x: targetNodeX, y: targetNodeY, width: targetNodeWidth, height: targetNodeHeight },
         dmnShapeSource,
         dmnShapeTarget,
       }),
-    [diagram.snapGrid, dmnEdge, dmnShapeSource, dmnShapeTarget, sourceNode, targetNode]
+    [
+      dmnEdge,
+      dmnShapeSource,
+      dmnShapeTarget,
+      snapGrid,
+      sourceNodeHeight,
+      sourceNodeWidth,
+      sourceNodeX,
+      sourceNodeY,
+      targetNodeHeight,
+      targetNodeWidth,
+      targetNodeX,
+      targetNodeY,
+    ]
   );
 }
diff --git a/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts b/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts
index 6e77aa97007..4106ae35051 100644
--- a/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts
+++ b/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts
@@ -20,7 +20,7 @@
 import * as RF from "reactflow";
 import { useState, useCallback, useMemo } from "react";
 import { addEdgeWaypoint } from "../../mutations/addEdgeWaypoint";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../../store/StoreContext";
 import { snapPoint } from "../SnapGrid";
 import { DC__Point } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { DmnDiagramNodeData } from "../nodes/Nodes";
@@ -33,7 +33,9 @@ export function usePotentialWaypointControls(
   edgeIndex: number | undefined,
   interactionPathRef: React.RefObject<SVGPathElement>
 ) {
-  const diagram = useDmnEditorStore((s) => s.diagram);
+  const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+  const drdIndex = useDmnEditorStore((s) => s.diagram.drdIndex);
+  const isDraggingWaypoint = useDmnEditorStore((s) => !!s.diagram.draggingWaypoints.find((e) => e === edgeId));
   const dmnEditorStoreApi = useDmnEditorStoreApi();
   const reactFlowInstance = RF.useReactFlow<DmnDiagramNodeData, DmnDiagramEdgeData>();
 
@@ -65,11 +67,11 @@ export function usePotentialWaypointControls(
       return undefined;
     }
 
-    return snapPoint(diagram.snapGrid, {
+    return snapPoint(snapGrid, {
       "@_x": potentialWaypoint.point.x,
       "@_y": potentialWaypoint.point.y,
     });
-  }, [diagram.snapGrid, potentialWaypoint]);
+  }, [snapGrid, potentialWaypoint]);
 
   const onDoubleClick = useCallback(() => {
     if (!potentialWaypoint || !snappedPotentialWaypoint || edgeIndex === undefined) {
@@ -96,14 +98,14 @@ export function usePotentialWaypointControls(
     dmnEditorStoreApi.setState((state) => {
       addEdgeWaypoint({
         definitions: state.dmn.model.definitions,
-        drdIndex: diagram.drdIndex,
+        drdIndex,
         beforeIndex: i - 1,
         edgeIndex,
         waypoint: snappedPotentialWaypoint,
       });
     });
   }, [
-    diagram.drdIndex,
+    drdIndex,
     dmnEditorStoreApi,
     edgeIndex,
     isExistingWaypoint,
@@ -112,8 +114,6 @@ export function usePotentialWaypointControls(
     waypoints,
   ]);
 
-  const isDraggingWaypoint = !!diagram.draggingWaypoints.find((e) => e === edgeId);
-
   const shouldReturnPotentialWaypoint =
     isEdgeSelected &&
     !isDraggingWaypoint &&
diff --git a/packages/dmn-editor/src/diagram/graph/graph.ts b/packages/dmn-editor/src/diagram/graph/graph.ts
index 0a7976c3d2d..eff1914b59a 100644
--- a/packages/dmn-editor/src/diagram/graph/graph.ts
+++ b/packages/dmn-editor/src/diagram/graph/graph.ts
@@ -17,29 +17,42 @@
  * under the License.
  */
 
-import * as RF from "reactflow";
-import { DmnDiagramEdgeData } from "../edges/Edges";
+import { DMN15__tDefinitions } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { Unpacked } from "../../tsExt/tsExt";
 
 export type AdjMatrix = Record<
   string,
-  undefined | Record<string, undefined | { direction: HierarchyDirection; edge: RF.Edge }>
+  undefined | Record<string, undefined | { direction: HierarchyDirection; edge: DrgEdge }>
 >;
 
 export type HierarchyDirection = "up" | "down";
 
-export function getAdjMatrix(edges: RF.Edge<any>[]): AdjMatrix {
+export type DrgEdge = {
+  sourceId: string;
+  targetId: string;
+  id: string;
+  dmnObject: {
+    namespace: string;
+    id: string;
+    type: Unpacked<DMN15__tDefinitions["artifact" | "drgElement"]>["__$$element"];
+    requirementType: "informationRequirement" | "knowledgeRequirement" | "authorityRequirement" | "association";
+    index: number;
+  };
+};
+
+export function getAdjMatrix(edges: DrgEdge[]): AdjMatrix {
   const __adjMatrix: AdjMatrix = {};
   for (const e of edges) {
-    __adjMatrix[e.source] ??= {};
-    __adjMatrix[e.target] ??= {};
-    __adjMatrix[e.source]![e.target] = { direction: "up", edge: e };
-    __adjMatrix[e.target]![e.source] = { direction: "down", edge: e };
+    __adjMatrix[e.sourceId] ??= {};
+    __adjMatrix[e.targetId] ??= {};
+    __adjMatrix[e.sourceId]![e.targetId] = { direction: "up", edge: e };
+    __adjMatrix[e.targetId]![e.sourceId] = { direction: "down", edge: e };
   }
   return __adjMatrix;
 }
 
 export type NodeVisitor = (nodeId: string, traversalDirection: HierarchyDirection) => void;
-export type EdgeVisitor = (edge: RF.Edge<DmnDiagramEdgeData>, traversalDirection: HierarchyDirection) => void;
+export type EdgeVisitor = (edge: DrgEdge, traversalDirection: HierarchyDirection) => void;
 
 export function traverse(
   __adjMatrix: AdjMatrix,
@@ -74,7 +87,7 @@ export function traverse(
       visited.add(curNodeId);
 
       // Only paint edges if at least one of the endpoints is not selected.
-      if (!(originalStartingNodeIds.has(edge.source) && originalStartingNodeIds.has(edge.target))) {
+      if (!(originalStartingNodeIds.has(edge.sourceId) && originalStartingNodeIds.has(edge.targetId))) {
         edgeVisitor?.(edge, traversalDirection);
       }
 
@@ -85,13 +98,7 @@ export function traverse(
   traverse(__adjMatrix, originalStartingNodeIds, nextNodeIds, traversalDirection, nodeVisitor, edgeVisitor, visited);
 }
 
-export function buildHierarchy({
-  nodeId,
-  edges,
-}: {
-  nodeId: string | undefined | null;
-  edges: RF.Edge<DmnDiagramEdgeData>[];
-}) {
+export function buildHierarchy({ nodeId, edges }: { nodeId: string | undefined | null; edges: DrgEdge[] }) {
   if (!nodeId) {
     return { dependencies: new Set<string>(), dependents: new Set<string>() };
   }
diff --git a/packages/dmn-editor/src/diagram/maths/DmnMaths.ts b/packages/dmn-editor/src/diagram/maths/DmnMaths.ts
index 5e965c0a7db..39846e985a2 100644
--- a/packages/dmn-editor/src/diagram/maths/DmnMaths.ts
+++ b/packages/dmn-editor/src/diagram/maths/DmnMaths.ts
@@ -24,15 +24,13 @@ import {
   DC__Point,
   DMNDI15__DMNShape,
 } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
-import * as RF from "reactflow";
+import { SnapGrid } from "../../store/Store";
+import { snapBoundsDimensions, snapBoundsPosition } from "../SnapGrid";
 import { PositionalNodeHandleId } from "../connections/PositionalNodeHandles";
 import { AutoPositionedEdgeMarker } from "../edges/AutoPositionedEdgeMarker";
 import { NODE_TYPES } from "../nodes/NodeTypes";
 import { NodeDmnObjects } from "../nodes/Nodes";
 import { getCenter } from "./Maths";
-import { SnapGrid } from "../../store/Store";
-import { snapBoundsDimensions, snapBoundsPosition, snapShapePosition } from "../SnapGrid";
-import { MIN_NODE_SIZES } from "../nodes/DefaultSizes";
 
 export const DEFAULT_INTRACTION_WIDTH = 40;
 export const CONTAINER_NODES_DESIRABLE_PADDING = 60;
@@ -41,12 +39,7 @@ export function getDistance(a: DC__Point, b: DC__Point) {
   return Math.sqrt(Math.pow(a["@_x"] - b["@_x"], 2) + Math.pow(a["@_y"] - b["@_y"], 2));
 }
 
-export function getNodeCenterPoint(node: RF.Node | undefined): DC__Point {
-  const { x, y } = getCenter(node?.positionAbsolute?.x, node?.positionAbsolute?.y, node?.width, node?.height);
-  return { "@_x": x, "@_y": y };
-}
-
-export function getBoundsCenterPoint(bounds: DC__Bounds): DC__Point {
+export function getDmnBoundsCenterPoint(bounds: DC__Bounds): DC__Point {
   const { x, y } = getCenter(bounds["@_x"], bounds["@_y"], bounds["@_width"], bounds["@_height"]);
   return { "@_x": x, "@_y": y };
 }
@@ -59,7 +52,7 @@ export function getPointForHandle({
   handle: PositionalNodeHandleId;
 }): DC__Point {
   if (handle === PositionalNodeHandleId.Center) {
-    return getBoundsCenterPoint(bounds);
+    return getDmnBoundsCenterPoint(bounds);
   } else if (handle === PositionalNodeHandleId.Top) {
     return { "@_x": bounds["@_x"] + bounds["@_width"] / 2, "@_y": bounds["@_y"] };
   } else if (handle === PositionalNodeHandleId.Right) {
@@ -209,7 +202,7 @@ export function getContainmentRelationship({
   const { x: bx, y: by } = snapBoundsPosition(snapGrid, bounds);
   const { width: bw, height: bh } = snapBoundsDimensions(snapGrid, bounds, boundsMinSizes(snapGrid));
 
-  const center = getBoundsCenterPoint({
+  const center = getDmnBoundsCenterPoint({
     "@_height": bh,
     "@_width": bw,
     "@_x": bx,
diff --git a/packages/dmn-editor/src/diagram/maths/Maths.ts b/packages/dmn-editor/src/diagram/maths/Maths.ts
index 11120d012fe..10e608608d0 100644
--- a/packages/dmn-editor/src/diagram/maths/Maths.ts
+++ b/packages/dmn-editor/src/diagram/maths/Maths.ts
@@ -17,39 +17,24 @@
  * under the License.
  */
 
+import { DC__Point } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import * as RF from "reactflow";
 
-export type Shape = {
+export type Bounds = {
   width: number | undefined | null;
   height: number | undefined | null;
   x: number | undefined | null;
   y: number | undefined | null;
 };
 
-// returns the parameters (sx, sy, tx, ty, sourcePos, targetPos) you need to create an edge
-export function getDiscretelyAutoPositionedEdgeParamsForRfNodes(source: RF.Node, target: RF.Node) {
-  const src = {
-    x: source.positionAbsolute?.x,
-    y: source.positionAbsolute?.y,
-    width: source.width,
-    height: source.height,
-  };
-  const tgt = {
-    x: target.positionAbsolute?.x,
-    y: target.positionAbsolute?.y,
-    width: target.width,
-    height: target.height,
-  };
-  return getDiscretelyAutoPositionedEdgeParams(src, tgt);
-}
-
-export function getDiscretelyAutoPositionedEdgeParams(src: Shape, tgt: Shape) {
+export function getDiscretelyAutoPositionedEdgeParams(src: Bounds, tgt: Bounds) {
   const [sx, sy, sourcePos] = getPositionalHandlePosition(src, tgt);
   const [tx, ty, targetPos] = getPositionalHandlePosition(tgt, src);
   return { sx, sy, tx, ty, sourcePos, targetPos };
 }
+
 // returns the position (top, right, bottom, or right) passed node compared to
-export function getPositionalHandlePosition(a: Shape, b: Shape) {
+export function getPositionalHandlePosition(a: Bounds, b: Bounds) {
   const centerA = getCenter(a.x, a.y, a.width, a.height);
   const centerB = getCenter(b.x, b.y, b.width, b.height);
 
@@ -101,7 +86,7 @@ export function scaleFromCenter(
   };
 }
 
-function getHandleCoordsByPosition(node: Shape, handlePosition: RF.Position) {
+function getHandleCoordsByPosition(node: Bounds, handlePosition: RF.Position) {
   let handleX = 0;
   let handleY = 0;
 
@@ -126,3 +111,7 @@ function getHandleCoordsByPosition(node: Shape, handlePosition: RF.Position) {
 
   return [(node?.x ?? 0) + handleX, (node?.y ?? 0) + handleY];
 }
+export function getBoundsCenterPoint(node: Bounds | undefined): DC__Point {
+  const { x, y } = getCenter(node?.x, node?.y, node?.width, node?.height);
+  return { "@_x": x, "@_y": y };
+}
diff --git a/packages/dmn-editor/src/focus/useFocusableElement.ts b/packages/dmn-editor/src/diagram/memoization/memoization.ts
similarity index 52%
copy from packages/dmn-editor/src/focus/useFocusableElement.ts
copy to packages/dmn-editor/src/diagram/memoization/memoization.ts
index d4b0823497b..1b94827254e 100644
--- a/packages/dmn-editor/src/focus/useFocusableElement.ts
+++ b/packages/dmn-editor/src/diagram/memoization/memoization.ts
@@ -17,32 +17,11 @@
  * under the License.
  */
 
-import { useEffect } from "react";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import fastDeepEqual from "fast-deep-equal";
 
-export function useFocusableElement(
-  ref: React.RefObject<HTMLInputElement>,
-  id: string | undefined,
-  before?: (cb: () => void) => void
-) {
-  const focus = useDmnEditorStore((s) => s.focus);
-  const dmnEditorStoreApi = useDmnEditorStoreApi();
-
-  useEffect(() => {
-    if (!id) {
-      return;
-    }
-
-    const cb = () => {
-      ref.current?.select();
-
-      dmnEditorStoreApi.setState((state) => {
-        state.focus.consumableId = undefined;
-      });
-    };
-
-    if (focus.consumableId === id && ref.current) {
-      before?.(cb) ?? cb();
-    }
-  }, [before, dmnEditorStoreApi, focus.consumableId, id, ref]);
-}
+/**
+ * This function is the reason why nodes and edges are memoized. Without it, the prev and next objects are compared as
+ * references, and they'll always be different, resulting in every node and edge re-rendering for every change. By
+ * comparing the values inside the objects, we avoid re-rendering unnecessarily.
+ */
+export const propsHaveSameValuesDeep = fastDeepEqual;
diff --git a/packages/dmn-editor/src/diagram/nodes/DataTypeNodePanel.tsx b/packages/dmn-editor/src/diagram/nodes/DataTypeNodePanel.tsx
index 428fbd43ed8..1ce71e28e05 100644
--- a/packages/dmn-editor/src/diagram/nodes/DataTypeNodePanel.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/DataTypeNodePanel.tsx
@@ -23,7 +23,7 @@ import {
   DMNDI15__DMNShape,
 } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { DmnBuiltInDataType } from "@kie-tools/boxed-expression-component/dist/api";
-import { useDmnEditorStore } from "../../store/Store";
+import { useDmnEditorStore } from "../../store/StoreContext";
 import { OnCreateDataType, OnTypeRefChange, TypeRefSelector } from "../../dataTypes/TypeRefSelector";
 import { useDmnEditor } from "../../DmnEditorContext";
 import { useResolvedTypeRef } from "../../dataTypes/useResolvedTypeRef";
@@ -38,20 +38,22 @@ export function DataTypeNodePanel(props: {
   shape: DMNDI15__DMNShape | undefined;
   onChange: OnTypeRefChange;
   onCreate?: OnCreateDataType;
-  namespace: string | undefined;
+  dmnObjectNamespace: string | undefined;
 }) {
-  const diagram = useDmnEditorStore((s) => s.diagram);
+  const enableDataTypesToolbarOnNodes = useDmnEditorStore((s) => s.diagram.overlays.enableDataTypesToolbarOnNodes);
 
   const { dmnEditorRootElementRef } = useDmnEditor();
 
   const resolvedTypeRef = useResolvedTypeRef(
     props.variable?.["@_typeRef"] ?? DmnBuiltInDataType.Undefined,
-    props.namespace
+    props.dmnObjectNamespace
   );
 
+  const isExternalNode = !!props.dmnObjectNamespace;
+
   return (
     <>
-      {props.isVisible && diagram.overlays.enableDataTypesToolbarOnNodes && (
+      {props.isVisible && enableDataTypesToolbarOnNodes && (
         <div
           className={"kie-dmn-editor--data-type-node-panel"}
           // Do not allow any events to go to the node itself...
@@ -61,7 +63,7 @@ export function DataTypeNodePanel(props: {
           onDoubleClick={stopPropagation}
           onMouseLeave={stopPropagation}
         >
-          <div>
+          <div style={{ background: isExternalNode ? "rgb(240, 240, 240)" : undefined }}>
             <TypeRefSelector
               zoom={0.8}
               heightRef={dmnEditorRootElementRef}
@@ -69,6 +71,7 @@ export function DataTypeNodePanel(props: {
               onChange={props.onChange}
               onCreate={props.onCreate}
               menuAppendTo={"parent"}
+              isDisabled={isExternalNode}
             />
           </div>
         </div>
diff --git a/packages/dmn-editor/src/diagram/nodes/EditExpressionNodePanel.tsx b/packages/dmn-editor/src/diagram/nodes/EditExpressionNodePanel.tsx
index 7de7bc3cc69..1dc64147e0f 100644
--- a/packages/dmn-editor/src/diagram/nodes/EditExpressionNodePanel.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/EditExpressionNodePanel.tsx
@@ -19,10 +19,9 @@
 
 import * as React from "react";
 import { Label } from "@patternfly/react-core/dist/js/components/Label";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../../store/Store";
+import { useDmnEditorStoreApi } from "../../store/StoreContext";
 
 export function EditExpressionNodePanel(props: { isVisible: boolean; id: string }) {
-  const dispatch = useDmnEditorStore((s) => s.dispatch);
   const dmnEditorStoreApi = useDmnEditorStoreApi();
 
   return (
@@ -31,7 +30,7 @@ export function EditExpressionNodePanel(props: { isVisible: boolean; id: string
         <Label
           onClick={() =>
             dmnEditorStoreApi.setState((state) => {
-              dispatch.boxedExpressionEditor.open(state, props.id);
+              state.dispatch(state).boxedExpressionEditor.open(props.id);
             })
           }
           className={"kie-dmn-editor--edit-expression-node-panel"}
diff --git a/packages/dmn-editor/src/diagram/nodes/EditableNodeLabel.tsx b/packages/dmn-editor/src/diagram/nodes/EditableNodeLabel.tsx
index ffd5a9d4663..2503ce966f7 100644
--- a/packages/dmn-editor/src/diagram/nodes/EditableNodeLabel.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/EditableNodeLabel.tsx
@@ -21,8 +21,7 @@ import * as React from "react";
 import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
 import { EmptyLabel } from "./Nodes";
 import { XmlQName } from "@kie-tools/xml-parser-ts/dist/qNames";
-import { useDmnEditorStore } from "../../store/Store";
-import { useDmnEditorDerivedStore } from "../../store/DerivedStore";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../../store/StoreContext";
 import { UniqueNameIndex } from "../../Dmn15Spec";
 import { buildFeelQNameFromXmlQName } from "../../feel/buildFeelQName";
 import { DMN15__tNamedElement } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
@@ -30,10 +29,11 @@ import { Truncate } from "@patternfly/react-core/dist/js/components/Truncate";
 import { DMN15_SPEC } from "../../Dmn15Spec";
 import { invalidInlineFeelNameStyle } from "../../feel/InlineFeelNameInput";
 import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
-import "./EditableNodeLabel.css";
 import { useFocusableElement } from "../../focus/useFocusableElement";
 import { flushSync } from "react-dom";
 import { NodeLabelPosition } from "./NodeSvgs";
+import "./EditableNodeLabel.css";
+import { State } from "../../store/Store";
 
 export type OnEditableNodeLabelChange = (value: string | undefined) => void;
 
@@ -50,8 +50,8 @@ export function EditableNodeLabel({
   grow,
   shouldCommitOnBlur,
   skipValidation,
-  allUniqueNames,
-  fontCssProperties: fontStyle,
+  onGetAllUniqueNames,
+  fontCssProperties,
 }: {
   id?: string;
   shouldCommitOnBlur?: boolean;
@@ -65,11 +65,28 @@ export function EditableNodeLabel({
   setEditing: React.Dispatch<React.SetStateAction<boolean>>;
   onChange: OnEditableNodeLabelChange;
   skipValidation?: boolean;
-  allUniqueNames: UniqueNameIndex;
+  onGetAllUniqueNames: (s: State) => UniqueNameIndex;
   fontCssProperties?: React.CSSProperties;
 }) {
-  const thisDmn = useDmnEditorStore((s) => s.dmn);
-  const { importsByNamespace } = useDmnEditorDerivedStore();
+  const displayValue = useDmnEditorStore((s) => {
+    if (!value) {
+      return undefined;
+    }
+
+    if (!namedElement || !namedElementQName) {
+      return value;
+    }
+
+    const feelName = buildFeelQNameFromXmlQName({
+      namedElement,
+      importsByNamespace: s.computed(s).importsByNamespace(),
+      model: s.dmn.model.definitions,
+      namedElementQName,
+      relativeToNamespace: s.dmn.model.definitions["@_namespace"],
+    });
+
+    return feelName.full;
+  });
 
   const isEditing = useMemo(() => {
     return !namedElementQName?.prefix && _isEditing; // Can't ever change the names of external nodes
@@ -87,26 +104,6 @@ export function EditableNodeLabel({
     [_setEditing, namedElementQName?.prefix]
   );
 
-  const displayValue = useMemo(() => {
-    if (!value) {
-      return undefined;
-    }
-
-    if (!namedElement || !namedElementQName) {
-      return value;
-    }
-
-    const feelName = buildFeelQNameFromXmlQName({
-      namedElement,
-      importsByNamespace,
-      model: thisDmn.model.definitions,
-      namedElementQName,
-      relativeToNamespace: thisDmn.model.definitions["@_namespace"],
-    });
-
-    return feelName.full;
-  }, [value, namedElement, namedElementQName, importsByNamespace, thisDmn.model.definitions]);
-
   const [internalValue, setInternalValue] = useState(displayValue);
   useEffect(() => {
     // Give `value` priority over `internalValue`, if it changes externally, we take that as the new `internalValue`.
@@ -130,13 +127,17 @@ export function EditableNodeLabel({
     }, 0);
   }, []);
 
-  const isValid = useMemo(() => {
+  const isValid = useDmnEditorStore((s) => {
     if (skipValidation) {
       return true;
     }
 
-    return DMN15_SPEC.namedElement.isValidName(namedElement?.["@_id"] ?? generateUuid(), internalValue, allUniqueNames);
-  }, [skipValidation, namedElement, internalValue, allUniqueNames]);
+    return DMN15_SPEC.namedElement.isValidName(
+      namedElement?.["@_id"] ?? generateUuid(),
+      internalValue,
+      onGetAllUniqueNames(s)
+    );
+  });
 
   const onBlur = useCallback(() => {
     setEditing(false);
@@ -218,7 +219,7 @@ export function EditableNodeLabel({
         <input
           spellCheck={"false"} // Let's not confuse FEEL name validation with the browser's grammar check.
           style={{
-            ...fontStyle,
+            ...fontCssProperties,
             ...(isValid ? {} : invalidInlineFeelNameStyle),
           }}
           onMouseDownCapture={(e) => e.stopPropagation()} // Make sure mouse events stay inside the node.
@@ -233,7 +234,7 @@ export function EditableNodeLabel({
         <span
           style={{
             whiteSpace: "pre-wrap",
-            ...fontStyle,
+            ...fontCssProperties,
             ...(isValid ? {} : invalidInlineFeelNameStyle),
           }}
         >
@@ -251,8 +252,12 @@ export function EditableNodeLabel({
 }
 
 export function useEditableNodeLabel(id: string | undefined) {
-  const focus = useDmnEditorStore((s) => s.focus);
-  const [isEditingLabel, setEditingLabel] = useState(!!id && !!focus.consumableId && focus.consumableId === id);
+  const dmnEditorStoreApi = useDmnEditorStoreApi();
+
+  const [isEditingLabel, setEditingLabel] = useState(
+    !!id && !!dmnEditorStoreApi.getState().focus.consumableId && dmnEditorStoreApi.getState().focus.consumableId === id
+  );
+
   const triggerEditing = useCallback<React.EventHandler<React.SyntheticEvent>>((e) => {
     e.stopPropagation();
     e.preventDefault();
@@ -269,5 +274,8 @@ export function useEditableNodeLabel(id: string | undefined) {
     [triggerEditing]
   );
 
-  return { isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter };
+  return useMemo(
+    () => ({ isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter }),
+    [isEditingLabel, triggerEditing, triggerEditingIfEnter]
+  );
 }
diff --git a/packages/dmn-editor/src/diagram/nodes/InfoNodePanel.tsx b/packages/dmn-editor/src/diagram/nodes/InfoNodePanel.tsx
index b857675261f..47e3c0bc22f 100644
--- a/packages/dmn-editor/src/diagram/nodes/InfoNodePanel.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/InfoNodePanel.tsx
@@ -20,7 +20,7 @@
 import * as React from "react";
 import { Label } from "@patternfly/react-core/dist/js/components/Label";
 import { InfoIcon } from "@patternfly/react-icons/dist/js/icons/info-icon";
-import { useDmnEditorStoreApi } from "../../store/Store";
+import { useDmnEditorStoreApi } from "../../store/StoreContext";
 
 export function InfoNodePanel(props: { isVisible: boolean }) {
   const dmnEditorStoreApi = useDmnEditorStoreApi();
diff --git a/packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx b/packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx
index 29e5baaf1b8..5fbc941da67 100644
--- a/packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx
@@ -229,7 +229,7 @@ export const DecisionServiceNodeSvg = React.forwardRef<
         width={width}
         height={height}
         strokeWidth={strokeWidth}
-        fill={isCollapsed ? DEFAULT_NODE_FILL : fillColor ?? "transparent"}
+        fill={fillColor ?? "transparent"}
         stroke={strokeColor ?? DEFAULT_NODE_STROKE_COLOR}
         strokeLinejoin={"round"}
         rx={"40"}
@@ -360,7 +360,7 @@ export const GroupNodeSvg = React.forwardRef<SVGRectElement, NodeSvgProps & { st
   }
 );
 
-export const UnknownNodeSvg = (_props: NodeSvgProps & { strokeDasharray?: string }) => {
+export function UnknownNodeSvg(_props: NodeSvgProps & { strokeDasharray?: string }) {
   const { strokeWidth, x, y, width, height, props } = normalize(_props);
   const strokeDasharray = props.strokeDasharray ?? "2,4";
   return (
@@ -379,7 +379,7 @@ export const UnknownNodeSvg = (_props: NodeSvgProps & { strokeDasharray?: string
       />
     </>
   );
-};
+}
 
 function NodeCollectionMarker(__props: NodeSvgProps & { anchor: "top" | "bottom" }) {
   const { strokeWidth, x, y, width, height, fillColor, strokeColor, props } = normalize(__props);
diff --git a/packages/dmn-editor/src/diagram/nodes/Nodes.tsx b/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
index 1082f3aa905..09174032ce6 100644
--- a/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
@@ -17,6 +17,7 @@
  * under the License.
  */
 
+import { DmnBuiltInDataType } from "@kie-tools/boxed-expression-component/dist/api";
 import {
   DMN15__tBusinessKnowledgeModel,
   DMN15__tDecision,
@@ -28,20 +29,32 @@ import {
   DMN15__tTextAnnotation,
   DMNDI15__DMNShape,
 } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { XmlQName } from "@kie-tools/xml-parser-ts/dist/qNames";
+import { drag } from "d3-drag";
+import { select } from "d3-selection";
 import * as React from "react";
 import { useCallback, useEffect, useMemo, useRef } from "react";
 import * as RF from "reactflow";
+import { OnCreateDataType, OnTypeRefChange } from "../../dataTypes/TypeRefSelector";
+import { addTopLevelItemDefinition } from "../../mutations/addTopLevelItemDefinition";
 import { renameDrgElement, renameGroupNode, updateTextAnnotation } from "../../mutations/renameNode";
-import { DmnEditorTab, DropTargetNode, SnapGrid, useDmnEditorStore, useDmnEditorStoreApi } from "../../store/Store";
+import { updateDecisionServiceDividerLine } from "../../mutations/updateDecisionServiceDividerLine";
+import { DmnEditorTab, SnapGrid, State } from "../../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../../store/StoreContext";
+import { Unpacked } from "../../tsExt/tsExt";
 import { snapShapeDimensions } from "../SnapGrid";
-import { DECISION_SERVICE_COLLAPSED_DIMENSIONS } from "./DefaultSizes";
 import { PositionalNodeHandles } from "../connections/PositionalNodeHandles";
 import { NodeType, containment, outgoingStructure } from "../connections/graphStructure";
 import { EDGE_TYPES } from "../edges/EdgeTypes";
+import { DmnDiagramEdgeData } from "../edges/Edges";
+import { getContainmentRelationship, getDecisionServiceDividerLineLocalY } from "../maths/DmnMaths";
+import { useIsHovered } from "../useIsHovered";
 import { DataTypeNodePanel } from "./DataTypeNodePanel";
+import { DECISION_SERVICE_COLLAPSED_DIMENSIONS, MIN_NODE_SIZES } from "./DefaultSizes";
 import { EditExpressionNodePanel } from "./EditExpressionNodePanel";
 import { EditableNodeLabel, OnEditableNodeLabelChange, useEditableNodeLabel } from "./EditableNodeLabel";
 import { InfoNodePanel } from "./InfoNodePanel";
+import { getNodeLabelPosition, useNodeStyle } from "./NodeStyle";
 import {
   BkmNodeSvg,
   DecisionNodeSvg,
@@ -54,20 +67,8 @@ import {
 } from "./NodeSvgs";
 import { NODE_TYPES } from "./NodeTypes";
 import { OutgoingStuffNodePanel } from "./OutgoingStuffNodePanel";
-import { useIsHovered } from "../useIsHovered";
-import { getContainmentRelationship, getDecisionServiceDividerLineLocalY } from "../maths/DmnMaths";
-import { useDmnEditorDerivedStore } from "../../store/DerivedStore";
-import { DmnDiagramEdgeData } from "../edges/Edges";
-import { XmlQName } from "@kie-tools/xml-parser-ts/dist/qNames";
-import { Unpacked } from "../../tsExt/tsExt";
-import { OnCreateDataType, OnTypeRefChange } from "../../dataTypes/TypeRefSelector";
-import { MIN_NODE_SIZES } from "./DefaultSizes";
-import { select } from "d3-selection";
-import { drag } from "d3-drag";
-import { updateDecisionServiceDividerLine } from "../../mutations/updateDecisionServiceDividerLine";
-import { addTopLevelItemDefinition } from "../../mutations/addTopLevelItemDefinition";
-import { DmnBuiltInDataType } from "@kie-tools/boxed-expression-component/dist/api";
-import { getNodeLabelPosition, useNodeStyle } from "./NodeStyle";
+import { propsHaveSameValuesDeep } from "../memoization/memoization";
+import { useExternalModels } from "../../includedModels/DmnEditorDependenciesContext";
 
 export type ElementFilter<E extends { __$$element: string }, Filter extends string> = E extends any
   ? E["__$$element"] extends Filter
@@ -103,23 +104,28 @@ export const InputDataNode = React.memo(
     type,
     id,
   }: RF.NodeProps<DmnDiagramNodeData<DMN15__tInputData & { __$$element: "inputData" }>>) => {
+    const renderCount = useRef<number>(0);
+    renderCount.current++;
+
     const ref = useRef<HTMLDivElement>(null);
     const isExternal = !!dmnObjectQName.prefix;
-    const isResizing = useNodeResizing(id);
-
-    const diagram = useDmnEditorStore((s) => s.diagram);
-    const isHovered = (useIsHovered(ref) || isResizing) && diagram.draggingNodes.length === 0;
 
-    const { isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter } = useEditableNodeLabel(
-      inputData["@_id"]
+    const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+    const enableCustomNodeStyles = useDmnEditorStore((s) => s.diagram.overlays.enableCustomNodeStyles);
+    const isHovered = useIsHovered(ref);
+    const isResizing = useNodeResizing(id);
+    const shouldActLikeHovered = useDmnEditorStore(
+      (s) => (isHovered || isResizing) && s.diagram.draggingNodes.length === 0
     );
-    useHoveredNodeAlwaysOnTop(ref, zIndex, isHovered, dragging, selected, isEditingLabel);
+
+    const { isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter } = useEditableNodeLabel(id);
+    useHoveredNodeAlwaysOnTop(ref, zIndex, shouldActLikeHovered, dragging, selected, isEditingLabel);
 
     const dmnEditorStoreApi = useDmnEditorStoreApi();
 
-    const { isTargeted, isValidConnectionTarget, isConnecting } = useConnectionTargetStatus(id, isHovered);
-    const className = useNodeClassName(diagram.dropTargetNode, isConnecting, isValidConnectionTarget, id);
-    const nodeDimensions = useNodeDimensions(type as NodeType, diagram.snapGrid, id, shape, isExternal);
+    const { isTargeted, isValidConnectionTarget } = useConnectionTargetStatus(id, shouldActLikeHovered);
+    const className = useNodeClassName(isValidConnectionTarget, id);
+    const nodeDimensions = useNodeDimensions(type as NodeType, snapGrid, shape, isExternal);
 
     const setName = useCallback<OnEditableNodeLabelChange>(
       (newName: string) => {
@@ -141,26 +147,34 @@ export const InputDataNode = React.memo(
       [dmnEditorStoreApi, index, inputData]
     );
 
-    const { allFeelVariableUniqueNames, allTopLevelItemDefinitionUniqueNames, allDataTypesById } =
-      useDmnEditorDerivedStore();
+    const getAllFeelVariableUniqueNames = useCallback((s: State) => s.computed(s).getAllFeelVariableUniqueNames(), []);
+
     const onCreateDataType = useDataTypeCreationCallbackForNodes(index, inputData["@_name"]);
 
     const { fontCssProperties, shapeStyle } = useNodeStyle({
       dmnStyle: shape["di:Style"],
       nodeType: type as NodeType,
-      isEnabled: diagram.overlays.enableStyles,
+      isEnabled: enableCustomNodeStyles,
     });
 
-    const isCollection = useMemo(() => {
+    const additionalClasses = `${className} ${dmnObjectQName.prefix ? "external" : ""}`;
+
+    const { externalModelsByNamespace } = useExternalModels();
+
+    const isCollection = useDmnEditorStore((s) => {
+      const { allDataTypesById, allTopLevelItemDefinitionUniqueNames } = s
+        .computed(s)
+        .getDataTypes(externalModelsByNamespace);
+
       return (
         allDataTypesById.get(allTopLevelItemDefinitionUniqueNames.get(inputData.variable?.["@_typeRef"] ?? "") ?? "")
           ?.itemDefinition?.["@_isCollection"] ?? false
       );
-    }, [allDataTypesById, allTopLevelItemDefinitionUniqueNames, inputData.variable]);
+    });
 
     return (
       <>
-        <svg className={`kie-dmn-editor--node-shape ${className} ${dmnObjectQName.prefix ? "external" : ""}`}>
+        <svg className={`kie-dmn-editor--node-shape ${additionalClasses}`}>
           <InputDataNodeSvg
             isCollection={isCollection}
             {...nodeDimensions}
@@ -174,17 +188,17 @@ export const InputDataNode = React.memo(
         <PositionalNodeHandles isTargeted={isTargeted && isValidConnectionTarget} nodeId={id} />
         <div
           ref={ref}
-          className={`kie-dmn-editor--node kie-dmn-editor--input-data-node ${className} ${
-            dmnObjectQName.prefix ? "external" : ""
-          }`}
+          className={`kie-dmn-editor--node kie-dmn-editor--input-data-node ${additionalClasses}`}
           tabIndex={-1}
           onDoubleClick={triggerEditing}
           onKeyDown={triggerEditingIfEnter}
         >
-          <InfoNodePanel isVisible={!isTargeted && isHovered} />
+          {/* {`render count: ${renderCount.current}`}
+          <br /> */}
+          <InfoNodePanel isVisible={!isTargeted && shouldActLikeHovered} />
 
           <OutgoingStuffNodePanel
-            isVisible={!isConnecting && !isTargeted && isHovered}
+            isVisible={!isTargeted && shouldActLikeHovered}
             nodeTypes={outgoingStructure[NODE_TYPES.inputData].nodes}
             edgeTypes={outgoingStructure[NODE_TYPES.inputData].edges}
           />
@@ -196,22 +210,22 @@ export const InputDataNode = React.memo(
             position={getNodeLabelPosition(type as NodeType)}
             value={inputData["@_label"] ?? inputData["@_name"]}
             onChange={setName}
-            allUniqueNames={allFeelVariableUniqueNames}
+            onGetAllUniqueNames={getAllFeelVariableUniqueNames}
             shouldCommitOnBlur={true}
             fontCssProperties={fontCssProperties}
           />
-          {isHovered && (
+          {shouldActLikeHovered && (
             <NodeResizerHandle
               nodeType={type as NodeType}
-              snapGrid={diagram.snapGrid}
+              snapGrid={snapGrid}
               nodeId={id}
               nodeShapeIndex={shape.index}
             />
           )}
           <DataTypeNodePanel
-            isVisible={!isTargeted && isHovered}
+            isVisible={!isTargeted && shouldActLikeHovered}
             variable={inputData.variable}
-            namespace={dmnObjectNamespace}
+            dmnObjectNamespace={dmnObjectNamespace}
             shape={shape}
             onCreate={onCreateDataType}
             onChange={onTypeRefChange}
@@ -219,7 +233,8 @@ export const InputDataNode = React.memo(
         </div>
       </>
     );
-  }
+  },
+  propsHaveSameValuesDeep
 );
 
 export const DecisionNode = React.memo(
@@ -231,23 +246,29 @@ export const DecisionNode = React.memo(
     type,
     id,
   }: RF.NodeProps<DmnDiagramNodeData<DMN15__tDecision & { __$$element: "decision" }>>) => {
+    const renderCount = useRef<number>(0);
+    renderCount.current++;
+
     const ref = useRef<HTMLDivElement>(null);
     const isExternal = !!dmnObjectQName.prefix;
-    const isResizing = useNodeResizing(id);
-
-    const diagram = useDmnEditorStore((s) => s.diagram);
-    const isHovered = (useIsHovered(ref) || isResizing) && diagram.draggingNodes.length === 0;
 
+    const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+    const enableCustomNodeStyles = useDmnEditorStore((s) => s.diagram.overlays.enableCustomNodeStyles);
+    const isHovered = useIsHovered(ref);
+    const isResizing = useNodeResizing(id);
+    const shouldActLikeHovered = useDmnEditorStore(
+      (s) => (isHovered || isResizing) && s.diagram.draggingNodes.length === 0
+    );
     const { isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter } = useEditableNodeLabel(
       decision["@_id"]
     );
-    useHoveredNodeAlwaysOnTop(ref, zIndex, isHovered, dragging, selected, isEditingLabel);
+    useHoveredNodeAlwaysOnTop(ref, zIndex, shouldActLikeHovered, dragging, selected, isEditingLabel);
 
     const dmnEditorStoreApi = useDmnEditorStoreApi();
 
-    const { isTargeted, isValidConnectionTarget, isConnecting } = useConnectionTargetStatus(id, isHovered);
-    const className = useNodeClassName(diagram.dropTargetNode, isConnecting, isValidConnectionTarget, id);
-    const nodeDimensions = useNodeDimensions(type as NodeType, diagram.snapGrid, id, shape, isExternal);
+    const { isTargeted, isValidConnectionTarget } = useConnectionTargetStatus(id, shouldActLikeHovered);
+    const className = useNodeClassName(isValidConnectionTarget, id);
+    const nodeDimensions = useNodeDimensions(type as NodeType, snapGrid, shape, isExternal);
     const setName = useCallback<OnEditableNodeLabelChange>(
       (newName: string) => {
         dmnEditorStoreApi.setState((state) => {
@@ -268,27 +289,34 @@ export const DecisionNode = React.memo(
       [decision, dmnEditorStoreApi, index]
     );
 
-    const { allFeelVariableUniqueNames, allTopLevelItemDefinitionUniqueNames, allDataTypesById } =
-      useDmnEditorDerivedStore();
+    const getAllFeelVariableUniqueNames = useCallback((s: State) => s.computed(s).getAllFeelVariableUniqueNames(), []);
 
     const onCreateDataType = useDataTypeCreationCallbackForNodes(index, decision["@_name"]);
 
     const { fontCssProperties, shapeStyle } = useNodeStyle({
       dmnStyle: shape["di:Style"],
       nodeType: type as NodeType,
-      isEnabled: diagram.overlays.enableStyles,
+      isEnabled: enableCustomNodeStyles,
     });
 
-    const isCollection = useMemo(() => {
+    const additionalClasses = `${className} ${dmnObjectQName.prefix ? "external" : ""}`;
+
+    const { externalModelsByNamespace } = useExternalModels();
+
+    const isCollection = useDmnEditorStore((s) => {
+      const { allDataTypesById, allTopLevelItemDefinitionUniqueNames } = s
+        .computed(s)
+        .getDataTypes(externalModelsByNamespace);
+
       return (
         allDataTypesById.get(allTopLevelItemDefinitionUniqueNames.get(decision.variable?.["@_typeRef"] ?? "") ?? "")
           ?.itemDefinition?.["@_isCollection"] ?? false
       );
-    }, [allDataTypesById, allTopLevelItemDefinitionUniqueNames, decision.variable]);
+    });
 
     return (
       <>
-        <svg className={`kie-dmn-editor--node-shape ${className} ${dmnObjectQName.prefix ? "external" : ""}`}>
+        <svg className={`kie-dmn-editor--node-shape ${additionalClasses}`}>
           <DecisionNodeSvg
             isCollection={isCollection}
             {...nodeDimensions}
@@ -304,18 +332,19 @@ export const DecisionNode = React.memo(
 
         <div
           ref={ref}
-          className={`kie-dmn-editor--node kie-dmn-editor--decision-node ${className} ${
-            dmnObjectQName.prefix ? "external" : ""
-          }`}
+          className={`kie-dmn-editor--node kie-dmn-editor--decision-node ${additionalClasses}`}
           tabIndex={-1}
           onDoubleClick={triggerEditing}
           onKeyDown={triggerEditingIfEnter}
         >
-          <InfoNodePanel isVisible={!isTargeted && isHovered} />
-
-          {!isExternal && <EditExpressionNodePanel isVisible={!isTargeted && isHovered} id={decision["@_id"]!} />}
+          {/* {`render count: ${renderCount.current}`}
+          <br /> */}
+          <InfoNodePanel isVisible={!isTargeted && shouldActLikeHovered} />
+          {!isExternal && (
+            <EditExpressionNodePanel isVisible={!isTargeted && shouldActLikeHovered} id={decision["@_id"]!} />
+          )}
           <OutgoingStuffNodePanel
-            isVisible={!isConnecting && !isTargeted && isHovered}
+            isVisible={!isTargeted && shouldActLikeHovered}
             nodeTypes={outgoingStructure[NODE_TYPES.decision].nodes}
             edgeTypes={outgoingStructure[NODE_TYPES.decision].edges}
           />
@@ -327,22 +356,22 @@ export const DecisionNode = React.memo(
             position={getNodeLabelPosition(type as NodeType)}
             value={decision["@_label"] ?? decision["@_name"]}
             onChange={setName}
-            allUniqueNames={allFeelVariableUniqueNames}
+            onGetAllUniqueNames={getAllFeelVariableUniqueNames}
             shouldCommitOnBlur={true}
             fontCssProperties={fontCssProperties}
           />
-          {isHovered && (
+          {shouldActLikeHovered && (
             <NodeResizerHandle
               nodeType={type as NodeType}
-              snapGrid={diagram.snapGrid}
+              snapGrid={snapGrid}
               nodeId={id}
               nodeShapeIndex={shape.index}
             />
           )}
           <DataTypeNodePanel
-            isVisible={!isTargeted && isHovered}
+            isVisible={!isTargeted && shouldActLikeHovered}
             variable={decision.variable}
-            namespace={dmnObjectNamespace}
+            dmnObjectNamespace={dmnObjectNamespace}
             shape={shape}
             onChange={onTypeRefChange}
             onCreate={onCreateDataType}
@@ -350,7 +379,8 @@ export const DecisionNode = React.memo(
         </div>
       </>
     );
-  }
+  },
+  propsHaveSameValuesDeep
 );
 
 export const BkmNode = React.memo(
@@ -362,23 +392,29 @@ export const BkmNode = React.memo(
     type,
     id,
   }: RF.NodeProps<DmnDiagramNodeData<DMN15__tBusinessKnowledgeModel & { __$$element: "businessKnowledgeModel" }>>) => {
+    const renderCount = useRef<number>(0);
+    renderCount.current++;
+
     const ref = useRef<HTMLDivElement>(null);
     const isExternal = !!dmnObjectQName.prefix;
-    const isResizing = useNodeResizing(id);
-
-    const diagram = useDmnEditorStore((s) => s.diagram);
-    const isHovered = (useIsHovered(ref) || isResizing) && diagram.draggingNodes.length === 0;
 
+    const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+    const enableCustomNodeStyles = useDmnEditorStore((s) => s.diagram.overlays.enableCustomNodeStyles);
+    const isHovered = useIsHovered(ref);
+    const isResizing = useNodeResizing(id);
+    const shouldActLikeHovered = useDmnEditorStore(
+      (s) => (isHovered || isResizing) && s.diagram.draggingNodes.length === 0
+    );
     const { isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter } = useEditableNodeLabel(
       bkm["@_id"]
     );
-    useHoveredNodeAlwaysOnTop(ref, zIndex, isHovered, dragging, selected, isEditingLabel);
+    useHoveredNodeAlwaysOnTop(ref, zIndex, shouldActLikeHovered, dragging, selected, isEditingLabel);
 
     const dmnEditorStoreApi = useDmnEditorStoreApi();
 
-    const { isTargeted, isValidConnectionTarget, isConnecting } = useConnectionTargetStatus(id, isHovered);
-    const className = useNodeClassName(diagram.dropTargetNode, isConnecting, isValidConnectionTarget, id);
-    const nodeDimensions = useNodeDimensions(type as NodeType, diagram.snapGrid, id, shape, isExternal);
+    const { isTargeted, isValidConnectionTarget } = useConnectionTargetStatus(id, shouldActLikeHovered);
+    const className = useNodeClassName(isValidConnectionTarget, id);
+    const nodeDimensions = useNodeDimensions(type as NodeType, snapGrid, shape, isExternal);
     const setName = useCallback<OnEditableNodeLabelChange>(
       (newName: string) => {
         dmnEditorStoreApi.setState((state) => {
@@ -399,19 +435,21 @@ export const BkmNode = React.memo(
       [bkm, dmnEditorStoreApi, index]
     );
 
-    const { allFeelVariableUniqueNames } = useDmnEditorDerivedStore();
+    const getAllFeelVariableUniqueNames = useCallback((s: State) => s.computed(s).getAllFeelVariableUniqueNames(), []);
 
     const onCreateDataType = useDataTypeCreationCallbackForNodes(index, bkm["@_name"]);
 
     const { fontCssProperties, shapeStyle } = useNodeStyle({
       dmnStyle: shape["di:Style"],
       nodeType: type as NodeType,
-      isEnabled: diagram.overlays.enableStyles,
+      isEnabled: enableCustomNodeStyles,
     });
 
+    const additionalClasses = `${className} ${dmnObjectQName.prefix ? "external" : ""}`;
+
     return (
       <>
-        <svg className={`kie-dmn-editor--node-shape ${className} ${dmnObjectQName.prefix ? "external" : ""}`}>
+        <svg className={`kie-dmn-editor--node-shape ${additionalClasses}`}>
           <BkmNodeSvg
             {...nodeDimensions}
             x={0}
@@ -426,18 +464,17 @@ export const BkmNode = React.memo(
 
         <div
           ref={ref}
-          className={`kie-dmn-editor--node kie-dmn-editor--bkm-node ${className} ${
-            dmnObjectQName.prefix ? "external" : ""
-          }`}
+          className={`kie-dmn-editor--node kie-dmn-editor--bkm-node ${additionalClasses}`}
           tabIndex={-1}
           onDoubleClick={triggerEditing}
           onKeyDown={triggerEditingIfEnter}
         >
-          <InfoNodePanel isVisible={!isTargeted && isHovered} />
-
-          {!isExternal && <EditExpressionNodePanel isVisible={!isTargeted && isHovered} id={bkm["@_id"]!} />}
+          {/* {`render count: ${renderCount.current}`}
+          <br /> */}
+          <InfoNodePanel isVisible={!isTargeted && shouldActLikeHovered} />
+          {!isExternal && <EditExpressionNodePanel isVisible={!isTargeted && shouldActLikeHovered} id={bkm["@_id"]!} />}
           <OutgoingStuffNodePanel
-            isVisible={!isConnecting && !isTargeted && isHovered}
+            isVisible={!isTargeted && shouldActLikeHovered}
             nodeTypes={outgoingStructure[NODE_TYPES.bkm].nodes}
             edgeTypes={outgoingStructure[NODE_TYPES.bkm].edges}
           />
@@ -449,22 +486,22 @@ export const BkmNode = React.memo(
             position={getNodeLabelPosition(type as NodeType)}
             value={bkm["@_label"] ?? bkm["@_name"]}
             onChange={setName}
-            allUniqueNames={allFeelVariableUniqueNames}
+            onGetAllUniqueNames={getAllFeelVariableUniqueNames}
             shouldCommitOnBlur={true}
             fontCssProperties={fontCssProperties}
           />
-          {isHovered && (
+          {shouldActLikeHovered && (
             <NodeResizerHandle
               nodeType={type as NodeType}
-              snapGrid={diagram.snapGrid}
+              snapGrid={snapGrid}
               nodeId={id}
               nodeShapeIndex={shape.index}
             />
           )}
           <DataTypeNodePanel
-            isVisible={!isTargeted && isHovered}
+            isVisible={!isTargeted && shouldActLikeHovered}
             variable={bkm.variable}
-            namespace={dmnObjectNamespace}
+            dmnObjectNamespace={dmnObjectNamespace}
             shape={shape}
             onChange={onTypeRefChange}
             onCreate={onCreateDataType}
@@ -472,7 +509,8 @@ export const BkmNode = React.memo(
         </div>
       </>
     );
-  }
+  },
+  propsHaveSameValuesDeep
 );
 
 export const KnowledgeSourceNode = React.memo(
@@ -484,23 +522,30 @@ export const KnowledgeSourceNode = React.memo(
     type,
     id,
   }: RF.NodeProps<DmnDiagramNodeData<DMN15__tKnowledgeSource & { __$$element: "knowledgeSource" }>>) => {
+    const renderCount = useRef<number>(0);
+    renderCount.current++;
+
     const ref = useRef<HTMLDivElement>(null);
     const isExternal = !!dmnObjectQName.prefix;
-    const isResizing = useNodeResizing(id);
 
-    const diagram = useDmnEditorStore((s) => s.diagram);
-    const isHovered = (useIsHovered(ref) || isResizing) && diagram.draggingNodes.length === 0;
+    const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+    const enableCustomNodeStyles = useDmnEditorStore((s) => s.diagram.overlays.enableCustomNodeStyles);
+    const isHovered = useIsHovered(ref);
+    const isResizing = useNodeResizing(id);
+    const shouldActLikeHovered = useDmnEditorStore(
+      (s) => (isHovered || isResizing) && s.diagram.draggingNodes.length === 0
+    );
 
     const { isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter } = useEditableNodeLabel(
       knowledgeSource["@_id"]
     );
-    useHoveredNodeAlwaysOnTop(ref, zIndex, isHovered, dragging, selected, isEditingLabel);
+    useHoveredNodeAlwaysOnTop(ref, zIndex, shouldActLikeHovered, dragging, selected, isEditingLabel);
 
     const dmnEditorStoreApi = useDmnEditorStoreApi();
 
-    const { isTargeted, isValidConnectionTarget, isConnecting } = useConnectionTargetStatus(id, isHovered);
-    const className = useNodeClassName(diagram.dropTargetNode, isConnecting, isValidConnectionTarget, id);
-    const nodeDimensions = useNodeDimensions(type as NodeType, diagram.snapGrid, id, shape, isExternal);
+    const { isTargeted, isValidConnectionTarget } = useConnectionTargetStatus(id, shouldActLikeHovered);
+    const className = useNodeClassName(isValidConnectionTarget, id);
+    const nodeDimensions = useNodeDimensions(type as NodeType, snapGrid, shape, isExternal);
     const setName = useCallback<OnEditableNodeLabelChange>(
       (newName: string) => {
         dmnEditorStoreApi.setState((state) => {
@@ -510,17 +555,19 @@ export const KnowledgeSourceNode = React.memo(
       [dmnEditorStoreApi, index]
     );
 
-    const { allFeelVariableUniqueNames } = useDmnEditorDerivedStore();
+    const getAllFeelVariableUniqueNames = useCallback((s: State) => s.computed(s).getAllFeelVariableUniqueNames(), []);
 
     const { fontCssProperties, shapeStyle } = useNodeStyle({
       dmnStyle: shape["di:Style"],
       nodeType: type as NodeType,
-      isEnabled: diagram.overlays.enableStyles,
+      isEnabled: enableCustomNodeStyles,
     });
 
+    const additionalClasses = `${className} ${dmnObjectQName.prefix ? "external" : ""}`;
+
     return (
       <>
-        <svg className={`kie-dmn-editor--node-shape ${className} ${dmnObjectQName.prefix ? "external" : ""}`}>
+        <svg className={`kie-dmn-editor--node-shape ${additionalClasses}`}>
           <KnowledgeSourceNodeSvg
             {...nodeDimensions}
             x={0}
@@ -535,16 +582,16 @@ export const KnowledgeSourceNode = React.memo(
 
         <div
           ref={ref}
-          className={`kie-dmn-editor--node kie-dmn-editor--knowledge-source-node ${className} ${
-            dmnObjectQName.prefix ? "external" : ""
-          }`}
+          className={`kie-dmn-editor--node kie-dmn-editor--knowledge-source-node ${additionalClasses}`}
           tabIndex={-1}
           onDoubleClick={triggerEditing}
           onKeyDown={triggerEditingIfEnter}
         >
-          <InfoNodePanel isVisible={!isTargeted && isHovered} />
+          {/* {`render count: ${renderCount.current}`}
+          <br /> */}
+          <InfoNodePanel isVisible={!isTargeted && shouldActLikeHovered} />
           <OutgoingStuffNodePanel
-            isVisible={!isConnecting && !isTargeted && isHovered}
+            isVisible={!isTargeted && shouldActLikeHovered}
             nodeTypes={outgoingStructure[NODE_TYPES.knowledgeSource].nodes}
             edgeTypes={outgoingStructure[NODE_TYPES.knowledgeSource].edges}
           />
@@ -557,14 +604,14 @@ export const KnowledgeSourceNode = React.memo(
             value={knowledgeSource["@_label"] ?? knowledgeSource["@_name"]}
             onChange={setName}
             skipValidation={true}
-            allUniqueNames={allFeelVariableUniqueNames}
+            onGetAllUniqueNames={getAllFeelVariableUniqueNames}
             shouldCommitOnBlur={true}
             fontCssProperties={fontCssProperties}
           />
-          {isHovered && (
+          {shouldActLikeHovered && (
             <NodeResizerHandle
               nodeType={type as NodeType}
-              snapGrid={diagram.snapGrid}
+              snapGrid={snapGrid}
               nodeId={id}
               nodeShapeIndex={shape.index}
             />
@@ -572,7 +619,8 @@ export const KnowledgeSourceNode = React.memo(
         </div>
       </>
     );
-  }
+  },
+  propsHaveSameValuesDeep
 );
 
 export const TextAnnotationNode = React.memo(
@@ -584,23 +632,30 @@ export const TextAnnotationNode = React.memo(
     type,
     id,
   }: RF.NodeProps<DmnDiagramNodeData<DMN15__tTextAnnotation & { __$$element: "textAnnotation" }>>) => {
+    const renderCount = useRef<number>(0);
+    renderCount.current++;
+
     const ref = useRef<HTMLDivElement>(null);
     const isExternal = !!dmnObjectQName.prefix;
-    const isResizing = useNodeResizing(id);
 
-    const diagram = useDmnEditorStore((s) => s.diagram);
-    const isHovered = (useIsHovered(ref) || isResizing) && diagram.draggingNodes.length === 0;
+    const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+    const enableCustomNodeStyles = useDmnEditorStore((s) => s.diagram.overlays.enableCustomNodeStyles);
+    const isHovered = useIsHovered(ref);
+    const isResizing = useNodeResizing(id);
+    const shouldActLikeHovered = useDmnEditorStore(
+      (s) => (isHovered || isResizing) && s.diagram.draggingNodes.length === 0
+    );
 
     const { isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter } = useEditableNodeLabel(
       textAnnotation["@_id"]
     );
-    useHoveredNodeAlwaysOnTop(ref, zIndex, isHovered, dragging, selected, isEditingLabel);
+    useHoveredNodeAlwaysOnTop(ref, zIndex, shouldActLikeHovered, dragging, selected, isEditingLabel);
 
     const dmnEditorStoreApi = useDmnEditorStoreApi();
 
-    const { isTargeted, isValidConnectionTarget, isConnecting } = useConnectionTargetStatus(id, isHovered);
-    const className = useNodeClassName(diagram.dropTargetNode, isConnecting, isValidConnectionTarget, id);
-    const nodeDimensions = useNodeDimensions(type as NodeType, diagram.snapGrid, id, shape, isExternal);
+    const { isTargeted, isValidConnectionTarget } = useConnectionTargetStatus(id, shouldActLikeHovered);
+    const className = useNodeClassName(isValidConnectionTarget, id);
+    const nodeDimensions = useNodeDimensions(type as NodeType, snapGrid, shape, isExternal);
     const setText = useCallback(
       (newText: string) => {
         dmnEditorStoreApi.setState((state) => {
@@ -610,17 +665,19 @@ export const TextAnnotationNode = React.memo(
       [dmnEditorStoreApi, index]
     );
 
-    const { allFeelVariableUniqueNames } = useDmnEditorDerivedStore();
+    const getAllFeelVariableUniqueNames = useCallback((s: State) => s.computed(s).getAllFeelVariableUniqueNames(), []);
 
     const { fontCssProperties, shapeStyle } = useNodeStyle({
       dmnStyle: shape["di:Style"],
       nodeType: type as NodeType,
-      isEnabled: diagram.overlays.enableStyles,
+      isEnabled: enableCustomNodeStyles,
     });
 
+    const additionalClasses = `${className} ${dmnObjectQName.prefix ? "external" : ""}`;
+
     return (
       <>
-        <svg className={`kie-dmn-editor--node-shape ${className} ${dmnObjectQName.prefix ? "external" : ""}`}>
+        <svg className={`kie-dmn-editor--node-shape ${additionalClasses}`}>
           <TextAnnotationNodeSvg
             {...nodeDimensions}
             x={0}
@@ -635,16 +692,16 @@ export const TextAnnotationNode = React.memo(
 
         <div
           ref={ref}
-          className={`kie-dmn-editor--node kie-dmn-editor--text-annotation-node ${className} ${
-            dmnObjectQName.prefix ? "external" : ""
-          }`}
+          className={`kie-dmn-editor--node kie-dmn-editor--text-annotation-node ${additionalClasses}`}
           tabIndex={-1}
           onDoubleClick={triggerEditing}
           onKeyDown={triggerEditingIfEnter}
         >
-          <InfoNodePanel isVisible={!isTargeted && isHovered} />
+          {/* {`render count: ${renderCount.current}`}
+          <br /> */}
+          <InfoNodePanel isVisible={!isTargeted && shouldActLikeHovered} />
           <OutgoingStuffNodePanel
-            isVisible={!isConnecting && !isTargeted && isHovered}
+            isVisible={!isTargeted && shouldActLikeHovered}
             nodeTypes={outgoingStructure[NODE_TYPES.textAnnotation].nodes}
             edgeTypes={outgoingStructure[NODE_TYPES.textAnnotation].edges}
           />
@@ -658,14 +715,14 @@ export const TextAnnotationNode = React.memo(
             value={textAnnotation["@_label"] ?? textAnnotation.text?.__$$text}
             onChange={setText}
             skipValidation={true}
-            allUniqueNames={allFeelVariableUniqueNames}
+            onGetAllUniqueNames={getAllFeelVariableUniqueNames}
             shouldCommitOnBlur={true}
             fontCssProperties={fontCssProperties}
           />
-          {isHovered && (
+          {shouldActLikeHovered && (
             <NodeResizerHandle
               nodeType={type as NodeType}
-              snapGrid={diagram.snapGrid}
+              snapGrid={snapGrid}
               nodeId={id}
               nodeShapeIndex={shape.index}
             />
@@ -673,7 +730,8 @@ export const TextAnnotationNode = React.memo(
         </div>
       </>
     );
-  }
+  },
+  propsHaveSameValuesDeep
 );
 
 export const DecisionServiceNode = React.memo(
@@ -685,24 +743,31 @@ export const DecisionServiceNode = React.memo(
     type,
     id,
   }: RF.NodeProps<DmnDiagramNodeData<DMN15__tDecisionService & { __$$element: "decisionService" }>>) => {
+    const renderCount = useRef<number>(0);
+    renderCount.current++;
+
     const ref = useRef<SVGRectElement>(null);
     const isExternal = !!dmnObjectQName.prefix;
 
+    const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+    const enableCustomNodeStyles = useDmnEditorStore((s) => s.diagram.overlays.enableCustomNodeStyles);
+    const isHovered = useIsHovered(ref);
     const isResizing = useNodeResizing(id);
-
-    const diagram = useDmnEditorStore((s) => s.diagram);
-    const isHovered = (useIsHovered(ref) || isResizing) && diagram.draggingNodes.length === 0;
+    const shouldActLikeHovered = useDmnEditorStore(
+      (s) => (isHovered || isResizing) && s.diagram.draggingNodes.length === 0
+    );
+    const isDropTarget = useDmnEditorStore((s) => s.diagram.dropTargetNode?.id === id);
 
     const { isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter } = useEditableNodeLabel(
       decisionService["@_id"]
     );
-    useHoveredNodeAlwaysOnTop(ref, zIndex, isHovered, dragging, selected, isEditingLabel);
+    useHoveredNodeAlwaysOnTop(ref, zIndex, shouldActLikeHovered, dragging, selected, isEditingLabel);
     const dmnEditorStoreApi = useDmnEditorStoreApi();
 
-    const { isTargeted, isValidConnectionTarget, isConnecting } = useConnectionTargetStatus(id, isHovered);
-    const className = useNodeClassName(diagram.dropTargetNode, isConnecting, isValidConnectionTarget, id);
+    const { isTargeted, isValidConnectionTarget } = useConnectionTargetStatus(id, shouldActLikeHovered);
+    const className = useNodeClassName(isValidConnectionTarget, id);
 
-    const nodeDimensions = useNodeDimensions(type as NodeType, diagram.snapGrid, id, shape, isExternal);
+    const nodeDimensions = useNodeDimensions(type as NodeType, snapGrid, shape, isExternal);
     const setName = useCallback<OnEditableNodeLabelChange>(
       (newName: string) => {
         dmnEditorStoreApi.setState((state) => {
@@ -742,7 +807,7 @@ export const DecisionServiceNode = React.memo(
       [decisionService, dmnEditorStoreApi, index]
     );
 
-    const { allFeelVariableUniqueNames, dmnShapesByHref } = useDmnEditorDerivedStore();
+    const getAllFeelVariableUniqueNames = useCallback((s: State) => s.computed(s).getAllFeelVariableUniqueNames(), []);
 
     const dividerLineRef = useRef<SVGPathElement>(null);
 
@@ -760,25 +825,25 @@ export const DecisionServiceNode = React.memo(
       const dragHandler = drag<SVGCircleElement, unknown>()
         .on("start", () => {
           dmnEditorStoreApi.setState((state) =>
-            state.dispatch.diagram.setDividerLineStatus(state, id, { moving: true })
+            state.dispatch(state).diagram.setDividerLineStatus(id, { moving: true })
           );
         })
         .on("drag", (e) => {
           dmnEditorStoreApi.setState((state) => {
             updateDecisionServiceDividerLine({
               definitions: state.dmn.model.definitions,
-              drdIndex: diagram.drdIndex,
-              dmnShapesByHref,
+              drdIndex: state.diagram.drdIndex,
+              dmnShapesByHref: state.computed(state).indexes().dmnShapesByHref,
               drgElementIndex: index,
               shapeIndex: shape.index,
               localYPosition: e.y,
-              snapGrid: diagram.snapGrid,
+              snapGrid: state.diagram.snapGrid,
             });
           });
         })
         .on("end", (e) => {
           dmnEditorStoreApi.setState((state) =>
-            state.dispatch.diagram.setDividerLineStatus(state, id, { moving: false })
+            state.dispatch(state).diagram.setDividerLineStatus(id, { moving: false })
           );
         });
 
@@ -786,26 +851,19 @@ export const DecisionServiceNode = React.memo(
       return () => {
         selection.on(".drag", null);
       };
-    }, [
-      decisionService,
-      diagram.drdIndex,
-      diagram.snapGrid,
-      dmnEditorStoreApi,
-      dmnShapesByHref,
-      id,
-      index,
-      shape.index,
-    ]);
+    }, [decisionService, dmnEditorStoreApi, id, index, shape.index]);
 
     const { fontCssProperties, shapeStyle } = useNodeStyle({
       dmnStyle: shape["di:Style"],
       nodeType: type as NodeType,
-      isEnabled: diagram.overlays.enableStyles,
+      isEnabled: enableCustomNodeStyles,
     });
 
+    const additionalClasses = `${className} ${dmnObjectQName.prefix ? "external" : ""}`;
+
     return (
       <>
-        <svg className={`kie-dmn-editor--node-shape ${className} ${dmnObjectQName.prefix ? "external" : ""}`}>
+        <svg className={`kie-dmn-editor--node-shape ${additionalClasses}`}>
           <DecisionServiceNodeSvg
             dividerLineRef={dividerLineRef}
             ref={ref}
@@ -817,7 +875,7 @@ export const DecisionServiceNode = React.memo(
             strokeColor={shapeStyle.strokeColor}
             isReadonly={false}
             isCollapsed={isCollapsed}
-            showSectionLabels={diagram.dropTargetNode?.id === id}
+            showSectionLabels={isDropTarget}
             dividerLineLocalY={getDecisionServiceDividerLineLocalY(shape)}
           />
         </svg>
@@ -825,17 +883,16 @@ export const DecisionServiceNode = React.memo(
         <PositionalNodeHandles isTargeted={isTargeted && isValidConnectionTarget} nodeId={id} />
 
         <div
-          className={`kie-dmn-editor--node kie-dmn-editor--decision-service-node ${className} ${
-            dmnObjectQName.prefix ? "external" : ""
-          }`}
+          className={`kie-dmn-editor--node kie-dmn-editor--decision-service-node ${additionalClasses}`}
           tabIndex={-1}
           onDoubleClick={triggerEditing}
           onKeyDown={triggerEditingIfEnter}
         >
+          {/* {`render count: ${renderCount.current}`}
+          <br /> */}
           <InfoNodePanel isVisible={!isTargeted && selected && !dragging} />
-
           <OutgoingStuffNodePanel
-            isVisible={!isConnecting && !isTargeted && selected && !dragging}
+            isVisible={!isTargeted && selected && !dragging}
             nodeTypes={outgoingStructure[NODE_TYPES.decisionService].nodes}
             edgeTypes={outgoingStructure[NODE_TYPES.decisionService].edges}
           />
@@ -847,14 +904,14 @@ export const DecisionServiceNode = React.memo(
             setEditing={setEditingLabel}
             value={decisionService["@_label"] ?? decisionService["@_name"]}
             onChange={setName}
-            allUniqueNames={allFeelVariableUniqueNames}
+            onGetAllUniqueNames={getAllFeelVariableUniqueNames}
             shouldCommitOnBlur={true}
             fontCssProperties={fontCssProperties}
           />
           {selected && !dragging && !isCollapsed && (
             <NodeResizerHandle
               nodeType={type as NodeType}
-              snapGrid={diagram.snapGrid}
+              snapGrid={snapGrid}
               nodeId={id}
               nodeShapeIndex={shape.index}
             />
@@ -863,7 +920,7 @@ export const DecisionServiceNode = React.memo(
           <DataTypeNodePanel
             isVisible={!isTargeted && selected && !dragging}
             variable={decisionService.variable}
-            namespace={dmnObjectNamespace}
+            dmnObjectNamespace={dmnObjectNamespace}
             shape={shape}
             onCreate={onCreateDataType}
             onChange={onTypeRefChange}
@@ -871,7 +928,8 @@ export const DecisionServiceNode = React.memo(
         </div>
       </>
     );
-  }
+  },
+  propsHaveSameValuesDeep
 );
 
 export const GroupNode = React.memo(
@@ -883,22 +941,28 @@ export const GroupNode = React.memo(
     type,
     id,
   }: RF.NodeProps<DmnDiagramNodeData<DMN15__tGroup & { __$$element: "group" }>>) => {
+    const renderCount = useRef<number>(0);
+    renderCount.current++;
+
     const ref = useRef<SVGRectElement>(null);
     const isExternal = !!dmnObjectQName.prefix;
-    const isResizing = useNodeResizing(id);
-
-    const diagram = useDmnEditorStore((s) => s.diagram);
-    const isHovered = (useIsHovered(ref) || isResizing) && diagram.draggingNodes.length === 0;
 
+    const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+    const enableCustomNodeStyles = useDmnEditorStore((s) => s.diagram.overlays.enableCustomNodeStyles);
+    const isHovered = useIsHovered(ref);
+    const isResizing = useNodeResizing(id);
+    const shouldActLikeHovered = useDmnEditorStore(
+      (s) => (isHovered || isResizing) && s.diagram.draggingNodes.length === 0
+    );
     const dmnEditorStoreApi = useDmnEditorStoreApi();
     const reactFlow = RF.useReactFlow<DmnDiagramNodeData, DmnDiagramEdgeData>();
 
     const { isEditingLabel, setEditingLabel, triggerEditing, triggerEditingIfEnter } = useEditableNodeLabel(
       group["@_id"]
     );
-    const { isTargeted, isValidConnectionTarget, isConnecting } = useConnectionTargetStatus(id, isHovered);
-    const className = useNodeClassName(diagram.dropTargetNode, isConnecting, isValidConnectionTarget, id);
-    const nodeDimensions = useNodeDimensions(type as NodeType, diagram.snapGrid, id, shape, isExternal);
+    const { isTargeted, isValidConnectionTarget } = useConnectionTargetStatus(id, shouldActLikeHovered);
+    const className = useNodeClassName(isValidConnectionTarget, id);
+    const nodeDimensions = useNodeDimensions(type as NodeType, snapGrid, shape, isExternal);
     const setName = useCallback<OnEditableNodeLabelChange>(
       (newName: string) => {
         dmnEditorStoreApi.setState((state) => {
@@ -933,17 +997,17 @@ export const GroupNode = React.memo(
       };
     }, [dmnEditorStoreApi, reactFlow, shape]);
 
-    const { allFeelVariableUniqueNames } = useDmnEditorDerivedStore();
-
     const { fontCssProperties, shapeStyle } = useNodeStyle({
       dmnStyle: shape["di:Style"],
       nodeType: type as NodeType,
-      isEnabled: diagram.overlays.enableStyles,
+      isEnabled: enableCustomNodeStyles,
     });
 
+    const additionalClasses = `${className} ${dmnObjectQName.prefix ? "external" : ""}`;
+
     return (
       <>
-        <svg className={`kie-dmn-editor--node-shape ${className} ${dmnObjectQName.prefix ? "external" : ""}`}>
+        <svg className={`kie-dmn-editor--node-shape ${additionalClasses}`}>
           <GroupNodeSvg
             ref={ref}
             {...nodeDimensions}
@@ -956,15 +1020,15 @@ export const GroupNode = React.memo(
         </svg>
 
         <div
-          className={`kie-dmn-editor--node kie-dmn-editor--group-node ${className} ${
-            dmnObjectQName.prefix ? "external" : ""
-          }`}
+          className={`kie-dmn-editor--node kie-dmn-editor--group-node ${additionalClasses}`}
           tabIndex={-1}
           onDoubleClick={triggerEditing}
           onKeyDown={triggerEditingIfEnter}
         >
+          {/* {`render count: ${renderCount.current}`}
+          <br /> */}
           <OutgoingStuffNodePanel
-            isVisible={!isConnecting && !isTargeted && selected && !dragging}
+            isVisible={!isTargeted && selected && !dragging}
             nodeTypes={outgoingStructure[NODE_TYPES.group].nodes}
             edgeTypes={outgoingStructure[NODE_TYPES.group].edges}
           />
@@ -978,14 +1042,14 @@ export const GroupNode = React.memo(
             value={group["@_label"] ?? group["@_name"]}
             onChange={setName}
             skipValidation={true}
-            allUniqueNames={allFeelVariableUniqueNames}
+            onGetAllUniqueNames={useCallback(() => new Map(), [])}
             shouldCommitOnBlur={true}
             fontCssProperties={fontCssProperties}
           />
           {selected && !dragging && (
             <NodeResizerHandle
               nodeType={type as NodeType}
-              snapGrid={diagram.snapGrid}
+              snapGrid={snapGrid}
               nodeId={id}
               nodeShapeIndex={shape.index}
             />
@@ -993,7 +1057,8 @@ export const GroupNode = React.memo(
         </div>
       </>
     );
-  }
+  },
+  propsHaveSameValuesDeep
 );
 
 export const UnknownNode = React.memo(
@@ -1005,16 +1070,23 @@ export const UnknownNode = React.memo(
     type,
     id,
   }: RF.NodeProps<DmnDiagramNodeData<null>>) => {
+    const renderCount = useRef<number>(0);
+    renderCount.current++;
+
     const ref = useRef<HTMLDivElement>(null);
     const isExternal = !!dmnObjectQName.prefix;
-    const isResizing = useNodeResizing(id);
 
-    const diagram = useDmnEditorStore((s) => s.diagram);
-    const isHovered = (useIsHovered(ref) || isResizing) && diagram.draggingNodes.length === 0;
+    const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
+    const enableCustomNodeStyles = useDmnEditorStore((s) => s.diagram.overlays.enableCustomNodeStyles);
+    const isHovered = useIsHovered(ref);
+    const isResizing = useNodeResizing(id);
+    const shouldActLikeHovered = useDmnEditorStore(
+      (s) => (isHovered || isResizing) && s.diagram.draggingNodes.length === 0
+    );
 
-    const { isTargeted, isValidConnectionTarget, isConnecting } = useConnectionTargetStatus(id, isHovered);
-    const className = useNodeClassName(diagram.dropTargetNode, isConnecting, isValidConnectionTarget, id);
-    const nodeDimensions = useNodeDimensions(type as NodeType, diagram.snapGrid, id, shape, isExternal);
+    const { isTargeted, isValidConnectionTarget } = useConnectionTargetStatus(id, shouldActLikeHovered);
+    const className = useNodeClassName(isValidConnectionTarget, id);
+    const nodeDimensions = useNodeDimensions(type as NodeType, snapGrid, shape, isExternal);
 
     return (
       <>
@@ -1025,7 +1097,9 @@ export const UnknownNode = React.memo(
         <RF.Handle key={"unknown"} id={"unknown"} type={"source"} style={{ opacity: 0 }} position={RF.Position.Top} />
 
         <div ref={ref} className={`kie-dmn-editor--node kie-dmn-editor--unknown-node ${className}`} tabIndex={-1}>
-          <InfoNodePanel isVisible={!isTargeted && isHovered} />
+          {/* {`render count: ${renderCount.current}`}
+          <br /> */}
+          <InfoNodePanel isVisible={!isTargeted && shouldActLikeHovered} />
 
           <EditableNodeLabel
             namedElement={undefined}
@@ -1036,13 +1110,13 @@ export const UnknownNode = React.memo(
             value={`? `}
             onChange={() => {}}
             skipValidation={false}
-            allUniqueNames={new Map()}
+            onGetAllUniqueNames={useCallback(() => new Map(), [])}
             shouldCommitOnBlur={true}
           />
           {selected && !dragging && (
             <NodeResizerHandle
               nodeType={type as NodeType}
-              snapGrid={diagram.snapGrid}
+              snapGrid={snapGrid}
               nodeId={id}
               nodeShapeIndex={shape.index}
             />
@@ -1050,7 +1124,8 @@ export const UnknownNode = React.memo(
         </div>
       </>
     );
-  }
+  },
+  propsHaveSameValuesDeep
 );
 
 ///
@@ -1095,41 +1170,31 @@ export function NodeResizerHandle(props: {
 }
 
 function useNodeResizing(id: string): boolean {
-  const node = RF.useStore((s) => s.nodeInternals.get(id));
-  if (!node) {
-    throw new Error("Can't use nodeInternals of non-existent node " + id);
-  }
-
-  return node.resizing ?? false;
+  return RF.useStore((s) => s.nodeInternals.get(id)?.resizing ?? false);
 }
+
 function useNodeDimensions(
   type: NodeType,
   snapGrid: SnapGrid,
-  id: string,
   shape: DMNDI15__DMNShape,
   isExternal: boolean
 ): RF.Dimensions {
-  const node = RF.useStore((s) => s.nodeInternals.get(id));
-  if (!node) {
-    throw new Error("Can't use nodeInternals of non-existent node " + id);
-  }
-
   if (type === NODE_TYPES.decisionService && (isExternal || shape["@_isCollapsed"])) {
     return DECISION_SERVICE_COLLAPSED_DIMENSIONS;
   }
 
-  const minSizes = MIN_NODE_SIZES[node.type as NodeType](snapGrid);
+  const minSizes = MIN_NODE_SIZES[type](snapGrid);
 
   return {
-    width: node.width ?? snapShapeDimensions(snapGrid, shape, minSizes).width,
-    height: node.height ?? snapShapeDimensions(snapGrid, shape, minSizes).height,
+    width: snapShapeDimensions(snapGrid, shape, minSizes).width,
+    height: snapShapeDimensions(snapGrid, shape, minSizes).height,
   };
 }
 
 function useHoveredNodeAlwaysOnTop(
   ref: React.RefObject<HTMLDivElement | SVGElement>,
   layer: number,
-  isHovered: boolean,
+  shouldActLikeHovered: boolean,
   dragging: boolean,
   selected: boolean,
   isEditing: boolean
@@ -1140,67 +1205,73 @@ function useHoveredNodeAlwaysOnTop(
         ref.current?.focus();
       }
       if (ref.current) {
-        ref.current.parentElement!.style.zIndex = `${isHovered || dragging ? layer + 1000 + 1 : layer}`;
+        ref.current.parentElement!.style.zIndex = `${shouldActLikeHovered || dragging ? layer + 1000 + 1 : layer}`;
       }
     }, 0);
-  }, [dragging, isHovered, ref, selected, layer, isEditing]);
+  }, [dragging, shouldActLikeHovered, ref, selected, layer, isEditing]);
 }
 
 export function useConnection(nodeId: string) {
   const connectionNodeId = RF.useStore((s) => s.connectionNodeId);
-  const connectionHandleId = RF.useStore((s) => s.connectionHandleId);
   const connectionHandleType = RF.useStore((s) => s.connectionHandleType);
-  const edgeIdBeingUpdated = useDmnEditorStore((s) => s.diagram.edgeIdBeingUpdated);
-  const { edgesById } = useDmnEditorDerivedStore();
 
-  const edge = edgeIdBeingUpdated ? edgesById.get(edgeIdBeingUpdated) : null;
   const source = connectionNodeId;
   const target = nodeId;
-  const sourceHandle = connectionHandleId ?? edge?.type ?? null;
 
-  const connection = {
-    source: connectionHandleType === "source" ? source : target,
-    target: connectionHandleType === "source" ? target : source,
-    sourceHandle,
-    targetHandle: null, // We don't use targetHandles, as target handles are only different in position, not in semantic.
-  };
+  const edgeIdBeingUpdated = useDmnEditorStore((s) => s.diagram.edgeIdBeingUpdated);
+  const sourceHandle = RF.useStore(
+    (s) => s.connectionHandleId ?? s.edges.find((e) => e.id === edgeIdBeingUpdated)?.type ?? null
+  );
+
+  const connection = useMemo(
+    () => ({
+      source: connectionHandleType === "source" ? source : target,
+      target: connectionHandleType === "source" ? target : source,
+      sourceHandle,
+      targetHandle: null, // We don't use targetHandles, as target handles are only different in position, not in semantic.
+    }),
+    [connectionHandleType, source, sourceHandle, target]
+  );
 
   return connection;
 }
 
-export function useConnectionTargetStatus(nodeId: string, isHovered: boolean) {
-  const connectionNodeId = RF.useStore((s) => s.connectionNodeId);
-  const isValidConnection = RF.useStore((s) => s.isValidConnection);
+export function useConnectionTargetStatus(nodeId: string, shouldActLikeHovered: boolean) {
+  const isTargeted = RF.useStore((s) => !!s.connectionNodeId && s.connectionNodeId !== nodeId && shouldActLikeHovered);
   const connection = useConnection(nodeId);
-
-  return {
-    isTargeted: !!connectionNodeId && connectionNodeId !== nodeId && isHovered,
-    isValidConnectionTarget: isValidConnection?.(connection) ?? false,
-    isConnecting: !!connectionNodeId,
-  };
+  const isValidConnectionTarget = RF.useStore((s) => s.isValidConnection?.(connection) ?? false);
+
+  return useMemo(
+    () => ({
+      isTargeted,
+      isValidConnectionTarget,
+    }),
+    [isTargeted, isValidConnectionTarget]
+  );
 }
 
-export function useNodeClassName(
-  dropTargetNode: DropTargetNode,
-  isConnecting: boolean,
-  isValidConnectionTarget: boolean,
-  nodeId: string
-) {
-  const { isDropTargetNodeValidForSelection } = useDmnEditorDerivedStore();
-  const connectionNodeId = RF.useStore((s) => s.connectionNodeId);
+export function useNodeClassName(isValidConnectionTarget: boolean, nodeId: string) {
+  const isDropTarget = useDmnEditorStore(
+    (s) => s.diagram.dropTargetNode?.id === nodeId && containment.get(s.diagram.dropTargetNode?.type as NodeType)
+  );
+  const { externalModelsByNamespace } = useExternalModels();
+  const isDropTargetNodeValidForSelection = useDmnEditorStore((s) =>
+    s.computed(s).isDropTargetNodeValidForSelection(externalModelsByNamespace)
+  );
+  const isConnectionNodeId = RF.useStore((s) => s.connectionNodeId === nodeId);
   const connection = useConnection(nodeId);
   const isEdgeConnection = !!Object.values(EDGE_TYPES).find((s) => s === connection.sourceHandle);
   const isNodeConnection = !!Object.values(NODE_TYPES).find((s) => s === connection.sourceHandle);
 
-  if (isNodeConnection && isConnecting && connectionNodeId !== nodeId) {
+  if (isNodeConnection && !isConnectionNodeId) {
     return "dimmed";
   }
 
-  if (isEdgeConnection && isConnecting && (!isValidConnectionTarget || connectionNodeId === nodeId)) {
+  if (isEdgeConnection && (!isValidConnectionTarget || isConnectionNodeId)) {
     return "dimmed";
   }
 
-  if (dropTargetNode?.id === nodeId && containment.get(dropTargetNode.type as NodeType)) {
+  if (isDropTarget) {
     return isDropTargetNodeValidForSelection ? "drop-target" : "drop-target-invalid";
   }
 
diff --git a/packages/dmn-editor/src/draggable/Draggable.tsx b/packages/dmn-editor/src/draggable/Draggable.tsx
index 7ae45ddb526..cdffd6aeac4 100644
--- a/packages/dmn-editor/src/draggable/Draggable.tsx
+++ b/packages/dmn-editor/src/draggable/Draggable.tsx
@@ -80,9 +80,6 @@ export function DragAndDrop({
   const [valuesKeys, setValuesKeys] = useState((values ?? [])?.map((_) => generateUuid()));
 
   useLayoutEffect(() => {
-    if (isDisabled) {
-      return;
-    }
     setValuesCopy((prev) => {
       if (values?.length !== prev.length) {
         setValuesKeys((values ?? [])?.map((_) => generateUuid()));
diff --git a/packages/dmn-editor/src/externalNodes/DmnObjectListItem.tsx b/packages/dmn-editor/src/externalNodes/DmnObjectListItem.tsx
index 928af9ec626..335c5f16c39 100644
--- a/packages/dmn-editor/src/externalNodes/DmnObjectListItem.tsx
+++ b/packages/dmn-editor/src/externalNodes/DmnObjectListItem.tsx
@@ -24,9 +24,10 @@ import { TypeRefLabel } from "../dataTypes/TypeRefLabel";
 import { NodeIcon } from "../icons/Icons";
 import { getNodeTypeFromDmnObject } from "../diagram/maths/DmnMaths";
 import { buildFeelQNameFromNamespace } from "../feel/buildFeelQName";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
 import { DmnBuiltInDataType } from "@kie-tools/boxed-expression-component/dist/api";
+import { useDmnEditorStore } from "../store/StoreContext";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 export function DmnObjectListItem({
   dmnObject,
@@ -39,7 +40,11 @@ export function DmnObjectListItem({
   namespace: string;
   relativeToNamespace: string;
 }) {
-  const { importsByNamespace, allTopLevelDataTypesByFeelName } = useDmnEditorDerivedStore();
+  const importsByNamespace = useDmnEditorStore((s) => s.computed(s).importsByNamespace());
+  const { externalModelsByNamespace } = useExternalModels();
+  const allTopLevelDataTypesByFeelName = useDmnEditorStore(
+    (s) => s.computed(s).getDataTypes(externalModelsByNamespace).allTopLevelDataTypesByFeelName
+  );
   if (!dmnObject) {
     return <>{dmnObjectHref}</>;
   }
diff --git a/packages/dmn-editor/src/externalNodes/ExternalNodesPanel.tsx b/packages/dmn-editor/src/externalNodes/ExternalNodesPanel.tsx
index ef89960b535..07fb04aaa20 100644
--- a/packages/dmn-editor/src/externalNodes/ExternalNodesPanel.tsx
+++ b/packages/dmn-editor/src/externalNodes/ExternalNodesPanel.tsx
@@ -19,9 +19,9 @@
 
 import * as React from "react";
 import { useCallback, useState } from "react";
-import { DiagramNodesPanel, DmnEditorTab, useDmnEditorStoreApi } from "../store/Store";
+import { DiagramNodesPanel, DmnEditorTab } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { buildXmlHref } from "../xml/xmlHrefs";
 import {
   EmptyState,
@@ -39,6 +39,7 @@ import { EMPTY_IMPORT_NAME_NAMESPACE_IDENTIFIER } from "../includedModels/Includ
 import { useDmnEditor } from "../DmnEditorContext";
 import { SearchInput } from "@patternfly/react-core/dist/js/components/SearchInput";
 import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 export type ExternalNode = {
   externalDrgElementNamespace: string;
@@ -50,7 +51,12 @@ export const MIME_TYPE_FOR_DMN_EDITOR_EXTERNAL_NODES_FROM_INCLUDED_MODELS =
 
 export function ExternalNodesPanel() {
   const dmnEditorStoreApi = useDmnEditorStoreApi();
-  const { dmnShapesByHref, externalDmnsByNamespace, importsByNamespace } = useDmnEditorDerivedStore();
+  const importsByNamespace = useDmnEditorStore((s) => s.computed(s).importsByNamespace());
+  const { externalModelsByNamespace } = useExternalModels();
+  const externalDmnsByNamespace = useDmnEditorStore(
+    (s) => s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).dmns
+  );
+  const dmnShapesByHref = useDmnEditorStore((s) => s.computed(s).indexes().dmnShapesByHref);
   const { onRequestToResolvePath } = useDmnEditor();
 
   const onDragStart = useCallback((event: React.DragEvent, externalNode: ExternalNode) => {
diff --git a/packages/dmn-editor/src/feel/InlineFeelNameInput.tsx b/packages/dmn-editor/src/feel/InlineFeelNameInput.tsx
index 2e0085d645d..0c8e8a4d7fb 100644
--- a/packages/dmn-editor/src/feel/InlineFeelNameInput.tsx
+++ b/packages/dmn-editor/src/feel/InlineFeelNameInput.tsx
@@ -19,9 +19,10 @@
 
 import * as React from "react";
 import { useCallback, useEffect, useRef, useState } from "react";
-import { DMN15_SPEC } from "../Dmn15Spec";
-import { UniqueNameIndex } from "../Dmn15Spec";
+import { DMN15_SPEC, UniqueNameIndex } from "../Dmn15Spec";
 import { useFocusableElement } from "../focus/useFocusableElement";
+import { State } from "../store/Store";
+import { useDmnEditorStoreApi } from "../store/StoreContext";
 
 export type OnInlineFeelNameRenamed = (newName: string) => void;
 
@@ -52,7 +53,7 @@ export function InlineFeelNameInput({
   isReadonly: boolean;
   isPlain: boolean;
   shouldCommitOnBlur: boolean;
-  allUniqueNames: UniqueNameIndex;
+  allUniqueNames: (s: State) => UniqueNameIndex;
   placeholder?: string;
   saveInvalidValue?: boolean;
   validate?: typeof DMN15_SPEC.namedElement.isValidName;
@@ -75,14 +76,16 @@ export function InlineFeelNameInput({
     }, 0);
   }, []);
 
-  const [isValid, setValid] = useState(_validate(id, name, allUniqueNames));
+  const dmnEditorStoreApi = useDmnEditorStoreApi();
+
+  const [isValid, setValid] = useState(_validate(id, name, allUniqueNames(dmnEditorStoreApi.getState())));
   const updateIsValidFlag = useCallback(
     (name: string) => {
-      const isValid = _validate(id, name, allUniqueNames);
+      const isValid = _validate(id, name, allUniqueNames(dmnEditorStoreApi.getState()));
       setValid(isValid);
       return isValid;
     },
-    [_validate, allUniqueNames, id]
+    [_validate, allUniqueNames, dmnEditorStoreApi, id]
   );
 
   useEffect(() => {
diff --git a/packages/dmn-editor/src/focus/useFocusableElement.ts b/packages/dmn-editor/src/focus/useFocusableElement.ts
index d4b0823497b..3c8853a195f 100644
--- a/packages/dmn-editor/src/focus/useFocusableElement.ts
+++ b/packages/dmn-editor/src/focus/useFocusableElement.ts
@@ -18,16 +18,17 @@
  */
 
 import { useEffect } from "react";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 
 export function useFocusableElement(
   ref: React.RefObject<HTMLInputElement>,
   id: string | undefined,
   before?: (cb: () => void) => void
 ) {
-  const focus = useDmnEditorStore((s) => s.focus);
   const dmnEditorStoreApi = useDmnEditorStoreApi();
 
+  const shoudFocus = useDmnEditorStore((s) => s.focus.consumableId === id);
+
   useEffect(() => {
     if (!id) {
       return;
@@ -41,8 +42,8 @@ export function useFocusableElement(
       });
     };
 
-    if (focus.consumableId === id && ref.current) {
+    if (shoudFocus && ref.current) {
       before?.(cb) ?? cb();
     }
-  }, [before, dmnEditorStoreApi, focus.consumableId, id, ref]);
+  }, [before, dmnEditorStoreApi, id, ref, shoudFocus]);
 }
diff --git a/packages/dmn-editor/src/includedModels/DmnEditorDependenciesContext.tsx b/packages/dmn-editor/src/includedModels/DmnEditorDependenciesContext.tsx
index c2cae5a95b2..462b5f2fac8 100644
--- a/packages/dmn-editor/src/includedModels/DmnEditorDependenciesContext.tsx
+++ b/packages/dmn-editor/src/includedModels/DmnEditorDependenciesContext.tsx
@@ -18,7 +18,7 @@
  */
 
 import * as React from "react";
-import { useContext } from "react";
+import { useContext, useMemo } from "react";
 import {
   OnRequestExternalModelsAvailableToInclude,
   OnRequestExternalModelByPath,
@@ -41,5 +41,18 @@ export function DmnEditorExternalModelsContextProvider(
   _props: React.PropsWithChildren<DmnEditorExternalModelsContextType>
 ) {
   const { children, ...props } = _props;
-  return <DmnEditorExternalModelsContext.Provider value={props}>{children}</DmnEditorExternalModelsContext.Provider>;
+
+  const value = useMemo<DmnEditorExternalModelsContextType>(() => {
+    return {
+      externalModelsByNamespace: props.externalModelsByNamespace,
+      onRequestExternalModelByPath: props.onRequestExternalModelByPath,
+      onRequestExternalModelsAvailableToInclude: props.onRequestExternalModelsAvailableToInclude,
+    };
+  }, [
+    props.externalModelsByNamespace,
+    props.onRequestExternalModelByPath,
+    props.onRequestExternalModelsAvailableToInclude,
+  ]);
+
+  return <DmnEditorExternalModelsContext.Provider value={value}>{children}</DmnEditorExternalModelsContext.Provider>;
 }
diff --git a/packages/dmn-editor/src/includedModels/IncludedModels.tsx b/packages/dmn-editor/src/includedModels/IncludedModels.tsx
index 3c4ecf7bc8e..03737d2a50c 100644
--- a/packages/dmn-editor/src/includedModels/IncludedModels.tsx
+++ b/packages/dmn-editor/src/includedModels/IncludedModels.tsx
@@ -19,7 +19,6 @@
 
 import * as React from "react";
 import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
-import { ns as dmn15ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/meta";
 import { ns as dmn12ns } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_2/ts-gen/meta";
 import { DMN15__tImport } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button";
@@ -43,8 +42,7 @@ import { InlineFeelNameInput, OnInlineFeelNameRenamed } from "../feel/InlineFeel
 import { addImport } from "../mutations/addImport";
 import { deleteImport } from "../mutations/deleteImport";
 import { renameImport } from "../mutations/renameImport";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { KIE_UNKNOWN_NAMESPACE } from "../kie/kie";
 import { ExternalModelLabel } from "./ExternalModelLabel";
 import { useExternalModels } from "./DmnEditorDependenciesContext";
@@ -56,6 +54,7 @@ import { Dropdown, DropdownItem, KebabToggle } from "@patternfly/react-core/dist
 import { TrashIcon } from "@patternfly/react-icons/dist/js/icons/trash-icon";
 import { useInViewSelect } from "../responsiveness/useInViewSelect";
 import { useCancelableEffect } from "@kie-tools-core/react-hooks/dist/useCancelableEffect";
+import { State } from "../store/Store";
 
 export const EMPTY_IMPORT_NAME_NAMESPACE_IDENTIFIER = "<Default>";
 
@@ -66,12 +65,11 @@ const namespaceForNewImportsByFileExtension: Record<string, string> = {
 
 export function IncludedModels() {
   const dmnEditorStoreApi = useDmnEditorStoreApi();
-  const thisDmn = useDmnEditorStore((s) => s.dmn);
-  const thisDmnsImports = useMemo(() => thisDmn.model.definitions.import ?? [], [thisDmn.model.definitions.import]);
+  const thisDmnsImports = useDmnEditorStore((s) => s.dmn.model.definitions.import ?? []);
 
   const { externalContextDescription, externalContextName, dmnEditorRootElementRef, onRequestToResolvePath } =
     useDmnEditor();
-  const { importsByNamespace, allFeelVariableUniqueNames } = useDmnEditorDerivedStore();
+  const importsByNamespace = useDmnEditorStore((s) => s.computed(s).importsByNamespace());
   const { externalModelsByNamespace, onRequestExternalModelsAvailableToInclude, onRequestExternalModelByPath } =
     useExternalModels();
 
@@ -126,10 +124,11 @@ export function IncludedModels() {
   }, []);
 
   const add = useCallback(() => {
+    const s = dmnEditorStoreApi.getState();
     if (
       !selectedPathRelativeToThisDmn ||
       !selectedModel ||
-      !DMN15_SPEC.IMPORT.name.isValid(generateUuid(), importName, allFeelVariableUniqueNames)
+      !DMN15_SPEC.IMPORT.name.isValid(generateUuid(), importName, s.computed(s).getAllFeelVariableUniqueNames())
     ) {
       return;
     }
@@ -166,7 +165,7 @@ export function IncludedModels() {
     }, 5000); // Give it time for the `externalModelsByNamespace` object to be reassembled externally.
 
     cancel();
-  }, [selectedPathRelativeToThisDmn, selectedModel, importName, allFeelVariableUniqueNames, dmnEditorStoreApi, cancel]);
+  }, [dmnEditorStoreApi, selectedPathRelativeToThisDmn, selectedModel, importName, cancel]);
 
   const [modelPathRelativeToThisDmn, setModelPathsRelativeToThisDmn] = useState<string[] | undefined>(undefined);
   useCancelableEffect(
@@ -234,6 +233,8 @@ export function IncludedModels() {
   const selectToggleRef = useRef<HTMLButtonElement>(null);
   const inViewSelect = useInViewSelect(dmnEditorRootElementRef, selectToggleRef);
 
+  const getAllUniqueNames = useCallback((s: State) => s.computed(s).getAllFeelVariableUniqueNames(), []);
+
   return (
     <>
       <Modal
@@ -343,7 +344,7 @@ export function IncludedModels() {
                       shouldCommitOnBlur={true}
                       className={"pf-c-form-control"}
                       onRenamed={setImportName}
-                      allUniqueNames={allFeelVariableUniqueNames}
+                      allUniqueNames={getAllUniqueNames}
                     />
                   </FormGroup>
                   <br />
@@ -436,6 +437,7 @@ function IncludedModelCard({
   isReadonly: boolean;
 }) {
   const dmnEditorStoreApi = useDmnEditorStoreApi();
+
   const { onRequestToJumpToPath, onRequestToResolvePath } = useDmnEditor();
 
   const remove = useCallback(
@@ -447,15 +449,21 @@ function IncludedModelCard({
     [dmnEditorStoreApi]
   );
 
-  const { allFeelVariableUniqueNames, allTopLevelDataTypesByFeelName } = useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
 
   const rename = useCallback<OnInlineFeelNameRenamed>(
     (newName) => {
       dmnEditorStoreApi.setState((state) => {
-        renameImport({ definitions: state.dmn.model.definitions, index, newName, allTopLevelDataTypesByFeelName });
+        renameImport({
+          definitions: state.dmn.model.definitions,
+          index,
+          newName,
+          allTopLevelDataTypesByFeelName: state.computed(state).getDataTypes(externalModelsByNamespace)
+            .allTopLevelDataTypesByFeelName,
+        });
       });
     },
-    [allTopLevelDataTypesByFeelName, dmnEditorStoreApi, index]
+    [dmnEditorStoreApi, externalModelsByNamespace, index]
   );
 
   const extension = useMemo(() => {
@@ -521,7 +529,7 @@ function IncludedModelCard({
           <InlineFeelNameInput
             placeholder={EMPTY_IMPORT_NAME_NAMESPACE_IDENTIFIER}
             isPlain={true}
-            allUniqueNames={allFeelVariableUniqueNames}
+            allUniqueNames={useCallback((s) => s.computed(s).getAllFeelVariableUniqueNames(), [])}
             id={_import["@_id"]!}
             name={_import["@_name"]}
             isReadonly={false}
@@ -576,15 +584,21 @@ function UnknownIncludedModelCard({
     [dmnEditorStoreApi]
   );
 
-  const { allFeelVariableUniqueNames, allTopLevelDataTypesByFeelName } = useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
 
   const rename = useCallback<OnInlineFeelNameRenamed>(
     (newName) => {
       dmnEditorStoreApi.setState((state) => {
-        renameImport({ definitions: state.dmn.model.definitions, index, newName, allTopLevelDataTypesByFeelName });
+        renameImport({
+          definitions: state.dmn.model.definitions,
+          index,
+          newName,
+          allTopLevelDataTypesByFeelName: state.computed(state).getDataTypes(externalModelsByNamespace)
+            .allTopLevelDataTypesByFeelName,
+        });
       });
     },
-    [allTopLevelDataTypesByFeelName, dmnEditorStoreApi, index]
+    [dmnEditorStoreApi, externalModelsByNamespace, index]
   );
 
   const extension = useMemo(() => {
@@ -635,7 +649,7 @@ function UnknownIncludedModelCard({
           <InlineFeelNameInput
             placeholder={EMPTY_IMPORT_NAME_NAMESPACE_IDENTIFIER}
             isPlain={true}
-            allUniqueNames={allFeelVariableUniqueNames}
+            allUniqueNames={useCallback((s) => s.computed(s).getAllFeelVariableUniqueNames(), [])}
             id={_import["@_id"]!}
             name={_import["@_name"]}
             isReadonly={false}
diff --git a/packages/dmn-editor/src/mutations/addConnectedNode.ts b/packages/dmn-editor/src/mutations/addConnectedNode.ts
index d20a718927b..e356a302a68 100644
--- a/packages/dmn-editor/src/mutations/addConnectedNode.ts
+++ b/packages/dmn-editor/src/mutations/addConnectedNode.ts
@@ -29,7 +29,7 @@ import {
 import { EdgeType, NodeType } from "../diagram/connections/graphStructure";
 import { AutoPositionedEdgeMarker } from "../diagram/edges/AutoPositionedEdgeMarker";
 import { EDGE_TYPES } from "../diagram/edges/EdgeTypes";
-import { getBoundsCenterPoint } from "../diagram/maths/DmnMaths";
+import { getDmnBoundsCenterPoint } from "../diagram/maths/DmnMaths";
 import { NODE_TYPES } from "../diagram/nodes/NodeTypes";
 import { switchExpression } from "@kie-tools-core/switch-expression-ts";
 import { NodeNature, nodeNatures } from "./NodeNature";
@@ -171,7 +171,7 @@ export function addConnectedNode({
     "@_dmnElementRef": newEdgeId,
     "@_sourceElement": sourceNode.shapeId,
     "@_targetElement": newShapeId,
-    "di:waypoint": [getBoundsCenterPoint(sourceNode.bounds), getBoundsCenterPoint(newNode.bounds)],
+    "di:waypoint": [getDmnBoundsCenterPoint(sourceNode.bounds), getDmnBoundsCenterPoint(newNode.bounds)],
   });
 
   repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions });
diff --git a/packages/dmn-editor/src/mutations/addEdge.ts b/packages/dmn-editor/src/mutations/addEdge.ts
index f328d071d32..ff98be9a09d 100644
--- a/packages/dmn-editor/src/mutations/addEdge.ts
+++ b/packages/dmn-editor/src/mutations/addEdge.ts
@@ -38,6 +38,7 @@ import { addOrGetDrd } from "./addOrGetDrd";
 import { Unpacked } from "../tsExt/tsExt";
 import { repopulateInputDataAndDecisionsOnAllDecisionServices } from "./repopulateInputDataAndDecisionsOnDecisionService";
 import { DmnDiagramNodeData } from "../diagram/nodes/Nodes";
+import { AutoPositionedEdgeMarker } from "../diagram/edges/AutoPositionedEdgeMarker";
 
 export function addEdge({
   definitions,
@@ -64,7 +65,12 @@ export function addEdge({
     shapeId: string | undefined;
     index: number;
   };
-  edge: { type: EdgeType; targetHandle: PositionalNodeHandleId; sourceHandle: PositionalNodeHandleId };
+  edge: {
+    type: EdgeType;
+    targetHandle: PositionalNodeHandleId;
+    sourceHandle: PositionalNodeHandleId;
+    autoPositionedEdgeMarker: AutoPositionedEdgeMarker | undefined;
+  };
   keepWaypoints: boolean;
 }) {
   if (!_checkIsValidConnection(sourceNode, targetNode, edge.type)) {
@@ -168,7 +174,9 @@ export function addEdge({
 
   const newDmnEdge: Unpacked<typeof diagramElements> = {
     __$$element: "dmndi:DMNEdge",
-    "@_id": withoutDiscreteAutoPosinitioningMarker(removedDmnEdge?.["@_id"] ?? generateUuid()),
+    "@_id":
+      withoutDiscreteAutoPosinitioningMarker(removedDmnEdge?.["@_id"] ?? generateUuid()) +
+      (edge.autoPositionedEdgeMarker ?? ""),
     "@_dmnElementRef": existingEdgeId ?? newEdgeId,
     "@_sourceElement": sourceNode.shapeId,
     "@_targetElement": targetNode.shapeId,
diff --git a/packages/dmn-editor/src/mutations/deleteEdge.ts b/packages/dmn-editor/src/mutations/deleteEdge.ts
index bdae048fcc2..925779ea486 100644
--- a/packages/dmn-editor/src/mutations/deleteEdge.ts
+++ b/packages/dmn-editor/src/mutations/deleteEdge.ts
@@ -27,52 +27,78 @@ import { addOrGetDrd } from "./addOrGetDrd";
 import { DmnDiagramEdgeData } from "../diagram/edges/Edges";
 import { repopulateInputDataAndDecisionsOnAllDecisionServices } from "./repopulateInputDataAndDecisionsOnDecisionService";
 
+export enum EdgeDeletionMode {
+  FORM_DRG_AND_ALL_DRDS,
+  FROM_CURRENT_DRD_ONLY,
+}
+
 export function deleteEdge({
   definitions,
   drdIndex,
   edge,
+  mode,
 }: {
   definitions: DMN15__tDefinitions;
   drdIndex: number;
   edge: { id: string; dmnObject: DmnDiagramEdgeData["dmnObject"] };
+  mode: EdgeDeletionMode;
 }) {
-  const { diagramElements } = addOrGetDrd({ definitions, drdIndex });
+  if (edge.dmnObject.namespace !== definitions["@_namespace"]) {
+    console.debug("DMN MUTATION: Can't delete an edge that's from an external node.");
+    return { dmnEdge: undefined };
+  }
 
-  const dmnObjects: DMN15__tDefinitions["artifact"] | DMN15__tDefinitions["drgElement"] =
+  const dmnObjects: DMN15__tDefinitions["drgElement" | "artifact"] =
     switchExpression(edge?.dmnObject.type, {
       association: definitions.artifact,
+      group: definitions.artifact,
       default: definitions.drgElement,
     }) ?? [];
 
   const dmnObjectIndex = dmnObjects.findIndex((d) => d["@_id"] === edge.dmnObject.id);
   if (dmnObjectIndex < 0) {
-    throw new Error(`Can't find DMN element with ID ${edge.dmnObject.id}`);
+    throw new Error(`DMN MUTATION: Can't find DMN element with ID ${edge.dmnObject.id}`);
   }
 
-  const requirements =
-    switchExpression(edge?.dmnObject.requirementType, {
-      // Casting to DMN15__tDecision because if has all types of requirement, but not necessarily that's true.
-      informationRequirement: (dmnObjects[dmnObjectIndex] as DMN15__tDecision).informationRequirement,
-      knowledgeRequirement: (dmnObjects[dmnObjectIndex] as DMN15__tDecision).knowledgeRequirement,
-      authorityRequirement: (dmnObjects[dmnObjectIndex] as DMN15__tDecision).authorityRequirement,
-      association: dmnObjects,
-    }) ?? [];
+  if (mode === EdgeDeletionMode.FORM_DRG_AND_ALL_DRDS) {
+    const requirements =
+      switchExpression(edge?.dmnObject.requirementType, {
+        // Casting to DMN15__tDecision because if has all types of requirement, but not necessarily that's true.
+        informationRequirement: (dmnObjects[dmnObjectIndex] as DMN15__tDecision).informationRequirement,
+        knowledgeRequirement: (dmnObjects[dmnObjectIndex] as DMN15__tDecision).knowledgeRequirement,
+        authorityRequirement: (dmnObjects[dmnObjectIndex] as DMN15__tDecision).authorityRequirement,
+        association: dmnObjects,
+      }) ?? [];
 
-  // Deleting the requirement
-  const requirementIndex = (requirements ?? []).findIndex((d) => d["@_id"] === edge.id);
-  if (requirementIndex >= 0) {
-    requirements?.splice(requirementIndex, 1);
+    // Deleting the requirement
+    const requirementIndex = (requirements ?? []).findIndex((d) => d["@_id"] === edge.id);
+    if (requirementIndex >= 0) {
+      requirements?.splice(requirementIndex, 1);
+    }
   }
 
   // Deleting the DMNEdge's
-  let dmnEdge: DMNDI15__DMNEdge | undefined;
-  const dmnEdgeIndex = (diagramElements ?? []).findIndex((d) => d["@_dmnElementRef"] === edge.id);
-  if (dmnEdgeIndex >= 0) {
-    dmnEdge = diagramElements[dmnEdgeIndex];
-    diagramElements?.splice(dmnEdgeIndex, 1);
+  let deletedDmnEdgeOnCurrentDrd: DMNDI15__DMNEdge | undefined;
+
+  const drdCount = (definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"] ?? []).length;
+  for (let i = 0; i < drdCount; i++) {
+    const { diagramElements } = addOrGetDrd({ definitions, drdIndex: i });
+
+    if (mode === EdgeDeletionMode.FROM_CURRENT_DRD_ONLY && i !== drdIndex) {
+      continue;
+    }
+
+    const dmnEdgeIndex = (diagramElements ?? []).findIndex((d) => d["@_dmnElementRef"] === edge.id);
+    if (dmnEdgeIndex >= 0) {
+      if (i === drdIndex) {
+        deletedDmnEdgeOnCurrentDrd = diagramElements[dmnEdgeIndex];
+      }
+
+      diagramElements?.splice(dmnEdgeIndex, 1);
+    }
   }
 
   repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions });
 
-  return { dmnEdge };
+  return { deletedDmnEdgeOnCurrentDrd };
 }
diff --git a/packages/dmn-editor/src/mutations/deleteNode.ts b/packages/dmn-editor/src/mutations/deleteNode.ts
index ab7898262c9..363fd2f4627 100644
--- a/packages/dmn-editor/src/mutations/deleteNode.ts
+++ b/packages/dmn-editor/src/mutations/deleteNode.ts
@@ -17,65 +17,174 @@
  * under the License.
  */
 
-import { DMN15__tDefinitions } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { DMN15__tDefinitions, DMNDI15__DMNShape } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { NodeNature } from "./NodeNature";
 import { addOrGetDrd } from "./addOrGetDrd";
 import { repopulateInputDataAndDecisionsOnAllDecisionServices } from "./repopulateInputDataAndDecisionsOnDecisionService";
 import { XmlQName, buildXmlQName } from "@kie-tools/xml-parser-ts/dist/qNames";
 import { getNewDmnIdRandomizer } from "../idRandomizer/dmnIdRandomizer";
+import { buildXmlHref } from "../xml/xmlHrefs";
+import { Unpacked } from "../tsExt/tsExt";
+import { DrgEdge } from "../diagram/graph/graph";
+import { EdgeDeletionMode, deleteEdge } from "./deleteEdge";
+
+export enum NodeDeletionMode {
+  FORM_DRG_AND_ALL_DRDS,
+  FROM_CURRENT_DRD_ONLY,
+}
 
 export function deleteNode({
   definitions,
+  drgEdges,
   drdIndex,
   nodeNature,
   dmnObjectId,
   dmnObjectQName,
+  dmnObjectNamespace,
+  mode,
 }: {
   definitions: DMN15__tDefinitions;
+  drgEdges: DrgEdge[];
   drdIndex: number;
   nodeNature: NodeNature;
+  dmnObjectNamespace: string | undefined;
   dmnObjectId: string | undefined;
   dmnObjectQName: XmlQName;
-}) {
-  const { diagramElements, widthsExtension } = addOrGetDrd({ definitions, drdIndex });
+  mode: NodeDeletionMode;
+}): {
+  deletedDmnObject: Unpacked<DMN15__tDefinitions["drgElement" | "artifact"]> | undefined;
+  deletedDmnShapeOnCurrentDrd: DMNDI15__DMNShape | undefined;
+} {
+  if (
+    mode === NodeDeletionMode.FROM_CURRENT_DRD_ONLY &&
+    !canRemoveNodeFromDrdOnly({
+      definitions,
+      drdIndex,
+      dmnObjectNamespace,
+      dmnObjectId,
+    })
+  ) {
+    console.warn("DMN MUTATION: Cannot hide a Decision that's contained by a Decision Service from a DRD.");
+    return { deletedDmnObject: undefined, deletedDmnShapeOnCurrentDrd: undefined };
+  }
 
-  // Edges need to be deleted by a separate call to `deleteEdge` prior to this.
+  // 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.
+  if (mode === NodeDeletionMode.FORM_DRG_AND_ALL_DRDS) {
+    const nodeId = buildXmlHref({ namespace: dmnObjectNamespace, id: dmnObjectId! });
+    for (let i = 0; i < drgEdges.length; i++) {
+      const drgEdge = drgEdges[i];
+      // Only delete edges that end at or start from the node being deleted.
+      if (drgEdge.sourceId === nodeId || drgEdge.targetId === nodeId) {
+        deleteEdge({
+          definitions,
+          drdIndex,
+          mode: EdgeDeletionMode.FORM_DRG_AND_ALL_DRDS,
+          edge: {
+            id: drgEdge.id,
+            dmnObject: drgEdge.dmnObject,
+          },
+        });
+      }
+    }
+  }
 
-  // delete the DMNShape
-  const shapeDmnElementRef = buildXmlQName(dmnObjectQName);
-  diagramElements?.splice(
-    (diagramElements ?? []).findIndex((d) => d["@_dmnElementRef"] === shapeDmnElementRef),
-    1
-  );
+  let dmnObject: Unpacked<DMN15__tDefinitions["drgElement" | "artifact"]> | undefined;
 
   // External or unknown nodes don't have a dmnObject associated with it, just the shape..
   if (!dmnObjectQName.prefix) {
     // Delete the dmnObject itself
     if (nodeNature === NodeNature.ARTIFACT) {
-      definitions.artifact?.splice(
-        (definitions.artifact ?? []).findIndex((a) => a["@_id"] === dmnObjectId),
-        1
-      );
+      if (mode === NodeDeletionMode.FORM_DRG_AND_ALL_DRDS) {
+        const nodeIndex = (definitions.artifact ?? []).findIndex((a) => a["@_id"] === dmnObjectId);
+        dmnObject = definitions.artifact?.splice(nodeIndex, 1)?.[0];
+      }
     } else if (nodeNature === NodeNature.DRG_ELEMENT) {
-      const deleted = definitions.drgElement?.splice(
-        (definitions.drgElement ?? []).findIndex((d) => d["@_id"] === dmnObjectId),
-        1
-      );
-
-      const deletedIdsOnDrgElementTree = getNewDmnIdRandomizer()
-        .ack({ json: deleted, type: "DMN15__tDefinitions", attr: "drgElement" })
-        .getOriginalIds();
-
-      // Delete widths
-      widthsExtension["kie:ComponentWidths"] = widthsExtension["kie:ComponentWidths"]?.filter(
-        (w) => !deletedIdsOnDrgElementTree.has(w["@_dmnElementRef"]!)
-      );
+      const nodeIndex = (definitions.drgElement ?? []).findIndex((d) => d["@_id"] === dmnObjectId);
+      dmnObject =
+        mode === NodeDeletionMode.FORM_DRG_AND_ALL_DRDS
+          ? definitions.drgElement?.splice(nodeIndex, 1)?.[0]
+          : definitions.drgElement?.[nodeIndex];
     } else if (nodeNature === NodeNature.UNKNOWN) {
       // Ignore. There's no dmnObject here.
     } else {
       throw new Error(`Unknown node nature '${nodeNature}'.`);
     }
+
+    if (!dmnObject) {
+      throw new Error(`DMN MUTATION: Can't delete DMN object that doesn't exist: ID=${dmnObjectId}`);
+    }
+  }
+
+  const shapeDmnElementRef = buildXmlQName(dmnObjectQName);
+
+  // Deleting the DMNShape's
+  let deletedDmnShapeOnCurrentDrd: DMNDI15__DMNShape | undefined;
+
+  const deletedIdsOnDmnObjectTree = dmnObject
+    ? getNewDmnIdRandomizer()
+        .ack({ json: [dmnObject], type: "DMN15__tDefinitions", attr: "drgElement" })
+        .getOriginalIds()
+    : new Set<string>();
+
+  const drdCount = (definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"] ?? []).length;
+  for (let i = 0; i < drdCount; i++) {
+    if (mode === NodeDeletionMode.FROM_CURRENT_DRD_ONLY && i !== drdIndex) {
+      continue;
+    }
+
+    const { diagramElements, widthsExtension } = addOrGetDrd({ definitions, drdIndex: i });
+    const dmnShapeIndex = (diagramElements ?? []).findIndex((d) => d["@_dmnElementRef"] === shapeDmnElementRef);
+    if (dmnShapeIndex >= 0) {
+      if (i === drdIndex) {
+        deletedDmnShapeOnCurrentDrd = diagramElements[dmnShapeIndex];
+      }
+
+      diagramElements?.splice(dmnShapeIndex, 1);
+    }
+
+    // Delete widths
+    widthsExtension["kie:ComponentWidths"] = widthsExtension["kie:ComponentWidths"]?.filter(
+      (w) => !deletedIdsOnDmnObjectTree.has(w["@_dmnElementRef"]!) // Only works because xsd:IDs are exactly the same as QNames when the QName is not prefixed.
+    );
   }
 
   repopulateInputDataAndDecisionsOnAllDecisionServices({ definitions });
+
+  return {
+    deletedDmnObject: mode === NodeDeletionMode.FORM_DRG_AND_ALL_DRDS ? dmnObject : undefined,
+    deletedDmnShapeOnCurrentDrd,
+  };
+}
+
+export function canRemoveNodeFromDrdOnly({
+  definitions,
+  drdIndex,
+  dmnObjectNamespace,
+  dmnObjectId,
+}: {
+  dmnObjectNamespace: string | undefined;
+  dmnObjectId: string | undefined;
+  definitions: DMN15__tDefinitions;
+  drdIndex: number;
+}) {
+  const { diagramElements } = addOrGetDrd({ definitions, drdIndex });
+
+  const dmnObjectHref = buildXmlHref({ namespace: dmnObjectNamespace, id: dmnObjectId! });
+
+  const containingDecisionService = definitions.drgElement?.find(
+    (drgElement) =>
+      drgElement.__$$element === "decisionService" &&
+      [...(drgElement.encapsulatedDecision ?? []), ...(drgElement.outputDecision ?? [])].some(
+        (dd) => dd["@_href"] === dmnObjectHref
+      )
+  );
+
+  const isContainingDecisionServicePresentInTheDrd =
+    containingDecisionService &&
+    diagramElements.some(
+      (s) =>
+        s.__$$element === "dmndi:DMNShape" &&
+        s["@_dmnElementRef"] === buildXmlQName({ type: "xml-qname", localPart: containingDecisionService["@_id"]! })
+    );
+  return !containingDecisionService || !isContainingDecisionServicePresentInTheDrd;
 }
diff --git a/packages/dmn-editor/src/overlaysPanel/OverlaysPanel.tsx b/packages/dmn-editor/src/overlaysPanel/OverlaysPanel.tsx
index 38929f3b82b..f964ee90256 100644
--- a/packages/dmn-editor/src/overlaysPanel/OverlaysPanel.tsx
+++ b/packages/dmn-editor/src/overlaysPanel/OverlaysPanel.tsx
@@ -22,7 +22,7 @@ import { Switch } from "@patternfly/react-core/dist/js/components/Switch";
 import { Form, FormGroup } from "@patternfly/react-core/dist/js/components/Form";
 import { Divider } from "@patternfly/react-core/dist/js/components/Divider";
 import { Slider } from "@patternfly/react-core/dist/js/components/Slider";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 
 const MIN_SNAP = 5;
 const MAX_SNAP = 50;
@@ -115,17 +115,6 @@ export function OverlaysPanel() {
             }
           />
         </FormGroup>
-        {/* <FormGroup label={"Custom node styles"}>
-          <Switch
-            aria-label={"ustom node styles"}
-            isChecked={diagram.overlays.enableCustomNodeStyles}
-            onChange={(newValue) =>
-              dmnEditorStoreApi.setState((state) => {
-                state.diagram.overlays.enableCustomNodeStyles = newValue;
-              })
-            }
-          />
-        </FormGroup> */}
         <FormGroup label={"Show data type toolbar on nodes"}>
           <Switch
             aria-label={"Show data type toolbar on nodes"}
@@ -140,10 +129,10 @@ export function OverlaysPanel() {
         <FormGroup label={"Enable styles"}>
           <Switch
             aria-label={"Show data type toolbar on nodes"}
-            isChecked={diagram.overlays.enableStyles}
+            isChecked={diagram.overlays.enableCustomNodeStyles}
             onChange={(newValue) =>
               dmnEditorStoreApi.setState((state) => {
-                state.diagram.overlays.enableStyles = newValue;
+                state.diagram.overlays.enableCustomNodeStyles = newValue;
               })
             }
           />
diff --git a/packages/dmn-editor/src/propertiesPanel/BeePropertiesPanel.tsx b/packages/dmn-editor/src/propertiesPanel/BeePropertiesPanel.tsx
index de9b031d68b..1321b95629b 100644
--- a/packages/dmn-editor/src/propertiesPanel/BeePropertiesPanel.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/BeePropertiesPanel.tsx
@@ -24,26 +24,30 @@ import {
   DrawerHead,
   DrawerPanelContent,
 } from "@patternfly/react-core/dist/js/components/Drawer";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { useMemo } from "react";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { buildXmlHref } from "../xml/xmlHrefs";
 import { SingleNodeProperties } from "./SingleNodeProperties";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 export function BeePropertiesPanel() {
   const dmnEditorStoreApi = useDmnEditorStoreApi();
   const { selectedObjectId, activeDrgElementId } = useDmnEditorStore((s) => s.boxedExpressionEditor);
-  const { nodesById } = useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
+  const node = useDmnEditorStore((s) =>
+    activeDrgElementId
+      ? s
+          .computed(s)
+          .getDiagramData(externalModelsByNamespace)
+          .nodesById.get(buildXmlHref({ id: activeDrgElementId }))
+      : undefined
+  );
 
   const shouldDisplayDecisionOrBkmProps = useMemo(
     () => selectedObjectId === undefined || (selectedObjectId && selectedObjectId === activeDrgElementId),
     [activeDrgElementId, selectedObjectId]
   );
 
-  const node = useMemo(() => {
-    return activeDrgElementId ? nodesById.get(buildXmlHref({ id: activeDrgElementId })) : undefined;
-  }, [activeDrgElementId, nodesById]);
-
   return (
     <>
       {node && (
diff --git a/packages/dmn-editor/src/propertiesPanel/BkmProperties.tsx b/packages/dmn-editor/src/propertiesPanel/BkmProperties.tsx
index dd346dcfc25..1383fe45b67 100644
--- a/packages/dmn-editor/src/propertiesPanel/BkmProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/BkmProperties.tsx
@@ -24,12 +24,12 @@ import { FormGroup } from "@patternfly/react-core/dist/js/components/Form";
 import { TextArea } from "@patternfly/react-core/dist/js/components/TextArea";
 import { DocumentationLinksFormGroup } from "./DocumentationLinksFormGroup";
 import { TypeRefSelector } from "../dataTypes/TypeRefSelector";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { renameDrgElement } from "../mutations/renameNode";
 import { InlineFeelNameInput } from "../feel/InlineFeelNameInput";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { useDmnEditor } from "../DmnEditorContext";
 import { useResolvedTypeRef } from "../dataTypes/useResolvedTypeRef";
+import { useCallback } from "react";
 
 export function BkmProperties({
   bkm,
@@ -45,7 +45,6 @@ export function BkmProperties({
   const thisDmnsNamespace = useDmnEditorStore((s) => s.dmn.model.definitions["@_namespace"]);
   const isReadonly = !!namespace && namespace !== thisDmnsNamespace;
 
-  const { allFeelVariableUniqueNames } = useDmnEditorDerivedStore();
   const { dmnEditorRootElementRef } = useDmnEditor();
 
   const resolvedTypeRef = useResolvedTypeRef(bkm.variable?.["@_typeRef"], namespace);
@@ -70,7 +69,7 @@ export function BkmProperties({
               });
             });
           }}
-          allUniqueNames={allFeelVariableUniqueNames}
+          allUniqueNames={useCallback((s) => s.computed(s).getAllFeelVariableUniqueNames(), [])}
         />
       </FormGroup>
 
diff --git a/packages/dmn-editor/src/propertiesPanel/DecisionProperties.tsx b/packages/dmn-editor/src/propertiesPanel/DecisionProperties.tsx
index ccb6ed3a04d..4a571eb9cb0 100644
--- a/packages/dmn-editor/src/propertiesPanel/DecisionProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/DecisionProperties.tsx
@@ -24,12 +24,12 @@ import { FormGroup } from "@patternfly/react-core/dist/js/components/Form";
 import { TextArea } from "@patternfly/react-core/dist/js/components/TextArea";
 import { DocumentationLinksFormGroup } from "./DocumentationLinksFormGroup";
 import { TypeRefSelector } from "../dataTypes/TypeRefSelector";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { renameDrgElement } from "../mutations/renameNode";
 import { InlineFeelNameInput } from "../feel/InlineFeelNameInput";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { useDmnEditor } from "../DmnEditorContext";
 import { useResolvedTypeRef } from "../dataTypes/useResolvedTypeRef";
+import { useCallback } from "react";
 
 export function DecisionProperties({
   decision,
@@ -45,8 +45,6 @@ export function DecisionProperties({
   const thisDmnsNamespace = useDmnEditorStore((s) => s.dmn.model.definitions["@_namespace"]);
   const isReadonly = !!namespace && namespace !== thisDmnsNamespace;
 
-  const { allFeelVariableUniqueNames } = useDmnEditorDerivedStore();
-
   const { dmnEditorRootElementRef } = useDmnEditor();
 
   const resolvedTypeRef = useResolvedTypeRef(decision.variable?.["@_typeRef"], namespace);
@@ -71,7 +69,7 @@ export function DecisionProperties({
               });
             });
           }}
-          allUniqueNames={allFeelVariableUniqueNames}
+          allUniqueNames={useCallback((s) => s.computed(s).getAllFeelVariableUniqueNames(), [])}
         />
       </FormGroup>
 
diff --git a/packages/dmn-editor/src/propertiesPanel/DecisionServiceProperties.tsx b/packages/dmn-editor/src/propertiesPanel/DecisionServiceProperties.tsx
index 9c839201f64..3ae80477c27 100644
--- a/packages/dmn-editor/src/propertiesPanel/DecisionServiceProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/DecisionServiceProperties.tsx
@@ -28,16 +28,16 @@ import { FormGroup } from "@patternfly/react-core/dist/js/components/Form";
 import { TextArea } from "@patternfly/react-core/dist/js/components/TextArea";
 import { DocumentationLinksFormGroup } from "./DocumentationLinksFormGroup";
 import { TypeRefSelector } from "../dataTypes/TypeRefSelector";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
-import { useMemo } from "react";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
+import { useCallback, useMemo } from "react";
 import { buildXmlHref, parseXmlHref } from "../xml/xmlHrefs";
 import { DmnObjectListItem } from "../externalNodes/DmnObjectListItem";
 import { renameDrgElement } from "../mutations/renameNode";
 import { InlineFeelNameInput } from "../feel/InlineFeelNameInput";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { Divider } from "@patternfly/react-core/dist/js/components/Divider";
 import { useDmnEditor } from "../DmnEditorContext";
 import { useResolvedTypeRef } from "../dataTypes/useResolvedTypeRef";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 export type AllKnownDrgElementsByHref = Map<
   string,
@@ -56,7 +56,10 @@ export function DecisionServiceProperties({
   const { setState } = useDmnEditorStoreApi();
 
   const thisDmn = useDmnEditorStore((s) => s.dmn);
-  const { externalDmnsByNamespace, allFeelVariableUniqueNames } = useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
+  const externalDmnsByNamespace = useDmnEditorStore(
+    (s) => s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).dmns
+  );
 
   const allDrgElementsByHref = useMemo(() => {
     const ret: AllKnownDrgElementsByHref = new Map();
@@ -107,7 +110,7 @@ export function DecisionServiceProperties({
               });
             });
           }}
-          allUniqueNames={allFeelVariableUniqueNames}
+          allUniqueNames={useCallback((s) => s.computed(s).getAllFeelVariableUniqueNames(), [])}
         />
       </FormGroup>
 
diff --git a/packages/dmn-editor/src/propertiesPanel/DiagramPropertiesPanel.tsx b/packages/dmn-editor/src/propertiesPanel/DiagramPropertiesPanel.tsx
index 0c87e4b5111..2a6992c4302 100644
--- a/packages/dmn-editor/src/propertiesPanel/DiagramPropertiesPanel.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/DiagramPropertiesPanel.tsx
@@ -21,13 +21,17 @@ import * as React from "react";
 
 import { DrawerHead, DrawerPanelContent } from "@patternfly/react-core/dist/js/components/Drawer";
 import { GlobalDiagramProperties } from "./GlobalDiagramProperties";
-import "./DiagramPropertiesPanel.css";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { SingleNodeProperties } from "./SingleNodeProperties";
 import { MultipleNodeProperties } from "./MultipleNodeProperties";
+import { useDmnEditorStore } from "../store/StoreContext";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
+import "./DiagramPropertiesPanel.css";
 
 export function DiagramPropertiesPanel() {
-  const { selectedNodesById } = useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
+  const selectedNodesById = useDmnEditorStore(
+    (s) => s.computed(s).getDiagramData(externalModelsByNamespace).selectedNodesById
+  );
 
   return (
     <DrawerPanelContent
diff --git a/packages/dmn-editor/src/propertiesPanel/DocumentationLinksFormGroup.tsx b/packages/dmn-editor/src/propertiesPanel/DocumentationLinksFormGroup.tsx
index ce7c1699f10..b0deae57865 100644
--- a/packages/dmn-editor/src/propertiesPanel/DocumentationLinksFormGroup.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/DocumentationLinksFormGroup.tsx
@@ -19,7 +19,6 @@
 
 import * as React from "react";
 import { useMemo, useState, useCallback, useRef, useEffect } from "react";
-import "./DocumentationLinksFormGroup.css";
 import { KIE__tAttachment } from "@kie-tools/dmn-marshaller/dist/schemas/kie-1_0/ts-gen/types";
 import { Namespaced } from "@kie-tools/xml-parser-ts";
 import { Text, TextVariants } from "@patternfly/react-core/dist/js/components/Text";
@@ -33,6 +32,7 @@ import { AngleRightIcon } from "@patternfly/react-icons/dist/js/icons/angle-righ
 import { InlineFeelNameInput, invalidInlineFeelNameStyle } from "../feel/InlineFeelNameInput";
 import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
 import { Draggable, DragAndDrop, useDraggableItemContext } from "../draggable/Draggable";
+import "./DocumentationLinksFormGroup.css";
 
 const PLACEHOLDER_URL_TITLE = "Enter a title...";
 const PLACEHOLDER_URL = "http://";
@@ -374,7 +374,7 @@ function DocumentationLinksInput({
                   // reset the changedByToogle
                   updatedOnToogle.current = false;
                 }}
-                allUniqueNames={allUniqueNames}
+                allUniqueNames={() => allUniqueNames}
                 validate={validateTitle}
                 autoFocus={parentAutoFocus || autoFocus}
                 onKeyDown={(e) => {
@@ -400,7 +400,7 @@ function DocumentationLinksInput({
                   // reset the changedByToogle
                   updatedOnToogle.current = false;
                 }}
-                allUniqueNames={allUniqueNames}
+                allUniqueNames={() => allUniqueNames}
                 validate={validateUrl}
                 saveInvalidValue={true}
                 onKeyDown={(e) => {
diff --git a/packages/dmn-editor/src/propertiesPanel/FontOptions.tsx b/packages/dmn-editor/src/propertiesPanel/FontOptions.tsx
index 26fd6f9854f..d8ba5278f6c 100644
--- a/packages/dmn-editor/src/propertiesPanel/FontOptions.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/FontOptions.tsx
@@ -22,7 +22,8 @@ import { useState, useMemo, useCallback, useEffect } from "react";
 import { FormSection } from "@patternfly/react-core/dist/js/components/Form";
 import { PencilAltIcon } from "@patternfly/react-icons/dist/js/icons/pencil-alt-icon";
 import { PropertiesPanelHeader } from "./PropertiesPanelHeader";
-import { State, useDmnEditorStoreApi } from "../store/Store";
+import { State } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { NumberInput } from "@patternfly/react-core/dist/js/components/NumberInput";
 import { DMNDI15__DMNShape } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { addOrGetDrd } from "../mutations/addOrGetDrd";
@@ -30,12 +31,11 @@ import { ToggleGroup, ToggleGroupItem } from "@patternfly/react-core/dist/js/com
 import { Select, SelectVariant, SelectOption } from "@patternfly/react-core/dist/js/components/Select";
 import { useInViewSelect } from "../responsiveness/useInViewSelect";
 import { useDmnEditor } from "../DmnEditorContext";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
-import "./FontOptions.css";
 import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button";
 import { UndoAltIcon } from "@patternfly/react-icons/dist/js/icons/undo-alt-icon";
 import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip";
 import { ColorPicker } from "./ColorPicker";
+import "./FontOptions.css";
 
 // https://www.w3schools.com/cssref/css_websafe_fonts.php
 // Array of [name, family]
@@ -67,7 +67,7 @@ export function FontOptions({ startExpanded, nodeIds }: { startExpanded: boolean
   const dmnEditorStoreApi = useDmnEditorStoreApi();
   const [isStyleSectionExpanded, setStyleSectionExpanded] = useState<boolean>(startExpanded);
 
-  const { dmnShapesByHref } = useDmnEditorDerivedStore();
+  const dmnShapesByHref = useDmnEditorStore((s) => s.computed(s).indexes().dmnShapesByHref);
   const shapes = useMemo(() => nodeIds.map((nodeId) => dmnShapesByHref.get(nodeId)), [dmnShapesByHref, nodeIds]);
   const shapesStyle = useMemo(() => shapes.map((shape) => shape?.["di:Style"]), [shapes]);
 
@@ -208,7 +208,7 @@ export function FontOptions({ startExpanded, nodeIds }: { startExpanded: boolean
     (newColor: string) => {
       setTemporaryFontColor(newColor.replace("#", ""));
       editShapeStyle((shapes, state) => {
-        state!.diagram.editingStyle = true;
+        state!.diagram.isEditingStyle = true;
       });
     },
     [editShapeStyle]
@@ -226,7 +226,7 @@ export function FontOptions({ startExpanded, nodeIds }: { startExpanded: boolean
             green !== shape?.["di:Style"]?.["dmndi:FontColor"]?.["@_green"] &&
             blue !== shape?.["di:Style"]?.["dmndi:FontColor"]?.["@_blue"]
           ) {
-            state!.diagram.editingStyle = false;
+            state!.diagram.isEditingStyle = false;
             shape!["di:Style"]!["dmndi:FontColor"] ??= { "@_blue": 0, "@_green": 0, "@_red": 0 };
             shape!["di:Style"]!["dmndi:FontColor"]["@_red"] = red;
             shape!["di:Style"]!["dmndi:FontColor"]["@_green"] = green;
@@ -243,7 +243,7 @@ export function FontOptions({ startExpanded, nodeIds }: { startExpanded: boolean
   const onReset = useCallback(() => {
     setTemporaryFontColor("000000");
     editShapeStyle((shapes, state) => {
-      state!.diagram.editingStyle = false;
+      state!.diagram.isEditingStyle = false;
       shapes.forEach((shape) => {
         shape["di:Style"]!["@_fontBold"] = undefined;
         shape["di:Style"]!["@_fontItalic"] = undefined;
diff --git a/packages/dmn-editor/src/propertiesPanel/GlobalDiagramProperties.tsx b/packages/dmn-editor/src/propertiesPanel/GlobalDiagramProperties.tsx
index e5091ffb5c7..cf12d52da12 100644
--- a/packages/dmn-editor/src/propertiesPanel/GlobalDiagramProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/GlobalDiagramProperties.tsx
@@ -23,7 +23,7 @@ import { Form, FormSection, FormGroup } from "@patternfly/react-core/dist/js/com
 import { TextArea } from "@patternfly/react-core/dist/js/components/TextArea";
 import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput";
 import { DataSourceIcon } from "@patternfly/react-icons/dist/js/icons/data-source-icon";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { InlineFeelNameInput } from "../feel/InlineFeelNameInput";
 import { useState } from "react";
 import { Modal, ModalVariant } from "@patternfly/react-core/dist/js/components/Modal";
@@ -85,7 +85,7 @@ export function GlobalDiagramProperties() {
                       state.dmn.model.definitions["@_name"] = newName;
                     });
                   }}
-                  allUniqueNames={new Map()} // Right now, there's no way to know what are the unique names of all DMNs in the scope. So we let any name go.
+                  allUniqueNames={() => new Map()} // Right now, there's no way to know what are the unique names of all DMNs in the scope. So we let any name go.
                 />
               </FormGroup>
               <FormGroup label="Description">
diff --git a/packages/dmn-editor/src/propertiesPanel/GroupProperties.tsx b/packages/dmn-editor/src/propertiesPanel/GroupProperties.tsx
index 29c4480a267..3e4f20bded7 100644
--- a/packages/dmn-editor/src/propertiesPanel/GroupProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/GroupProperties.tsx
@@ -23,7 +23,7 @@ import { ClipboardCopy } from "@patternfly/react-core/dist/js/components/Clipboa
 import { FormGroup } from "@patternfly/react-core/dist/js/components/Form";
 import { TextArea } from "@patternfly/react-core/dist/js/components/TextArea";
 import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput";
-import { useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStoreApi } from "../store/StoreContext";
 import { renameGroupNode } from "../mutations/renameNode";
 
 export function GroupProperties({ group, index }: { group: DMN15__tGroup; index: number }) {
diff --git a/packages/dmn-editor/src/propertiesPanel/InputDataProperties.tsx b/packages/dmn-editor/src/propertiesPanel/InputDataProperties.tsx
index 1ebe6abd1f0..8a5d8b7c0d4 100644
--- a/packages/dmn-editor/src/propertiesPanel/InputDataProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/InputDataProperties.tsx
@@ -24,12 +24,12 @@ import { FormGroup } from "@patternfly/react-core/dist/js/components/Form";
 import { TextArea } from "@patternfly/react-core/dist/js/components/TextArea";
 import { DocumentationLinksFormGroup } from "./DocumentationLinksFormGroup";
 import { TypeRefSelector } from "../dataTypes/TypeRefSelector";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { renameDrgElement } from "../mutations/renameNode";
 import { InlineFeelNameInput } from "../feel/InlineFeelNameInput";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { useDmnEditor } from "../DmnEditorContext";
 import { useResolvedTypeRef } from "../dataTypes/useResolvedTypeRef";
+import { useCallback } from "react";
 
 export function InputDataProperties({
   inputData,
@@ -45,8 +45,6 @@ export function InputDataProperties({
   const thisDmnsNamespace = useDmnEditorStore((s) => s.dmn.model.definitions["@_namespace"]);
   const isReadonly = !!namespace && namespace !== thisDmnsNamespace;
 
-  const { allFeelVariableUniqueNames } = useDmnEditorDerivedStore();
-
   const { dmnEditorRootElementRef } = useDmnEditor();
 
   const resolvedTypeRef = useResolvedTypeRef(inputData.variable?.["@_typeRef"], namespace);
@@ -71,7 +69,7 @@ export function InputDataProperties({
               });
             });
           }}
-          allUniqueNames={allFeelVariableUniqueNames}
+          allUniqueNames={useCallback((s) => s.computed(s).getAllFeelVariableUniqueNames(), [])}
         />
       </FormGroup>
       <FormGroup label="Data type">
diff --git a/packages/dmn-editor/src/propertiesPanel/KnowledgeSourceProperties.tsx b/packages/dmn-editor/src/propertiesPanel/KnowledgeSourceProperties.tsx
index 401333ac07f..36af3c30a17 100644
--- a/packages/dmn-editor/src/propertiesPanel/KnowledgeSourceProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/KnowledgeSourceProperties.tsx
@@ -24,10 +24,10 @@ import { FormGroup } from "@patternfly/react-core/dist/js/components/Form";
 import { TextArea } from "@patternfly/react-core/dist/js/components/TextArea";
 import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput";
 import { DocumentationLinksFormGroup } from "./DocumentationLinksFormGroup";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { renameDrgElement } from "../mutations/renameNode";
 import { InlineFeelNameInput } from "../feel/InlineFeelNameInput";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
+import { useCallback } from "react";
 
 export function KnowledgeSourceProperties({
   knowledgeSource,
@@ -43,8 +43,6 @@ export function KnowledgeSourceProperties({
   const thisDmnsNamespace = useDmnEditorStore((s) => s.dmn.model.definitions["@_namespace"]);
   const isReadonly = !!namespace && namespace !== thisDmnsNamespace;
 
-  const { allFeelVariableUniqueNames } = useDmnEditorDerivedStore();
-
   return (
     <>
       <FormGroup label="Name">
@@ -65,7 +63,7 @@ export function KnowledgeSourceProperties({
               });
             });
           }}
-          allUniqueNames={allFeelVariableUniqueNames}
+          allUniqueNames={useCallback((s) => s.computed(s).getAllFeelVariableUniqueNames(), [])}
         />
       </FormGroup>
 
diff --git a/packages/dmn-editor/src/propertiesPanel/MultipleNodeProperties.tsx b/packages/dmn-editor/src/propertiesPanel/MultipleNodeProperties.tsx
index 75fcf33c9c1..31815bc8aad 100644
--- a/packages/dmn-editor/src/propertiesPanel/MultipleNodeProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/MultipleNodeProperties.tsx
@@ -23,7 +23,7 @@ import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
 import { Form, FormSection } from "@patternfly/react-core/dist/js/components/Form";
 import { Text, TextContent, TextVariants } from "@patternfly/react-core/dist/js/components/Text";
 import { FontOptions } from "./FontOptions";
-import { useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStoreApi } from "../store/StoreContext";
 import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button";
 import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
 import { Truncate } from "@patternfly/react-core/dist/js/components/Truncate";
diff --git a/packages/dmn-editor/src/propertiesPanel/ShapeOptions.tsx b/packages/dmn-editor/src/propertiesPanel/ShapeOptions.tsx
index 78d3c6f7ac2..0b0bbdcb786 100644
--- a/packages/dmn-editor/src/propertiesPanel/ShapeOptions.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/ShapeOptions.tsx
@@ -23,9 +23,9 @@ import { FormGroup, FormSection } from "@patternfly/react-core/dist/js/component
 import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput";
 import { CubeIcon } from "@patternfly/react-icons/dist/js/icons/cube-icon";
 import { PropertiesPanelHeader } from "./PropertiesPanelHeader";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { DC__Bounds, DMNDI15__DMNShape } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
-import { State, useDmnEditorStoreApi } from "../store/Store";
+import { State } from "../store/Store";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { addOrGetDrd } from "../mutations/addOrGetDrd";
 import { ArrowsAltVIcon } from "@patternfly/react-icons/dist/js/icons/arrows-alt-v-icon";
 import { ArrowsAltHIcon } from "@patternfly/react-icons/dist/js/icons/arrows-alt-h-icon";
@@ -34,7 +34,6 @@ import UndoAltIcon from "@patternfly/react-icons/dist/js/icons/undo-alt-icon";
 import { ColorPicker } from "./ColorPicker";
 import { ToggleGroup, ToggleGroupItem } from "@patternfly/react-core/dist/js/components/ToggleGroup";
 import "./ShapeOptions.css";
-import { Color } from "../diagram/nodes/NodeStyle";
 
 export function ShapeOptions({
   startExpanded,
@@ -49,7 +48,7 @@ export function ShapeOptions({
 }) {
   const [isShapeSectionExpanded, setShapeSectionExpanded] = useState<boolean>(startExpanded);
   const dmnEditorStoreApi = useDmnEditorStoreApi();
-  const { dmnShapesByHref } = useDmnEditorDerivedStore();
+  const dmnShapesByHref = useDmnEditorStore((s) => s.computed(s).indexes().dmnShapesByHref);
 
   const shapes = useMemo(() => nodeIds.map((nodeId) => dmnShapesByHref.get(nodeId)), [dmnShapesByHref, nodeIds]);
   // it only edits the first selected node
@@ -146,7 +145,7 @@ export function ShapeOptions({
     (newColor: string) => {
       setTemporaryStrokeColor(newColor.replace("#", ""));
       editShapeStyle((shapes, state) => {
-        state!.diagram.editingStyle = true;
+        state!.diagram.isEditingStyle = true;
       });
     },
     [editShapeStyle]
@@ -164,7 +163,7 @@ export function ShapeOptions({
             green !== shape?.["di:Style"]?.["dmndi:StrokeColor"]?.["@_green"] &&
             blue !== shape?.["di:Style"]?.["dmndi:StrokeColor"]?.["@_blue"]
           ) {
-            state!.diagram.editingStyle = false;
+            state!.diagram.isEditingStyle = false;
             shape!["di:Style"]!["dmndi:StrokeColor"] ??= { "@_blue": 0, "@_green": 0, "@_red": 0 };
             shape!["di:Style"]!["dmndi:StrokeColor"]["@_red"] = red;
             shape!["di:Style"]!["dmndi:StrokeColor"]["@_green"] = green;
@@ -183,7 +182,7 @@ export function ShapeOptions({
     (newColor: string) => {
       setTemporaryFillColor(newColor.replace("#", ""));
       editShapeStyle((shapes, state) => {
-        state!.diagram.editingStyle = true;
+        state!.diagram.isEditingStyle = true;
       });
     },
     [editShapeStyle]
@@ -201,7 +200,7 @@ export function ShapeOptions({
             green !== shape?.["di:Style"]?.["dmndi:FillColor"]?.["@_green"] &&
             blue !== shape?.["di:Style"]?.["dmndi:FillColor"]?.["@_blue"]
           ) {
-            state!.diagram.editingStyle = false;
+            state!.diagram.isEditingStyle = false;
             shape!["di:Style"]!["dmndi:FillColor"] ??= { "@_blue": 255, "@_green": 255, "@_red": 255 };
             shape!["di:Style"]!["dmndi:FillColor"]["@_red"] = red;
             shape!["di:Style"]!["dmndi:FillColor"]["@_green"] = green;
diff --git a/packages/dmn-editor/src/propertiesPanel/SingleNodeProperties.tsx b/packages/dmn-editor/src/propertiesPanel/SingleNodeProperties.tsx
index 182dfac85f9..cd258c487c5 100644
--- a/packages/dmn-editor/src/propertiesPanel/SingleNodeProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/SingleNodeProperties.tsx
@@ -30,8 +30,7 @@ import { DecisionServiceProperties } from "./DecisionServiceProperties";
 import { KnowledgeSourceProperties } from "./KnowledgeSourceProperties";
 import { TextAnnotationProperties } from "./TextAnnotationProperties";
 import { useMemo } from "react";
-import { useDmnEditorStoreApi } from "../store/Store";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
+import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/StoreContext";
 import { NODE_TYPES } from "../diagram/nodes/NodeTypes";
 import {
   DMN15__tBusinessKnowledgeModel,
@@ -49,17 +48,15 @@ import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components
 import { TimesIcon } from "@patternfly/react-icons/dist/js/icons/times-icon";
 import { PropertiesPanelHeader } from "./PropertiesPanelHeader";
 import { UnknownProperties } from "./UnknownProperties";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 import "./SingleNodeProperties.css";
 
 export function SingleNodeProperties({ nodeId }: { nodeId: string }) {
   const dmnEditorStoreApi = useDmnEditorStoreApi();
-  const { nodesById } = useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
+  const node = useDmnEditorStore((s) => s.computed(s).getDiagramData(externalModelsByNamespace).nodesById.get(nodeId));
   const [isSectionExpanded, setSectionExpanded] = useState<boolean>(true);
 
-  const node = useMemo(() => {
-    return nodesById.get(nodeId);
-  }, [nodeId, nodesById]);
-
   if (!node) {
     return <>Node not found: {nodeId}</>;
   }
diff --git a/packages/dmn-editor/src/propertiesPanel/TextAnnotationProperties.tsx b/packages/dmn-editor/src/propertiesPanel/TextAnnotationProperties.tsx
index 2151cf9e97e..574ab6c6733 100644
--- a/packages/dmn-editor/src/propertiesPanel/TextAnnotationProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/TextAnnotationProperties.tsx
@@ -23,7 +23,7 @@ import { ClipboardCopy } from "@patternfly/react-core/dist/js/components/Clipboa
 import { FormGroup } from "@patternfly/react-core/dist/js/components/Form";
 import { TextArea } from "@patternfly/react-core/dist/js/components/TextArea";
 import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput";
-import { useDmnEditorStoreApi } from "../store/Store";
+import { useDmnEditorStoreApi } from "../store/StoreContext";
 import { updateTextAnnotation } from "../mutations/renameNode";
 
 export function TextAnnotationProperties({
diff --git a/packages/dmn-editor/src/propertiesPanel/UnknownProperties.tsx b/packages/dmn-editor/src/propertiesPanel/UnknownProperties.tsx
index 73aea18a00b..a94148e4c3b 100644
--- a/packages/dmn-editor/src/propertiesPanel/UnknownProperties.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/UnknownProperties.tsx
@@ -20,19 +20,21 @@
 import * as React from "react";
 import { Alert, AlertVariant } from "@patternfly/react-core/dist/js/components/Alert/Alert";
 import { DMN15__tDefinitions, DMNDI15__DMNShape } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
-import { useDmnEditorStore } from "../store/Store";
+import { useDmnEditorStore } from "../store/StoreContext";
 import { useMemo } from "react";
 import { Unpacked } from "../tsExt/tsExt";
-import { useDmnEditorDerivedStore } from "../store/DerivedStore";
 import { XmlQName, buildXmlQName } from "@kie-tools/xml-parser-ts/dist/qNames";
 import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button";
 import { useDmnEditor } from "../DmnEditorContext";
 import { Divider } from "@patternfly/react-core/dist/js/components/Divider";
+import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
 
 export function UnknownProperties(props: { shape: DMNDI15__DMNShape; dmnElementRefQName: XmlQName }) {
   const thisDmn = useDmnEditorStore((s) => s.dmn);
-
-  const { externalDmnsByNamespace } = useDmnEditorDerivedStore();
+  const { externalModelsByNamespace } = useExternalModels();
+  const externalDmnsByNamespace = useDmnEditorStore(
+    (s) => s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).dmns
+  );
   const { onRequestToJumpToPath } = useDmnEditor();
 
   const content = useMemo(() => {
diff --git a/packages/dmn-editor/src/store/ComputedStateCache.ts b/packages/dmn-editor/src/store/ComputedStateCache.ts
new file mode 100644
index 00000000000..84d4b7c0644
--- /dev/null
+++ b/packages/dmn-editor/src/store/ComputedStateCache.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.
+ */
+
+export type TypeOrReturnType<T> = T extends (...args: any[]) => any ? ReturnType<T> : T;
+
+export type CacheEntry<T> = {
+  value: TypeOrReturnType<T> | undefined;
+  dependencies: readonly any[];
+};
+
+export type Cache<T> = {
+  [K in keyof T]: CacheEntry<T[K]>;
+};
+
+let r: number = 0;
+// let h: number = 0;
+// let m: number = 0;
+
+export class ComputedStateCache<T extends Record<string, any>> {
+  private readonly cache: Cache<T>;
+
+  constructor(initialValues: Cache<T>) {
+    this.cache = { ...initialValues };
+  }
+
+  public cached<K extends keyof T, D extends readonly any[]>(
+    key: K,
+    delegate: (...dependencies: D) => TypeOrReturnType<T[K]>,
+    dependencies: D
+  ): TypeOrReturnType<T[K]> {
+    r++;
+
+    const cachedDeps = this.cache[key]?.dependencies ?? [];
+
+    let depsAreEqual = cachedDeps.length === dependencies.length;
+    if (depsAreEqual) {
+      for (let i = 0; i < cachedDeps.length; i++) {
+        if (!Object.is(cachedDeps[i], dependencies[i])) {
+          depsAreEqual = false;
+        }
+      }
+    } else {
+      // console.debug(`${r}: COMPUTED STORE CACHE: (Miss) Deps don't have the same length... (${String(key)})`);
+    }
+
+    if (depsAreEqual) {
+      // console.debug(`${r}: COMPUTED STORE CACHE: Hit ${++h}! (${String(key)})`);
+      return this.cache[key].value!;
+    } else {
+      // console.debug(`${r}: COMPUTED STORE CACHE: (Miss) Deps have different values... (${String(key)})`);
+    }
+
+    // console.debug(`${r}: COMPUTED STORE CACHE: Miss (${++m}})... (${String(key)})`);
+
+    const v = delegate(...dependencies);
+    this.cache[key].dependencies = dependencies;
+    this.cache[key].value = v;
+    return v;
+  }
+}
diff --git a/packages/dmn-editor/src/store/DerivedStore.tsx b/packages/dmn-editor/src/store/DerivedStore.tsx
deleted file mode 100644
index b35b706fb1b..00000000000
--- a/packages/dmn-editor/src/store/DerivedStore.tsx
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * 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 * as RF from "reactflow";
-import { useMemo } from "react";
-import { isValidContainment as _isValidContainment } from "../diagram/connections/isValidContainment";
-import { NodeType } from "../diagram/connections/graphStructure";
-import { useDmnEditorStore } from "./Store";
-import { useDiagramData } from "./useDiagramData";
-import {
-  DMN15__tImport,
-  DMN15__tItemDefinition,
-  DMNDI15__DMNEdge,
-  DMNDI15__DMNShape,
-} from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
-import { DmnDiagramNodeData } from "../diagram/nodes/Nodes";
-import { DmnDiagramEdgeData } from "../diagram/edges/Edges";
-import { DataTypeIndex, DataType } from "../dataTypes/DataTypes";
-import { buildFeelQNameFromNamespace } from "../feel/buildFeelQName";
-import { useExternalModels } from "../includedModels/DmnEditorDependenciesContext";
-import { UniqueNameIndex } from "../Dmn15Spec";
-import { ExternalPmmlsIndex, ExternalDmnsIndex } from "../DmnEditor";
-import { builtInFeelTypeNames } from "../dataTypes/BuiltInFeelTypes";
-import { getNamespaceOfDmnImport } from "../includedModels/importNamespaces";
-
-export type DerivedStore = {
-  selectedNodeTypes: Set<NodeType>;
-  isDropTargetNodeValidForSelection: boolean;
-  isDiagramEditingInProgress: boolean;
-  nodes: RF.Node[];
-  edges: RF.Edge[];
-  nodesById: Map<string, RF.Node<DmnDiagramNodeData>>;
-  edgesById: Map<string, RF.Edge<DmnDiagramEdgeData>>;
-  selectedNodesById: Map<string, RF.Node<DmnDiagramNodeData>>;
-  selectedEdgesById: Map<string, RF.Edge<DmnDiagramEdgeData>>;
-  importsByNamespace: Map<string, DMN15__tImport>;
-  dataTypesTree: DataType[];
-  allDataTypesById: DataTypeIndex;
-  allTopLevelDataTypesByFeelName: DataTypeIndex;
-  dmnEdgesByDmnElementRef: Map<string, DMNDI15__DMNEdge & { index: number }>;
-  dmnShapesByHref: Map<string, DMNDI15__DMNShape & { index: number }>;
-  drgElementsWithoutVisualRepresentationOnCurrentDrd: string[];
-  allFeelVariableUniqueNames: UniqueNameIndex;
-  allTopLevelItemDefinitionUniqueNames: UniqueNameIndex;
-  externalDmnsByNamespace: ExternalDmnsIndex;
-  externalPmmlsByNamespace: ExternalPmmlsIndex;
-};
-
-const DmnEditorDerivedStoreContext = React.createContext<DerivedStore>({} as any);
-
-export function useDmnEditorDerivedStore() {
-  return React.useContext(DmnEditorDerivedStoreContext);
-}
-
-export function DmnEditorDerivedStoreContextProvider(props: React.PropsWithChildren<{}>) {
-  const diagram = useDmnEditorStore((s) => s.diagram);
-  const thisDmn = useDmnEditorStore((s) => s.dmn);
-  const thisDmnsImports = useMemo(() => thisDmn.model.definitions.import ?? [], [thisDmn.model.definitions.import]);
-
-  const thisDmnsImportsByNamespace = useMemo(() => {
-    const ret = new Map<string, DMN15__tImport>();
-    for (let i = 0; i < thisDmnsImports.length; i++) {
-      ret.set(thisDmnsImports[i]["@_namespace"], thisDmnsImports[i]);
-    }
-    return ret;
-  }, [thisDmnsImports]);
-
-  const { externalModelsByNamespace } = useExternalModels();
-
-  const { dmns: externalDmnsByNamespace, pmmls: externalPmmlsByNamespace } = useMemo<{
-    dmns: ExternalDmnsIndex;
-    pmmls: ExternalPmmlsIndex;
-  }>(() => {
-    return thisDmnsImports.reduce<{ dmns: ExternalDmnsIndex; pmmls: ExternalPmmlsIndex }>(
-      (acc, _import) => {
-        const externalModel = externalModelsByNamespace?.[getNamespaceOfDmnImport({ dmnImport: _import })];
-        if (!externalModel) {
-          console.warn(
-            `DMN DIAGRAM: Can't index external model with namespace '${_import["@_namespace"]}' because it doesn't exist on the external models list.`
-          );
-          return acc;
-        }
-
-        if (externalModel.type === "dmn") {
-          acc.dmns.set(_import["@_namespace"], externalModel);
-        } else if (externalModel.type === "pmml") {
-          acc.pmmls.set(_import["@_namespace"], externalModel);
-        } else {
-          console.warn("DMN EDITOR: Unknown external model type", externalModel);
-        }
-
-        return acc;
-      },
-      { dmns: new Map(), pmmls: new Map() }
-    );
-  }, [externalModelsByNamespace, thisDmnsImports]);
-
-  const {
-    nodes,
-    edges,
-    nodesById,
-    edgesById,
-    dmnEdgesByDmnElementRef,
-    dmnShapesByHref,
-    selectedNodesById,
-    selectedEdgesById,
-    selectedNodeTypes,
-    drgElementsWithoutVisualRepresentationOnCurrentDrd,
-  } = useDiagramData(externalDmnsByNamespace);
-
-  const { dataTypesTree, allDataTypesById, allTopLevelDataTypesByFeelName } = useMemo(() => {
-    const allDataTypesById: DataTypeIndex = new Map();
-    const allTopLevelDataTypesByFeelName: DataTypeIndex = new Map();
-
-    const externalDmnsDataTypeTree = [...externalDmnsByNamespace.values()].flatMap((externalDmn) => {
-      return buildDataTypesTree(
-        externalDmn.model.definitions.itemDefinition ?? [],
-        thisDmnsImportsByNamespace,
-        allDataTypesById,
-        allTopLevelDataTypesByFeelName,
-        undefined,
-        new Set(),
-        externalDmn.model.definitions["@_namespace"],
-        thisDmn.model.definitions["@_namespace"]
-      );
-    });
-
-    // Purposefully do thisDmn's after. This will make sure thisDmn's ItemDefintiions
-    // take precedence over any external ones imported to the default namespace.
-    const thisDmnsDataTypeTree = buildDataTypesTree(
-      thisDmn.model.definitions.itemDefinition ?? [],
-      thisDmnsImportsByNamespace,
-      allDataTypesById,
-      allTopLevelDataTypesByFeelName,
-      undefined,
-      new Set(),
-      thisDmn.model.definitions["@_namespace"],
-      thisDmn.model.definitions["@_namespace"]
-    );
-
-    return {
-      dataTypesTree: [...thisDmnsDataTypeTree, ...externalDmnsDataTypeTree],
-      allDataTypesById,
-      allTopLevelDataTypesByFeelName,
-    };
-  }, [externalDmnsByNamespace, thisDmn.model.definitions, thisDmnsImportsByNamespace]);
-
-  const allTopLevelItemDefinitionUniqueNames = useMemo(() => {
-    const ret: UniqueNameIndex = new Map();
-
-    for (const [k, v] of allTopLevelDataTypesByFeelName.entries()) {
-      ret.set(k, v.itemDefinition["@_id"]!);
-    }
-
-    for (const type of builtInFeelTypeNames) {
-      ret.set(type, type);
-    }
-
-    return ret;
-  }, [allTopLevelDataTypesByFeelName]);
-
-  const allFeelVariableUniqueNames = useMemo(() => {
-    const ret: UniqueNameIndex = new Map();
-
-    const drgElements = thisDmn.model.definitions.drgElement ?? [];
-    for (let i = 0; i < drgElements.length; i++) {
-      const drgElement = drgElements[i];
-      ret.set(drgElement["@_name"]!, drgElement["@_id"]!);
-    }
-
-    for (let i = 0; i < thisDmnsImports.length; i++) {
-      const _import = thisDmnsImports[i];
-      ret.set(_import["@_name"], _import["@_id"]!);
-    }
-
-    return ret;
-  }, [thisDmn.model.definitions.drgElement, thisDmnsImports]);
-
-  const isDropTargetNodeValidForSelection =
-    !!diagram.dropTargetNode &&
-    _isValidContainment({
-      nodeTypes: selectedNodeTypes,
-      inside: diagram.dropTargetNode.type as NodeType,
-      dmnObjectQName: diagram.dropTargetNode.data.dmnObjectQName,
-    });
-
-  const isDiagramEditingInProgress =
-    diagram.draggingNodes.length > 0 ||
-    diagram.resizingNodes.length > 0 ||
-    diagram.draggingWaypoints.length > 0 ||
-    diagram.movingDividerLines.length > 0 ||
-    diagram.editingStyle;
-
-  const value = useMemo(
-    () => ({
-      selectedNodeTypes,
-      isDropTargetNodeValidForSelection,
-      isDiagramEditingInProgress,
-      nodes,
-      edges,
-      nodesById,
-      edgesById,
-      selectedNodesById,
-      selectedEdgesById,
-      importsByNamespace: thisDmnsImportsByNamespace,
-      dmnEdgesByDmnElementRef,
-      dmnShapesByHref,
-      dataTypesTree,
-      allDataTypesById,
-      allTopLevelDataTypesByFeelName,
-      allFeelVariableUniqueNames,
-      allTopLevelItemDefinitionUniqueNames,
-      externalDmnsByNamespace,
-      externalPmmlsByNamespace,
-      drgElementsWithoutVisualRepresentationOnCurrentDrd,
-    }),
-    [
-      selectedNodeTypes,
-      isDropTargetNodeValidForSelection,
-      isDiagramEditingInProgress,
-      nodes,
-      edges,
-      nodesById,
-      edgesById,
-      selectedNodesById,
-      selectedEdgesById,
-      thisDmnsImportsByNamespace,
-      dmnEdgesByDmnElementRef,
-      dmnShapesByHref,
-      dataTypesTree,
-      allDataTypesById,
-      allTopLevelDataTypesByFeelName,
-      allFeelVariableUniqueNames,
-      allTopLevelItemDefinitionUniqueNames,
-      externalDmnsByNamespace,
-      externalPmmlsByNamespace,
-      drgElementsWithoutVisualRepresentationOnCurrentDrd,
-    ]
-  );
-
-  return <DmnEditorDerivedStoreContext.Provider value={value}>{props.children}</DmnEditorDerivedStoreContext.Provider>;
-}
-
-function buildDataTypesTree(
-  items: DMN15__tItemDefinition[],
-  importsByNamespace: Map<string, DMN15__tImport>,
-  allDataTypesById: DataTypeIndex,
-  allTopLevelDataTypesByFeelName: DataTypeIndex,
-  parentId: string | undefined,
-  parents: Set<string>,
-  namespace: string,
-  relativeToNamespace: string
-) {
-  const dataTypesTree: DataType[] = [];
-
-  for (let i = 0; i < items.length; i++) {
-    const itemDefinition = items[i];
-
-    const feelName = buildFeelQNameFromNamespace({
-      importsByNamespace,
-      namedElement: itemDefinition,
-      namespace,
-      relativeToNamespace,
-    }).full;
-
-    const dataType: DataType = {
-      itemDefinition,
-      index: i,
-      parentId,
-      parents,
-      feelName,
-      namespace,
-      children: buildDataTypesTree(
-        itemDefinition.itemComponent ?? [],
-        importsByNamespace,
-        allDataTypesById,
-        allTopLevelDataTypesByFeelName,
-        itemDefinition["@_id"],
-        new Set([...parents, itemDefinition["@_id"]!]),
-        namespace,
-        relativeToNamespace
-      ),
-    };
-
-    dataTypesTree.push(dataType);
-    allDataTypesById.set(itemDefinition["@_id"]!, dataType);
-
-    if (parentId === undefined) {
-      allTopLevelDataTypesByFeelName.set(feelName, dataType);
-    }
-  }
-
-  return dataTypesTree;
-}
diff --git a/packages/dmn-editor/src/store/Store.ts b/packages/dmn-editor/src/store/Store.ts
index 99db6143919..a02b2de50e2 100644
--- a/packages/dmn-editor/src/store/Store.ts
+++ b/packages/dmn-editor/src/store/Store.ts
@@ -17,13 +17,24 @@
  * under the License.
  */
 
-import { createContext, useContext } from "react";
-import * as RF from "reactflow";
-import { StoreApi, UseBoundStore, create } from "zustand";
-import { WithImmer, immer } from "zustand/middleware/immer";
-import { useStoreWithEqualityFn } from "zustand/traditional";
 import { DmnLatestModel } from "@kie-tools/dmn-marshaller";
+import { DMN15__tImport } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { enableMapSet } from "immer";
+import * as RF from "reactflow";
+import { create } from "zustand";
+import { immer } from "zustand/middleware/immer";
+import { ExternalModelsIndex } from "../DmnEditor";
 import { DmnDiagramNodeData } from "../diagram/nodes/Nodes";
+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 { computeImportsByNamespace } from "./computed/computeImportsByNamespace";
+import { computeIndexes } from "./computed/computeIndexes";
+import { computeIsDropTargetNodeValidForSelection } from "./computed/computeIsDropTargetNodeValidForSelection";
+
+enableMapSet(); // Necessary because `Computed` has a lot of Maps and Sets.
 
 export interface DmnEditorDiagramNodeStatus {
   selected: boolean;
@@ -54,7 +65,8 @@ export enum DiagramNodesPanel {
 export type DropTargetNode = undefined | RF.Node<DmnDiagramNodeData>;
 
 export interface State {
-  dispatch: Dispatch;
+  dispatch: (s: State) => Dispatch;
+  computed: (s: State) => Computed;
   dmn: { model: DmnLatestModel };
   focus: {
     consumableId: string | undefined;
@@ -92,9 +104,8 @@ export interface State {
     overlays: {
       enableNodeHierarchyHighlight: boolean;
       enableExecutionHitsHighlights: boolean;
-      enableCustomNodeStyles: boolean;
       enableDataTypesToolbarOnNodes: boolean;
-      enableStyles: boolean;
+      enableCustomNodeStyles: boolean;
     };
     snapGrid: SnapGrid;
     _selectedNodes: Array<string>;
@@ -103,26 +114,44 @@ export interface State {
     resizingNodes: Array<string>;
     draggingWaypoints: Array<string>;
     movingDividerLines: Array<string>;
-    editingStyle: boolean;
+    isEditingStyle: boolean;
   };
 }
 
+// Read this to understand why we need computed as part of the store.
+// https://github.com/pmndrs/zustand/issues/132#issuecomment-1120467721
+export type Computed = {
+  isDiagramEditingInProgress(): boolean;
+
+  importsByNamespace(): Map<string, DMN15__tImport>;
+
+  indexes(): ReturnType<typeof computeIndexes>;
+
+  getDiagramData(e: ExternalModelsIndex | undefined): ReturnType<typeof computeDiagramData>;
+
+  isDropTargetNodeValidForSelection(e: ExternalModelsIndex | undefined): boolean;
+
+  getExternalModelTypesByNamespace: (
+    e: ExternalModelsIndex | undefined
+  ) => ReturnType<typeof computeExternalModelsByType>;
+
+  getDataTypes(e: ExternalModelsIndex | undefined): ReturnType<typeof computeDataTypes>;
+
+  getAllFeelVariableUniqueNames(): ReturnType<typeof computeAllFeelVariableUniqueNames>;
+};
+
 export type Dispatch = {
   dmn: {
     reset: (model: State["dmn"]["model"]) => void;
   };
   boxedExpressionEditor: {
-    open: (state: State, id: string) => void;
-    close: (state: State) => void;
+    open: (id: string) => void;
+    close: () => void;
   };
   diagram: {
-    setNodeStatus: (state: State, nodeId: string, status: Partial<DmnEditorDiagramNodeStatus>) => void;
-    setEdgeStatus: (state: State, edgeId: string, status: Partial<DmnEditorDiagramEdgeStatus>) => void;
-    setDividerLineStatus: (
-      state: State,
-      decisionServiceId: string,
-      status: Partial<DmnEditorDiagramDividerLineStatus>
-    ) => void;
+    setNodeStatus: (nodeId: string, status: Partial<DmnEditorDiagramNodeStatus>) => void;
+    setEdgeStatus: (edgeId: string, status: Partial<DmnEditorDiagramEdgeStatus>) => void;
+    setDividerLineStatus: (decisionServiceId: string, status: Partial<DmnEditorDiagramDividerLineStatus>) => void;
   };
 };
 
@@ -132,37 +161,7 @@ export enum DmnEditorTab {
   INCLUDED_MODELS,
 }
 
-export const NODE_LAYERS = {
-  GROUP_NODE: 0,
-  NODES: 1000, // We need a difference > 1000 here, since ReactFlow will add 1000 to the z-index when a node is selected.
-  DECISION_SERVICE_NODE: 2000, // We need a difference > 1000 here, since ReactFlow will add 1000 to the z-index when a node is selected.
-  NESTED_NODES: 4000,
-};
-
-type ExtractState = StoreApi<State> extends { getState: () => infer T } ? T : never;
-
-export function useDmnEditorStore<StateSlice = ExtractState>(
-  selector: (state: State) => StateSlice,
-  equalityFn?: (a: StateSlice, b: StateSlice) => boolean
-) {
-  const store = useContext(DmnEditorStoreApiContext);
-
-  if (store === null) {
-    throw new Error("Can't use DMN Editor Store outside of the DmnEditor component.");
-  }
-
-  return useStoreWithEqualityFn(store, selector, equalityFn);
-}
-
-export function useDmnEditorStoreApi() {
-  return useContext(DmnEditorStoreApiContext);
-}
-
-export const DmnEditorStoreApiContext = createContext<StoreApiType>({} as any);
-
-export type StoreApiType = UseBoundStore<WithImmer<StoreApi<State>>>;
-
-export const defaultStaticState = () => ({
+export const defaultStaticState = (): Omit<State, "dmn" | "dispatch" | "computed"> => ({
   boxedExpressionEditor: {
     activeDrgElementId: undefined,
     selectedObjectId: undefined,
@@ -173,6 +172,13 @@ export const defaultStaticState = () => ({
   navigation: {
     tab: DmnEditorTab.EDITOR,
   },
+  focus: {
+    consumableId: undefined,
+  },
+  dataTypesEditor: {
+    activeItemDefinitionId: undefined,
+    expandedItemComponentIds: [],
+  },
   diagram: {
     drdIndex: 0,
     edgeIdBeingUpdated: undefined,
@@ -185,7 +191,6 @@ export const defaultStaticState = () => ({
     overlaysPanel: {
       isOpen: false,
     },
-
     openNodesPanel: DiagramNodesPanel.NONE,
     drdSelector: {
       isOpen: false,
@@ -193,118 +198,184 @@ export const defaultStaticState = () => ({
     overlays: {
       enableNodeHierarchyHighlight: false,
       enableExecutionHitsHighlights: false,
-      enableCustomNodeStyles: false,
+      enableCustomNodeStyles: true,
       enableDataTypesToolbarOnNodes: true,
-      enableStyles: true,
     },
-    snapGrid: { isEnabled: true, x: 20, y: 20 },
+    snapGrid: {
+      isEnabled: true,
+      x: 20,
+      y: 20,
+    },
     _selectedNodes: [],
     _selectedEdges: [],
     draggingNodes: [],
     resizingNodes: [],
     draggingWaypoints: [],
     movingDividerLines: [],
-    editingStyle: false,
+    isEditingStyle: false,
   },
 });
 
-export function createDmnEditorStore(model: State["dmn"]["model"]) {
+export function createDmnEditorStore(model: State["dmn"]["model"], computedCache: ComputedStateCache<Computed>) {
   return create(
-    immer<State>((set, get) => ({
+    immer<State>(() => ({
       dmn: {
         model,
       },
-      focus: {
-        consumableId: undefined,
-      },
-      dataTypesEditor: {
-        activeItemDefinitionId: undefined,
-        expandedItemComponentIds: [],
-      },
       ...defaultStaticState(),
-      dispatch: {
-        dmn: {
-          reset: (model) => {
-            set((state) => {
-              state.diagram._selectedNodes = [];
-              state.diagram.draggingNodes = [];
-              state.diagram.resizingNodes = [];
-              state.navigation.tab = DmnEditorTab.EDITOR;
-              state.boxedExpressionEditor.activeDrgElementId = undefined;
-              state.boxedExpressionEditor.selectedObjectId = undefined;
-            });
+      dispatch(s: State) {
+        return {
+          dmn: {
+            reset: () => {
+              s.diagram._selectedNodes = [];
+              s.diagram.draggingNodes = [];
+              s.diagram.resizingNodes = [];
+              s.navigation.tab = DmnEditorTab.EDITOR;
+              s.boxedExpressionEditor.activeDrgElementId = undefined;
+              s.boxedExpressionEditor.selectedObjectId = undefined;
+            },
           },
-        },
-        boxedExpressionEditor: {
-          open: (state, id) => {
-            state.boxedExpressionEditor.activeDrgElementId = id;
-            state.boxedExpressionEditor.selectedObjectId = undefined;
-            state.boxedExpressionEditor.propertiesPanel.isOpen = state.diagram.propertiesPanel.isOpen;
+          boxedExpressionEditor: {
+            open: (id) => {
+              s.boxedExpressionEditor.activeDrgElementId = id;
+              s.boxedExpressionEditor.selectedObjectId = undefined;
+              s.boxedExpressionEditor.propertiesPanel.isOpen = s.diagram.propertiesPanel.isOpen;
+            },
+            close: () => {
+              s.diagram.propertiesPanel.isOpen = s.boxedExpressionEditor.propertiesPanel.isOpen;
+              s.boxedExpressionEditor.activeDrgElementId = undefined;
+              s.boxedExpressionEditor.selectedObjectId = undefined;
+            },
           },
-          close: (state) => {
-            state.diagram.propertiesPanel.isOpen = state.boxedExpressionEditor.propertiesPanel.isOpen;
-            state.boxedExpressionEditor.activeDrgElementId = undefined;
-            state.boxedExpressionEditor.selectedObjectId = undefined;
-          },
-        },
-        diagram: {
-          setNodeStatus: (prev, nodeId, newStatus) => {
-            //selected
-            if (newStatus.selected !== undefined) {
-              if (newStatus.selected) {
-                prev.diagram._selectedNodes.push(nodeId);
-              } else {
-                prev.diagram._selectedNodes = prev.diagram._selectedNodes.filter((s) => s !== nodeId);
+          diagram: {
+            setNodeStatus: (nodeId, newStatus) => {
+              //selected
+              if (newStatus.selected !== undefined) {
+                if (newStatus.selected) {
+                  s.diagram._selectedNodes.push(nodeId);
+                } else {
+                  s.diagram._selectedNodes = s.diagram._selectedNodes.filter((s) => s !== nodeId);
+                }
               }
-            }
-            //dragging
-            if (newStatus.dragging !== undefined) {
-              if (newStatus.dragging) {
-                prev.diagram.draggingNodes.push(nodeId);
-              } else {
-                prev.diagram.draggingNodes = prev.diagram.draggingNodes.filter((s) => s !== nodeId);
+              //dragging
+              if (newStatus.dragging !== undefined) {
+                if (newStatus.dragging) {
+                  s.diagram.draggingNodes.push(nodeId);
+                } else {
+                  s.diagram.draggingNodes = s.diagram.draggingNodes.filter((s) => s !== nodeId);
+                }
               }
-            }
-            // resizing
-            if (newStatus.resizing !== undefined) {
-              if (newStatus.resizing) {
-                prev.diagram.resizingNodes.push(nodeId);
-              } else {
-                prev.diagram.resizingNodes = prev.diagram.resizingNodes.filter((s) => s !== nodeId);
+              // resizing
+              if (newStatus.resizing !== undefined) {
+                if (newStatus.resizing) {
+                  s.diagram.resizingNodes.push(nodeId);
+                } else {
+                  s.diagram.resizingNodes = s.diagram.resizingNodes.filter((s) => s !== nodeId);
+                }
               }
-            }
-          },
-          setEdgeStatus: (prev, edgeId, newStatus) => {
-            //selected
-            if (newStatus.selected !== undefined) {
-              if (newStatus.selected) {
-                prev.diagram._selectedEdges.push(edgeId);
-              } else {
-                prev.diagram._selectedEdges = prev.diagram._selectedEdges.filter((s) => s !== edgeId);
+            },
+            setEdgeStatus: (edgeId, newStatus) => {
+              //selected
+              if (newStatus.selected !== undefined) {
+                if (newStatus.selected) {
+                  s.diagram._selectedEdges.push(edgeId);
+                } else {
+                  s.diagram._selectedEdges = s.diagram._selectedEdges.filter((s) => s !== edgeId);
+                }
               }
-            }
-            //dragging
-            if (newStatus.draggingWaypoint !== undefined) {
-              if (newStatus.draggingWaypoint) {
-                prev.diagram.draggingWaypoints.push(edgeId);
-              } else {
-                prev.diagram.draggingWaypoints = prev.diagram.draggingWaypoints.filter((s) => s !== edgeId);
+              //dragging
+              if (newStatus.draggingWaypoint !== undefined) {
+                if (newStatus.draggingWaypoint) {
+                  s.diagram.draggingWaypoints.push(edgeId);
+                } else {
+                  s.diagram.draggingWaypoints = s.diagram.draggingWaypoints.filter((s) => s !== edgeId);
+                }
               }
-            }
-          },
-          setDividerLineStatus: (prev, decisionServiceId, newStatus) => {
-            //dragging
-            if (newStatus.moving !== undefined) {
-              if (newStatus.moving) {
-                prev.diagram.movingDividerLines.push(decisionServiceId);
-              } else {
-                prev.diagram.movingDividerLines = prev.diagram.movingDividerLines.filter(
-                  (s) => s !== decisionServiceId
-                );
+            },
+            setDividerLineStatus: (decisionServiceId, newStatus) => {
+              //dragging
+              if (newStatus.moving !== undefined) {
+                if (newStatus.moving) {
+                  s.diagram.movingDividerLines.push(decisionServiceId);
+                } else {
+                  s.diagram.movingDividerLines = s.diagram.movingDividerLines.filter((s) => s !== decisionServiceId);
+                }
               }
-            }
+            },
           },
-        },
+        };
+      },
+      computed(s: State) {
+        return {
+          isDiagramEditingInProgress: () => {
+            return computedCache.cached(
+              "isDiagramEditingInProgress",
+              (
+                draggingNodesCount: number,
+                resizingNodesCount: number,
+                draggingWaypointsCount: number,
+                movingDividerLinesCount: number,
+                isisEditingStyle: boolean
+              ) =>
+                draggingNodesCount > 0 ||
+                resizingNodesCount > 0 ||
+                draggingWaypointsCount > 0 ||
+                movingDividerLinesCount > 0 ||
+                isisEditingStyle,
+              [
+                s.diagram.draggingNodes.length,
+                s.diagram.resizingNodes.length,
+                s.diagram.draggingWaypoints.length,
+                s.diagram.movingDividerLines.length,
+                s.diagram.isEditingStyle,
+              ]
+            );
+          },
+
+          indexes: () => {
+            return computedCache.cached("indexes", computeIndexes, [s.dmn.model.definitions, s.diagram.drdIndex]);
+          },
+
+          importsByNamespace: () => {
+            return computedCache.cached("importsByNamespace", computeImportsByNamespace, [
+              s.dmn.model.definitions.import,
+            ]);
+          },
+
+          isDropTargetNodeValidForSelection: (externalModelsByNamespace: ExternalModelsIndex | undefined) =>
+            computedCache.cached("isDropTargetNodeValidForSelection", computeIsDropTargetNodeValidForSelection, [
+              s.diagram.dropTargetNode,
+              s.computed(s).getDiagramData(externalModelsByNamespace),
+            ]),
+
+          getDataTypes: (externalModelsByNamespace: ExternalModelsIndex | undefined) =>
+            computedCache.cached("getDataTypes", computeDataTypes, [
+              s.dmn.model.definitions["@_namespace"],
+              s.dmn.model.definitions.itemDefinition,
+              s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace),
+              s.computed(s).importsByNamespace(),
+            ]),
+
+          getAllFeelVariableUniqueNames: () =>
+            computedCache.cached("getAllFeelVariableUniqueNames", computeAllFeelVariableUniqueNames, [
+              s.dmn.model.definitions.drgElement,
+              s.dmn.model.definitions.import,
+            ]),
+
+          getExternalModelTypesByNamespace: (externalModelsByNamespace: ExternalModelsIndex | undefined) =>
+            computedCache.cached("getExternalModelTypesByNamespace", computeExternalModelsByType, [
+              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).indexes(),
+            ]),
+        };
       },
     }))
   );
diff --git a/packages/dmn-editor/src/store/StoreContext.ts b/packages/dmn-editor/src/store/StoreContext.ts
new file mode 100644
index 00000000000..9edb82d8ac3
--- /dev/null
+++ b/packages/dmn-editor/src/store/StoreContext.ts
@@ -0,0 +1,47 @@
+/*
+ * 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 { createContext, useContext } from "react";
+import { StoreApi, UseBoundStore } from "zustand";
+import { WithImmer } from "zustand/middleware/immer";
+import { useStoreWithEqualityFn } from "zustand/traditional";
+import { State } from "./Store";
+
+type ExtractState = StoreApi<State> extends { getState: () => infer T } ? T : never;
+
+export type StoreApiType = UseBoundStore<WithImmer<StoreApi<State>>>;
+
+export const DmnEditorStoreApiContext = createContext<StoreApiType>({} as any);
+
+export function useDmnEditorStore<StateSlice = ExtractState>(
+  selector: (state: State) => StateSlice,
+  equalityFn?: (a: StateSlice, b: StateSlice) => boolean
+) {
+  const store = useContext(DmnEditorStoreApiContext);
+
+  if (store === null) {
+    throw new Error("Can't use DMN Editor Store outside of the DmnEditor component.");
+  }
+
+  return useStoreWithEqualityFn(store, selector, equalityFn);
+}
+
+export function useDmnEditorStoreApi() {
+  return useContext(DmnEditorStoreApiContext);
+}
diff --git a/packages/dmn-editor/src/focus/useFocusableElement.ts b/packages/dmn-editor/src/store/computed/computeAllFeelVariableUniqueNames.ts
similarity index 53%
copy from packages/dmn-editor/src/focus/useFocusableElement.ts
copy to packages/dmn-editor/src/store/computed/computeAllFeelVariableUniqueNames.ts
index d4b0823497b..e64538f84f3 100644
--- a/packages/dmn-editor/src/focus/useFocusableElement.ts
+++ b/packages/dmn-editor/src/store/computed/computeAllFeelVariableUniqueNames.ts
@@ -17,32 +17,27 @@
  * under the License.
  */
 
-import { useEffect } from "react";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { UniqueNameIndex } from "../../Dmn15Spec";
+import { State } from "../Store";
 
-export function useFocusableElement(
-  ref: React.RefObject<HTMLInputElement>,
-  id: string | undefined,
-  before?: (cb: () => void) => void
+export function computeAllFeelVariableUniqueNames(
+  drgElements: State["dmn"]["model"]["definitions"]["drgElement"],
+  imports: State["dmn"]["model"]["definitions"]["import"]
 ) {
-  const focus = useDmnEditorStore((s) => s.focus);
-  const dmnEditorStoreApi = useDmnEditorStoreApi();
+  const ret: UniqueNameIndex = new Map();
 
-  useEffect(() => {
-    if (!id) {
-      return;
-    }
+  drgElements ??= [];
+  imports ??= [];
 
-    const cb = () => {
-      ref.current?.select();
+  for (let i = 0; i < drgElements.length; i++) {
+    const drgElement = drgElements[i];
+    ret.set(drgElement["@_name"]!, drgElement["@_id"]!);
+  }
 
-      dmnEditorStoreApi.setState((state) => {
-        state.focus.consumableId = undefined;
-      });
-    };
+  for (let i = 0; i < imports.length; i++) {
+    const _import = imports[i];
+    ret.set(_import["@_name"], _import["@_id"]!);
+  }
 
-    if (focus.consumableId === id && ref.current) {
-      before?.(cb) ?? cb();
-    }
-  }, [before, dmnEditorStoreApi, focus.consumableId, id, ref]);
+  return ret;
 }
diff --git a/packages/dmn-editor/src/store/computed/computeDataTypes.ts b/packages/dmn-editor/src/store/computed/computeDataTypes.ts
new file mode 100644
index 00000000000..a54e6db33da
--- /dev/null
+++ b/packages/dmn-editor/src/store/computed/computeDataTypes.ts
@@ -0,0 +1,131 @@
+/*
+ * 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 { DMN15__tImport, DMN15__tItemDefinition } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { UniqueNameIndex } from "../../Dmn15Spec";
+import { builtInFeelTypeNames } from "../../dataTypes/BuiltInFeelTypes";
+import { DataType, DataTypeIndex } from "../../dataTypes/DataTypes";
+import { buildFeelQNameFromNamespace } from "../../feel/buildFeelQName";
+import { TypeOrReturnType } from "../ComputedStateCache";
+import { Computed, State } from "../Store";
+
+export function computeDataTypes(
+  namespace: State["dmn"]["model"]["definitions"]["@_namespace"],
+  itemDefinitions: State["dmn"]["model"]["definitions"]["itemDefinition"],
+  externalModelTypesByNamespace: TypeOrReturnType<Computed["getExternalModelTypesByNamespace"]>,
+  thisDmnsImportsByNamespace: TypeOrReturnType<Computed["importsByNamespace"]>
+) {
+  const allDataTypesById: DataTypeIndex = new Map();
+  const allTopLevelDataTypesByFeelName: DataTypeIndex = new Map();
+
+  const externalDmnsDataTypeTree = [...externalModelTypesByNamespace.dmns.values()].flatMap((externalDmn) => {
+    return buildDataTypesTree(
+      externalDmn.model.definitions.itemDefinition ?? [],
+      thisDmnsImportsByNamespace,
+      allDataTypesById,
+      allTopLevelDataTypesByFeelName,
+      undefined,
+      new Set(),
+      externalDmn.model.definitions["@_namespace"],
+      namespace
+    );
+  });
+
+  // Purposefully do thisDmn's after. This will make sure thisDmn's ItemDefintiions
+  // take precedence over any external ones imported to the default namespace.
+  const thisDmnsDataTypeTree = buildDataTypesTree(
+    itemDefinitions ?? [],
+    thisDmnsImportsByNamespace,
+    allDataTypesById,
+    allTopLevelDataTypesByFeelName,
+    undefined,
+    new Set(),
+    namespace,
+    namespace
+  );
+
+  const allTopLevelItemDefinitionUniqueNames: UniqueNameIndex = new Map();
+
+  for (const [k, v] of allTopLevelDataTypesByFeelName.entries()) {
+    allTopLevelItemDefinitionUniqueNames.set(k, v.itemDefinition["@_id"]!);
+  }
+
+  for (const type of builtInFeelTypeNames) {
+    allTopLevelItemDefinitionUniqueNames.set(type, type);
+  }
+
+  return {
+    dataTypesTree: [...thisDmnsDataTypeTree, ...externalDmnsDataTypeTree],
+    allDataTypesById,
+    allTopLevelDataTypesByFeelName,
+    allTopLevelItemDefinitionUniqueNames,
+  };
+}
+
+export function buildDataTypesTree(
+  items: DMN15__tItemDefinition[],
+  importsByNamespace: Map<string, DMN15__tImport>,
+  allDataTypesById: DataTypeIndex,
+  allTopLevelDataTypesByFeelName: DataTypeIndex,
+  parentId: string | undefined,
+  parents: Set<string>,
+  namespace: string,
+  relativeToNamespace: string
+) {
+  const dataTypesTree: DataType[] = [];
+
+  for (let i = 0; i < items.length; i++) {
+    const itemDefinition = items[i];
+
+    const feelName = buildFeelQNameFromNamespace({
+      importsByNamespace,
+      namedElement: itemDefinition,
+      namespace,
+      relativeToNamespace,
+    }).full;
+
+    const dataType: DataType = {
+      itemDefinition,
+      index: i,
+      parentId,
+      parents,
+      feelName,
+      namespace,
+      children: buildDataTypesTree(
+        itemDefinition.itemComponent ?? [],
+        importsByNamespace,
+        allDataTypesById,
+        allTopLevelDataTypesByFeelName,
+        itemDefinition["@_id"],
+        new Set([...parents, itemDefinition["@_id"]!]),
+        namespace,
+        relativeToNamespace
+      ),
+    };
+
+    dataTypesTree.push(dataType);
+    allDataTypesById.set(itemDefinition["@_id"]!, dataType);
+
+    if (parentId === undefined) {
+      allTopLevelDataTypesByFeelName.set(feelName, dataType);
+    }
+  }
+
+  return dataTypesTree;
+}
diff --git a/packages/dmn-editor/src/store/computed/computeDiagramData.ts b/packages/dmn-editor/src/store/computed/computeDiagramData.ts
new file mode 100644
index 00000000000..bc71ae64dd0
--- /dev/null
+++ b/packages/dmn-editor/src/store/computed/computeDiagramData.ts
@@ -0,0 +1,432 @@
+/*
+ * 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 { DMN15__tDefinitions } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { XmlQName } from "@kie-tools/xml-parser-ts/dist/qNames";
+import * as RF from "reactflow";
+import { KIE_DMN_UNKNOWN_NAMESPACE } from "../../Dmn15Spec";
+import { snapShapeDimensions, snapShapePosition } from "../../diagram/SnapGrid";
+import { EdgeType, NodeType } from "../../diagram/connections/graphStructure";
+import { EDGE_TYPES } from "../../diagram/edges/EdgeTypes";
+import { DmnDiagramEdgeData } from "../../diagram/edges/Edges";
+import { DrgEdge, EdgeVisitor, NodeVisitor, getAdjMatrix, traverse } from "../../diagram/graph/graph";
+import { getNodeTypeFromDmnObject } from "../../diagram/maths/DmnMaths";
+import { DECISION_SERVICE_COLLAPSED_DIMENSIONS, MIN_NODE_SIZES } from "../../diagram/nodes/DefaultSizes";
+import { ___NASTY_HACK_FOR_SAFARI_to_force_redrawing_svgs_and_avoid_repaint_glitches } from "../../diagram/nodes/NodeSvgs";
+import { NODE_TYPES } from "../../diagram/nodes/NodeTypes";
+import { DmnDiagramNodeData, NodeDmnObjects } from "../../diagram/nodes/Nodes";
+import { Unpacked } from "../../tsExt/tsExt";
+import { buildXmlHref, parseXmlHref } from "../../xml/xmlHrefs";
+import { TypeOrReturnType } from "../ComputedStateCache";
+import { Computed, State } from "../Store";
+
+export const NODE_LAYERS = {
+  GROUP_NODE: 0,
+  NODES: 1000, // We need a difference > 1000 here, since ReactFlow will add 1000 to the z-index when a node is selected.
+  DECISION_SERVICE_NODE: 2000, // We need a difference > 1000 here, since ReactFlow will add 1000 to the z-index when a node is selected.
+  NESTED_NODES: 4000,
+};
+
+type AckEdge = (args: {
+  id: string;
+  dmnObject: DmnDiagramEdgeData["dmnObject"];
+  type: EdgeType;
+  source: string;
+  target: string;
+}) => RF.Edge<DmnDiagramEdgeData>;
+
+type AckNode = (
+  dmnObjectQName: XmlQName,
+  dmnObject: NodeDmnObjects,
+  index: number
+) => RF.Node<DmnDiagramNodeData> | undefined;
+
+export function computeDiagramData(
+  diagram: State["diagram"],
+  definitions: State["dmn"]["model"]["definitions"],
+  externalModelTypesByNamespace: TypeOrReturnType<Computed["getExternalModelTypesByNamespace"]>,
+  indexes: TypeOrReturnType<Computed["indexes"]>
+) {
+  // console.time("nodes");
+  ___NASTY_HACK_FOR_SAFARI_to_force_redrawing_svgs_and_avoid_repaint_glitches.flag =
+    !___NASTY_HACK_FOR_SAFARI_to_force_redrawing_svgs_and_avoid_repaint_glitches.flag;
+
+  const drgElementsWithoutVisualRepresentationOnCurrentDrd: string[] = [];
+
+  const selectedNodesById = new Map<string, RF.Node<DmnDiagramNodeData>>();
+  const selectedEdgesById = new Map<string, RF.Edge<DmnDiagramEdgeData>>();
+  const selectedNodeTypes = new Set<NodeType>();
+  const nodesById = new Map<string, RF.Node<DmnDiagramNodeData>>();
+  const edgesById = new Map<string, RF.Edge<DmnDiagramEdgeData>>();
+  const parentIdsById = new Map<string, DmnDiagramNodeData>();
+
+  const { selectedNodes, draggingNodes, resizingNodes, selectedEdges } = {
+    selectedNodes: new Set(diagram._selectedNodes),
+    draggingNodes: new Set(diagram.draggingNodes),
+    resizingNodes: new Set(diagram.resizingNodes),
+    selectedEdges: new Set(diagram._selectedEdges),
+  };
+
+  // console.time("edges");
+  const edges: RF.Edge<DmnDiagramEdgeData>[] = [];
+
+  const drgEdges: DrgEdge[] = [];
+
+  const ackEdge: AckEdge = ({ id, type, dmnObject, source, target }) => {
+    const data = {
+      dmnObject,
+      dmnEdge: id ? indexes.dmnEdgesByDmnElementRef.get(id) : undefined,
+      dmnShapeSource: indexes.dmnShapesByHref.get(source),
+      dmnShapeTarget: indexes.dmnShapesByHref.get(target),
+    };
+
+    const edge: RF.Edge<DmnDiagramEdgeData> = {
+      data,
+      id,
+      type,
+      source,
+      target,
+      selected: selectedEdges.has(id),
+    };
+
+    edgesById.set(edge.id, edge);
+    if (edge.selected) {
+      selectedEdgesById.set(edge.id, edge);
+    }
+
+    edges.push(edge);
+
+    drgEdges.push({ id, sourceId: source, targetId: target, dmnObject });
+
+    return edge;
+  };
+
+  // requirements
+  ackRequirementEdges(definitions["@_namespace"], definitions["@_namespace"], definitions.drgElement, ackEdge);
+
+  // associations
+  (definitions.artifact ?? []).forEach((dmnObject, index) => {
+    if (dmnObject.__$$element !== "association") {
+      return;
+    }
+
+    ackEdge({
+      id: dmnObject["@_id"]!,
+      dmnObject: {
+        namespace: definitions["@_namespace"],
+        type: dmnObject.__$$element,
+        id: dmnObject["@_id"]!,
+        requirementType: "association",
+        index,
+      },
+      type: EDGE_TYPES.association,
+      source: dmnObject.sourceRef?.["@_href"],
+      target: dmnObject.targetRef?.["@_href"],
+    });
+  });
+
+  // console.timeEnd("edges");
+  const ackNode: AckNode = (dmnObjectQName, dmnObject, index) => {
+    const type = getNodeTypeFromDmnObject(dmnObject);
+    if (!type) {
+      return undefined;
+    }
+
+    // If the QName is composite, we try and get the namespace from the XML namespace declarations. If it's not found, we use `UNKNOWN_DMN_NAMESPACE`
+    // If the QName is simple, we simply say that the namespace is undefined, which is the same as the default namespace.
+    const dmnObjectNamespace = dmnObjectQName.prefix
+      ? definitions[`@_xmlns:${dmnObjectQName.prefix}`] ?? KIE_DMN_UNKNOWN_NAMESPACE
+      : undefined;
+
+    const id = buildXmlHref({ namespace: dmnObjectNamespace, id: dmnObjectQName.localPart });
+
+    const _shape = indexes.dmnShapesByHref.get(id);
+    if (!_shape) {
+      drgElementsWithoutVisualRepresentationOnCurrentDrd.push(id);
+      return undefined;
+    }
+
+    const { dmnElementRefQName, ...shape } = _shape;
+
+    const data: DmnDiagramNodeData = {
+      dmnObjectNamespace,
+      dmnObjectQName,
+      dmnObject,
+      shape,
+      index,
+      parentRfNode: undefined,
+    };
+
+    const newNode: RF.Node<DmnDiagramNodeData> = {
+      id,
+      type,
+      selected: selectedNodes.has(id),
+      dragging: draggingNodes.has(id),
+      resizing: resizingNodes.has(id),
+      position: snapShapePosition(diagram.snapGrid, shape),
+      data,
+      zIndex: NODE_LAYERS.NODES,
+      style: { ...snapShapeDimensions(diagram.snapGrid, shape, MIN_NODE_SIZES[type](diagram.snapGrid)) },
+    };
+
+    if (dmnObject?.__$$element === "decisionService") {
+      const containedDecisions = [...(dmnObject.outputDecision ?? []), ...(dmnObject.encapsulatedDecision ?? [])];
+      for (let i = 0; i < containedDecisions.length; i++) {
+        parentIdsById.set(containedDecisions[i]["@_href"], data);
+      }
+      if (shape["@_isCollapsed"] || !!dmnObjectNamespace) {
+        newNode.style = {
+          ...newNode.style,
+          ...DECISION_SERVICE_COLLAPSED_DIMENSIONS,
+        };
+      }
+    }
+
+    nodesById.set(newNode.id, newNode);
+    if (newNode.selected) {
+      selectedNodesById.set(newNode.id, newNode);
+      selectedNodeTypes.add(newNode.type as NodeType);
+    }
+    return newNode;
+  };
+
+  const localNodes: RF.Node<DmnDiagramNodeData>[] = [
+    ...(definitions.drgElement ?? []).flatMap((dmnObject, index) => {
+      const newNode = ackNode({ type: "xml-qname", localPart: dmnObject["@_id"]! }, dmnObject, index);
+      return newNode ? [newNode] : [];
+    }),
+    ...(definitions.artifact ?? []).flatMap((dmnObject, index) => {
+      if (dmnObject.__$$element === "association") {
+        return [];
+      }
+
+      const newNode = ackNode({ type: "xml-qname", localPart: dmnObject["@_id"]! }, dmnObject, index);
+      return newNode ? [newNode] : [];
+    }),
+  ];
+
+  // Assign parents & z-index to NODES
+  for (let i = 0; i < localNodes.length; i++) {
+    const parent = parentIdsById.get(localNodes[i].id);
+    if (parent) {
+      localNodes[i].data.parentRfNode = nodesById.get(
+        buildXmlHref({ namespace: parent.dmnObjectNamespace, id: parent.dmnObjectQName.localPart })
+      );
+      localNodes[i].extent = undefined; // Allows the node to be dragged freely outside of parent's bounds.
+      localNodes[i].zIndex = NODE_LAYERS.NESTED_NODES;
+    }
+
+    if (localNodes[i].type === NODE_TYPES.group) {
+      localNodes[i].zIndex = NODE_LAYERS.GROUP_NODE;
+    } else if (localNodes[i].type === NODE_TYPES.decisionService) {
+      localNodes[i].zIndex = NODE_LAYERS.DECISION_SERVICE_NODE;
+    }
+  }
+
+  const externalDrgElementsByIdByNamespace = [...externalModelTypesByNamespace.dmns.entries()].reduce(
+    (acc, [namespace, externalDmn]) => {
+      // Taking advantage of the loop to add the edges here...
+      ackRequirementEdges(
+        definitions["@_namespace"],
+        externalDmn.model.definitions["@_namespace"],
+        externalDmn.model.definitions.drgElement,
+        ackEdge
+      );
+
+      return acc.set(
+        namespace,
+        (externalDmn.model.definitions.drgElement ?? []).reduce(
+          (acc, e, index) => acc.set(e["@_id"]!, { element: e, index }),
+          new Map<string, { index: number; element: Unpacked<DMN15__tDefinitions["drgElement"]> }>()
+        )
+      );
+    },
+    new Map<string, Map<string, { index: number; element: Unpacked<DMN15__tDefinitions["drgElement"]> }>>()
+  );
+
+  const externalNodes = [...indexes.dmnShapesByHref.entries()].flatMap(([href, shape]) => {
+    if (nodesById.get(href)) {
+      return [];
+    }
+
+    if (!nodesById.get(href) && !indexes.hrefsOfDmnElementRefsOfShapesPointingToExternalDmnObjects.has(href)) {
+      // Unknown local node.
+      console.warn(`DMN DIAGRAM: Found a shape that references a local DRG element that doesn't exist.`, shape);
+      const newNode = ackNode(shape.dmnElementRefQName, null, -1);
+      return newNode ? [newNode] : [];
+    }
+
+    const namespace = definitions[`@_xmlns:${shape.dmnElementRefQName.prefix}`];
+    if (!namespace) {
+      console.warn(
+        `DMN DIAGRAM: Found a shape that references an external node with a namespace that is not declared at this DMN.`,
+        shape
+      );
+      const newNode = ackNode(shape.dmnElementRefQName, null, -1);
+      return newNode ? [newNode] : [];
+    }
+
+    const externalDrgElementsById = externalDrgElementsByIdByNamespace.get(namespace);
+    if (!externalDrgElementsById) {
+      console.warn(
+        `DMN DIAGRAM: Found a shape that references an external node from a namespace that is not provided on this DMN's external DMNs mapping.`,
+        shape
+      );
+      const newNode = ackNode(shape.dmnElementRefQName, null, -1);
+      return newNode ? [newNode] : [];
+    }
+
+    const externalDrgElement = externalDrgElementsById.get(shape.dmnElementRefQName.localPart);
+    if (!externalDrgElement) {
+      console.warn(`DMN DIAGRAM: Found a shape that references a non-existent node from an external DMN.`, shape);
+      const newNode = ackNode(shape.dmnElementRefQName, null, -1);
+      return newNode ? [newNode] : [];
+    }
+
+    const newNode = ackNode(shape.dmnElementRefQName, externalDrgElement.element, externalDrgElement.index);
+    return newNode ? [newNode] : [];
+  });
+
+  // Groups are always at the back. Decision Services after groups, then everything else.
+  const sortedNodes = [...localNodes, ...externalNodes]
+    .sort((a, b) => Number(b.type === NODE_TYPES.decisionService) - Number(a.type === NODE_TYPES.decisionService))
+    .sort((a, b) => Number(b.type === NODE_TYPES.group) - Number(a.type === NODE_TYPES.group));
+
+  // Selected edges go to the end of the array. This is necessary because z-index doesn't work on SVGs.
+  const sortedEdges = edges
+    .filter((e) => nodesById.has(e.source) && nodesById.has(e.target))
+    .sort((a, b) => Number(selectedEdges.has(a.id)) - Number(selectedEdges.has(b.id)));
+
+  // console.timeEnd("nodes");
+  if (diagram.overlays.enableNodeHierarchyHighlight) {
+    assignClassesToHighlightedHierarchyNodes(diagram._selectedNodes, nodesById, edgesById, drgEdges);
+  }
+
+  return {
+    drgEdges,
+    nodes: sortedNodes,
+    edges: sortedEdges,
+    edgesById,
+    nodesById,
+    selectedNodeTypes,
+    selectedNodesById,
+    selectedEdgesById,
+    drgElementsWithoutVisualRepresentationOnCurrentDrd,
+  };
+}
+
+function ackRequirementEdges(
+  thisDmnsNamespace: string,
+  drgElementsNamespace: string,
+  drgElements: DMN15__tDefinitions["drgElement"],
+  ackEdge: AckEdge
+) {
+  const namespace = drgElementsNamespace === thisDmnsNamespace ? "" : drgElementsNamespace;
+
+  for (const dmnObject of drgElements ?? []) {
+    // information requirements
+    if (dmnObject.__$$element === "decision") {
+      (dmnObject.informationRequirement ?? []).forEach((ir, index) => {
+        const irHref = parseXmlHref((ir.requiredDecision ?? ir.requiredInput)!["@_href"]);
+        ackEdge({
+          id: ir["@_id"]!,
+          dmnObject: {
+            namespace: drgElementsNamespace,
+            type: dmnObject.__$$element,
+            id: dmnObject["@_id"]!,
+            requirementType: "informationRequirement",
+            index,
+          },
+          type: EDGE_TYPES.informationRequirement,
+          source: buildXmlHref({ namespace: irHref.namespace ?? namespace, id: irHref.id }),
+          target: buildXmlHref({ namespace, id: dmnObject["@_id"]! }),
+        });
+      });
+    }
+    // knowledge requirements
+    if (dmnObject.__$$element === "decision" || dmnObject.__$$element === "businessKnowledgeModel") {
+      (dmnObject.knowledgeRequirement ?? []).forEach((kr, index) => {
+        const krHref = parseXmlHref(kr.requiredKnowledge["@_href"]);
+        ackEdge({
+          id: kr["@_id"]!,
+          dmnObject: {
+            namespace: drgElementsNamespace,
+            type: dmnObject.__$$element,
+            id: dmnObject["@_id"]!,
+            requirementType: "knowledgeRequirement",
+            index,
+          },
+          type: EDGE_TYPES.knowledgeRequirement,
+          source: buildXmlHref({ namespace: krHref.namespace ?? namespace, id: krHref.id }),
+          target: buildXmlHref({ namespace, id: dmnObject["@_id"]! }),
+        });
+      });
+    }
+    // authority requirements
+    if (
+      dmnObject.__$$element === "decision" ||
+      dmnObject.__$$element === "businessKnowledgeModel" ||
+      dmnObject.__$$element === "knowledgeSource"
+    ) {
+      (dmnObject.authorityRequirement ?? []).forEach((ar, index) => {
+        const arHref = parseXmlHref((ar.requiredInput ?? ar.requiredDecision ?? ar.requiredAuthority)!["@_href"]);
+        ackEdge({
+          id: ar["@_id"]!,
+          dmnObject: {
+            namespace: drgElementsNamespace,
+            type: dmnObject.__$$element,
+            id: dmnObject["@_id"]!,
+            requirementType: "authorityRequirement",
+            index,
+          },
+          type: EDGE_TYPES.authorityRequirement,
+          source: buildXmlHref({ namespace: arHref.namespace ?? namespace, id: arHref.id }),
+          target: buildXmlHref({ namespace, id: dmnObject["@_id"]! }),
+        });
+      });
+    }
+  }
+}
+
+export function assignClassesToHighlightedHierarchyNodes(
+  selected: string[],
+  nodesById: Map<string, RF.Node>,
+  edgesById: Map<string, RF.Edge>,
+  drgEdges: DrgEdge[]
+) {
+  const nodeVisitor: NodeVisitor = (nodeId, traversalDirection) => {
+    const node = nodesById.get(nodeId);
+    if (node) {
+      node.className = `hierarchy ${traversalDirection}`;
+    }
+  };
+
+  const edgeVisitor: EdgeVisitor = (edge, traversalDirection) => {
+    const rfEdge = edgesById.get(edge.id);
+    if (rfEdge) {
+      rfEdge.className = `hierarchy ${traversalDirection}`;
+    }
+  };
+
+  const __selectedSet = new Set(selected);
+  const __adjMatrix = getAdjMatrix(drgEdges);
+
+  traverse(__adjMatrix, __selectedSet, selected, "up", nodeVisitor, edgeVisitor);
+  traverse(__adjMatrix, __selectedSet, selected, "down", nodeVisitor, edgeVisitor); // Traverse "down" after "up" because when there's a cycle, highlighting a node as a dependency is preferable.
+}
diff --git a/packages/dmn-editor/src/store/computed/computeExternalModelsByType.ts b/packages/dmn-editor/src/store/computed/computeExternalModelsByType.ts
new file mode 100644
index 00000000000..b62fec76e2b
--- /dev/null
+++ b/packages/dmn-editor/src/store/computed/computeExternalModelsByType.ts
@@ -0,0 +1,50 @@
+/*
+ * 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 { ExternalDmnsIndex, ExternalModelsIndex, ExternalPmmlsIndex } from "../../DmnEditor";
+import { getNamespaceOfDmnImport } from "../../includedModels/importNamespaces";
+import { State } from "../Store";
+
+export function computeExternalModelsByType(
+  imports: State["dmn"]["model"]["definitions"]["import"],
+  externalModelsByNamespace: ExternalModelsIndex | undefined
+) {
+  return (imports ?? []).reduce<{ dmns: ExternalDmnsIndex; pmmls: ExternalPmmlsIndex }>(
+    (acc, _import) => {
+      const externalModel = externalModelsByNamespace?.[getNamespaceOfDmnImport({ dmnImport: _import })];
+      if (!externalModel) {
+        console.warn(
+          `DMN DIAGRAM: Can't index external model with namespace '${_import["@_namespace"]}' because it doesn't exist on the external models list.`
+        );
+        return acc;
+      }
+
+      if (externalModel.type === "dmn") {
+        acc.dmns.set(_import["@_namespace"], externalModel);
+      } else if (externalModel.type === "pmml") {
+        acc.pmmls.set(_import["@_namespace"], externalModel);
+      } else {
+        console.warn("DMN EDITOR: Unknown external model type", externalModel);
+      }
+
+      return acc;
+    },
+    { dmns: new Map(), pmmls: new Map() }
+  );
+}
diff --git a/packages/dmn-editor/src/focus/useFocusableElement.ts b/packages/dmn-editor/src/store/computed/computeImportsByNamespace.ts
similarity index 52%
copy from packages/dmn-editor/src/focus/useFocusableElement.ts
copy to packages/dmn-editor/src/store/computed/computeImportsByNamespace.ts
index d4b0823497b..994cf3ce945 100644
--- a/packages/dmn-editor/src/focus/useFocusableElement.ts
+++ b/packages/dmn-editor/src/store/computed/computeImportsByNamespace.ts
@@ -17,32 +17,15 @@
  * under the License.
  */
 
-import { useEffect } from "react";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../store/Store";
+import { DMN15__tImport } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { State } from "../Store";
 
-export function useFocusableElement(
-  ref: React.RefObject<HTMLInputElement>,
-  id: string | undefined,
-  before?: (cb: () => void) => void
-) {
-  const focus = useDmnEditorStore((s) => s.focus);
-  const dmnEditorStoreApi = useDmnEditorStoreApi();
+export function computeImportsByNamespace(imports: State["dmn"]["model"]["definitions"]["import"]) {
+  imports ??= [];
 
-  useEffect(() => {
-    if (!id) {
-      return;
-    }
-
-    const cb = () => {
-      ref.current?.select();
-
-      dmnEditorStoreApi.setState((state) => {
-        state.focus.consumableId = undefined;
-      });
-    };
-
-    if (focus.consumableId === id && ref.current) {
-      before?.(cb) ?? cb();
-    }
-  }, [before, dmnEditorStoreApi, focus.consumableId, id, ref]);
+  const ret = new Map<string, DMN15__tImport>();
+  for (let i = 0; i < imports.length; i++) {
+    ret.set(imports[i]["@_namespace"], imports[i]);
+  }
+  return ret;
 }
diff --git a/packages/dmn-editor/src/store/computed/computeIndexes.ts b/packages/dmn-editor/src/store/computed/computeIndexes.ts
new file mode 100644
index 00000000000..9e5cd35e677
--- /dev/null
+++ b/packages/dmn-editor/src/store/computed/computeIndexes.ts
@@ -0,0 +1,68 @@
+/*
+ * 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 { DMNDI15__DMNEdge, DMNDI15__DMNShape } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
+import { XmlQName, parseXmlQName } from "@kie-tools/xml-parser-ts/dist/qNames";
+import { KIE_DMN_UNKNOWN_NAMESPACE } from "../../Dmn15Spec";
+import { buildXmlHref } from "../../xml/xmlHrefs";
+import { State } from "../Store";
+
+export function computeIndexes(
+  definitions: State["dmn"]["model"]["definitions"],
+  drdIndex: State["diagram"]["drdIndex"]
+) {
+  const dmnEdgesByDmnElementRef = new Map<string, DMNDI15__DMNEdge & { index: number }>();
+  const dmnShapesByHref = new Map<string, DMNDI15__DMNShape & { index: number; dmnElementRefQName: XmlQName }>();
+  const hrefsOfDmnElementRefsOfShapesPointingToExternalDmnObjects = new Set<string>();
+
+  const diagramElements = definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[drdIndex]["dmndi:DMNDiagramElement"] ?? [];
+  for (let i = 0; i < diagramElements.length; i++) {
+    const e = diagramElements[i];
+    // DMNEdge
+    if (e.__$$element === "dmndi:DMNEdge") {
+      dmnEdgesByDmnElementRef.set(e["@_dmnElementRef"], { ...e, index: i });
+    }
+
+    // DMNShape
+    else if (e.__$$element === "dmndi:DMNShape") {
+      let href: string;
+      // @_dmnElementRef is a xsd:QName, meaning it can be prefixed with a namespace name.
+      // If we find the namespace as a namespace declaration on the `definitions` object, then this shape represents a node from an included model.
+      // Therefore, we need to add it to `dmnShapesForExternalNodesByDmnRefId`, so we can draw these nodes.
+      // Do not skip adding it to the regular `dmnShapesByHref`, as nodes will query this.
+      const dmnElementRefQName = parseXmlQName(e["@_dmnElementRef"]);
+      if (dmnElementRefQName.prefix) {
+        const namespace = definitions[`@_xmlns:${dmnElementRefQName.prefix}`] ?? KIE_DMN_UNKNOWN_NAMESPACE;
+        href = buildXmlHref({ namespace, id: dmnElementRefQName.localPart });
+        hrefsOfDmnElementRefsOfShapesPointingToExternalDmnObjects.add(href);
+      } else {
+        href = buildXmlHref({ id: dmnElementRefQName.localPart });
+      }
+
+      dmnShapesByHref.set(href, { ...e, index: i, dmnElementRefQName });
+    } else {
+      // Ignore anything that is unknown.
+    }
+  }
+  return {
+    dmnEdgesByDmnElementRef,
+    dmnShapesByHref,
+    hrefsOfDmnElementRefsOfShapesPointingToExternalDmnObjects,
+  };
+}
diff --git a/packages/dmn-editor/src/diagram/nodes/EditExpressionNodePanel.tsx b/packages/dmn-editor/src/store/computed/computeIsDropTargetNodeValidForSelection.ts
similarity index 53%
copy from packages/dmn-editor/src/diagram/nodes/EditExpressionNodePanel.tsx
copy to packages/dmn-editor/src/store/computed/computeIsDropTargetNodeValidForSelection.ts
index 7de7bc3cc69..c9bd4c8ac30 100644
--- a/packages/dmn-editor/src/diagram/nodes/EditExpressionNodePanel.tsx
+++ b/packages/dmn-editor/src/store/computed/computeIsDropTargetNodeValidForSelection.ts
@@ -17,28 +17,20 @@
  * under the License.
  */
 
-import * as React from "react";
-import { Label } from "@patternfly/react-core/dist/js/components/Label";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../../store/Store";
-
-export function EditExpressionNodePanel(props: { isVisible: boolean; id: string }) {
-  const dispatch = useDmnEditorStore((s) => s.dispatch);
-  const dmnEditorStoreApi = useDmnEditorStoreApi();
+import { NodeType } from "../../diagram/connections/graphStructure";
+import { isValidContainment } from "../../diagram/connections/isValidContainment";
+import { Computed, State } from "../Store";
 
+export function computeIsDropTargetNodeValidForSelection(
+  dropTargetNode: State["diagram"]["dropTargetNode"],
+  diagramData: ReturnType<Computed["getDiagramData"]>
+) {
   return (
-    <>
-      {props.isVisible && (
-        <Label
-          onClick={() =>
-            dmnEditorStoreApi.setState((state) => {
-              dispatch.boxedExpressionEditor.open(state, props.id);
-            })
-          }
-          className={"kie-dmn-editor--edit-expression-node-panel"}
-        >
-          Edit
-        </Label>
-      )}
-    </>
+    !!dropTargetNode &&
+    isValidContainment({
+      nodeTypes: diagramData.selectedNodeTypes,
+      inside: dropTargetNode.type as NodeType,
+      dmnObjectQName: dropTargetNode.data.dmnObjectQName,
+    })
   );
 }
diff --git a/packages/dmn-editor/src/diagram/nodes/EditExpressionNodePanel.tsx b/packages/dmn-editor/src/store/computed/initial.ts
similarity index 51%
copy from packages/dmn-editor/src/diagram/nodes/EditExpressionNodePanel.tsx
copy to packages/dmn-editor/src/store/computed/initial.ts
index 7de7bc3cc69..6b497a254a9 100644
--- a/packages/dmn-editor/src/diagram/nodes/EditExpressionNodePanel.tsx
+++ b/packages/dmn-editor/src/store/computed/initial.ts
@@ -17,28 +17,40 @@
  * under the License.
  */
 
-import * as React from "react";
-import { Label } from "@patternfly/react-core/dist/js/components/Label";
-import { useDmnEditorStore, useDmnEditorStoreApi } from "../../store/Store";
+import { Cache } from "../ComputedStateCache";
+import { Computed } from "../Store";
 
-export function EditExpressionNodePanel(props: { isVisible: boolean; id: string }) {
-  const dispatch = useDmnEditorStore((s) => s.dispatch);
-  const dmnEditorStoreApi = useDmnEditorStoreApi();
-
-  return (
-    <>
-      {props.isVisible && (
-        <Label
-          onClick={() =>
-            dmnEditorStoreApi.setState((state) => {
-              dispatch.boxedExpressionEditor.open(state, props.id);
-            })
-          }
-          className={"kie-dmn-editor--edit-expression-node-panel"}
-        >
-          Edit
-        </Label>
-      )}
-    </>
-  );
-}
+export const INITIAL_COMPUTED_CACHE: Cache<Computed> = {
+  isDiagramEditingInProgress: {
+    value: undefined,
+    dependencies: [],
+  },
+  importsByNamespace: {
+    value: undefined,
+    dependencies: [],
+  },
+  indexes: {
+    value: undefined,
+    dependencies: [],
+  },
+  getDiagramData: {
+    value: undefined,
+    dependencies: [],
+  },
+  isDropTargetNodeValidForSelection: {
+    value: undefined,
+    dependencies: [],
+  },
+  getExternalModelTypesByNamespace: {
+    value: undefined,
+    dependencies: [],
+  },
+  getDataTypes: {
+    value: undefined,
+    dependencies: [],
+  },
+  getAllFeelVariableUniqueNames: {
+    value: undefined,
+    dependencies: [],
+  },
+};
diff --git a/packages/dmn-editor/src/store/useDiagramData.tsx b/packages/dmn-editor/src/store/useDiagramData.tsx
deleted file mode 100644
index 3ca1beaf800..00000000000
--- a/packages/dmn-editor/src/store/useDiagramData.tsx
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * 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 {
-  DMN15__tDefinitions,
-  DMNDI15__DMNEdge,
-  DMNDI15__DMNShape,
-} from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
-import { useMemo } from "react";
-import * as RF from "reactflow";
-import { NODE_LAYERS, useDmnEditorStore } from "./Store";
-import { snapShapeDimensions, snapShapePosition } from "../diagram/SnapGrid";
-import { DECISION_SERVICE_COLLAPSED_DIMENSIONS } from "../diagram/nodes/DefaultSizes";
-import { EdgeType, NodeType } from "../diagram/connections/graphStructure";
-import { EDGE_TYPES } from "../diagram/edges/EdgeTypes";
-import { DmnDiagramEdgeData } from "../diagram/edges/Edges";
-import { NODE_TYPES } from "../diagram/nodes/NodeTypes";
-import { DmnDiagramNodeData, NodeDmnObjects } from "../diagram/nodes/Nodes";
-import { getNodeTypeFromDmnObject } from "../diagram/maths/DmnMaths";
-import { XmlQName, parseXmlQName } from "@kie-tools/xml-parser-ts/dist/qNames";
-import { buildXmlHref } from "../xml/xmlHrefs";
-import { ___NASTY_HACK_FOR_SAFARI_to_force_redrawing_svgs_and_avoid_repaint_glitches } from "../diagram/nodes/NodeSvgs";
-import { ExternalDmnsIndex } from "../DmnEditor";
-import { MIN_NODE_SIZES } from "../diagram/nodes/DefaultSizes";
-import { Unpacked } from "../tsExt/tsExt";
-import { NodeVisitor, EdgeVisitor, getAdjMatrix, traverse } from "../diagram/graph/graph";
-import { KIE_DMN_UNKNOWN_NAMESPACE } from "../Dmn15Spec";
-
-export const diagramColors = {
-  hierarchyUp: "#0083a4",
-  hierarchyDown: "#003fa4",
-  selected: "#006ba4",
-};
-
-export function useDiagramData(externalDmnsByNamespace: ExternalDmnsIndex) {
-  ___NASTY_HACK_FOR_SAFARI_to_force_redrawing_svgs_and_avoid_repaint_glitches.flag =
-    !___NASTY_HACK_FOR_SAFARI_to_force_redrawing_svgs_and_avoid_repaint_glitches.flag;
-
-  const thisDmn = useDmnEditorStore((s) => s.dmn);
-  const diagram = useDmnEditorStore((s) => s.diagram);
-
-  const { dmnEdgesByDmnElementRef, dmnShapesByHref, hrefsOfDmnElementRefsOfShapesPointingToExternalDmnObjects } =
-    useMemo(() => {
-      const dmnEdgesByDmnElementRef = new Map<string, DMNDI15__DMNEdge & { index: number }>();
-      const dmnShapesByHref = new Map<string, DMNDI15__DMNShape & { index: number; dmnElementRefQName: XmlQName }>();
-      const hrefsOfDmnElementRefsOfShapesPointingToExternalDmnObjects = new Set<string>();
-
-      const diagramElements =
-        thisDmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[diagram.drdIndex]["dmndi:DMNDiagramElement"] ??
-        [];
-      for (let i = 0; i < diagramElements.length; i++) {
-        const e = diagramElements[i];
-        // DMNEdge
-        if (e.__$$element === "dmndi:DMNEdge") {
-          dmnEdgesByDmnElementRef.set(e["@_dmnElementRef"], { ...e, index: i });
-        }
-
-        // DMNShape
-        else if (e.__$$element === "dmndi:DMNShape") {
-          let href: string;
-          // @_dmnElementRef is a xsd:QName, meaning it can be prefixed with a namespace name.
-          // If we find the namespace as a namespace declaration on the `definitions` object, then this shape represents a node from an included model.
-          // Therefore, we need to add it to `dmnShapesForExternalNodesByDmnRefId`, so we can draw these nodes.
-          // Do not skip adding it to the regular `dmnShapesByHref`, as nodes will query this.
-          const dmnElementRefQName = parseXmlQName(e["@_dmnElementRef"]);
-          if (dmnElementRefQName.prefix) {
-            const namespace =
-              thisDmn.model.definitions[`@_xmlns:${dmnElementRefQName.prefix}`] ?? KIE_DMN_UNKNOWN_NAMESPACE;
-            href = buildXmlHref({ namespace, id: dmnElementRefQName.localPart });
-            hrefsOfDmnElementRefsOfShapesPointingToExternalDmnObjects.add(href);
-          } else {
-            href = buildXmlHref({ id: dmnElementRefQName.localPart });
-          }
-
-          dmnShapesByHref.set(href, { ...e, index: i, dmnElementRefQName });
-        } else {
-          // Ignore anything that is unknown.
-        }
-      }
-      return {
-        dmnEdgesByDmnElementRef,
-        dmnShapesByHref,
-        hrefsOfDmnElementRefsOfShapesPointingToExternalDmnObjects,
-      };
-    }, [diagram.drdIndex, thisDmn.model.definitions]);
-
-  const {
-    nodes,
-    edges,
-    nodesById,
-    edgesById,
-    selectedNodeTypes,
-    selectedNodesById,
-    selectedEdgesById,
-    drgElementsWithoutVisualRepresentationOnCurrentDrd,
-  } = useMemo(() => {
-    // console.time("nodes");
-
-    const drgElementsWithoutVisualRepresentationOnCurrentDrd: string[] = [];
-
-    const selectedNodesById = new Map<string, RF.Node<DmnDiagramNodeData>>();
-    const selectedEdgesById = new Map<string, RF.Edge<DmnDiagramEdgeData>>();
-    const selectedNodeTypes = new Set<NodeType>();
-    const nodesById = new Map<string, RF.Node<DmnDiagramNodeData>>();
-    const edgesById = new Map<string, RF.Edge<DmnDiagramEdgeData>>();
-    const parentIdsById = new Map<string, DmnDiagramNodeData>();
-
-    const { selectedNodes, draggingNodes, resizingNodes, selectedEdges } = {
-      selectedNodes: new Set(diagram._selectedNodes),
-      draggingNodes: new Set(diagram.draggingNodes),
-      resizingNodes: new Set(diagram.resizingNodes),
-      selectedEdges: new Set(diagram._selectedEdges),
-    };
-
-    function ackEdge({
-      id,
-      type,
-      dmnObject,
-      source,
-      target,
-    }: {
-      id: string;
-      dmnObject: DmnDiagramEdgeData["dmnObject"];
-      type: EdgeType;
-      source: string;
-      target: string;
-    }): RF.Edge<DmnDiagramEdgeData> {
-      const data = {
-        dmnObject,
-        dmnEdge: id ? dmnEdgesByDmnElementRef.get(id) : undefined,
-        dmnShapeSource: dmnShapesByHref.get(source),
-        dmnShapeTarget: dmnShapesByHref.get(target),
-      };
-
-      const edge: RF.Edge<DmnDiagramEdgeData> = {
-        data,
-        id,
-        type,
-        source,
-        target,
-        selected: selectedEdges.has(id),
-      };
-      edgesById.set(edge.id, edge);
-      if (edge.selected) {
-        selectedEdgesById.set(edge.id, edge);
-      }
-      return edge;
-    }
-
-    // console.time("edges");
-
-    const edges: RF.Edge<DmnDiagramEdgeData>[] = [
-      // information requirements
-      ...(thisDmn.model.definitions.drgElement ?? []).reduce<RF.Edge<DmnDiagramEdgeData>[]>((acc, dmnObject) => {
-        if (dmnObject.__$$element === "decision") {
-          acc.push(
-            ...(dmnObject.informationRequirement ?? []).map((ir, index) =>
-              ackEdge({
-                id: ir["@_id"] ?? "",
-                dmnObject: {
-                  type: dmnObject.__$$element,
-                  id: dmnObject["@_id"] ?? "",
-                  requirementType: "informationRequirement",
-                  index,
-                },
-                type: EDGE_TYPES.informationRequirement,
-                source: (ir.requiredDecision ?? ir.requiredInput)!["@_href"],
-                target: buildXmlHref({ id: dmnObject["@_id"]! }),
-              })
-            )
-          );
-        }
-        // knowledge requirements
-        if (dmnObject.__$$element === "decision" || dmnObject.__$$element === "businessKnowledgeModel") {
-          acc.push(
-            ...(dmnObject.knowledgeRequirement ?? []).map((kr, index) =>
-              ackEdge({
-                id: kr["@_id"] ?? "",
-                dmnObject: {
-                  type: dmnObject.__$$element,
-                  id: dmnObject["@_id"] ?? "",
-                  requirementType: "knowledgeRequirement",
-                  index,
-                },
-                type: EDGE_TYPES.knowledgeRequirement,
-                source: kr.requiredKnowledge["@_href"],
-                target: buildXmlHref({ id: dmnObject["@_id"]! }),
-              })
-            )
-          );
-        }
-        // authority requirements
-        if (
-          dmnObject.__$$element === "decision" ||
-          dmnObject.__$$element === "businessKnowledgeModel" ||
-          dmnObject.__$$element === "knowledgeSource"
-        ) {
-          acc.push(
-            ...(dmnObject.authorityRequirement ?? []).map((ar, index) =>
-              ackEdge({
-                id: ar["@_id"] ?? "",
-                dmnObject: {
-                  type: dmnObject.__$$element,
-                  id: dmnObject["@_id"] ?? "",
-                  requirementType: "authorityRequirement",
-                  index,
-                },
-                type: EDGE_TYPES.authorityRequirement,
-                source: (ar.requiredInput ?? ar.requiredDecision ?? ar.requiredAuthority)!["@_href"],
-                target: buildXmlHref({ id: dmnObject["@_id"]! }),
-              })
-            )
-          );
-        }
-        return acc;
-      }, []),
-      // associations
-      ...(thisDmn.model.definitions.artifact ?? []).flatMap((dmnObject, index) =>
-        dmnObject.__$$element === "association"
-          ? [
-              ackEdge({
-                id: dmnObject["@_id"] ?? "",
-                dmnObject: {
-                  type: dmnObject.__$$element,
-                  id: dmnObject["@_id"] ?? "",
-                  requirementType: "association",
-                  index,
-                },
-                type: EDGE_TYPES.association,
-                source: dmnObject.sourceRef?.["@_href"],
-                target: dmnObject.targetRef?.["@_href"],
-              }),
-            ]
-          : []
-      ),
-    ];
-
-    // Selected edges go to the end of the array. This is necessary because z-index doesn't work on SVGs.
-    const sortedEdges = edges.sort((a, b) => Number(selectedEdges.has(a.id)) - Number(selectedEdges.has(b.id)));
-
-    // console.timeEnd("edges");
-
-    function ackNode(dmnObjectQName: XmlQName, dmnObject: NodeDmnObjects, index: number) {
-      const type = getNodeTypeFromDmnObject(dmnObject);
-      if (!type) {
-        return undefined;
-      }
-
-      // If the QName is composite, we try and get the namespace from the XML namespace declarations. If it's not found, we use `UNKNOWN_DMN_NAMESPACE`
-      // If the QName is simple, we simply say that the namespace is undefined, which is the same as the default namespace.
-      const dmnObjectNamespace = dmnObjectQName.prefix
-        ? thisDmn.model.definitions[`@_xmlns:${dmnObjectQName.prefix}`] ?? KIE_DMN_UNKNOWN_NAMESPACE
-        : undefined;
-
-      const id = buildXmlHref({ namespace: dmnObjectNamespace, id: dmnObjectQName.localPart });
-
-      const _shape = dmnShapesByHref.get(id);
-      if (!_shape) {
-        drgElementsWithoutVisualRepresentationOnCurrentDrd.push(id);
-        return undefined;
-      }
-
-      const { dmnElementRefQName, ...shape } = _shape;
-
-      const data: DmnDiagramNodeData = {
-        dmnObjectNamespace,
-        dmnObjectQName,
-        dmnObject,
-        shape,
-        index,
-        parentRfNode: undefined,
-      };
-
-      const newNode: RF.Node<DmnDiagramNodeData> = {
-        id,
-        type,
-        selected: selectedNodes.has(id),
-        dragging: draggingNodes.has(id),
-        resizing: resizingNodes.has(id),
-        position: snapShapePosition(diagram.snapGrid, shape),
-        data,
-        zIndex: NODE_LAYERS.NODES,
-        style: { ...snapShapeDimensions(diagram.snapGrid, shape, MIN_NODE_SIZES[type](diagram.snapGrid)) },
-      };
-
-      if (dmnObject?.__$$element === "decisionService") {
-        const containedDecisions = [...(dmnObject.outputDecision ?? []), ...(dmnObject.encapsulatedDecision ?? [])];
-        for (let i = 0; i < containedDecisions.length; i++) {
-          parentIdsById.set(containedDecisions[i]["@_href"], data);
-        }
-        if (shape["@_isCollapsed"] || !!dmnObjectNamespace) {
-          newNode.style = {
-            ...newNode.style,
-            ...DECISION_SERVICE_COLLAPSED_DIMENSIONS,
-          };
-        }
-      }
-
-      nodesById.set(newNode.id, newNode);
-      if (newNode.selected) {
-        selectedNodesById.set(newNode.id, newNode);
-        selectedNodeTypes.add(newNode.type as NodeType);
-      }
-      return newNode;
-    }
-
-    const localNodes: RF.Node<DmnDiagramNodeData>[] = [
-      ...(thisDmn.model.definitions.drgElement ?? []).flatMap((dmnObject, index) => {
-        const newNode = ackNode({ type: "xml-qname", localPart: dmnObject["@_id"]! }, dmnObject, index);
-        return newNode ? [newNode] : [];
-      }),
-      ...(thisDmn.model.definitions.artifact ?? []).flatMap((dmnObject, index) => {
-        if (dmnObject.__$$element === "association") {
-          return [];
-        }
-
-        const newNode = ackNode({ type: "xml-qname", localPart: dmnObject["@_id"]! }, dmnObject, index);
-        return newNode ? [newNode] : [];
-      }),
-    ];
-
-    // Assign parents & z-index to NODES
-    for (let i = 0; i < localNodes.length; i++) {
-      const parent = parentIdsById.get(localNodes[i].id);
-      if (parent) {
-        localNodes[i].data.parentRfNode = nodesById.get(
-          buildXmlHref({ namespace: parent.dmnObjectNamespace, id: parent.dmnObjectQName.localPart })
-        );
-        localNodes[i].extent = undefined; // Allows the node to be dragged freely outside of parent's bounds.
-        localNodes[i].zIndex = NODE_LAYERS.NESTED_NODES;
-      }
-
-      if (localNodes[i].type === NODE_TYPES.group) {
-        localNodes[i].zIndex = NODE_LAYERS.GROUP_NODE;
-      } else if (localNodes[i].type === NODE_TYPES.decisionService) {
-        localNodes[i].zIndex = NODE_LAYERS.DECISION_SERVICE_NODE;
-      }
-    }
-
-    const externalNodes = [...dmnShapesByHref.entries()].flatMap(([href, shape]) => {
-      if (nodesById.get(href)) {
-        return [];
-      }
-
-      if (!nodesById.get(href) && !hrefsOfDmnElementRefsOfShapesPointingToExternalDmnObjects.has(href)) {
-        // Unknown local node.
-        console.warn(`DMN DIAGRAM: Found a shape that references a local DRG element that doesn't exist.`, shape);
-        const newNode = ackNode(shape.dmnElementRefQName, null, -1);
-        return newNode ? [newNode] : [];
-      }
-
-      const namespace = thisDmn.model.definitions[`@_xmlns:${shape.dmnElementRefQName.prefix}`];
-      if (!namespace) {
-        console.warn(
-          `DMN DIAGRAM: Found a shape that references an external node with a namespace that is not declared at this DMN.`,
-          shape
-        );
-        const newNode = ackNode(shape.dmnElementRefQName, null, -1);
-        return newNode ? [newNode] : [];
-      }
-
-      const externalDmn = externalDmnsByNamespace.get(namespace);
-      if (!externalDmn) {
-        console.warn(
-          `DMN DIAGRAM: Found a shape that references an external node from a namespace that is not provided on this DMN's external DMNs mapping.`,
-          shape
-        );
-        const newNode = ackNode(shape.dmnElementRefQName, null, -1);
-        return newNode ? [newNode] : [];
-      }
-
-      const externalDrgElementsById = (externalDmn.model.definitions.drgElement ?? []).reduce(
-        (acc, e, index) => acc.set(e["@_id"]!, { element: e, index }),
-        new Map<string, { index: number; element: Unpacked<DMN15__tDefinitions["drgElement"]> }>()
-      );
-
-      const externalDrgElement = externalDrgElementsById.get(shape.dmnElementRefQName.localPart);
-      if (!externalDrgElement) {
-        console.warn(`DMN DIAGRAM: Found a shape that references a non-existent node from an external DMN.`, shape);
-        const newNode = ackNode(shape.dmnElementRefQName, null, -1);
-        return newNode ? [newNode] : [];
-      }
-
-      const newNode = ackNode(shape.dmnElementRefQName, externalDrgElement.element, externalDrgElement.index);
-      return newNode ? [newNode] : [];
-    });
-
-    // Groups are always at the back. Decision Services after groups, then everything else.
-    const sortedNodes = [...localNodes, ...externalNodes]
-      .sort((a, b) => Number(b.type === NODE_TYPES.decisionService) - Number(a.type === NODE_TYPES.decisionService))
-      .sort((a, b) => Number(b.type === NODE_TYPES.group) - Number(a.type === NODE_TYPES.group));
-
-    // console.timeEnd("nodes");
-
-    if (diagram.overlays.enableNodeHierarchyHighlight) {
-      assignClassesToHighlightedHierarchyNodes([...selectedNodesById.keys()], nodesById, edges);
-    }
-
-    return {
-      nodes: sortedNodes,
-      edges: sortedEdges,
-      edgesById,
-      nodesById,
-      selectedNodeTypes,
-      selectedNodesById,
-      selectedEdgesById,
-      drgElementsWithoutVisualRepresentationOnCurrentDrd,
-    };
-  }, [
-    diagram._selectedNodes,
-    diagram.draggingNodes,
-    diagram.resizingNodes,
-    diagram._selectedEdges,
-    diagram.overlays.enableNodeHierarchyHighlight,
-    diagram.snapGrid,
-    thisDmn.model.definitions,
-    hrefsOfDmnElementRefsOfShapesPointingToExternalDmnObjects,
-    dmnEdgesByDmnElementRef,
-    dmnShapesByHref,
-    externalDmnsByNamespace,
-  ]);
-
-  return {
-    drgElementsWithoutVisualRepresentationOnCurrentDrd,
-    dmnShapesByHref,
-    dmnEdgesByDmnElementRef,
-    nodesById,
-    edgesById,
-    nodes,
-    edges,
-    selectedNodeTypes,
-    selectedNodesById,
-    selectedEdgesById,
-  };
-}
-
-export function assignClassesToHighlightedHierarchyNodes(
-  selected: string[],
-  nodes: Map<string, RF.Node>,
-  edges: RF.Edge[]
-) {
-  const nodeVisitor: NodeVisitor = (nodeId, traversalDirection) => {
-    const node = nodes.get(nodeId);
-    if (node) {
-      node.className = `hierarchy ${traversalDirection}`;
-    }
-  };
-
-  const edgeVisitor: EdgeVisitor = (edge, traversalDirection) => {
-    edge.className = `hierarchy ${traversalDirection}`;
-  };
-
-  const __selectedSet = new Set(selected);
-  const __adjMatrix = getAdjMatrix(edges);
-
-  traverse(__adjMatrix, __selectedSet, selected, "up", nodeVisitor, edgeVisitor);
-  traverse(__adjMatrix, __selectedSet, selected, "down", nodeVisitor, edgeVisitor); // Traverse "down" after "up" because when there's a cycle, highlighting a node as a dependency is preferable.
-}
diff --git a/packages/dmn-editor/src/svg/DmnDiagramSvg.tsx b/packages/dmn-editor/src/svg/DmnDiagramSvg.tsx
index 7dc91246484..14ed32fd83b 100644
--- a/packages/dmn-editor/src/svg/DmnDiagramSvg.tsx
+++ b/packages/dmn-editor/src/svg/DmnDiagramSvg.tsx
@@ -27,7 +27,7 @@ import {
   KnowledgeRequirementPath,
 } from "../diagram/edges/Edges";
 import { DmnDiagramNodeData } from "../diagram/nodes/Nodes";
-import { SnapGrid, State } from "../store/Store";
+import { Computed, SnapGrid, State } from "../store/Store";
 import { EdgeMarkers } from "../diagram/edges/EdgeMarkers";
 import { EDGE_TYPES } from "../diagram/edges/EdgeTypes";
 import { getSnappedMultiPointAnchoredEdgePath } from "../diagram/edges/getSnappedMultiPointAnchoredEdgePath";
@@ -54,8 +54,8 @@ import {
 } from "../diagram/nodes/NodeStyle";
 import { NodeType } from "../diagram/connections/graphStructure";
 import { buildFeelQNameFromXmlQName } from "../feel/buildFeelQName";
-import { DerivedStore } from "../store/DerivedStore";
 import { Text } from "@visx/text";
+import { TypeOrReturnType } from "../store/ComputedStateCache";
 
 export function DmnDiagramSvg({
   nodes,
@@ -68,7 +68,7 @@ export function DmnDiagramSvg({
   edges: RF.Edge<DmnDiagramEdgeData>[];
   snapGrid: SnapGrid;
   thisDmn: State["dmn"];
-  importsByNamespace: DerivedStore["importsByNamespace"];
+  importsByNamespace: TypeOrReturnType<Computed["importsByNamespace"]>;
 }) {
   const { nodesSvg, nodesById } = useMemo(() => {
     const nodesById = new Map<string, RF.Node<DmnDiagramNodeData>>();
@@ -102,105 +102,103 @@ export function DmnDiagramSvg({
             }).full;
 
       return (
-        <>
-          <g data-kie-dmn-node-id={node.id}>
-            {node.type === NODE_TYPES.inputData && (
-              <InputDataNodeSvg
-                width={node.width!}
-                height={node.height!}
-                x={node.positionAbsolute!.x}
-                y={node.positionAbsolute!.y}
-                {...style}
-                {...shapeStyle}
-              />
-            )}
-            {node.type === NODE_TYPES.decision && (
-              <DecisionNodeSvg
-                width={node.width!}
-                height={node.height!}
-                x={node.positionAbsolute!.x}
-                y={node.positionAbsolute!.y}
-                {...style}
-                {...shapeStyle}
-              />
-            )}
-            {node.type === NODE_TYPES.bkm && (
-              <BkmNodeSvg
-                width={node.width!}
-                height={node.height!}
-                x={node.positionAbsolute!.x}
-                y={node.positionAbsolute!.y}
-                {...style}
-                {...shapeStyle}
-              />
-            )}
-            {node.type === NODE_TYPES.knowledgeSource && (
-              <KnowledgeSourceNodeSvg
-                width={node.width!}
-                height={node.height!}
-                x={node.positionAbsolute!.x}
-                y={node.positionAbsolute!.y}
-                {...style}
-                {...shapeStyle}
-              />
-            )}
-            {node.type === NODE_TYPES.decisionService && (
-              <DecisionServiceNodeSvg
-                width={node.width!}
-                height={node.height!}
-                x={node.positionAbsolute!.x}
-                y={node.positionAbsolute!.y}
-                showSectionLabels={false}
-                isReadonly={true}
-                {...style}
-                {...shapeStyle}
-              />
-            )}
-            {node.type === NODE_TYPES.group && (
-              <GroupNodeSvg
-                width={node.width!}
-                height={node.height!}
-                x={node.positionAbsolute!.x}
-                y={node.positionAbsolute!.y}
-                {...style}
-                {...(shapeStyle as any)}
-              />
-            )}
-            {node.type === NODE_TYPES.textAnnotation && (
-              <TextAnnotationNodeSvg
-                width={node.width!}
-                height={node.height!}
-                x={node.positionAbsolute!.x}
-                y={node.positionAbsolute!.y}
-                {...style}
-                {...shapeStyle}
-              />
-            )}
-            {node.type === NODE_TYPES.unknown && (
-              <UnknownNodeSvg
-                width={node.width!}
-                height={node.height!}
-                x={node.positionAbsolute!.x}
-                y={node.positionAbsolute!.y}
-                {...style}
-                {...(shapeStyle as any)}
-              />
-            )}
-            <>
-              {label.split("\n").map((labelLine, i) => (
-                <Text
-                  key={i}
-                  lineHeight={fontStyle.lineHeight}
-                  style={{ ...fontStyle, fill: fontStyle.color }}
-                  dy={`calc(1.5em * ${i})`}
-                  {...getNodeLabelSvgTextAlignmentProps(node, getNodeLabelPosition(node.type as NodeType))}
-                >
-                  {labelLine}
-                </Text>
-              ))}
-            </>
-          </g>
-        </>
+        <g data-kie-dmn-node-id={node.id} key={node.id}>
+          {node.type === NODE_TYPES.inputData && (
+            <InputDataNodeSvg
+              width={node.width!}
+              height={node.height!}
+              x={node.positionAbsolute!.x}
+              y={node.positionAbsolute!.y}
+              {...style}
+              {...shapeStyle}
+            />
+          )}
+          {node.type === NODE_TYPES.decision && (
+            <DecisionNodeSvg
+              width={node.width!}
+              height={node.height!}
+              x={node.positionAbsolute!.x}
+              y={node.positionAbsolute!.y}
+              {...style}
+              {...shapeStyle}
+            />
+          )}
+          {node.type === NODE_TYPES.bkm && (
+            <BkmNodeSvg
+              width={node.width!}
+              height={node.height!}
+              x={node.positionAbsolute!.x}
+              y={node.positionAbsolute!.y}
+              {...style}
+              {...shapeStyle}
+            />
+          )}
+          {node.type === NODE_TYPES.knowledgeSource && (
+            <KnowledgeSourceNodeSvg
+              width={node.width!}
+              height={node.height!}
+              x={node.positionAbsolute!.x}
+              y={node.positionAbsolute!.y}
+              {...style}
+              {...shapeStyle}
+            />
+          )}
+          {node.type === NODE_TYPES.decisionService && (
+            <DecisionServiceNodeSvg
+              width={node.width!}
+              height={node.height!}
+              x={node.positionAbsolute!.x}
+              y={node.positionAbsolute!.y}
+              showSectionLabels={false}
+              isReadonly={true}
+              {...style}
+              {...shapeStyle}
+            />
+          )}
+          {node.type === NODE_TYPES.group && (
+            <GroupNodeSvg
+              width={node.width!}
+              height={node.height!}
+              x={node.positionAbsolute!.x}
+              y={node.positionAbsolute!.y}
+              {...style}
+              {...(shapeStyle as any)}
+            />
+          )}
+          {node.type === NODE_TYPES.textAnnotation && (
+            <TextAnnotationNodeSvg
+              width={node.width!}
+              height={node.height!}
+              x={node.positionAbsolute!.x}
+              y={node.positionAbsolute!.y}
+              {...style}
+              {...shapeStyle}
+            />
+          )}
+          {node.type === NODE_TYPES.unknown && (
+            <UnknownNodeSvg
+              width={node.width!}
+              height={node.height!}
+              x={node.positionAbsolute!.x}
+              y={node.positionAbsolute!.y}
+              {...style}
+              {...(shapeStyle as any)}
+            />
+          )}
+          <>
+            {label.split("\n").map((labelLine, i) => (
+              <Text
+                key={i}
+                lineHeight={fontStyle.lineHeight}
+                style={{ ...fontStyle }}
+                dy={`calc(1.5em * ${i})`}
+                {...getNodeLabelSvgTextAlignmentProps(node, getNodeLabelPosition(node.type as NodeType))}
+              >
+                {labelLine}
+              </Text>
+            ))}
+          </>
+        </g>
       );
     });
 
@@ -211,23 +209,35 @@ export function DmnDiagramSvg({
     <>
       <EdgeMarkers />
       {edges.map((e) => {
+        const s = nodesById?.get(e.source);
+        const t = nodesById?.get(e.target);
         const { path } = getSnappedMultiPointAnchoredEdgePath({
           snapGrid,
           dmnEdge: e.data?.dmnEdge,
           dmnShapeSource: e.data?.dmnShapeSource,
           dmnShapeTarget: e.data?.dmnShapeTarget,
-          sourceNode: nodesById?.get(e.source),
-          targetNode: nodesById?.get(e.target),
+          sourceNodeBounds: {
+            x: s?.positionAbsolute?.x,
+            y: s?.positionAbsolute?.y,
+            width: s?.width,
+            height: s?.height,
+          },
+          targetNodeBounds: {
+            x: t?.positionAbsolute?.x,
+            y: t?.positionAbsolute?.y,
+            width: t?.width,
+            height: t?.height,
+          },
         });
         return (
-          <>
+          <React.Fragment key={e.id}>
             {e.type === EDGE_TYPES.informationRequirement && <InformationRequirementPath d={path} />}
             {e.type === EDGE_TYPES.knowledgeRequirement && <KnowledgeRequirementPath d={path} />}
             {e.type === EDGE_TYPES.authorityRequirement && (
               <AuthorityRequirementPath d={path} centerToConnectionPoint={true} />
             )}
             {e.type === EDGE_TYPES.association && <AssociationPath d={path} />}
-          </>
+          </React.Fragment>
         );
       })}
       {nodesSvg}
diff --git a/packages/dmn-editor/tsconfig.json b/packages/dmn-editor/tsconfig.json
index 6a8d695ed19..e1728dbdb5f 100644
--- a/packages/dmn-editor/tsconfig.json
+++ b/packages/dmn-editor/tsconfig.json
@@ -1,8 +1,10 @@
 {
   "extends": "@kie-tools/tsconfig/tsconfig.json",
   "compilerOptions": {
-    "outDir": "dist",
-    "esModuleInterop": true
+    "module": "ES6",
+    "moduleResolution": "Node",
+    "esModuleInterop": true,
+    "outDir": "./dist"
   },
   "include": ["./src"]
 }
diff --git a/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts b/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts
index 5b9366d7884..c26f7ba35f1 100644
--- a/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts
+++ b/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts
@@ -513,7 +513,7 @@ export class VariablesRepository {
         break;
 
       default:
-        throw new Error("Unknown or not supported type for expression.");
+      // throw new Error("Unknown or not supported type for expression.");
     }
   }
 
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 119a03261d6..c5f21896cf6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3352,6 +3352,12 @@ importers:
       d3-selection:
         specifier: ^3.0.0
         version: 3.0.0
+      elkjs:
+        specifier: ^0.9.1
+        version: 0.9.1
+      fast-deep-equal:
+        specifier: ^3.1.3
+        version: 3.1.3
       immer:
         specifier: ^10.0.3
         version: 10.0.3(patch_hash=utu5oov26wz5mjuays57tp3ybu)
@@ -30078,6 +30084,11 @@ packages:
       { integrity: sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ== }
     dev: false
 
+  /elkjs@0.9.1:
+    resolution:
+      { integrity: sha512-JWKDyqAdltuUcyxaECtYG6H4sqysXSLeoXuGUBfRNESMTkj+w+qdb0jya8Z/WI0jVd03WQtCGhS6FOFtlhD5FQ== }
+    dev: false
+
   /ellipsize@0.2.0:
     resolution:
       { integrity: sha512-InJhblLPZbBjw3N49knOWonfprgKPLKGySmG6bGHi7WsD5OkXIIlLkU4AguROmaMZ0v1BRdo267wEc0Pexw8ww== }


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