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 ff41758977b kie-issues#1823: Integrate DMN Runner evaluation data with 
KIE Sandbox (#2942)
ff41758977b is described below

commit ff41758977b512bee3ef41aba1751cd25cf3a427
Author: Jozef Marko <[email protected]>
AuthorDate: Fri Mar 7 17:11:31 2025 +0100

    kie-issues#1823: Integrate DMN Runner evaluation data with KIE Sandbox 
(#2942)
---
 packages/dmn-editor-envelope/src/DmnEditorRoot.tsx |   8 +-
 .../src/NewDmnEditorEnvelopeApi.ts                 |   2 +
 .../src/NewDmnEditorEnvelopeApiFactory.ts          |   7 ++
 .../src/NewDmnEditorFactory.tsx                    |   5 +
 ...mnEditorEnvelopeApi.ts => NewDmnEditorTypes.ts} |  10 +-
 packages/dmn-editor/src/DmnEditor.css              |   4 +-
 packages/dmn-editor/src/DmnEditor.tsx              |  23 +++--
 packages/dmn-editor/src/DmnEditorContext.tsx       |   8 +-
 .../src/boxedExpressions/BoxedExpressionScreen.tsx |   9 ++
 packages/dmn-editor/src/diagram/nodes/Nodes.tsx    |   9 +-
 .../dmn-editor/stories/dev/DevWebApp.stories.tsx   |   4 +-
 .../dmn-editor/stories/dmnEditorStoriesWrapper.tsx |  12 ++-
 .../stories/misc/empty/Empty.stories.tsx           |   2 +-
 .../EmptyWithAvailableExternalModels.stories.tsx   |   4 +-
 .../EvaluationHighlights.stories.tsx               |  24 +++--
 .../evaluation-highlights-skipped.png              | Bin 3307 -> 2486 bytes
 .../evaluation-highlights-succeeded.png            | Bin 0 -> 3283 bytes
 .../evaluation-highlights-success.png              | Bin 2467 -> 0 bytes
 .../evaluation-highlights-skipped.png              | Bin 3319 -> 2498 bytes
 .../evaluation-highlights-succeeded.png            | Bin 0 -> 3296 bytes
 .../evaluation-highlights-success.png              | Bin 2478 -> 0 bytes
 .../evaluation-highlights-skipped.png              | Bin 3087 -> 2183 bytes
 .../evaluation-highlights-succeeded.png            | Bin 0 -> 3059 bytes
 .../evaluation-highlights-success.png              | Bin 2147 -> 0 bytes
 .../evaluationHighlights.spec.ts                   |   8 +-
 packages/extended-services-api/src/dmnResult.ts    |   1 +
 packages/form-dmn/src/FormDmnOutputs.tsx           |   8 +-
 packages/form-dmn/src/i18n/FormDmnI18n.ts          |   2 +-
 packages/form-dmn/src/i18n/locales/de.ts           |   2 +-
 packages/form-dmn/src/i18n/locales/en.ts           |   2 +-
 packages/form-dmn/tests/FormDmnOutputs.test.tsx    |   6 ++
 .../src/dmnRunner/DmnRunnerContextProvider.tsx     | 104 ++++++++++++++++++++-
 32 files changed, 213 insertions(+), 51 deletions(-)

diff --git a/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx 
b/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx
index f9dc8e02640..f04d98684c7 100644
--- a/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx
+++ b/packages/dmn-editor-envelope/src/DmnEditorRoot.tsx
@@ -74,6 +74,7 @@ export type DmnEditorRootState = {
   keyboardShortcutsRegisterIds: number[];
   keyboardShortcutsRegistered: boolean;
   error: Error | undefined;
+  evaluationResultsByNodeId: DmnEditor.EvaluationResultsByNodeId;
 };
 
 export class DmnEditorRoot extends React.Component<DmnEditorRootProps, 
DmnEditorRootState> {
@@ -96,6 +97,7 @@ export class DmnEditorRoot extends 
React.Component<DmnEditorRootProps, DmnEditor
       keyboardShortcutsRegisterIds: [],
       keyboardShortcutsRegistered: false,
       error: undefined,
+      evaluationResultsByNodeId: new Map(),
     };
   }
 
@@ -105,6 +107,10 @@ export class DmnEditorRoot extends 
React.Component<DmnEditorRootProps, DmnEditor
     this.dmnEditorRef.current?.openBoxedExpressionEditor(nodeId);
   }
 
+  public showDmnEvaluationResults(evaluationResultsByNodeId: 
DmnEditor.EvaluationResultsByNodeId): void {
+    this.setState((prev) => ({ ...prev, evaluationResultsByNodeId: 
evaluationResultsByNodeId }));
+  }
+
   public async undo(): Promise<void> {
     this.setState((prev) => ({ ...prev, pointer: Math.max(0, prev.pointer - 1) 
}));
   }
@@ -479,7 +485,7 @@ export class DmnEditorRoot extends 
React.Component<DmnEditorRootProps, DmnEditor
               originalVersion={this.state.marshaller?.originalVersion}
               model={this.model}
               externalModelsByNamespace={this.state.externalModelsByNamespace}
-              evaluationResults={{}}
+              evaluationResultsByNodeId={this.state.evaluationResultsByNodeId}
               validationMessages={[]}
               externalContextName={""}
               externalContextDescription={""}
diff --git a/packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApi.ts 
b/packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApi.ts
index 692f3ca8622..51b567f9b56 100644
--- a/packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApi.ts
+++ b/packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApi.ts
@@ -18,6 +18,7 @@
  */
 
 import { KogitoEditorEnvelopeApi } from "@kie-tools-core/editor/dist/api";
+import { NewDmnEditorTypes } from "./NewDmnEditorTypes";
 
 export interface NewDmnEditorEnvelopeApi extends KogitoEditorEnvelopeApi {
   /**
@@ -25,4 +26,5 @@ export interface NewDmnEditorEnvelopeApi extends 
KogitoEditorEnvelopeApi {
    * @param nodeId id of the node to open
    */
   dmnEditor_openBoxedExpressionEditor(nodeId: string): void;
+  newDmnEditor_showDmnEvaluationResults(evaluationResultsByNodeId: 
NewDmnEditorTypes.EvaluationResultsByNodeId): void;
 }
diff --git a/packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApiFactory.ts 
b/packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApiFactory.ts
index b8772e3d58a..7c7ae5c2aa5 100644
--- a/packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApiFactory.ts
+++ b/packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApiFactory.ts
@@ -24,6 +24,7 @@ import { NewDmnEditorInterface } from "./NewDmnEditorFactory";
 import { NewDmnEditorEnvelopeApi } from "./NewDmnEditorEnvelopeApi";
 import { NewDmnEditorChannelApi } from "./NewDmnEditorChannelApi";
 import { NewDmnEditorFactory } from "./NewDmnEditorFactory";
+import { NewDmnEditorTypes } from "./NewDmnEditorTypes";
 
 export type NewDmnEnvelopeApiFactoryArgs = EnvelopeApiFactoryArgs<
   NewDmnEditorEnvelopeApi,
@@ -43,4 +44,10 @@ export class NewDmnEditorEnvelopeApiImpl
   public dmnEditor_openBoxedExpressionEditor(nodeId: string): void {
     this.getEditorOrThrowError().openBoxedExpressionEditor(nodeId);
   }
+
+  public newDmnEditor_showDmnEvaluationResults(
+    evaluationResultsByNodeId: NewDmnEditorTypes.EvaluationResultsByNodeId
+  ): void {
+    
this.getEditorOrThrowError().showDmnEvaluationResults(evaluationResultsByNodeId);
+  }
 }
diff --git a/packages/dmn-editor-envelope/src/NewDmnEditorFactory.tsx 
b/packages/dmn-editor-envelope/src/NewDmnEditorFactory.tsx
index 80dcfb511b4..3fca40f33df 100644
--- a/packages/dmn-editor-envelope/src/NewDmnEditorFactory.tsx
+++ b/packages/dmn-editor-envelope/src/NewDmnEditorFactory.tsx
@@ -22,6 +22,7 @@ import { EditorFactory, EditorInitArgs, 
KogitoEditorEnvelopeContextType } from "
 import { NewDmnEditorChannelApi } from "./NewDmnEditorChannelApi";
 import { DmnEditorInterface } from "./DmnEditorFactory";
 import { NewDmnEditorEnvelopeApi } from "./NewDmnEditorEnvelopeApi";
+import { NewDmnEditorTypes } from "./NewDmnEditorTypes";
 
 export class NewDmnEditorFactory
   implements EditorFactory<NewDmnEditorInterface, NewDmnEditorEnvelopeApi, 
NewDmnEditorChannelApi>
@@ -42,4 +43,8 @@ export class NewDmnEditorInterface extends DmnEditorInterface 
{
   public openBoxedExpressionEditor(nodeId: string): void {
     this.self.openBoxedExpressionEditor(nodeId);
   }
+
+  public showDmnEvaluationResults(evaluationResultsByNodeId: 
NewDmnEditorTypes.EvaluationResultsByNodeId): void {
+    this.self.showDmnEvaluationResults(evaluationResultsByNodeId);
+  }
 }
diff --git a/packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApi.ts 
b/packages/dmn-editor-envelope/src/NewDmnEditorTypes.ts
similarity index 71%
copy from packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApi.ts
copy to packages/dmn-editor-envelope/src/NewDmnEditorTypes.ts
index 692f3ca8622..3aed64bcc60 100644
--- a/packages/dmn-editor-envelope/src/NewDmnEditorEnvelopeApi.ts
+++ b/packages/dmn-editor-envelope/src/NewDmnEditorTypes.ts
@@ -17,12 +17,6 @@
  * under the License.
  */
 
-import { KogitoEditorEnvelopeApi } from "@kie-tools-core/editor/dist/api";
+import type * as NewDmnEditorTypes from "@kie-tools/dmn-editor/dist/DmnEditor";
 
-export interface NewDmnEditorEnvelopeApi extends KogitoEditorEnvelopeApi {
-  /**
-   * Open boxed expression editor for given node
-   * @param nodeId id of the node to open
-   */
-  dmnEditor_openBoxedExpressionEditor(nodeId: string): void;
-}
+export { NewDmnEditorTypes };
diff --git a/packages/dmn-editor/src/DmnEditor.css 
b/packages/dmn-editor/src/DmnEditor.css
index 3e3ec3996d5..b36e4d8f123 100644
--- a/packages/dmn-editor/src/DmnEditor.css
+++ b/packages/dmn-editor/src/DmnEditor.css
@@ -105,7 +105,7 @@
 /* (end) nodes */
 
 /* (begin) decision node evaluation status */
-.kie-dmn-editor--decision-node--evaluation-status-failure::before {
+.kie-dmn-editor--decision-node--evaluation-status-failed::before {
   content: "\2716";
   font-size: 0.8em;
   text-align: left;
@@ -121,7 +121,7 @@
   padding-top: 2px;
 }
 
-.kie-dmn-editor--decision-node--evaluation-status-success::before {
+.kie-dmn-editor--decision-node--evaluation-status-succeeded::before {
   content: "\2714";
   font-size: 0.8em;
   text-align: left;
diff --git a/packages/dmn-editor/src/DmnEditor.tsx 
b/packages/dmn-editor/src/DmnEditor.tsx
index 455c6629782..acfd8e52cf1 100644
--- a/packages/dmn-editor/src/DmnEditor.tsx
+++ b/packages/dmn-editor/src/DmnEditor.tsx
@@ -72,13 +72,22 @@ export type DmnEditorRef = {
 };
 
 /**
- * TODO we need to implement mapping  between:
- * - DMN Runner engine
- * - and (extended-services-api/src/dmnResult.ts)
- * - and (EvaluationResults)
- * https://github.com/apache/incubator-kie-issues/issues/1823
+ * We need to keep in sync:
+ *   * dmn-editor/src/DmnEditor.tsx - NodeEvaluationResults
+ *   * dmn-editor-envelope/src/DmnEditorRoot.tsx -
+ *   * dmn-editor-envelope/src/NewDmnEditorEnvelopeApi.tsx - 
newDmnEditor_showDmnEvaluationResults
+ *   * dmn-editor-envelope/src/NewDmnEditorFactory.tsx - 
NewDmnEditorInterface#showDmnEvaluationResults
+ *   * extended-services-api/src/dmnResult.ts - DmnEvaluationStatus
+ *
+ * For more details see: 
https://github.com/apache/incubator-kie-issues/issues/1823
  */
-export type EvaluationResults = Record<string, "success" | "failure" | 
"skipped">;
+export type NodeEvaluationResults = {
+  evaluationResult: EvaluationResult;
+  evaluationHitsCountByRuleOrRowId: Map<string, number>;
+};
+
+export type EvaluationResult = "succeeded" | "failed" | "skipped";
+export type EvaluationResultsByNodeId = Map<string, NodeEvaluationResults>;
 export type ValidationMessages = Record<string, any>;
 export type OnDmnModelChange = (model: Normalized<DmnLatestModel>) => void;
 
@@ -136,7 +145,7 @@ export type DmnEditorProps = {
   /**
    * To show information about execution results directly on the DMN diagram 
and/or Boxed Expression Editor, use this prop.
    */
-  evaluationResults?: EvaluationResults;
+  evaluationResultsByNodeId?: EvaluationResultsByNodeId;
   /**
    * To show information about validation messages directly on the DMN diagram 
and/or Boxed Expression Editor, use this prop.
    */
diff --git a/packages/dmn-editor/src/DmnEditorContext.tsx 
b/packages/dmn-editor/src/DmnEditorContext.tsx
index 909182258e3..875e63ce479 100644
--- a/packages/dmn-editor/src/DmnEditorContext.tsx
+++ b/packages/dmn-editor/src/DmnEditorContext.tsx
@@ -30,7 +30,7 @@ export type DmnEditorContextProviderProps = Pick<
   | "model"
   | "onRequestToJumpToPath"
   | "onRequestToResolvePath"
-  | "evaluationResults"
+  | "evaluationResultsByNodeId"
 >;
 
 export type DmnModelBeforeEditing = DmnLatestModel;
@@ -42,7 +42,7 @@ export type DmnEditorContextType = Pick<
   | "issueTrackerHref"
   | "onRequestToJumpToPath"
   | "onRequestToResolvePath"
-  | "evaluationResults"
+  | "evaluationResultsByNodeId"
 > & {
   dmnModelBeforeEditingRef: React.MutableRefObject<DmnModelBeforeEditing>;
   dmnEditorRootElementRef: React.RefObject<HTMLDivElement>;
@@ -67,7 +67,7 @@ export function DmnEditorContextProvider(props: 
React.PropsWithChildren<DmnEdito
       issueTrackerHref: props.issueTrackerHref,
       onRequestToJumpToPath: props.onRequestToJumpToPath,
       onRequestToResolvePath: props.onRequestToResolvePath,
-      evaluationResults: props.evaluationResults,
+      evaluationResultsByNodeId: props.evaluationResultsByNodeId,
     }),
     [
       props.externalContextDescription,
@@ -75,7 +75,7 @@ export function DmnEditorContextProvider(props: 
React.PropsWithChildren<DmnEdito
       props.issueTrackerHref,
       props.onRequestToJumpToPath,
       props.onRequestToResolvePath,
-      props.evaluationResults,
+      props.evaluationResultsByNodeId,
     ]
   );
   return <DmnEditorContext.Provider 
value={value}>{props.children}</DmnEditorContext.Provider>;
diff --git a/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx 
b/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx
index 2028d9a7954..17349f3a642 100644
--- a/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx
+++ b/packages/dmn-editor/src/boxedExpressions/BoxedExpressionScreen.tsx
@@ -92,6 +92,7 @@ import {
   RefactorConfirmationDialog,
 } from "../refactor/RefactorConfirmationDialog";
 import { EvaluationHighlightsBadge } from 
"../evaluationHighlights/EvaluationHighlightsBadge";
+import { useDmnEditor } from "../DmnEditorContext";
 
 export function BoxedExpressionScreen({ container }: { container: 
React.RefObject<HTMLElement> }) {
   const { externalModelsByNamespace } = useExternalModels();
@@ -119,6 +120,9 @@ export function BoxedExpressionScreen({ container }: { 
container: React.RefObjec
     s.computed(s).getExternalDmnModelsByNamespaceMap(externalModelsByNamespace)
   );
 
+  const { evaluationResultsByNodeId } = useDmnEditor();
+  const isEvaluationHighlightsEnabled = useDmnEditorStore((s) => 
s.diagram.overlays.enableEvaluationHighlights);
+
   const onRequestFeelIdentifiers = useCallback(() => {
     return new FeelIdentifiers({
       _readonly_dmnDefinitions: 
dmnEditorStoreApi.getState().dmn.model.definitions,
@@ -534,6 +538,11 @@ export function BoxedExpressionScreen({ container }: { 
container: React.RefObjec
             widthsById={widthsById}
             onWidthsChange={onWidthsChange}
             isReadOnly={settings.isReadOnly}
+            evaluationHitsCountById={
+              isEvaluationHighlightsEnabled
+                ? evaluationResultsByNodeId?.get(activeDrgElementId ?? 
"")?.evaluationHitsCountByRuleOrRowId
+                : undefined
+            }
           />
         </div>
       </>
diff --git a/packages/dmn-editor/src/diagram/nodes/Nodes.tsx 
b/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
index fb9f15e2fc9..b0ba66b7547 100644
--- a/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
@@ -392,13 +392,14 @@ export const DecisionNode = React.memo(
     });
 
     const isEvaluationHighlightsEnabled = useDmnEditorStore((s) => 
s.diagram.overlays.enableEvaluationHighlights);
-    const { evaluationResults } = useDmnEditor();
+    const { evaluationResultsByNodeId } = useDmnEditor();
     const evaluationResultsClassName = useMemo(
       () =>
-        isEvaluationHighlightsEnabled && evaluationResults![decision["@_id"]] 
!== undefined
-          ? 
`kie-dmn-editor--decision-node--evaluation-status-${evaluationResults![decision["@_id"]]}`
+        isEvaluationHighlightsEnabled &&
+        evaluationResultsByNodeId?.get(decision["@_id"])?.evaluationResult !== 
undefined
+          ? 
`kie-dmn-editor--decision-node--evaluation-status-${evaluationResultsByNodeId?.get(decision["@_id"])?.evaluationResult}`
           : "",
-      [decision, evaluationResults, isEvaluationHighlightsEnabled]
+      [decision, evaluationResultsByNodeId, isEvaluationHighlightsEnabled]
     );
 
     return (
diff --git a/packages/dmn-editor/stories/dev/DevWebApp.stories.tsx 
b/packages/dmn-editor/stories/dev/DevWebApp.stories.tsx
index 3d9922f2118..8cd50d561e3 100644
--- a/packages/dmn-editor/stories/dev/DevWebApp.stories.tsx
+++ b/packages/dmn-editor/stories/dev/DevWebApp.stories.tsx
@@ -230,7 +230,7 @@ function DevWebApp(args: DmnEditorProps) {
                 externalContextName: args.externalContextName,
                 externalContextDescription: args.externalContextDescription,
                 validationMessages: args.validationMessages,
-                evaluationResults: args.evaluationResults,
+                evaluationResultsByNodeId: args.evaluationResultsByNodeId,
                 issueTrackerHref: args.issueTrackerHref,
                 onRequestToJumpToPath,
                 isReadOnly: args.isReadOnly,
@@ -270,7 +270,7 @@ export const WebApp: Story = {
   args: {
     model: getMarshaller(initialModel, { upgradeTo: "latest" }).parser.parse(),
     originalVersion: "1.5",
-    evaluationResults: {},
+    evaluationResultsByNodeId: new Map(),
     externalContextDescription:
       "You're using the DMN Dev webapp, so there's only two simple external 
models that can be included.",
     externalContextName: "Dev webapp",
diff --git a/packages/dmn-editor/stories/dmnEditorStoriesWrapper.tsx 
b/packages/dmn-editor/stories/dmnEditorStoriesWrapper.tsx
index 25191c97e9e..64f95d23927 100644
--- a/packages/dmn-editor/stories/dmnEditorStoriesWrapper.tsx
+++ b/packages/dmn-editor/stories/dmnEditorStoriesWrapper.tsx
@@ -20,13 +20,19 @@
 import * as React from "react";
 import { useCallback, useState, useRef, useMemo, useEffect } from "react";
 import { useArgs } from "@storybook/preview-api";
-import { DmnEditor, DmnEditorProps, DmnEditorRef, EvaluationResults, 
ValidationMessages } from "../src/DmnEditor";
+import {
+  DmnEditor,
+  DmnEditorProps,
+  DmnEditorRef,
+  EvaluationResultsByNodeId,
+  ValidationMessages,
+} from "../src/DmnEditor";
 import { DmnLatestModel, getMarshaller } from "@kie-tools/dmn-marshaller";
 import { normalize } from 
"@kie-tools/dmn-marshaller/dist/normalization/normalize";
 import { diff } from "deep-object-diff";
 import { generateEmptyDmn15 } from "./misc/empty/Empty.stories";
 
-export const evaluationResults: EvaluationResults = {};
+export const evaluationResultsByNodeId: EvaluationResultsByNodeId = new Map();
 export const validationMessages: ValidationMessages = {};
 
 export type StorybookDmnEditorProps = DmnEditorProps & { xml: string };
@@ -105,7 +111,7 @@ export function DmnEditorWrapper(props?: 
Partial<StorybookDmnEditorProps>) {
           externalContextName={props?.externalContextName ?? 
args.externalContextName}
           externalContextDescription={props?.externalContextDescription ?? 
args.externalContextDescription}
           validationMessages={props?.validationMessages ?? 
args.validationMessages}
-          evaluationResults={props?.evaluationResults ?? 
args.evaluationResults}
+          evaluationResultsByNodeId={props?.evaluationResultsByNodeId ?? 
args.evaluationResultsByNodeId}
           issueTrackerHref={props?.issueTrackerHref ?? args.issueTrackerHref}
           onRequestToJumpToPath={props?.onRequestToJumpToPath ?? 
args.onRequestToJumpToPath}
           onModelDebounceStateChanged={onModelDebounceStateChanged}
diff --git a/packages/dmn-editor/stories/misc/empty/Empty.stories.tsx 
b/packages/dmn-editor/stories/misc/empty/Empty.stories.tsx
index ecbac14555d..af3959e35f6 100644
--- a/packages/dmn-editor/stories/misc/empty/Empty.stories.tsx
+++ b/packages/dmn-editor/stories/misc/empty/Empty.stories.tsx
@@ -51,7 +51,7 @@ export const Empty: Story = {
   args: {
     model: model,
     originalVersion: "1.5",
-    evaluationResults: {},
+    evaluationResultsByNodeId: new Map(),
     externalContextDescription: "",
     externalContextName: "Storybook - DMN Editor",
     externalModelsByNamespace: {},
diff --git 
a/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/EmptyWithAvailableExternalModels.stories.tsx
 
b/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/EmptyWithAvailableExternalModels.stories.tsx
index 7bd165e1b8b..18f59021125 100644
--- 
a/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/EmptyWithAvailableExternalModels.stories.tsx
+++ 
b/packages/dmn-editor/stories/misc/emptyWithAvailableExternalModels/EmptyWithAvailableExternalModels.stories.tsx
@@ -103,7 +103,7 @@ function EmptyStoryWithIncludedModels(args: DmnEditorProps) 
{
         externalContextName: args.externalContextName,
         externalContextDescription: args.externalContextDescription,
         validationMessages: args.validationMessages,
-        evaluationResults: args.evaluationResults,
+        evaluationResultsByNodeId: args.evaluationResultsByNodeId,
         issueTrackerHref: args.issueTrackerHref,
       })}
     </>
@@ -124,7 +124,7 @@ export const EmptyWithAvailableExternalModels: Story = {
   args: {
     model: getMarshaller(initialModel, { upgradeTo: "latest" }).parser.parse(),
     originalVersion: "1.5",
-    evaluationResults: {},
+    evaluationResultsByNodeId: new Map(),
     externalContextDescription: "External context description",
     externalContextName: "Storybook - DMN Editor",
     externalModelsByNamespace: {},
diff --git 
a/packages/dmn-editor/stories/misc/evaluationHighlights/EvaluationHighlights.stories.tsx
 
b/packages/dmn-editor/stories/misc/evaluationHighlights/EvaluationHighlights.stories.tsx
index 55ad44b1718..edc00b616ba 100644
--- 
a/packages/dmn-editor/stories/misc/evaluationHighlights/EvaluationHighlights.stories.tsx
+++ 
b/packages/dmn-editor/stories/misc/evaluationHighlights/EvaluationHighlights.stories.tsx
@@ -815,7 +815,7 @@ function EvaluationHighlights(args: DmnEditorProps) {
         externalContextName: args.externalContextName,
         externalContextDescription: args.externalContextDescription,
         validationMessages: args.validationMessages,
-        evaluationResults: args.evaluationResults,
+        evaluationResultsByNodeId: args.evaluationResultsByNodeId,
         issueTrackerHref: args.issueTrackerHref,
       })}
     </>
@@ -836,11 +836,23 @@ export const EvaluationHighlightsStory: Story = {
   args: {
     model: getMarshaller(initialModel, { upgradeTo: "latest" }).parser.parse(),
     originalVersion: "1.5",
-    evaluationResults: {
-      "_F0DC8923-5FC7-4200-8BD1-461D5F3714BE": "success",
-      "_D6F4234F-15B3-4F5B-B814-5F6FF29D2907": "failure",
-      "_2FE51DB1-3083-4BF7-AA71-0B0065310E72": "skipped",
-    },
+    evaluationResultsByNodeId: new Map([
+      [
+        "_F0DC8923-5FC7-4200-8BD1-461D5F3714BE",
+        { evaluationResult: "skipped", evaluationHitsCountByRuleOrRowId: new 
Map() },
+      ],
+      [
+        "_D6F4234F-15B3-4F5B-B814-5F6FF29D2907",
+        { evaluationResult: "failed", evaluationHitsCountByRuleOrRowId: new 
Map() },
+      ],
+      [
+        "_2FE51DB1-3083-4BF7-AA71-0B0065310E72",
+        {
+          evaluationResult: "succeeded",
+          evaluationHitsCountByRuleOrRowId: new 
Map([["_11976EBA-60BC-421B-A270-089A45E9B167", 10]]),
+        },
+      ],
+    ]),
     externalContextDescription: "External context description",
     externalContextName: "Storybook - DMN Editor",
     externalModelsByNamespace: {},
diff --git 
a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/evaluationHighlights/evaluation-highlights-skipped.png
 
b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/evaluationHighlights/evaluation-highlights-skipped.png
index f781f707e56..697158353c9 100644
Binary files 
a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/evaluationHighlights/evaluation-highlights-skipped.png
 and 
b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/evaluationHighlights/evaluation-highlights-skipped.png
 differ
diff --git 
a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/evaluationHighlights/evaluation-highlights-succeeded.png
 
b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/evaluationHighlights/evaluation-highlights-succeeded.png
new file mode 100644
index 00000000000..b2af1471e86
Binary files /dev/null and 
b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/evaluationHighlights/evaluation-highlights-succeeded.png
 differ
diff --git 
a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/evaluationHighlights/evaluation-highlights-success.png
 
b/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/evaluationHighlights/evaluation-highlights-success.png
deleted file mode 100644
index 9e1c273c2f2..00000000000
Binary files 
a/packages/dmn-editor/tests-e2e/__screenshots__/Google-Chrome/evaluationHighlights/evaluation-highlights-success.png
 and /dev/null differ
diff --git 
a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/evaluationHighlights/evaluation-highlights-skipped.png
 
b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/evaluationHighlights/evaluation-highlights-skipped.png
index ed84bb73c34..08da8f3a50b 100644
Binary files 
a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/evaluationHighlights/evaluation-highlights-skipped.png
 and 
b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/evaluationHighlights/evaluation-highlights-skipped.png
 differ
diff --git 
a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/evaluationHighlights/evaluation-highlights-succeeded.png
 
b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/evaluationHighlights/evaluation-highlights-succeeded.png
new file mode 100644
index 00000000000..a498c4193bc
Binary files /dev/null and 
b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/evaluationHighlights/evaluation-highlights-succeeded.png
 differ
diff --git 
a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/evaluationHighlights/evaluation-highlights-success.png
 
b/packages/dmn-editor/tests-e2e/__screenshots__/chromium/evaluationHighlights/evaluation-highlights-success.png
deleted file mode 100644
index 9a073e010fb..00000000000
Binary files 
a/packages/dmn-editor/tests-e2e/__screenshots__/chromium/evaluationHighlights/evaluation-highlights-success.png
 and /dev/null differ
diff --git 
a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/evaluationHighlights/evaluation-highlights-skipped.png
 
b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/evaluationHighlights/evaluation-highlights-skipped.png
index 81bbf421259..38927ed6daf 100644
Binary files 
a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/evaluationHighlights/evaluation-highlights-skipped.png
 and 
b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/evaluationHighlights/evaluation-highlights-skipped.png
 differ
diff --git 
a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/evaluationHighlights/evaluation-highlights-succeeded.png
 
b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/evaluationHighlights/evaluation-highlights-succeeded.png
new file mode 100644
index 00000000000..ef68a7f7355
Binary files /dev/null and 
b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/evaluationHighlights/evaluation-highlights-succeeded.png
 differ
diff --git 
a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/evaluationHighlights/evaluation-highlights-success.png
 
b/packages/dmn-editor/tests-e2e/__screenshots__/webkit/evaluationHighlights/evaluation-highlights-success.png
deleted file mode 100644
index befdf171e85..00000000000
Binary files 
a/packages/dmn-editor/tests-e2e/__screenshots__/webkit/evaluationHighlights/evaluation-highlights-success.png
 and /dev/null differ
diff --git 
a/packages/dmn-editor/tests-e2e/evaluationHighlights/evaluationHighlights.spec.ts
 
b/packages/dmn-editor/tests-e2e/evaluationHighlights/evaluationHighlights.spec.ts
index dbc7345531c..2d407e40931 100644
--- 
a/packages/dmn-editor/tests-e2e/evaluationHighlights/evaluationHighlights.spec.ts
+++ 
b/packages/dmn-editor/tests-e2e/evaluationHighlights/evaluationHighlights.spec.ts
@@ -25,15 +25,15 @@ test.beforeEach(async ({ overlays, editor }) => {
 });
 
 test.describe("Evaluation Highlights on Nodes", () => {
-  test("should highlight node evaluation result - success", async ({ nodes }) 
=> {
-    await expect(nodes.get({ name: "Front End Ratio" 
})).toHaveScreenshot("evaluation-highlights-success.png");
+  test("should highlight node evaluation result - skipped", async ({ nodes }) 
=> {
+    await expect(nodes.get({ name: "Front End Ratio" 
})).toHaveScreenshot("evaluation-highlights-skipped.png");
   });
 
   test("should highlight node evaluation result - failure", async ({ nodes }) 
=> {
     await expect(nodes.get({ name: "Back End Ratio" 
})).toHaveScreenshot("evaluation-highlights-failure.png");
   });
 
-  test("should highlight node evaluation result - skipped", async ({ nodes }) 
=> {
-    await expect(nodes.get({ name: "Credit Score Rating" 
})).toHaveScreenshot("evaluation-highlights-skipped.png");
+  test("should highlight node evaluation result - succeeded", async ({ nodes 
}) => {
+    await expect(nodes.get({ name: "Credit Score Rating" 
})).toHaveScreenshot("evaluation-highlights-succeeded.png");
   });
 });
diff --git a/packages/extended-services-api/src/dmnResult.ts 
b/packages/extended-services-api/src/dmnResult.ts
index 8dc9237812f..f759dab9c7c 100644
--- a/packages/extended-services-api/src/dmnResult.ts
+++ b/packages/extended-services-api/src/dmnResult.ts
@@ -48,6 +48,7 @@ export interface DecisionResult {
   result: DmnEvaluationResult;
   messages?: DmnEvaluationMessages[];
   evaluationStatus: DmnEvaluationStatus;
+  evaluationHitIds: Object;
 }
 
 // Result returned from extended-services /jitdmn/dmnresult;
diff --git a/packages/form-dmn/src/FormDmnOutputs.tsx 
b/packages/form-dmn/src/FormDmnOutputs.tsx
index 5523a8527ba..c3d99a93dea 100644
--- a/packages/form-dmn/src/FormDmnOutputs.tsx
+++ b/packages/form-dmn/src/FormDmnOutputs.tsx
@@ -112,10 +112,12 @@ export function FormDmnOutputs({ openExecutionTab, 
openBoxedExpressionEditor, ..
                 <CheckCircleIcon />
                 {props.notificationsPanel ? (
                   <a onClick={onOpenExecutionTab} 
className={"kogito--editor__dmn-form-result__evaluation-link"}>
-                    {i18n.result.evaluation.success}
+                    {i18n.result.evaluation.succeeded}
                   </a>
                 ) : (
-                  <p 
className={"kogito--editor__dmn-form-result__evaluation-link"}>{i18n.result.evaluation.success}</p>
+                  <p 
className={"kogito--editor__dmn-form-result__evaluation-link"}>
+                    {i18n.result.evaluation.succeeded}
+                  </p>
                 )}
               </div>
             </>
@@ -155,7 +157,7 @@ export function FormDmnOutputs({ openExecutionTab, 
openBoxedExpressionEditor, ..
     [
       i18n.result.evaluation.failed,
       i18n.result.evaluation.skipped,
-      i18n.result.evaluation.success,
+      i18n.result.evaluation.succeeded,
       onOpenExecutionTab,
       props.notificationsPanel,
     ]
diff --git a/packages/form-dmn/src/i18n/FormDmnI18n.ts 
b/packages/form-dmn/src/i18n/FormDmnI18n.ts
index fd7f410372a..9a14a365f0a 100644
--- a/packages/form-dmn/src/i18n/FormDmnI18n.ts
+++ b/packages/form-dmn/src/i18n/FormDmnI18n.ts
@@ -33,7 +33,7 @@ export interface FormDmnI18n extends FormI18n {
   };
   result: {
     evaluation: {
-      success: string;
+      succeeded: string;
       skipped: string;
       failed: string;
     };
diff --git a/packages/form-dmn/src/i18n/locales/de.ts 
b/packages/form-dmn/src/i18n/locales/de.ts
index 283b89bbf71..fbe3dada83b 100644
--- a/packages/form-dmn/src/i18n/locales/de.ts
+++ b/packages/form-dmn/src/i18n/locales/de.ts
@@ -58,7 +58,7 @@ export const de: TranslatedDictionary<FormDmnI18n> = {
   },
   result: {
     evaluation: {
-      success: "Erfolgreich evaluiert",
+      succeeded: "Erfolgreich evaluiert",
       skipped: "Evaluierung übersprungen",
       failed: "Evaluierung fehlgeschlagen",
     },
diff --git a/packages/form-dmn/src/i18n/locales/en.ts 
b/packages/form-dmn/src/i18n/locales/en.ts
index d24521ab5fc..b60f38bd366 100644
--- a/packages/form-dmn/src/i18n/locales/en.ts
+++ b/packages/form-dmn/src/i18n/locales/en.ts
@@ -59,7 +59,7 @@ export const en: FormDmnI18n = {
   },
   result: {
     evaluation: {
-      success: "Evaluated with success",
+      succeeded: "Evaluation succeeded",
       skipped: "Evaluation skipped",
       failed: "Evaluation failed",
     },
diff --git a/packages/form-dmn/tests/FormDmnOutputs.test.tsx 
b/packages/form-dmn/tests/FormDmnOutputs.test.tsx
index 70e07ef885e..81e3adc5b77 100644
--- a/packages/form-dmn/tests/FormDmnOutputs.test.tsx
+++ b/packages/form-dmn/tests/FormDmnOutputs.test.tsx
@@ -45,6 +45,7 @@ describe("FormDmnOutputs tests", () => {
         result: null,
         messages: [],
         evaluationStatus: DmnEvaluationStatus.FAILED,
+        evaluationHitIds: {},
       },
     ];
 
@@ -61,6 +62,7 @@ describe("FormDmnOutputs tests", () => {
         result: null,
         messages: [],
         evaluationStatus: DmnEvaluationStatus.FAILED,
+        evaluationHitIds: {},
       },
       {
         decisionId: "_9BD7BB23-0B23-488F-8DED-F5462CF89E0B",
@@ -68,6 +70,7 @@ describe("FormDmnOutputs tests", () => {
         result: null,
         messages: [],
         evaluationStatus: DmnEvaluationStatus.SUCCEEDED,
+        evaluationHitIds: {},
       },
       {
         decisionId: "_9BD7BB23-0B23-488F-8DED-F5462CF89E0B",
@@ -75,6 +78,7 @@ describe("FormDmnOutputs tests", () => {
         result: null,
         messages: [],
         evaluationStatus: DmnEvaluationStatus.SKIPPED,
+        evaluationHitIds: {},
       },
     ];
 
@@ -93,6 +97,7 @@ describe("FormDmnOutputs tests", () => {
         result: null,
         messages: [],
         evaluationStatus: DmnEvaluationStatus.FAILED,
+        evaluationHitIds: {},
       },
     ];
 
@@ -110,6 +115,7 @@ describe("FormDmnOutputs tests", () => {
         result: null,
         messages: [],
         evaluationStatus: DmnEvaluationStatus.FAILED,
+        evaluationHitIds: {},
       },
     ];
 
diff --git a/packages/online-editor/src/dmnRunner/DmnRunnerContextProvider.tsx 
b/packages/online-editor/src/dmnRunner/DmnRunnerContextProvider.tsx
index 7cb82c0e04e..fdda208087c 100644
--- a/packages/online-editor/src/dmnRunner/DmnRunnerContextProvider.tsx
+++ b/packages/online-editor/src/dmnRunner/DmnRunnerContextProvider.tsx
@@ -35,7 +35,12 @@ import { ExtendedServicesStatus } from 
"../extendedServices/ExtendedServicesStat
 import { usePrevious } from "@kie-tools-core/react-hooks/dist/usePrevious";
 import { useExtendedServices } from 
"../extendedServices/ExtendedServicesContext";
 import { InputRow } from "@kie-tools/form-dmn";
-import { DecisionResult, DmnEvaluationMessages, ExtendedServicesModelPayload } 
from "@kie-tools/extended-services-api";
+import {
+  DecisionResult,
+  DmnEvaluationMessages,
+  ExtendedServicesDmnResult,
+  ExtendedServicesModelPayload,
+} from "@kie-tools/extended-services-api";
 import { DmnRunnerAjv } from "@kie-tools/dmn-runner/dist/ajv";
 import { useDmnRunnerPersistence } from 
"../dmnRunnerPersistence/DmnRunnerPersistenceHook";
 import { DmnLanguageService } from "@kie-tools/dmn-language-service";
@@ -73,6 +78,9 @@ import {
 import { extractDifferencesFromArray } from 
"@kie-tools/dmn-runner/dist/results";
 import { openapiSchemaToJsonSchema } from 
"@openapi-contrib/openapi-schema-to-json-schema";
 import type { JSONSchema4 } from "json-schema";
+import { MessageBusClientApi } from "@kie-tools-core/envelope-bus/dist/api";
+import { NewDmnEditorEnvelopeApi } from 
"@kie-tools/dmn-editor-envelope/dist/NewDmnEditorEnvelopeApi";
+import { NewDmnEditorTypes } from 
"@kie-tools/dmn-editor-envelope/dist/NewDmnEditorTypes";
 
 interface Props {
   isEditorReady?: boolean;
@@ -119,6 +127,92 @@ function dmnRunnerResultsReducer(dmnRunnerResults: 
DmnRunnerResults, action: Dmn
   }
 }
 
+/**
+ * This transformation is needed for these reasons:
+ * ### -1- ###
+ * DMN Runner backend return upper case constants: "SUCCEEDED", "FAILED", 
"SKIPPED"
+ * DMN Editor code base uses lower case constants: "succeeded", "failed", 
"skipped"
+ *
+ * ### -2- ###
+ * DMN Runner backend return evaluationHitIds as Object:
+ * {
+ *   _F0DC8923-5FC7-4200-8BD1-461D5F3715CF: 1,
+ *   _F0DC8923-5FC7-4200-8BD1-461D5F3713AD: 2
+ * }
+ * DMN Editor code base uses evaluationHitIds as Map<string, number>
+ * [
+ *   {
+ *     key: "_F0DC8923-5FC7-4200-8BD1-461D5F3715CF,
+ *     value: 1
+ *   },
+ *   {
+ *     key: "_F0DC8923-5FC7-4200-8BD1-461D5F3713AD",
+ *     value: 2
+ *   }
+ * ]
+ *
+ * ### -3- ###
+ * DMN Runner backend return data spilt into junks corresponding to table row 
or collection item
+ * DMN Editor want to show aggregated data for everything together
+ *
+ * @param result - DMN Runner backend data
+ * @param evaluationResultsByNodeId - transformed data for DMN Editor
+ */
+function transformExtendedServicesDmnResult(
+  result: ExtendedServicesDmnResult,
+  evaluationResultsByNodeId: NewDmnEditorTypes.EvaluationResultsByNodeId
+) {
+  result.decisionResults?.forEach((dr) => {
+    const evaluationHitsCountByRuleOrRowId = new Map<string, number>();
+    // ### -2- ###
+    for (const [key, value] of Object.entries(dr.evaluationHitIds)) {
+      evaluationHitsCountByRuleOrRowId.set(`${key}`, value as number);
+    }
+    // We want to merge evaluation results that belongs to the same Decision
+    // So we need to check if the Decision wasn't already partially processed
+    if (!evaluationResultsByNodeId.has(dr.decisionId)) {
+      evaluationResultsByNodeId.set(dr.decisionId, {
+        // ### -1- ###
+        evaluationResult: dr.evaluationStatus.toLowerCase() as 
NewDmnEditorTypes.EvaluationResult,
+        evaluationHitsCountByRuleOrRowId: evaluationHitsCountByRuleOrRowId,
+      });
+    } else {
+      const existingEvaluationHitsCount = evaluationResultsByNodeId.get(
+        dr.decisionId
+      )?.evaluationHitsCountByRuleOrRowId;
+      evaluationHitsCountByRuleOrRowId.forEach((value, key) => {
+        // ### -3- ###
+        if (existingEvaluationHitsCount?.has(key)) {
+          existingEvaluationHitsCount.set(key, 
(existingEvaluationHitsCount?.get(key) ?? 0) + value);
+        } else {
+          existingEvaluationHitsCount?.set(key, value);
+        }
+      });
+      evaluationResultsByNodeId.set(dr.decisionId, {
+        // For a collection input or DMN Runner table mode one Decision may 
have multiple different evaluation results
+        // We keep the worst evaluation result.
+        evaluationResult: theWorstEvaluationResult(
+          evaluationResultsByNodeId.get(dr.decisionId)?.evaluationResult,
+          dr.evaluationStatus.toLowerCase() as 
NewDmnEditorTypes.EvaluationResult
+        ),
+        evaluationHitsCountByRuleOrRowId: existingEvaluationHitsCount ?? new 
Map(),
+      });
+    }
+  });
+
+  return evaluationResultsByNodeId;
+}
+
+function theWorstEvaluationResult(a?: NewDmnEditorTypes.EvaluationResult, b?: 
NewDmnEditorTypes.EvaluationResult) {
+  if (a === "failed" || b === "failed") {
+    return "failed";
+  }
+  if (a === "skipped" || b === "skipped") {
+    return "skipped";
+  }
+  return "succeeded";
+}
+
 export function DmnRunnerContextProvider(props: PropsWithChildren<Props>) {
   const { i18n } = useOnlineI18n();
   // Calling forceDmnRunnerReRender will cause a update in the dmnRunnerKey
@@ -163,6 +257,8 @@ export function DmnRunnerContextProvider(props: 
PropsWithChildren<Props>) {
   const status = useMemo(() => (isExpanded ? DmnRunnerStatus.AVAILABLE : 
DmnRunnerStatus.UNAVAILABLE), [isExpanded]);
   const dmnRunnerAjv = useMemo(() => new DmnRunnerAjv().getAjv(), []);
 
+  const { envelopeServer } = useEditorDockContext();
+
   useLayoutEffect(() => {
     if (props.isEditorReady) {
       setCanBeVisualized(true);
@@ -264,6 +360,7 @@ export function DmnRunnerContextProvider(props: 
PropsWithChildren<Props>) {
             }
 
             const runnerResults: Array<DecisionResult[] | undefined> = [];
+            const evaluationResultsByNodeId: 
NewDmnEditorTypes.EvaluationResultsByNodeId = new Map();
             for (const result of results) {
               if (Object.hasOwnProperty.call(result, "details") && 
Object.hasOwnProperty.call(result, "stack")) {
                 setExtendedServicesError(true);
@@ -271,9 +368,13 @@ export function DmnRunnerContextProvider(props: 
PropsWithChildren<Props>) {
               }
               if (result) {
                 runnerResults.push(result.decisionResults);
+                transformExtendedServicesDmnResult(result, 
evaluationResultsByNodeId);
               }
             }
             setDmnRunnerResults({ type: DmnRunnerResultsActionType.DEFAULT, 
newResults: runnerResults });
+
+            const newDmnEditorEnvelopeApi = envelopeServer?.envelopeApi as 
MessageBusClientApi<NewDmnEditorEnvelopeApi>;
+            
newDmnEditorEnvelopeApi.notifications.newDmnEditor_showDmnEvaluationResults.send(evaluationResultsByNodeId);
           })
           .catch((err) => {
             console.log(err);
@@ -281,6 +382,7 @@ export function DmnRunnerContextProvider(props: 
PropsWithChildren<Props>) {
           });
       },
       [
+        envelopeServer,
         props.workspaceFile.extension,
         extendedServices.status,
         extendedServices.client,


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


Reply via email to