diff --git a/app/cdap/components/hydrator/components/Canvas/index.tsx b/app/cdap/components/hydrator/components/Canvas/index.tsx index afcb2487143..686988cb68a 100644 --- a/app/cdap/components/hydrator/components/Canvas/index.tsx +++ b/app/cdap/components/hydrator/components/Canvas/index.tsx @@ -56,6 +56,7 @@ import { IComment } from 'components/AbstractWidget/Comment/CommentConstants'; import IconSVG from 'components/shared/IconSVG'; import { copyToClipBoard } from 'services/Clipboard'; import { INodePosition, ISelectedElements } from './types'; +import { useDispatch, useSelector } from 'react-redux'; interface ICanvasProps { angularNodes: any; @@ -222,6 +223,10 @@ const Canvas = ({ return reactflowNode; }); }; + const {angularNodes2} = useSelector((state) => ({ + angularNodes2: state.nodesStore.nodes + })) + const dispatch = useDispatch(); const [nodes, setNodes, onNodesChange] = useNodesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]); @@ -380,14 +385,17 @@ const Canvas = ({ }; const updateNodesUIPosition = (node: Node) => { - updateNodePositions({ - id: node.data.node.id, - position: { - _uiPosition: { - top: node.position.y + 'px', - left: node.position.x + 'px', + dispatch({ + type: 'UPDATE_NODE_UI_POSITION', + payload: { + id: node.data.node.id, + position: { + _uiPosition: { + top: node.position.y + 'px', + left: node.position.x + 'px', + }, }, - }, + } }); }; @@ -417,9 +425,9 @@ const Canvas = ({ useEffect(() => { setNodes((nds) => { - return [].concat(getNodesForDisplay(getAngularNodes(), nds)); + return [].concat(getNodesForDisplay(angularNodes2, nds)); }); - }, [JSON.stringify(angularNodes), previewMode, metricsData]); + }, [JSON.stringify(angularNodes2), previewMode, metricsData]); useEffect(() => { setEdges(() => { diff --git a/app/cdap/components/hydrator/components/StudioRoutes/Studio.tsx b/app/cdap/components/hydrator/components/StudioRoutes/Studio.tsx index 84cf0d55b99..123c0036999 100644 --- a/app/cdap/components/hydrator/components/StudioRoutes/Studio.tsx +++ b/app/cdap/components/hydrator/components/StudioRoutes/Studio.tsx @@ -34,11 +34,11 @@ export interface IStudioCreateState { export const Studio = ({leftPanelCtrl, topPanelCtrl, canvasCtrl, dagCtrl, metadataExpanded}: IStudioCreateState) => { return ( -
+
- + -
-
+
); }; diff --git a/app/cdap/components/hydrator/reducers/DAGNodesStore.ts b/app/cdap/components/hydrator/reducers/DAGNodesStore.ts index e69de29bb2d..f88911491cb 100644 --- a/app/cdap/components/hydrator/reducers/DAGNodesStore.ts +++ b/app/cdap/components/hydrator/reducers/DAGNodesStore.ts @@ -0,0 +1,118 @@ +/* + * Copyright © 2023 Cask Data, Inc. + * + * Licensed 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 { createAction, createReducer, current } from '@reduxjs/toolkit'; +import { GLOBALS } from 'services/global-constants'; +import uuidV4 from 'uuid/v4'; +import { santizeStringForHTMLID } from 'services/helpers'; + +const addNode = createAction('ADD_NODE') +const updateNodeUIPosition = createAction('UPDATE_NODE_UI_POSITION') +const reset = createAction('LEFTPANELSTORE_RESET'); + +const getInitialState = () => { + return { + nodes: [], + connections: [], + activeNodeId: null, + currentSourceCount: 0, + currentTransformCount: 0, + currentSinkCount: 0, + canvasPanning: { + top: 0, + left: 0 + }, + } +} + +const setNodeInitialPosition = (config, state) => { + const canvasPanning = state.canvasPanning; + + const sourcePosition = { + top: 150 - canvasPanning.top, + left: (10/100 * document.documentElement.clientWidth) - canvasPanning.left + }; + const transformPosition = { + top: 150 - canvasPanning.top, + left: (30/100 * document.documentElement.clientWidth) - canvasPanning.left + }; + const sinkPosition = { + top: 150 - canvasPanning.top, + left: (50/100 * document.documentElement.clientWidth) - canvasPanning.left + }; + + const offset = 35; + + // set initial position + switch (GLOBALS.pluginConvert[config.type]) { + case 'source': + const sourceOffset = state.currentSourceCount * offset; + config._uiPosition = { + top: (sourcePosition.top + sourceOffset) + 'px', + left: (sourcePosition.left + sourceOffset) + 'px' + }; + break; + case 'sink': + const sinkOffset = state.currentSinkCount * offset; + config._uiPosition = { + top: (sinkPosition.top + sinkOffset) + 'px', + left: (sinkPosition.left + sinkOffset) + 'px' + }; + break; + default: + const transformOffset = state.currentTransformCount * offset; + config._uiPosition = { + top: (transformPosition.top + transformOffset) + 'px', + left: (transformPosition.left + transformOffset) + 'px' + }; + break; + } + if (!config.name) { + config.name = config.plugin.label + '-' + uuidV4(); + } + if (!config.id) { + config.id = santizeStringForHTMLID(config.plugin.label) + '-' + uuidV4(); + } + return config; +} + +export const nodeReducer = createReducer({ + ...getInitialState() +}, (builder) => { + builder.addCase(addNode, (state, action) => { + const config = setNodeInitialPosition(action.payload.config, state) + switch (GLOBALS.pluginConvert[config.type]) { + case 'source': + state.currentSourceCount++ + break; + case 'sink': + state.currentSinkCount++ + break; + default: + state.currentTransformCount++ + break; + } + state.nodes.push(config); + }) + .addCase(updateNodeUIPosition, (state, action) => { + const {id, position} = action.payload + const nodeToUpdate = state.nodes.filter(node => node.id === id)[0] + nodeToUpdate._uiPosition = position._uiPosition + }) + .addCase(reset, (state, action) => { + state = getInitialState() + }) +}) \ No newline at end of file diff --git a/app/cdap/components/hydrator/reducers/index.ts b/app/cdap/components/hydrator/reducers/index.ts index d1ad6cc72be..e10e143f330 100644 --- a/app/cdap/components/hydrator/reducers/index.ts +++ b/app/cdap/components/hydrator/reducers/index.ts @@ -15,6 +15,7 @@ */ import { configureStore } from '@reduxjs/toolkit'; import reduxThunk from 'redux-thunk'; +import { nodeReducer } from './DAGNodesStore'; import { pluginReducer, extensionsReducer, artifactReducer } from './leftPanelStore'; export const configureStores = configureStore({ @@ -22,6 +23,7 @@ export const configureStores = configureStore({ artifact: artifactReducer, extensions: extensionsReducer, plugins: pluginReducer, + nodesStore: nodeReducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: { diff --git a/app/directives/dag-plus/services/stores/nodes-store.js b/app/directives/dag-plus/services/stores/nodes-store.js index c0f17f50a2b..ab9fcbd5bf7 100644 --- a/app/directives/dag-plus/services/stores/nodes-store.js +++ b/app/directives/dag-plus/services/stores/nodes-store.js @@ -229,9 +229,9 @@ class DAGPlusPlusNodesStore { resetActiveNode() { this.state.activeNodeId = null; - angular.forEach(this.state.nodes, (node) => { - node.selected = false; - }); + // angular.forEach(this.state.nodes, (node) => { + // node.selected = false; + // }); this.emitChange(); } diff --git a/app/hydrator/controllers/create/leftpanel-ctrl.js b/app/hydrator/controllers/create/leftpanel-ctrl.js index 8b3a191245d..c1a8f69cbd2 100644 --- a/app/hydrator/controllers/create/leftpanel-ctrl.js +++ b/app/hydrator/controllers/create/leftpanel-ctrl.js @@ -502,6 +502,12 @@ export class HydratorPlusPlusLeftPanelCtrl { }; } this.DAGPlusPlusNodesActionsFactory.addNode(config); + this.ReactStores.dispatch({ + type: 'ADD_NODE', + payload: { + config + } + }) } }