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

tiagobento pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git


The following commit(s) were added to refs/heads/main by this push:
     new eee40f92865  kie-issues#629: Test Scenario Editor: BeeTable 
Integration (#2075)
eee40f92865 is described below

commit eee40f928654f213b4aab88c92b0de573829b2ce
Author: Yeser Amer <[email protected]>
AuthorDate: Tue Dec 19 13:26:44 2023 +0100

     kie-issues#629: Test Scenario Editor: BeeTable Integration (#2075)
---
 .gitignore                                         |    1 +
 .../boxed-expression-component/src/api/BeeTable.ts |    2 +-
 .../src/table/BeeTable/BeeTable.tsx                |    2 +-
 .../table/BeeTable/BeeTableContextMenuHandler.tsx  |    8 +-
 .../src/table/BeeTable/BeeTableTh.tsx              |    8 +-
 .../scesim-editor/dev-webapp/webpack.config.js     |    2 +-
 packages/scesim-editor/package.json                |   10 +-
 packages/scesim-editor/src/@types/react-tables.ts  |   67 ++
 packages/scesim-editor/src/TestScenarioEditor.css  |    4 +
 packages/scesim-editor/src/TestScenarioEditor.tsx  |   24 +-
 .../drawer/TestScenarioDrawerDataObjectsPanel.tsx  |    4 +-
 .../src/drawer/TestScenarioDrawerSettingsPanel.tsx |   10 +-
 .../src/i18n/TestScenarioEditorI18n.ts             |   26 +-
 packages/scesim-editor/src/i18n/index.ts           |    2 +-
 packages/scesim-editor/src/i18n/locales/en.ts      |   28 +-
 .../scesim-editor/src/resources/EmptyScesimFile.ts |  139 ++-
 .../scesim-editor/src/table/TestScenarioTable.css  |   47 +
 .../scesim-editor/src/table/TestScenarioTable.tsx  | 1000 ++++++++++++++++++++
 .../src/schemas/scesim-1_8/SceSim.xsd              |    2 +-
 pnpm-lock.yaml                                     |   26 +-
 repo/graph.dot                                     |    4 +-
 repo/graph.json                                    |    4 +-
 22 files changed, 1338 insertions(+), 82 deletions(-)

diff --git a/.gitignore b/.gitignore
index 9c8c57d6d6c..24a344a6244 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
 **/node_modules/
 **/dist/
 **/dist-dev/
+**/dist-dev-webapp/
 **/dist-tests/
 **/dist-e2e-tests/
 **/dist-storybook/
diff --git a/packages/boxed-expression-component/src/api/BeeTable.ts 
b/packages/boxed-expression-component/src/api/BeeTable.ts
index 0bc0b961749..4be05fd9692 100644
--- a/packages/boxed-expression-component/src/api/BeeTable.ts
+++ b/packages/boxed-expression-component/src/api/BeeTable.ts
@@ -77,7 +77,7 @@ export interface BeeTableProps<R extends object> {
   onRowDuplicated?: (args: { rowIndex: number }) => void;
   onRowReset?: (args: { rowIndex: number }) => void;
   onRowDeleted?: (args: { rowIndex: number }) => void;
-  onColumnAdded?: (args: { beforeIndex: number; groupType: string | undefined 
}) => void;
+  onColumnAdded?: (args: { beforeIndex: number; currentIndex?: number; 
groupType: string | undefined }) => void;
   onColumnDeleted?: (args: { columnIndex: number; groupType: string | 
undefined }) => void;
   shouldRenderRowIndexColumn: boolean;
   shouldShowRowsInlineControls: boolean;
diff --git 
a/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx 
b/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx
index edad910346d..44c61f389e9 100644
--- a/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx
+++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTable.tsx
@@ -536,7 +536,7 @@ export function BeeTableInternal<R extends object>({
   );
 
   const onColumnAdded2 = useCallback(
-    (args: { beforeIndex: number; groupType: string }) => {
+    (args: { beforeIndex: number; currentIndex: number; groupType: string }) 
=> {
       if (onColumnAdded) {
         onColumnAdded(args);
         adaptSelection({
diff --git 
a/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx
 
b/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx
index 19f00255c1e..5c58fffa17f 100644
--- 
a/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx
+++ 
b/packages/boxed-expression-component/src/table/BeeTable/BeeTableContextMenuHandler.tsx
@@ -62,7 +62,7 @@ export interface BeeTableContextMenuHandlerProps {
   onRowDuplicated?: (args: { rowIndex: number }) => void;
   onRowReset?: (args: { rowIndex: number }) => void;
   onRowDeleted?: (args: { rowIndex: number }) => void;
-  onColumnAdded?: (args: { beforeIndex: number; groupType: string | undefined 
}) => void;
+  onColumnAdded?: (args: { beforeIndex: number; currentIndex: number; 
groupType: string | undefined }) => void;
   onColumnDeleted?: (args: { columnIndex: number; groupType: string | 
undefined }) => void;
 }
 
@@ -306,6 +306,7 @@ export function BeeTableContextMenuHandler({
         case BeeTableOperation.ColumnInsertLeft:
           onColumnAdded?.({
             beforeIndex: columnIndex - 1,
+            currentIndex: columnIndex,
             groupType: column?.groupType,
           });
           console.debug(`Insert column left to ${columnIndex}`);
@@ -313,6 +314,7 @@ export function BeeTableContextMenuHandler({
         case BeeTableOperation.ColumnInsertRight:
           onColumnAdded?.({
             beforeIndex: columnIndex,
+            currentIndex: columnIndex,
             groupType: column?.groupType,
           });
           console.debug(`Insert column right to ${columnIndex}`);
@@ -588,7 +590,7 @@ export function BeeTableContextMenuHandler({
               onClick={(e) => e.stopPropagation()}
               drilldownMenu={createDrillDownMenu(group, operation.type)}
             >
-              {operationLabel(operation.type)}
+              {operation.name ? operation.name : 
operationLabel(operation.type)}
             </MenuItem>
           ) : (
             <MenuItem
@@ -599,7 +601,7 @@ export function BeeTableContextMenuHandler({
               onClick={() => handleOperation(operation.type)}
               
isDisabled={!allowedOperationsForSelection.includes(operation.type)}
             >
-              {operationLabel(operation.type)}
+              {operation.name ? operation.name : 
operationLabel(operation.type)}
             </MenuItem>
           )
         )}
diff --git 
a/packages/boxed-expression-component/src/table/BeeTable/BeeTableTh.tsx 
b/packages/boxed-expression-component/src/table/BeeTable/BeeTableTh.tsx
index b399f371cf8..a954aa3b96a 100644
--- a/packages/boxed-expression-component/src/table/BeeTable/BeeTableTh.tsx
+++ b/packages/boxed-expression-component/src/table/BeeTable/BeeTableTh.tsx
@@ -31,7 +31,7 @@ import { useBoxedExpressionEditor } from 
"../../expressions/BoxedExpressionEdito
 
 export interface BeeTableThProps<R extends object> {
   groupType: string | undefined;
-  onColumnAdded?: (args: { beforeIndex: number; groupType: string | undefined 
}) => void;
+  onColumnAdded?: (args: { beforeIndex: number; currentIndex: number; 
groupType: string | undefined }) => void;
   className: string;
   thProps: Partial<ReactTable.TableHeaderProps>;
   onClick?: React.MouseEventHandler;
@@ -79,7 +79,11 @@ export function BeeTableTh<R extends object>({
       }
 
       // This index doesn't take into account the rowIndex column, so we 
actually need to subtract 1.
-      onColumnAdded?.({ beforeIndex: hoverInfo.part === "left" ? columnIndex - 
1 : columnIndex, groupType: groupType });
+      onColumnAdded?.({
+        beforeIndex: hoverInfo.part === "left" ? columnIndex - 1 : columnIndex,
+        currentIndex: columnIndex,
+        groupType: groupType,
+      });
 
       if (hoverInfo.part === "left") {
         setHoverInfo({ isHovered: false });
diff --git a/packages/scesim-editor/dev-webapp/webpack.config.js 
b/packages/scesim-editor/dev-webapp/webpack.config.js
index 2b0240186c2..619256f5817 100644
--- a/packages/scesim-editor/dev-webapp/webpack.config.js
+++ b/packages/scesim-editor/dev-webapp/webpack.config.js
@@ -32,7 +32,7 @@ module.exports = (env) =>
       index: path.resolve(__dirname, "./src/index.tsx"),
     },
     output: {
-      path: path.resolve(__dirname, "../dist-dev"),
+      path: path.resolve(__dirname, "../dist-dev-webapp"),
     },
     plugins: [
       new CopyPlugin({
diff --git a/packages/scesim-editor/package.json 
b/packages/scesim-editor/package.json
index 8aa7420c7f0..64f880e351d 100644
--- a/packages/scesim-editor/package.json
+++ b/packages/scesim-editor/package.json
@@ -15,12 +15,16 @@
   "dependencies": {
     "@kie-tools-core/i18n": "workspace:*",
     "@kie-tools-core/patternfly-base": "workspace:*",
+    "@kie-tools/boxed-expression-component": "workspace:*",
     "@kie-tools/i18n-common-dictionary": "workspace:*",
     "@patternfly/react-core": "^4.276.6",
     "@patternfly/react-icons": "^4.93.6",
     "@patternfly/react-styles": "^4.92.6",
+    "lodash": "^4.17.21",
     "react": "^17.0.2",
-    "react-dom": "^17.0.2"
+    "react-dom": "^17.0.2",
+    "react-table": "^7.6.2",
+    "uuid": "^8.3.2"
   },
   "devDependencies": {
     "@babel/core": "^7.16.0",
@@ -31,11 +35,13 @@
     "@kie-tools/root-env": "workspace:*",
     "@kie-tools/scesim-marshaller": "workspace:*",
     "@kie-tools/tsconfig": "workspace:*",
+    "@types/lodash": "^4.14.168",
     "@types/react": "^17.0.6",
     "@types/react-dom": "^17.0.5",
+    "@types/react-table": "^7.0.25",
+    "@types/uuid": "^8.3.0",
     "copy-webpack-plugin": "^11.0.0",
     "file-loader": "^6.2.0",
-    "react-json-view": "^1.21.3",
     "rimraf": "^3.0.2",
     "typescript": "^4.6.2",
     "webpack": "^5.88.2",
diff --git a/packages/scesim-editor/src/@types/react-tables.ts 
b/packages/scesim-editor/src/@types/react-tables.ts
new file mode 100644
index 00000000000..e6b347498e5
--- /dev/null
+++ b/packages/scesim-editor/src/@types/react-tables.ts
@@ -0,0 +1,67 @@
+/*
+ * 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";
+
+// Extending react-table definitions with missing and custom properties
+declare module "react-table" {
+  export interface TableState {
+    columnResizing: {
+      isResizingColumn: boolean;
+      columnWidths: {
+        [columnName: string]: number;
+      };
+    };
+  }
+
+  export interface ColumnInstance<D extends object> {
+    /** Current column is an empty TH element, created by react-table to fill 
a missing header cell element */
+    placeholderOf?: ColumnInstance<D> | undefined;
+
+    columns?: Array<ColumnInstance<D>>;
+  }
+
+  export interface ColumnInterface<D extends object> {
+    /** Used by react-table to hold the original id chosen for the column, 
independently from applied operations */
+    originalId?: string;
+    /** Column identifier */
+    accessor: string;
+    /** Column group type */
+    groupType?: string;
+    /** Column css classes - appended as passed */
+    cssClasses?: string;
+    /** Column label */
+    label: string;
+    /** Custom Element to be rendered in place of the column label */
+    headerCellElement?: JSX.Element;
+    /** It makes this column header inline editable (with double-click) */
+    isInlineEditable?: boolean;
+    /** Column data type */
+    dataType?: string;
+    /** It tells whether column is of type counter or not */
+    isRowIndexColumn: boolean;
+
+    cellDelegate?: (id: string) => React.ReactNode;
+    width?: number;
+    setWidth?: (newWidth: number) => void;
+    isWidthPinned?: boolean;
+    isWidthConstant?: boolean;
+    columns?: Array<Column<D>>;
+  }
+}
diff --git a/packages/scesim-editor/src/TestScenarioEditor.css 
b/packages/scesim-editor/src/TestScenarioEditor.css
index 6f7a3a280e4..194aa0cd70e 100644
--- a/packages/scesim-editor/src/TestScenarioEditor.css
+++ b/packages/scesim-editor/src/TestScenarioEditor.css
@@ -38,3 +38,7 @@
 .kie-scesim-editor--grid-container {
   height: 100%;
 }
+
+.kie-scesim-editor--table-container {
+  overflow-x: auto;
+}
diff --git a/packages/scesim-editor/src/TestScenarioEditor.tsx 
b/packages/scesim-editor/src/TestScenarioEditor.tsx
index 69e69707a07..1376c120dd2 100644
--- a/packages/scesim-editor/src/TestScenarioEditor.tsx
+++ b/packages/scesim-editor/src/TestScenarioEditor.tsx
@@ -26,12 +26,13 @@ import { I18nDictionariesProvider } from 
"@kie-tools-core/i18n/dist/react-compon
 
 import { testScenarioEditorDictionaries, TestScenarioEditorI18nContext, 
testScenarioEditorI18nDefaults } from "./i18n";
 
-import { getMarshaller } from "@kie-tools/scesim-marshaller";
+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 { Alert } from "@patternfly/react-core/dist/js/components/Alert";
 import { Bullseye } from "@patternfly/react-core/dist/js/layouts/Bullseye";
 import { Button } from "@patternfly/react-core/dist/js/components/Button";
 import { Checkbox } from "@patternfly/react-core/dist/js/components/Checkbox";
@@ -52,12 +53,12 @@ import TableIcon from 
"@patternfly/react-icons/dist/esm/icons/table-icon";
 import ErrorBoundary from "./reactExt/ErrorBoundary";
 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 { Alert } from "@patternfly/react-core/dist/js/components/Alert";
 
 /* Constants */
 
@@ -158,10 +159,7 @@ function TestScenarioCreationPanel({
             value={assetType}
             id="asset-type-select"
             name="asset-type-select"
-            onChange={(value: string) => {
-              console.log(assetType);
-              setAssetType(value);
-            }}
+            onChange={(value: string) => setAssetType(value)}
           >
             {assetsOption.map((option, index) => (
               <FormSelectOption isDisabled={option.disabled} key={index} 
value={option.value} label={option.label} />
@@ -234,10 +232,12 @@ function TestScenarioMainPanel({
   fileName,
   scesimModel,
   updateSettingField,
+  updateTestScenarioModel,
 }: {
   fileName: string;
   scesimModel: { ScenarioSimulationModel: SceSim__ScenarioSimulationModelType 
};
   updateSettingField: (field: string, value: string) => void;
+  updateTestScenarioModel: React.Dispatch<React.SetStateAction<SceSimModel>>;
 }) {
   const { i18n } = useTestScenarioEditorI18n();
 
@@ -280,6 +280,9 @@ function TestScenarioMainPanel({
     /* 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 dataObject = dataObjects.find((value) => value.id === 
factsMappings[i]["factAlias"].__$$text);
       if (dataObject) {
         if (!dataObject.children?.some((value) => value.id === 
factsMappings[i]["expressionAlias"]?.__$$text)) {
@@ -378,7 +381,13 @@ function TestScenarioMainPanel({
                       </>
                     }
                   >
-                    <Bullseye>{i18n.tab.scenarioTabTitle}</Bullseye>
+                    <div className="kie-scesim-editor--table-container">
+                      <TestScenarioTable
+                        
assetType={scesimModel.ScenarioSimulationModel.settings.type!.__$$text}
+                        
tableData={scesimModel.ScenarioSimulationModel.simulation}
+                        updateTestScenarioModel={updateTestScenarioModel}
+                      />
+                    </div>
                   </Tab>
                   <Tab
                     eventKey={TestScenarioEditorTab.BACKGROUND}
@@ -568,6 +577,7 @@ const TestScenarioEditorInternal = ({ forwardRef }: { 
forwardRef?: React.Ref<Tes
               <TestScenarioMainPanel
                 fileName={scesimFile.path}
                 scesimModel={scesimModel}
+                updateTestScenarioModel={setScesimModel}
                 updateSettingField={updateSettingsField}
               />
             );
diff --git 
a/packages/scesim-editor/src/drawer/TestScenarioDrawerDataObjectsPanel.tsx 
b/packages/scesim-editor/src/drawer/TestScenarioDrawerDataObjectsPanel.tsx
index 516f9a9b3d6..3be9e957ab0 100644
--- a/packages/scesim-editor/src/drawer/TestScenarioDrawerDataObjectsPanel.tsx
+++ b/packages/scesim-editor/src/drawer/TestScenarioDrawerDataObjectsPanel.tsx
@@ -25,8 +25,8 @@ import { Bullseye } from 
"@patternfly/react-core/dist/js/layouts/Bullseye";
 import { Button } from "@patternfly/react-core/dist/js/components/Button/";
 import { Divider } from "@patternfly/react-core/dist/js/components/Divider/";
 import { EmptyState, EmptyStateBody, EmptyStateIcon } from 
"@patternfly/react-core/dist/js/components/EmptyState";
+import { HelpIcon } from "@patternfly/react-icons/dist/esm/icons/help-icon";
 import { Icon } from "@patternfly/react-core/dist/js/components/Icon";
-import { InfoCircleIcon } from 
"@patternfly/react-icons/dist/esm/icons/info-circle-icon";
 import { Text } from "@patternfly/react-core/dist/js/components/Text";
 import { Title } from "@patternfly/react-core/dist/js/components/Title";
 import { Toolbar } from "@patternfly/react-core/dist/js/components/Toolbar/";
@@ -122,7 +122,7 @@ function TestScenarioDataObjectsPanel({
           }
         >
           <Icon className={"kie-scesim-editor-drawer-data-objects--info-icon"} 
size="sm" status="info">
-            <InfoCircleIcon />
+            <HelpIcon />
           </Icon>
         </Tooltip>
       </Text>
diff --git 
a/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx 
b/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx
index 5e63e9abed9..6e6f421e9a4 100644
--- a/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx
+++ b/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx
@@ -26,8 +26,8 @@ import { Title } from 
"@patternfly/react-core/dist/js/components/Title";
 import { TestScenarioSettings, TestScenarioType } from "../TestScenarioEditor";
 import { useTestScenarioEditorI18n } from "../i18n";
 
+import { HelpIcon } from "@patternfly/react-icons/dist/esm/icons/help-icon";
 import { Icon } from "@patternfly/react-core/dist/esm/components/Icon/Icon";
-import { InfoCircleIcon } from 
"@patternfly/react-icons/dist/esm/icons/info-circle-icon";
 import { Tooltip } from "@patternfly/react-core/dist/esm/components/Tooltip";
 
 import "./TestScenarioDrawerSettingsPanel.css";
@@ -98,7 +98,7 @@ function TestScenarioDrawerSettingsPanel({
             {i18n.drawer.settings.kieSessionRule}
             <Tooltip content={i18n.drawer.settings.kieSessionRuleTooltip}>
               <Icon className={"kie-scesim-editor-drawer-settings--info-icon"} 
size="sm" status="info">
-                <InfoCircleIcon />
+                <HelpIcon />
               </Icon>
             </Tooltip>
           </Title>
@@ -113,7 +113,7 @@ function TestScenarioDrawerSettingsPanel({
             {i18n.drawer.settings.ruleFlowGroup}
             <Tooltip content={i18n.drawer.settings.ruleFlowGroupTooltip}>
               <Icon className={"kie-scesim-editor-drawer-settings--info-icon"} 
size="sm" status="info">
-                <InfoCircleIcon />
+                <HelpIcon />
               </Icon>
             </Tooltip>
           </Title>
@@ -135,7 +135,7 @@ function TestScenarioDrawerSettingsPanel({
             </div>
             <Tooltip 
content={i18n.drawer.settings.statelessSessionRuleTooltip}>
               <Icon className={"kie-scesim-editor-drawer-settings--info-icon"} 
size="sm" status="info">
-                <InfoCircleIcon />
+                <HelpIcon />
               </Icon>
             </Tooltip>
           </div>
@@ -152,7 +152,7 @@ function TestScenarioDrawerSettingsPanel({
         </div>
         <Tooltip content={i18n.drawer.settings.testSkippedTooltip}>
           <Icon className={"kie-scesim-editor-drawer-settings--info-icon"} 
size="sm" status="info">
-            <InfoCircleIcon />
+            <HelpIcon />
           </Icon>
         </Tooltip>
       </div>
diff --git a/packages/scesim-editor/src/i18n/TestScenarioEditorI18n.ts 
b/packages/scesim-editor/src/i18n/TestScenarioEditorI18n.ts
index 18ba32e30db..b087201e137 100644
--- a/packages/scesim-editor/src/i18n/TestScenarioEditorI18n.ts
+++ b/packages/scesim-editor/src/i18n/TestScenarioEditorI18n.ts
@@ -17,8 +17,8 @@
  * under the License.
  */
 
-import { ReferenceDictionary } from "@kie-tools-core/i18n/dist/core";
 import { CommonI18n } from "@kie-tools/i18n-common-dictionary";
+import { ReferenceDictionary } from "@kie-tools-core/i18n/dist/core";
 
 interface TestScenarioEditorDictionary extends ReferenceDictionary {
   alerts: {
@@ -101,6 +101,30 @@ interface TestScenarioEditorDictionary extends 
ReferenceDictionary {
     backgroundTabTitle: string;
     scenarioTabTitle: string;
   };
+  table: {
+    simulation: { singleEntry: string };
+    background: {};
+    copy: string;
+    cut: string;
+    delete: string;
+    duplicate: string;
+    deleteField: string;
+    deleteInstance: string;
+    expect: string;
+    field: string;
+    given: string;
+    insert: string;
+    insertAbove: string;
+    insertBelow: string;
+    insertLeftField: string;
+    insertRightField: string;
+    insertLeftInstance: string;
+    insertRightInstance: string;
+    instance: string;
+    paste: string;
+    reset: string;
+    selection: string;
+  };
 }
 
 export default interface TestScenarioEditorI18n extends 
TestScenarioEditorDictionary, CommonI18n {}
diff --git a/packages/scesim-editor/src/i18n/index.ts 
b/packages/scesim-editor/src/i18n/index.ts
index 45e4a647c46..7aff62e673c 100644
--- a/packages/scesim-editor/src/i18n/index.ts
+++ b/packages/scesim-editor/src/i18n/index.ts
@@ -17,5 +17,5 @@
  * under the License.
  */
 
-export * from "./TestScenarioEditorI18n";
 export * from "./setup";
+export * from "./TestScenarioEditorI18n";
diff --git a/packages/scesim-editor/src/i18n/locales/en.ts 
b/packages/scesim-editor/src/i18n/locales/en.ts
index ca672dd0d99..cf571477d2a 100644
--- a/packages/scesim-editor/src/i18n/locales/en.ts
+++ b/packages/scesim-editor/src/i18n/locales/en.ts
@@ -118,6 +118,32 @@ export const en: TestScenarioEditorI18n = {
   },
   tab: {
     backgroundTabTitle: "Background",
-    scenarioTabTitle: "Test Scenario",
+    scenarioTabTitle: "Scenarios",
+  },
+  table: {
+    simulation: {
+      singleEntry: "Scenario",
+    },
+    background: {},
+    copy: "Copy",
+    cut: "Cut",
+    delete: "Delete",
+    deleteField: "Delete Field",
+    deleteInstance: "Delete Instance",
+    duplicate: "Duplicate",
+    expect: "Expect",
+    field: "Field",
+    given: "Given",
+    insert: "Insert",
+    insertAbove: "Insert Above",
+    insertBelow: "Insert Below",
+    insertLeftField: "Insert Field Left",
+    insertRightField: "Insert Field Right",
+    insertLeftInstance: "Insert Instance Left",
+    insertRightInstance: "Insert Instance Right",
+    instance: "Instance",
+    paste: "Paste",
+    reset: "Reset",
+    selection: "Selection",
   },
 };
diff --git a/packages/scesim-editor/src/resources/EmptyScesimFile.ts 
b/packages/scesim-editor/src/resources/EmptyScesimFile.ts
index f571536f4a2..ef13d8bd36f 100644
--- a/packages/scesim-editor/src/resources/EmptyScesimFile.ts
+++ b/packages/scesim-editor/src/resources/EmptyScesimFile.ts
@@ -49,8 +49,40 @@ export const EMPTY_ONE_EIGHT = `<?xml version="1.0" 
encoding="UTF-8"?>
           </factIdentifier>
           <className>java.lang.String</className>
           <factAlias>Scenario description</factAlias>
+          <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
           <columnWidth>300</columnWidth>
+        </FactMapping>
+        <FactMapping>
+          <expressionElements/>
+          <expressionIdentifier>
+            <name>1|1</name>
+            <type>GIVEN</type>
+          </expressionIdentifier>
+          <factIdentifier>
+            <name>Empty</name>
+            <className>java.lang.Void</className>
+          </factIdentifier>
+          <className>java.lang.Void</className>
+          <factAlias>INSTANCE-1</factAlias>
+          <expressionAlias>PROPERTY</expressionAlias>
+          <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
+          <columnWidth>150</columnWidth>
+        </FactMapping>
+        <FactMapping>
+          <expressionElements/>
+          <expressionIdentifier>
+            <name>1|2</name>
+            <type>EXPECT</type>
+          </expressionIdentifier>
+          <factIdentifier>
+            <name>Empty</name>
+            <className>java.lang.Void</className>
+          </factIdentifier>
+          <className>java.lang.Void</className>
+          <factAlias>INSTANCE-2</factAlias>
+          <expressionAlias>PROPERTY</expressionAlias>
           <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
+          <columnWidth>150</columnWidth>
         </FactMapping>
       </factMappings>
     </scesimModelDescriptor>
@@ -67,52 +99,71 @@ export const EMPTY_ONE_EIGHT = `<?xml version="1.0" 
encoding="UTF-8"?>
               <type>OTHER</type>
             </expressionIdentifier>
           </FactMappingValue>
+          <FactMappingValue>
+            <factIdentifier>
+              <name>Empty</name>
+              <className>java.lang.Void</className>
+            </factIdentifier>
+            <expressionIdentifier>
+              <name>1|1</name>
+              <type>GIVEN</type>
+            </expressionIdentifier>
+          </FactMappingValue>
+          <FactMappingValue>
+            <factIdentifier>
+              <name>Empty</name>
+              <className>java.lang.Void</className>
+            </factIdentifier>
+            <expressionIdentifier>
+              <name>1|2</name>
+              <type>EXPECT</type>
+            </expressionIdentifier>
+          </FactMappingValue>
         </factMappingValues>
       </Scenario>
     </scesimData>
   </simulation>
-      <background>
-        <scesimModelDescriptor>
-          <factMappings>
-            <FactMapping>
-              <expressionElements/>
-              <expressionIdentifier>
-                <name>1|1</name>
-                <type>GIVEN</type>
-              </expressionIdentifier>
-              <factIdentifier>
-                <name>Empty</name>
-                <className>java.lang.Void</className>
-              </factIdentifier>
+  <background>
+    <scesimModelDescriptor>
+      <factMappings>
+        <FactMapping>
+          <expressionElements/>
+          <expressionIdentifier>
+            <name>1|1</name>
+            <type>GIVEN</type>
+          </expressionIdentifier>
+          <factIdentifier>
+            <name>Empty</name>
+            <className>java.lang.Void</className>
+          </factIdentifier>
+          <className>java.lang.Void</className>
+          <factAlias>INSTANCE-1</factAlias>
+          <expressionAlias>PROPERTY</expressionAlias>
+          <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
+        </FactMapping>
+      </factMappings>
+    </scesimModelDescriptor>
+    <scesimData>
+      <BackgroundData>
+        <factMappingValues>
+          <FactMappingValue>
+            <factIdentifier>
+              <name>Empty</name>
               <className>java.lang.Void</className>
-              <factAlias>INSTANCE 1</factAlias>
-              <expressionAlias>PROPERTY 1</expressionAlias>
-              <columnWidth>114</columnWidth>
-              <factMappingValueType>NOT_EXPRESSION</factMappingValueType>
-            </FactMapping>
-          </factMappings>
-        </scesimModelDescriptor>
-        <scesimData>
-          <BackgroundData>
-            <factMappingValues>
-              <FactMappingValue>
-                <factIdentifier>
-                  <name>Empty</name>
-                  <className>java.lang.Void</className>
-                </factIdentifier>
-                <expressionIdentifier>
-                  <name>1|1</name>
-                  <type>GIVEN</type>
-                </expressionIdentifier>
-              </FactMappingValue>
-            </factMappingValues>
-          </BackgroundData>
-        </scesimData>
-      </background>
-      <settings>
-        <skipFromBuild>false</skipFromBuild>
-      </settings>
-      <imports>
-        <imports/>
-      </imports>
-    </ScenarioSimulationModel>`;
+            </factIdentifier>
+            <expressionIdentifier>
+              <name>1|1</name>
+              <type>GIVEN</type>
+            </expressionIdentifier>
+          </FactMappingValue>
+        </factMappingValues>
+      </BackgroundData>
+    </scesimData>
+  </background>
+  <settings>
+    <skipFromBuild>false</skipFromBuild>
+  </settings>
+  <imports>
+    <imports/>
+  </imports>
+</ScenarioSimulationModel>`;
diff --git a/packages/scesim-editor/src/table/TestScenarioTable.css 
b/packages/scesim-editor/src/table/TestScenarioTable.css
new file mode 100644
index 00000000000..1b7110e134e
--- /dev/null
+++ b/packages/scesim-editor/src/table/TestScenarioTable.css
@@ -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. 
+ */
+
+.test-scenario-table .expression-container table thead th.given,
+.test-scenario-table .expression-container thead th.given .add-column-button,
+.test-scenario-table .expression-container table thead th.given-header,
+.test-scenario-table .expression-container table thead th.given-instance {
+  background-color: #def3ff;
+}
+
+.test-scenario-table .expression-container table thead th.expect,
+.test-scenario-table .expression-container table thead th.expect 
.add-column-button,
+.test-scenario-table .expression-container table thead th.expect-header,
+.test-scenario-table .expression-container table thead th.expect-instance {
+  background-color: #bee1f4;
+}
+
+.test-scenario-table .expression-container table thead th.other,
+.test-scenario-table .expression-container table thead th.other 
.add-column-button {
+  background-color: #ffffff;
+}
+
+.test-scenario-table .inline-editable-preview {
+  font-family: Menlo, monospace;
+  font-size: 0.8em;
+  white-space: pre !important;
+}
+
+.test-scenario-table .header-cell-info input[type="text"] {
+  font-size: 0.8em;
+}
diff --git a/packages/scesim-editor/src/table/TestScenarioTable.tsx 
b/packages/scesim-editor/src/table/TestScenarioTable.tsx
new file mode 100644
index 00000000000..a7c0d4a269c
--- /dev/null
+++ b/packages/scesim-editor/src/table/TestScenarioTable.tsx
@@ -0,0 +1,1000 @@
+/*
+ * 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, useMemo, useRef } from "react";
+
+import * as ReactTable from "react-table";
+import _, { isNumber } from "lodash";
+import { v4 as uuid } from "uuid";
+
+import {
+  SceSim__expressionIdentifierType,
+  SceSim__factIdentifierType,
+  SceSim__FactMappingType,
+  SceSim__FactMappingValueType,
+  SceSim__ScenarioType,
+  SceSim__simulationType,
+} from "@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
+
+import {
+  BeeTableContextMenuAllowedOperationsConditions,
+  BeeTableHeaderVisibility,
+  BeeTableOperation,
+  BeeTableOperationConfig,
+} from "@kie-tools/boxed-expression-component/dist/api/BeeTable";
+import { ResizerStopBehavior } from 
"@kie-tools/boxed-expression-component/dist/resizing/ResizingWidthsContext";
+import {
+  BeeTableCellUpdate,
+  StandaloneBeeTable,
+  getColumnsAtLastLevel,
+} from "@kie-tools/boxed-expression-component/dist/table/BeeTable";
+
+import { SceSimModel } from "@kie-tools/scesim-marshaller";
+
+import { useTestScenarioEditorI18n } from "../i18n";
+import { TestScenarioType } from "../TestScenarioEditor";
+
+import "./TestScenarioTable.css";
+
+function TestScenarioTable({
+  assetType,
+  tableData,
+  updateTestScenarioModel,
+}: {
+  assetType: string;
+  tableData: SceSim__simulationType;
+  updateTestScenarioModel: React.Dispatch<React.SetStateAction<SceSimModel>>;
+}) {
+  enum TestScenarioTableColumnHeaderGroup {
+    EXPECT = "expect-header",
+    GIVEN = "given-header",
+  }
+  enum TestScenarioTableColumnInstanceGroup {
+    EXPECT = "expect-instance",
+    GIVEN = "given-instance",
+  }
+  enum TestScenarioTableColumnFieldGroup {
+    EXPECT = "expect",
+    GIVEN = "given",
+    OTHER = "other",
+  }
+
+  type ROWTYPE = any; // FIXME: 
https://github.com/kiegroup/kie-issues/issues/169
+
+  const { i18n } = useTestScenarioEditorI18n();
+
+  const tableScrollableElementRef = useRef<{ current: HTMLDivElement | null 
}>({ current: null });
+
+  useEffect(() => {
+    tableScrollableElementRef.current.current = 
document.querySelector(".kie-scesim-editor--table-container") ?? null;
+  }, []);
+
+  /** TABLE COLUMNS AND ROWS POPULATION */
+
+  /* It determines the Data Type Label based on the given Data Type.
+     In case of RULE Scenario, the Data Type is a FQCN (eg. java.lang.String). 
So, the label will take the class name only
+     In any case, if the Data Type ends with a "Void", that means the type has 
not been assigned, so we show Undefined. */
+  const determineDataTypeLabel = useCallback(
+    (dataType: string) => {
+      let dataTypeLabel = dataType;
+      if (assetType === TestScenarioType[TestScenarioType.RULE]) {
+        dataTypeLabel = dataTypeLabel.split(".").pop() ?? dataTypeLabel;
+      }
+      return dataTypeLabel.endsWith("Void") ? "<Undefined>" : dataTypeLabel;
+    },
+    [assetType]
+  );
+
+  /* It updates any column width change in the Model */
+  const setColumnWidth = useCallback(
+    (inputIndex: number) => (newWidthAction: React.SetStateAction<number | 
undefined>) => {
+      updateTestScenarioModel((prevState) => {
+        const oldWidth =
+          
prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping![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(prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.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: deepClonedFactMappings,
+                  },
+                },
+              },
+            },
+          };
+        }
+
+        return model;
+      });
+    },
+    [updateTestScenarioModel]
+  );
+
+  /* It determines the column data based on the given FactMapping (Scesim 
column representation).
+     In case of the Description column, the behavior is slightly different 
(column dimension, label and no datatype label) 
+  */
+  const generateColumnFromFactMapping = useCallback(
+    (factMapping: SceSim__FactMappingType, factMappingIndex: number, 
isDescriptionColumn?: boolean) => {
+      return {
+        accessor: factMapping.expressionIdentifier.name!.__$$text,
+        dataType: isDescriptionColumn ? undefined : 
determineDataTypeLabel(factMapping.className.__$$text),
+        groupType: 
factMapping.expressionIdentifier.type!.__$$text.toLowerCase(),
+        id: factMapping!.expressionIdentifier.name!.__$$text,
+        isRowIndexColumn: false,
+        // isInlineEditable: isDescriptionColumn         **TODO NOT SURE IF IT 
MAKES SENSE TO IMPLEMENT IT
+        //   ? false
+        //   : assetType === TestScenarioType[TestScenarioType.RULE]
+        //   ? true
+        //   : false,
+        label: isDescriptionColumn ? factMapping.factAlias.__$$text : 
factMapping.expressionAlias!.__$$text,
+        minWidth: isDescriptionColumn ? 300 : 100,
+        setWidth: setColumnWidth(factMappingIndex),
+        width: factMapping.columnWidth?.__$$text ?? (isDescriptionColumn ? 300 
: factMapping.columnWidth?.__$$text),
+      };
+    },
+    [determineDataTypeLabel, setColumnWidth]
+  );
+
+  /* It determines the Instance Section (the header row in the middle) based 
on the given FactMapping (Scesim column representation)
+     and the groupType. An Instance represents the a real implementation of a 
DMN Type (DMN-based SCESIM) / Java Class (Rule-based Scesim)
+  */
+  const generateInstanceSectionFromFactMapping = useCallback(
+    (factMapping: SceSim__FactMappingType, groupType: 
TestScenarioTableColumnInstanceGroup) => {
+      /* RULE Test Scenarios can have the same instance in both GIVEN and 
EXPECT section. Therefore, using the following 
+         pattern to identify it */
+      const instanceID =
+        factMapping.expressionIdentifier.type?.__$$text + "." + 
factMapping.factIdentifier.name!.__$$text;
+
+      return {
+        accessor: instanceID,
+        dataType: 
determineDataTypeLabel(factMapping.factIdentifier.className!.__$$text),
+        groupType: groupType.toLowerCase(),
+        id: instanceID,
+        isRowIndexColumn: false,
+        label: factMapping.factAlias.__$$text,
+        columns: [] as ReactTable.Column<ROWTYPE>[],
+      };
+    },
+    [determineDataTypeLabel]
+  );
+
+  /**
+    It generates the columns of the TestScenarioTable, based on the following 
logic:
+    
+---+------------------------------------------------------+----------------------------------------+
+    |   |  Description  |  givenSection (given-header)         |   
expectSection (expect-header)        |
+    |   |               
+--------------------------------+-----+----------------------------------+-----+
+    | # |               | givenInstance (given-instance) | ... | expectGroup 
(expect-instance)    | ... |
+    |   |               
+----------------+---------------+-----+----------------------------------+-----+
+    |   |               | 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
+    adding/removing a field)
+    Background table shows the givenSection only.
+    The returned object contains all the columns in the above structure and 
the instancesGroup (givenInstance + expectInstance)
+    required to correctly manage the instance header's context menu behavior.
+   */
+
+  const tableColumns = useMemo<{
+    allColumns: ReactTable.Column<ROWTYPE>[];
+    instancesGroup: ReactTable.Column<ROWTYPE>[];
+  }>(() => {
+    const descriptionColumns: ReactTable.Column<ROWTYPE>[] = [];
+    const givenInstances: ReactTable.Column<ROWTYPE>[] = [];
+    const expectInstances: ReactTable.Column<ROWTYPE>[] = [];
+
+    (tableData.scesimModelDescriptor.factMappings.FactMapping ?? 
[]).forEach((factMapping, index) => {
+      /* RULE Test Scenarios can have the same instance in both GIVEN and 
EXPECT section. Therefore, using the following 
+         pattern to identify it */
+      const instanceID =
+        factMapping.expressionIdentifier.type?.__$$text + "." + 
factMapping.factIdentifier.name!.__$$text;
+      if (factMapping.expressionIdentifier.type?.__$$text === 
TestScenarioTableColumnFieldGroup.GIVEN.toUpperCase()) {
+        const instance = givenInstances.find((instanceColumn) => 
instanceColumn.id === instanceID);
+        if (instance) {
+          instance.columns?.push(generateColumnFromFactMapping(factMapping, 
index));
+        } else {
+          const newInstance = generateInstanceSectionFromFactMapping(
+            factMapping,
+            TestScenarioTableColumnInstanceGroup.GIVEN
+          );
+          newInstance.columns.push(generateColumnFromFactMapping(factMapping, 
index));
+          givenInstances.push(newInstance);
+        }
+      } else if (
+        factMapping.expressionIdentifier.type!.__$$text === 
TestScenarioTableColumnFieldGroup.EXPECT.toUpperCase()
+      ) {
+        const instance = expectInstances.find((instanceColumn) => 
instanceColumn.id === instanceID);
+        if (instance) {
+          instance.columns?.push(generateColumnFromFactMapping(factMapping, 
index));
+        } else {
+          const newInstance = generateInstanceSectionFromFactMapping(
+            factMapping,
+            TestScenarioTableColumnInstanceGroup.EXPECT
+          );
+          newInstance.columns.push(generateColumnFromFactMapping(factMapping, 
index));
+          expectInstances.push(newInstance);
+        }
+      } else if (
+        factMapping.expressionIdentifier.type!.__$$text === 
TestScenarioTableColumnFieldGroup.OTHER.toUpperCase() &&
+        factMapping.expressionIdentifier.name!.__$$text === "Description"
+      ) {
+        descriptionColumns.push(generateColumnFromFactMapping(factMapping, 
index, true));
+      }
+    });
+
+    const givenSection = [
+      {
+        accessor: TestScenarioTableColumnHeaderGroup.GIVEN,
+        groupType: TestScenarioTableColumnHeaderGroup.GIVEN,
+        id: TestScenarioTableColumnHeaderGroup.GIVEN,
+        isRowIndexColumn: false,
+        label: i18n.table.given.toUpperCase(),
+        columns: givenInstances,
+      },
+    ];
+
+    const expectSection =
+      expectInstances.length > 0
+        ? [
+            {
+              accessor: TestScenarioTableColumnHeaderGroup.EXPECT,
+              groupType: TestScenarioTableColumnHeaderGroup.EXPECT,
+              id: TestScenarioTableColumnHeaderGroup.EXPECT,
+              isRowIndexColumn: false,
+              label: i18n.table.expect.toUpperCase(),
+              columns: expectInstances,
+            },
+          ]
+        : [];
+
+    return {
+      allColumns: [...descriptionColumns, ...givenSection, ...expectSection],
+      instancesGroup: [...givenInstances, ...expectInstances],
+    };
+  }, [
+    generateColumnFromFactMapping,
+    generateInstanceSectionFromFactMapping,
+    i18n,
+    TestScenarioTableColumnHeaderGroup,
+    TestScenarioTableColumnFieldGroup,
+    TestScenarioTableColumnInstanceGroup,
+    tableData.scesimModelDescriptor.factMappings.FactMapping,
+  ]);
+
+  /* It generates the columns of the TestScenarioTable */
+  const tableRows = useMemo(
+    () =>
+      (tableData.scesimData.Scenario ?? []).map((scenario, index) => {
+        const factMappingValues = scenario.factMappingValues.FactMappingValue 
?? [];
+
+        const tableRow = getColumnsAtLastLevel(tableColumns.allColumns, 
2).reduce(
+          (tableRow: ROWTYPE, column: ReactTable.Column<ROWTYPE>) => {
+            const factMappingValue = factMappingValues.filter(
+              (fmv) => fmv.expressionIdentifier.name!.__$$text === 
column.accessor
+            );
+            tableRow[column.accessor] = 
factMappingValue[0]?.rawValue?.__$$text ?? "";
+            return tableRow;
+          },
+          { id: index }
+        );
+        return tableRow;
+      }),
+    [tableColumns, tableData.scesimData.Scenario]
+  );
+
+  /** TABLE'S CONTEXT MENU MANAGEMENT */
+
+  const allowedOperations = useCallback(
+    (conditions: BeeTableContextMenuAllowedOperationsConditions) => {
+      const isHeader =
+        conditions.column?.groupType === 
TestScenarioTableColumnHeaderGroup.EXPECT ||
+        conditions.column?.groupType === 
TestScenarioTableColumnHeaderGroup.GIVEN;
+      const isInstance =
+        conditions.column?.groupType === 
TestScenarioTableColumnInstanceGroup.EXPECT ||
+        conditions.column?.groupType === 
TestScenarioTableColumnInstanceGroup.GIVEN;
+
+      if (!conditions.selection.selectionStart || 
!conditions.selection.selectionEnd || isHeader) {
+        return [];
+      }
+
+      const columnIndex = conditions.selection.selectionStart.columnIndex;
+      const groupType = conditions.column?.groupType;
+
+      const atLeastTwoColumnsOfTheSameGroupType = groupType
+        ? _.groupBy(conditions.columns, (column) => 
column?.groupType)[groupType].length > 1
+        : true;
+
+      const columnCanBeDeleted =
+        columnIndex > 0 && atLeastTwoColumnsOfTheSameGroupType && 
(conditions.columns?.length ?? 0) > 4;
+
+      const columnOperations = (isInstance ? columnIndex in [0] : columnIndex 
in [0, 1])
+        ? []
+        : [
+            BeeTableOperation.ColumnInsertLeft,
+            BeeTableOperation.ColumnInsertRight,
+            BeeTableOperation.ColumnInsertN,
+            ...(columnCanBeDeleted ? [BeeTableOperation.ColumnDelete] : []),
+          ];
+
+      return [
+        ...(columnIndex >= 0 && conditions.selection.selectionStart.rowIndex < 
0 ? columnOperations : []),
+        ...(conditions.selection.selectionStart.rowIndex >= 0 && columnIndex > 0
+          ? [
+              BeeTableOperation.SelectionCopy,
+              BeeTableOperation.SelectionCut,
+              BeeTableOperation.SelectionPaste,
+              BeeTableOperation.SelectionReset,
+            ]
+          : []),
+        ...(conditions.selection.selectionStart.rowIndex >= 0
+          ? [
+              BeeTableOperation.RowInsertAbove,
+              BeeTableOperation.RowInsertBelow,
+              BeeTableOperation.RowInsertN,
+              ...(tableRows.length > 1 ? [BeeTableOperation.RowDelete] : []),
+              BeeTableOperation.RowReset,
+              BeeTableOperation.RowDuplicate,
+            ]
+          : []),
+      ];
+    },
+    [TestScenarioTableColumnHeaderGroup, TestScenarioTableColumnInstanceGroup, 
tableRows.length]
+  );
+
+  const generateOperationConfig = useCallback(
+    (groupName: string) => {
+      const isInstance =
+        groupName === TestScenarioTableColumnInstanceGroup.EXPECT ||
+        groupName === TestScenarioTableColumnInstanceGroup.GIVEN;
+
+      const groupLabel = (!isInstance ? i18n.table.field : 
i18n.table.instance).toUpperCase();
+
+      return [
+        {
+          group: groupLabel,
+          items: [
+            {
+              name: isInstance ? i18n.table.insertLeftInstance : 
i18n.table.insertLeftField,
+              type: BeeTableOperation.ColumnInsertLeft,
+            },
+            {
+              name: isInstance ? i18n.table.insertRightInstance : 
i18n.table.insertRightField,
+              type: BeeTableOperation.ColumnInsertRight,
+            },
+            { name: i18n.table.insert, type: BeeTableOperation.ColumnInsertN },
+            {
+              name: isInstance ? i18n.table.deleteInstance : 
i18n.table.deleteField,
+              type: BeeTableOperation.ColumnDelete,
+            },
+          ],
+        },
+        {
+          group: i18n.table.simulation.singleEntry.toUpperCase(),
+          items: [
+            { name: i18n.table.insertAbove, type: 
BeeTableOperation.RowInsertAbove },
+            { name: i18n.table.insertBelow, type: 
BeeTableOperation.RowInsertBelow },
+            { name: i18n.table.insert, type: BeeTableOperation.RowInsertN },
+            { name: i18n.table.delete, type: BeeTableOperation.RowDelete },
+            { name: i18n.table.duplicate, type: BeeTableOperation.RowDuplicate 
},
+          ],
+        },
+        {
+          group: i18n.table.selection.toUpperCase(),
+          items: [
+            { name: i18n.table.copy, type: BeeTableOperation.SelectionCopy },
+            { name: i18n.table.cut, type: BeeTableOperation.SelectionCut },
+            { name: i18n.table.paste, type: BeeTableOperation.SelectionPaste },
+            { name: i18n.table.reset, type: BeeTableOperation.SelectionReset },
+          ],
+        },
+      ];
+    },
+    [TestScenarioTableColumnInstanceGroup, i18n]
+  );
+
+  const simulationOperationConfig = useMemo<BeeTableOperationConfig>(() => {
+    const config: BeeTableOperationConfig = {};
+    config[""] = generateOperationConfig("");
+    config[TestScenarioTableColumnHeaderGroup.EXPECT] = 
generateOperationConfig("");
+    config[TestScenarioTableColumnHeaderGroup.GIVEN] = 
generateOperationConfig("");
+    config[TestScenarioTableColumnInstanceGroup.EXPECT] = 
generateOperationConfig(
+      TestScenarioTableColumnInstanceGroup.EXPECT
+    );
+    config[TestScenarioTableColumnInstanceGroup.GIVEN] = 
generateOperationConfig(
+      TestScenarioTableColumnInstanceGroup.GIVEN
+    );
+    config[TestScenarioTableColumnFieldGroup.EXPECT] = generateOperationConfig(
+      TestScenarioTableColumnFieldGroup.EXPECT
+    );
+    config[TestScenarioTableColumnFieldGroup.GIVEN] = 
generateOperationConfig(TestScenarioTableColumnFieldGroup.GIVEN);
+    config[TestScenarioTableColumnFieldGroup.OTHER] = 
generateOperationConfig(TestScenarioTableColumnFieldGroup.OTHER);
+    return config;
+  }, [
+    TestScenarioTableColumnFieldGroup,
+    TestScenarioTableColumnHeaderGroup,
+    TestScenarioTableColumnInstanceGroup,
+    generateOperationConfig,
+  ]);
+
+  /** TABLE UPDATES FUNCTIONS */
+
+  /** 
+    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.
+   */
+  const retrieveFactMappingValueIndexByIdentifiers = useCallback(
+    (
+      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
+      );
+    },
+    []
+  );
+
+  /**
+   * It updates every changed Cell in its related FactMappingValue
+   */
+  const onCellUpdates = useCallback(
+    (cellUpdates: BeeTableCellUpdate<ROWTYPE>[]) => {
+      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 =
+            
prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping![
+              update.columnIndex + 1
+            ];
+
+          const deepClonedScenarios: SceSim__ScenarioType[] = JSON.parse(
+            
JSON.stringify(prevState.ScenarioSimulationModel.simulation.scesimData.Scenario)
+          );
+          const factMappingValues = 
deepClonedScenarios[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,
+              },
+            };
+          }
+
+          
deepClonedScenarios[update.rowIndex].factMappingValues.FactMappingValue = 
newFactMappingValues;
+
+          return {
+            ScenarioSimulationModel: {
+              ...prevState.ScenarioSimulationModel,
+              simulation: {
+                ...prevState.ScenarioSimulationModel.simulation,
+                scesimData: {
+                  Scenario: deepClonedScenarios,
+                },
+              },
+            },
+          };
+        });
+      });
+    },
+    [retrieveFactMappingValueIndexByIdentifiers, 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[],
+      isDirectionRight: boolean,
+      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 (isDirectionRight) {
+          return selectedColumnIndex + 1;
+        } else {
+          return selectedColumnIndex;
+        }
+      }
+
+      let newColumnTargetColumn = -1;
+
+      if (isDirectionRight) {
+        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
+          ) {
+            continue;
+          } else {
+            newColumnTargetColumn = i + 1;
+            break;
+          }
+        }
+      }
+
+      return newColumnTargetColumn;
+    },
+    [TestScenarioTableColumnFieldGroup]
+  );
+
+  /**
+     This logic determines the selected column index in the table's 
multi-layer headers. This is required because currently
+     every layer handles apply a different logic to setting the index. 
Last-level header follows the natural columns index order, 
+     while the 1th and 2th not. The following schema should clarify the 
current logic:
+    
+---+------------------------------------------------------+----------------------------------------+
+    |   |       1       |                1                     |               
  2                      |
+    |   |               
+--------------------------------+-----+----------------------------------+-----+
+    | 0 |               |                1               |  2  |               
  3                |  4  |
+    |   |               
+----------------+---------------+-----+----------------------------------+-----+
+    |   |               |       2        |       3       |  4  |       5       
  |        6       |  7  |
+    
+---+---------------+----------------+---------------+-----+-----------------+----------------+-----+
+    The First layer doesn't perform any operation, so it's not managed here.
+   */
+  const determineSelectedColumnIndex = useCallback(
+    (factMappings: SceSim__FactMappingType[], originalSelectedColumnIndex: 
number, isInstance: boolean) => {
+      if (isInstance) {
+        const instanceSectionID = 
tableColumns.instancesGroup[originalSelectedColumnIndex - 1].id;
+
+        return (
+          factMappings.findIndex(
+            (factMapping) =>
+              factMapping.expressionIdentifier.type?.__$$text + "." + 
factMapping.factIdentifier.name!.__$$text ===
+              instanceSectionID
+          ) ?? -1
+        );
+      }
+      return originalSelectedColumnIndex;
+    },
+    [tableColumns.instancesGroup]
+  );
+
+  /**
+   * It adds a new FactMapping (Column) in the Model Descriptor structure and 
adds the new column related FactMapping Value (Cell)
+   */
+  const onColumnAdded = useCallback(
+    (args: { beforeIndex: number; currentIndex: number; groupType: string }) 
=> {
+      /* GIVEN and EXPECTED column types can be added only */
+      if (TestScenarioTableColumnFieldGroup.OTHER === args.groupType) {
+        return;
+      }
+      const isInstance =
+        args.groupType === TestScenarioTableColumnInstanceGroup.EXPECT ||
+        args.groupType === TestScenarioTableColumnInstanceGroup.GIVEN;
+
+      updateTestScenarioModel((prevState) => {
+        const factMappingList =
+          
prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.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.beforeIndex === args.currentIndex,
+          selectedColumnIndex,
+          args.groupType,
+          selectedColumnFactMapping
+        );
+
+        const instanceDefaultNames = 
prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings
+          .FactMapping!.filter((factMapping) => 
factMapping.factIdentifier.name!.__$$text.startsWith("INSTANCE-"))
+          .map((factMapping) => factMapping.factIdentifier.name!.__$$text);
+
+        const newFactMapping = {
+          expressionIdentifier: {
+            name: { __$$text: `_${uuid()}`.toLocaleUpperCase() },
+            type: { __$$text: 
selectedColumnFactMapping.expressionIdentifier.type!.__$$text },
+          },
+          factIdentifier: {
+            name: {
+              __$$text: isInstance
+                ? getNextAvailablePrefixedName(instanceDefaultNames, 
"INSTANCE")
+                : selectedColumnFactMapping.factIdentifier.name!.__$$text,
+            },
+            className: {
+              __$$text: isInstance ? "java.lang.Void" : 
selectedColumnFactMapping.factIdentifier.className!.__$$text,
+            },
+          },
+          className: { __$$text: "java.lang.Void" },
+          factAlias: {
+            __$$text: isInstance
+              ? getNextAvailablePrefixedName(instanceDefaultNames, "INSTANCE")
+              : selectedColumnFactMapping.factAlias.__$$text,
+          },
+          expressionAlias: { __$$text: "PROPERTY" },
+          columnWidth: { __$$text: 150 },
+          factMappingValueType: { __$$text: "NOT_EXPRESSION" },
+        };
+
+        /* Cloning the FactMapping list and putting the new one in the user 
defined index */
+        const deepClonedFactMappings = JSON.parse(
+          
JSON.stringify(prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.factMappings.FactMapping)
+        );
+        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 deepClonedScenarios: SceSim__ScenarioType[] = JSON.parse(
+          
JSON.stringify(prevState.ScenarioSimulationModel.simulation.scesimData.Scenario)
+        );
+        deepClonedScenarios.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" },
+          });
+        });
+
+        return {
+          ScenarioSimulationModel: {
+            ...prevState.ScenarioSimulationModel,
+            simulation: {
+              scesimModelDescriptor: {
+                factMappings: {
+                  FactMapping: deepClonedFactMappings,
+                },
+              },
+              scesimData: {
+                Scenario: deepClonedScenarios,
+              },
+            },
+          },
+        };
+      });
+    },
+    [
+      TestScenarioTableColumnFieldGroup,
+      TestScenarioTableColumnInstanceGroup,
+      determineNewColumnTargetIndex,
+      determineSelectedColumnIndex,
+      getNextAvailablePrefixedName,
+      updateTestScenarioModel,
+    ]
+  );
+
+  /**
+   * It removes a FactMapping (Column) at the given column index toghter with 
its related Data Cells.
+   */
+  const onColumnDeleted = useCallback(
+    (args: { columnIndex: number; groupType: string }) => {
+      updateTestScenarioModel((prevState) => {
+        const isInstance =
+          args.groupType === TestScenarioTableColumnInstanceGroup.EXPECT ||
+          args.groupType === TestScenarioTableColumnInstanceGroup.GIVEN;
+
+        const factMappings =
+          
prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.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 + 1, factMapping: 
factMappingToRemove }];
+
+        /* Cloning the FactMappings list (Columns) and and removing the 
FactMapping (Column) at given index */
+        const deepClonedFactMappings = JSON.parse(
+          
JSON.stringify(prevState.ScenarioSimulationModel.simulation.scesimModelDescriptor.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 deepClonedScenarios = JSON.parse(
+          
JSON.stringify(prevState.ScenarioSimulationModel.simulation.scesimData.Scenario 
?? [])
+        );
+        deepClonedScenarios.forEach((scenario: SceSim__ScenarioType) => {
+          allFactMappingWithIndexesToRemove.forEach((itemToRemove) => {
+            const factMappingValueColumnIndexToRemove = 
retrieveFactMappingValueIndexByIdentifiers(
+              scenario.factMappingValues.FactMappingValue!,
+              itemToRemove.factMapping!.factIdentifier,
+              itemToRemove.factMapping!.expressionIdentifier
+            )!;
+
+            return {
+              factMappingValues: {
+                FactMappingValue: 
scenario.factMappingValues.FactMappingValue!.splice(
+                  factMappingValueColumnIndexToRemove,
+                  1
+                ),
+              },
+            };
+          });
+        });
+
+        return {
+          ScenarioSimulationModel: {
+            ...prevState.ScenarioSimulationModel,
+            simulation: {
+              scesimModelDescriptor: {
+                factMappings: {
+                  FactMapping: deepClonedFactMappings,
+                },
+              },
+              scesimData: {
+                Scenario: deepClonedScenarios,
+              },
+            },
+          },
+        };
+      });
+    },
+    [
+      TestScenarioTableColumnInstanceGroup,
+      determineSelectedColumnIndex,
+      retrieveFactMappingValueIndexByIdentifiers,
+      updateTestScenarioModel,
+    ]
+  );
+
+  /**
+   * It adds a Scenario (Row) at the given row index
+   */
+  const onRowAdded = useCallback(
+    (args: { beforeIndex: number }) => {
+      updateTestScenarioModel((prevState) => {
+        /* Creating a new Scenario (Row) composed by a list of 
FactMappingValues. The list order is not relevant. */
+        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" },
+          };
+        });
+
+        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,
+              },
+            },
+          },
+        };
+      });
+    },
+    [updateTestScenarioModel]
+  );
+
+  /**
+   * It deletes a Scenario (Row) at the given row index
+   */
+  const onRowDeleted = useCallback(
+    (args: { rowIndex: number }) => {
+      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,
+              },
+            },
+          },
+        };
+      });
+    },
+    [updateTestScenarioModel]
+  );
+
+  /**
+   * It duplicates a Scenario (Row) at the given row index
+   */
+  const onRowDuplicated = useCallback(
+    (args: { rowIndex: number }) => {
+      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
+          )
+        );
+
+        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,
+              },
+            },
+          },
+        };
+      });
+    },
+    [updateTestScenarioModel]
+  );
+
+  return (
+    <div className={"test-scenario-table"}>
+      <StandaloneBeeTable
+        allowedOperations={allowedOperations}
+        columns={tableColumns.allColumns}
+        enableKeyboardNavigation={true}
+        headerLevelCountForAppendingRowIndexColumn={2}
+        headerVisibility={BeeTableHeaderVisibility.AllLevels}
+        isEditableHeader={false}
+        isReadOnly={false}
+        onCellUpdates={onCellUpdates}
+        onColumnAdded={onColumnAdded}
+        onColumnDeleted={onColumnDeleted}
+        onRowAdded={onRowAdded}
+        onRowDeleted={onRowDeleted}
+        onRowDuplicated={onRowDuplicated}
+        operationConfig={simulationOperationConfig}
+        resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER}
+        rows={tableRows}
+        scrollableParentRef={tableScrollableElementRef.current}
+        shouldRenderRowIndexColumn={true}
+        shouldShowColumnsInlineControls={true}
+        shouldShowRowsInlineControls={true}
+      />
+    </div>
+  );
+}
+
+export default TestScenarioTable;
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 80099601251..9ed196d323d 100644
--- a/packages/scesim-marshaller/src/schemas/scesim-1_8/SceSim.xsd
+++ b/packages/scesim-marshaller/src/schemas/scesim-1_8/SceSim.xsd
@@ -57,7 +57,7 @@
   </xsd:complexType>
   <xsd:complexType name="scesimModelDescriptorType">
     <xsd:sequence>
-      <xsd:element type="factMappingsType" name="factMappings" minOccurs="0" />
+      <xsd:element type="factMappingsType" name="factMappings" />
     </xsd:sequence>
   </xsd:complexType>
   <xsd:complexType name="settingsType">
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4048cd904aa..9249eb97138 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -6989,6 +6989,9 @@ importers:
       "@kie-tools-core/patternfly-base":
         specifier: workspace:*
         version: link:../patternfly-base
+      "@kie-tools/boxed-expression-component":
+        specifier: workspace:*
+        version: link:../boxed-expression-component
       "@kie-tools/i18n-common-dictionary":
         specifier: workspace:*
         version: link:../i18n-common-dictionary
@@ -7001,12 +7004,21 @@ importers:
       "@patternfly/react-styles":
         specifier: ^4.92.6
         version: 4.92.6
+      lodash:
+        specifier: ^4.17.21
+        version: 4.17.21
       react:
         specifier: ^17.0.2
         version: 17.0.2
       react-dom:
         specifier: ^17.0.2
         version: 17.0.2([email protected])
+      react-table:
+        specifier: ^7.6.2
+        version: 7.7.0([email protected])
+      uuid:
+        specifier: ^8.3.2
+        version: 8.3.2
     devDependencies:
       "@babel/core":
         specifier: ^7.16.0
@@ -7032,21 +7044,27 @@ importers:
       "@kie-tools/tsconfig":
         specifier: workspace:*
         version: link:../tsconfig
+      "@types/lodash":
+        specifier: ^4.14.168
+        version: 4.14.169
       "@types/react":
         specifier: ^17.0.6
         version: 17.0.21
       "@types/react-dom":
         specifier: ^17.0.5
         version: 17.0.8
+      "@types/react-table":
+        specifier: ^7.0.25
+        version: 7.7.7
+      "@types/uuid":
+        specifier: ^8.3.0
+        version: 8.3.0
       copy-webpack-plugin:
         specifier: ^11.0.0
         version: 11.0.0([email protected])
       file-loader:
         specifier: ^6.2.0
         version: 6.2.0([email protected])
-      react-json-view:
-        specifier: ^1.21.3
-        version: 1.21.3(@types/[email protected])([email protected])([email protected])
       rimraf:
         specifier: ^3.0.2
         version: 3.0.2
@@ -43536,7 +43554,7 @@ packages:
       "@webpack-cli/configtest": 1.2.0([email protected])([email protected])
       "@webpack-cli/info": 1.5.0([email protected])
       "@webpack-cli/serve": 1.7.0([email protected])
-      colorette: 2.0.20
+      colorette: 2.0.16
       commander: 7.2.0
       cross-spawn: 7.0.3
       fastest-levenshtein: 1.0.12
diff --git a/repo/graph.dot b/repo/graph.dot
index 93bbb0677a1..bda593ccf8b 100644
--- a/repo/graph.dot
+++ b/repo/graph.dot
@@ -394,9 +394,7 @@ digraph G {
   "@kie-tools/runtime-tools-gateway-api" -> "@kie-tools/root-env" [ style = 
"dashed", color = "blue" ];
   "@kie-tools/runtime-tools-gateway-api" -> "@kie-tools/tsconfig" [ style = 
"dashed", color = "blue" ];
   "@kie-tools/runtime-tools-webapp-components" -> 
"@kie-tools/runtime-tools-enveloped-components" [ style = "solid", color = 
"blue" ];
-  "@kie-tools/scesim-editor" -> "@kie-tools-core/patternfly-base" [ style = 
"solid", color = "blue" ];
-  "@kie-tools/scesim-editor" -> "@kie-tools/i18n-common-dictionary" [ style = 
"solid", color = "blue" ];
-  "@kie-tools/scesim-editor" -> "@kie-tools-core/webpack-base" [ style = 
"dashed", color = "blue" ];
+  "@kie-tools/scesim-editor" -> "@kie-tools/boxed-expression-component" [ 
style = "solid", color = "blue" ];
   "@kie-tools/scesim-editor" -> "@kie-tools/scesim-marshaller" [ style = 
"dashed", color = "blue" ];
   "@kie-tools/scesim-marshaller" -> "@kie-tools/xml-parser-ts-codegen" [ style 
= "dashed", color = "blue" ];
   "@kie-tools/serverless-logic-web-tools" -> 
"@kie-tools-core/kubernetes-bridge" [ style = "solid", color = "black" ];
diff --git a/repo/graph.json b/repo/graph.json
index e25db3775c1..bc987c04db3 100644
--- a/repo/graph.json
+++ b/repo/graph.json
@@ -773,9 +773,7 @@
         "target": "@kie-tools/runtime-tools-enveloped-components",
         "weight": 1
       },
-      { "source": "@kie-tools/scesim-editor", "target": 
"@kie-tools-core/patternfly-base", "weight": 1 },
-      { "source": "@kie-tools/scesim-editor", "target": 
"@kie-tools/i18n-common-dictionary", "weight": 1 },
-      { "source": "@kie-tools/scesim-editor", "target": 
"@kie-tools-core/webpack-base", "weight": 1 },
+      { "source": "@kie-tools/scesim-editor", "target": 
"@kie-tools/boxed-expression-component", "weight": 1 },
       { "source": "@kie-tools/scesim-editor", "target": 
"@kie-tools/scesim-marshaller", "weight": 1 },
       { "source": "@kie-tools/scesim-marshaller", "target": 
"@kie-tools/xml-parser-ts-codegen", "weight": 1 },
       { "source": "@kie-tools/serverless-logic-web-tools", "target": 
"@kie-tools-core/kubernetes-bridge", "weight": 1 },


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

Reply via email to