tiagobento commented on code in PR #3252:
URL: 
https://github.com/apache/incubator-kie-tools/pull/3252#discussion_r2335147025


##########
packages/swf-editor/env/index.js:
##########
@@ -0,0 +1,33 @@
+/*
+ * 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"), 
require("@kie-tools-core/webpack-base/env")], {
+  vars: varsWithName({}),
+  get env() {
+    return {
+      swfEditor: {
+        storybook: {
+          port: "9901",

Review Comment:
   Same port as other packages. Please find a port that's not being used yet.



##########
packages/swf-editor/src/store/Store.ts:
##########
@@ -0,0 +1,304 @@
+/*
+ * 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 { enableMapSet, immerable } from "immer";
+import * as RF from "reactflow";
+import { create } from "zustand";
+import { immer } from "zustand/middleware/immer";
+import { SwfDiagramNodeData } from "../diagram/nodes/SwfNodes";
+import { ComputedStateCache } from "./ComputedStateCache";
+import { computeDiagramData } from "./computed/computeDiagramData";
+import { computeIndexedSwf } from "./computed/computeIndexes";
+import { computeIsDropTargetNodeValidForSelection } from 
"./computed/computeIsDropTargetNodeValidForSelection";
+import { DEFAULT_VIEWPORT } from "../diagram/Diagram";
+
+import { Specification } from "@severlessworkflow/sdk-typescript";
+
+enableMapSet(); // Necessary because `Computed` has a lot of Maps and Sets.
+
+export interface SwfEditorDiagramNodeStatus {
+  selected: boolean;
+  dragging: boolean;
+}
+
+export interface SwfEditorDiagramEdgeStatus {
+  selected: boolean;
+  draggingWaypoint: boolean;
+}
+
+export interface SnapGrid {
+  isEnabled: boolean;
+  x: number;
+  y: number;
+}
+
+export type DropTargetNode = undefined | RF.Node<SwfDiagramNodeData>;
+
+export interface State {
+  dispatch: (s: State) => Dispatch;
+  computed: (s: State) => Computed;
+  layout: (s: State) => Layout;
+  swf: { model: Specification.Workflow };
+  focus: {
+    consumableId: string | undefined;
+  };
+  diagram: {
+    autoLayout: {
+      canAutoGenerate: boolean;
+    };
+    __unsafeSwfIndex: number;
+    edgeIdBeingUpdated: string | undefined;
+    dropTargetNode: DropTargetNode;
+    ongoingConnection: RF.OnConnectStartParams | undefined;
+    overlaysPanel: {
+      isOpen: boolean;
+    };
+    overlays: {
+      enableNodeHierarchyHighlight: boolean;
+      enableCustomNodeStyles: boolean;
+      enableEvaluationHighlights: boolean;

Review Comment:
   This value does not make sense for the SWF Editor.



##########
packages/swf-editor/src/swfUtils.ts:
##########
@@ -0,0 +1,39 @@
+/*
+ * 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 { v4 as uuid } from "uuid";
+import { SwfEdgeTypes } from "./diagram/graph/graph";
+
+/**
+ * Generates a UUID with a format similar to 
_6EFDBCB4-F4AF-4E9A-9A66-2A9F24185674
+ */
+export const generateUuid = () => {
+  return `_${uuid()}`.toLocaleUpperCase();
+};
+
+/**
+ * Build edge Id string based on source, target and edgeType
+ */
+export const buildEdgeId = (
+  source: string | undefined,
+  target: string | undefined,
+  edgeType: SwfEdgeTypes | undefined
+) => {
+  return source + "_" + target + "_" + edgeType?.toString();
+};

Review Comment:
   There's a folder `diagram/edges/`. Why not put this function there?



##########
packages/swf-editor/src/swfUtils.ts:
##########
@@ -0,0 +1,39 @@
+/*
+ * 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 { v4 as uuid } from "uuid";
+import { SwfEdgeTypes } from "./diagram/graph/graph";
+
+/**
+ * Generates a UUID with a format similar to 
_6EFDBCB4-F4AF-4E9A-9A66-2A9F24185674
+ */
+export const generateUuid = () => {
+  return `_${uuid()}`.toLocaleUpperCase();
+};
+
+/**
+ * Build edge Id string based on source, target and edgeType
+ */
+export const buildEdgeId = (
+  source: string | undefined,
+  target: string | undefined,
+  edgeType: SwfEdgeTypes | undefined
+) => {
+  return source + "_" + target + "_" + edgeType?.toString();
+};

Review Comment:
   I'm not a big fan of global "utils" files, as they tend age badly, grouping 
unrelated code into the same file, often creating unnecessary coupling and 
making our lives harder in the future when a refactor/modularization effort is 
necessary.



##########
packages/swf-editor/src/SwfEditor.tsx:
##########
@@ -0,0 +1,289 @@
+/*
+ * 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 "@patternfly/react-core/dist/styles/base.css";
+import "reactflow/dist/style.css";
+
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+import * as RF from "reactflow";
+import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from 
"react-error-boundary";
+import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, 
useState } from "react";
+//import { original } from "immer";
+import { Diagram, DiagramRef } from "./diagram/Diagram";
+import { SwfEditorContextProvider, useSwfEditor } from "./SwfEditorContext";
+import { SwfEditorErrorFallback } from "./SwfEditorErrorFallback";
+import { ComputedStateCache } from "./store/ComputedStateCache";
+import { Computed, createSwfEditorStore, defaultStaticState } from 
"./store/Store";
+import { SwfEditorStoreApiContext, StoreApiType, useSwfEditorStore, 
useSwfEditorStoreApi } from "./store/StoreContext";
+import { SwfDiagramSvg } from "./svg/SwfDiagramSvg";
+import { useEffectAfterFirstRender } from "./useEffectAfterFirstRender";
+import { INITIAL_COMPUTED_CACHE } from "./store/computed/initial";
+import "./SwfEditor.css"; // Leave it for last, as this overrides some of the 
PF and RF styles.
+import { Commands, CommandsContextProvider, useCommands } from 
"./commands/CommandsContextProvider";
+import { SwfEditorSettingsContextProvider } from 
"./settings/SwfEditorSettingsContext";
+import { Specification } from "@severlessworkflow/sdk-typescript";
+
+const ON_MODEL_CHANGE_DEBOUNCE_TIME_IN_MS = 500;
+
+const SVG_PADDING = 20;
+
+export type SwfEditorRef = {
+  reset: (mode: Specification.Workflow) => void;
+  getDiagramSvg: () => Promise<string | undefined>;
+  getCommands: () => Commands;
+};
+
+export type EvaluationResults = Record<string, any>;
+export type ValidationMessages = Record<string, any>;
+export type OnSwfModelChange = (model: Specification.Workflow) => void;
+
+export type OnRequestToJumpToPath = (normalizedPosixPathRelativeToTheOpenFile: 
string) => void;
+export type OnRequestToResolvePath = 
(normalizedPosixPathRelativeToTheOpenFile: string) => string;
+
+export type SwfEditorProps = {
+  /**
+   * The SWF itself.
+   */
+  model: Specification.Workflow;
+  /**
+   * Called when a change occurs on `model`, so the controlled flow of the 
component can be done.
+   */
+  onModelChange?: OnSwfModelChange;
+  /**
+   * To show information about execution results directly on the SWF diagram, 
use this prop.
+   */
+  evaluationResults?: EvaluationResults;
+  /**
+   * To show information about validation messages directly on the SWF 
diagram, use this prop.
+   */
+  validationMessages?: ValidationMessages;

Review Comment:
   Both do not belong in the SWF Editor.



##########
packages/swf-editor/src/marshallers/swfMarshaller.ts:
##########


Review Comment:
   Both new DMN and the upcoming BPMN Editor abstract the marshalling process 
away, purposefully, to couple itself only with the model's interfaces. Please 
consider the same strategy here. We don't want the editor to do any kind of 
heavy lifting when it comes to **file** formats. Graphical editors for DMN, 
BPMN, SWF, and whatever other format we might want to support in the future, 
IMHO, should not know the concept of a "file", let alone a "file format". By 
defining this hard boundary we can confidently keep the editors being 
Controlled Components, with easy to understand mechanics and expectations from 
our users.



##########
packages/swf-editor/src/store/Store.ts:
##########
@@ -0,0 +1,304 @@
+/*
+ * 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 { enableMapSet, immerable } from "immer";
+import * as RF from "reactflow";
+import { create } from "zustand";
+import { immer } from "zustand/middleware/immer";
+import { SwfDiagramNodeData } from "../diagram/nodes/SwfNodes";
+import { ComputedStateCache } from "./ComputedStateCache";
+import { computeDiagramData } from "./computed/computeDiagramData";
+import { computeIndexedSwf } from "./computed/computeIndexes";
+import { computeIsDropTargetNodeValidForSelection } from 
"./computed/computeIsDropTargetNodeValidForSelection";
+import { DEFAULT_VIEWPORT } from "../diagram/Diagram";
+
+import { Specification } from "@severlessworkflow/sdk-typescript";
+
+enableMapSet(); // Necessary because `Computed` has a lot of Maps and Sets.
+
+export interface SwfEditorDiagramNodeStatus {
+  selected: boolean;
+  dragging: boolean;
+}
+
+export interface SwfEditorDiagramEdgeStatus {
+  selected: boolean;
+  draggingWaypoint: boolean;
+}
+
+export interface SnapGrid {
+  isEnabled: boolean;
+  x: number;
+  y: number;
+}
+
+export type DropTargetNode = undefined | RF.Node<SwfDiagramNodeData>;
+
+export interface State {
+  dispatch: (s: State) => Dispatch;
+  computed: (s: State) => Computed;
+  layout: (s: State) => Layout;
+  swf: { model: Specification.Workflow };
+  focus: {
+    consumableId: string | undefined;
+  };
+  diagram: {
+    autoLayout: {
+      canAutoGenerate: boolean;
+    };
+    __unsafeSwfIndex: number;
+    edgeIdBeingUpdated: string | undefined;
+    dropTargetNode: DropTargetNode;
+    ongoingConnection: RF.OnConnectStartParams | undefined;
+    overlaysPanel: {
+      isOpen: boolean;
+    };
+    overlays: {
+      enableNodeHierarchyHighlight: boolean;
+      enableCustomNodeStyles: boolean;
+      enableEvaluationHighlights: boolean;

Review Comment:
   It's a DMN-specific thing for Decision Tables and Boxed Conditionals.



##########
packages/swf-editor/src/evaluationHighlights/EvaluationHighlightsBadge.tsx:
##########


Review Comment:
   This file and folder do not belong in the SWF Editor. Please see the other 
comment about the same feature.



##########
packages/swf-editor/src/mutations/renameNode.ts:
##########
@@ -0,0 +1,37 @@
+/*
+ * 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 { Specification } from "@severlessworkflow/sdk-typescript";
+
+// TODO: we need to update all references to ID/Name if we want to change a 
name.

Review Comment:
   Maybe map this TODO in a new issue? I remember there's an Epic for the new 
SWF Editor, no?



##########
packages/swf-editor/src/SwfEditor.tsx:
##########
@@ -0,0 +1,289 @@
+/*
+ * 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 "@patternfly/react-core/dist/styles/base.css";
+import "reactflow/dist/style.css";
+
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+import * as RF from "reactflow";
+import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from 
"react-error-boundary";
+import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, 
useState } from "react";
+//import { original } from "immer";
+import { Diagram, DiagramRef } from "./diagram/Diagram";
+import { SwfEditorContextProvider, useSwfEditor } from "./SwfEditorContext";
+import { SwfEditorErrorFallback } from "./SwfEditorErrorFallback";
+import { ComputedStateCache } from "./store/ComputedStateCache";
+import { Computed, createSwfEditorStore, defaultStaticState } from 
"./store/Store";
+import { SwfEditorStoreApiContext, StoreApiType, useSwfEditorStore, 
useSwfEditorStoreApi } from "./store/StoreContext";
+import { SwfDiagramSvg } from "./svg/SwfDiagramSvg";
+import { useEffectAfterFirstRender } from "./useEffectAfterFirstRender";
+import { INITIAL_COMPUTED_CACHE } from "./store/computed/initial";
+import "./SwfEditor.css"; // Leave it for last, as this overrides some of the 
PF and RF styles.

Review Comment:
   Shouldn't it be the last import?



##########
packages/swf-editor/src/SwfEditor.tsx:
##########
@@ -0,0 +1,289 @@
+/*
+ * 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 "@patternfly/react-core/dist/styles/base.css";
+import "reactflow/dist/style.css";
+
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+import * as RF from "reactflow";
+import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from 
"react-error-boundary";
+import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, 
useState } from "react";
+//import { original } from "immer";
+import { Diagram, DiagramRef } from "./diagram/Diagram";
+import { SwfEditorContextProvider, useSwfEditor } from "./SwfEditorContext";
+import { SwfEditorErrorFallback } from "./SwfEditorErrorFallback";
+import { ComputedStateCache } from "./store/ComputedStateCache";
+import { Computed, createSwfEditorStore, defaultStaticState } from 
"./store/Store";
+import { SwfEditorStoreApiContext, StoreApiType, useSwfEditorStore, 
useSwfEditorStoreApi } from "./store/StoreContext";
+import { SwfDiagramSvg } from "./svg/SwfDiagramSvg";
+import { useEffectAfterFirstRender } from "./useEffectAfterFirstRender";
+import { INITIAL_COMPUTED_CACHE } from "./store/computed/initial";
+import "./SwfEditor.css"; // Leave it for last, as this overrides some of the 
PF and RF styles.
+import { Commands, CommandsContextProvider, useCommands } from 
"./commands/CommandsContextProvider";
+import { SwfEditorSettingsContextProvider } from 
"./settings/SwfEditorSettingsContext";
+import { Specification } from "@severlessworkflow/sdk-typescript";
+
+const ON_MODEL_CHANGE_DEBOUNCE_TIME_IN_MS = 500;
+
+const SVG_PADDING = 20;
+
+export type SwfEditorRef = {
+  reset: (mode: Specification.Workflow) => void;
+  getDiagramSvg: () => Promise<string | undefined>;
+  getCommands: () => Commands;
+};
+
+export type EvaluationResults = Record<string, any>;
+export type ValidationMessages = Record<string, any>;
+export type OnSwfModelChange = (model: Specification.Workflow) => void;
+
+export type OnRequestToJumpToPath = (normalizedPosixPathRelativeToTheOpenFile: 
string) => void;
+export type OnRequestToResolvePath = 
(normalizedPosixPathRelativeToTheOpenFile: string) => string;
+
+export type SwfEditorProps = {
+  /**
+   * The SWF itself.
+   */
+  model: Specification.Workflow;
+  /**
+   * Called when a change occurs on `model`, so the controlled flow of the 
component can be done.
+   */
+  onModelChange?: OnSwfModelChange;
+  /**
+   * To show information about execution results directly on the SWF diagram, 
use this prop.
+   */
+  evaluationResults?: EvaluationResults;
+  /**
+   * To show information about validation messages directly on the SWF 
diagram, use this prop.
+   */
+  validationMessages?: ValidationMessages;
+  /**
+   * A link that will take users to an issue tracker so they can report 
problems they find on the SWF Editor.
+   * This is shown on the ErrorBoundary fallback component, when an uncaught 
error happens.
+   */
+  issueTrackerHref?: string;
+  /**
+   * A flag to enable read-only mode on the SWF Editor.
+   * When enabled navigation is still possible,
+   * but no changes can be made and the model itself is unaltered.
+   */
+  isReadOnly?: boolean;
+  /**
+   * 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 SWF 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;
+  /**
+   * Notifies the caller when the SWF Editor performs a new edit after the 
debounce time.
+   */
+  onModelDebounceStateChanged?: (changed: boolean) => void;
+};
+
+export const SwfEditorInternal = ({
+  model,
+  onModelChange,
+  onModelDebounceStateChanged,
+  forwardRef,
+}: SwfEditorProps & { forwardRef?: React.Ref<SwfEditorRef> }) => {
+  const swf = useSwfEditorStore((s) => s.swf);
+  const isDiagramEditingInProgress = useSwfEditorStore((s) => 
s.computed(s).isDiagramEditingInProgress());
+  const swfEditorStoreApi = useSwfEditorStoreApi();
+  const { commandsRef } = useCommands();
+
+  const { swfModelBeforeEditingRef, swfEditorRootElementRef } = useSwfEditor();
+
+  // Refs
+  const diagramRef = useRef<DiagramRef>(null);
+  const diagramContainerRef = useRef<HTMLDivElement>(null);
+
+  // Allow imperativelly controlling the Editor.
+  useImperativeHandle(
+    forwardRef,
+    () => ({
+      reset: (model) => {
+        const state = swfEditorStoreApi.getState();
+        return state.dispatch(state).swf.reset(model);
+      },
+      getDiagramSvg: async () => {
+        const nodes = diagramRef.current?.getReactFlowInstance()?.getNodes();
+        const edges = diagramRef.current?.getReactFlowInstance()?.getEdges();
+        if (!nodes || !edges) {
+          return undefined;
+        }
+
+        const bounds = RF.getNodesBounds(nodes);
+        const state = swfEditorStoreApi.getState();
+
+        const svg = document.createElementNS("http://www.w3.org/2000/svg";, 
"svg");
+        svg.setAttribute("width", bounds.width + SVG_PADDING * 2 + "");
+        svg.setAttribute("height", bounds.height + SVG_PADDING * 2 + "");
+
+        // We're still on React 17.
+        // eslint-disable-next-line react/no-deprecated
+        ReactDOM.render(
+          // Indepdent of where the nodes are located, they'll always be 
rendered at the top-left corner of the SVG
+          <g transform={`translate(${-bounds.x + SVG_PADDING} ${-bounds.y + 
SVG_PADDING})`}>
+            <SwfDiagramSvg nodes={nodes} edges={edges} 
snapGrid={state.diagram.snapGrid} thisSwf={state.swf} />
+          </g>,
+          svg
+        );
+
+        return new XMLSerializer().serializeToString(svg);
+      },
+      getCommands: () => commandsRef.current,
+    }),
+    [swfEditorStoreApi, commandsRef]
+  );
+
+  // Make sure the SWF Editor reacts to props changing.
+  useEffectAfterFirstRender(() => {
+    swfEditorStoreApi.setState((state) => {
+      // Avoid unecessary state updates
+      // if (model === original(state.swf.model)) {
+      //   return;
+      // }
+      // TODO: Swf model is not immerable so a draft cannot be created
+      // Consider the possibility of adding immerable to all sdk mddel classes
+      // Comparing strings as workaround
+      if (JSON.stringify(model) === JSON.stringify(state.swf.model)) {
+        return;
+      }

Review Comment:
   What makes the model not "immerable"? Maybe it's not suited to be a state 
too?



##########
packages/swf-editor/stories/dev/DevWebApp.stories.tsx:
##########
@@ -0,0 +1,253 @@
+/*
+ * 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, useRef, useState } from "react";
+import type { Meta, StoryObj } from "@storybook/react";
+import "@patternfly/react-core/dist/styles/base.css";
+import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
+import { Page, PageSection } from 
"@patternfly/react-core/dist/js/components/Page";
+import { SwfEditorWrapper } from "../swfEditorStoriesWrapper";
+import { SwfEditorProps, OnSwfModelChange, OnRequestToJumpToPath } from 
"../../src/SwfEditor";
+import { Specification } from "@severlessworkflow/sdk-typescript";
+import { Marshaller, getMarshaller, serializeSwf } from 
"../../src/marshallers/swfMarshaller";

Review Comment:
   This import going a little too far back? :D Why go outside the `src` folder 
just to re-enter it?



##########
packages/swf-editor/src/SwfEditor.tsx:
##########
@@ -0,0 +1,289 @@
+/*
+ * 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 "@patternfly/react-core/dist/styles/base.css";
+import "reactflow/dist/style.css";
+
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+import * as RF from "reactflow";
+import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from 
"react-error-boundary";
+import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, 
useState } from "react";
+//import { original } from "immer";
+import { Diagram, DiagramRef } from "./diagram/Diagram";
+import { SwfEditorContextProvider, useSwfEditor } from "./SwfEditorContext";
+import { SwfEditorErrorFallback } from "./SwfEditorErrorFallback";
+import { ComputedStateCache } from "./store/ComputedStateCache";
+import { Computed, createSwfEditorStore, defaultStaticState } from 
"./store/Store";
+import { SwfEditorStoreApiContext, StoreApiType, useSwfEditorStore, 
useSwfEditorStoreApi } from "./store/StoreContext";
+import { SwfDiagramSvg } from "./svg/SwfDiagramSvg";
+import { useEffectAfterFirstRender } from "./useEffectAfterFirstRender";
+import { INITIAL_COMPUTED_CACHE } from "./store/computed/initial";
+import "./SwfEditor.css"; // Leave it for last, as this overrides some of the 
PF and RF styles.
+import { Commands, CommandsContextProvider, useCommands } from 
"./commands/CommandsContextProvider";
+import { SwfEditorSettingsContextProvider } from 
"./settings/SwfEditorSettingsContext";
+import { Specification } from "@severlessworkflow/sdk-typescript";
+
+const ON_MODEL_CHANGE_DEBOUNCE_TIME_IN_MS = 500;
+
+const SVG_PADDING = 20;
+
+export type SwfEditorRef = {
+  reset: (mode: Specification.Workflow) => void;
+  getDiagramSvg: () => Promise<string | undefined>;
+  getCommands: () => Commands;
+};
+
+export type EvaluationResults = Record<string, any>;
+export type ValidationMessages = Record<string, any>;
+export type OnSwfModelChange = (model: Specification.Workflow) => void;
+
+export type OnRequestToJumpToPath = (normalizedPosixPathRelativeToTheOpenFile: 
string) => void;
+export type OnRequestToResolvePath = 
(normalizedPosixPathRelativeToTheOpenFile: string) => string;
+
+export type SwfEditorProps = {
+  /**
+   * The SWF itself.
+   */
+  model: Specification.Workflow;
+  /**
+   * Called when a change occurs on `model`, so the controlled flow of the 
component can be done.
+   */
+  onModelChange?: OnSwfModelChange;
+  /**
+   * To show information about execution results directly on the SWF diagram, 
use this prop.
+   */
+  evaluationResults?: EvaluationResults;
+  /**
+   * To show information about validation messages directly on the SWF 
diagram, use this prop.
+   */
+  validationMessages?: ValidationMessages;
+  /**
+   * A link that will take users to an issue tracker so they can report 
problems they find on the SWF Editor.
+   * This is shown on the ErrorBoundary fallback component, when an uncaught 
error happens.
+   */
+  issueTrackerHref?: string;
+  /**
+   * A flag to enable read-only mode on the SWF Editor.
+   * When enabled navigation is still possible,
+   * but no changes can be made and the model itself is unaltered.
+   */
+  isReadOnly?: boolean;
+  /**
+   * 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 SWF 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;
+  /**
+   * Notifies the caller when the SWF Editor performs a new edit after the 
debounce time.
+   */
+  onModelDebounceStateChanged?: (changed: boolean) => void;

Review Comment:
   Are those being used? I'd like to avoid having dead-code introduced from the 
start.



##########
packages/swf-editor/src/store/Store.ts:
##########
@@ -0,0 +1,304 @@
+/*
+ * 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 { enableMapSet, immerable } from "immer";
+import * as RF from "reactflow";
+import { create } from "zustand";
+import { immer } from "zustand/middleware/immer";
+import { SwfDiagramNodeData } from "../diagram/nodes/SwfNodes";
+import { ComputedStateCache } from "./ComputedStateCache";
+import { computeDiagramData } from "./computed/computeDiagramData";
+import { computeIndexedSwf } from "./computed/computeIndexes";
+import { computeIsDropTargetNodeValidForSelection } from 
"./computed/computeIsDropTargetNodeValidForSelection";
+import { DEFAULT_VIEWPORT } from "../diagram/Diagram";
+
+import { Specification } from "@severlessworkflow/sdk-typescript";
+
+enableMapSet(); // Necessary because `Computed` has a lot of Maps and Sets.
+
+export interface SwfEditorDiagramNodeStatus {
+  selected: boolean;
+  dragging: boolean;
+}
+
+export interface SwfEditorDiagramEdgeStatus {
+  selected: boolean;
+  draggingWaypoint: boolean;
+}
+
+export interface SnapGrid {
+  isEnabled: boolean;
+  x: number;
+  y: number;
+}
+
+export type DropTargetNode = undefined | RF.Node<SwfDiagramNodeData>;
+
+export interface State {
+  dispatch: (s: State) => Dispatch;
+  computed: (s: State) => Computed;
+  layout: (s: State) => Layout;
+  swf: { model: Specification.Workflow };
+  focus: {
+    consumableId: string | undefined;
+  };
+  diagram: {
+    autoLayout: {
+      canAutoGenerate: boolean;
+    };
+    __unsafeSwfIndex: number;
+    edgeIdBeingUpdated: string | undefined;
+    dropTargetNode: DropTargetNode;
+    ongoingConnection: RF.OnConnectStartParams | undefined;
+    overlaysPanel: {
+      isOpen: boolean;
+    };
+    overlays: {
+      enableNodeHierarchyHighlight: boolean;
+      enableCustomNodeStyles: boolean;
+      enableEvaluationHighlights: boolean;
+    };
+    snapGrid: SnapGrid;
+    nodesPosition: NodesPosition;
+    edgesWaypoints: EdgesWaypoints;
+    _selectedNodes: Array<string>;
+    _selectedEdges: Array<string>;
+    draggingNodes: Array<string>;
+    draggingWaypoints: Array<string>;
+    isEditingStyle: boolean;
+    viewport: {
+      x: number;
+      y: number;
+      zoom: number;
+    };
+  };
+}
+
+// Read this to understand why we need computed as part of the store.
+// https://github.com/pmndrs/zustand/issues/132#issuecomment-1120467721
+export type Computed = {
+  isDiagramEditingInProgress(): boolean;
+
+  indexedSwf(): ReturnType<typeof computeIndexedSwf>;
+
+  getDiagramData(requiresLayout?: boolean): ReturnType<typeof 
computeDiagramData>;
+
+  isDropTargetNodeValidForSelection(): boolean;
+};
+
+//Handle layout data out of the model
+export type Layout = {
+  setNodePosition: (nodeId: string, newPosition: RF.XYPosition | undefined) => 
void;
+  setEdgeWaypoints: (edgeId: string, newWaypoints: RF.XYPosition[] | 
undefined) => void;
+  updateWaypointPosition: (edgeId: string, index: number, newPosition: 
RF.XYPosition | undefined) => void;
+};
+
+export class NodesPosition {
+  // Handle node position out of the model
+  [immerable] = false;

Review Comment:
   What does this do?



##########
packages/swf-editor/src/SwfEditor.tsx:
##########
@@ -0,0 +1,289 @@
+/*
+ * 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 "@patternfly/react-core/dist/styles/base.css";
+import "reactflow/dist/style.css";
+
+import * as React from "react";
+import * as ReactDOM from "react-dom";
+import * as RF from "reactflow";
+import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from 
"react-error-boundary";
+import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, 
useState } from "react";
+//import { original } from "immer";

Review Comment:
   Why?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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


Reply via email to