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]