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 6e4f2aef901 kie-issues#937: On the DMN Editor, adding a DRD then 
pressing "Undo", makes the Editor will crash (#2304)
6e4f2aef901 is described below

commit 6e4f2aef901c2559c3357cd9b5b229919d8fc907
Author: Luiz João Motta <[email protected]>
AuthorDate: Wed May 8 11:10:04 2024 -0300

    kie-issues#937: On the DMN Editor, adding a DRD then pressing "Undo", makes 
the Editor will crash (#2304)
---
 packages/dmn-editor/src/DmnEditor.tsx              |  1 +
 .../dmn-editor/src/autolayout/AutolayoutButton.tsx |  8 ++---
 .../src/boxedExpressions/BoxedExpressionScreen.tsx |  7 ++--
 packages/dmn-editor/src/clipboard/Clipboard.ts     |  6 ++--
 packages/dmn-editor/src/diagram/Diagram.tsx        | 38 +++++++++++-----------
 .../dmn-editor/src/diagram/DiagramCommands.tsx     | 16 ++++-----
 .../dmn-editor/src/diagram/DrdSelectorPanel.tsx    | 19 ++++++-----
 packages/dmn-editor/src/diagram/Palette.tsx        | 18 ++++++----
 .../dmn-editor/src/diagram/edges/Waypoints.tsx     |  8 ++---
 .../diagram/edges/usePotentialWaypointControls.ts  |  2 +-
 packages/dmn-editor/src/diagram/nodes/Nodes.tsx    |  2 +-
 .../dmn-editor/src/propertiesPanel/FontOptions.tsx |  5 ++-
 .../src/propertiesPanel/ShapeOptions.tsx           | 10 ++++--
 packages/dmn-editor/src/store/Store.ts             | 24 +++++++++++---
 .../src/store/computed/computeIndexes.ts           |  4 +--
 packages/dmn-editor/src/store/computed/initial.ts  |  4 +++
 16 files changed, 104 insertions(+), 68 deletions(-)

diff --git a/packages/dmn-editor/src/DmnEditor.tsx 
b/packages/dmn-editor/src/DmnEditor.tsx
index 571d18ec019..8e0e26ab201 100644
--- a/packages/dmn-editor/src/DmnEditor.tsx
+++ b/packages/dmn-editor/src/DmnEditor.tsx
@@ -247,6 +247,7 @@ export const DmnEditorInternal = ({
         return;
       }
       state.dmn.model = normalize(model);
+
       dmnModelBeforeEditingRef.current = state.dmn.model;
     });
   }, [dmnEditorStoreApi, model]);
diff --git a/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx 
b/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx
index 0bf61e814c2..e2d88e4aef3 100644
--- a/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx
+++ b/packages/dmn-editor/src/autolayout/AutolayoutButton.tsx
@@ -372,7 +372,7 @@ export function AutolayoutButton() {
 
           repositionNode({
             definitions: s.dmn.model.definitions,
-            drdIndex: s.diagram.drdIndex,
+            drdIndex: s.computed(s).getDrdIndex(),
             controlWaypointsByEdge: new Map(),
             change: {
               nodeType: node.type as NodeType,
@@ -406,7 +406,7 @@ export function AutolayoutButton() {
 
           resizeNode({
             definitions: s.dmn.model.definitions,
-            drdIndex: s.diagram.drdIndex,
+            drdIndex: s.computed(s).getDrdIndex(),
             dmnShapesByHref: s.computed(s).indexedDrd().dmnShapesByHref,
             snapGrid,
             change: {
@@ -454,7 +454,7 @@ export function AutolayoutButton() {
 
         updateDecisionServiceDividerLine({
           definitions: s.dmn.model.definitions,
-          drdIndex: s.diagram.drdIndex,
+          drdIndex: s.computed(s).getDrdIndex(),
           dmnShapesByHref: s.computed(s).indexedDrd().dmnShapesByHref,
           drgElementIndex: parentNode.data.index,
           shapeIndex: parentNode.data.shape.index,
@@ -481,7 +481,7 @@ export function AutolayoutButton() {
 
         addEdge({
           definitions: s.dmn.model.definitions,
-          drdIndex: s.diagram.drdIndex,
+          drdIndex: s.computed(s).getDrdIndex(),
           edge: {
             autoPositionedEdgeMarker: undefined,
             type: edge.type as EdgeType,
diff --git a/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx 
b/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx
index dbc155484f7..791ac403c1e 100644
--- a/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx
+++ b/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx
@@ -101,6 +101,7 @@ export function BoxedExpressionScreen({ container }: { 
container: React.RefObjec
     (s) => 
s.computed(s).getExternalModelTypesByNamespace(externalModelsByNamespace).pmmls
   );
   const isAlternativeInputDataShape = useDmnEditorStore((s) => 
s.computed(s).isAlternativeInputDataShape());
+  const drdIndex = useDmnEditorStore((s) => s.computed(s).getDrdIndex());
 
   const onRequestFeelVariables = useCallback(() => {
     const externalModels = new Map<string, DmnLatestModel>();
@@ -142,7 +143,7 @@ export function BoxedExpressionScreen({ container }: { 
container: React.RefObjec
   // recalculated, breaking batching.
   const widthsById = useMemo(() => {
     return (
-      
thisDmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[diagram.drdIndex]["di:extension"]?.[
+      
thisDmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[drdIndex]["di:extension"]?.[
         "kie:ComponentsWidthsExtension"
       ]?.["kie:ComponentWidths"] ?? []
     ).reduce((acc, c) => {
@@ -155,7 +156,7 @@ export function BoxedExpressionScreen({ container }: { 
container: React.RefObjec
         );
       }
     }, new Map<string, number[]>());
-  }, [diagram.drdIndex, thisDmn.model.definitions]);
+  }, [drdIndex, thisDmn.model.definitions]);
 
   const expression = useMemo(() => {
     if (!drgElement) {
@@ -193,7 +194,7 @@ export function BoxedExpressionScreen({ container }: { 
container: React.RefObjec
 
         updateExpressionWidths({
           definitions: state.dmn.model.definitions,
-          drdIndex: state.diagram.drdIndex,
+          drdIndex: state.computed(state).getDrdIndex(),
           widthsById: newWidthsById,
         });
       });
diff --git a/packages/dmn-editor/src/clipboard/Clipboard.ts 
b/packages/dmn-editor/src/clipboard/Clipboard.ts
index b1b1e7e87d7..87e80ad728c 100644
--- a/packages/dmn-editor/src/clipboard/Clipboard.ts
+++ b/packages/dmn-editor/src/clipboard/Clipboard.ts
@@ -188,9 +188,9 @@ export function buildClipboardFromDiagram(rfState: 
RF.ReactFlowState, dmnEditorS
     .getOriginalIds();
 
   clipboard.widths = (
-    
dmnEditorState.dmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[dmnEditorState.diagram.drdIndex][
-      "di:extension"
-    ]?.["kie:ComponentsWidthsExtension"]?.["kie:ComponentWidths"] ?? []
+    
dmnEditorState.dmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[
+      dmnEditorState.computed(dmnEditorState).getDrdIndex()
+    
]["di:extension"]?.["kie:ComponentsWidthsExtension"]?.["kie:ComponentWidths"] 
?? []
   ).filter((w: KIE__tComponentWidths) => 
idsOnDrgElementTrees.has(w["@_dmnElementRef"]!));
 
   const artifacts = dmnEditorState.dmn.model.definitions.artifact ?? [];
diff --git a/packages/dmn-editor/src/diagram/Diagram.tsx 
b/packages/dmn-editor/src/diagram/Diagram.tsx
index 57f591c6f9e..504586968f4 100644
--- a/packages/dmn-editor/src/diagram/Diagram.tsx
+++ b/packages/dmn-editor/src/diagram/Diagram.tsx
@@ -209,7 +209,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
 
           addEdge({
             definitions: state.dmn.model.definitions,
-            drdIndex: state.diagram.drdIndex,
+            drdIndex: state.computed(state).getDrdIndex(),
             edge: {
               type: sourceHandle as EdgeType,
               targetHandle: targetHandle as PositionalNodeHandleId,
@@ -307,7 +307,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
           dmnEditorStoreApi.setState((state) => {
             const { id, href: newNodeId } = addStandaloneNode({
               definitions: state.dmn.model.definitions,
-              drdIndex: state.diagram.drdIndex,
+              drdIndex: state.computed(state).getDrdIndex(),
               newNode: {
                 type: typeOfNewNodeFromPalette,
                 bounds: {
@@ -371,7 +371,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
               addExistingDecisionServiceToDrd({
                 decisionService: externalDrgElement,
                 decisionServiceNamespace: 
externalNodeDmn.model.definitions["@_namespace"],
-                drdIndex: state.diagram.drdIndex,
+                drdIndex: state.computed(state).getDrdIndex(),
                 dropPoint,
                 externalDmnsIndex,
                 thisDmnsDefinitions: state.dmn.model.definitions,
@@ -382,7 +382,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
               const externalNodeType = 
getNodeTypeFromDmnObject(externalDrgElement)!;
               addShape({
                 definitions: state.dmn.model.definitions,
-                drdIndex: state.diagram.drdIndex,
+                drdIndex: state.computed(state).getDrdIndex(),
                 nodeType: externalNodeType,
                 shape: {
                   "@_dmnElementRef": xmlHrefToQName(externalNodeHref, 
state.dmn.model.definitions),
@@ -419,7 +419,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
               addExistingDecisionServiceToDrd({
                 decisionService: drgElement,
                 decisionServiceNamespace: 
state.dmn.model.definitions["@_namespace"],
-                drdIndex: state.diagram.drdIndex,
+                drdIndex: state.computed(state).getDrdIndex(),
                 dropPoint,
                 externalDmnsIndex: 
state.computed(state).getExternalModelTypesByNamespace(externalModelsByNamespace)
                   .dmns,
@@ -431,7 +431,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
               const nodeType = getNodeTypeFromDmnObject(drgElement)!;
               addShape({
                 definitions: state.dmn.model.definitions,
-                drdIndex: state.diagram.drdIndex,
+                drdIndex: state.computed(state).getDrdIndex(),
                 nodeType,
                 shape: {
                   "@_dmnElementRef": buildXmlQName({ type: "xml-qname", 
localPart: drgElement["@_id"]! }),
@@ -524,7 +524,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
 
           const { id, href: newDmnObejctHref } = addConnectedNode({
             definitions: state.dmn.model.definitions,
-            drdIndex: state.diagram.drdIndex,
+            drdIndex: state.computed(state).getDrdIndex(),
             edgeType,
             sourceNode: {
               href: sourceNode.id,
@@ -629,7 +629,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
                   ) {
                     resizeNode({
                       definitions: state.dmn.model.definitions,
-                      drdIndex: state.diagram.drdIndex,
+                      drdIndex: state.computed(state).getDrdIndex(),
                       dmnShapesByHref: 
state.computed(state).indexedDrd().dmnShapesByHref,
                       snapGrid: state.diagram.snapGrid,
                       change: {
@@ -668,7 +668,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
                     .nodesById.get(change.id)!;
                   const { delta } = repositionNode({
                     definitions: state.dmn.model.definitions,
-                    drdIndex: state.diagram.drdIndex,
+                    drdIndex: state.computed(state).getDrdIndex(),
                     controlWaypointsByEdge,
                     change: {
                       type: "absolute",
@@ -713,7 +713,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
                       );
                       repositionNode({
                         definitions: state.dmn.model.definitions,
-                        drdIndex: state.diagram.drdIndex,
+                        drdIndex: state.computed(state).getDrdIndex(),
                         controlWaypointsByEdge,
                         change: {
                           type: "absolute",
@@ -739,7 +739,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
                 deleteNode({
                   drgEdges: 
state.computed(state).getDiagramData(externalModelsByNamespace).drgEdges,
                   definitions: state.dmn.model.definitions,
-                  drdIndex: state.diagram.drdIndex,
+                  drdIndex: state.computed(state).getDrdIndex(),
                   dmnObjectNamespace: node.data.dmnObjectNamespace ?? 
state.dmn.model.definitions["@_namespace"],
                   dmnObjectQName: node.data.dmnObjectQName,
                   dmnObjectId: node.data.dmnObject?.["@_id"],
@@ -877,7 +877,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
               for (let i = 0; i < selectedNodes.length; i++) {
                 addDecisionToDecisionService({
                   definitions: state.dmn.model.definitions,
-                  drdIndex: state.diagram.drdIndex,
+                  drdIndex: state.computed(state).getDrdIndex(),
                   decisionId: selectedNodes[i].data.dmnObject!["@_id"]!, // We 
can assume that all selected nodes are Decisions because the contaiment was 
validated above.
                   decisionServiceId: state
                     .computed(state)
@@ -915,7 +915,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
                 if (edge?.data) {
                   deleteEdge({
                     definitions: state.dmn.model.definitions,
-                    drdIndex: state.diagram.drdIndex,
+                    drdIndex: state.computed(state).getDrdIndex(),
                     edge: { id: change.id, dmnObject: edge.data.dmnObject },
                     mode: EdgeDeletionMode.FROM_DRG_AND_ALL_DRDS,
                   });
@@ -966,7 +966,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
 
           const { newDmnEdge } = addEdge({
             definitions: state.dmn.model.definitions,
-            drdIndex: state.diagram.drdIndex,
+            drdIndex: state.computed(state).getDrdIndex(),
             edge: {
               autoPositionedEdgeMarker: undefined,
               type: oldEdge.type as EdgeType,
@@ -999,7 +999,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
           if (newDmnEdge["@_dmnElementRef"] !== oldEdge.id) {
             const { deletedDmnEdgeOnCurrentDrd } = deleteEdge({
               definitions: state.dmn.model.definitions,
-              drdIndex: state.diagram.drdIndex,
+              drdIndex: state.computed(state).getDrdIndex(),
               edge: { id: oldEdge.id, dmnObject: oldEdge.data!.dmnObject },
               mode: EdgeDeletionMode.FROM_DRG_AND_ALL_DRDS,
             });
@@ -1229,7 +1229,7 @@ function DmnDiagramEmptyState({
                 dmnEditorStoreApi.setState((state) => {
                   const { href: decisionNodeHref } = addStandaloneNode({
                     definitions: state.dmn.model.definitions,
-                    drdIndex: state.diagram.drdIndex,
+                    drdIndex: state.computed(state).getDrdIndex(),
                     newNode: {
                       type: NODE_TYPES.decision,
                       bounds: {
@@ -1267,7 +1267,7 @@ function DmnDiagramEmptyState({
 
                   updateExpressionWidths({
                     definitions: state.dmn.model.definitions,
-                    drdIndex: state.diagram.drdIndex,
+                    drdIndex: state.computed(state).getDrdIndex(),
                     widthsById: defaultWidthsById,
                   });
 
@@ -1298,7 +1298,7 @@ function DmnDiagramEmptyState({
 
                   const { href: inputDataNodeHref, shapeId: inputDataShapeId } 
= addStandaloneNode({
                     definitions: state.dmn.model.definitions,
-                    drdIndex: state.diagram.drdIndex,
+                    drdIndex: state.computed(state).getDrdIndex(),
                     newNode: {
                       type: NODE_TYPES.inputData,
                       bounds: inputDataNodeBounds,
@@ -1307,7 +1307,7 @@ function DmnDiagramEmptyState({
 
                   const { href: decisionNodeHref } = addConnectedNode({
                     definitions: state.dmn.model.definitions,
-                    drdIndex: state.diagram.drdIndex,
+                    drdIndex: state.computed(state).getDrdIndex(),
                     edgeType: EDGE_TYPES.informationRequirement,
                     sourceNode: {
                       href: inputDataNodeHref,
diff --git a/packages/dmn-editor/src/diagram/DiagramCommands.tsx 
b/packages/dmn-editor/src/diagram/DiagramCommands.tsx
index 9d073b1c98c..a05ce8736df 100644
--- a/packages/dmn-editor/src/diagram/DiagramCommands.tsx
+++ b/packages/dmn-editor/src/diagram/DiagramCommands.tsx
@@ -131,7 +131,7 @@ export function DiagramCommands(props: {}) {
           [...copiedEdgesById.values(), 
...danglingEdgesById.values()].forEach((edge) => {
             deleteEdge({
               definitions: state.dmn.model.definitions,
-              drdIndex: state.diagram.drdIndex,
+              drdIndex: state.computed(state).getDrdIndex(),
               edge: { id: edge.id, dmnObject: edge.data!.dmnObject },
               mode: EdgeDeletionMode.FROM_DRG_AND_ALL_DRDS,
             });
@@ -150,7 +150,7 @@ export function DiagramCommands(props: {}) {
                 deleteNode({
                   drgEdges: 
state.computed(state).getDiagramData(externalModelsByNamespace).drgEdges,
                   definitions: state.dmn.model.definitions,
-                  drdIndex: state.diagram.drdIndex,
+                  drdIndex: state.computed(state).getDrdIndex(),
                   dmnObjectNamespace: node.data.dmnObjectNamespace ?? 
state.dmn.model.definitions["@_namespace"],
                   dmnObjectQName: node.data.dmnObjectQName,
                   dmnObjectId: node.data.dmnObject?.["@_id"],
@@ -235,7 +235,7 @@ export function DiagramCommands(props: {}) {
 
           const { diagramElements, widths } = addOrGetDrd({
             definitions: state.dmn.model.definitions,
-            drdIndex: state.diagram.drdIndex,
+            drdIndex: state.computed(state).getDrdIndex(),
           });
           diagramElements.push(...clipboard.shapes.map((s) => ({ ...s, 
__$$element: "dmndi:DMNShape" as const })));
           diagramElements.push(...clipboard.edges.map((s) => ({ ...s, 
__$$element: "dmndi:DMNEdge" as const })));
@@ -307,7 +307,7 @@ export function DiagramCommands(props: {}) {
 
         const { href: newNodeId } = addStandaloneNode({
           definitions: state.dmn.model.definitions,
-          drdIndex: state.diagram.drdIndex,
+          drdIndex: state.computed(state).getDrdIndex(),
           newNode: {
             type: NODE_TYPES.group,
             bounds: getBounds({
@@ -368,7 +368,7 @@ export function DiagramCommands(props: {}) {
                 externalDmnsIndex: 
state.computed(state).getExternalModelTypesByNamespace(externalModelsByNamespace)
                   .dmns,
                 definitions: state.dmn.model.definitions,
-                drdIndex: state.diagram.drdIndex,
+                drdIndex: state.computed(state).getDrdIndex(),
                 dmnObjectNamespace:
                   nodesById.get(edge.source)!.data.dmnObjectNamespace ?? 
state.dmn.model.definitions["@_namespace"],
                 dmnObjectId: 
nodesById.get(edge.source)!.data.dmnObject?.["@_id"],
@@ -378,7 +378,7 @@ export function DiagramCommands(props: {}) {
                 externalDmnsIndex: 
state.computed(state).getExternalModelTypesByNamespace(externalModelsByNamespace)
                   .dmns,
                 definitions: state.dmn.model.definitions,
-                drdIndex: state.diagram.drdIndex,
+                drdIndex: state.computed(state).getDrdIndex(),
                 dmnObjectNamespace:
                   nodesById.get(edge.target)!.data.dmnObjectNamespace ?? 
state.dmn.model.definitions["@_namespace"],
                 dmnObjectId: 
nodesById.get(edge.target)!.data.dmnObject?.["@_id"],
@@ -386,7 +386,7 @@ export function DiagramCommands(props: {}) {
           ) {
             deleteEdge({
               definitions: state.dmn.model.definitions,
-              drdIndex: state.diagram.drdIndex,
+              drdIndex: state.computed(state).getDrdIndex(),
               edge: { id: edge.id, dmnObject: edge.data!.dmnObject },
               mode: EdgeDeletionMode.FROM_CURRENT_DRD_ONLY,
             });
@@ -403,7 +403,7 @@ export function DiagramCommands(props: {}) {
             drgEdges: [], // Deleting from DRD only.
             definitions: state.dmn.model.definitions,
             externalDmnsIndex: 
state.computed(state).getExternalModelTypesByNamespace(externalModelsByNamespace).dmns,
-            drdIndex: state.diagram.drdIndex,
+            drdIndex: state.computed(state).getDrdIndex(),
             dmnObjectNamespace: node.data.dmnObjectNamespace ?? 
state.dmn.model.definitions["@_namespace"],
             dmnObjectQName: node.data.dmnObjectQName,
             dmnObjectId: node.data.dmnObject?.["@_id"],
diff --git a/packages/dmn-editor/src/diagram/DrdSelectorPanel.tsx 
b/packages/dmn-editor/src/diagram/DrdSelectorPanel.tsx
index 465cdb16004..65f6b15cc7c 100644
--- a/packages/dmn-editor/src/diagram/DrdSelectorPanel.tsx
+++ b/packages/dmn-editor/src/diagram/DrdSelectorPanel.tsx
@@ -37,11 +37,12 @@ import { useCallback } from "react";
 export function DrdSelectorPanel() {
   const thisDmn = useDmnEditorStore((s) => s.dmn);
   const diagram = useDmnEditorStore((s) => s.diagram);
+  const drdIndex = useDmnEditorStore((s) => s.computed(s).getDrdIndex());
   const isAlternativeInputDataShape = useDmnEditorStore((s) => 
s.computed(s).isAlternativeInputDataShape());
   const drdName = useDmnEditorStore(
     (s) =>
-      
s.dmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[s.diagram.drdIndex]?.["@_name"]
 ||
-      getDefaultDrdName({ drdIndex: s.diagram.drdIndex })
+      
s.dmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[s.computed(s).getDrdIndex()]?.["@_name"]
 ||
+      getDefaultDrdName({ drdIndex: s.computed(s).getDrdIndex() })
   );
 
   const dmnEditorStoreApi = useDmnEditorStoreApi();
@@ -51,8 +52,8 @@ export function DrdSelectorPanel() {
   const removeDrd = useCallback(() => {
     dmnEditorStoreApi.setState((s) => {
       const nextDrds = 
s.dmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"];
-      nextDrds?.splice(s.diagram.drdIndex, 1);
-      s.diagram.drdIndex = Math.max(0, Math.min(s.diagram.drdIndex, 
(nextDrds?.length ?? 0) - 1));
+      nextDrds?.splice(s.computed(s).getDrdIndex(), 1);
+      s.diagram.__unsafeDrdIndex = Math.max(0, 
Math.min(s.computed(s).getDrdIndex(), (nextDrds?.length ?? 0) - 1));
     });
   }, [dmnEditorStoreApi]);
 
@@ -89,7 +90,7 @@ export function DrdSelectorPanel() {
                     drdIndex: newIndex,
                   });
 
-                  state.diagram.drdIndex = newIndex;
+                  state.diagram.__unsafeDrdIndex = newIndex;
                   state.diagram.openLhsPanel = DiagramLhsPanel.DRG_NODES;
                   state.focus.consumableId = getDrdId({ drdIndex: newIndex });
                 });
@@ -118,10 +119,10 @@ export function DrdSelectorPanel() {
             {drds.map((drd, i) => (
               <React.Fragment key={drd["@_id"]!}>
                 <button
-                  className={i === diagram.drdIndex ? "active" : undefined}
+                  className={i === drdIndex ? "active" : undefined}
                   onClick={() => {
                     dmnEditorStoreApi.setState((state) => {
-                      state.diagram.drdIndex = i;
+                      state.diagram.__unsafeDrdIndex = i;
                     });
                   }}
                 >
@@ -165,7 +166,7 @@ export function DrdSelectorPanel() {
                       dmnEditorStoreApi.setState((s) => {
                         const { diagram: drd } = addOrGetDrd({
                           definitions: s.dmn.model.definitions,
-                          drdIndex: s.diagram.drdIndex,
+                          drdIndex: s.computed(s).getDrdIndex(),
                         });
                         drd["@_useAlternativeInputDataShape"] = false;
                       })
@@ -187,7 +188,7 @@ export function DrdSelectorPanel() {
                       dmnEditorStoreApi.setState((s) => {
                         const { diagram: drd } = addOrGetDrd({
                           definitions: s.dmn.model.definitions,
-                          drdIndex: s.diagram.drdIndex,
+                          drdIndex: s.computed(s).getDrdIndex(),
                         });
                         drd["@_useAlternativeInputDataShape"] = true;
                       })
diff --git a/packages/dmn-editor/src/diagram/Palette.tsx 
b/packages/dmn-editor/src/diagram/Palette.tsx
index 6d21a3a2313..77a7f980b2a 100644
--- a/packages/dmn-editor/src/diagram/Palette.tsx
+++ b/packages/dmn-editor/src/diagram/Palette.tsx
@@ -63,6 +63,7 @@ export function Palette({ pulse }: { pulse: boolean }) {
   const thisDmn = useDmnEditorStore((s) => s.dmn.model);
   const rfStoreApi = RF.useStoreApi();
   const isAlternativeInputDataShape = useDmnEditorStore((s) => 
s.computed(s).isAlternativeInputDataShape());
+  const drdIndex = useDmnEditorStore((s) => s.computed(s).getDrdIndex());
 
   const groupNodes = useCallback(() => {
     dmnEditorStoreApi.setState((state) => {
@@ -77,7 +78,7 @@ export function Palette({ pulse }: { pulse: boolean }) {
 
       const { href: newNodeId } = addStandaloneNode({
         definitions: state.dmn.model.definitions,
-        drdIndex: diagram.drdIndex,
+        drdIndex: state.computed(state).getDrdIndex(),
         newNode: {
           type: NODE_TYPES.group,
           bounds: getBounds({
@@ -89,9 +90,9 @@ export function Palette({ pulse }: { pulse: boolean }) {
 
       state.dispatch(state).diagram.setNodeStatus(newNodeId, { selected: true 
});
     });
-  }, [diagram.drdIndex, dmnEditorStoreApi, rfStoreApi]);
+  }, [dmnEditorStoreApi, rfStoreApi]);
 
-  const drd = 
thisDmn.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[diagram.drdIndex];
+  const drd = 
thisDmn.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]?.[drdIndex];
 
   const drdSelectorPopoverRef = React.useRef<HTMLDivElement>(null);
   const nodesPalletePopoverRef = React.useRef<HTMLDivElement>(null);
@@ -107,15 +108,18 @@ export function Palette({ pulse }: { pulse: boolean }) {
             validate={() => true}
             allUniqueNames={() => new Map()}
             name={drd?.["@_name"] ?? ""}
-            prefix={`${diagram.drdIndex + 1}.`}
-            id={getDrdId({ drdIndex: diagram.drdIndex })}
+            prefix={`${drdIndex + 1}.`}
+            id={getDrdId({ drdIndex: drdIndex })}
             onRenamed={(newName) => {
               dmnEditorStoreApi.setState((state) => {
-                const drd = addOrGetDrd({ definitions: 
state.dmn.model.definitions, drdIndex: diagram.drdIndex });
+                const drd = addOrGetDrd({
+                  definitions: state.dmn.model.definitions,
+                  drdIndex: state.computed(state).getDrdIndex(),
+                });
                 drd.diagram["@_name"] = newName;
               });
             }}
-            placeholder={getDefaultDrdName({ drdIndex: diagram.drdIndex })}
+            placeholder={getDefaultDrdName({ drdIndex: drdIndex })}
             isReadonly={false}
             isPlain={true}
             shouldCommitOnBlur={true}
diff --git a/packages/dmn-editor/src/diagram/edges/Waypoints.tsx 
b/packages/dmn-editor/src/diagram/edges/Waypoints.tsx
index e5fca361a2a..643d25185d0 100644
--- a/packages/dmn-editor/src/diagram/edges/Waypoints.tsx
+++ b/packages/dmn-editor/src/diagram/edges/Waypoints.tsx
@@ -68,7 +68,7 @@ export function Waypoint({
 }) {
   const circleRef = React.useRef<SVGCircleElement>(null);
   const diagram = useDmnEditorStore((s) => s.diagram);
-  const dispatch = useDmnEditorStore((s) => s.dispatch);
+  const drdIndex = useDmnEditorStore((s) => s.computed(s).getDrdIndex());
   const { setState } = useDmnEditorStoreApi();
 
   useEffect(() => {
@@ -85,7 +85,7 @@ export function Waypoint({
         setState((state) => {
           repositionEdgeWaypoint({
             definitions: state.dmn.model.definitions,
-            drdIndex: diagram.drdIndex,
+            drdIndex: drdIndex,
             edgeIndex,
             waypointIndex: index,
             waypoint: snapPoint(diagram.snapGrid, { "@_x": e.x, "@_y": e.y }),
@@ -101,7 +101,7 @@ export function Waypoint({
     return () => {
       selection.on(".drag", null);
     };
-  }, [diagram.drdIndex, diagram.snapGrid, edgeId, edgeIndex, index, 
onDragStop, setState]);
+  }, [drdIndex, diagram.snapGrid, edgeId, edgeIndex, index, onDragStop, 
setState]);
 
   return (
     <circle
@@ -118,7 +118,7 @@ export function Waypoint({
         setState((state) => {
           deleteEdgeWaypoint({
             definitions: state.dmn.model.definitions,
-            drdIndex: diagram.drdIndex,
+            drdIndex: drdIndex,
             edgeIndex,
             waypointIndex: index,
           });
diff --git 
a/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts 
b/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts
index 4106ae35051..1a80d491a4b 100644
--- a/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts
+++ b/packages/dmn-editor/src/diagram/edges/usePotentialWaypointControls.ts
@@ -34,7 +34,7 @@ export function usePotentialWaypointControls(
   interactionPathRef: React.RefObject<SVGPathElement>
 ) {
   const snapGrid = useDmnEditorStore((s) => s.diagram.snapGrid);
-  const drdIndex = useDmnEditorStore((s) => s.diagram.drdIndex);
+  const drdIndex = useDmnEditorStore((s) => s.computed(s).getDrdIndex());
   const isDraggingWaypoint = useDmnEditorStore((s) => 
!!s.diagram.draggingWaypoints.find((e) => e === edgeId));
   const dmnEditorStoreApi = useDmnEditorStoreApi();
   const reactFlowInstance = RF.useReactFlow<DmnDiagramNodeData, 
DmnDiagramEdgeData>();
diff --git a/packages/dmn-editor/src/diagram/nodes/Nodes.tsx 
b/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
index fed4d403ab6..cf7a7240e6b 100644
--- a/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
@@ -962,7 +962,7 @@ export const DecisionServiceNode = React.memo(
           dmnEditorStoreApi.setState((state) => {
             updateDecisionServiceDividerLine({
               definitions: state.dmn.model.definitions,
-              drdIndex: state.diagram.drdIndex,
+              drdIndex: state.computed(state).getDrdIndex(),
               dmnShapesByHref: 
state.computed(state).indexedDrd().dmnShapesByHref,
               drgElementIndex: index,
               shapeIndex: shape.index,
diff --git a/packages/dmn-editor/src/propertiesPanel/FontOptions.tsx 
b/packages/dmn-editor/src/propertiesPanel/FontOptions.tsx
index b87b0cf7b2a..fabeac4a0fc 100644
--- a/packages/dmn-editor/src/propertiesPanel/FontOptions.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/FontOptions.tsx
@@ -88,7 +88,10 @@ export function FontOptions({ startExpanded, nodeIds }: { 
startExpanded: boolean
   const setShapeStyles = useCallback(
     (callback: (shape: DMNDI15__DMNShape[], state: State) => void) => {
       dmnEditorStoreApi.setState((s) => {
-        const { diagramElements } = addOrGetDrd({ definitions: 
s.dmn.model.definitions, drdIndex: s.diagram.drdIndex });
+        const { diagramElements } = addOrGetDrd({
+          definitions: s.dmn.model.definitions,
+          drdIndex: s.computed(s).getDrdIndex(),
+        });
 
         const shapes = nodeIds.map((nodeId) => {
           const shape = s.computed(s).indexedDrd().dmnShapesByHref.get(nodeId);
diff --git a/packages/dmn-editor/src/propertiesPanel/ShapeOptions.tsx 
b/packages/dmn-editor/src/propertiesPanel/ShapeOptions.tsx
index b58e300ee03..bf3f81c8e09 100644
--- a/packages/dmn-editor/src/propertiesPanel/ShapeOptions.tsx
+++ b/packages/dmn-editor/src/propertiesPanel/ShapeOptions.tsx
@@ -109,7 +109,10 @@ export function ShapeOptions({
   const setBounds = useCallback(
     (callback: (bounds: DC__Bounds, state: State) => void, nodeId: string) => {
       dmnEditorStoreApi.setState((s) => {
-        const { diagramElements } = addOrGetDrd({ definitions: 
s.dmn.model.definitions, drdIndex: s.diagram.drdIndex });
+        const { diagramElements } = addOrGetDrd({
+          definitions: s.dmn.model.definitions,
+          drdIndex: s.computed(s).getDrdIndex(),
+        });
 
         const index = 
s.computed(s).indexedDrd()?.dmnShapesByHref?.get(nodeId)?.index ?? -1;
         if (index < 0) {
@@ -204,7 +207,10 @@ export function ShapeOptions({
       ) => void
     ) => {
       dmnEditorStoreApi.setState((s) => {
-        const { diagramElements } = addOrGetDrd({ definitions: 
s.dmn.model.definitions, drdIndex: s.diagram.drdIndex });
+        const { diagramElements } = addOrGetDrd({
+          definitions: s.dmn.model.definitions,
+          drdIndex: s.computed(s).getDrdIndex(),
+        });
 
         const shapesWithMinNodeSize = nodeIds.map((nodeId) => {
           const shape = s.computed(s).indexedDrd().dmnShapesByHref.get(nodeId);
diff --git a/packages/dmn-editor/src/store/Store.ts 
b/packages/dmn-editor/src/store/Store.ts
index 108f9fa5385..99ccdb6b8cd 100644
--- a/packages/dmn-editor/src/store/Store.ts
+++ b/packages/dmn-editor/src/store/Store.ts
@@ -88,7 +88,7 @@ export interface State {
     tab: DmnEditorTab;
   };
   diagram: {
-    drdIndex: number;
+    __unsafeDrdIndex: number;
     edgeIdBeingUpdated: string | undefined;
     dropTargetNode: DropTargetNode;
     ongoingConnection: RF.OnConnectStartParams | undefined;
@@ -136,6 +136,12 @@ export type Computed = {
     e: ExternalModelsIndex | undefined
   ) => ReturnType<typeof computeExternalModelsByType>;
 
+  /**
+   * Get a valid DRD index.
+   * `__unsafeDrdIndex` can point to a DRD that doens't exist.
+   */
+  getDrdIndex(): number;
+
   getDataTypes(e: ExternalModelsIndex | undefined): ReturnType<typeof 
computeDataTypes>;
 
   getAllFeelVariableUniqueNames(): ReturnType<typeof 
computeAllFeelVariableUniqueNames>;
@@ -181,7 +187,7 @@ export const defaultStaticState = (): Omit<State, "dmn" | 
"dispatch" | "computed
     expandedItemComponentIds: [],
   },
   diagram: {
-    drdIndex: 0,
+    __unsafeDrdIndex: 0,
     edgeIdBeingUpdated: undefined,
     dropTargetNode: undefined,
     ongoingConnection: undefined,
@@ -334,7 +340,7 @@ export function createDmnEditorStore(model: 
State["dmn"]["model"], computedCache
             return computedCache.cached("indexedDrd", computeIndexedDrd, [
               s.dmn.model.definitions["@_namespace"],
               s.dmn.model.definitions,
-              s.diagram.drdIndex,
+              s.computed(s).getDrdIndex(),
             ]);
           },
 
@@ -348,7 +354,7 @@ export function createDmnEditorStore(model: 
State["dmn"]["model"], computedCache
             computedCache.cached(
               "isAlternativeInputDataShape",
               (drdIndex, dmnDiagram) => 
dmnDiagram?.[drdIndex]?.["@_useAlternativeInputDataShape"] ?? false,
-              [s.diagram.drdIndex, 
s.dmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]] as const
+              [s.computed(s).getDrdIndex(), 
s.dmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]] as const
             ),
 
           isDropTargetNodeValidForSelection: (externalModelsByNamespace: 
ExternalModelsIndex | undefined) =>
@@ -357,6 +363,16 @@ export function createDmnEditorStore(model: 
State["dmn"]["model"], computedCache
               s.computed(s).getDiagramData(externalModelsByNamespace),
             ]),
 
+          getDrdIndex: () =>
+            computedCache.cached(
+              "getDrdIndex",
+              (__unsafeDrdIndex, dmnDiagram) =>
+                dmnDiagram?.length && __unsafeDrdIndex > dmnDiagram.length - 1
+                  ? dmnDiagram.length - 1
+                  : __unsafeDrdIndex,
+              [s.diagram.__unsafeDrdIndex, 
s.dmn.model.definitions["dmndi:DMNDI"]?.["dmndi:DMNDiagram"]] as const
+            ),
+
           getDataTypes: (externalModelsByNamespace: ExternalModelsIndex | 
undefined) =>
             computedCache.cached("getDataTypes", computeDataTypes, [
               s.dmn.model.definitions["@_namespace"],
diff --git a/packages/dmn-editor/src/store/computed/computeIndexes.ts 
b/packages/dmn-editor/src/store/computed/computeIndexes.ts
index 3d1d4d68c5e..56ac9bac6fd 100644
--- a/packages/dmn-editor/src/store/computed/computeIndexes.ts
+++ b/packages/dmn-editor/src/store/computed/computeIndexes.ts
@@ -21,12 +21,12 @@ import { DMNDI15__DMNEdge, DMNDI15__DMNShape } from 
"@kie-tools/dmn-marshaller/d
 import { XmlQName, parseXmlQName } from "@kie-tools/xml-parser-ts/dist/qNames";
 import { KIE_DMN_UNKNOWN_NAMESPACE } from 
"@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/Dmn15Spec";
 import { buildXmlHref } from "../../xml/xmlHrefs";
-import { State } from "../Store";
+import { Computed, State } from "../Store";
 
 export function computeIndexedDrd(
   thisDmnsNamespace: string,
   definitions: State["dmn"]["model"]["definitions"],
-  drdIndex: State["diagram"]["drdIndex"]
+  drdIndex: ReturnType<Computed["getDrdIndex"]>
 ) {
   const dmnEdgesByDmnElementRef = new Map<string, DMNDI15__DMNEdge & { index: 
number }>();
   const dmnShapesByHref = new Map<string, DMNDI15__DMNShape & { index: number; 
dmnElementRefQName: XmlQName }>();
diff --git a/packages/dmn-editor/src/store/computed/initial.ts 
b/packages/dmn-editor/src/store/computed/initial.ts
index 89c8d98bead..7efe970d57e 100644
--- a/packages/dmn-editor/src/store/computed/initial.ts
+++ b/packages/dmn-editor/src/store/computed/initial.ts
@@ -57,4 +57,8 @@ export const INITIAL_COMPUTED_CACHE: Cache<Computed> = {
     value: undefined,
     dependencies: [],
   },
+  getDrdIndex: {
+    value: undefined,
+    dependencies: [],
+  },
 };


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to