diff --git a/packages/dmn-editor/package.json b/packages/dmn-editor/package.json
index 27b6bec36ae..3441696ef18 100644
--- a/packages/dmn-editor/package.json
+++ b/packages/dmn-editor/package.json
@@ -54,7 +54,7 @@
"fast-deep-equal": "^3.1.3",
"immer": "^10.0.3",
"moment": "^2.29.4",
- "react-error-boundary": "^4.0.11",
+ "react-error-boundary": "^4.0.13",
"reactflow": "^11.8.3",
"uuid": "^8.3.2",
"zustand": "^4.4.2"
diff --git a/packages/dmn-editor/stories/useCases/loanPreQualification/LoanPreQualification.stories.tsx b/packages/dmn-editor/stories/useCases/loanPreQualification/LoanPreQualification.stories.tsx
index 01285c05d15..131be55e62a 100644
--- a/packages/dmn-editor/stories/useCases/loanPreQualification/LoanPreQualification.stories.tsx
+++ b/packages/dmn-editor/stories/useCases/loanPreQualification/LoanPreQualification.stories.tsx
@@ -792,7 +792,6 @@ const model = marshaller.parser.parse();
export const LoanPreQualification: Story = {
render: Empty.render,
args: {
- ...Empty.args,
model: model,
xml: marshaller.builder.build(model),
},
diff --git a/packages/scesim-editor/.storybook/preview.tsx b/packages/scesim-editor/.storybook/preview.tsx
index 4e7e10ae856..f0300e08ed8 100644
--- a/packages/scesim-editor/.storybook/preview.tsx
+++ b/packages/scesim-editor/.storybook/preview.tsx
@@ -44,13 +44,7 @@ const preview: Preview = {
},
// It should be Story() to be possible to use "preview-api" inside stories; (https://github.com/storybookjs/storybook/issues/22132)
- decorators: [
- (Story) => (
-
- {Story()}
-
- ),
- ],
+ decorators: [(Story) => {Story()}
],
};
export default preview;
diff --git a/packages/scesim-editor/README.md b/packages/scesim-editor/README.md
index fd2b0454047..eedff691504 100644
--- a/packages/scesim-editor/README.md
+++ b/packages/scesim-editor/README.md
@@ -44,16 +44,16 @@ To build the `scesim-editor` module ONLY, you can use ONE of the below commands:
- `pnpm -F @kie-tools/scesim-editor build:dev` This is fast, but not as strict. It skips tests, linters, and some type checks. Recommended for dev purposes.
- `pnpm -F @kie-tools/scesim-editor build:prod` The default command to build production-ready packages. This is the recommended build for production purposes
-## How to launch the Test Scenario Dev WebApp
+## How to launch the Test Scenario Storybook Dev WebApp
-After building the project, you can benefit of the Dev Webapp for development or testing scope.
+After building the project, you can benefit of the Storybook Dev Webapp for development or testing scope.
To launch it, simply type in your terminal the following command:
`pnpm -F @kie-tools/scesim-editor start`
A web server with a Dev Webapp of Test Scenario editor will be launched, reachable at the following address:
-http://localhost:9004/ or http://192.168.1.128:9004/
+http://localhost:9902/ or http://172.20.10.3:9902/
---
diff --git a/packages/scesim-editor/package.json b/packages/scesim-editor/package.json
index 3d420430f19..9cd082deee5 100644
--- a/packages/scesim-editor/package.json
+++ b/packages/scesim-editor/package.json
@@ -26,11 +26,13 @@
"@patternfly/react-core": "^4.276.6",
"@patternfly/react-icons": "^4.93.6",
"@patternfly/react-styles": "^4.92.6",
+ "immer": "^10.0.3",
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-table": "^7.6.2",
- "uuid": "^8.3.2"
+ "uuid": "^8.3.2",
+ "zustand": "^4.4.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
@@ -57,7 +59,9 @@
"@types/uuid": "^8.3.0",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
+ "deep-object-diff": "^1.1.9",
"file-loader": "^6.2.0",
+ "react-error-boundary": "^4.0.13",
"rimraf": "^3.0.2",
"run-script-os": "^1.1.6",
"storybook": "^7.3.2",
diff --git a/packages/scesim-editor/src/TestScenarioEditor.tsx b/packages/scesim-editor/src/TestScenarioEditor.tsx
index 62f15be68f3..faf089991e7 100644
--- a/packages/scesim-editor/src/TestScenarioEditor.tsx
+++ b/packages/scesim-editor/src/TestScenarioEditor.tsx
@@ -20,17 +20,14 @@
import "@patternfly/react-core/dist/styles/base.css";
import * as React from "react";
-import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
+import { useCallback, useImperativeHandle, useMemo, useRef } from "react";
import { I18nDictionariesProvider } from "@kie-tools-core/i18n/dist/react-components";
import { testScenarioEditorDictionaries, TestScenarioEditorI18nContext, testScenarioEditorI18nDefaults } from "./i18n";
-import { getMarshaller, SceSimModel } from "@kie-tools/scesim-marshaller";
-import {
- SceSim__FactMappingType,
- SceSim__ScenarioSimulationModelType,
-} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+import { SceSimModel } from "@kie-tools/scesim-marshaller";
+import { SceSim__FactMappingType } from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
import { Alert } from "@patternfly/react-core/dist/js/components/Alert";
import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye";
@@ -46,16 +43,27 @@ import ErrorIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-ico
import TableIcon from "@patternfly/react-icons/dist/esm/icons/table-icon";
import HelpIcon from "@patternfly/react-icons/dist/esm/icons/help-icon";
-import ErrorBoundary from "./reactExt/ErrorBoundary";
+import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from "react-error-boundary";
+
+import TestScenarioCreationPanel from "./creation/TestScenarioCreationPanel";
import TestScenarioDrawerPanel from "./drawer/TestScenarioDrawerPanel";
import TestScenarioSideBarMenu from "./sidebar/TestScenarioSideBarMenu";
import TestScenarioTable from "./table/TestScenarioTable";
import { useTestScenarioEditorI18n } from "./i18n";
-import { EMPTY_ONE_EIGHT } from "./resources/EmptyScesimFile";
-
import "./TestScenarioEditor.css";
-import TestScenarioCreationPanel from "./creation/TestScenarioCreationPanel";
+import { ComputedStateCache } from "./store/ComputedStateCache";
+import { Computed, createTestScenarioEditorStore, TestScenarioEditorTab } from "./store/TestScenarioEditorStore";
+import {
+ StoreApiType,
+ TestScenarioEditorStoreApiContext,
+ useTestScenarioEditorStore,
+ useTestScenarioEditorStoreApi,
+} from "./store/TestScenarioStoreContext";
+import { TestScenarioEditorErrorFallback } from "./TestScenarioEditorErrorFallback";
+import { TestScenarioEditorContextProvider, useTestScenarioEditor } from "./TestScenarioEditorContext";
+import { useEffectAfterFirstRender } from "./hook/useEffectAfterFirstRender";
+import { INITIAL_COMPUTED_CACHE } from "./store/computed/initial";
/* Constants */
@@ -63,17 +71,6 @@ const CURRENT_SUPPORTED_VERSION = "1.8";
/* Enums */
-export enum TestScenarioEditorDock {
- CHEATSHEET,
- DATA_OBJECT,
- SETTINGS,
-}
-
-enum TestScenarioEditorTab {
- EDITOR,
- BACKGROUND,
-}
-
enum TestScenarioFileStatus {
EMPTY,
ERROR,
@@ -82,43 +79,33 @@ enum TestScenarioFileStatus {
VALID,
}
-export enum TestScenarioType {
- DMN,
- RULE,
-}
-
/* Types */
-export type TestScenarioAlert = {
- enabled: boolean;
- message?: string;
- variant: "success" | "danger" | "warning" | "info" | "default";
-};
-
-export type TestScenarioDataObject = {
- id: string;
- children?: TestScenarioDataObject[];
- customBadgeContent?: string;
- isSimpleTypeFact?: boolean;
- name: string;
+export type OnSceSimModelChange = (model: SceSimModel) => void;
+
+export type TestScenarioEditorProps = {
+ /**
+ * A link that will take users to an issue tracker so they can report problems they find on the Test Scenario Editor.
+ * This is shown on the ErrorBoundary fallback component, when an uncaught error happens.
+ */
+ issueTrackerHref?: string;
+ /**
+ * The Test Scenario itself.
+ */
+ model: SceSimModel;
+ /**
+ * Called when a change occurs on `model`, so the controlled flow of the component can be done.
+ */
+ onModelChange?: OnSceSimModelChange;
+ /**
+ * Notifies the caller when the Test Scenario Editor performs a new edit after the debounce time.
+ */
+ onModelDebounceStateChanged?: (changed: boolean) => void;
};
export type TestScenarioEditorRef = {
- /* TODO Convert these to Promises */
- getContent(): string;
+ reset: (mode: SceSimModel) => void;
getDiagramSvg: () => Promise;
- setContent(pathRelativeToTheWorkspaceRoot: string, content: string): void;
-};
-
-export type TestScenarioSettings = {
- assetType: string;
- dmnFilePath?: string;
- dmnName?: string;
- dmnNamespace?: string;
- isStatelessSessionRule?: boolean;
- isTestSkipped: boolean;
- kieSessionRule?: string;
- ruleFlowGroup?: string;
};
export type TestScenarioSelectedColumnMetaData = {
@@ -127,174 +114,59 @@ export type TestScenarioSelectedColumnMetaData = {
isBackground: boolean;
};
-function TestScenarioMainPanel({
- fileName,
- scesimModel,
- updateSettingField,
- updateTestScenarioModel,
-}: {
- fileName: string;
- scesimModel: { ScenarioSimulationModel: SceSim__ScenarioSimulationModelType };
- updateSettingField: (field: string, value: string) => void;
- updateTestScenarioModel: React.Dispatch>;
-}) {
+function TestScenarioMainPanel({ fileName }: { fileName: string }) {
const { i18n } = useTestScenarioEditorI18n();
-
- const [alert, setAlert] = useState({ enabled: false, variant: "info" });
- const [dataObjects, setDataObjects] = useState([]);
- const [dockPanel, setDockPanel] = useState({ isOpen: true, selected: TestScenarioEditorDock.DATA_OBJECT });
- const [selectedColumnMetadata, setSelectedColumnMetaData] = useState(null);
- const [tab, setTab] = useState(TestScenarioEditorTab.EDITOR);
+ const testScenarioEditorStoreApi = useTestScenarioEditorStoreApi();
+ const navigation = useTestScenarioEditorStore((s) => s.navigation);
+ const scesimModel = useTestScenarioEditorStore((s) => s.scesim.model);
+ const isAlertEnabled = true; // Will be managed in kie-issue#970
+ const testScenarioType = scesimModel.ScenarioSimulationModel.settings.type?.__$$text.toUpperCase();
const scenarioTableScrollableElementRef = useRef(null);
const backgroundTableScrollableElementRef = useRef(null);
- const onTabChanged = useCallback((_event, tab) => {
- setSelectedColumnMetaData(null);
- setTab(tab);
- }, []);
-
- const closeDockPanel = useCallback(() => {
- setDockPanel((prev) => {
- return { ...prev, isOpen: false };
- });
- }, []);
-
- const openDockPanel = useCallback((selected: TestScenarioEditorDock) => {
- setDockPanel({ isOpen: true, selected: selected });
- }, []);
-
- useEffect(() => {
- setDockPanel({ isOpen: true, selected: TestScenarioEditorDock.DATA_OBJECT });
- setSelectedColumnMetaData(null);
- setTab(TestScenarioEditorTab.EDITOR);
- }, [fileName]);
-
- /** This is TEMPORARY */
- useEffect(() => {
- /* To create the Data Object arrays we need an external source, in details: */
- /* DMN Data: Retrieving DMN type from linked DMN file */
- /* Java classes: Retrieving Java classes info from the user projects */
- /* At this time, none of the above are supported */
- /* Therefore, it tries to retrieve these info from the SCESIM file, if are present */
-
- /* Retriving Data Object from the scesim file.
- That makes sense for previously created scesim files */
-
- const factsMappings: SceSim__FactMappingType[] =
- scesimModel.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping ?? [];
-
- const dataObjects: TestScenarioDataObject[] = [];
-
- /* The first two FactMapping are related to the "Number" and "Description" columns.
- If those columns only are present, no Data Objects can be detected in the scesim file */
- for (let i = 2; i < factsMappings.length; i++) {
- if (factsMappings[i].className!.__$$text === "java.lang.Void") {
- continue;
- }
- const factID = factsMappings[i].expressionElements!.ExpressionElement![0].step.__$$text;
- const dataObject = dataObjects.find((value) => value.id === factID);
- const isSimpleTypeFact = factsMappings[i].expressionElements!.ExpressionElement!.length == 1;
- const propertyID = isSimpleTypeFact //POTENTIAL BUG
- ? factsMappings[i].expressionElements!.ExpressionElement![0].step.__$$text.concat(".")
- : factsMappings[i]
- .expressionElements!.ExpressionElement!.map((expressionElement) => expressionElement.step.__$$text)
- .join(".");
- const propertyName = isSimpleTypeFact
- ? "value"
- : factsMappings[i].expressionElements!.ExpressionElement!.slice(-1)[0].step.__$$text;
- if (dataObject) {
- if (!dataObject.children?.some((value) => value.id === propertyID)) {
- dataObject.children!.push({
- id: propertyID,
- customBadgeContent: factsMappings[i].className.__$$text,
- isSimpleTypeFact: isSimpleTypeFact,
- name: propertyName,
- });
- }
- } else {
- dataObjects.push({
- id: factID,
- name: factsMappings[i].factAlias!.__$$text,
- customBadgeContent: factsMappings[i].factIdentifier!.className!.__$$text,
- children: [
- {
- id: propertyID,
- name: propertyName,
- customBadgeContent: factsMappings[i].className.__$$text,
- },
- ],
- });
- }
- }
-
- setDataObjects(dataObjects);
- }, [scesimModel.ScenarioSimulationModel.settings.type]);
-
- /** It determines the Alert State */
- useEffect(() => {
- const assetType = scesimModel.ScenarioSimulationModel.settings.type!.__$$text;
-
- let alertEnabled = false;
- let alertMessage = "";
- let alertVariant: "default" | "danger" | "warning" | "info" | "success" = "danger";
-
- if (dataObjects.length > 0) {
- alertMessage =
- assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.alerts.dmnDataRetrievedFromScesim
- : i18n.alerts.ruleDataRetrievedFromScesim;
- alertEnabled = true;
- } else {
- alertMessage =
- assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.alerts.dmnDataNotAvailable
- : i18n.alerts.ruleDataNotAvailable;
- alertVariant = assetType === TestScenarioType[TestScenarioType.DMN] ? "warning" : "danger";
- alertEnabled = true;
- }
+ const onTabChanged = useCallback(
+ (_event, tab) => {
+ testScenarioEditorStoreApi.setState((state) => {
+ state.navigation.tab = tab;
+ });
+ },
+ [testScenarioEditorStoreApi]
+ );
- setAlert({ enabled: alertEnabled, message: alertMessage, variant: alertVariant });
- }, [dataObjects, i18n, scesimModel.ScenarioSimulationModel.settings.type]);
+ const showDockPanel = useCallback(
+ (show: boolean) => {
+ testScenarioEditorStoreApi.setState((state) => {
+ state.navigation.dock.isOpen = show;
+ });
+ },
+ [testScenarioEditorStoreApi]
+ );
return (
<>
-
+
- }
+ panelContent={ showDockPanel(false)} />}
>
- {alert.enabled && (
+ {isAlertEnabled && (
)}
-
+
@@ -314,11 +186,8 @@ function TestScenarioMainPanel({
ref={scenarioTableScrollableElementRef}
>
@@ -343,11 +212,8 @@ function TestScenarioMainPanel({
ref={backgroundTableScrollableElementRef}
>
@@ -357,7 +223,7 @@ function TestScenarioMainPanel({
-
+
>
);
}
@@ -380,29 +246,82 @@ function TestScenarioParserErrorPanel({
);
}
-const TestScenarioEditorInternal = ({ forwardRef }: { forwardRef?: React.Ref }) => {
- /** Test Scenario File, Model and Marshaller Management */
+export const TestScenarioEditorInternal = ({
+ model,
+ onModelChange,
+ onModelDebounceStateChanged,
+ forwardRef,
+}: TestScenarioEditorProps & { forwardRef?: React.Ref }) => {
+ console.trace("[TestScenarioEditorInternal] Component creation ...");
- const [scesimFile, setScesimFile] = useState({ content: "", path: "" });
+ const scesim = useTestScenarioEditorStore((s) => s.scesim);
+ const testScenarioEditorStoreApi = useTestScenarioEditorStoreApi();
+ const { testScenarioEditorModelBeforeEditingRef, testScenarioEditorRootElementRef } = useTestScenarioEditor();
- const marshaller = useMemo(() => getMarshaller(scesimFile.content.trim()), [scesimFile]);
+ /** Implementing Editor APIs */
- const scesimLoaded: { ScenarioSimulationModel: SceSim__ScenarioSimulationModelType } = useMemo(
- () => marshaller.parser.parse(),
- [marshaller.parser]
+ // Allow imperativelly controlling the Editor.
+ useImperativeHandle(
+ forwardRef,
+ () => ({
+ reset: () => {
+ console.trace("[TestScenarioEditorInternal: Reset called!");
+ const state = testScenarioEditorStoreApi.getState();
+ state.dispatch(state).scesim.reset();
+ },
+ getDiagramSvg: async () => undefined,
+ }),
+ [testScenarioEditorStoreApi]
);
- const [scesimModel, setScesimModel] = useState(scesimLoaded);
+ // Make sure the Test Scenario Editor reacts to props changing.
+ useEffectAfterFirstRender(() => {
+ testScenarioEditorStoreApi.setState((state) => {
+ // Avoid unecessary state updates
+ if (model === state.scesim.model) {
+ console.trace("[TestScenarioEditorInternal]: useEffectAfterFirstRender called, but the models are the same!");
+ return;
+ }
+
+ console.trace("[TestScenarioEditorInternal]: Model updated!");
+
+ state.scesim.model = model;
+ testScenarioEditorModelBeforeEditingRef.current = model;
+ //state.dispatch(state).scesim.reset();
+ });
+ }, [testScenarioEditorStoreApi, model]);
+
+ // Only notify changes when dragging/resizing operations are not happening.
+ useEffectAfterFirstRender(() => {
+ onModelDebounceStateChanged?.(false);
+
+ const timeout = setTimeout(() => {
+ // Ignore changes made outside... If the controller of the component
+ // changed its props, it knows it already, we don't need to call "onModelChange" again.
+ if (model === scesim.model) {
+ return;
+ }
+
+ onModelDebounceStateChanged?.(true);
+ console.trace("[TestScenarioEditorInternal: Debounce State changed!");
+ console.trace(scesim.model);
+ onModelChange?.(scesim.model);
+ }, 500);
+
+ return () => {
+ clearTimeout(timeout);
+ };
+ }, [onModelChange, scesim.model]);
const scesimFileStatus = useMemo(() => {
- if (scesimModel.ScenarioSimulationModel) {
- const parserErrorField = "parsererror" as keyof typeof scesimModel.ScenarioSimulationModel;
- if (scesimModel.ScenarioSimulationModel[parserErrorField]) {
+ if (scesim.model.ScenarioSimulationModel) {
+ const parserErrorField = "parsererror" as keyof typeof scesim.model.ScenarioSimulationModel;
+ if (scesim.model.ScenarioSimulationModel[parserErrorField]) {
return TestScenarioFileStatus.ERROR;
}
- if (scesimModel.ScenarioSimulationModel["@_version"] != CURRENT_SUPPORTED_VERSION) {
+ if (scesim.model.ScenarioSimulationModel["@_version"] != CURRENT_SUPPORTED_VERSION) {
return TestScenarioFileStatus.UNSUPPORTED;
- } else if (scesimModel.ScenarioSimulationModel["settings"]?.["type"]) {
+ } else if (scesim.model.ScenarioSimulationModel.settings?.type) {
return TestScenarioFileStatus.VALID;
} else {
return TestScenarioFileStatus.NEW;
@@ -410,84 +329,12 @@ const TestScenarioEditorInternal = ({ forwardRef }: { forwardRef?: React.Ref {
- console.debug("SCESIM Model updated");
- console.debug(scesimLoaded);
- setScesimModel(scesimLoaded);
- }, [scesimLoaded]);
-
- /** Implementing Editor APIs */
-
- useImperativeHandle(
- forwardRef,
- () => ({
- getContent: () => marshaller.builder.build(scesimModel),
- getDiagramSvg: async () => undefined,
- setContent: (normalizedPosixPathRelativeToTheWorkspaceRoot, content) => {
- console.debug("SCESIM setContent called");
- console.debug("=== FILE CONTENT ===");
- console.debug(content ? content : "EMPTY FILE");
- console.debug("=== END FILE CONTENT ===");
-
- setScesimFile({ content: content || EMPTY_ONE_EIGHT, path: normalizedPosixPathRelativeToTheWorkspaceRoot });
- },
- }),
- [marshaller.builder, scesimModel]
- );
+ }, [scesim]);
- /** scesim model update functions */
-
- const setInitialSettings = useCallback(
- (
- assetType: string,
- isStatelessSessionRule: boolean,
- isTestSkipped: boolean,
- kieSessionRule: string,
- ruleFlowGroup: string
- ) =>
- setScesimModel((prevState) => ({
- ScenarioSimulationModel: {
- ...prevState.ScenarioSimulationModel,
- settings: {
- ...prevState.ScenarioSimulationModel.settings,
- dmnFilePath:
- assetType === TestScenarioType[TestScenarioType.DMN] ? { __$$text: "./MockedDMNName.dmn" } : undefined,
- dmoSession:
- assetType === TestScenarioType[TestScenarioType.RULE] && kieSessionRule
- ? { __$$text: kieSessionRule }
- : undefined,
- ruleFlowGroup:
- assetType === TestScenarioType[TestScenarioType.RULE] && ruleFlowGroup
- ? { __$$text: ruleFlowGroup }
- : undefined,
- skipFromBuild: { __$$text: isTestSkipped },
- stateless:
- assetType === TestScenarioType[TestScenarioType.RULE] ? { __$$text: isStatelessSessionRule } : undefined,
- type: { __$$text: assetType },
- },
- },
- })),
- [setScesimModel]
- );
-
- const updateSettingsField = useCallback(
- (fieldName: string, value: string) =>
- setScesimModel((prevState) => ({
- ScenarioSimulationModel: {
- ...prevState.ScenarioSimulationModel,
- ["settings"]: {
- ...prevState.ScenarioSimulationModel["settings"],
- [fieldName]: { __$$text: value },
- },
- },
- })),
- [setScesimModel]
- );
+ console.trace("[TestScenarioEditorInternal] File Status: " + TestScenarioFileStatus[scesimFileStatus]);
return (
- <>
+
{(() => {
switch (scesimFileStatus) {
case TestScenarioFileStatus.EMPTY:
@@ -507,13 +354,13 @@ const TestScenarioEditorInternal = ({ forwardRef }: { forwardRef?: React.Ref
);
case TestScenarioFileStatus.NEW:
- return ;
+ return ;
case TestScenarioFileStatus.UNSUPPORTED:
return (
);
case TestScenarioFileStatus.VALID:
- return (
-
- );
+ return ;
}
})()}
- >
+
);
};
-export const TestScenarioEditor = React.forwardRef((props: {}, ref: React.Ref) => {
- const [scesimFileParsingError, setScesimFileParsingError] = useState(null);
-
- return (
-
-
- }
- setError={setScesimFileParsingError}
+export const TestScenarioEditor = React.forwardRef(
+ (props: TestScenarioEditorProps, ref: React.Ref) => {
+ console.trace("[TestScenarioEditor] Component creation ... ");
+ console.trace(props.model);
+
+ const store = useMemo(
+ () => createTestScenarioEditorStore(props.model, new ComputedStateCache(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(store);
+
+ const resetState: ErrorBoundaryPropsWithFallback["onReset"] = useCallback(({ args }) => {
+ storeRef.current?.setState((state) => {
+ state.scesim.model = args[0];
+ });
+ }, []);
+
+ return (
+
-
-
-
- );
-});
+
+
+
+
+
+
+
+
+ );
+ }
+);
diff --git a/packages/scesim-editor/src/TestScenarioEditorContext.tsx b/packages/scesim-editor/src/TestScenarioEditorContext.tsx
new file mode 100644
index 00000000000..49ffc97ffd1
--- /dev/null
+++ b/packages/scesim-editor/src/TestScenarioEditorContext.tsx
@@ -0,0 +1,55 @@
+/*
+ * 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 { useContext, useMemo, useRef } from "react";
+import { SceSimModel } from "@kie-tools/scesim-marshaller";
+import { TestScenarioEditorProps } from "./TestScenarioEditor";
+
+export type SceSimModelBeforeEditing = SceSimModel;
+
+export type TestScenarioEditorContextProviderProps = Pick;
+
+export type TestScenarioEditorContextType = Pick & {
+ testScenarioEditorModelBeforeEditingRef: React.MutableRefObject;
+ testScenarioEditorRootElementRef: React.RefObject;
+};
+
+const TestScenarioEditorContext = React.createContext({} as any);
+
+export function useTestScenarioEditor() {
+ return useContext(TestScenarioEditorContext);
+}
+
+export function TestScenarioEditorContextProvider(
+ props: React.PropsWithChildren
+) {
+ const testScenarioEditorModelBeforeEditingRef = useRef(props.model);
+ const testScenarioEditorRootElementRef = useRef(null);
+
+ const value = useMemo(
+ () => ({
+ issueTrackerHref: props.issueTrackerHref,
+ testScenarioEditorModelBeforeEditingRef,
+ testScenarioEditorRootElementRef,
+ }),
+ [props.issueTrackerHref]
+ );
+ return {props.children};
+}
diff --git a/packages/scesim-editor/src/TestScenarioEditorErrorFallback.tsx b/packages/scesim-editor/src/TestScenarioEditorErrorFallback.tsx
new file mode 100644
index 00000000000..5d532330d10
--- /dev/null
+++ b/packages/scesim-editor/src/TestScenarioEditorErrorFallback.tsx
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as React from "react";
+import { useCallback, useEffect } from "react";
+import { Button, ButtonVariant } from "@patternfly/react-core/dist/js/components/Button";
+import {
+ EmptyState,
+ EmptyStateBody,
+ EmptyStateIcon,
+ EmptyStatePrimary,
+} from "@patternfly/react-core/dist/js/components/EmptyState";
+import { ExternalLinkAltIcon } from "@patternfly/react-icons/dist/js/icons/external-link-alt-icon";
+import { ClipboardCopy, ClipboardCopyVariant } from "@patternfly/react-core/dist/js/components/ClipboardCopy";
+import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
+import { Title } from "@patternfly/react-core/dist/js/components/Title";
+import { FallbackProps } from "react-error-boundary";
+import { useTestScenarioEditorI18n } from "./i18n";
+import { useTestScenarioEditor } from "./TestScenarioEditorContext";
+
+export function TestScenarioEditorErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
+ const { i18n } = useTestScenarioEditorI18n();
+ const { testScenarioEditorModelBeforeEditingRef, issueTrackerHref } = useTestScenarioEditor();
+
+ const resetToLastWorkingState = useCallback(() => {
+ resetErrorBoundary(testScenarioEditorModelBeforeEditingRef.current);
+ }, [testScenarioEditorModelBeforeEditingRef, resetErrorBoundary]);
+
+ useEffect(() => {
+ console.error(error);
+ }, [error]);
+
+ return (
+
+
+ 😕
} />
+
+ {i18n.errorFallBack.title}
+
+ {i18n.errorFallBack.body}
+
+
+ {JSON.stringify(
+ {
+ name: error.name,
+ message: error.message,
+ cause: error.cause,
+ stack: error.stack,
+ },
+ null,
+ 2
+ ).replaceAll("\\n", "\n")}
+
+
+
+
+ {issueTrackerHref && (
+
+ }>
+ {i18n.errorFallBack.fileIssueHref}...
+
+
+ )}
+
+
+
+ );
+}
diff --git a/packages/scesim-editor/src/common/TestScenarioCommonFunctions.tsx b/packages/scesim-editor/src/common/TestScenarioCommonFunctions.tsx
deleted file mode 100644
index cd9b95ca376..00000000000
--- a/packages/scesim-editor/src/common/TestScenarioCommonFunctions.tsx
+++ /dev/null
@@ -1,60 +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 {
- SceSim__FactMappingValueType,
- SceSim__ScenarioSimulationModelType,
- SceSim__expressionIdentifierType,
- SceSim__factIdentifierType,
-} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
-import * as React from "react";
-
-/**
- Given a List of FactMappingValues (Row of Cells), it founds the index of the list's element that matches with the
- identifiers (factIdentifier and expressionIdentifier) fields.
-*/
-export const retrieveFactMappingValueIndexByIdentifiers = (
- factMappingValues: SceSim__FactMappingValueType[],
- factIdentifier: SceSim__factIdentifierType,
- expressionIdentifier: SceSim__expressionIdentifierType
-) => {
- return factMappingValues.findIndex(
- (factMappingValue) =>
- factMappingValue.factIdentifier.name?.__$$text == factIdentifier.name?.__$$text &&
- factMappingValue.factIdentifier.className?.__$$text == factIdentifier.className?.__$$text &&
- factMappingValue.expressionIdentifier.name?.__$$text == expressionIdentifier.name?.__$$text &&
- factMappingValue.expressionIdentifier.type?.__$$text == expressionIdentifier.type?.__$$text
- );
-};
-
-export const retrieveModelDescriptor = (scesimModel: SceSim__ScenarioSimulationModelType, isBackground: boolean) => {
- if (isBackground) {
- return scesimModel.background.scesimModelDescriptor;
- } else {
- return scesimModel.simulation.scesimModelDescriptor;
- }
-};
-
-export const retrieveRowsDataFromModel = (scesimModel: SceSim__ScenarioSimulationModelType, isBackground: boolean) => {
- if (isBackground) {
- return scesimModel.background.scesimData.BackgroundData;
- } else {
- return scesimModel.simulation.scesimData.Scenario;
- }
-};
diff --git a/packages/scesim-editor/src/creation/TestScenarioCreationPanel.tsx b/packages/scesim-editor/src/creation/TestScenarioCreationPanel.tsx
index 9dfd3812fca..679b924171b 100644
--- a/packages/scesim-editor/src/creation/TestScenarioCreationPanel.tsx
+++ b/packages/scesim-editor/src/creation/TestScenarioCreationPanel.tsx
@@ -18,6 +18,7 @@
*/
import * as React from "react";
+import { useCallback } from "react";
import { Button } from "@patternfly/react-core/dist/js/components/Button";
import { Checkbox } from "@patternfly/react-core/dist/js/components/Checkbox";
@@ -33,36 +34,49 @@ import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip";
import AddIcon from "@patternfly/react-icons/dist/esm/icons/add-circle-o-icon";
import CubesIcon from "@patternfly/react-icons/dist/esm/icons/cubes-icon";
-import { TestScenarioType } from "../TestScenarioEditor";
+import { useTestScenarioEditorStoreApi } from "../store/TestScenarioStoreContext";
import { useTestScenarioEditorI18n } from "../i18n";
import "./TestScenarioCreationPanel.css";
-function TestScenarioCreationPanel({
- onCreateScesimButtonClicked,
-}: {
- onCreateScesimButtonClicked: (
- assetType: string,
- isStatelessSessionRule: boolean,
- isTestSkipped: boolean,
- kieSessionRule: string,
- ruleFlowGroup: string
- ) => void;
-}) {
+function TestScenarioCreationPanel() {
const { i18n } = useTestScenarioEditorI18n();
const assetsOption = [
{ value: "", label: i18n.creationPanel.assetsOption.noChoice, disabled: true },
- { value: TestScenarioType[TestScenarioType.DMN], label: i18n.creationPanel.assetsOption.dmn, disabled: false },
- { value: TestScenarioType[TestScenarioType.RULE], label: i18n.creationPanel.assetsOption.rule, disabled: false },
+ { value: "DMN", label: i18n.creationPanel.assetsOption.dmn, disabled: false },
+ { value: "RULE", label: i18n.creationPanel.assetsOption.rule, disabled: false },
];
- const [assetType, setAssetType] = React.useState("");
+ const [assetType, setAssetType] = React.useState<"" | "DMN" | "RULE">("");
const [isAutoFillTableEnabled, setAutoFillTableEnabled] = React.useState(true);
const [isStatelessSessionRule, setStatelessSessionRule] = React.useState(false);
const [isTestSkipped, setTestSkipped] = React.useState(false);
const [kieSessionRule, setKieSessionRule] = React.useState("");
const [ruleFlowGroup, setRuleFlowGroup] = React.useState("");
+ const testScenarioEditorStoreApi = useTestScenarioEditorStoreApi();
+
+ const createTestScenario = useCallback(
+ (
+ assetType: string,
+ isStatelessSessionRule: boolean,
+ isTestSkipped: boolean,
+ kieSessionRule: string,
+ ruleFlowGroup: string
+ ) =>
+ testScenarioEditorStoreApi.setState((state) => {
+ const settings = state.scesim.model.ScenarioSimulationModel.settings;
+ settings.dmnFilePath = assetType === "DMN" ? { __$$text: "./MockedDMNName.dmn" } : undefined;
+ settings.dmnName = assetType === "DMN" ? { __$$text: "MockedDMNName.dmn" } : undefined;
+ settings.dmnNamespace = assetType === "DMN" ? { __$$text: "https:\\kiegroup" } : undefined;
+ settings.dmoSession = assetType === "RULE" && kieSessionRule ? { __$$text: kieSessionRule } : undefined;
+ settings.ruleFlowGroup = assetType === "RULE" && ruleFlowGroup ? { __$$text: ruleFlowGroup } : undefined;
+ settings.skipFromBuild = { __$$text: isTestSkipped };
+ settings.stateless = assetType === "RULE" ? { __$$text: isStatelessSessionRule } : undefined;
+ settings.type = { __$$text: assetType };
+ }),
+ [testScenarioEditorStoreApi]
+ );
return (
@@ -75,7 +89,7 @@ function TestScenarioCreationPanel({
setAssetType(value)}
+ onChange={(value: "" | "DMN" | "RULE") => setAssetType(value)}
value={assetType}
>
{assetsOption.map((option, index) => (
@@ -83,7 +97,7 @@ function TestScenarioCreationPanel({
))}
- {assetType === TestScenarioType[TestScenarioType.DMN] && (
+ {assetType === "DMN" && (
<>
@@ -111,7 +125,7 @@ function TestScenarioCreationPanel({
>
)}
- {assetType === TestScenarioType[TestScenarioType.RULE] && (
+ {assetType === "RULE" && (
<>
}
isDisabled={assetType == ""}
onClick={() =>
- onCreateScesimButtonClicked(assetType, isStatelessSessionRule, isTestSkipped, kieSessionRule, ruleFlowGroup)
+ createTestScenario(assetType, isStatelessSessionRule, isTestSkipped, kieSessionRule, ruleFlowGroup)
}
variant="primary"
>
diff --git a/packages/scesim-editor/src/drawer/TestScenarioDrawerCheatSheetPanel.tsx b/packages/scesim-editor/src/drawer/TestScenarioDrawerCheatSheetPanel.tsx
index c3b14567fdb..982456cf6c4 100644
--- a/packages/scesim-editor/src/drawer/TestScenarioDrawerCheatSheetPanel.tsx
+++ b/packages/scesim-editor/src/drawer/TestScenarioDrawerCheatSheetPanel.tsx
@@ -21,79 +21,58 @@ import * as React from "react";
import { Text, TextContent, TextList, TextListItem } from "@patternfly/react-core/dist/js/components/Text";
-import { TestScenarioType } from "../TestScenarioEditor";
import { useTestScenarioEditorI18n } from "../i18n";
+import { useTestScenarioEditorStore } from "../store/TestScenarioStoreContext";
-function TestScenarioDrawerCheatSheetPanel({ assetType }: { assetType: string }) {
+function TestScenarioDrawerCheatSheetPanel() {
const { i18n } = useTestScenarioEditorI18n();
+ const settingsModel = useTestScenarioEditorStore((state) => state.scesim.model.ScenarioSimulationModel.settings);
+ const testScenarioType = settingsModel.type?.__$$text.toUpperCase();
return (
{i18n.drawer.cheatSheet.paragraph1}
{i18n.drawer.cheatSheet.paragraph2(
- assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.dataSelector.titleDMN
- : i18n.drawer.dataSelector.titleRule
+ testScenarioType === "DMN" ? i18n.drawer.dataSelector.titleDMN : i18n.drawer.dataSelector.titleRule
)}
{i18n.drawer.cheatSheet.paragraph3(i18n.tab.backgroundTabTitle, i18n.tab.scenarioTabTitle)}
{i18n.drawer.cheatSheet.paragraph4}
- {assetType === TestScenarioType[TestScenarioType.DMN] && {i18n.drawer.cheatSheet.paragraph5DMN}}
+ {testScenarioType === "DMN" && {i18n.drawer.cheatSheet.paragraph5DMN}}
- {assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.cheatSheet.paragraph6DMN
- : i18n.drawer.cheatSheet.paragraph6Rule}
+ {testScenarioType === "DMN" ? i18n.drawer.cheatSheet.paragraph6DMN : i18n.drawer.cheatSheet.paragraph6Rule}
- {assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.cheatSheet.expression1DMN
- : i18n.drawer.cheatSheet.expression1Rule}
+ {testScenarioType === "DMN" ? i18n.drawer.cheatSheet.expression1DMN : i18n.drawer.cheatSheet.expression1Rule}
- {assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.cheatSheet.expression2DMN
- : i18n.drawer.cheatSheet.expression2Rule}
+ {testScenarioType === "DMN" ? i18n.drawer.cheatSheet.expression2DMN : i18n.drawer.cheatSheet.expression2Rule}
- {assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.cheatSheet.expression3DMN
- : i18n.drawer.cheatSheet.expression3Rule}
+ {testScenarioType === "DMN" ? i18n.drawer.cheatSheet.expression3DMN : i18n.drawer.cheatSheet.expression3Rule}
- {assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.cheatSheet.expression4DMN
- : i18n.drawer.cheatSheet.expression4Rule}
+ {testScenarioType === "DMN" ? i18n.drawer.cheatSheet.expression4DMN : i18n.drawer.cheatSheet.expression4Rule}
- {assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.cheatSheet.expression5DMN
- : i18n.drawer.cheatSheet.expression5Rule}
+ {testScenarioType === "DMN" ? i18n.drawer.cheatSheet.expression5DMN : i18n.drawer.cheatSheet.expression5Rule}
+ T
- {assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.cheatSheet.expression6DMN
- : i18n.drawer.cheatSheet.expression6Rule}
+ {testScenarioType === "DMN" ? i18n.drawer.cheatSheet.expression6DMN : i18n.drawer.cheatSheet.expression6Rule}
- {assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.cheatSheet.expression7DMN
- : i18n.drawer.cheatSheet.expression7Rule}
+ {testScenarioType === "DMN" ? i18n.drawer.cheatSheet.expression7DMN : i18n.drawer.cheatSheet.expression7Rule}
- {assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.cheatSheet.expression8DMN
- : i18n.drawer.cheatSheet.expression8Rule}
+ {testScenarioType === "DMN" ? i18n.drawer.cheatSheet.expression8DMN : i18n.drawer.cheatSheet.expression8Rule}
- {assetType === TestScenarioType[TestScenarioType.DMN]
- ? i18n.drawer.cheatSheet.expression9DMN
- : i18n.drawer.cheatSheet.expression9Rule}
+ {testScenarioType === "DMN" ? i18n.drawer.cheatSheet.expression9DMN : i18n.drawer.cheatSheet.expression9Rule}
- {assetType === TestScenarioType[TestScenarioType.DMN] && (
- {i18n.drawer.cheatSheet.expression10DMN}
- )}
+ {testScenarioType === "DMN" && {i18n.drawer.cheatSheet.expression10DMN}}
);
diff --git a/packages/scesim-editor/src/drawer/TestScenarioDrawerDataSelectorPanel.tsx b/packages/scesim-editor/src/drawer/TestScenarioDrawerDataSelectorPanel.tsx
index d1a1d554ea7..f6aebaa087b 100644
--- a/packages/scesim-editor/src/drawer/TestScenarioDrawerDataSelectorPanel.tsx
+++ b/packages/scesim-editor/src/drawer/TestScenarioDrawerDataSelectorPanel.tsx
@@ -34,24 +34,14 @@ import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip/";
import { TreeView, TreeViewDataItem, TreeViewSearch } from "@patternfly/react-core/dist/js/components/TreeView/";
import { WarningTriangleIcon } from "@patternfly/react-icons/dist/esm/icons/warning-triangle-icon";
-import { SceSimModel } from "@kie-tools/scesim-marshaller";
-import {
- SceSim__FactMappingType,
- SceSim__FactMappingValuesTypes,
- SceSim__expressionElementsType,
-} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
-
-import { TestScenarioDataObject, TestScenarioSelectedColumnMetaData, TestScenarioType } from "../TestScenarioEditor";
-import { useTestScenarioEditorI18n } from "../i18n";
+import { SceSim__expressionElementsType } from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
-import { EMPTY_TYPE, TEST_SCENARIO_EXPRESSION_TYPE } from "../common/TestScenarioCommonConstants";
-import {
- retrieveFactMappingValueIndexByIdentifiers,
- retrieveModelDescriptor,
- retrieveRowsDataFromModel,
-} from "../common/TestScenarioCommonFunctions";
+import { useTestScenarioEditorI18n } from "../i18n";
import "./TestScenarioDrawerDataSelectorPanel.css";
+import { useTestScenarioEditorStore, useTestScenarioEditorStoreApi } from "../store/TestScenarioStoreContext";
+import { TestScenarioDataObject, TestScenarioEditorTab } from "../store/TestScenarioEditorStore";
+import { updateColumn } from "../mutations/updateColumn";
const enum TestScenarioDataSelectorState {
DISABLED, // All subcomponents are DISABLED
@@ -59,22 +49,19 @@ const enum TestScenarioDataSelectorState {
TREEVIEW_ENABLED_ONLY, // TreeView component is enabled only, in a read only mode (when a column is selected)
}
-function TestScenarioDataSelectorPanel({
- assetType,
- dataObjects,
- scesimModel,
- selectedColumnMetadata,
- updateSelectedColumnMetaData,
- updateTestScenarioModel,
-}: {
- assetType: string;
- dataObjects: TestScenarioDataObject[];
- scesimModel: SceSimModel;
- selectedColumnMetadata: TestScenarioSelectedColumnMetaData | null;
- updateSelectedColumnMetaData: React.Dispatch>;
- updateTestScenarioModel: React.Dispatch>;
-}) {
+function TestScenarioDataSelectorPanel() {
const { i18n } = useTestScenarioEditorI18n();
+ const dataObjects = useTestScenarioEditorStore((state) => state.computed(state).getTestScenarioDataObjects());
+ const scesimModel = useTestScenarioEditorStore((state) => state.scesim.model);
+ const tableStatus = useTestScenarioEditorStore((state) => state.table);
+ const tabStatus = useTestScenarioEditorStore((state) => state.navigation.tab);
+ const testScenarioEditorStoreApi = useTestScenarioEditorStoreApi();
+ const testScenarioType = scesimModel.ScenarioSimulationModel.settings.type?.__$$text.toUpperCase();
+
+ const selectedColumnMetadata =
+ tabStatus === TestScenarioEditorTab.SIMULATION
+ ? tableStatus.simulation.selectedColumn
+ : tableStatus.background.selectedColumn;
const [allExpanded, setAllExpanded] = useState(false);
const [dataSelectorStatus, setDataSelectorStatus] = useState(TestScenarioDataSelectorState.DISABLED);
@@ -171,8 +158,9 @@ function TestScenarioDataSelectorPanel({
/** It filters out all the Data Objects and their Children already assigned in the table */
const filterOutAlreadyAssignedDataObjectsAndChildren = useCallback(
(expressionElement: SceSim__expressionElementsType, isBackground: boolean) => {
- const testScenarioDescriptor = retrieveModelDescriptor(scesimModel.ScenarioSimulationModel, isBackground);
-
+ const testScenarioDescriptor = isBackground
+ ? scesimModel.ScenarioSimulationModel.background.scesimModelDescriptor
+ : scesimModel.ScenarioSimulationModel.simulation.scesimModelDescriptor;
const assignedExpressionElements = testScenarioDescriptor.factMappings.FactMapping!.map(
(factMapping) => factMapping.expressionElements!
);
@@ -233,9 +221,9 @@ function TestScenarioDataSelectorPanel({
* - All the NOT-assigned fields of the selected column instance
* - All the NOT-assigned fields of the NOT-ASSIGNED instances, if the selected column doesn't have an instance (1th level header) assigned
*/
- if (selectedColumnMetadata.factMapping.className.__$$text === EMPTY_TYPE) {
+ if (selectedColumnMetadata.factMapping.className.__$$text === "java.lang.Void") {
const isFactIdentifierAssigned =
- selectedColumnMetadata.factMapping.factIdentifier.className!.__$$text !== EMPTY_TYPE;
+ selectedColumnMetadata.factMapping.factIdentifier.className!.__$$text !== "java.lang.Void";
let filteredDataObjects: TestScenarioDataObject[] = [];
if (isFactIdentifierAssigned) {
@@ -245,10 +233,9 @@ function TestScenarioDataSelectorPanel({
selectedColumnMetadata.isBackground
);
} else {
- const testScenarioDescriptor = retrieveModelDescriptor(
- scesimModel.ScenarioSimulationModel,
- selectedColumnMetadata.isBackground
- );
+ const testScenarioDescriptor = selectedColumnMetadata.isBackground
+ ? scesimModel.ScenarioSimulationModel.background.scesimModelDescriptor
+ : scesimModel.ScenarioSimulationModel.simulation.scesimModelDescriptor;
const assignedExpressionElements = testScenarioDescriptor.factMappings.FactMapping!.map(
(factMapping) => factMapping.expressionElements!
);
@@ -286,12 +273,10 @@ function TestScenarioDataSelectorPanel({
*/
const factIdentifier = selectedColumnMetadata.factMapping.expressionElements!.ExpressionElement![0].step.__$$text;
const filteredDataObjects = dataObjects.filter((dataObject) => filterTypesItems(dataObject, factIdentifier));
- const isExpressionType =
- selectedColumnMetadata.factMapping.factMappingValueType!.__$$text ===
- TEST_SCENARIO_EXPRESSION_TYPE[TEST_SCENARIO_EXPRESSION_TYPE.EXPRESSION];
+ const isExpressionType = selectedColumnMetadata.factMapping.factMappingValueType!.__$$text === "EXPRESSION";
const isSimpleTypeFact =
selectedColumnMetadata.factMapping.expressionElements!.ExpressionElement!.length === 1 &&
- selectedColumnMetadata.factMapping.className.__$$text !== EMPTY_TYPE;
+ selectedColumnMetadata.factMapping.className.__$$text !== "java.lang.Void";
let fieldID: string;
if (isExpressionType) {
fieldID = selectedColumnMetadata.factMapping.expressionElements!.ExpressionElement![0].step.__$$text;
@@ -303,7 +288,7 @@ function TestScenarioDataSelectorPanel({
.join(".");
}
- //TODO 1 This not work with multiple level and expressions fields.
+ //TODO 1 This not work with multiple level and expressions fields. see kie-issues#1514
const treeViewItemToActivate = filteredDataObjects
.reduce((acc: TestScenarioDataObject[], item) => {
return item.children ? acc.concat(item.children) : acc;
@@ -332,25 +317,25 @@ function TestScenarioDataSelectorPanel({
const treeViewEmptyIcon = filteredItems.length === 0 ? WarningTriangleIcon : WarningTriangleIcon;
const title =
dataObjects.length === 0
- ? assetType === TestScenarioType[TestScenarioType.DMN]
+ ? testScenarioType === "DMN"
? i18n.drawer.dataSelector.emptyDataObjectsTitleDMN
: i18n.drawer.dataSelector.emptyDataObjectsTitleRule
: "No more properties"; //TODO CHANGE
const description =
dataObjects.length === 0
- ? assetType === TestScenarioType[TestScenarioType.DMN]
+ ? testScenarioType === "DMN"
? i18n.drawer.dataSelector.emptyDataObjectsDescriptionDMN
: i18n.drawer.dataSelector.emptyDataObjectsDescriptionRule
: "All the properties have been already assigned"; //TODO CHANGE
{
- assetType === TestScenarioType[TestScenarioType.DMN]
+ testScenarioType === "DMN"
? i18n.drawer.dataSelector.emptyDataObjectsTitleDMN
: i18n.drawer.dataSelector.emptyDataObjectsTitleRule;
}
return { description: description, enabled: isTreeViewNotEmpty, icon: treeViewEmptyIcon, title: title };
- }, [assetType, dataObjects.length, filteredItems.length, i18n]);
+ }, [testScenarioType, dataObjects.length, filteredItems.length, i18n]);
const insertDataObjectButtonStatus = useMemo(() => {
if (!selectedColumnMetadata) {
@@ -391,106 +376,49 @@ function TestScenarioDataSelectorPanel({
// CHECK
const onInsertDataObjectClick = useCallback(
- /** TODO 2 : NEED A POPUP ASKING IF WE WANT TO REPLACE VALUES OR NOT */
-
+ /** TODO 2 : NEED A POPUP ASKING IF WE WANT TO REPLACE VALUES OR NOT see kie-issues#1514 */
() => {
- updateTestScenarioModel((prevState) => {
- const isBackground = selectedColumnMetadata!.isBackground;
- const factMappings = retrieveModelDescriptor(prevState.ScenarioSimulationModel, isBackground).factMappings
- .FactMapping!;
- const deepClonedFactMappings = JSON.parse(JSON.stringify(factMappings));
- const isRootType = isDataObjectRootParent(dataObjects, treeViewStatus.activeItems[0].id!.toString());
- const rootDataObject = findDataObjectRootParent(dataObjects, treeViewStatus.activeItems[0].id!.toString());
-
- const className = treeViewStatus.activeItems[0].customBadgeContent!.toString();
- const expressionAlias = isRootType ? "Expression >" : treeViewStatus.activeItems[0].name!.toString();
- const expressionElementsSteps = treeViewStatus.activeItems[0].id!.split(".").filter((step) => !!step.trim()); //WARNING !!!! THIS DOESN'T WORK WITH IMPORTED DATA OBJECTS
- const factName = treeViewStatus.activeItems[0].id!.split(".")[0]; //WARNING !!!! THIS DOESN'T WORK WITH IMPORTED DATA OBJECTS
- const factClassName = isRootType
- ? treeViewStatus.activeItems[0].customBadgeContent!.toString()
- : rootDataObject.customBadgeContent!.toString();
- const factMappingValueType = isRootType
- ? TEST_SCENARIO_EXPRESSION_TYPE[TEST_SCENARIO_EXPRESSION_TYPE.EXPRESSION]
- : TEST_SCENARIO_EXPRESSION_TYPE[TEST_SCENARIO_EXPRESSION_TYPE.NOT_EXPRESSION];
-
- const factMappingToUpdate: SceSim__FactMappingType = deepClonedFactMappings[selectedColumnMetadata!.index];
- factMappingToUpdate.className = { __$$text: className };
- factMappingToUpdate.factAlias = { __$$text: factName };
- factMappingToUpdate.factIdentifier.className = { __$$text: factClassName };
- factMappingToUpdate.factIdentifier.name = { __$$text: factName };
- factMappingToUpdate.factMappingValueType = { __$$text: factMappingValueType };
- factMappingToUpdate.expressionAlias = { __$$text: expressionAlias };
- factMappingToUpdate.expressionElements = {
- ExpressionElement: expressionElementsSteps.map((ee) => {
- return { step: { __$$text: ee } };
- }),
- };
-
- const deepClonedRowsData: SceSim__FactMappingValuesTypes[] = JSON.parse(
- JSON.stringify(retrieveRowsDataFromModel(prevState.ScenarioSimulationModel, isBackground))
- );
-
- deepClonedRowsData.forEach((fmv, index) => {
- const factMappingValues = fmv.factMappingValues.FactMappingValue!;
- const newFactMappingValues = [...factMappingValues];
-
- const factMappingValueToUpdateIndex = retrieveFactMappingValueIndexByIdentifiers(
- newFactMappingValues,
- selectedColumnMetadata!.factMapping.factIdentifier,
- selectedColumnMetadata!.factMapping.expressionIdentifier
- );
- const factMappingValueToUpdate = factMappingValues[factMappingValueToUpdateIndex];
- newFactMappingValues[factMappingValueToUpdateIndex] = {
- ...factMappingValueToUpdate,
- factIdentifier: { className: { __$$text: factClassName }, name: { __$$text: factName } },
- // rawValue: {
- // __$$text: update.value, //TODO 2 related
- // },
- };
-
- deepClonedRowsData[index].factMappingValues.FactMappingValue = newFactMappingValues;
+ const isBackground = selectedColumnMetadata!.isBackground;
+ const isRootType = isDataObjectRootParent(dataObjects, treeViewStatus.activeItems[0].id!.toString());
+ const rootDataObject = findDataObjectRootParent(dataObjects, treeViewStatus.activeItems[0].id!.toString());
+ const className = treeViewStatus.activeItems[0].customBadgeContent!.toString();
+ const expressionAlias = isRootType ? "Expression >" : treeViewStatus.activeItems[0].name!.toString();
+ const expressionElementsSteps = treeViewStatus.activeItems[0].id!.split(".").filter((step) => !!step.trim()); //WARNING !!!! THIS DOESN'T WORK WITH IMPORTED DATA OBJECTS see kie-issues#1514
+ const factName = treeViewStatus.activeItems[0].id!.split(".")[0]; //WARNING !!!! THIS DOESN'T WORK WITH IMPORTED DATA OBJECTS see kie-issues#1514
+ const factClassName = isRootType
+ ? treeViewStatus.activeItems[0].customBadgeContent!.toString()
+ : rootDataObject.customBadgeContent!.toString();
+ const factMappingValueType = isRootType ? "EXPRESSION" : "NOT_EXPRESSION";
+
+ testScenarioEditorStoreApi.setState((state) => {
+ const factMappings = isBackground
+ ? state.scesim.model.ScenarioSimulationModel.background.scesimModelDescriptor.factMappings.FactMapping!
+ : state.scesim.model.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping!;
+ const factMappingValuesTypes = isBackground
+ ? state.scesim.model.ScenarioSimulationModel.background.scesimData.BackgroundData!
+ : state.scesim.model.ScenarioSimulationModel.simulation.scesimData.Scenario!;
+
+ const { updatedFactMapping } = updateColumn({
+ className: className,
+ expressionAlias: expressionAlias,
+ expressionElementsSteps: expressionElementsSteps,
+ expressionIdentifierName: selectedColumnMetadata!.factMapping.expressionIdentifier.name?.__$$text,
+ expressionIdentifierType: selectedColumnMetadata!.factMapping.expressionIdentifier.type?.__$$text,
+ factMappings: factMappings,
+ factClassName: factClassName,
+ factIdentifierClassName: selectedColumnMetadata!.factMapping.factIdentifier.className?.__$$text,
+ factIdentifierName: selectedColumnMetadata!.factMapping.factIdentifier.name?.__$$text,
+ factMappingValuesTypes: factMappingValuesTypes,
+ factMappingValueType: factMappingValueType,
+ factName: factName,
+ selectedColumnIndex: selectedColumnMetadata!.index,
});
- /** Updating the selectedColumn */
- updateSelectedColumnMetaData({
- factMapping: JSON.parse(JSON.stringify(factMappingToUpdate)),
+ state.dispatch(state).table.updateSelectedColumn({
+ factMapping: updatedFactMapping,
index: selectedColumnMetadata!.index,
isBackground: isBackground,
});
-
- return {
- ScenarioSimulationModel: {
- ...prevState.ScenarioSimulationModel,
- simulation: {
- scesimModelDescriptor: {
- factMappings: {
- FactMapping: isBackground
- ? prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping
- : deepClonedFactMappings,
- },
- },
- scesimData: {
- Scenario: isBackground
- ? prevState.ScenarioSimulationModel.simulation.scesimData.Scenario
- : deepClonedRowsData,
- },
- },
- background: {
- scesimModelDescriptor: {
- factMappings: {
- FactMapping: isBackground
- ? deepClonedFactMappings
- : prevState.ScenarioSimulationModel.background.scesimModelDescriptor.factMappings.FactMapping,
- },
- },
- scesimData: {
- BackgroundData: isBackground
- ? deepClonedRowsData
- : prevState.ScenarioSimulationModel.background.scesimData.BackgroundData,
- },
- },
- },
- };
});
},
[
@@ -498,9 +426,8 @@ function TestScenarioDataSelectorPanel({
findDataObjectRootParent,
isDataObjectRootParent,
selectedColumnMetadata,
+ testScenarioEditorStoreApi,
treeViewStatus.activeItems,
- updateSelectedColumnMetaData,
- updateTestScenarioModel,
]
);
@@ -552,12 +479,12 @@ function TestScenarioDataSelectorPanel({
return (
<>
- {assetType === TestScenarioType[TestScenarioType.DMN]
+ {testScenarioType === "DMN"
? i18n.drawer.dataSelector.descriptionDMN
: i18n.drawer.dataSelector.descriptionRule}
void;
- onUpdateSettingField: (field: string, value: boolean | string) => void;
- scesimModel: SceSimModel;
- selectedColumnMetaData: TestScenarioSelectedColumnMetaData | null;
- selectedDock: TestScenarioEditorDock;
- testScenarioSettings: TestScenarioSettings;
- updateSelectedColumnMetaData: React.Dispatch>;
- updateTestScenarioModel: React.Dispatch>;
-}) {
+function TestScenarioDrawerPanel({ fileName, onDrawerClose }: { fileName: string; onDrawerClose: () => void }) {
const { i18n } = useTestScenarioEditorI18n();
+ const navigation = useTestScenarioEditorStore((state) => state.navigation);
+ const settingsModel = useTestScenarioEditorStore((state) => state.scesim.model.ScenarioSimulationModel.settings);
+ const testScenarioType = settingsModel.type?.__$$text.toUpperCase();
return (
@@ -77,17 +51,17 @@ function TestScenarioDrawerPanel({
{(() => {
- switch (selectedDock) {
+ switch (navigation.dock.selected) {
case TestScenarioEditorDock.CHEATSHEET:
return i18n.drawer.cheatSheet.title;
case TestScenarioEditorDock.DATA_OBJECT:
- return testScenarioSettings.assetType === TestScenarioType[TestScenarioType.DMN]
+ return testScenarioType === "DMN"
? i18n.drawer.dataSelector.titleDMN
: i18n.drawer.dataSelector.titleRule;
case TestScenarioEditorDock.SETTINGS:
return i18n.drawer.settings.title;
default:
- throw new Error("Wrong state, an invalid dock has been selected " + selectedDock);
+ throw new Error("Wrong state, an invalid dock has been selected " + navigation.dock.selected);
}
})()}
@@ -96,30 +70,15 @@ function TestScenarioDrawerPanel({
{(() => {
- switch (selectedDock) {
+ switch (navigation.dock.selected) {
case TestScenarioEditorDock.CHEATSHEET:
- return ;
+ return ;
case TestScenarioEditorDock.DATA_OBJECT:
- return (
-
- );
+ return ;
case TestScenarioEditorDock.SETTINGS:
- return (
-
- );
+ return ;
default:
- throw new Error("Wrong state, an invalid dock has been selected " + selectedDock);
+ throw new Error("Wrong state, an invalid dock has been selected " + navigation.dock.selected);
}
})()}
diff --git a/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx b/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx
index 6e6f421e9a4..9f522a2ccbf 100644
--- a/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx
+++ b/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx
@@ -17,31 +17,38 @@
* under the License.
*/
import * as React from "react";
+import { useCallback } from "react";
import { Checkbox } from "@patternfly/react-core/dist/esm/components/Checkbox";
import { FormSelect, FormSelectOption } from "@patternfly/react-core/dist/esm/components/FormSelect";
+import { HelpIcon } from "@patternfly/react-icons/dist/esm/icons/help-icon";
+import { Icon } from "@patternfly/react-core/dist/esm/components/Icon/Icon";
import { TextInput } from "@patternfly/react-core/dist/js/components/TextInput";
import { Title } from "@patternfly/react-core/dist/js/components/Title";
+import { Tooltip } from "@patternfly/react-core/dist/esm/components/Tooltip";
-import { TestScenarioSettings, TestScenarioType } from "../TestScenarioEditor";
-import { useTestScenarioEditorI18n } from "../i18n";
+import { SceSim__settingsType } from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
-import { HelpIcon } from "@patternfly/react-icons/dist/esm/icons/help-icon";
-import { Icon } from "@patternfly/react-core/dist/esm/components/Icon/Icon";
-import { Tooltip } from "@patternfly/react-core/dist/esm/components/Tooltip";
+import { useTestScenarioEditorI18n } from "../i18n";
+import { useTestScenarioEditorStore, useTestScenarioEditorStoreApi } from "../store/TestScenarioStoreContext";
import "./TestScenarioDrawerSettingsPanel.css";
-function TestScenarioDrawerSettingsPanel({
- fileName,
- onUpdateSettingField,
- testScenarioSettings,
-}: {
- fileName: string;
- onUpdateSettingField: (field: string, value: boolean | string) => void;
- testScenarioSettings: TestScenarioSettings;
-}) {
+function TestScenarioDrawerSettingsPanel({ fileName }: { fileName: string }) {
const { i18n } = useTestScenarioEditorI18n();
+ const settingsModel = useTestScenarioEditorStore((state) => state.scesim.model.ScenarioSimulationModel.settings);
+ const testScenarioEditorStoreApi = useTestScenarioEditorStoreApi();
+ const testScenarioType = settingsModel.type?.__$$text.toUpperCase();
+
+ const updateSettingsField = useCallback(
+ (fieldName: keyof SceSim__settingsType, value: string | boolean) =>
+ testScenarioEditorStoreApi.setState((state) => {
+ (state.scesim.model.ScenarioSimulationModel.settings[fieldName] as { __$$text: string | boolean }) = {
+ __$$text: value,
+ };
+ }),
+ [testScenarioEditorStoreApi]
+ );
return (
<>
@@ -54,11 +61,11 @@ function TestScenarioDrawerSettingsPanel({
- {testScenarioSettings.assetType === TestScenarioType[TestScenarioType.DMN] ? (
+ {testScenarioType === "DMN" ? (
<>
{i18n.drawer.settings.dmnModel}
@@ -78,7 +85,7 @@ function TestScenarioDrawerSettingsPanel({
@@ -87,7 +94,7 @@ function TestScenarioDrawerSettingsPanel({
@@ -104,10 +111,10 @@ function TestScenarioDrawerSettingsPanel({
onUpdateSettingField("dmoSession", value)}
+ onChange={(value) => updateSettingsField("dmoSession", value)}
placeholder={i18n.drawer.settings.kieSessionRulePlaceholder}
type="text"
- value={testScenarioSettings.kieSessionRule}
+ value={settingsModel.dmoSession?.__$$text}
/>
{i18n.drawer.settings.ruleFlowGroup}
@@ -119,18 +126,18 @@ function TestScenarioDrawerSettingsPanel({
onUpdateSettingField("ruleFlowGroup", value)}
+ onChange={(value) => updateSettingsField("ruleFlowGroup", value)}
placeholder={i18n.drawer.settings.ruleFlowGroupPlaceholder}
type="text"
- value={testScenarioSettings.ruleFlowGroup}
+ value={settingsModel.ruleFlowGroup?.__$$text}
/>
onUpdateSettingField("stateless", value)}
+ onChange={(value) => updateSettingsField("stateless", value)}
/>
@@ -145,9 +152,9 @@ function TestScenarioDrawerSettingsPanel({
onUpdateSettingField("skipFromBuild", value)}
+ onChange={(value) => updateSettingsField("skipFromBuild", value)}
/>
diff --git a/packages/scesim-editor/src/hook/useEffectAfterFirstRender.ts b/packages/scesim-editor/src/hook/useEffectAfterFirstRender.ts
new file mode 100644
index 00000000000..df84f4b1ae9
--- /dev/null
+++ b/packages/scesim-editor/src/hook/useEffectAfterFirstRender.ts
@@ -0,0 +1,32 @@
+/*
+ * 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 { useEffect, useRef } from "react";
+
+export function useEffectAfterFirstRender(effect: Parameters[0], b: React.DependencyList) {
+ const didMountRef = useRef(false);
+
+ useEffect(() => {
+ if (didMountRef.current) {
+ return effect();
+ }
+ didMountRef.current = true;
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, b);
+}
diff --git a/packages/scesim-editor/src/i18n/TestScenarioEditorI18n.ts b/packages/scesim-editor/src/i18n/TestScenarioEditorI18n.ts
index be68682f4d4..1eaebb8771b 100644
--- a/packages/scesim-editor/src/i18n/TestScenarioEditorI18n.ts
+++ b/packages/scesim-editor/src/i18n/TestScenarioEditorI18n.ts
@@ -115,6 +115,12 @@ interface TestScenarioEditorDictionary extends ReferenceDictionary {
title: string;
};
};
+ errorFallBack: {
+ title: string;
+ body: string;
+ lastActionButton: string;
+ fileIssueHref: string;
+ };
sidebar: {
cheatSheetTooltip: string;
dataSelectorTooltip: string;
diff --git a/packages/scesim-editor/src/i18n/locales/en.ts b/packages/scesim-editor/src/i18n/locales/en.ts
index 72de8ce02cc..888f1e2b871 100644
--- a/packages/scesim-editor/src/i18n/locales/en.ts
+++ b/packages/scesim-editor/src/i18n/locales/en.ts
@@ -137,6 +137,12 @@ export const en: TestScenarioEditorI18n = {
title: "Settings",
},
},
+ errorFallBack: {
+ title: "An unexpected error happened",
+ body: "This is a bug. Please consider reporting it so the DMN Editor can continue improving. See the details below.",
+ lastActionButton: "Try undoing last action",
+ fileIssueHref: "File an issue",
+ },
sidebar: {
cheatSheetTooltip: "CheatSheet: Useful information for Test Scenario Usage",
dataSelectorTooltip: "Selector: It provides a tool to edit your Scenarios",
diff --git a/packages/scesim-editor/src/mutations/addColumn.ts b/packages/scesim-editor/src/mutations/addColumn.ts
new file mode 100644
index 00000000000..ab5a22bf7a3
--- /dev/null
+++ b/packages/scesim-editor/src/mutations/addColumn.ts
@@ -0,0 +1,183 @@
+/*
+ * 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 _ from "lodash";
+import { v4 as uuid } from "uuid";
+
+import {
+ SceSim__FactMappingType,
+ SceSim__FactMappingValuesTypes,
+} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+import { InsertRowColumnsDirection } from "@kie-tools/boxed-expression-component/dist/api/BeeTable";
+
+export function addColumn({
+ beforeIndex,
+ factMappings,
+ factMappingValues,
+ insertDirection,
+ isInstance,
+ selectedColumnFactMappingIndex,
+}: {
+ beforeIndex: number;
+ factMappings: SceSim__FactMappingType[];
+ factMappingValues: SceSim__FactMappingValuesTypes[];
+ insertDirection: InsertRowColumnsDirection;
+ isInstance: boolean;
+ selectedColumnFactMappingIndex: number;
+}) {
+ const selectedColumnFactMapping = factMappings[selectedColumnFactMappingIndex];
+ const targetColumnIndex = determineNewColumnTargetIndex(
+ factMappings,
+ insertDirection,
+ isInstance,
+ selectedColumnFactMappingIndex,
+ selectedColumnFactMapping
+ );
+
+ const instanceDefaultNames = factMappings
+ .filter((factMapping) => factMapping.factAlias!.__$$text.startsWith("INSTANCE-"))
+ .map((factMapping) => factMapping.factAlias!.__$$text);
+
+ const isNewInstance = isInstance || selectedColumnFactMapping.factIdentifier.className?.__$$text === "java.lang.Void";
+
+ const newFactMapping = {
+ className: { __$$text: "java.lang.Void" },
+ columnWidth: { __$$text: 150 },
+ expressionAlias: { __$$text: "PROPERTY" },
+ expressionElements: isNewInstance
+ ? undefined
+ : {
+ ExpressionElement: [
+ {
+ step: {
+ __$$text: selectedColumnFactMapping.expressionElements!.ExpressionElement![0].step.__$$text,
+ },
+ },
+ ],
+ },
+ expressionIdentifier: {
+ name: { __$$text: `_${uuid()}`.toLocaleUpperCase() },
+ type: { __$$text: selectedColumnFactMapping.expressionIdentifier.type!.__$$text },
+ },
+ factAlias: {
+ __$$text: isNewInstance
+ ? getNextAvailablePrefixedName(instanceDefaultNames, "INSTANCE")
+ : selectedColumnFactMapping.factAlias.__$$text,
+ },
+ factIdentifier: {
+ name: {
+ __$$text: isNewInstance
+ ? getNextAvailablePrefixedName(instanceDefaultNames, "INSTANCE")
+ : selectedColumnFactMapping.factIdentifier.name!.__$$text,
+ },
+ className: {
+ __$$text: isNewInstance ? "java.lang.Void" : selectedColumnFactMapping.factIdentifier.className!.__$$text,
+ },
+ },
+ factMappingValueType: { __$$text: "NOT_EXPRESSION" },
+ };
+
+ factMappings.splice(targetColumnIndex, 0, newFactMapping);
+
+ factMappingValues.forEach((scenario) => {
+ scenario.factMappingValues.FactMappingValue!.splice(beforeIndex + 1, 0, {
+ expressionIdentifier: {
+ name: { __$$text: newFactMapping.expressionIdentifier.name.__$$text },
+ type: { __$$text: newFactMapping.expressionIdentifier.type.__$$text },
+ },
+ factIdentifier: {
+ name: { __$$text: newFactMapping.factIdentifier.name.__$$text },
+ className: { __$$text: newFactMapping.factIdentifier.className.__$$text },
+ },
+ rawValue: { __$$text: "", "@_class": "string" },
+ });
+ });
+}
+
+/* It determines in which index position a column should be added. In case of a field, the new column index is simply
+ in the right or in the left of the selected column. In case of a new instance, it's required to find the first column
+ index outside the selected Instance group. */
+const determineNewColumnTargetIndex = (
+ factMappings: SceSim__FactMappingType[],
+ insertDirection: InsertRowColumnsDirection,
+ isInstance: boolean,
+ selectedColumnIndex: number,
+ selectedFactMapping: SceSim__FactMappingType
+) => {
+ const groupType = selectedFactMapping.expressionIdentifier.type!.__$$text;
+ const instanceName = selectedFactMapping.factIdentifier.name!.__$$text;
+ const instanceType = selectedFactMapping.factIdentifier.className!.__$$text;
+
+ if (!isInstance) {
+ if (insertDirection === InsertRowColumnsDirection.AboveOrRight) {
+ return selectedColumnIndex + 1;
+ } else {
+ return selectedColumnIndex;
+ }
+ }
+
+ let newColumnTargetColumn = -1;
+
+ if (insertDirection === InsertRowColumnsDirection.AboveOrRight) {
+ for (let i = selectedColumnIndex; i < factMappings.length; i++) {
+ const currentFM = factMappings[i];
+ if (
+ currentFM.expressionIdentifier.type!.__$$text === groupType &&
+ currentFM.factIdentifier.name?.__$$text === instanceName &&
+ currentFM.factIdentifier.className?.__$$text === instanceType
+ ) {
+ if (i == factMappings.length - 1) {
+ newColumnTargetColumn = i + 1;
+ }
+ } else {
+ newColumnTargetColumn = i;
+ break;
+ }
+ }
+ } else {
+ for (let i = selectedColumnIndex; i >= 0; i--) {
+ const currentFM = factMappings[i];
+
+ if (
+ currentFM.expressionIdentifier.type!.__$$text === groupType &&
+ currentFM.factIdentifier.name?.__$$text === instanceName &&
+ currentFM.factIdentifier.className?.__$$text === instanceType
+ ) {
+ if (i == 0) {
+ newColumnTargetColumn = 0;
+ }
+ } else {
+ newColumnTargetColumn = i + 1;
+ break;
+ }
+ }
+ }
+
+ return newColumnTargetColumn;
+};
+
+const getNextAvailablePrefixedName = (
+ names: string[],
+ namePrefix: string,
+ lastIndex: number = names.length
+): string => {
+ const candidate = `${namePrefix}-${lastIndex + 1}`;
+ const elemWithCandidateName = names.indexOf(candidate);
+ return elemWithCandidateName >= 0 ? getNextAvailablePrefixedName(names, namePrefix, lastIndex + 1) : candidate;
+};
diff --git a/packages/scesim-editor/src/mutations/addRow.ts b/packages/scesim-editor/src/mutations/addRow.ts
new file mode 100644
index 00000000000..65887921b4e
--- /dev/null
+++ b/packages/scesim-editor/src/mutations/addRow.ts
@@ -0,0 +1,56 @@
+/*
+ * 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 {
+ SceSim__FactMappingType,
+ SceSim__FactMappingValuesTypes,
+} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+
+export function addRow({
+ beforeIndex,
+ factMappings,
+ factMappingValues,
+}: {
+ beforeIndex: number;
+ factMappings: SceSim__FactMappingType[];
+ factMappingValues: SceSim__FactMappingValuesTypes[];
+}) {
+ /* Creating a new Scenario (Row) composed by a list of FactMappingValues. The list order is not relevant. */
+ const factMappingValuesItems = factMappings.map((factMapping) => {
+ return {
+ expressionIdentifier: {
+ name: { __$$text: factMapping.expressionIdentifier.name!.__$$text },
+ type: { __$$text: factMapping.expressionIdentifier.type!.__$$text },
+ },
+ factIdentifier: {
+ name: { __$$text: factMapping.factIdentifier.name!.__$$text },
+ className: { __$$text: factMapping.factIdentifier.className!.__$$text },
+ },
+ rawValue: { __$$text: "", "@_class": "string" },
+ };
+ });
+
+ const newScenario = {
+ factMappingValues: {
+ FactMappingValue: factMappingValuesItems,
+ },
+ };
+
+ factMappingValues.splice(beforeIndex, 0, newScenario);
+}
diff --git a/packages/scesim-editor/src/mutations/deleteColumn.ts b/packages/scesim-editor/src/mutations/deleteColumn.ts
new file mode 100644
index 00000000000..07137ff667d
--- /dev/null
+++ b/packages/scesim-editor/src/mutations/deleteColumn.ts
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import _, { isNumber } from "lodash";
+import {
+ SceSim__FactMappingType,
+ SceSim__FactMappingValuesTypes,
+} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+
+export function deleteColumn({
+ factMappingIndexToRemove,
+ factMappings,
+ factMappingValues,
+ isBackground,
+ isInstance,
+ selectedColumnIndex,
+}: {
+ factMappingIndexToRemove: number;
+ factMappings: SceSim__FactMappingType[];
+ factMappingValues: SceSim__FactMappingValuesTypes[];
+ isBackground: boolean;
+ isInstance: boolean;
+ selectedColumnIndex: number;
+}): {
+ deletedFactMappingIndexs: number[];
+} {
+ /* Retriving the FactMapping (Column) to be removed). If the user selected a single column, it finds the exact
+ FactMapping to delete. If the user selected an instance (group of columns), it retrives all the FactMappings
+ that belongs to the the instance group */
+ const factMappingToRemove = factMappings[factMappingIndexToRemove];
+ const groupType = factMappingToRemove.expressionIdentifier.type!.__$$text;
+ const instanceName = factMappingToRemove.factIdentifier.name!.__$$text;
+ const instanceType = factMappingToRemove.factIdentifier.className!.__$$text;
+
+ const allFactMappingWithIndexesToRemove = isInstance
+ ? factMappings
+ .map((factMapping, index) => {
+ if (
+ factMapping.expressionIdentifier.type!.__$$text === groupType &&
+ factMapping.factIdentifier.name?.__$$text === instanceName &&
+ factMapping.factIdentifier.className?.__$$text === instanceType
+ ) {
+ return { factMappingIndex: index, factMapping: factMapping };
+ } else {
+ return {};
+ }
+ })
+ .filter((item) => isNumber(item.factMappingIndex))
+ : [{ factMappingIndex: selectedColumnIndex + (isBackground ? 0 : 1), factMapping: factMappingToRemove }];
+
+ factMappings.splice(allFactMappingWithIndexesToRemove[0].factMappingIndex!, allFactMappingWithIndexesToRemove.length);
+
+ factMappingValues.forEach((rowData) => {
+ allFactMappingWithIndexesToRemove.forEach((itemToRemove) => {
+ const factMappingValueColumnIndexToRemove = rowData.factMappingValues.FactMappingValue!.findIndex(
+ (factMappingValue) =>
+ factMappingValue.factIdentifier.name?.__$$text === itemToRemove.factMapping!.factIdentifier.name?.__$$text &&
+ factMappingValue.factIdentifier.className?.__$$text ===
+ itemToRemove.factMapping!.factIdentifier.className?.__$$text &&
+ factMappingValue.expressionIdentifier.name?.__$$text ===
+ itemToRemove.factMapping!.expressionIdentifier.name?.__$$text &&
+ factMappingValue.expressionIdentifier.type?.__$$text ===
+ itemToRemove.factMapping!.expressionIdentifier.type?.__$$text
+ );
+
+ rowData.factMappingValues.FactMappingValue!.splice(factMappingValueColumnIndexToRemove, 1);
+ });
+ });
+
+ return { deletedFactMappingIndexs: allFactMappingWithIndexesToRemove.flatMap((item) => item.factMappingIndex!) };
+}
diff --git a/packages/scesim-editor/src/mutations/deleteRow.ts b/packages/scesim-editor/src/mutations/deleteRow.ts
new file mode 100644
index 00000000000..26f14903a7d
--- /dev/null
+++ b/packages/scesim-editor/src/mutations/deleteRow.ts
@@ -0,0 +1,30 @@
+/*
+ * 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 { SceSim__FactMappingValuesTypes } from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+
+export function deleteRow({
+ rowIndex,
+ factMappingValues,
+}: {
+ rowIndex: number;
+ factMappingValues: SceSim__FactMappingValuesTypes[];
+}) {
+ factMappingValues.splice(rowIndex, 1);
+}
diff --git a/packages/scesim-editor/src/mutations/duplicateRow.ts b/packages/scesim-editor/src/mutations/duplicateRow.ts
new file mode 100644
index 00000000000..268da3f826f
--- /dev/null
+++ b/packages/scesim-editor/src/mutations/duplicateRow.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 { SceSim__FactMappingValuesTypes } from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+
+export function dupliacteRow({
+ rowIndex,
+ factMappingValues,
+}: {
+ rowIndex: number;
+ factMappingValues: SceSim__FactMappingValuesTypes[];
+}) {
+ /* It simply clones a Scenario (Row) and adds it in a current-cloned Scenario list */
+ const factMappingValuesItems = JSON.parse(
+ JSON.stringify(factMappingValues[rowIndex].factMappingValues.FactMappingValue)
+ );
+
+ const newScenario = {
+ factMappingValues: {
+ FactMappingValue: factMappingValuesItems,
+ },
+ };
+
+ factMappingValues.splice(rowIndex, 0, newScenario);
+}
diff --git a/packages/scesim-editor/src/mutations/updateCell.ts b/packages/scesim-editor/src/mutations/updateCell.ts
new file mode 100644
index 00000000000..3a984fb32c7
--- /dev/null
+++ b/packages/scesim-editor/src/mutations/updateCell.ts
@@ -0,0 +1,52 @@
+/*
+ * 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 {
+ SceSim__FactMappingType,
+ SceSim__FactMappingValuesTypes,
+} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+
+export function updateCell({
+ columnIndex,
+ factMappings,
+ factMappingValuesTypes,
+ rowIndex,
+ value,
+}: {
+ columnIndex: number;
+ factMappings: SceSim__FactMappingType[];
+ factMappingValuesTypes: SceSim__FactMappingValuesTypes[];
+ rowIndex: number;
+ value: any;
+}) {
+ /* To update the related FactMappingValue, it compares every FactMappingValue associated with the Scenario (Row)
+ that contains the cell with the FactMapping (Column) fields factIdentifier and expressionIdentifier */
+ const factMapping = factMappings[columnIndex];
+ const factMappingValues = factMappingValuesTypes[rowIndex].factMappingValues.FactMappingValue!;
+
+ const factMappingValueToUpdateIndex = factMappingValues.findIndex(
+ (factMappingValue) =>
+ factMappingValue.factIdentifier.name?.__$$text === factMapping!.factIdentifier.name?.__$$text &&
+ factMappingValue.factIdentifier.className?.__$$text === factMapping!.factIdentifier.className?.__$$text &&
+ factMappingValue.expressionIdentifier.name?.__$$text === factMapping!.expressionIdentifier.name?.__$$text &&
+ factMappingValue.expressionIdentifier.type?.__$$text === factMapping!.expressionIdentifier.type?.__$$text
+ );
+ const factMappingValueToUpdate = factMappingValues[factMappingValueToUpdateIndex];
+ factMappingValueToUpdate.rawValue = { __$$text: value };
+}
diff --git a/packages/scesim-editor/src/mutations/updateColumn.ts b/packages/scesim-editor/src/mutations/updateColumn.ts
new file mode 100644
index 00000000000..081e78de4c4
--- /dev/null
+++ b/packages/scesim-editor/src/mutations/updateColumn.ts
@@ -0,0 +1,84 @@
+/*
+ * 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 _ from "lodash";
+import {
+ SceSim__FactMappingType,
+ SceSim__FactMappingValuesTypes,
+} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+
+export function updateColumn({
+ className,
+ expressionAlias,
+ expressionElementsSteps,
+ expressionIdentifierName,
+ expressionIdentifierType,
+ factMappings,
+ factMappingValuesTypes,
+ factMappingValueType,
+ factClassName,
+ factIdentifierClassName,
+ factIdentifierName,
+ factName,
+ selectedColumnIndex,
+}: {
+ className: string;
+ expressionAlias: string;
+ expressionElementsSteps: string[];
+ expressionIdentifierName: string | undefined;
+ expressionIdentifierType: string | undefined;
+ factMappings: SceSim__FactMappingType[];
+ factMappingValuesTypes: SceSim__FactMappingValuesTypes[];
+ factMappingValueType: "EXPRESSION" | "NOT_EXPRESSION";
+ factClassName: string;
+ factIdentifierClassName: string | undefined;
+ factIdentifierName: string | undefined;
+ factName: string;
+ selectedColumnIndex: number;
+}): { updatedFactMapping: SceSim__FactMappingType } {
+ const factMappingToUpdate = factMappings[selectedColumnIndex];
+ factMappingToUpdate.className = { __$$text: className };
+ factMappingToUpdate.factAlias = { __$$text: factName };
+ factMappingToUpdate.factIdentifier.className = { __$$text: factClassName };
+ factMappingToUpdate.factIdentifier.name = { __$$text: factName };
+ factMappingToUpdate.factMappingValueType = { __$$text: factMappingValueType };
+ factMappingToUpdate.expressionAlias = { __$$text: expressionAlias };
+ factMappingToUpdate.expressionElements = {
+ ExpressionElement: expressionElementsSteps.map((ee) => {
+ return { step: { __$$text: ee } };
+ }),
+ };
+
+ factMappingValuesTypes.forEach((fmv) => {
+ const factMappingValues = fmv.factMappingValues.FactMappingValue!;
+ const factMappingValueToUpdateIndex = factMappingValues.findIndex(
+ (factMappingValue) =>
+ factMappingValue.factIdentifier.name?.__$$text === factIdentifierName &&
+ factMappingValue.factIdentifier.className?.__$$text === factIdentifierClassName &&
+ factMappingValue.expressionIdentifier.name?.__$$text === expressionIdentifierName &&
+ factMappingValue.expressionIdentifier.type?.__$$text === expressionIdentifierType
+ );
+ const factMappingValueToUpdate = factMappingValues[factMappingValueToUpdateIndex];
+ factMappingValueToUpdate.factIdentifier.className = { __$$text: factClassName };
+ factMappingValueToUpdate.factIdentifier.name = { __$$text: factName };
+ //factMappingValueToUpdate.rawValue = { __$$text: update.value }, //TODO 2 related see kie-issues#1514
+ });
+
+ return { updatedFactMapping: JSON.parse(JSON.stringify(factMappingToUpdate)) };
+}
diff --git a/packages/scesim-editor/src/mutations/updateColumnWidth.ts b/packages/scesim-editor/src/mutations/updateColumnWidth.ts
new file mode 100644
index 00000000000..8a59346ad03
--- /dev/null
+++ b/packages/scesim-editor/src/mutations/updateColumnWidth.ts
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { SceSim__FactMappingType } from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+
+export function updateColumnWidth({
+ factMappings,
+ columnIndex,
+ newWidth,
+ oldWidth,
+}: {
+ factMappings: SceSim__FactMappingType[];
+ columnIndex: number;
+ newWidth: number | undefined;
+ oldWidth: number | undefined;
+}) {
+ if (newWidth && oldWidth !== newWidth) {
+ factMappings[columnIndex].columnWidth = {
+ __$$text: newWidth,
+ };
+ }
+}
diff --git a/packages/scesim-editor/src/reactExt/ErrorBoundary.tsx b/packages/scesim-editor/src/reactExt/ErrorBoundary.tsx
deleted file mode 100644
index e61f50af242..00000000000
--- a/packages/scesim-editor/src/reactExt/ErrorBoundary.tsx
+++ /dev/null
@@ -1,62 +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 { ErrorInfo } from "react";
-
-interface State {
- hasError: boolean;
-}
-
-interface Props {
- children: React.ReactNode;
- error: React.ReactNode;
- setError?: React.Dispatch;
-}
-
-export class ErrorBoundary extends React.Component {
- constructor(props: any) {
- super(props);
- this.state = { hasError: false };
- }
-
- public reset() {
- this.props.setError?.(null);
- this.setState({ hasError: false });
- }
-
- public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
- this.props.setError?.(error);
- console.error(error);
- }
-
- public render() {
- if (this.state.hasError) {
- return this.props.error;
- }
-
- return this.props.children;
- }
-
- public static getDerivedStateFromError(error: Error) {
- return { hasError: true };
- }
-}
-
-export default ErrorBoundary;
diff --git a/packages/scesim-editor/src/sidebar/TestScenarioSideBarMenu.tsx b/packages/scesim-editor/src/sidebar/TestScenarioSideBarMenu.tsx
index df9671c6bb9..de41743c500 100644
--- a/packages/scesim-editor/src/sidebar/TestScenarioSideBarMenu.tsx
+++ b/packages/scesim-editor/src/sidebar/TestScenarioSideBarMenu.tsx
@@ -27,25 +27,32 @@ import CogIcon from "@patternfly/react-icons/dist/esm/icons/cog-icon";
import EditIcon from "@patternfly/react-icons/dist/esm/icons/edit-alt-icon";
import InfoIcon from "@patternfly/react-icons/dist/esm/icons/info-icon";
-import { TestScenarioEditorDock } from "../TestScenarioEditor";
import { useTestScenarioEditorI18n } from "../i18n";
+import { TestScenarioEditorDock } from "../store/TestScenarioEditorStore";
+import { useTestScenarioEditorStore, useTestScenarioEditorStoreApi } from "../store/TestScenarioStoreContext";
import "./TestScenarioSideBarMenu.css";
-function TestScenarioSideBarMenu({
- onSideBarButtonClicked,
- selectedSideBarMenuItem,
-}: {
- onSideBarButtonClicked: (selected: TestScenarioEditorDock) => void;
- selectedSideBarMenuItem: { isOpen: boolean; selected: TestScenarioEditorDock };
-}) {
+function TestScenarioSideBarMenu() {
const { i18n } = useTestScenarioEditorI18n();
+ const navigation = useTestScenarioEditorStore((state) => state.navigation);
+ const testScenarioEditorStoreApi = useTestScenarioEditorStoreApi();
const isSelectedMenuItem = useCallback(
(item: TestScenarioEditorDock) => {
- return selectedSideBarMenuItem.isOpen && selectedSideBarMenuItem.selected === item;
+ return navigation.dock.isOpen && navigation.dock.selected === item;
},
- [selectedSideBarMenuItem]
+ [navigation.dock]
+ );
+
+ const updateSelectedDock = useCallback(
+ (selected: TestScenarioEditorDock) => {
+ testScenarioEditorStoreApi.setState((state) => {
+ state.navigation.dock.isOpen = true;
+ state.navigation.dock.selected = selected;
+ });
+ },
+ [testScenarioEditorStoreApi]
);
return (
@@ -58,7 +65,7 @@ function TestScenarioSideBarMenu({
: "kie-scesim-editor-side-bar-menu--button"
}
variant="plain"
- onClick={() => onSideBarButtonClicked(TestScenarioEditorDock.DATA_OBJECT)}
+ onClick={() => updateSelectedDock(TestScenarioEditorDock.DATA_OBJECT)}
icon={}
/>
@@ -70,7 +77,7 @@ function TestScenarioSideBarMenu({
: "kie-scesim-editor-side-bar-menu--button"
}
icon={}
- onClick={() => onSideBarButtonClicked(TestScenarioEditorDock.CHEATSHEET)}
+ onClick={() => updateSelectedDock(TestScenarioEditorDock.CHEATSHEET)}
variant="plain"
/>
@@ -82,7 +89,7 @@ function TestScenarioSideBarMenu({
: "kie-scesim-editor-side-bar-menu--button"
}
icon={
}
- onClick={() => onSideBarButtonClicked(TestScenarioEditorDock.SETTINGS)}
+ onClick={() => updateSelectedDock(TestScenarioEditorDock.SETTINGS)}
variant="plain"
/>
diff --git a/packages/scesim-editor/src/store/ComputedStateCache.ts b/packages/scesim-editor/src/store/ComputedStateCache.ts
new file mode 100644
index 00000000000..400595c931b
--- /dev/null
+++ b/packages/scesim-editor/src/store/ComputedStateCache.ts
@@ -0,0 +1,96 @@
+/*
+ * 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 extends (...args: any[]) => any ? ReturnType : T;
+
+export type CacheEntry = {
+ value: TypeOrReturnType | undefined;
+ dependencies: readonly any[];
+};
+
+export type Cache = {
+ [K in keyof T]: CacheEntry;
+};
+
+let r: number = 0;
+
+export class ComputedStateCache> {
+ private readonly cache: Cache;
+
+ constructor(initialValues: Cache) {
+ this.cache = { ...initialValues };
+ }
+
+ public cached(
+ key: K,
+ delegate: (...dependencies: D) => TypeOrReturnType,
+ dependencies: D
+ ): TypeOrReturnType {
+ 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;
+ }
+ }
+ }
+
+ if (depsAreEqual) {
+ return this.cache[key].value!;
+ }
+
+ const v = delegate(...dependencies);
+ this.cache[key].dependencies = dependencies;
+ this.cache[key].value = v;
+ return v;
+ }
+
+ public cachedData(
+ key: K,
+ delegate: (...data: Y) => TypeOrReturnType,
+ data: Y,
+ dependencies: D
+ ): TypeOrReturnType {
+ 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;
+ }
+ }
+ }
+
+ if (depsAreEqual) {
+ return this.cache[key].value!;
+ }
+
+ const v = delegate(...data);
+ this.cache[key].dependencies = dependencies;
+ this.cache[key].value = v;
+ return v;
+ }
+}
diff --git a/packages/scesim-editor/src/store/TestScenarioEditorStore.ts b/packages/scesim-editor/src/store/TestScenarioEditorStore.ts
new file mode 100644
index 00000000000..7be9d3f10ec
--- /dev/null
+++ b/packages/scesim-editor/src/store/TestScenarioEditorStore.ts
@@ -0,0 +1,164 @@
+/*
+ * 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 { SceSimModel } from "@kie-tools/scesim-marshaller";
+import { enableMapSet } from "immer";
+import { create } from "zustand";
+import { immer } from "zustand/middleware/immer";
+
+import { SceSim__FactMappingType } from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+
+import { ComputedStateCache } from "./ComputedStateCache";
+import { computeTestScenarioDataObjects } from "./computed/computeTestScenarioDataObjects";
+
+enableMapSet(); // Necessary because `Computed` has a lot of Maps and Sets.
+
+export enum TestScenarioEditorDock {
+ CHEATSHEET,
+ DATA_OBJECT,
+ SETTINGS,
+}
+
+export enum TestScenarioEditorTab {
+ BACKGROUND,
+ SIMULATION,
+}
+
+export type TestScenarioAlert = {
+ enabled: boolean;
+ message?: string;
+ variant: "success" | "danger" | "warning" | "info" | "default";
+};
+
+export type TestScenarioDataObject = {
+ id: string;
+ children?: TestScenarioDataObject[];
+ customBadgeContent?: string;
+ isSimpleTypeFact?: boolean;
+ name: string;
+};
+
+export type TestScenarioSelectedColumnMetaData = {
+ factMapping: SceSim__FactMappingType;
+ index: number;
+ isBackground: boolean;
+};
+
+export interface State {
+ computed: (s: State) => Computed;
+ dispatch: (s: State) => Dispatch;
+ navigation: {
+ dock: {
+ isOpen: boolean;
+ selected: TestScenarioEditorDock;
+ };
+ tab: TestScenarioEditorTab;
+ };
+ scesim: { model: SceSimModel };
+ table: {
+ background: {
+ selectedColumn: TestScenarioSelectedColumnMetaData | null;
+ };
+ simulation: {
+ selectedColumn: TestScenarioSelectedColumnMetaData | null;
+ };
+ };
+}
+
+// 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 = {
+ getTestScenarioDataObjects(): TestScenarioDataObject[];
+};
+
+export type Dispatch = {
+ scesim: {
+ reset: () => void;
+ };
+ table: {
+ updateSelectedColumn: (columnMetadata: TestScenarioSelectedColumnMetaData | null) => void;
+ };
+};
+
+export const defaultStaticState = (): Omit => ({
+ navigation: {
+ dock: {
+ isOpen: true,
+ selected: TestScenarioEditorDock.DATA_OBJECT,
+ },
+ tab: TestScenarioEditorTab.SIMULATION,
+ },
+ table: {
+ background: {
+ selectedColumn: null,
+ },
+ simulation: {
+ selectedColumn: null,
+ },
+ },
+});
+
+export function createTestScenarioEditorStore(model: SceSimModel, computedCache: ComputedStateCache) {
+ console.trace("[TestScenarioEditorStore] Creating store with above model and empty cache ");
+ console.trace(model);
+
+ const { ...defaultState } = defaultStaticState();
+ return create(
+ immer(() => ({
+ ...defaultState,
+ scesim: {
+ model: model,
+ },
+ dispatch(state: State) {
+ return {
+ scesim: {
+ reset: () => {
+ state.navigation.tab = TestScenarioEditorTab.SIMULATION;
+ state.navigation.dock.isOpen = true;
+ state.navigation.dock.selected = TestScenarioEditorDock.DATA_OBJECT;
+ state.table.background.selectedColumn = null;
+ state.table.simulation.selectedColumn = null;
+ },
+ },
+ table: {
+ updateSelectedColumn: (columnMetadata: TestScenarioSelectedColumnMetaData) => {
+ if (state.navigation.tab === TestScenarioEditorTab.BACKGROUND) {
+ state.table.background.selectedColumn = columnMetadata;
+ } else {
+ state.table.simulation.selectedColumn = columnMetadata;
+ }
+ },
+ },
+ };
+ },
+ computed(state: State) {
+ return {
+ getTestScenarioDataObjects: () => {
+ return computedCache.cachedData(
+ "getTestScenarioDataObjects",
+ computeTestScenarioDataObjects,
+ [state.scesim.model.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping],
+ [state.scesim.model.ScenarioSimulationModel.settings.type]
+ );
+ },
+ };
+ },
+ }))
+ );
+}
diff --git a/packages/scesim-editor/src/store/TestScenarioStoreContext.ts b/packages/scesim-editor/src/store/TestScenarioStoreContext.ts
new file mode 100644
index 00000000000..f910fc424dc
--- /dev/null
+++ b/packages/scesim-editor/src/store/TestScenarioStoreContext.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 "./TestScenarioEditorStore";
+
+type ExtractState = StoreApi extends { getState: () => infer T } ? T : never;
+
+export type StoreApiType = UseBoundStore>>;
+
+export const TestScenarioEditorStoreApiContext = createContext({} as any);
+
+export function useTestScenarioEditorStore(
+ selector: (state: State) => StateSlice,
+ equalityFn?: (a: StateSlice, b: StateSlice) => boolean
+) {
+ const store = useContext(TestScenarioEditorStoreApiContext);
+
+ if (store === null) {
+ throw new Error("Can't use Test Scenario Editor Store outside of the TestScenarioEditor component.");
+ }
+
+ return useStoreWithEqualityFn(store, selector, equalityFn);
+}
+
+export function useTestScenarioEditorStoreApi() {
+ return useContext(TestScenarioEditorStoreApiContext);
+}
diff --git a/packages/scesim-editor/src/store/computed/computeTestScenarioDataObjects.ts b/packages/scesim-editor/src/store/computed/computeTestScenarioDataObjects.ts
new file mode 100644
index 00000000000..228f4b1fbe8
--- /dev/null
+++ b/packages/scesim-editor/src/store/computed/computeTestScenarioDataObjects.ts
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Computed, State, TestScenarioDataObject } from "../TestScenarioEditorStore";
+
+export function computeTestScenarioDataObjects(
+ factMappings: State["scesim"]["model"]["ScenarioSimulationModel"]["simulation"]["scesimModelDescriptor"]["factMappings"]["FactMapping"]
+) {
+ /* To create the Data Object arrays we need an external source, in details: */
+ /* DMN Data: Retrieving DMN type from linked DMN file */
+ /* Java classes: Retrieving Java classes info from the user projects */
+ /* At this time, none of the above are supported */
+ /* Therefore, it tries to retrieve these info from the SCESIM file, if are present */
+
+ /* Retriving Data Object from the scesim file.
+ That makes sense for previously created scesim files */
+
+ const factsMappings = factMappings ?? [];
+ const dataObjects: TestScenarioDataObject[] = [];
+
+ /* The first two FactMapping are related to the "Number" and "Description" columns.
+ If those columns only are present, no Data Objects can be detected in the scesim file */
+ for (let i = 2; i < factsMappings.length; i++) {
+ if (factsMappings[i].className!.__$$text === "java.lang.Void") {
+ continue;
+ }
+ const factID = factsMappings[i].expressionElements!.ExpressionElement![0].step.__$$text;
+ const dataObject = dataObjects.find((value) => value.id === factID);
+ const isSimpleTypeFact = factsMappings[i].expressionElements!.ExpressionElement!.length === 1;
+ const propertyID = isSimpleTypeFact //POTENTIAL BUG
+ ? factsMappings[i].expressionElements!.ExpressionElement![0].step.__$$text.concat(".")
+ : factsMappings[i]
+ .expressionElements!.ExpressionElement!.map((expressionElement) => expressionElement.step.__$$text)
+ .join(".");
+ const propertyName = isSimpleTypeFact
+ ? "value"
+ : factsMappings[i].expressionElements!.ExpressionElement!.slice(-1)[0].step.__$$text;
+ if (dataObject) {
+ if (!dataObject.children?.some((value) => value.id === propertyID)) {
+ dataObject.children!.push({
+ id: propertyID,
+ customBadgeContent: factsMappings[i].className.__$$text,
+ isSimpleTypeFact: isSimpleTypeFact,
+ name: propertyName,
+ });
+ }
+ } else {
+ dataObjects.push({
+ id: factID,
+ name: factsMappings[i].factAlias!.__$$text,
+ customBadgeContent: factsMappings[i].factIdentifier!.className!.__$$text,
+ children: [
+ {
+ id: propertyID,
+ name: propertyName,
+ customBadgeContent: factsMappings[i].className.__$$text,
+ },
+ ],
+ });
+ }
+ }
+
+ return dataObjects;
+}
diff --git a/packages/scesim-editor/src/common/TestScenarioCommonConstants.ts b/packages/scesim-editor/src/store/computed/initial.ts
similarity index 76%
rename from packages/scesim-editor/src/common/TestScenarioCommonConstants.ts
rename to packages/scesim-editor/src/store/computed/initial.ts
index 55edecff712..ce228895c2a 100644
--- a/packages/scesim-editor/src/common/TestScenarioCommonConstants.ts
+++ b/packages/scesim-editor/src/store/computed/initial.ts
@@ -17,9 +17,12 @@
* under the License.
*/
-export const EMPTY_TYPE = "java.lang.Void";
+import { Cache } from "../ComputedStateCache";
+import { Computed } from "../TestScenarioEditorStore";
-export enum TEST_SCENARIO_EXPRESSION_TYPE {
- EXPRESSION,
- NOT_EXPRESSION,
-}
+export const INITIAL_COMPUTED_CACHE: Cache = {
+ getTestScenarioDataObjects: {
+ value: undefined,
+ dependencies: [],
+ },
+};
diff --git a/packages/scesim-editor/src/table/TestScenarioTable.tsx b/packages/scesim-editor/src/table/TestScenarioTable.tsx
index 32ec8ae704d..14a83ff5289 100644
--- a/packages/scesim-editor/src/table/TestScenarioTable.tsx
+++ b/packages/scesim-editor/src/table/TestScenarioTable.tsx
@@ -21,17 +21,7 @@ import * as React from "react";
import { useCallback, useMemo } from "react";
import * as ReactTable from "react-table";
-import _, { isNumber } from "lodash";
-import { v4 as uuid } from "uuid";
-
-import {
- SceSim__backgroundDatasType,
- SceSim__backgroundType,
- SceSim__FactMappingType,
- SceSim__FactMappingValuesTypes,
- SceSim__scenariosType,
- SceSim__simulationType,
-} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+import _ from "lodash";
import {
BeeTableContextMenuAllowedOperationsConditions,
@@ -47,30 +37,32 @@ import {
getColumnsAtLastLevel,
} from "@kie-tools/boxed-expression-component/dist/table/BeeTable";
-import { SceSimModel } from "@kie-tools/scesim-marshaller";
+import {
+ SceSim__backgroundDatasType,
+ SceSim__backgroundType,
+ SceSim__FactMappingType,
+ SceSim__scenariosType,
+ SceSim__simulationType,
+} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
import { useTestScenarioEditorI18n } from "../i18n";
-import { TestScenarioSelectedColumnMetaData, TestScenarioType } from "../TestScenarioEditor";
+import { useTestScenarioEditorStore, useTestScenarioEditorStoreApi } from "../store/TestScenarioStoreContext";
+import { addColumn } from "../mutations/addColumn";
+import { deleteColumn } from "../mutations/deleteColumn";
import "./TestScenarioTable.css";
-import {
- retrieveFactMappingValueIndexByIdentifiers,
- retrieveModelDescriptor,
- retrieveRowsDataFromModel,
-} from "../common/TestScenarioCommonFunctions";
+import { addRow } from "../mutations/addRow";
+import { deleteRow } from "../mutations/deleteRow";
+import { dupliacteRow } from "../mutations/duplicateRow";
+import { updateCell } from "../mutations/updateCell";
+import { updateColumnWidth } from "../mutations/updateColumnWidth";
function TestScenarioTable({
- assetType,
tableData,
scrollableParentRef,
- updateSelectedColumnMetaData,
- updateTestScenarioModel,
}: {
- assetType: string;
tableData: SceSim__simulationType | SceSim__backgroundType;
scrollableParentRef: React.RefObject;
- updateSelectedColumnMetaData: React.Dispatch>;
- updateTestScenarioModel: React.Dispatch>;
}) {
enum TestScenarioTableColumnHeaderGroup {
EXPECT = "expect-header",
@@ -89,6 +81,9 @@ function TestScenarioTable({
type ROWTYPE = any; // FIXME: https://github.com/apache/incubator-kie-issues/issues/169
const { i18n } = useTestScenarioEditorI18n();
+ const testScenarioEditorStoreApi = useTestScenarioEditorStoreApi();
+ const settingsModel = useTestScenarioEditorStore((state) => state.scesim.model.ScenarioSimulationModel.settings);
+ const testScenarioType = settingsModel.type?.__$$text.toUpperCase();
/** BACKGROUND TABLE MANAGMENT */
@@ -119,71 +114,33 @@ function TestScenarioTable({
const determineDataTypeLabel = useCallback(
(dataType: string) => {
let dataTypeLabel = dataType;
- if (assetType === TestScenarioType[TestScenarioType.RULE]) {
+ if (testScenarioType === "RULE") {
dataTypeLabel = dataTypeLabel.split(".").pop() ?? dataTypeLabel;
}
return dataTypeLabel.endsWith("Void") ? "" : dataTypeLabel;
},
- [assetType]
+ [testScenarioType]
);
/* It updates any column width change in the Model */
const setColumnWidth = useCallback(
(inputIndex: number) => (newWidthAction: React.SetStateAction) => {
- updateTestScenarioModel((prevState) => {
- const oldWidth = retrieveModelDescriptor(prevState.ScenarioSimulationModel, isBackground).factMappings
- .FactMapping![inputIndex].columnWidth?.__$$text;
+ testScenarioEditorStoreApi.setState((state) => {
+ const factMappings = isBackground
+ ? state.scesim.model.ScenarioSimulationModel.background.scesimModelDescriptor.factMappings.FactMapping!
+ : state.scesim.model.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping!;
+ const oldWidth = factMappings[inputIndex].columnWidth?.__$$text;
const newWidth = typeof newWidthAction === "function" ? newWidthAction(oldWidth) : newWidthAction;
- let model = prevState;
- if (newWidth && oldWidth !== newWidth) {
- /* Cloning the FactMapping list and updating the new width */
- const deepClonedFactMappings: SceSim__FactMappingType[] = JSON.parse(
- JSON.stringify(
- retrieveModelDescriptor(prevState.ScenarioSimulationModel, isBackground).factMappings.FactMapping
- )
- );
- const factMappingToUpdate = deepClonedFactMappings[inputIndex];
-
- if (factMappingToUpdate.columnWidth?.__$$text) {
- factMappingToUpdate.columnWidth.__$$text = newWidth;
- } else {
- factMappingToUpdate.columnWidth = {
- __$$text: newWidth,
- };
- }
-
- model = {
- ScenarioSimulationModel: {
- ...prevState.ScenarioSimulationModel,
- simulation: {
- ...prevState.ScenarioSimulationModel.simulation,
- scesimModelDescriptor: {
- factMappings: {
- FactMapping: isBackground
- ? prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping
- : deepClonedFactMappings,
- },
- },
- },
- background: {
- ...prevState.ScenarioSimulationModel.background,
- scesimModelDescriptor: {
- factMappings: {
- FactMapping: isBackground
- ? deepClonedFactMappings
- : prevState.ScenarioSimulationModel.background.scesimModelDescriptor.factMappings.FactMapping,
- },
- },
- },
- },
- };
- }
-
- return model;
+ updateColumnWidth({
+ factMappings: factMappings,
+ columnIndex: inputIndex,
+ newWidth: newWidth,
+ oldWidth: oldWidth,
+ });
});
},
- [isBackground, updateTestScenarioModel]
+ [isBackground, testScenarioEditorStoreApi]
);
/* It determines the column data based on the given FactMapping (Scesim column representation).
@@ -244,7 +201,7 @@ function TestScenarioTable({
| | +--------------------------------+-----+----------------------------------+-----+
| # | | givenInstance (given-instance) | ... | expectGroup (expect-instance) | ... |
| | +----------------+---------------+-----+----------------------------------+-----+
- | | | field (given) | field (given)| ... | field (expect) | field (expect)| ... |
+ | | | field (given) | field (given) | ... | field (expect) | field (expect)| ... |
+---+---------------+----------------+---------------+-----+-----------------+----------------+-----+
Every section has its related groupType in the rounded brackets, that are crucial to determine
the correct context menu behavior (adding/removing an instance requires a different logic than
@@ -507,140 +464,25 @@ function TestScenarioTable({
const onCellUpdates = useCallback(
(cellUpdates: BeeTableCellUpdate[]) => {
cellUpdates.forEach((update) => {
- updateTestScenarioModel((prevState) => {
- /* To update the related FactMappingValue, it compares every FactMappingValue associated with the Scenario (Row)
- that contains the cell with the FactMapping (Column) fields factIdentifier and expressionIdentifier */
- const factMapping = retrieveModelDescriptor(prevState.ScenarioSimulationModel, isBackground).factMappings
- .FactMapping![update.columnIndex + columnIndexStart];
-
- const deepClonedRowsData: SceSim__FactMappingValuesTypes[] = JSON.parse(
- JSON.stringify(retrieveRowsDataFromModel(prevState.ScenarioSimulationModel, isBackground))
- );
- const factMappingValues = deepClonedRowsData[update.rowIndex].factMappingValues.FactMappingValue!;
- const newFactMappingValues = [...factMappingValues];
-
- const factMappingValueToUpdateIndex = retrieveFactMappingValueIndexByIdentifiers(
- newFactMappingValues,
- factMapping.factIdentifier,
- factMapping.expressionIdentifier
- );
- const factMappingValueToUpdate = factMappingValues[factMappingValueToUpdateIndex];
-
- if (factMappingValueToUpdate.rawValue) {
- factMappingValueToUpdate.rawValue!.__$$text = update.value;
- } else {
- newFactMappingValues[factMappingValueToUpdateIndex] = {
- ...factMappingValueToUpdate,
- rawValue: {
- __$$text: update.value,
- },
- };
- }
-
- deepClonedRowsData[update.rowIndex].factMappingValues.FactMappingValue = newFactMappingValues;
-
- return {
- ScenarioSimulationModel: {
- ...prevState.ScenarioSimulationModel,
- simulation: {
- ...prevState.ScenarioSimulationModel.simulation,
- scesimData: {
- Scenario: isBackground
- ? prevState.ScenarioSimulationModel.simulation.scesimData.Scenario
- : deepClonedRowsData,
- },
- },
- background: {
- ...prevState.ScenarioSimulationModel.background,
- scesimData: {
- BackgroundData: isBackground
- ? deepClonedRowsData
- : prevState.ScenarioSimulationModel.background.scesimData.BackgroundData,
- },
- },
- },
- };
+ testScenarioEditorStoreApi.setState((state) => {
+ const factMappings = isBackground
+ ? state.scesim.model.ScenarioSimulationModel.background.scesimModelDescriptor.factMappings.FactMapping!
+ : state.scesim.model.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping!;
+ const factMappingValuesTypes = isBackground
+ ? state.scesim.model.ScenarioSimulationModel.background.scesimData.BackgroundData!
+ : state.scesim.model.ScenarioSimulationModel.simulation.scesimData.Scenario!;
+
+ updateCell({
+ columnIndex: update.columnIndex + columnIndexStart,
+ factMappings: factMappings,
+ factMappingValuesTypes: factMappingValuesTypes,
+ rowIndex: update.rowIndex,
+ value: update.value,
+ });
});
});
},
- [columnIndexStart, isBackground, updateTestScenarioModel]
- );
-
- const getNextAvailablePrefixedName = useCallback(
- (names: string[], namePrefix: string, lastIndex: number = names.length): string => {
- const candidate = `${namePrefix}-${lastIndex + 1}`;
- const elemWithCandidateName = names.indexOf(candidate);
- return elemWithCandidateName >= 0 ? getNextAvailablePrefixedName(names, namePrefix, lastIndex + 1) : candidate;
- },
- []
- );
-
- /* It determines in which index position a column should be added. In case of a field, the new column index
- is simply in the right or in the left of the selected column. In case of a new instance, it's required to
- find the first column index outside the selected Instance group. */
- const determineNewColumnTargetIndex = useCallback(
- (
- factMappings: SceSim__FactMappingType[],
- insertDirection: InsertRowColumnsDirection,
- selectedColumnIndex: number,
- selectedColumnGroupType: string,
- selectedFactMapping: SceSim__FactMappingType
- ) => {
- const groupType = selectedFactMapping.expressionIdentifier.type!.__$$text;
- const instanceName = selectedFactMapping.factIdentifier.name!.__$$text;
- const instanceType = selectedFactMapping.factIdentifier.className!.__$$text;
-
- if (
- selectedColumnGroupType === TestScenarioTableColumnFieldGroup.EXPECT ||
- selectedColumnGroupType === TestScenarioTableColumnFieldGroup.GIVEN
- ) {
- if (insertDirection === InsertRowColumnsDirection.AboveOrRight) {
- return selectedColumnIndex + 1;
- } else {
- return selectedColumnIndex;
- }
- }
-
- let newColumnTargetColumn = -1;
-
- if (insertDirection === InsertRowColumnsDirection.AboveOrRight) {
- for (let i = selectedColumnIndex; i < factMappings.length; i++) {
- const currentFM = factMappings[i];
- if (
- currentFM.expressionIdentifier.type!.__$$text === groupType &&
- currentFM.factIdentifier.name?.__$$text === instanceName &&
- currentFM.factIdentifier.className?.__$$text === instanceType
- ) {
- if (i == factMappings.length - 1) {
- newColumnTargetColumn = i + 1;
- }
- } else {
- newColumnTargetColumn = i;
- break;
- }
- }
- } else {
- for (let i = selectedColumnIndex; i >= 0; i--) {
- const currentFM = factMappings[i];
-
- if (
- currentFM.expressionIdentifier.type!.__$$text === groupType &&
- currentFM.factIdentifier.name?.__$$text === instanceName &&
- currentFM.factIdentifier.className?.__$$text === instanceType
- ) {
- if (i == 0) {
- newColumnTargetColumn = 0;
- }
- } else {
- newColumnTargetColumn = i + 1;
- break;
- }
- }
- }
-
- return newColumnTargetColumn;
- },
- [TestScenarioTableColumnFieldGroup]
+ [columnIndexStart, isBackground, testScenarioEditorStoreApi]
);
/**
@@ -687,143 +529,48 @@ function TestScenarioTable({
columnsCount: number;
insertDirection: InsertRowColumnsDirection;
}) => {
- /* GIVEN and EXPECTED column types can be added only */
- if (TestScenarioTableColumnFieldGroup.OTHER === args.groupType) {
+ /* GIVEN and EXPECTED of FIELD and INSTANCE column types can be added only */
+ if (
+ TestScenarioTableColumnFieldGroup.OTHER === args.groupType ||
+ TestScenarioTableColumnHeaderGroup.EXPECT === args.groupType ||
+ TestScenarioTableColumnHeaderGroup.GIVEN === args.groupType
+ ) {
+ console.error("Can't add a " + args.groupType + " type column.");
return;
}
const isInstance =
args.groupType === TestScenarioTableColumnInstanceGroup.EXPECT ||
args.groupType === TestScenarioTableColumnInstanceGroup.GIVEN;
- updateTestScenarioModel((prevState) => {
- const factMappingList = retrieveModelDescriptor(prevState.ScenarioSimulationModel, isBackground).factMappings
- .FactMapping!;
- const selectedColumnIndex = determineSelectedColumnIndex(factMappingList, args.currentIndex, isInstance);
-
- /* Creating the new FactMapping based on the original selected column's FactMapping */
- const selectedColumnFactMapping = factMappingList[selectedColumnIndex];
- const targetColumnIndex = determineNewColumnTargetIndex(
- factMappingList,
- args.insertDirection,
- selectedColumnIndex,
- args.groupType,
- selectedColumnFactMapping
- );
-
- const instanceDefaultNames = factMappingList
- .filter((factMapping) => factMapping.factAlias!.__$$text.startsWith("INSTANCE-"))
- .map((factMapping) => factMapping.factAlias!.__$$text);
-
- const isNewInstance =
- isInstance || selectedColumnFactMapping.factIdentifier.className?.__$$text === "java.lang.Void";
-
- const newFactMapping = {
- className: { __$$text: "java.lang.Void" },
- columnWidth: { __$$text: 150 },
- expressionAlias: { __$$text: "PROPERTY" },
- expressionElements: isNewInstance
- ? undefined
- : {
- ExpressionElement: [
- {
- step: {
- __$$text: selectedColumnFactMapping.expressionElements!.ExpressionElement![0].step.__$$text,
- },
- },
- ],
- },
- expressionIdentifier: {
- name: { __$$text: `_${uuid()}`.toLocaleUpperCase() },
- type: { __$$text: selectedColumnFactMapping.expressionIdentifier.type!.__$$text },
- },
- factAlias: {
- __$$text: isNewInstance
- ? getNextAvailablePrefixedName(instanceDefaultNames, "INSTANCE")
- : selectedColumnFactMapping.factAlias.__$$text,
- },
- factIdentifier: {
- name: {
- __$$text: isNewInstance
- ? getNextAvailablePrefixedName(instanceDefaultNames, "INSTANCE")
- : selectedColumnFactMapping.factIdentifier.name!.__$$text,
- },
- className: {
- __$$text: isNewInstance ? "java.lang.Void" : selectedColumnFactMapping.factIdentifier.className!.__$$text,
- },
- },
- factMappingValueType: { __$$text: "NOT_EXPRESSION" },
- };
-
- /* Cloning the FactMapping list and putting the new one in the user defined index */
- const deepClonedFactMappings = JSON.parse(
- JSON.stringify(
- retrieveModelDescriptor(prevState.ScenarioSimulationModel, isBackground).factMappings.FactMapping
- )
+ testScenarioEditorStoreApi.setState((state) => {
+ const factMappings = isBackground
+ ? state.scesim.model.ScenarioSimulationModel.background.scesimModelDescriptor.factMappings.FactMapping!
+ : state.scesim.model.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping!;
+ const factMappingValues = isBackground
+ ? state.scesim.model.ScenarioSimulationModel.background.scesimData.BackgroundData!
+ : state.scesim.model.ScenarioSimulationModel.simulation.scesimData.Scenario!;
+ const selectedColumnFactMappingIndex = determineSelectedColumnIndex(
+ factMappings,
+ args.currentIndex,
+ isInstance
);
- deepClonedFactMappings.splice(targetColumnIndex, 0, newFactMapping);
- /* Creating and adding a new FactMappingValue (cell) in every row, as a consequence of the new FactMapping (column)
- we're going to introduce. The FactMappingValue will be linked with its related FactMapping via expressionIdentifier
- and factIdentier data. That means, the column index of new FactMappingValue could be different in other Scenario (rows) */
- const deepClonedRowsData: SceSim__FactMappingValuesTypes[] = JSON.parse(
- JSON.stringify(retrieveRowsDataFromModel(prevState.ScenarioSimulationModel, isBackground))
- );
- deepClonedRowsData.forEach((scenario) => {
- scenario.factMappingValues.FactMappingValue!.splice(args.beforeIndex + 1, 0, {
- expressionIdentifier: {
- name: { __$$text: newFactMapping.expressionIdentifier.name.__$$text },
- type: { __$$text: newFactMapping.expressionIdentifier.type.__$$text },
- },
- factIdentifier: {
- name: { __$$text: newFactMapping.factIdentifier.name.__$$text },
- className: { __$$text: newFactMapping.factIdentifier.className.__$$text },
- },
- rawValue: { __$$text: "", "@_class": "string" },
- });
+ addColumn({
+ beforeIndex: args.beforeIndex,
+ factMappings: factMappings,
+ factMappingValues: factMappingValues,
+ isInstance: isInstance,
+ insertDirection: args.insertDirection,
+ selectedColumnFactMappingIndex: selectedColumnFactMappingIndex,
});
-
- return {
- ScenarioSimulationModel: {
- ...prevState.ScenarioSimulationModel,
- simulation: {
- scesimModelDescriptor: {
- factMappings: {
- FactMapping: isBackground
- ? prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping
- : deepClonedFactMappings,
- },
- },
- scesimData: {
- Scenario: isBackground
- ? prevState.ScenarioSimulationModel.simulation.scesimData.Scenario
- : deepClonedRowsData,
- },
- },
- background: {
- scesimModelDescriptor: {
- factMappings: {
- FactMapping: isBackground
- ? deepClonedFactMappings
- : prevState.ScenarioSimulationModel.background.scesimModelDescriptor.factMappings.FactMapping,
- },
- },
- scesimData: {
- BackgroundData: isBackground
- ? deepClonedRowsData
- : prevState.ScenarioSimulationModel.background.scesimData.BackgroundData,
- },
- },
- },
- };
});
},
[
- determineNewColumnTargetIndex,
determineSelectedColumnIndex,
- getNextAvailablePrefixedName,
isBackground,
- updateTestScenarioModel,
+ testScenarioEditorStoreApi,
TestScenarioTableColumnFieldGroup,
+ TestScenarioTableColumnHeaderGroup,
TestScenarioTableColumnInstanceGroup,
]
);
@@ -833,127 +580,54 @@ function TestScenarioTable({
*/
const onColumnDeleted = useCallback(
(args: { columnIndex: number; groupType: string }) => {
- updateTestScenarioModel((prevState) => {
- const isInstance =
- args.groupType === TestScenarioTableColumnInstanceGroup.EXPECT ||
- args.groupType === TestScenarioTableColumnInstanceGroup.GIVEN;
-
- const factMappings = retrieveModelDescriptor(prevState.ScenarioSimulationModel, isBackground).factMappings
- .FactMapping!;
- const columnIndexToRemove = determineSelectedColumnIndex(factMappings, args.columnIndex + 1, isInstance);
-
- /* Retriving the FactMapping (Column) to be removed). If the user selected a single column, it finds the exact
- FactMapping to delete. If the user selected an instance (group of columns), it retrives all the FactMappings
- that belongs to the the instance group */
- const factMappingToRemove = factMappings[columnIndexToRemove];
- const groupType = factMappingToRemove.expressionIdentifier.type!.__$$text;
- const instanceName = factMappingToRemove.factIdentifier.name!.__$$text;
- const instanceType = factMappingToRemove.factIdentifier.className!.__$$text;
-
- const allFactMappingWithIndexesToRemove = isInstance
- ? factMappings
- .map((factMapping, index) => {
- if (
- factMapping.expressionIdentifier.type!.__$$text === groupType &&
- factMapping.factIdentifier.name?.__$$text === instanceName &&
- factMapping.factIdentifier.className?.__$$text === instanceType
- ) {
- return { factMappingIndex: index, factMapping: factMapping };
- } else {
- return {};
- }
- })
- .filter((item) => isNumber(item.factMappingIndex))
- : [{ factMappingIndex: args.columnIndex + columnIndexStart, factMapping: factMappingToRemove }];
-
- /* Cloning the FactMappings list (Columns) and and removing the FactMapping (Column) at given index */
- const deepClonedFactMappings = JSON.parse(
- JSON.stringify(
- retrieveModelDescriptor(prevState.ScenarioSimulationModel, isBackground).factMappings.FactMapping
- )
- );
- deepClonedFactMappings.splice(
- allFactMappingWithIndexesToRemove[0].factMappingIndex,
- allFactMappingWithIndexesToRemove.length
- );
-
- /* Cloning the Scenario List (Rows) and finding the Cell(s) to remove accordingly to the factMapping data of
- the removed columns */
- const deepClonedRowsData: SceSim__FactMappingValuesTypes[] = JSON.parse(
- JSON.stringify(retrieveRowsDataFromModel(prevState.ScenarioSimulationModel, isBackground) ?? [])
- );
- deepClonedRowsData.forEach((rowData) => {
- allFactMappingWithIndexesToRemove.forEach((itemToRemove) => {
- const factMappingValueColumnIndexToRemove = retrieveFactMappingValueIndexByIdentifiers(
- rowData.factMappingValues.FactMappingValue!,
- itemToRemove.factMapping!.factIdentifier,
- itemToRemove.factMapping!.expressionIdentifier
- )!;
-
- return {
- factMappingValues: {
- FactMappingValue: rowData.factMappingValues.FactMappingValue!.splice(
- factMappingValueColumnIndexToRemove,
- 1
- ),
- },
- };
- });
+ /* GIVEN and EXPECTED of FIELD and INSTANCE column types can be deleted only */
+ if (
+ TestScenarioTableColumnFieldGroup.OTHER === args.groupType ||
+ TestScenarioTableColumnHeaderGroup.EXPECT === args.groupType ||
+ TestScenarioTableColumnHeaderGroup.GIVEN === args.groupType
+ ) {
+ console.error("Can't delete a " + args.groupType + " type column.");
+ return;
+ }
+ const isInstance =
+ args.groupType === TestScenarioTableColumnInstanceGroup.EXPECT ||
+ args.groupType === TestScenarioTableColumnInstanceGroup.GIVEN;
+ testScenarioEditorStoreApi.setState((state) => {
+ const factMappings = isBackground
+ ? state.scesim.model.ScenarioSimulationModel.background.scesimModelDescriptor.factMappings.FactMapping!
+ : state.scesim.model.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping!;
+ const factMappingValues = isBackground
+ ? state.scesim.model.ScenarioSimulationModel.background.scesimData.BackgroundData!
+ : state.scesim.model.ScenarioSimulationModel.simulation.scesimData.Scenario!;
+ const factMappingIndexToRemove = determineSelectedColumnIndex(factMappings, args.columnIndex + 1, isInstance);
+
+ const { deletedFactMappingIndexs } = deleteColumn({
+ factMappingIndexToRemove: factMappingIndexToRemove,
+ factMappings: factMappings,
+ factMappingValues: factMappingValues,
+ isBackground: isBackground,
+ isInstance: isInstance,
+ selectedColumnIndex: args.columnIndex,
});
/** Updating the selectedColumn. When deleting, BEETable automatically shifts the selected cell in the left */
- const firstIndexOnTheLeft = Math.min(
- ...allFactMappingWithIndexesToRemove.map((item) => item.factMappingIndex!)
- );
+ const firstIndexOnTheLeft = Math.min(...deletedFactMappingIndexs);
const selectedColumnIndex = firstIndexOnTheLeft > 0 ? firstIndexOnTheLeft - 1 : 0;
- updateSelectedColumnMetaData({
- factMapping: JSON.parse(JSON.stringify(deepClonedFactMappings[selectedColumnIndex])),
+
+ state.dispatch(state).table.updateSelectedColumn({
+ factMapping: JSON.parse(JSON.stringify(factMappings[selectedColumnIndex])),
index: firstIndexOnTheLeft,
- isBackground,
+ isBackground: isBackground,
});
-
- return {
- ScenarioSimulationModel: {
- ...prevState.ScenarioSimulationModel,
- simulation: {
- scesimModelDescriptor: {
- factMappings: {
- FactMapping: isBackground
- ? prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping
- : deepClonedFactMappings,
- },
- },
- scesimData: {
- Scenario: isBackground
- ? prevState.ScenarioSimulationModel.simulation.scesimData.Scenario
- : deepClonedRowsData,
- },
- },
- background: {
- scesimModelDescriptor: {
- factMappings: {
- FactMapping: isBackground
- ? deepClonedFactMappings
- : prevState.ScenarioSimulationModel.background.scesimModelDescriptor.factMappings.FactMapping,
- },
- },
- scesimData: {
- BackgroundData: isBackground
- ? deepClonedRowsData
- : prevState.ScenarioSimulationModel.background.scesimData.BackgroundData,
- },
- },
- },
- };
});
},
[
- updateTestScenarioModel,
- TestScenarioTableColumnInstanceGroup,
- isBackground,
determineSelectedColumnIndex,
- columnIndexStart,
- updateSelectedColumnMetaData,
+ isBackground,
+ testScenarioEditorStoreApi,
+ TestScenarioTableColumnFieldGroup,
+ TestScenarioTableColumnHeaderGroup,
+ TestScenarioTableColumnInstanceGroup,
]
);
@@ -965,50 +639,15 @@ function TestScenarioTable({
if (isBackground) {
throw new Error("Impossible state. Background table can have a single row only");
}
- updateTestScenarioModel((prevState) => {
- /* Creating a new Scenario (Row) composed by a list of FactMappingValues. The list order is not relevant. */
+ testScenarioEditorStoreApi.setState((state) => {
const factMappings =
- prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping ?? [];
- const factMappingValuesItems = factMappings.map((factMapping) => {
- return {
- expressionIdentifier: {
- name: { __$$text: factMapping.expressionIdentifier.name!.__$$text },
- type: { __$$text: factMapping.expressionIdentifier.type!.__$$text },
- },
- factIdentifier: {
- name: { __$$text: factMapping.factIdentifier.name!.__$$text },
- className: { __$$text: factMapping.factIdentifier.className!.__$$text },
- },
- rawValue: { __$$text: "", "@_class": "string" },
- };
- });
+ state.scesim.model.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping!;
+ const factMappingValues = state.scesim.model.ScenarioSimulationModel.simulation.scesimData.Scenario!;
- const newScenario = {
- factMappingValues: {
- FactMappingValue: factMappingValuesItems,
- },
- };
-
- /* Cloning che current Scenario List and adding thew new Scenario previously created */
- const deepClonedScenarios = JSON.parse(
- JSON.stringify(prevState.ScenarioSimulationModel.simulation.scesimData.Scenario)
- );
- deepClonedScenarios.splice(args.beforeIndex, 0, newScenario);
-
- return {
- ScenarioSimulationModel: {
- ...prevState.ScenarioSimulationModel,
- simulation: {
- ...prevState.ScenarioSimulationModel.simulation,
- scesimData: {
- Scenario: deepClonedScenarios,
- },
- },
- },
- };
+ addRow({ beforeIndex: args.beforeIndex, factMappings: factMappings, factMappingValues: factMappingValues });
});
},
- [isBackground, updateTestScenarioModel]
+ [isBackground, testScenarioEditorStoreApi]
);
/**
@@ -1019,28 +658,13 @@ function TestScenarioTable({
if (isBackground) {
throw new Error("Impossible state. Background table can have a single row only");
}
- updateTestScenarioModel((prevState) => {
- /* Just updating the Scenario List (Rows) cloning the current List and removing the row at the given rowIndex */
- const deepClonedScenarios = JSON.parse(
- JSON.stringify(prevState.ScenarioSimulationModel.simulation.scesimData.Scenario ?? [])
- );
- deepClonedScenarios.splice(args.rowIndex, 1);
-
- return {
- ScenarioSimulationModel: {
- ...prevState.ScenarioSimulationModel,
- simulation: {
- ...prevState.ScenarioSimulationModel.simulation,
- scesimData: {
- ...prevState.ScenarioSimulationModel.simulation.scesimData,
- Scenario: deepClonedScenarios,
- },
- },
- },
- };
+ testScenarioEditorStoreApi.setState((state) => {
+ const factMappingValues = state.scesim.model.ScenarioSimulationModel.simulation.scesimData.Scenario!;
+
+ deleteRow({ rowIndex: args.rowIndex, factMappingValues: factMappingValues });
});
},
- [isBackground, updateTestScenarioModel]
+ [isBackground, testScenarioEditorStoreApi]
);
/**
@@ -1051,41 +675,13 @@ function TestScenarioTable({
if (isBackground) {
throw new Error("Impossible state. Background table can have a single row only");
}
- updateTestScenarioModel((prevState) => {
- /* It simply clones a Scenario (Row) and adds it in a current-cloned Scenario list */
- const clonedFactMappingValues = JSON.parse(
- JSON.stringify(
- prevState.ScenarioSimulationModel.simulation.scesimData.Scenario![args.rowIndex].factMappingValues
- .FactMappingValue
- )
- );
+ testScenarioEditorStoreApi.setState((state) => {
+ const factMappingValues = state.scesim.model.ScenarioSimulationModel.simulation.scesimData.Scenario!;
- const factMappingValues = {
- factMappingValues: {
- FactMappingValue: clonedFactMappingValues,
- },
- };
-
- const deepClonedScenarios = JSON.parse(
- JSON.stringify(prevState.ScenarioSimulationModel.simulation.scesimData.Scenario ?? [])
- );
- deepClonedScenarios.splice(args.rowIndex, 0, factMappingValues);
-
- return {
- ScenarioSimulationModel: {
- ...prevState.ScenarioSimulationModel,
- simulation: {
- ...prevState.ScenarioSimulationModel.simulation,
- scesimData: {
- ...prevState.ScenarioSimulationModel.simulation.scesimData,
- Scenario: deepClonedScenarios,
- },
- },
- },
- };
+ dupliacteRow({ rowIndex: args.rowIndex, factMappingValues: factMappingValues });
});
},
- [isBackground, updateTestScenarioModel]
+ [isBackground, testScenarioEditorStoreApi]
);
/**
@@ -1093,9 +689,11 @@ function TestScenarioTable({
*/
const onDataCellClick = useCallback(
(_columnID: string) => {
- updateSelectedColumnMetaData(null);
+ testScenarioEditorStoreApi.setState((state) => {
+ state.dispatch(state).table.updateSelectedColumn(null);
+ });
},
- [updateSelectedColumnMetaData]
+ [testScenarioEditorStoreApi]
);
const onHeaderClick = useCallback(
@@ -1105,7 +703,9 @@ function TestScenarioTable({
columnKey == TestScenarioTableColumnHeaderGroup.EXPECT ||
columnKey == TestScenarioTableColumnHeaderGroup.GIVEN
) {
- updateSelectedColumnMetaData(null);
+ testScenarioEditorStoreApi.setState((state) => {
+ state.dispatch(state).table.updateSelectedColumn(null);
+ });
return;
}
@@ -1123,25 +723,23 @@ function TestScenarioTable({
selectedInstanceGroup?.columns[0].dataType === ""
) {
const propertyID = selectedInstanceGroup?.columns[0].id;
- let selectedFactMapping;
- let selectedFactIndex;
- if (propertyID) {
- selectedFactMapping = modelDescriptor.factMappings.FactMapping!.find(
- (factMapping) => factMapping.expressionIdentifier.name?.__$$text === propertyID
- );
- selectedFactIndex = selectedFactMapping
- ? modelDescriptor.factMappings.FactMapping!.indexOf(selectedFactMapping!)
- : -1;
- }
- const selectedColumnMetaData = {
- factMapping: JSON.parse(JSON.stringify(selectedFactMapping)),
- index: selectedFactIndex ?? -1,
- isBackground: isBackground,
- };
-
- updateSelectedColumnMetaData(selectedColumnMetaData);
+ const selectedFactMapping = modelDescriptor.factMappings.FactMapping!.find(
+ (factMapping) => factMapping.expressionIdentifier.name?.__$$text === propertyID
+ );
+ const selectedFactIndex = selectedFactMapping
+ ? modelDescriptor.factMappings.FactMapping!.indexOf(selectedFactMapping!)
+ : -1;
+ testScenarioEditorStoreApi.setState((state) => {
+ state.dispatch(state).table.updateSelectedColumn({
+ factMapping: JSON.parse(JSON.stringify(selectedFactMapping)),
+ index: selectedFactIndex ?? -1,
+ isBackground: isBackground,
+ });
+ });
} else {
- updateSelectedColumnMetaData(null);
+ testScenarioEditorStoreApi.setState((state) => {
+ state.dispatch(state).table.updateSelectedColumn(null);
+ });
}
return;
}
@@ -1153,13 +751,13 @@ function TestScenarioTable({
? modelDescriptor.factMappings.FactMapping!.indexOf(selectedFactMapping!)
: -1;
- const selectedColumnMetaData = {
- factMapping: JSON.parse(JSON.stringify(selectedFactMapping)),
- index: selectedFactIndex ?? -1,
- isBackground: isBackground,
- };
-
- updateSelectedColumnMetaData(selectedColumnMetaData ?? null);
+ testScenarioEditorStoreApi.setState((state) => {
+ state.dispatch(state).table.updateSelectedColumn({
+ factMapping: JSON.parse(JSON.stringify(selectedFactMapping)),
+ index: selectedFactIndex ?? -1,
+ isBackground: isBackground,
+ });
+ });
},
[
TestScenarioTableColumnFieldGroup,
@@ -1167,7 +765,7 @@ function TestScenarioTable({
isBackground,
tableColumns.instancesGroup,
tableData,
- updateSelectedColumnMetaData,
+ testScenarioEditorStoreApi,
]
);
diff --git a/packages/scesim-editor/stories/dev/DevWebApp.stories.tsx b/packages/scesim-editor/stories/dev/DevWebApp.stories.tsx
index 9d17767d2bf..b9d91f5a091 100644
--- a/packages/scesim-editor/stories/dev/DevWebApp.stories.tsx
+++ b/packages/scesim-editor/stories/dev/DevWebApp.stories.tsx
@@ -17,26 +17,22 @@
* under the License.
*/
-import React, { useCallback, useRef, useState, useEffect } from "react";
+import React, { useCallback, useRef, useState } from "react";
import type { Meta, StoryObj } from "@storybook/react";
-import { SceSimEditorWrapper, SceSimEditorWrapperProps } from "../scesimEditorStoriesWrapper";
-import { Button, Flex, FlexItem, Page, PageSection } from "@patternfly/react-core/dist/js";
-import { TestScenarioEditorRef } from "../../src/TestScenarioEditor";
-import { SceSimMarshaller } from "../../../scesim-marshaller/src/index";
-import { SceSimModel, getMarshaller } from "@kie-tools/scesim-marshaller";
+import "@patternfly/react-core/dist/styles/base.css";
+import { Button } from "@patternfly/react-core/dist/js/components/Button";
+import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
+import { Page, PageSection } from "@patternfly/react-core/dist/js/components/Page";
+import { Stack, StackItem } from "@patternfly/react-core/dist/js";
+import { SceSimMarshaller, SceSimModel, getMarshaller } from "@kie-tools/scesim-marshaller";
+import { OnSceSimModelChange, TestScenarioEditorProps } from "../../src/TestScenarioEditor";
+import { SceSimEditorWrapper } from "../scesimEditorStoriesWrapper";
import { emptySceSim } from "../misc/empty/Empty.stories";
import { isOldEnoughDrl } from "../useCases/IsOldEnoughRule.stories";
import { trafficViolationDmn } from "../useCases/TrafficViolationDmn.stories";
-import { useArgs } from "@storybook/preview-api";
-
import "./DevWebApp.css";
-type DevWebAppProps = SceSimEditorWrapperProps;
-
-function DevWebApp(props: DevWebAppProps) {
- const ref = useRef(null);
- const [args, updateArgs] = useArgs();
-
+function DevWebApp(args: TestScenarioEditorProps) {
const [state, setState] = useState<{ marshaller: SceSimMarshaller; stack: SceSimModel[]; pointer: number }>(() => {
const emptySceSimMarshaller = getMarshaller(emptySceSim);
return {
@@ -46,38 +42,68 @@ function DevWebApp(props: DevWebAppProps) {
};
});
- const onSelectModel = useCallback((newModel) => {
- const model = getMarshaller(newModel).parser.parse();
- setState((prev) => {
- const newStack = prev.stack.slice(0, prev.pointer + 1);
- return {
- ...prev,
- stack: [...newStack, model],
- pointer: newStack.length,
- };
- });
+ const currentModel = state.stack[state.pointer];
+ const downloadRef = useRef(null);
+ const isUndoEnabled = state.pointer > 0;
+ const isRedoEnabled = state.pointer !== state.stack.length - 1;
+
+ const copyAsXml = useCallback(() => {
+ navigator.clipboard.writeText(state.marshaller.builder.build(currentModel));
+ }, [currentModel, state.marshaller.builder]);
+
+ const downloadAsXml = useCallback(() => {
+ if (downloadRef.current) {
+ const fileBlob = new Blob([state.marshaller.builder.build(currentModel)], { type: "text/xml" });
+ downloadRef.current.download = `scesim-test-${makeid(10)}.scesim`;
+ downloadRef.current.href = URL.createObjectURL(fileBlob);
+ downloadRef.current.click();
+ }
+ }, [currentModel, state.marshaller.builder]);
+
+ const onDragOver = useCallback((e: React.DragEvent) => {
+ e.preventDefault(); // Necessary to disable the browser's default 'onDrop' handling.
}, []);
const onDrop = useCallback((e: React.DragEvent) => {
+ console.log("Test Scenario Editor :: Dev webapp :: File(s) dropped! Opening it.");
+
e.preventDefault(); // Necessary to disable the browser's default 'onDrop' handling.
if (e.dataTransfer.items) {
// Use DataTransferItemList interface to access the file(s)
[...e.dataTransfer.items].forEach((item, i) => {
if (item.kind === "file") {
- const fileName = item.getAsFile()?.name;
const reader = new FileReader();
- reader.addEventListener("load", ({ target }) =>
- ref.current?.setContent(fileName ?? "", target?.result as string)
- );
+ reader.addEventListener("load", ({ target }) => {
+ const marshaller = getMarshaller(target?.result as string);
+ setState({ marshaller, stack: [marshaller.parser.parse()], pointer: 0 });
+ });
reader.readAsText(item.getAsFile() as any);
}
});
}
}, []);
- const onDragOver = useCallback((e: React.DragEvent) => {
- e.preventDefault(); // Necessary to disable the browser's default 'onDrop' handling.
+ const onModelChange = useCallback((model) => {
+ setState((prev) => {
+ const newStack = prev.stack.slice(0, prev.pointer + 1);
+ return {
+ ...prev,
+ stack: [...newStack, model],
+ pointer: newStack.length,
+ };
+ });
+ }, []);
+
+ const onSelectModel = useCallback(
+ (newModel) => {
+ onModelChange(getMarshaller(newModel).parser.parse());
+ },
+ [onModelChange]
+ );
+
+ const redo = useCallback(() => {
+ setState((prev) => ({ ...prev, pointer: Math.min(prev.stack.length - 1, prev.pointer + 1) }));
}, []);
const reset = useCallback(() => {
@@ -89,40 +115,27 @@ function DevWebApp(props: DevWebAppProps) {
});
}, []);
- const currentModel = state.stack[state.pointer];
-
- const downloadRef = useRef(null);
- const downloadAsXml = useCallback(() => {
- if (downloadRef.current) {
- const fileBlob = new Blob([state.marshaller.builder.build(currentModel)], { type: "text/xml" });
- downloadRef.current.download = `scesim-${makeid(10)}.scesim`;
- downloadRef.current.href = URL.createObjectURL(fileBlob);
- downloadRef.current.click();
- }
- }, [currentModel, state.marshaller.builder]);
-
- const copyAsXml = useCallback(() => {
- navigator.clipboard.writeText(state.marshaller.builder.build(currentModel));
- }, [currentModel, state.marshaller.builder]);
+ const undo = useCallback(() => {
+ setState((prev) => ({ ...prev, pointer: Math.max(0, prev.pointer - 1) }));
+ }, []);
- useEffect(() => {
- updateArgs({ content: state.marshaller.builder.build(state.stack[state.stack.length - 1]) });
- }, [state.marshaller.builder, state.stack, updateArgs]);
+ /* TODO: DMN DATA Retieve
+ const externalModelsByNamespace = useMemo(() => {
+ return (currentModel.definitions.import ?? []).reduce((acc, i) => {
+ acc[i["@_namespace"]] = modelsByNamespace[i["@_namespace"]];
+ return acc;
+ }, {} as ExternalModelsIndex);
+ }, [currentModel.definitions.import]);
- useEffect(() => {
- onSelectModel(args.content);
- }, [args.content, onSelectModel]);
+ const onRequestExternalModelByPath = useCallback(async (path) => {
+ return availableModelsByPath[path] ?? null;
+ }, []);*/
return (
- <>
-
-
-
+
+
+
+
Test Scenario Editor :: Dev WebApp
@@ -130,6 +143,10 @@ function DevWebApp(props: DevWebAppProps) {
(Drag & drop a file anywhere to open it)
+
+
+
+
@@ -137,31 +154,56 @@ function DevWebApp(props: DevWebAppProps) {
|
-
+
+
+
+ |
+
-
+
-
+
-
-
-
-
- {SceSimEditorWrapper({
- pathRelativeToTheWorkspaceRoot: "dev.scesim",
- content: state.marshaller.builder.build(state.stack[state.stack.length - 1]),
- })}
-
-
-
- >
+
+
+
+
+
+
+ {SceSimEditorWrapper({
+ issueTrackerHref: args.issueTrackerHref,
+ model: currentModel,
+ onModelChange: onModelChange,
+ })}
+
+
);
}
@@ -177,18 +219,18 @@ function makeid(length: number) {
return result;
}
-const meta: Meta = {
+const meta: Meta = {
title: "Dev/Web App",
component: DevWebApp,
};
export default meta;
-type Story = StoryObj;
+type Story = StoryObj;
export const WebApp: Story = {
render: (args) => DevWebApp(args),
args: {
- pathRelativeToTheWorkspaceRoot: "dev.scesim",
- content: emptySceSim,
+ issueTrackerHref: "https://github.com/apache/incubator-kie-issues/issues/new",
+ model: getMarshaller(emptySceSim).parser.parse(),
},
};
diff --git a/packages/scesim-editor/stories/examples/AvailableDMNModels.ts b/packages/scesim-editor/stories/examples/AvailableDMNModels.ts
index 315e2451ebc..4d7722fa228 100644
--- a/packages/scesim-editor/stories/examples/AvailableDMNModels.ts
+++ b/packages/scesim-editor/stories/examples/AvailableDMNModels.ts
@@ -47,12 +47,3 @@ export const avaiableModels: {
// },
// {} as Record
// );
-
-// export const modelsByNamespace = Object.values(avaiableModels).reduce((acc, v) => {
-// if (v.type === "dmn") {
-// acc[v.model.definitions["@_namespace"]] = v;
-// } else if (v.type === "pmml") {
-// acc[getPmmlNamespace({ normalizedPosixPathRelativeToTheOpenFile: v.normalizedPosixPathRelativeToTheOpenFile })] = v;
-// }
-// return acc;
-// }, {} as DmnEditor.ExternalModelsIndex);
diff --git a/packages/scesim-editor/stories/misc/empty/Empty.stories.tsx b/packages/scesim-editor/stories/misc/empty/Empty.stories.tsx
index af7a17fc235..dc538bb058e 100644
--- a/packages/scesim-editor/stories/misc/empty/Empty.stories.tsx
+++ b/packages/scesim-editor/stories/misc/empty/Empty.stories.tsx
@@ -18,11 +18,12 @@
*/
import type { Meta, StoryObj } from "@storybook/react";
-import { SceSimEditorWrapper, SceSimEditorWrapperProps } from "../../scesimEditorStoriesWrapper";
+import { getMarshaller } from "@kie-tools/scesim-marshaller";
import { TestScenarioEditor } from "../../../src/TestScenarioEditor";
+import { SceSimEditorWrapper, StorybookTestScenarioEditorProps } from "../../scesimEditorStoriesWrapper";
export const emptySceSim = `
-
+
@@ -180,12 +181,15 @@ const meta: Meta<{}> = {
};
export default meta;
-type Story = StoryObj;
+type Story = StoryObj;
+
+const marshaller = getMarshaller(emptySceSim);
+const model = marshaller.parser.parse();
export const Empty: Story = {
render: (args) => SceSimEditorWrapper(args),
args: {
- pathRelativeToTheWorkspaceRoot: "empty.scesim",
- content: emptySceSim,
+ model: marshaller.parser.parse(),
+ xml: marshaller.builder.build(model),
},
};
diff --git a/packages/scesim-editor/stories/scesimEditor/SceSimEditor.mdx b/packages/scesim-editor/stories/scesimEditor/SceSimEditor.mdx
index 33f1a2e32a8..c253f319b3f 100644
--- a/packages/scesim-editor/stories/scesimEditor/SceSimEditor.mdx
+++ b/packages/scesim-editor/stories/scesimEditor/SceSimEditor.mdx
@@ -17,9 +17,9 @@
import { Meta } from "@storybook/blocks";
-
+
-# SceSim Editor
+# Test Scenario Editor
Before deploying them into a production environment, test scenarios enable you to validate the functionality of
- Business rules and business rule data (for rules-based test scenarios)
diff --git a/packages/scesim-editor/stories/scesimEditorStoriesWrapper.tsx b/packages/scesim-editor/stories/scesimEditorStoriesWrapper.tsx
index 656adba6208..7588aa49d41 100644
--- a/packages/scesim-editor/stories/scesimEditorStoriesWrapper.tsx
+++ b/packages/scesim-editor/stories/scesimEditorStoriesWrapper.tsx
@@ -18,25 +18,59 @@
*/
import * as React from "react";
-import { useEffect, useRef } from "react";
-import { TestScenarioEditor, TestScenarioEditorRef } from "../src/TestScenarioEditor";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { useArgs } from "@storybook/preview-api";
+import { diff } from "deep-object-diff";
+import { SceSimModel, getMarshaller } from "@kie-tools/scesim-marshaller";
+import { TestScenarioEditor, TestScenarioEditorProps, TestScenarioEditorRef } from "../src/TestScenarioEditor";
+import { EMPTY_ONE_EIGHT } from "../src/resources/EmptyScesimFile";
-export interface SceSimEditorWrapperProps {
- pathRelativeToTheWorkspaceRoot: string;
- content: string;
-}
+export type StorybookTestScenarioEditorProps = TestScenarioEditorProps & { xml: string };
-export function SceSimEditorWrapper(props: SceSimEditorWrapperProps) {
+export function SceSimEditorWrapper(props: Partial) {
+ const [args, updateArgs] = useArgs();
+ const argsCopy = useRef(args);
const ref = useRef(null);
+ const [modelArgs, setModelArgs] = useState(args.model);
+ const model = useMemo(() => props?.model ?? modelArgs, [modelArgs, props?.model]);
+
+ const onModelChange = useMemo(
+ () => (props?.onModelChange ? props.onModelChange : setModelArgs),
+ [props?.onModelChange]
+ );
useEffect(() => {
- /* Simulating a call from "Foundation" code */
- ref.current?.setContent(props.pathRelativeToTheWorkspaceRoot, props.content);
- }, [ref, props.content, props.pathRelativeToTheWorkspaceRoot]);
+ if (Object.keys(diff(argsCopy.current.model, model)).length !== 0) {
+ updateArgs({
+ ...argsCopy.current,
+ model: model,
+ xml: getMarshaller(EMPTY_ONE_EIGHT).builder.build(model),
+ });
+ }
+ }, [updateArgs, model]);
+
+ useEffect(() => {
+ if (Object.keys(diff(argsCopy.current, args)).length === 0) {
+ return;
+ }
+ argsCopy.current = args;
+ if (Object.keys(diff(args.model, model)).length === 0) {
+ return;
+ }
+ onModelChange(args.model);
+ }, [args, model, onModelChange]);
+
+ const onModelDebounceStateChanged = useCallback(() => {
+ console.debug("[scesimEditorStoriesWrapper] Model Debounce state");
+ }, []);
return (
-
-
-
+
);
}
diff --git a/packages/scesim-editor/stories/useCases/IsOldEnoughRule.stories.tsx b/packages/scesim-editor/stories/useCases/IsOldEnoughRule.stories.tsx
index 86592e1a75d..9f0e102caaf 100644
--- a/packages/scesim-editor/stories/useCases/IsOldEnoughRule.stories.tsx
+++ b/packages/scesim-editor/stories/useCases/IsOldEnoughRule.stories.tsx
@@ -19,8 +19,9 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
+import { getMarshaller } from "@kie-tools/scesim-marshaller";
import { TestScenarioEditor } from "../../src/TestScenarioEditor";
-import { SceSimEditorWrapper, SceSimEditorWrapperProps } from "../scesimEditorStoriesWrapper";
+import { SceSimEditorWrapper, StorybookTestScenarioEditorProps } from "../scesimEditorStoriesWrapper";
export const isOldEnoughDrl = `
@@ -394,12 +395,15 @@ const meta: Meta<{}> = {
};
export default meta;
-type Story = StoryObj;
+type Story = StoryObj;
+
+const marshaller = getMarshaller(isOldEnoughDrl);
+const model = marshaller.parser.parse();
export const IsOldEnough: Story = {
render: (args) => SceSimEditorWrapper(args),
args: {
- pathRelativeToTheWorkspaceRoot: "isOldEnough.scesim",
- content: isOldEnoughDrl,
+ model: marshaller.parser.parse(),
+ xml: marshaller.builder.build(model),
},
};
diff --git a/packages/scesim-editor/stories/useCases/TrafficViolationDmn.stories.tsx b/packages/scesim-editor/stories/useCases/TrafficViolationDmn.stories.tsx
index 031704f4650..19ba0102ca1 100644
--- a/packages/scesim-editor/stories/useCases/TrafficViolationDmn.stories.tsx
+++ b/packages/scesim-editor/stories/useCases/TrafficViolationDmn.stories.tsx
@@ -19,8 +19,9 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
+import { getMarshaller } from "@kie-tools/scesim-marshaller";
import { TestScenarioEditor } from "../../src/TestScenarioEditor";
-import { SceSimEditorWrapper, SceSimEditorWrapperProps } from "../scesimEditorStoriesWrapper";
+import { SceSimEditorWrapper, StorybookTestScenarioEditorProps } from "../scesimEditorStoriesWrapper";
export const trafficViolationDmn = `
@@ -796,12 +797,15 @@ const meta: Meta<{}> = {
};
export default meta;
-type Story = StoryObj;
+type Story = StoryObj;
+
+const marshaller = getMarshaller(trafficViolationDmn);
+const model = marshaller.parser.parse();
export const TrafficViolation: Story = {
render: (args) => SceSimEditorWrapper(args),
args: {
- pathRelativeToTheWorkspaceRoot: "trafficViolation.scesim",
- content: trafficViolationDmn,
+ model: marshaller.parser.parse(),
+ xml: marshaller.builder.build(model),
},
};
diff --git a/packages/scesim-editor/tests-e2e/__screenshots__/Google-Chrome/misc/emptyExpression/create-a-new-test-scenario.png b/packages/scesim-editor/tests-e2e/__screenshots__/Google-Chrome/misc/emptyExpression/create-a-new-test-scenario.png
index 97f6e8b3d07..4334ab5e3a3 100644
Binary files a/packages/scesim-editor/tests-e2e/__screenshots__/Google-Chrome/misc/emptyExpression/create-a-new-test-scenario.png and b/packages/scesim-editor/tests-e2e/__screenshots__/Google-Chrome/misc/emptyExpression/create-a-new-test-scenario.png differ
diff --git a/packages/scesim-editor/tests-e2e/__screenshots__/chromium/misc/emptyExpression/create-a-new-test-scenario.png b/packages/scesim-editor/tests-e2e/__screenshots__/chromium/misc/emptyExpression/create-a-new-test-scenario.png
index e85c3f76dec..7cd45f75364 100644
Binary files a/packages/scesim-editor/tests-e2e/__screenshots__/chromium/misc/emptyExpression/create-a-new-test-scenario.png and b/packages/scesim-editor/tests-e2e/__screenshots__/chromium/misc/emptyExpression/create-a-new-test-scenario.png differ
diff --git a/packages/scesim-editor/tests-e2e/__screenshots__/webkit/misc/emptyExpression/create-a-new-test-scenario.png b/packages/scesim-editor/tests-e2e/__screenshots__/webkit/misc/emptyExpression/create-a-new-test-scenario.png
index 30c67fbe4bf..caa7de3b78b 100644
Binary files a/packages/scesim-editor/tests-e2e/__screenshots__/webkit/misc/emptyExpression/create-a-new-test-scenario.png and b/packages/scesim-editor/tests-e2e/__screenshots__/webkit/misc/emptyExpression/create-a-new-test-scenario.png differ
diff --git a/packages/scesim-marshaller/src/schemas/scesim-1_8/SceSim.xsd b/packages/scesim-marshaller/src/schemas/scesim-1_8/SceSim.xsd
index 6f5ebe95ae7..efa8b3b494e 100644
--- a/packages/scesim-marshaller/src/schemas/scesim-1_8/SceSim.xsd
+++ b/packages/scesim-marshaller/src/schemas/scesim-1_8/SceSim.xsd
@@ -1,3 +1,20 @@
+
+
=17.0.2 <19.0.0'
version: 17.0.2(react@17.0.2)
react-error-boundary:
- specifier: ^4.0.11
- version: 4.0.12(react@17.0.2)
+ specifier: ^4.0.13
+ version: 4.0.13(react@17.0.2)
reactflow:
specifier: ^11.8.3
version: 11.10.1(@types/react@17.0.21)(immer@10.0.3(patch_hash=utu5oov26wz5mjuays57tp3ybu))(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
@@ -9316,6 +9316,9 @@ importers:
'@patternfly/react-styles':
specifier: ^4.92.6
version: 4.92.6
+ immer:
+ specifier: ^10.0.3
+ version: 10.0.3(patch_hash=utu5oov26wz5mjuays57tp3ybu)
lodash:
specifier: ^4.17.21
version: 4.17.21
@@ -9331,6 +9334,9 @@ importers:
uuid:
specifier: ^8.3.2
version: 8.3.2
+ zustand:
+ specifier: ^4.4.2
+ version: 4.4.2(patch_hash=7tws22nsyaxzkdpquvgytzpdve)(@types/react@17.0.21)(immer@10.0.3(patch_hash=utu5oov26wz5mjuays57tp3ybu))(react@17.0.2)
devDependencies:
'@babel/core':
specifier: ^7.16.0
@@ -9404,9 +9410,15 @@ importers:
cross-env:
specifier: ^7.0.3
version: 7.0.3
+ deep-object-diff:
+ specifier: ^1.1.9
+ version: 1.1.9
file-loader:
specifier: ^6.2.0
version: 6.2.0(webpack@5.94.0(webpack-cli@4.10.0))
+ react-error-boundary:
+ specifier: ^4.0.13
+ version: 4.0.13(react@17.0.2)
rimraf:
specifier: ^3.0.2
version: 3.0.2
@@ -27459,8 +27471,8 @@ packages:
peerDependencies:
react: '>=16.13.1'
- react-error-boundary@4.0.12:
- resolution: {integrity: sha512-kJdxdEYlb7CPC1A0SeUY38cHpjuu6UkvzKiAmqmOFL21VRfMhOcWxTCBgLVCO0VEMh9JhFNcVaXlV4/BTpiwOA==}
+ react-error-boundary@4.0.13:
+ resolution: {integrity: sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==}
peerDependencies:
react: '>=16.13.1'
@@ -31007,7 +31019,7 @@ snapshots:
'@babel/core': 7.24.9
'@babel/generator': 7.23.6
'@babel/parser': 7.23.9
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@babel/traverse': 7.23.9
'@babel/types': 7.23.9
babel-preset-fbjs: 3.4.0(@babel/core@7.24.9)
@@ -39419,15 +39431,15 @@ snapshots:
'@radix-ui/number@1.0.1':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/primitive@1.0.1':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-arrow@1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
react: 17.0.2
react-dom: 17.0.2(react@17.0.2)
@@ -39437,7 +39449,7 @@ snapshots:
'@radix-ui/react-collection@1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-compose-refs': 1.0.1(@types/react@17.0.21)(react@17.0.2)
'@radix-ui/react-context': 1.0.1(@types/react@17.0.21)(react@17.0.2)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
@@ -39450,28 +39462,28 @@ snapshots:
'@radix-ui/react-compose-refs@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
react: 17.0.2
optionalDependencies:
'@types/react': 17.0.21
'@radix-ui/react-context@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
react: 17.0.2
optionalDependencies:
'@types/react': 17.0.21
'@radix-ui/react-direction@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
react: 17.0.2
optionalDependencies:
'@types/react': 17.0.21
'@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@17.0.21)(react@17.0.2)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
@@ -39485,14 +39497,14 @@ snapshots:
'@radix-ui/react-focus-guards@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
react: 17.0.2
optionalDependencies:
'@types/react': 17.0.21
'@radix-ui/react-focus-scope@1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-compose-refs': 1.0.1(@types/react@17.0.21)(react@17.0.2)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@17.0.21)(react@17.0.2)
@@ -39504,7 +39516,7 @@ snapshots:
'@radix-ui/react-id@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@17.0.21)(react@17.0.2)
react: 17.0.2
optionalDependencies:
@@ -39512,7 +39524,7 @@ snapshots:
'@radix-ui/react-popper@1.1.2(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@floating-ui/react-dom': 2.0.2(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
'@radix-ui/react-arrow': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
'@radix-ui/react-compose-refs': 1.0.1(@types/react@17.0.21)(react@17.0.2)
@@ -39531,7 +39543,7 @@ snapshots:
'@radix-ui/react-portal@1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
react: 17.0.2
react-dom: 17.0.2(react@17.0.2)
@@ -39541,7 +39553,7 @@ snapshots:
'@radix-ui/react-primitive@1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-slot': 1.0.2(@types/react@17.0.21)(react@17.0.2)
react: 17.0.2
react-dom: 17.0.2(react@17.0.2)
@@ -39551,7 +39563,7 @@ snapshots:
'@radix-ui/react-roving-focus@1.0.4(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-collection': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
'@radix-ui/react-compose-refs': 1.0.1(@types/react@17.0.21)(react@17.0.2)
@@ -39569,7 +39581,7 @@ snapshots:
'@radix-ui/react-select@1.2.2(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/number': 1.0.1
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-collection': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
@@ -39599,7 +39611,7 @@ snapshots:
'@radix-ui/react-separator@1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
react: 17.0.2
react-dom: 17.0.2(react@17.0.2)
@@ -39609,7 +39621,7 @@ snapshots:
'@radix-ui/react-slot@1.0.2(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-compose-refs': 1.0.1(@types/react@17.0.21)(react@17.0.2)
react: 17.0.2
optionalDependencies:
@@ -39617,7 +39629,7 @@ snapshots:
'@radix-ui/react-toggle-group@1.0.4(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-context': 1.0.1(@types/react@17.0.21)(react@17.0.2)
'@radix-ui/react-direction': 1.0.1(@types/react@17.0.21)(react@17.0.2)
@@ -39633,7 +39645,7 @@ snapshots:
'@radix-ui/react-toggle@1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@17.0.21)(react@17.0.2)
@@ -39645,7 +39657,7 @@ snapshots:
'@radix-ui/react-toolbar@1.0.4(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-context': 1.0.1(@types/react@17.0.21)(react@17.0.2)
'@radix-ui/react-direction': 1.0.1(@types/react@17.0.21)(react@17.0.2)
@@ -39661,14 +39673,14 @@ snapshots:
'@radix-ui/react-use-callback-ref@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
react: 17.0.2
optionalDependencies:
'@types/react': 17.0.21
'@radix-ui/react-use-controllable-state@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@17.0.21)(react@17.0.2)
react: 17.0.2
optionalDependencies:
@@ -39676,7 +39688,7 @@ snapshots:
'@radix-ui/react-use-escape-keydown@1.0.3(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@17.0.21)(react@17.0.2)
react: 17.0.2
optionalDependencies:
@@ -39684,21 +39696,21 @@ snapshots:
'@radix-ui/react-use-layout-effect@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
react: 17.0.2
optionalDependencies:
'@types/react': 17.0.21
'@radix-ui/react-use-previous@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
react: 17.0.2
optionalDependencies:
'@types/react': 17.0.21
'@radix-ui/react-use-rect@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/rect': 1.0.1
react: 17.0.2
optionalDependencies:
@@ -39706,7 +39718,7 @@ snapshots:
'@radix-ui/react-use-size@1.0.1(@types/react@17.0.21)(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@17.0.21)(react@17.0.2)
react: 17.0.2
optionalDependencies:
@@ -39714,7 +39726,7 @@ snapshots:
'@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.8)(@types/react@17.0.21)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
react: 17.0.2
react-dom: 17.0.2(react@17.0.2)
@@ -39724,7 +39736,7 @@ snapshots:
'@radix-ui/rect@1.0.1':
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
'@reactflow/background@11.3.6(@types/react@17.0.21)(immer@10.0.3(patch_hash=utu5oov26wz5mjuays57tp3ybu))(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
@@ -44411,7 +44423,7 @@ snapshots:
babel-plugin-macros@2.8.0:
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
cosmiconfig: 6.0.0
resolve: 1.22.8
@@ -46692,7 +46704,7 @@ snapshots:
date-fns@2.30.0:
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
date-format@4.0.3: {}
@@ -47038,7 +47050,7 @@ snapshots:
dom-helpers@5.2.0:
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
csstype: 3.0.11
dom-serialize@2.2.1:
@@ -49075,7 +49087,7 @@ snapshots:
history@5.3.0:
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
hmac-drbg@1.0.1:
dependencies:
@@ -53915,7 +53927,7 @@ snapshots:
dependencies:
'@babel/core': 7.24.9
'@babel/generator': 7.23.6
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
ast-types: 0.14.2
commander: 2.20.3
doctrine: 3.0.0
@@ -53988,9 +54000,9 @@ snapshots:
'@babel/runtime': 7.23.6
react: 17.0.2
- react-error-boundary@4.0.12(react@17.0.2):
+ react-error-boundary@4.0.13(react@17.0.2):
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
react: 17.0.2
react-fast-compare@2.0.4: {}
@@ -54445,11 +54457,11 @@ snapshots:
regenerator-transform@0.15.1:
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
regenerator-transform@0.15.2:
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
regex-not@1.0.2:
dependencies:
@@ -54493,7 +54505,7 @@ snapshots:
relay-runtime@12.0.0(encoding@0.1.13):
dependencies:
- '@babel/runtime': 7.23.6
+ '@babel/runtime': 7.24.7
fbjs: 3.0.2(encoding@0.1.13)
invariant: 2.2.4
transitivePeerDependencies: