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 2fd5a2c3e45 kie-issues#1481: Test Scenario Editor: Create
`@kie-tools/scesim-editor-envelope` (#2687)
2fd5a2c3e45 is described below
commit 2fd5a2c3e45b59a25beabff12bcc0ac7b7f817b7
Author: Yeser Amer <[email protected]>
AuthorDate: Tue Oct 22 17:52:26 2024 +0200
kie-issues#1481: Test Scenario Editor: Create
`@kie-tools/scesim-editor-envelope` (#2687)
---
packages/scesim-editor-envelope/README.md | 46 ++
packages/scesim-editor-envelope/env/index.js | 27 ++
packages/scesim-editor-envelope/package.json | 55 +++
.../src/TestScenarioEditorEnvelopeApiFactory.ts | 44 ++
.../src/TestScenarioEditorFactory.tsx | 160 +++++++
.../src/TestScenarioEditorRoot.tsx | 517 +++++++++++++++++++++
packages/scesim-editor-envelope/tsconfig.json | 6 +
packages/scesim-editor/package.json | 1 +
packages/scesim-editor/src/TestScenarioEditor.tsx | 87 +++-
.../src/TestScenarioEditorContext.tsx | 28 +-
.../src/commands/CommandsContextProvider.tsx | 43 ++
.../src/drawer/TestScenarioDrawerPanel.tsx | 4 +-
.../src/drawer/TestScenarioDrawerSettingsPanel.tsx | 33 +-
.../TestScenarioEditorDependenciesContext.tsx | 64 +++
.../stories/dev/DevWebApp.stories.tsx | 86 ++--
.../stories/examples/AvailableDMNModels.ts | 34 +-
.../stories/misc/empty/Empty.stories.tsx | 2 +
.../stories/scesimEditorStoriesWrapper.tsx | 11 +-
.../stories/useCases/IsOldEnoughRule.stories.tsx | 4 +-
.../useCases/TrafficViolationDmn.stories.tsx | 2 +
pnpm-lock.yaml | 82 ++++
repo/graph.dot | 4 +
repo/graph.json | 17 +
23 files changed, 1288 insertions(+), 69 deletions(-)
diff --git a/packages/scesim-editor-envelope/README.md
b/packages/scesim-editor-envelope/README.md
new file mode 100644
index 00000000000..64a8f8018c0
--- /dev/null
+++ b/packages/scesim-editor-envelope/README.md
@@ -0,0 +1,46 @@
+<!--
+ 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 Editor Envelope
+
+Package responsible for creating the necessary pumbling for `scesim-editor` to
be used inside an Envelope.
+
+---
+
+Apache KIE (incubating) is an effort undergoing incubation at The Apache
Software
+Foundation (ASF), sponsored by the name of Apache Incubator. Incubation is
+required of all newly accepted projects until a further review indicates that
+the infrastructure, communications, and decision making process have stabilized
+in a manner consistent with other successful ASF projects. While incubation
+status is not necessarily a reflection of the completeness or stability of the
+code, it does indicate that the project has yet to be fully endorsed by the
ASF.
+
+Some of the incubating project’s releases may not be fully compliant with ASF
+policy. For example, releases may have incomplete or un-reviewed licensing
+conditions. What follows is a list of known issues the project is currently
+aware of (note that this list, by definition, is likely to be incomplete):
+
+- Hibernate, an LGPL project, is being used. Hibernate is in the process of
+ relicensing to ASL v2
+- Some files, particularly test files, and those not supporting comments, may
+ be missing the ASF Licensing Header
+
+If you are planning to incorporate this work into your product/project, please
+be aware that you will need to conduct a thorough licensing review to determine
+the overall implications of including this work. For the current status of this
+project through the Apache Incubator visit:
+https://incubator.apache.org/projects/kie.html
diff --git a/packages/scesim-editor-envelope/env/index.js
b/packages/scesim-editor-envelope/env/index.js
new file mode 100644
index 00000000000..61bc742bd66
--- /dev/null
+++ b/packages/scesim-editor-envelope/env/index.js
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+const { varsWithName, composeEnv } = require("@kie-tools-scripts/build-env");
+
+module.exports = composeEnv([require("@kie-tools/root-env/env")], {
+ vars: varsWithName({}),
+ get env() {
+ return {};
+ },
+});
diff --git a/packages/scesim-editor-envelope/package.json
b/packages/scesim-editor-envelope/package.json
new file mode 100644
index 00000000000..17edf9fec90
--- /dev/null
+++ b/packages/scesim-editor-envelope/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "@kie-tools/scesim-editor-envelope",
+ "version": "0.0.0",
+ "description": "",
+ "license": "Apache-2.0",
+ "keywords": [],
+ "homepage": "https://github.com/apache/incubator-kie-tools",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/apache/incubator-kie-tools.git"
+ },
+ "bugs": {
+ "url": "https://github.com/apache/incubator-kie-tools/issues"
+ },
+ "files": [
+ "dist",
+ "src"
+ ],
+ "scripts": {
+ "build:dev": "rimraf dist && tsc -p tsconfig.json",
+ "build:prod": "rimraf dist && pnpm lint && tsc -p tsconfig.json",
+ "lint": "run-script-if --bool \"$(build-env linters.run)\" --then
\"kie-tools--eslint ./src\""
+ },
+ "dependencies": {
+ "@kie-tools-core/editor": "workspace:*",
+ "@kie-tools-core/envelope": "workspace:*",
+ "@kie-tools-core/envelope-bus": "workspace:*",
+ "@kie-tools-core/keyboard-shortcuts": "workspace:*",
+ "@kie-tools-core/notifications": "workspace:*",
+ "@kie-tools-core/react-hooks": "workspace:*",
+ "@kie-tools-core/workspace": "workspace:*",
+ "@kie-tools/boxed-expression-component": "workspace:*",
+ "@kie-tools/dmn-marshaller": "workspace:*",
+ "@kie-tools/scesim-editor": "workspace:*",
+ "@kie-tools/scesim-marshaller": "workspace:*",
+ "@kie-tools/xml-parser-ts": "workspace:*",
+ "@patternfly/react-core": "^4.276.6"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.16.0",
+ "@babel/preset-env": "^7.16.0",
+ "@babel/preset-react": "^7.16.0",
+ "@kie-tools/eslint": "workspace:*",
+ "@kie-tools/root-env": "workspace:*",
+ "@kie-tools/tsconfig": "workspace:*",
+ "@types/react": "^17.0.6",
+ "@types/react-dom": "^17.0.5",
+ "rimraf": "^3.0.2",
+ "typescript": "^5.5.3"
+ },
+ "peerDependencies": {
+ "react": ">=17.0.2 <19.0.0",
+ "react-dom": ">=17.0.2 <19.0.0"
+ }
+}
diff --git
a/packages/scesim-editor-envelope/src/TestScenarioEditorEnvelopeApiFactory.ts
b/packages/scesim-editor-envelope/src/TestScenarioEditorEnvelopeApiFactory.ts
new file mode 100644
index 00000000000..394581f8575
--- /dev/null
+++
b/packages/scesim-editor-envelope/src/TestScenarioEditorEnvelopeApiFactory.ts
@@ -0,0 +1,44 @@
+/*
+ * 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 { EnvelopeApiFactoryArgs } from "@kie-tools-core/envelope";
+import { EditorEnvelopeViewApi, KogitoEditorEnvelopeApiImpl } from
"@kie-tools-core/editor/dist/envelope";
+import {
+ Editor,
+ KogitoEditorChannelApi,
+ KogitoEditorEnvelopeApi,
+ KogitoEditorEnvelopeContextType,
+} from "@kie-tools-core/editor/dist/api";
+import { TestScenarioEditorFactory } from "./TestScenarioEditorFactory";
+
+export type TestScenarioEnvelopeApiFactoryArgs = EnvelopeApiFactoryArgs<
+ KogitoEditorEnvelopeApi,
+ KogitoEditorChannelApi,
+ EditorEnvelopeViewApi<Editor>,
+ KogitoEditorEnvelopeContextType<KogitoEditorChannelApi>
+>;
+
+export class TestScenarioEditorEnvelopeApiImpl
+ extends KogitoEditorEnvelopeApiImpl<Editor, KogitoEditorEnvelopeApi,
KogitoEditorChannelApi>
+ implements KogitoEditorEnvelopeApi
+{
+ constructor(readonly scesimArgs: TestScenarioEnvelopeApiFactoryArgs) {
+ super(scesimArgs, new TestScenarioEditorFactory());
+ }
+}
diff --git a/packages/scesim-editor-envelope/src/TestScenarioEditorFactory.tsx
b/packages/scesim-editor-envelope/src/TestScenarioEditorFactory.tsx
new file mode 100644
index 00000000000..8957ffaf43f
--- /dev/null
+++ b/packages/scesim-editor-envelope/src/TestScenarioEditorFactory.tsx
@@ -0,0 +1,160 @@
+/*
+ * 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 } from "react";
+import {
+ Editor,
+ EditorFactory,
+ EditorInitArgs,
+ KogitoEditorEnvelopeContextType,
+ KogitoEditorChannelApi,
+ EditorTheme,
+ DEFAULT_WORKSPACE_ROOT_ABSOLUTE_POSIX_PATH,
+} from "@kie-tools-core/editor/dist/api";
+import { Notification } from "@kie-tools-core/notifications/dist/api";
+import { ResourceContent, ResourcesList, WorkspaceEdit } from
"@kie-tools-core/workspace/dist/api";
+import { TestScenarioEditorRoot } from "./TestScenarioEditorRoot";
+
+export class TestScenarioEditorFactory implements EditorFactory<Editor,
KogitoEditorChannelApi> {
+ public createEditor(
+ envelopeContext: KogitoEditorEnvelopeContextType<KogitoEditorChannelApi>,
+ initArgs: EditorInitArgs
+ ): Promise<Editor> {
+ return Promise.resolve(new TestScenarioEditorInterface(envelopeContext,
initArgs));
+ }
+}
+
+export class TestScenarioEditorInterface implements Editor {
+ private self: TestScenarioEditorRoot;
+ public af_isReact = true;
+ public af_componentId: "scesim-editor";
+ public af_componentTitle: "Test Scenario Editor";
+
+ constructor(
+ private readonly envelopeContext:
KogitoEditorEnvelopeContextType<KogitoEditorChannelApi>,
+ private readonly initArgs: EditorInitArgs
+ ) {}
+
+ // Not in-editor
+
+ public getPreview(): Promise<string | undefined> {
+ return this.self.getDiagramSvg();
+ }
+
+ public async validate(): Promise<Notification[]> {
+ return Promise.resolve([]);
+ }
+
+ // Forwarding to the editor
+
+ public async setTheme(theme: EditorTheme): Promise<void> {
+ return Promise.resolve(); // No-op for now. The Test Scenario Editor only
has the LIGHT theme.
+ }
+
+ public async undo(): Promise<void> {
+ return this.self.undo();
+ }
+
+ public async redo(): Promise<void> {
+ return this.self.redo();
+ }
+
+ public getContent(): Promise<string> {
+ return this.self.getContent();
+ }
+
+ public setContent(normalizedPosixPathRelativeToTheWorkspaceRoot: string,
content: string): Promise<void> {
+ return this.self.setContent(normalizedPosixPathRelativeToTheWorkspaceRoot,
content);
+ }
+
+ // This is the argument to ReactDOM.render. These props can be understood
like "static globals".
+ public af_componentRoot() {
+ return (
+ <TestScenarioEditorRootWrapper
+ exposing={(testScenarioEditorRoot) => (this.self =
testScenarioEditorRoot)}
+ envelopeContext={this.envelopeContext}
+ workspaceRootAbsolutePosixPath={
+ this.initArgs.workspaceRootAbsolutePosixPath ??
DEFAULT_WORKSPACE_ROOT_ABSOLUTE_POSIX_PATH
+ }
+ isReadOnly={this.initArgs.isReadOnly}
+ />
+ );
+ }
+}
+
+// This component is a wrapper. It memoizes the TestScenarioEditorRoot props
beforing rendering it.
+function TestScenarioEditorRootWrapper({
+ envelopeContext,
+ exposing,
+ workspaceRootAbsolutePosixPath,
+ isReadOnly,
+}: {
+ envelopeContext?: KogitoEditorEnvelopeContextType<KogitoEditorChannelApi>;
+ exposing: (s: TestScenarioEditorRoot) => void;
+ workspaceRootAbsolutePosixPath: string;
+ isReadOnly: boolean;
+}) {
+ const onNewEdit = useCallback(
+ (workspaceEdit: WorkspaceEdit) => {
+
envelopeContext?.channelApi.notifications.kogitoWorkspace_newEdit.send(workspaceEdit);
+ },
+ [envelopeContext]
+ );
+
+ const onRequestWorkspaceFilesList = useCallback(
+ async (resource: ResourcesList) => {
+ return (
+
envelopeContext?.channelApi.requests.kogitoWorkspace_resourceListRequest(resource)
?? new ResourcesList("", [])
+ );
+ },
+ [envelopeContext]
+ );
+
+ const onRequestWorkspaceFileContent = useCallback(
+ async (resource: ResourceContent) => {
+ return
envelopeContext?.channelApi.requests.kogitoWorkspace_resourceContentRequest(resource);
+ },
+ [envelopeContext]
+ );
+
+ const onOpenFileFromNormalizedPosixPathRelativeToTheWorkspaceRoot =
useCallback(
+ (normalizedPosixPathRelativeToTheWorkspaceRoot: string) => {
+ envelopeContext?.channelApi.notifications.kogitoWorkspace_openFile.send(
+ normalizedPosixPathRelativeToTheWorkspaceRoot
+ );
+ },
+ [envelopeContext]
+ );
+
+ return (
+ <TestScenarioEditorRoot
+ exposing={exposing}
+ onNewEdit={onNewEdit}
+ onRequestWorkspaceFilesList={onRequestWorkspaceFilesList}
+ onRequestWorkspaceFileContent={onRequestWorkspaceFileContent}
+ onOpenFileFromNormalizedPosixPathRelativeToTheWorkspaceRoot={
+ onOpenFileFromNormalizedPosixPathRelativeToTheWorkspaceRoot
+ }
+ workspaceRootAbsolutePosixPath={workspaceRootAbsolutePosixPath}
+ keyboardShortcutsService={envelopeContext?.services.keyboardShortcuts}
+ isReadOnly={isReadOnly}
+ />
+ );
+}
diff --git a/packages/scesim-editor-envelope/src/TestScenarioEditorRoot.tsx
b/packages/scesim-editor-envelope/src/TestScenarioEditorRoot.tsx
new file mode 100644
index 00000000000..d38148a2239
--- /dev/null
+++ b/packages/scesim-editor-envelope/src/TestScenarioEditorRoot.tsx
@@ -0,0 +1,517 @@
+/*
+ * 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 { useEffect, useMemo, useState } from "react";
+import * as __path from "path";
+import {
+ imperativePromiseHandle,
+ PromiseImperativeHandle,
+} from "@kie-tools-core/react-hooks/dist/useImperativePromiseHandler";
+import { generateUuid } from "@kie-tools/boxed-expression-component/dist/api";
+import { ResourceContent, SearchType, WorkspaceChannelApi, WorkspaceEdit }
from "@kie-tools-core/workspace/dist/api";
+import { KeyboardShortcutsService } from
"@kie-tools-core/keyboard-shortcuts/dist/envelope/KeyboardShortcutsService";
+import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex";
+import { EmptyState, EmptyStateBody, EmptyStateIcon } from
"@patternfly/react-core/dist/js/components/EmptyState";
+import { Title } from "@patternfly/react-core/dist/js/components/Title";
+import { domParser } from "@kie-tools/xml-parser-ts";
+import { normalize } from
"@kie-tools/dmn-marshaller/dist/normalization/normalize";
+import { getMarshaller as getDmnMarshaller } from "@kie-tools/dmn-marshaller";
+import * as TestScenarioEditor from
"@kie-tools/scesim-editor/dist/TestScenarioEditor";
+import { getMarshaller, SceSimMarshaller, SceSimModel } from
"@kie-tools/scesim-marshaller";
+import { EMPTY_ONE_EIGHT } from
"@kie-tools/scesim-editor/dist/resources/EmptyScesimFile";
+
+export const DMN_MODELS_SEARCH_GLOB_PATTERN = "**/*.{dmn}";
+
+export type TestScenarioEditorRootProps = {
+ exposing: (s: TestScenarioEditorRoot) => void;
+ isReadOnly: boolean;
+ keyboardShortcutsService: KeyboardShortcutsService | undefined;
+ onNewEdit: (edit: WorkspaceEdit) => void;
+ onRequestWorkspaceFilesList:
WorkspaceChannelApi["kogitoWorkspace_resourceListRequest"];
+ onRequestWorkspaceFileContent:
WorkspaceChannelApi["kogitoWorkspace_resourceContentRequest"];
+ onOpenFileFromNormalizedPosixPathRelativeToTheWorkspaceRoot:
WorkspaceChannelApi["kogitoWorkspace_openFile"];
+ workspaceRootAbsolutePosixPath: string;
+};
+
+export type TestScenarioEditorRootState = {
+ error: Error | undefined;
+ externalModelsByNamespace: TestScenarioEditor.ExternalDmnsIndex;
+ externalModelsManagerDoneBootstraping: boolean;
+ isReadOnly: boolean;
+ keyboardShortcutsRegistred: boolean;
+ keyboardShortcutsRegisterIds: number[];
+ marshaller: SceSimMarshaller | undefined;
+ openFilenormalizedPosixPathRelativeToTheWorkspaceRoot: string | undefined;
+ pointer: number;
+ stack: SceSimModel[];
+};
+
+export class TestScenarioEditorRoot extends
React.Component<TestScenarioEditorRootProps, TestScenarioEditorRootState> {
+ private readonly externalModelsManagerDoneBootstraping =
imperativePromiseHandle<void>();
+
+ private readonly testScenarioEditorRef:
React.RefObject<TestScenarioEditor.TestScenarioEditorRef>;
+
+ constructor(props: TestScenarioEditorRootProps) {
+ super(props);
+ props.exposing(this);
+ this.testScenarioEditorRef = React.createRef();
+ this.state = {
+ error: undefined,
+ externalModelsByNamespace: {},
+ externalModelsManagerDoneBootstraping: false,
+ isReadOnly: props.isReadOnly,
+ keyboardShortcutsRegisterIds: [],
+ keyboardShortcutsRegistred: false,
+ marshaller: undefined,
+ openFilenormalizedPosixPathRelativeToTheWorkspaceRoot: undefined,
+ pointer: -1,
+ stack: [],
+ };
+ }
+
+ // Exposed API
+
+ public async undo(): Promise<void> {
+ this.setState((prev) => ({ ...prev, pointer: Math.max(0, prev.pointer - 1)
}));
+ }
+
+ public async redo(): Promise<void> {
+ this.setState((prev) => ({ ...prev, pointer: Math.min(prev.stack.length -
1, prev.pointer + 1) }));
+ }
+
+ public async getDiagramSvg(): Promise<string | undefined> {
+ return this.testScenarioEditorRef.current?.getDiagramSvg();
+ }
+
+ public async getContent(): Promise<string> {
+ if (!this.state.marshaller || !this.model) {
+ throw new Error(
+ `Test Scenario EDITOR ROOT: Content has not been set yet. Throwing an
error to prevent returning a "default" content.`
+ );
+ }
+
+ return this.state.marshaller.builder.build(this.model);
+ }
+
+ public async setContent(
+ openFilenormalizedPosixPathRelativeToTheWorkspaceRoot: string,
+ content: string
+ ): Promise<void> {
+ const marshaller = this.getMarshaller(content || EMPTY_ONE_EIGHT);
+
+ // Save stack
+ let savedStackPointer: SceSimModel[] = [];
+
+ // Set the model and path for external models manager.
+ this.setState((prev) => {
+ savedStackPointer = [...prev.stack];
+ return {
+ stack: [marshaller.parser.parse()],
+ openFilenormalizedPosixPathRelativeToTheWorkspaceRoot,
+ pointer: 0,
+ };
+ });
+
+ // Wait the external manager models to load.
+ await this.externalModelsManagerDoneBootstraping.promise;
+
+ // Set the valeus to render the Test Scenario Editor.
+ this.setState((prev) => {
+ // External change to the same file.
+ if (
+ prev.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot ===
+ openFilenormalizedPosixPathRelativeToTheWorkspaceRoot
+ ) {
+ const newStack = savedStackPointer.slice(0, prev.pointer + 1);
+ return {
+ externalModelsManagerDoneBootstraping: true,
+ isReadOnly: prev.isReadOnly,
+ openFilenormalizedPosixPathRelativeToTheWorkspaceRoot,
+ marshaller,
+ pointer: newStack.length,
+ stack: [...newStack, marshaller.parser.parse()],
+ };
+ }
+
+ // Different file opened. Need to reset everything.
+ else {
+ return {
+ externalModelsManagerDoneBootstraping: true,
+ isReadOnly: prev.isReadOnly,
+ marshaller,
+ openFilenormalizedPosixPathRelativeToTheWorkspaceRoot,
+ pointer: 0,
+ stack: [marshaller.parser.parse()],
+ };
+ }
+ });
+ }
+
+ public get model(): SceSimModel | undefined {
+ return this.state.stack[this.state.pointer];
+ }
+
+ // Internal methods
+
+ private getMarshaller(content: string) {
+ try {
+ return getMarshaller(content || EMPTY_ONE_EIGHT);
+ } catch (e) {
+ this.setState((s) => ({
+ ...s,
+ error: e,
+ }));
+ throw e;
+ }
+ }
+
+ private setExternalModelsByNamespace = (externalModelsByNamespace:
TestScenarioEditor.ExternalDmnsIndex) => {
+ this.setState((prev) => ({ ...prev, externalModelsByNamespace }));
+ };
+
+ private onModelChange: TestScenarioEditor.OnSceSimModelChange = (model) => {
+ this.setState(
+ (prev) => {
+ const newStack = prev.stack.slice(0, prev.pointer + 1);
+ return {
+ ...prev,
+ stack: [...newStack, model],
+ pointer: newStack.length,
+ };
+ },
+ () =>
+ this.props.onNewEdit({
+ id:
`${this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot}__${generateUuid()}`,
+ })
+ );
+ };
+
+ private onRequestExternalModelsAvailableToInclude:
TestScenarioEditor.OnRequestExternalModelsAvailableToInclude =
+ async () => {
+ if (!this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot) {
+ return [];
+ }
+
+ const list = await this.props.onRequestWorkspaceFilesList({
+ pattern: DMN_MODELS_SEARCH_GLOB_PATTERN,
+ opts: { type: SearchType.TRAVERSAL },
+ });
+
+ return list.normalizedPosixPathsRelativeToTheWorkspaceRoot.flatMap((p) =>
+
__path.relative(__path.dirname(this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot!),
p)
+ );
+ };
+
+ private onRequestToResolvePathRelativeToTheOpenFile:
TestScenarioEditor.OnRequestToResolvePath = (
+ normalizedPosixPathRelativeToTheOpenFile
+ ) => {
+ const normalizedPosixPathRelativeToTheWorkspaceRoot = __path
+ .resolve(
+
__path.dirname(this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot!),
+ normalizedPosixPathRelativeToTheOpenFile
+ )
+ .substring(1); // Remove leading slash.
+
+ return normalizedPosixPathRelativeToTheWorkspaceRoot;
+
+ // Example:
+ // this.state.openFileAbsolutePath = /Users/ljmotta/packages/dmns/Dmn.dmn
+ // normalizedPosixPathRelativeToTheOpenFile = ../../tmp/Tmp.dmn
+ // workspaceRootAbsolutePosixPath = /Users/ljmotta
+ // resolvedAbsolutePath = /Users/ljmotta/tmp/Tmp.dmn
+ // return (which is the normalizedPosixPathRelativeToTheWorkspaceRoot) =
tmp/Tmp.dmn
+ };
+
+ private onRequestExternalModelByPathsRelativeToTheOpenFile:
TestScenarioEditor.OnRequestExternalModelByPath = async (
+ normalizedPosixPathRelativeToTheOpenFile
+ ) => {
+ const normalizedPosixPathRelativeToTheWorkspaceRoot =
this.onRequestToResolvePathRelativeToTheOpenFile(
+ normalizedPosixPathRelativeToTheOpenFile
+ );
+ const resource = await this.props.onRequestWorkspaceFileContent({
+ normalizedPosixPathRelativeToTheWorkspaceRoot,
+ opts: { type: "text" },
+ });
+
+ const ext = __path.extname(normalizedPosixPathRelativeToTheOpenFile);
+ if (ext === ".dmn") {
+ return {
+ normalizedPosixPathRelativeToTheOpenFile,
+ type: "dmn",
+ model: normalize(getDmnMarshaller(resource?.content ?? "", {
upgradeTo: "latest" }).parser.parse()),
+ svg: "",
+ };
+ } else {
+ throw new Error(`Unknown extension '${ext}'.`);
+ }
+ };
+
+ private onOpenFileFromPathRelativeToTheOpenFile =
(normalizedPosixPathRelativeToTheOpenFile: string) => {
+ if (!this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot) {
+ return;
+ }
+
+ this.props.onOpenFileFromNormalizedPosixPathRelativeToTheWorkspaceRoot(
+
this.onRequestToResolvePathRelativeToTheOpenFile(normalizedPosixPathRelativeToTheOpenFile)
+ );
+ };
+
+ public componentDidUpdate(
+ prevProps: Readonly<TestScenarioEditorRootProps>,
+ prevState: Readonly<TestScenarioEditorRootState>,
+ snapshot?: any
+ ): void {
+ if (this.props.keyboardShortcutsService === undefined ||
this.state.keyboardShortcutsRegistred === true) {
+ return;
+ }
+
+ const commands = this.testScenarioEditorRef.current?.getCommands();
+ if (commands === undefined) {
+ return;
+ }
+ const togglePropertiesPanel =
this.props.keyboardShortcutsService?.registerKeyPress(
+ "I",
+ "Misc | Open/Close dock panel",
+ async () => commands.toggleTestScenarioDock()
+ );
+
+ this.setState((prev) => ({
+ ...prev,
+ keyboardShortcutsRegistred: true,
+ keyboardShortcutsRegisterIds: [togglePropertiesPanel],
+ }));
+ }
+
+ public componentWillUnmount() {
+ const keyboardShortcuts =
this.testScenarioEditorRef.current?.getCommands();
+ if (keyboardShortcuts === undefined) {
+ return;
+ }
+
+ this.state.keyboardShortcutsRegisterIds.forEach((id) => {
+ this.props.keyboardShortcutsService?.deregister(id);
+ });
+ }
+
+ public render() {
+ return (
+ <>
+ {this.state.error && <TestScenarioMarshallerFallbackError
error={this.state.error} />}
+ {this.model && (
+ <>
+ <TestScenarioEditor.TestScenarioEditor
+ ref={this.testScenarioEditorRef}
+ issueTrackerHref={""}
+ model={this.model}
+ onModelChange={this.onModelChange}
+
onRequestExternalModelsAvailableToInclude={this.onRequestExternalModelsAvailableToInclude}
+
onRequestExternalModelByPath={this.onRequestExternalModelByPathsRelativeToTheOpenFile}
+
onRequestToJumpToPath={this.onOpenFileFromPathRelativeToTheOpenFile}
+
onRequestToResolvePath={this.onRequestToResolvePathRelativeToTheOpenFile}
+ openFileNormalizedPosixPathRelativeToTheWorkspaceRoot={
+
this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot
+ }
+ />
+ {
+ <ExternalModelsManager
+
workspaceRootAbsolutePosixPath={this.props.workspaceRootAbsolutePosixPath}
+ thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot={
+
this.state.openFilenormalizedPosixPathRelativeToTheWorkspaceRoot
+ }
+ model={this.model}
+ onChange={this.setExternalModelsByNamespace}
+
onRequestWorkspaceFilesList={this.props.onRequestWorkspaceFilesList}
+
onRequestWorkspaceFileContent={this.props.onRequestWorkspaceFileContent}
+
externalModelsManagerDoneBootstraping={this.externalModelsManagerDoneBootstraping}
+ />
+ }
+ </>
+ )}
+ </>
+ );
+ }
+}
+
+function ExternalModelsManager({
+ workspaceRootAbsolutePosixPath,
+ thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot,
+ model,
+ onChange,
+ onRequestWorkspaceFileContent,
+ onRequestWorkspaceFilesList,
+ externalModelsManagerDoneBootstraping,
+}: {
+ workspaceRootAbsolutePosixPath: string;
+ thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot: string | undefined;
+ model: SceSimModel;
+ onChange: (externalModelsByNamespace: TestScenarioEditor.ExternalDmnsIndex)
=> void;
+ onRequestWorkspaceFileContent:
WorkspaceChannelApi["kogitoWorkspace_resourceContentRequest"];
+ onRequestWorkspaceFilesList:
WorkspaceChannelApi["kogitoWorkspace_resourceListRequest"];
+ externalModelsManagerDoneBootstraping: PromiseImperativeHandle<void>;
+}) {
+ const targetNamespace = useMemo(() => {
+ if (model.ScenarioSimulationModel.settings.type?.__$$text !== "DMN") {
+ return null;
+ }
+ if (model.ScenarioSimulationModel.settings.dmnNamespace?.__$$text) {
+ return
model.ScenarioSimulationModel.settings.dmnNamespace?.__$$text.toUpperCase();
+ }
+ return null;
+ }, [model.ScenarioSimulationModel.settings]);
+
+ const [externalUpdatesCount, setExternalUpdatesCount] = useState(0);
+
+ // This is a hack. Every time a file is updates in KIE Sandbox, the Shared
Worker emits an event to this BroadcastChannel.
+ // By listening to it, we can reload the `externalModelsByNamespace` object.
This makes the DMN Editor react to external changes,
+ // Which is very important for multi-file editing.
+ //
+ // Now, this mechanism is not ideal. We would ideally only be notified on
changes to relevant files, but this sub-system does not exist yet.
+ // The consequence of this "hack" is some extra reloads.
+ useEffect(() => {
+ const bc = new BroadcastChannel("workspaces_files");
+ bc.onmessage = ({ data }) => {
+ // Changes to `thisDmn` shouldn't update its references to external
models.
+ // Here, `data?.relativePath` is relative to the workspace root.
+ if (data?.relativePath ===
thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot) {
+ return;
+ }
+ // We want to track changes on DMN files only.
+ if (
+ !thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot &&
+
__path.extname(thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot!).toUpperCase()
!== "dmn"
+ ) {
+ return;
+ }
+
+ setExternalUpdatesCount((prev) => prev + 1);
+ };
+ return () => {
+ bc.close();
+ };
+ }, [thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot]);
+
+ // This effect actually populates `externalModelsByNamespace` through the
`onChange` call.
+ useEffect(() => {
+ let canceled = false;
+
+ if (!thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot ||
!targetNamespace) {
+ return;
+ }
+
+ onRequestWorkspaceFilesList({ pattern: DMN_MODELS_SEARCH_GLOB_PATTERN,
opts: { type: SearchType.TRAVERSAL } })
+ .then((list) => {
+ const resources: Array<Promise<ResourceContent | undefined>> = [];
+ for (let i = 0; i <
list.normalizedPosixPathsRelativeToTheWorkspaceRoot.length; i++) {
+ const normalizedPosixPathRelativeToTheWorkspaceRoot =
list.normalizedPosixPathsRelativeToTheWorkspaceRoot[i];
+
+ if (
+ normalizedPosixPathRelativeToTheWorkspaceRoot ===
thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot
+ ) {
+ continue;
+ }
+
+ resources.push(
+ onRequestWorkspaceFileContent({
+ normalizedPosixPathRelativeToTheWorkspaceRoot,
+ opts: { type: "text" },
+ })
+ );
+ }
+ return Promise.all(resources);
+ })
+ .then((resources) => {
+ const externalModelsIndex: TestScenarioEditor.ExternalDmnsIndex = {};
+
+ for (let i = 0; i < resources.length; i++) {
+ const resource = resources[i];
+ if (!resource) {
+ continue;
+ }
+
+ const content = resource.content ?? "";
+
+ const normalizedPosixPathRelativeToTheOpenFile = __path.relative(
+
__path.dirname(thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot),
+ resource.normalizedPosixPathRelativeToTheWorkspaceRoot
+ );
+
+ const ext =
__path.extname(resource.normalizedPosixPathRelativeToTheWorkspaceRoot);
+ if (ext === ".dmn") {
+ const namespace =
domParser.getDomDocument(content).documentElement.getAttribute("namespace");
+ if (namespace === targetNamespace) {
+ // Check for multiplicity of namespaces on DMN models
+ if (externalModelsIndex[namespace]) {
+ console.warn(
+ `TEST SCENARIO EDITOR ROOT: Multiple DMN models encountered
with the same namespace '${namespace}': '${
+ resource.normalizedPosixPathRelativeToTheWorkspaceRoot
+ }' and '${
+
externalModelsIndex[namespace]!.normalizedPosixPathRelativeToTheOpenFile
+ }'. The latter will be considered.`
+ );
+ }
+
+ externalModelsIndex[namespace] = {
+ normalizedPosixPathRelativeToTheOpenFile,
+ model: normalize(getDmnMarshaller(content, { upgradeTo:
"latest" }).parser.parse()),
+ svg: "",
+ };
+ }
+ } else {
+ throw new Error(`Unknown extension '${ext}'.`);
+ }
+ }
+
+ if (!canceled) {
+ onChange(externalModelsIndex);
+ }
+ externalModelsManagerDoneBootstraping.resolve();
+ });
+
+ return () => {
+ canceled = true;
+ };
+ }, [
+ targetNamespace,
+ onChange,
+ onRequestWorkspaceFileContent,
+ onRequestWorkspaceFilesList,
+ thisScesimNormalizedPosixPathRelativeToTheWorkspaceRoot,
+ externalUpdatesCount,
+ workspaceRootAbsolutePosixPath,
+ externalModelsManagerDoneBootstraping,
+ ]);
+
+ return <></>;
+}
+
+function TestScenarioMarshallerFallbackError({ error }: { error: Error }) {
+ return (
+ <Flex justifyContent={{ default: "justifyContentCenter" }} style={{
marginTop: "100px" }}>
+ <EmptyState style={{ maxWidth: "1280px" }}>
+ <EmptyStateIcon icon={() => <div style={{ fontSize: "3em" }}>😕</div>}
/>
+ <Title size={"lg"} headingLevel={"h4"}>
+ Unable to open file.
+ </Title>
+ <br />
+ <EmptyStateBody>Error details: {error.message}</EmptyStateBody>
+ </EmptyState>
+ </Flex>
+ );
+}
diff --git a/packages/scesim-editor-envelope/tsconfig.json
b/packages/scesim-editor-envelope/tsconfig.json
new file mode 100644
index 00000000000..9154a249aa5
--- /dev/null
+++ b/packages/scesim-editor-envelope/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "extends": "@kie-tools/tsconfig/tsconfig.esm.json",
+ "compilerOptions": {
+ "jsx": "react-jsx"
+ }
+}
diff --git a/packages/scesim-editor/package.json
b/packages/scesim-editor/package.json
index 9cd082deee5..5814b86fe1f 100644
--- a/packages/scesim-editor/package.json
+++ b/packages/scesim-editor/package.json
@@ -21,6 +21,7 @@
"@kie-tools-core/i18n": "workspace:*",
"@kie-tools-core/patternfly-base": "workspace:*",
"@kie-tools/boxed-expression-component": "workspace:*",
+ "@kie-tools/dmn-marshaller": "workspace:*",
"@kie-tools/i18n-common-dictionary": "workspace:*",
"@kie-tools/scesim-marshaller": "workspace:*",
"@patternfly/react-core": "^4.276.6",
diff --git a/packages/scesim-editor/src/TestScenarioEditor.tsx
b/packages/scesim-editor/src/TestScenarioEditor.tsx
index faf089991e7..b352179c2ff 100644
--- a/packages/scesim-editor/src/TestScenarioEditor.tsx
+++ b/packages/scesim-editor/src/TestScenarioEditor.tsx
@@ -20,12 +20,15 @@
import "@patternfly/react-core/dist/styles/base.css";
import * as React from "react";
-import { useCallback, useImperativeHandle, useMemo, useRef } from "react";
+import { useCallback, useEffect, useImperativeHandle, useMemo, useRef } from
"react";
import { I18nDictionariesProvider } from
"@kie-tools-core/i18n/dist/react-components";
import { testScenarioEditorDictionaries, TestScenarioEditorI18nContext,
testScenarioEditorI18nDefaults } from "./i18n";
+import { DmnLatestModel } from "@kie-tools/dmn-marshaller";
+import { Normalized } from
"@kie-tools/dmn-marshaller/dist/normalization/normalize";
+
import { SceSimModel } from "@kie-tools/scesim-marshaller";
import { SceSim__FactMappingType } from
"@kie-tools/scesim-marshaller/dist/schemas/scesim-1_8/ts-gen/types";
@@ -45,6 +48,7 @@ import HelpIcon from
"@patternfly/react-icons/dist/esm/icons/help-icon";
import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from
"react-error-boundary";
+import { Commands, CommandsContextProvider, useCommands } from
"./commands/CommandsContextProvider";
import TestScenarioCreationPanel from "./creation/TestScenarioCreationPanel";
import TestScenarioDrawerPanel from "./drawer/TestScenarioDrawerPanel";
import TestScenarioSideBarMenu from "./sidebar/TestScenarioSideBarMenu";
@@ -62,6 +66,7 @@ import {
} from "./store/TestScenarioStoreContext";
import { TestScenarioEditorErrorFallback } from
"./TestScenarioEditorErrorFallback";
import { TestScenarioEditorContextProvider, useTestScenarioEditor } from
"./TestScenarioEditorContext";
+import { TestScenarioEditorExternalModelsContextProvider } from
"./externalModels/TestScenarioEditorDependenciesContext";
import { useEffectAfterFirstRender } from "./hook/useEffectAfterFirstRender";
import { INITIAL_COMPUTED_CACHE } from "./store/computed/initial";
@@ -81,9 +86,28 @@ enum TestScenarioFileStatus {
/* Types */
+export type OnRequestExternalModelsAvailableToInclude = () =>
Promise<string[]>;
+export type OnRequestToJumpToPath = (normalizedPosixPathRelativeToTheOpenFile:
string) => void;
+export type OnRequestToResolvePath =
(normalizedPosixPathRelativeToTheOpenFile: string) => string;
export type OnSceSimModelChange = (model: SceSimModel) => void;
+export type OnRequestExternalModelByPath = (
+ normalizedPosixPathRelativeToTheOpenFile: string
+) => Promise<ExternalDmn | null>;
+export type ExternalDmnsIndex = Record<string /**
normalizedPosixPathRelativeToTheOpenFile */, ExternalDmn | undefined>;
+
+export type ExternalDmn = {
+ model: Normalized<DmnLatestModel>;
+ normalizedPosixPathRelativeToTheOpenFile: string;
+ svg: string;
+};
+
export type TestScenarioEditorProps = {
+ /**
+ * When the SceSim represented by `model` ("This SceSim") is DMN-type Test
Scenario this prop needs to map their contents by namespace.
+ * The SceSim model won't be correctly rendered if an included model is not
found on this object.
+ */
+ externalModelsByNamespace?: ExternalDmnsIndex;
/**
* A link that will take users to an issue tracker so they can report
problems they find on the Test Scenario Editor.
* This is shown on the ErrorBoundary fallback component, when an uncaught
error happens.
@@ -101,10 +125,33 @@ export type TestScenarioEditorProps = {
* Notifies the caller when the Test Scenario Editor performs a new edit
after the debounce time.
*/
onModelDebounceStateChanged?: (changed: boolean) => void;
+ /**
+ * Called when the contents of a specific available DMN model is necessary.
+ */
+ onRequestExternalModelByPath?: OnRequestExternalModelByPath;
+ /**
+ * Called when the list of paths of available DMN models
+ */
+ onRequestExternalModelsAvailableToInclude?:
OnRequestExternalModelsAvailableToInclude;
+ /**
+ * When users want to jump to another file, this method is called, allowing
the controller of this component decide what to do.
+ * Links are only rendered if this is provided. Otherwise, paths will be
rendered as text.
+ */
+ onRequestToJumpToPath?: OnRequestToJumpToPath;
+ /**
+ * All paths inside the Test Scenario Editor are relative. To be able to
resolve them and display them as absolute paths, this function is called.
+ * If undefined, the relative paths will be displayed.
+ */
+ onRequestToResolvePath?: OnRequestToResolvePath;
+ /**
+ * The file path of the current opened Test Scenario scesim file
+ */
+ openFileNormalizedPosixPathRelativeToTheWorkspaceRoot: string | undefined;
};
export type TestScenarioEditorRef = {
reset: (mode: SceSimModel) => void;
+ getCommands: () => Commands;
getDiagramSvg: () => Promise<string | undefined>;
};
@@ -114,8 +161,9 @@ export type TestScenarioSelectedColumnMetaData = {
isBackground: boolean;
};
-function TestScenarioMainPanel({ fileName }: { fileName: string }) {
+function TestScenarioMainPanel() {
const { i18n } = useTestScenarioEditorI18n();
+ const { commandsRef } = useCommands();
const testScenarioEditorStoreApi = useTestScenarioEditorStoreApi();
const navigation = useTestScenarioEditorStore((s) => s.navigation);
const scesimModel = useTestScenarioEditorStore((s) => s.scesim.model);
@@ -143,13 +191,24 @@ function TestScenarioMainPanel({ fileName }: { fileName:
string }) {
[testScenarioEditorStoreApi]
);
+ // Show Properties panel
+ useEffect(() => {
+ if (!commandsRef.current) {
+ return;
+ }
+ commandsRef.current.toggleTestScenarioDock = async () => {
+ console.trace("Test Scenario Editor: COMMANDS: Toggle dock panel...");
+ testScenarioEditorStoreApi.setState((state) => {
+ state.navigation.dock.isOpen = !state.navigation.dock.isOpen;
+ });
+ };
+ }, [testScenarioEditorStoreApi, commandsRef]);
+
return (
<>
<div className="kie-scesim-editor--content">
<Drawer isExpanded={navigation.dock.isOpen} isInline={true}
position={"right"}>
- <DrawerContent
- panelContent={<TestScenarioDrawerPanel fileName={fileName}
onDrawerClose={() => showDockPanel(false)} />}
- >
+ <DrawerContent panelContent={<TestScenarioDrawerPanel
onDrawerClose={() => showDockPanel(false)} />}>
<DrawerContentBody>
{isAlertEnabled && (
<div className="kie-scesim-editor--content-alert">
@@ -247,16 +306,17 @@ function TestScenarioParserErrorPanel({
}
export const TestScenarioEditorInternal = ({
+ forwardRef,
model,
onModelChange,
onModelDebounceStateChanged,
- forwardRef,
}: TestScenarioEditorProps & { forwardRef?: React.Ref<TestScenarioEditorRef>
}) => {
console.trace("[TestScenarioEditorInternal] Component creation ...");
const scesim = useTestScenarioEditorStore((s) => s.scesim);
const testScenarioEditorStoreApi = useTestScenarioEditorStoreApi();
const { testScenarioEditorModelBeforeEditingRef,
testScenarioEditorRootElementRef } = useTestScenarioEditor();
+ const { commandsRef } = useCommands();
/** Implementing Editor APIs */
@@ -269,9 +329,10 @@ export const TestScenarioEditorInternal = ({
const state = testScenarioEditorStoreApi.getState();
state.dispatch(state).scesim.reset();
},
+ getCommands: () => commandsRef.current,
getDiagramSvg: async () => undefined,
}),
- [testScenarioEditorStoreApi]
+ [commandsRef, testScenarioEditorStoreApi]
);
// Make sure the Test Scenario Editor reacts to props changing.
@@ -372,7 +433,7 @@ export const TestScenarioEditorInternal = ({
/>
);
case TestScenarioFileStatus.VALID:
- return <TestScenarioMainPanel fileName={"Test"} />;
+ return <TestScenarioMainPanel />;
}
})()}
</div>
@@ -407,9 +468,13 @@ export const TestScenarioEditor = React.forwardRef(
>
<TestScenarioEditorContextProvider {...props}>
<ErrorBoundary FallbackComponent={TestScenarioEditorErrorFallback}
onReset={resetState}>
- <TestScenarioEditorStoreApiContext.Provider
value={storeRef.current}>
- <TestScenarioEditorInternal forwardRef={ref} {...props} />
- </TestScenarioEditorStoreApiContext.Provider>
+ <TestScenarioEditorExternalModelsContextProvider {...props}>
+ <TestScenarioEditorStoreApiContext.Provider
value={storeRef.current}>
+ <CommandsContextProvider>
+ <TestScenarioEditorInternal forwardRef={ref} {...props} />
+ </CommandsContextProvider>
+ </TestScenarioEditorStoreApiContext.Provider>
+ </TestScenarioEditorExternalModelsContextProvider>
</ErrorBoundary>
</TestScenarioEditorContextProvider>
</I18nDictionariesProvider>
diff --git a/packages/scesim-editor/src/TestScenarioEditorContext.tsx
b/packages/scesim-editor/src/TestScenarioEditorContext.tsx
index 49ffc97ffd1..3702076ce6c 100644
--- a/packages/scesim-editor/src/TestScenarioEditorContext.tsx
+++ b/packages/scesim-editor/src/TestScenarioEditorContext.tsx
@@ -24,9 +24,22 @@ import { TestScenarioEditorProps } from
"./TestScenarioEditor";
export type SceSimModelBeforeEditing = SceSimModel;
-export type TestScenarioEditorContextProviderProps =
Pick<TestScenarioEditorProps, "issueTrackerHref" | "model">;
+export type TestScenarioEditorContextProviderProps = Pick<
+ TestScenarioEditorProps,
+ | "issueTrackerHref"
+ | "model"
+ | "onRequestToJumpToPath"
+ | "onRequestToResolvePath"
+ | "openFileNormalizedPosixPathRelativeToTheWorkspaceRoot"
+>;
-export type TestScenarioEditorContextType =
Pick<TestScenarioEditorContextProviderProps, "issueTrackerHref"> & {
+export type TestScenarioEditorContextType = Pick<
+ TestScenarioEditorContextProviderProps,
+ | "issueTrackerHref"
+ | "onRequestToJumpToPath"
+ | "onRequestToResolvePath"
+ | "openFileNormalizedPosixPathRelativeToTheWorkspaceRoot"
+> & {
testScenarioEditorModelBeforeEditingRef:
React.MutableRefObject<SceSimModelBeforeEditing>;
testScenarioEditorRootElementRef: React.RefObject<HTMLDivElement>;
};
@@ -48,8 +61,17 @@ export function TestScenarioEditorContextProvider(
issueTrackerHref: props.issueTrackerHref,
testScenarioEditorModelBeforeEditingRef,
testScenarioEditorRootElementRef,
+ onRequestToJumpToPath: props.onRequestToJumpToPath,
+ onRequestToResolvePath: props.onRequestToResolvePath,
+ openFileNormalizedPosixPathRelativeToTheWorkspaceRoot:
+ props.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot,
}),
- [props.issueTrackerHref]
+ [
+ props.issueTrackerHref,
+ props.onRequestToJumpToPath,
+ props.onRequestToResolvePath,
+ props.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot,
+ ]
);
return <TestScenarioEditorContext.Provider
value={value}>{props.children}</TestScenarioEditorContext.Provider>;
}
diff --git a/packages/scesim-editor/src/commands/CommandsContextProvider.tsx
b/packages/scesim-editor/src/commands/CommandsContextProvider.tsx
new file mode 100644
index 00000000000..aa6b09ac182
--- /dev/null
+++ b/packages/scesim-editor/src/commands/CommandsContextProvider.tsx
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as React from "react";
+import { useContext, useRef } from "react";
+
+export interface Commands {
+ toggleTestScenarioDock: () => void;
+}
+
+const CommandsContext = React.createContext<{
+ commandsRef: React.MutableRefObject<Commands>;
+}>({} as any);
+
+export function useCommands() {
+ return useContext(CommandsContext);
+}
+
+export function CommandsContextProvider(props: React.PropsWithChildren<{}>) {
+ const commandsRef = useRef<Commands>({
+ toggleTestScenarioDock: () => {
+ throw new Error("Test Scenario EDITOR: toggleTestScenarioDock command
not implemented.");
+ },
+ });
+
+ return <CommandsContext.Provider value={{ commandsRef
}}>{props.children}</CommandsContext.Provider>;
+}
diff --git a/packages/scesim-editor/src/drawer/TestScenarioDrawerPanel.tsx
b/packages/scesim-editor/src/drawer/TestScenarioDrawerPanel.tsx
index 0045f44ec58..cf354e6cd8a 100644
--- a/packages/scesim-editor/src/drawer/TestScenarioDrawerPanel.tsx
+++ b/packages/scesim-editor/src/drawer/TestScenarioDrawerPanel.tsx
@@ -36,7 +36,7 @@ import TestScenarioDrawerDataSelectorPanel from
"./TestScenarioDrawerDataSelecto
import TestScenarioDrawerCheatSheetPanel from
"./TestScenarioDrawerCheatSheetPanel";
import TestScenarioDrawerSettingsPanel from
"../drawer/TestScenarioDrawerSettingsPanel";
-function TestScenarioDrawerPanel({ fileName, onDrawerClose }: { fileName:
string; onDrawerClose: () => void }) {
+function TestScenarioDrawerPanel({ onDrawerClose }: { onDrawerClose: () =>
void }) {
const { i18n } = useTestScenarioEditorI18n();
const navigation = useTestScenarioEditorStore((state) => state.navigation);
const settingsModel = useTestScenarioEditorStore((state) =>
state.scesim.model.ScenarioSimulationModel.settings);
@@ -76,7 +76,7 @@ function TestScenarioDrawerPanel({ fileName, onDrawerClose }:
{ fileName: string
case TestScenarioEditorDock.DATA_OBJECT:
return <TestScenarioDrawerDataSelectorPanel />;
case TestScenarioEditorDock.SETTINGS:
- return <TestScenarioDrawerSettingsPanel fileName={fileName} />;
+ return <TestScenarioDrawerSettingsPanel />;
default:
throw new Error("Wrong state, an invalid dock has been selected
" + navigation.dock.selected);
}
diff --git
a/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx
b/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx
index 9f522a2ccbf..d8dc56ea324 100644
--- a/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx
+++ b/packages/scesim-editor/src/drawer/TestScenarioDrawerSettingsPanel.tsx
@@ -33,9 +33,11 @@ import { useTestScenarioEditorI18n } from "../i18n";
import { useTestScenarioEditorStore, useTestScenarioEditorStoreApi } from
"../store/TestScenarioStoreContext";
import "./TestScenarioDrawerSettingsPanel.css";
+import { useTestScenarioEditor } from "../TestScenarioEditorContext";
-function TestScenarioDrawerSettingsPanel({ fileName }: { fileName: string }) {
+function TestScenarioDrawerSettingsPanel() {
const { i18n } = useTestScenarioEditorI18n();
+ const { openFileNormalizedPosixPathRelativeToTheWorkspaceRoot } =
useTestScenarioEditor();
const settingsModel = useTestScenarioEditorStore((state) =>
state.scesim.model.ScenarioSimulationModel.settings);
const testScenarioEditorStoreApi = useTestScenarioEditorStoreApi();
const testScenarioType = settingsModel.type?.__$$text.toUpperCase();
@@ -55,15 +57,22 @@ function TestScenarioDrawerSettingsPanel({ fileName }: {
fileName: string }) {
<Title className={"kie-scesim-editor-drawer-settings--title"}
headingLevel={"h6"}>
{i18n.drawer.settings.fileName}
</Title>
- <TextInput className={"kie-scesim-editor-drawer-settings--text-input"}
value={fileName} type="text" isDisabled />
+ <TextInput
+ aria-label="filename"
+ className={"kie-scesim-editor-drawer-settings--text-input"}
+ isDisabled
+ type="text"
+ value={openFileNormalizedPosixPathRelativeToTheWorkspaceRoot}
+ />
<Title className={"kie-scesim-editor-drawer-settings--title"}
headingLevel={"h6"}>
{i18n.drawer.settings.assetType}
</Title>
<TextInput
+ aria-label="asset-type"
className={"kie-scesim-editor-drawer-settings--text-input"}
- value={testScenarioType}
- type="text"
isDisabled
+ type="text"
+ value={testScenarioType}
/>
{testScenarioType === "DMN" ? (
<>
@@ -72,10 +81,10 @@ function TestScenarioDrawerSettingsPanel({ fileName }: {
fileName: string }) {
</Title>
{/* Temporary Mocked */}
<FormSelect
+ aria-label="form-select-input"
className={"kie-scesim-editor-drawer-settings--form-select"}
- value={"1"}
- aria-label="FormSelect Input"
ouiaId="BasicFormSelect"
+ value={"1"}
>
<FormSelectOption isDisabled={true} key={0} value={"1"}
label={"MockedDMN.dmn"} />
<FormSelectOption isDisabled={true} key={1} value={"2"}
label={"MockedDMN2.dmn"} />
@@ -84,19 +93,21 @@ function TestScenarioDrawerSettingsPanel({ fileName }: {
fileName: string }) {
{i18n.drawer.settings.dmnName}
</Title>
<TextInput
+ aria-label="dmn-name"
className={"kie-scesim-editor-drawer-settings--text-input"}
- value={settingsModel.dmnName?.__$$text}
- type="text"
isDisabled
+ type="text"
+ value={settingsModel.dmnName?.__$$text}
/>
<Title className={"kie-scesim-editor-drawer-settings--title"}
headingLevel={"h6"}>
{i18n.drawer.settings.dmnNameSpace}
</Title>
<TextInput
+ aria-label="dmn-namespace"
className={"kie-scesim-editor-drawer-settings--text-input"}
- value={settingsModel.dmnNamespace?.__$$text}
- type="text"
isDisabled
+ type="text"
+ value={settingsModel.dmnNamespace?.__$$text}
/>
</>
) : (
@@ -110,6 +121,7 @@ function TestScenarioDrawerSettingsPanel({ fileName }: {
fileName: string }) {
</Tooltip>
</Title>
<TextInput
+ aria-label="rule-session"
className={"kie-scesim-editor-drawer-settings--text-input"}
onChange={(value) => updateSettingsField("dmoSession", value)}
placeholder={i18n.drawer.settings.kieSessionRulePlaceholder}
@@ -125,6 +137,7 @@ function TestScenarioDrawerSettingsPanel({ fileName }: {
fileName: string }) {
</Tooltip>
</Title>
<TextInput
+ aria-label="rule-flow-group"
className={"kie-scesim-editor-drawer-settings--text-input"}
onChange={(value) => updateSettingsField("ruleFlowGroup", value)}
placeholder={i18n.drawer.settings.ruleFlowGroupPlaceholder}
diff --git
a/packages/scesim-editor/src/externalModels/TestScenarioEditorDependenciesContext.tsx
b/packages/scesim-editor/src/externalModels/TestScenarioEditorDependenciesContext.tsx
new file mode 100644
index 00000000000..b74b9447f3d
--- /dev/null
+++
b/packages/scesim-editor/src/externalModels/TestScenarioEditorDependenciesContext.tsx
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as React from "react";
+import { useContext, useMemo } from "react";
+import {
+ OnRequestExternalModelsAvailableToInclude,
+ OnRequestExternalModelByPath,
+ ExternalDmnsIndex,
+} from "../TestScenarioEditor";
+
+export interface TestScenarioEditorExternalModelsContextType {
+ onRequestExternalModelByPath?: OnRequestExternalModelByPath;
+ onRequestExternalModelsAvailableToInclude?:
OnRequestExternalModelsAvailableToInclude;
+ externalModelsByNamespace?: ExternalDmnsIndex;
+}
+
+const TestScenarioEditorExternalModelsContext =
React.createContext<TestScenarioEditorExternalModelsContextType>(
+ {} as any
+);
+
+export function useExternalModels() {
+ return useContext(TestScenarioEditorExternalModelsContext);
+}
+
+export function TestScenarioEditorExternalModelsContextProvider(
+ _props: React.PropsWithChildren<TestScenarioEditorExternalModelsContextType>
+) {
+ const { children, ...props } = _props;
+
+ const value = useMemo<TestScenarioEditorExternalModelsContextType>(() => {
+ return {
+ externalModelsByNamespace: props.externalModelsByNamespace,
+ onRequestExternalModelByPath: props.onRequestExternalModelByPath,
+ onRequestExternalModelsAvailableToInclude:
props.onRequestExternalModelsAvailableToInclude,
+ };
+ }, [
+ props.externalModelsByNamespace,
+ props.onRequestExternalModelByPath,
+ props.onRequestExternalModelsAvailableToInclude,
+ ]);
+
+ return (
+ <TestScenarioEditorExternalModelsContext.Provider value={value}>
+ {children}
+ </TestScenarioEditorExternalModelsContext.Provider>
+ );
+}
diff --git a/packages/scesim-editor/stories/dev/DevWebApp.stories.tsx
b/packages/scesim-editor/stories/dev/DevWebApp.stories.tsx
index b9d91f5a091..580fe83116e 100644
--- a/packages/scesim-editor/stories/dev/DevWebApp.stories.tsx
+++ b/packages/scesim-editor/stories/dev/DevWebApp.stories.tsx
@@ -17,7 +17,7 @@
* under the License.
*/
-import React, { useCallback, useRef, useState } from "react";
+import React, { useCallback, useMemo, useRef, useState } from "react";
import type { Meta, StoryObj } from "@storybook/react";
import "@patternfly/react-core/dist/styles/base.css";
import { Button } from "@patternfly/react-core/dist/js/components/Button";
@@ -25,20 +25,33 @@ import { Flex, FlexItem } from
"@patternfly/react-core/dist/js/layouts/Flex";
import { Page, PageSection } from
"@patternfly/react-core/dist/js/components/Page";
import { Stack, StackItem } from "@patternfly/react-core/dist/js";
import { SceSimMarshaller, SceSimModel, getMarshaller } from
"@kie-tools/scesim-marshaller";
-import { OnSceSimModelChange, TestScenarioEditorProps } from
"../../src/TestScenarioEditor";
+import {
+ ExternalDmnsIndex,
+ OnRequestExternalModelByPath,
+ OnRequestExternalModelsAvailableToInclude,
+ OnRequestToJumpToPath,
+ OnSceSimModelChange,
+ TestScenarioEditorProps,
+} from "../../src/TestScenarioEditor";
import { SceSimEditorWrapper } from "../scesimEditorStoriesWrapper";
-import { emptySceSim } from "../misc/empty/Empty.stories";
-import { isOldEnoughDrl } from "../useCases/IsOldEnoughRule.stories";
-import { trafficViolationDmn } from "../useCases/TrafficViolationDmn.stories";
+import { emptyFileName, emptySceSim } from "../misc/empty/Empty.stories";
+import { isOldEnoughDrl, isOldEnoughDrlFileName } from
"../useCases/IsOldEnoughRule.stories";
+import { trafficViolationDmn, trafficViolationDmnFileName } from
"../useCases/TrafficViolationDmn.stories";
+import { availableModelsByPath } from "../examples/AvailableDMNModels";
import "./DevWebApp.css";
-function DevWebApp(args: TestScenarioEditorProps) {
- const [state, setState] = useState<{ marshaller: SceSimMarshaller; stack:
SceSimModel[]; pointer: number }>(() => {
+function DevWebApp(props: TestScenarioEditorProps) {
+ const [fileName, setFileName] = useState<string |
undefined>("Untitled.scesim");
+ const [state, setState] = useState<{
+ marshaller: SceSimMarshaller;
+ pointer: number;
+ stack: SceSimModel[];
+ }>(() => {
const emptySceSimMarshaller = getMarshaller(emptySceSim);
return {
marshaller: emptySceSimMarshaller,
- stack: [emptySceSimMarshaller.parser.parse()],
pointer: 0,
+ stack: [emptySceSimMarshaller.parser.parse()],
};
});
@@ -54,11 +67,16 @@ function DevWebApp(args: TestScenarioEditorProps) {
const downloadAsXml = useCallback(() => {
if (downloadRef.current) {
const fileBlob = new
Blob([state.marshaller.builder.build(currentModel)], { type: "text/xml" });
- downloadRef.current.download = `scesim-test-${makeid(10)}.scesim`;
+ downloadRef.current.download = fileName ??
`scesim-test-${makeid(10)}.scesim`;
downloadRef.current.href = URL.createObjectURL(fileBlob);
downloadRef.current.click();
}
- }, [currentModel, state.marshaller.builder]);
+ }, [currentModel, fileName, state.marshaller.builder]);
+
+ // TODO Unmarshall here the DMN
+ const externalModelsByNamespace = useMemo<ExternalDmnsIndex>(() => {
+ return
currentModel.ScenarioSimulationModel.settings.dmnNamespace?.__$$text, {} as
ExternalDmnsIndex;
+ }, [currentModel.ScenarioSimulationModel.settings.dmnNamespace]);
const onDragOver = useCallback((e: React.DragEvent) => {
e.preventDefault(); // Necessary to disable the browser's default 'onDrop'
handling.
@@ -74,9 +92,14 @@ function DevWebApp(args: TestScenarioEditorProps) {
[...e.dataTransfer.items].forEach((item, i) => {
if (item.kind === "file") {
const reader = new FileReader();
+ setFileName(item.getAsFile()?.name);
reader.addEventListener("load", ({ target }) => {
const marshaller = getMarshaller(target?.result as string);
- setState({ marshaller, stack: [marshaller.parser.parse()],
pointer: 0 });
+ setState({
+ marshaller,
+ pointer: 0,
+ stack: [marshaller.parser.parse()],
+ });
});
reader.readAsText(item.getAsFile() as any);
}
@@ -95,9 +118,14 @@ function DevWebApp(args: TestScenarioEditorProps) {
});
}, []);
+ const onRequestToJumpToPath = useCallback<OnRequestToJumpToPath>((path) => {
+ alert("A request to open this file: " + path);
+ }, []);
+
const onSelectModel = useCallback(
- (newModel) => {
+ (newModel, fileName) => {
onModelChange(getMarshaller(newModel).parser.parse());
+ setFileName(fileName);
},
[onModelChange]
);
@@ -110,8 +138,8 @@ function DevWebApp(args: TestScenarioEditorProps) {
const marshaller = getMarshaller(emptySceSim);
setState({
marshaller,
- stack: [marshaller.parser.parse()],
pointer: 0,
+ stack: [marshaller.parser.parse()],
});
}, []);
@@ -119,17 +147,13 @@ function DevWebApp(args: TestScenarioEditorProps) {
setState((prev) => ({ ...prev, pointer: Math.max(0, prev.pointer - 1) }));
}, []);
- /* TODO: DMN DATA Retieve
- const externalModelsByNamespace = useMemo<ExternalModelsIndex>(() => {
- return (currentModel.definitions.import ?? []).reduce((acc, i) => {
- acc[i["@_namespace"]] = modelsByNamespace[i["@_namespace"]];
- return acc;
- }, {} as ExternalModelsIndex);
- }, [currentModel.definitions.import]);
-
const onRequestExternalModelByPath =
useCallback<OnRequestExternalModelByPath>(async (path) => {
return availableModelsByPath[path] ?? null;
- }, []);*/
+ }, []);
+
+ const onRequestExternalModelsAvailableToInclude =
useCallback<OnRequestExternalModelsAvailableToInclude>(async () => {
+ return Object.keys(availableModelsByPath);
+ }, []);
return (
<Page onDragOver={onDragOver} onDrop={onDrop}>
@@ -148,11 +172,15 @@ function DevWebApp(args: TestScenarioEditorProps) {
<StackItem>
<Flex justifyContent={{ default: "justifyContentSpaceBetween" }}>
<FlexItem shrink={{ default: "shrink" }}>
- <Button onClick={() =>
onSelectModel(emptySceSim)}>Empty</Button>
+ <Button onClick={() => onSelectModel(emptySceSim,
emptyFileName)}>Empty</Button>
- <Button onClick={() => onSelectModel(isOldEnoughDrl)}>Are They
Old Enough?</Button>
+ <Button onClick={() => onSelectModel(isOldEnoughDrl,
isOldEnoughDrlFileName)}>
+ Are They Old Enough?
+ </Button>
- <Button onClick={() =>
onSelectModel(trafficViolationDmn)}>Traffic Violation</Button>
+ <Button onClick={() => onSelectModel(trafficViolationDmn,
trafficViolationDmnFileName)}>
+ Traffic Violation
+ </Button>
|
<Button
onClick={undo}
@@ -198,9 +226,14 @@ function DevWebApp(args: TestScenarioEditorProps) {
variant={"light"}
>
{SceSimEditorWrapper({
- issueTrackerHref: args.issueTrackerHref,
+ issueTrackerHref: props.issueTrackerHref,
+ externalModelsByNamespace: externalModelsByNamespace,
model: currentModel,
onModelChange: onModelChange,
+ onRequestExternalModelsAvailableToInclude:
onRequestExternalModelsAvailableToInclude,
+ onRequestExternalModelByPath: onRequestExternalModelByPath,
+ onRequestToJumpToPath: onRequestToJumpToPath,
+ openFileNormalizedPosixPathRelativeToTheWorkspaceRoot: fileName,
})}
</PageSection>
</Page>
@@ -232,5 +265,6 @@ export const WebApp: Story = {
args: {
issueTrackerHref:
"https://github.com/apache/incubator-kie-issues/issues/new",
model: getMarshaller(emptySceSim).parser.parse(),
+ openFileNormalizedPosixPathRelativeToTheWorkspaceRoot: "Untitled.scesim",
},
};
diff --git a/packages/scesim-editor/stories/examples/AvailableDMNModels.ts
b/packages/scesim-editor/stories/examples/AvailableDMNModels.ts
index 4d7722fa228..70d8fbb5f44 100644
--- a/packages/scesim-editor/stories/examples/AvailableDMNModels.ts
+++ b/packages/scesim-editor/stories/examples/AvailableDMNModels.ts
@@ -17,17 +17,19 @@
* under the License.
*/
-import { DmnLatestModel, getMarshaller } from "@kie-tools/dmn-marshaller";
+import * as TestScenarioEditor from "../../src/TestScenarioEditor";
+import { getMarshaller } from "@kie-tools/dmn-marshaller";
+import { normalize } from
"@kie-tools/dmn-marshaller/dist/normalization/normalize";
import { LOAN_PRE_QUALIFICATION, TRAFFIC_VIOLATION } from
"./ExternalDmnModels";
-export const loanPreQualification = getMarshaller(LOAN_PRE_QUALIFICATION, {
upgradeTo: "latest" }).parser.parse();
-export const trafficViolationModel = getMarshaller(TRAFFIC_VIOLATION, {
upgradeTo: "latest" }).parser.parse();
+export const loanPreQualification = normalize(
+ getMarshaller(LOAN_PRE_QUALIFICATION, { upgradeTo: "latest" }).parser.parse()
+);
+export const trafficViolationModel = normalize(
+ getMarshaller(TRAFFIC_VIOLATION, { upgradeTo: "latest" }).parser.parse()
+);
-export const avaiableModels: {
- model: DmnLatestModel;
- normalizedPosixPathRelativeToTheOpenFile: string;
- svg: string;
-}[] = [
+export const avaiableModels: TestScenarioEditor.ExternalDmn[] = [
{
model: loanPreQualification,
svg: "",
@@ -40,10 +42,12 @@ export const avaiableModels: {
},
];
-// export const availableModelsByPath: Record<string, DmnEditor.ExternalModel>
= Object.values(avaiableModels).reduce(
-// (acc, v) => {
-// acc[v.normalizedPosixPathRelativeToTheOpenFile] = v;
-// return acc;
-// },
-// {} as Record<string, DmnEditor.ExternalModel>
-// );
+export const availableModelsByPath: Record<string,
TestScenarioEditor.ExternalDmn> = Object.values(
+ avaiableModels
+).reduce(
+ (acc, v) => {
+ acc[v.normalizedPosixPathRelativeToTheOpenFile] = v;
+ return acc;
+ },
+ {} as Record<string, TestScenarioEditor.ExternalDmn>
+);
diff --git a/packages/scesim-editor/stories/misc/empty/Empty.stories.tsx
b/packages/scesim-editor/stories/misc/empty/Empty.stories.tsx
index dc538bb058e..7aa0696d501 100644
--- a/packages/scesim-editor/stories/misc/empty/Empty.stories.tsx
+++ b/packages/scesim-editor/stories/misc/empty/Empty.stories.tsx
@@ -22,6 +22,7 @@ import { getMarshaller } from "@kie-tools/scesim-marshaller";
import { TestScenarioEditor } from "../../../src/TestScenarioEditor";
import { SceSimEditorWrapper, StorybookTestScenarioEditorProps } from
"../../scesimEditorStoriesWrapper";
+export const emptyFileName = "Untitled.scesim";
export const emptySceSim = `<?xml version="1.0" encoding="UTF-8"?>
<ScenarioSimulationModel version="1.8" xmlns="https://kie.org/scesim/1.8">
<simulation>
@@ -190,6 +191,7 @@ export const Empty: Story = {
render: (args) => SceSimEditorWrapper(args),
args: {
model: marshaller.parser.parse(),
+ openFileNormalizedPosixPathRelativeToTheWorkspaceRoot: emptyFileName,
xml: marshaller.builder.build(model),
},
};
diff --git a/packages/scesim-editor/stories/scesimEditorStoriesWrapper.tsx
b/packages/scesim-editor/stories/scesimEditorStoriesWrapper.tsx
index 7588aa49d41..802302e52ca 100644
--- a/packages/scesim-editor/stories/scesimEditorStoriesWrapper.tsx
+++ b/packages/scesim-editor/stories/scesimEditorStoriesWrapper.tsx
@@ -67,10 +67,19 @@ export function SceSimEditorWrapper(props:
Partial<StorybookTestScenarioEditorPr
return (
<TestScenarioEditor
ref={ref}
- issueTrackerHref={args.issueTrackerHref}
+ issueTrackerHref={props?.issueTrackerHref ?? args.issueTrackerHref}
model={model}
onModelChange={onModelChange}
onModelDebounceStateChanged={onModelDebounceStateChanged}
+ onRequestExternalModelByPath={props?.onRequestExternalModelByPath ??
args.onRequestExternalModelByPath}
+ onRequestExternalModelsAvailableToInclude={
+ props?.onRequestExternalModelsAvailableToInclude ??
args.onRequestExternalModelsAvailableToInclude
+ }
+ openFileNormalizedPosixPathRelativeToTheWorkspaceRoot={
+ props?.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot ??
+ args.openFileNormalizedPosixPathRelativeToTheWorkspaceRoot
+ }
+ onRequestToJumpToPath={props?.onRequestToJumpToPath ??
args.onRequestToJumpToPath}
/>
);
}
diff --git
a/packages/scesim-editor/stories/useCases/IsOldEnoughRule.stories.tsx
b/packages/scesim-editor/stories/useCases/IsOldEnoughRule.stories.tsx
index 9f0e102caaf..0aa060b7715 100644
--- a/packages/scesim-editor/stories/useCases/IsOldEnoughRule.stories.tsx
+++ b/packages/scesim-editor/stories/useCases/IsOldEnoughRule.stories.tsx
@@ -23,6 +23,7 @@ import { getMarshaller } from "@kie-tools/scesim-marshaller";
import { TestScenarioEditor } from "../../src/TestScenarioEditor";
import { SceSimEditorWrapper, StorybookTestScenarioEditorProps } from
"../scesimEditorStoriesWrapper";
+export const isOldEnoughDrlFileName = "IsOldEnough.scesim";
export const isOldEnoughDrl = `<ScenarioSimulationModel version="1.8"
xmlns="https://kie.org/scesim/1.8">
<simulation>
<scesimModelDescriptor>
@@ -401,9 +402,10 @@ const marshaller = getMarshaller(isOldEnoughDrl);
const model = marshaller.parser.parse();
export const IsOldEnough: Story = {
- render: (args) => SceSimEditorWrapper(args),
args: {
model: marshaller.parser.parse(),
xml: marshaller.builder.build(model),
+ openFileNormalizedPosixPathRelativeToTheWorkspaceRoot:
isOldEnoughDrlFileName,
},
+ render: (args) => SceSimEditorWrapper(args),
};
diff --git
a/packages/scesim-editor/stories/useCases/TrafficViolationDmn.stories.tsx
b/packages/scesim-editor/stories/useCases/TrafficViolationDmn.stories.tsx
index 19ba0102ca1..58856b5432a 100644
--- a/packages/scesim-editor/stories/useCases/TrafficViolationDmn.stories.tsx
+++ b/packages/scesim-editor/stories/useCases/TrafficViolationDmn.stories.tsx
@@ -23,6 +23,7 @@ import { getMarshaller } from "@kie-tools/scesim-marshaller";
import { TestScenarioEditor } from "../../src/TestScenarioEditor";
import { SceSimEditorWrapper, StorybookTestScenarioEditorProps } from
"../scesimEditorStoriesWrapper";
+export const trafficViolationDmnFileName = "TrafficViolation.scesim";
export const trafficViolationDmn = `<?xml version="1.0" encoding="UTF-8"?>
<ScenarioSimulationModel version="1.8" xmlns="https://kie.org/scesim/1.8">
<simulation>
@@ -806,6 +807,7 @@ export const TrafficViolation: Story = {
render: (args) => SceSimEditorWrapper(args),
args: {
model: marshaller.parser.parse(),
+ openFileNormalizedPosixPathRelativeToTheWorkspaceRoot:
trafficViolationDmnFileName,
xml: marshaller.builder.build(model),
},
};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 23d9cdf6874..c799d568ed7 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9317,6 +9317,9 @@ importers:
'@kie-tools/boxed-expression-component':
specifier: workspace:*
version: link:../boxed-expression-component
+ '@kie-tools/dmn-marshaller':
+ specifier: workspace:*
+ version: link:../dmn-marshaller
'@kie-tools/i18n-common-dictionary':
specifier: workspace:*
version: link:../i18n-common-dictionary
@@ -9460,6 +9463,85 @@ importers:
specifier: ^5.9.0
version: 5.9.0
+ packages/scesim-editor-envelope:
+ dependencies:
+ '@kie-tools-core/editor':
+ specifier: workspace:*
+ version: link:../editor
+ '@kie-tools-core/envelope':
+ specifier: workspace:*
+ version: link:../envelope
+ '@kie-tools-core/envelope-bus':
+ specifier: workspace:*
+ version: link:../envelope-bus
+ '@kie-tools-core/keyboard-shortcuts':
+ specifier: workspace:*
+ version: link:../keyboard-shortcuts
+ '@kie-tools-core/notifications':
+ specifier: workspace:*
+ version: link:../notifications
+ '@kie-tools-core/react-hooks':
+ specifier: workspace:*
+ version: link:../react-hooks
+ '@kie-tools-core/workspace':
+ specifier: workspace:*
+ version: link:../workspace
+ '@kie-tools/boxed-expression-component':
+ specifier: workspace:*
+ version: link:../boxed-expression-component
+ '@kie-tools/dmn-marshaller':
+ specifier: workspace:*
+ version: link:../dmn-marshaller
+ '@kie-tools/scesim-editor':
+ specifier: workspace:*
+ version: link:../scesim-editor
+ '@kie-tools/scesim-marshaller':
+ specifier: workspace:*
+ version: link:../scesim-marshaller
+ '@kie-tools/xml-parser-ts':
+ specifier: workspace:*
+ version: link:../xml-parser-ts
+ '@patternfly/react-core':
+ specifier: ^4.276.6
+ version: 4.276.6([email protected]([email protected]))([email protected])
+ react:
+ specifier: '>=17.0.2 <19.0.0'
+ version: 17.0.2
+ react-dom:
+ specifier: '>=17.0.2 <19.0.0'
+ version: 17.0.2([email protected])
+ devDependencies:
+ '@babel/core':
+ specifier: ^7.16.0
+ version: 7.24.9
+ '@babel/preset-env':
+ specifier: ^7.16.0
+ version: 7.24.7(@babel/[email protected])
+ '@babel/preset-react':
+ specifier: ^7.16.0
+ version: 7.22.15(@babel/[email protected])
+ '@kie-tools/eslint':
+ specifier: workspace:*
+ version: link:../eslint
+ '@kie-tools/root-env':
+ specifier: workspace:*
+ version: link:../root-env
+ '@kie-tools/tsconfig':
+ specifier: workspace:*
+ version: link:../tsconfig
+ '@types/react':
+ specifier: ^17.0.6
+ version: 17.0.21
+ '@types/react-dom':
+ specifier: ^17.0.5
+ version: 17.0.8
+ rimraf:
+ specifier: ^3.0.2
+ version: 3.0.2
+ typescript:
+ specifier: ^5.5.3
+ version: 5.5.3
+
packages/scesim-marshaller:
dependencies:
'@kie-tools/xml-parser-ts':
diff --git a/repo/graph.dot b/repo/graph.dot
index 3ecfb0097fb..6d5c8fa636e 100644
--- a/repo/graph.dot
+++ b/repo/graph.dot
@@ -168,6 +168,7 @@ digraph G {
"@kie-tools/runtime-tools-swf-webapp-components" [ color = "blue", fontcolor
= "blue", style = "rounded" ];
"@kie-tools/scesim-editor" [ color = "blue", fontcolor = "blue", style =
"rounded" ];
"@kie-tools/scesim-marshaller" [ color = "blue", fontcolor = "blue", style =
"rounded" ];
+ "@kie-tools/scesim-editor-envelope" [ color = "blue", fontcolor = "blue",
style = "rounded" ];
"@kie-tools/serverless-logic-web-tools" [ color = "black", fontcolor =
"black", style = "dashed, rounded" ];
"@kie-tools/text-editor" [ color = "blue", fontcolor = "blue", style =
"rounded" ];
"@kie-tools/yard-editor" [ color = "blue", fontcolor = "blue", style =
"rounded" ];
@@ -534,6 +535,9 @@ digraph G {
"@kie-tools/runtime-tools-task-console-webapp" ->
"@kie-tools/runtime-tools-shared-webapp-components" [ style = "solid", color =
"blue" ];
"@kie-tools/scesim-editor" -> "@kie-tools/boxed-expression-component" [
style = "solid", color = "blue" ];
"@kie-tools/scesim-editor" -> "@kie-tools/scesim-marshaller" [ style =
"solid", color = "blue" ];
+ "@kie-tools/scesim-editor-envelope" -> "@kie-tools-core/editor" [ style =
"solid", color = "blue" ];
+ "@kie-tools/scesim-editor-envelope" -> "@kie-tools-core/react-hooks" [ style
= "solid", color = "blue" ];
+ "@kie-tools/scesim-editor-envelope" -> "@kie-tools/scesim-editor" [ style =
"solid", 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" ];
"@kie-tools/serverless-logic-web-tools" ->
"@kie-tools-core/workspaces-git-fs" [ style = "solid", color = "black" ];
diff --git a/repo/graph.json b/repo/graph.json
index 2cdd586225a..d7f93f2dcd1 100644
--- a/repo/graph.json
+++ b/repo/graph.json
@@ -176,6 +176,7 @@
{ "id": "@kie-tools/runtime-tools-swf-webapp-components" },
{ "id": "@kie-tools/scesim-editor" },
{ "id": "@kie-tools/scesim-marshaller" },
+ { "id": "@kie-tools/scesim-editor-envelope" },
{ "id": "@kie-tools/serverless-logic-web-tools" },
{ "id": "@kie-tools/text-editor" },
{ "id": "@kie-tools/yard-editor" },
@@ -2180,6 +2181,21 @@
"target": "@kie-tools/xml-parser-ts-codegen",
"weight": 1
},
+ {
+ "source": "@kie-tools/scesim-editor-envelope",
+ "target": "@kie-tools-core/editor",
+ "weight": 1
+ },
+ {
+ "source": "@kie-tools/scesim-editor-envelope",
+ "target": "@kie-tools-core/react-hooks",
+ "weight": 1
+ },
+ {
+ "source": "@kie-tools/scesim-editor-envelope",
+ "target": "@kie-tools/scesim-editor",
+ "weight": 1
+ },
{
"source": "@kie-tools/serverless-logic-web-tools",
"target": "@kie-tools-core/kubernetes-bridge",
@@ -2722,6 +2738,7 @@
["@kie-tools/runtime-tools-swf-webapp-components",
"packages/runtime-tools-swf-webapp-components"],
["@kie-tools/runtime-tools-task-console-webapp",
"packages/runtime-tools-task-console-webapp"],
["@kie-tools/scesim-editor", "packages/scesim-editor"],
+ ["@kie-tools/scesim-editor-envelope", "packages/scesim-editor-envelope"],
["@kie-tools/scesim-marshaller", "packages/scesim-marshaller"],
["@kie-tools/serverless-logic-web-tools",
"packages/serverless-logic-web-tools"],
[
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]