Browse Source

[Feature][JsonSplit-api] Improve some dag/formModel features (#6144)

* Add the prev tasks selector

* fix CONDITIONS node bugs

* fix code smells
Wangyizhi1 3 years ago
parent
commit
cca48d0a92

+ 121 - 22
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/canvas/canvas.vue

@@ -16,14 +16,14 @@
  */
 <template>
   <div class="dag-canvas">
-    <dag-taskbar @on-drag-start="_onDragStart" />
+    <dag-taskbar @on-drag-start="onDragStart" />
     <div
       class="dag-container"
       ref="container"
       @dragenter.prevent
       @dragover.prevent
       @dragleave.prevent
-      @drop.stop.prevent="_onDrop"
+      @drop.stop.prevent="onDrop"
     >
       <div ref="paper" class="paper"></div>
       <div ref="minimap" class="minimap"></div>
@@ -52,7 +52,7 @@
   } from './x6-helper'
   import { DagreLayout } from '@antv/layout'
   import { tasksType, tasksState } from '../config'
-  import { mapActions, mapMutations } from 'vuex'
+  import { mapActions, mapMutations, mapState } from 'vuex'
   import nodeStatus from './nodeStatus'
 
   export default {
@@ -84,6 +84,11 @@
       dagTaskbar,
       contextMenu
     },
+    computed: {
+      ...mapState('dag', [
+        'tasks'
+      ])
+    },
     methods: {
       ...mapActions('dag', ['genTaskCodeList']),
       ...mapMutations('dag', ['removeTask']),
@@ -182,7 +187,7 @@
                   sourceId: Number(sourceCell.id),
                   targetId: Number(targetCell.id)
                 }
-                if (!self.dagChart.edgeIsValid(edgeData)) {
+                if (!self.edgeIsValid(edgeData)) {
                   return false
                 }
               }
@@ -211,8 +216,6 @@
             }
           }
         }))
-        // TODO will be deleted
-        window._graph = graph
         this.registerX6Shape()
         this.bindGraphEvent()
         this.originalScrollPosition = graph.getScrollbarPosition()
@@ -476,6 +479,7 @@
        * @return {Edge[]} Edge is inherited from the Cell
        */
       // interface Edge {
+      //   id: string;
       //   label: string;
       //   sourceId: number;
       //   targetId: number;
@@ -485,6 +489,7 @@
         return edges.map((edge) => {
           const labelData = edge.getLabelAt(0)
           return {
+            id: edge.id,
             label: _.get(labelData, ['attrs', 'label', 'text'], ''),
             sourceId: Number(edge.getSourceCellId()),
             targetId: Number(edge.getTargetCellId())
@@ -626,10 +631,9 @@
       },
       /**
        * remove an edge
-       * @param {string|number} id EdgeId
+       * @param {string} id EdgeId
        */
       removeEdge (id) {
-        id += ''
         this.graph.removeEdge(id)
       },
       /**
@@ -644,6 +648,19 @@
           }
         })
       },
+      /**
+       * Verify whether edge is valid
+       * The number of edges start with CONDITIONS task cannot be greater than 2
+       */
+      edgeIsValid (edge) {
+        const { sourceId } = edge
+        const sourceTask = this.tasks.find((task) => task.code === sourceId)
+        if (sourceTask.taskType === 'CONDITIONS') {
+          const edges = this.getEdges()
+          return edges.filter((e) => e.sourceId === sourceTask.code).length <= 2
+        }
+        return true
+      },
       /**
        * Gets the current selections
        * @return {Cell[]}
@@ -687,7 +704,7 @@
       /**
        * Drag && Drop Event
        */
-      _onDragStart (e, taskType) {
+      onDragStart (e, taskType) {
         if (!this.editable) {
           e.preventDefault()
           return
@@ -698,6 +715,21 @@
           type: taskType.name
         }
       },
+      onDrop (e) {
+        const { type } = this.dragging
+        const { x, y } = this.calcGraphCoordinate(e.clientX, e.clientY)
+        this.genTaskCodeList({
+          genNum: 1
+        })
+          .then((res) => {
+            const [code] = res
+            this.addNode(code, type, { x, y })
+            this.dagChart.openFormModel(code, type)
+          })
+          .catch((err) => {
+            console.error(err)
+          })
+      },
       calcGraphCoordinate (mClientX, mClientY) {
         // Distance from the mouse to the top-left corner of the container;
         const { left: cX, top: cY } =
@@ -719,20 +751,87 @@
           y: mouseY + scrollY - eY
         }
       },
-      _onDrop (e) {
-        const { type } = this.dragging
-        const { x, y } = this.calcGraphCoordinate(e.clientX, e.clientY)
-        this.genTaskCodeList({
-          genNum: 1
+      /**
+       * Get prev nodes by code
+       * @param {number} code
+       * node1 -> node2 -> node3
+       * getPrevNodes(node2.code) => [node1]
+       */
+      getPrevNodes (code) {
+        const nodes = this.getNodes()
+        const edges = this.getEdges()
+        const nodesMap = {}
+        nodes.forEach(node => {
+          nodesMap[node.id] = node
+        })
+        return edges
+          .filter(edge => edge.targetId === code)
+          .map(edge => nodesMap[edge.sourceId])
+      },
+      /**
+       * set prev nodes
+       * @param {number} code
+       * @param {number[]} preNodeCodes
+       * @param {boolean} override If set to true, setPreNodes will delete all edges that end with the node and rebuild
+       */
+      setPreNodes (code, preNodeCodes, override) {
+        const edges = this.getEdges()
+        const currPreCodes = []
+        edges.forEach((edge) => {
+          if (edge.targetId === code) {
+            if (override) {
+              this.removeEdge(edge.id)
+            } else {
+              currPreCodes.push(edge.sourceId)
+            }
+          }
+        })
+        preNodeCodes.forEach(preCode => {
+          if (currPreCodes.includes(preCode) || preCode === code) return
+          const edge = this.genEdgeJSON(preCode, code)
+          this.graph.addEdge(edge)
+        })
+      },
+      /**
+       * Get post nodes by code
+       * @param {number} code
+       * node1 -> node2 -> node3
+       * getPostNodes(node2.code) => [node3]
+       */
+      getPostNodes (code) {
+        const nodes = this.getNodes()
+        const edges = this.getEdges()
+        const nodesMap = {}
+        nodes.forEach(node => {
+          nodesMap[node.id] = node
+        })
+        return edges
+          .filter(edge => edge.sourceId === code)
+          .map(edge => nodesMap[edge.targetId])
+      },
+      /**
+       * set post nodes
+       * @param {number} code
+       * @param {number[]} postNodeCodes
+       * @param {boolean} override If set to true, setPreNodes will delete all edges that end with the node and rebuild
+       */
+      setPostNodes (code, postNodeCodes, override) {
+        const edges = this.getEdges()
+        const currPostCodes = []
+        edges.forEach((edge) => {
+          if (edge.sourceId === code) {
+            if (override) {
+              this.removeEdge(edge.id)
+            } else {
+              currPostCodes.push(edge.targetId)
+            }
+          }
+        })
+        postNodeCodes.forEach(postCode => {
+          if (currPostCodes.includes(postCode) || postCode === code) return
+          const edge = this.genEdgeJSON(code, postCode)
+          this.graph.addEdge(edge)
         })
-          .then((res) => {
-            const [code] = res
-            this.addNode(code, type, { x, y })
-            this.dagChart.openFormModel(code, type)
-          })
-          .catch((err) => {
-            console.error(err)
-          })
       }
     }
   }

+ 18 - 23
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue

@@ -82,8 +82,6 @@
     id: null,
     taskType: '',
     self: {},
-    preNode: [],
-    rearList: [],
     instanceId: null
   }
 
@@ -139,8 +137,6 @@
       }
     },
     mounted () {
-      window._debug = this
-
       if (this.type === 'instance') {
         this.definitionCode = this.$route.query.code
       } else if (this.type === 'definition') {
@@ -420,19 +416,31 @@
           tasksMap[task.code] = task
         })
 
-        return tasks.map((task) => {
-          const preTask = preTaskMap[task.code]
+        const headEdges = tasks.filter(task => !preTaskMap[task.code]).map((task) => {
           return {
-            name: preTask ? preTask.edgeLabel : '',
-            preTaskCode: preTask ? preTask.sourceId : 0,
-            preTaskVersion: preTask ? tasksMap[preTask.sourceId].version : 0,
+            name: '',
+            preTaskCode: 0,
+            preTaskVersion: 0,
             postTaskCode: task.code,
-            postTaskVersion: tasksMap[task.code].version || 0,
+            postTaskVersion: task.version || 0,
             // conditionType and conditionParams are reserved
             conditionType: 0,
             conditionParams: {}
           }
         })
+
+        return edges.map(edge => {
+          return {
+            name: edge.label,
+            preTaskCode: edge.sourceId,
+            preTaskVersion: tasksMap[edge.sourceId].version || 0,
+            postTaskCode: edge.targetId,
+            postTaskVersion: tasksMap[edge.targetId].version || 0,
+            // conditionType and conditionParams are reserved
+            conditionType: 0,
+            conditionParams: {}
+          }
+        }).concat(headEdges)
       },
       backfill () {
         const tasks = this.tasks
@@ -496,19 +504,6 @@
       closeStart () {
         this.startDialog = false
       },
-      /**
-       * Verify whether edge is valid
-       * The number of edges start with CONDITIONS task cannot be greater than 2
-       */
-      edgeIsValid (edge) {
-        const { sourceId } = edge
-        const sourceTask = this.tasks.find((task) => task.code === sourceId)
-        if (sourceTask.taskType === 'CONDITIONS') {
-          const edges = this.$refs.canvas.getEdges()
-          return edges.filter((e) => e.sourceId === sourceTask.code).length <= 2
-        }
-        return true
-      },
       /**
        * Task status
        */

+ 55 - 79
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue

@@ -123,8 +123,8 @@
               </el-select>
             </span>
             <span class="text-b" style="padding-left: 38px">{{$t('Branch flow')}}</span>
-            <el-select style="width: 157px;" size="small" v-model="successBranch" clearable>
-              <el-option v-for="item in nodeData.rearList" :key="item.value" :value="item.value" :label="item.label"></el-option>
+            <el-select style="width: 157px;" size="small" v-model="successBranch" clearable :disabled="isDetails">
+              <el-option v-for="item in postTasks" :key="item.code" :value="item.name" :label="item.name"></el-option>
             </el-select>
           </div>
         </m-list-box>
@@ -137,8 +137,8 @@
               </el-select>
             </span>
             <span class="text-b" style="padding-left: 38px">{{$t('Branch flow')}}</span>
-            <el-select style="width: 157px;" size="small" v-model="failedBranch" clearable>
-              <el-option v-for="item in nodeData.rearList" :key="item.value" :value="item.value" :label="item.label"></el-option>
+            <el-select style="width: 157px;" size="small" v-model="failedBranch" clearable :disabled="isDetails">
+              <el-option v-for="item in postTasks" :key="item.code" :value="item.name" :label="item.name"></el-option>
             </el-select>
           </div>
         </m-list-box>
@@ -266,7 +266,7 @@
           @on-dependent="_onDependent"
           @on-cache-dependent="_onCacheDependent"
           :backfill-item="backfillItem"
-          :pre-node="nodeData.preNode">
+          :prev-tasks="prevTasks">
         </m-conditions>
         <m-switch
           v-if="nodeData.taskType === 'SWITCH'"
@@ -276,12 +276,7 @@
           :nodeData="nodeData"
         ></m-switch>
         <!-- Pre-tasks in workflow -->
-        <!-- TODO -->
-        <!-- <m-pre-tasks
-          v-if="['SHELL', 'SUB_PROCESS'].indexOf(nodeData.taskType) > -1"
-          @on-pre-tasks="_onPreTasks"
-          ref="PRE_TASK"
-          :backfill-item="backfillItem"></m-pre-tasks> -->
+        <m-pre-tasks ref="preTasks" v-if="['SHELL', 'SUB_PROCESS'].indexOf(nodeData.taskType) > -1" :code="code"/>
       </div>
     </div>
     <div class="bottom-box">
@@ -317,11 +312,12 @@
   import mTimeoutAlarm from './_source/timeoutAlarm'
   import mDependentTimeout from './_source/dependentTimeout'
   import mWorkerGroups from './_source/workerGroups'
-  // import mPreTasks from './tasks/pre_tasks'
   import mRelatedEnvironment from './_source/relatedEnvironment'
+  import mPreTasks from './tasks/pre_tasks'
   import clickoutside from '@/module/util/clickoutside'
   import disabledState from '@/module/mixin/disabledState'
   import mPriority from '@/module/components/priority/priority'
+  import { findComponentDownward } from '@/module/util/'
 
   export default {
     name: 'form-model',
@@ -352,7 +348,7 @@
         // cache dependence
         cacheDependence: {},
         // task code
-        code: '',
+        code: 0,
         // Current node params data
         params: {},
         // Running sign
@@ -386,10 +382,9 @@
             label: `${i18n.$t('Failed')}`
           }
         ],
-        // preTasks
-        preTaskIdsInWorkflow: [],
-        preTasksToAdd: [], // pre-taskIds to add, used in jsplumb connects
-        preTasksToDelete: [] // pre-taskIds to delete, used in jsplumb connects
+        // for CONDITIONS
+        postTasks: [],
+        prevTasks: []
       }
     },
     /**
@@ -400,6 +395,7 @@
     props: {
       nodeData: Object
     },
+    inject: ['dagChart'],
     methods: {
       ...mapActions('dag', ['getTaskInstanceList']),
       taskToBackfillItem (task) {
@@ -413,7 +409,6 @@
           maxRetryTimes: task.failRetryTimes,
           name: task.name,
           params: _.omit(task.taskParams, ['conditionResult', 'dependence']),
-          preTasks: [],
           retryInterval: task.failRetryInterval,
           runFlag: task.flag,
           taskInstancePriority: task.taskPriority,
@@ -423,7 +418,7 @@
             enable: task.timeoutFlag === 'OPEN'
           },
           type: task.taskType,
-          waitStartTimeout: task.waitStartTimeout,
+          waitStartTimeout: task.taskParams.waitStartTimeout,
           workerGroup: task.workerGroup
         }
       },
@@ -436,14 +431,6 @@
       _onSwitchResult (o) {
         this.switchResult = o
       },
-      /**
-       * Pre-tasks in workflow
-       */
-      _onPreTasks (o) {
-        this.preTaskIdsInWorkflow = o.preTasks
-        this.preTasksToAdd = o.preTasksToAdd
-        this.preTasksToDelete = o.preTasksToDelete
-      },
       /**
        * cache dependent
        */
@@ -515,41 +502,14 @@
       _onParams (o) {
         this.params = Object.assign({}, o)
       },
-      _onCacheParams (o) {
-        this.params = Object.assign(this.params, {}, o)
-        this._cacheItem()
-      },
       _onUpdateEnvironmentCode (o) {
         this.environmentCode = o
       },
-      _cacheItem () {
-        this.conditionResult.successNode[0] = this.successBranch
-        this.conditionResult.failedNode[0] = this.failedBranch
-        this.$emit('cacheTaskInfo', {
-          item: {
-            type: this.nodeData.taskType,
-            id: this.nodeData.id,
-            name: this.name,
-            code: this.code,
-            params: this.params,
-            desc: this.desc,
-            runFlag: this.runFlag,
-            conditionResult: this.conditionResult,
-            switchResult: this.switchResult,
-            dependence: this.cacheDependence,
-            maxRetryTimes: this.maxRetryTimes,
-            retryInterval: this.retryInterval,
-            delayTime: this.delayTime,
-            timeout: this.timeout,
-            waitStartTimeout: this.waitStartTimeout,
-            taskInstancePriority: this.taskInstancePriority,
-            workerGroup: this.workerGroup,
-            environmentCode: this.environmentCode,
-            status: this.status,
-            branch: this.branch
-          },
-          fromThis: this
-        })
+      /**
+       * _onCacheParams is reserved
+       */
+      _onCacheParams (o) {
+        this.params = Object.assign(this.params, {}, o)
       },
       /**
        * verification name
@@ -607,19 +567,13 @@
             return
           }
         }
-
         // Verify node parameters
         if (!this.$refs[this.nodeData.taskType]._verification()) {
           return
         }
-        // Verify preTasks and update dag-things
-        if (this.$refs.PRE_TASK) {
-          if (!this.$refs.PRE_TASK._verification()) {
-            return
-          } else {
-            // TODO sync preTasks to graph
-
-          }
+        // set preTask
+        if (this.$refs.preTasks) {
+          this.$refs.preTasks.setPreNodes()
         }
         this.conditionResult.successNode[0] = this.successBranch
         this.conditionResult.failedNode[0] = this.failedBranch
@@ -632,7 +586,8 @@
             taskParams: {
               ...this.params,
               dependence: this.cacheDependence,
-              conditionResult: this.conditionResult
+              conditionResult: this.conditionResult,
+              waitStartTimeout: this.waitStartTimeout
             },
             flag: this.runFlag,
             taskPriority: this.taskInstancePriority,
@@ -651,6 +606,8 @@
         })
         // set run flag
         this._setRunFlag()
+        // set edge label
+        this._setEdgeLabel()
       },
       /**
        * Sub-workflow selected node echo name
@@ -664,6 +621,21 @@
        */
       _setRunFlag () {
 
+      },
+      /**
+       *
+       */
+      _setEdgeLabel () {
+        if (this.successBranch || this.failedBranch) {
+          const canvas = findComponentDownward(this.dagChart, 'dag-canvas')
+          const edges = canvas.getEdges()
+          const successTask = this.postTasks.find(t => t.name === this.successBranch)
+          const failedTask = this.postTasks.find(t => t.name === this.failedBranch)
+          const sEdge = edges.find(edge => successTask && edge.sourceId === this.code && edge.targetId === successTask.code)
+          const fEdge = edges.find(edge => failedTask && edge.sourceId === this.code && edge.targetId === failedTask.code)
+          sEdge && canvas.setEdgeLabel(sEdge.id, this.$t('Success'))
+          fEdge && canvas.setEdgeLabel(fEdge.id, this.$t('Failed'))
+        }
       },
       /**
        * Submit verification
@@ -702,6 +674,7 @@
           }
         })
       }
+      this.code = this.nodeData.id
       // Non-null objects represent backfill
       if (!_.isEmpty(o)) {
         this.code = o.code
@@ -743,14 +716,17 @@
       this.cacheBackfillItem = JSON.parse(JSON.stringify(o))
       this.isContentBox = true
 
-      // Init value of preTask selector
-      let preTaskIds = $(`#${this.nodeData.id}`).attr('data-targetarr')
-      if (!_.isEmpty(this.backfillItem)) {
-        if (preTaskIds && preTaskIds.length) {
-          this.backfillItem.preTasks = preTaskIds.split(',')
-        } else {
-          this.backfillItem.preTasks = []
-        }
+      if (this.dagChart) {
+        const canvas = findComponentDownward(this.dagChart, 'dag-canvas')
+        const postNodes = canvas.getPostNodes(this.code)
+        const prevNodes = canvas.getPrevNodes(this.code)
+        const buildTask = (node) => ({
+          code: node.id,
+          name: node.data.taskName,
+          type: node.data.taskType
+        })
+        this.postTasks = postNodes.map(buildTask)
+        this.prevTasks = prevNodes.map(buildTask)
       }
     },
     mounted () {
@@ -809,8 +785,8 @@
       mDependentTimeout,
       mPriority,
       mWorkerGroups,
-      // mPreTasks
-      mRelatedEnvironment
+      mRelatedEnvironment,
+      mPreTasks
     }
   }
 </script>

+ 2 - 2
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/nodeStatus.vue

@@ -18,7 +18,7 @@
   <div class="dep-list-model">
     <div v-for="(el,$index) in dependItemList" :key='$index' class="list" @click="itemIndex = $index">
       <el-select style="width: 150px;" size="small" v-model="el.depTasks" :disabled="isDetails">
-        <el-option v-for="item in preNode" :key="item.value" :value="item.value" :label="item.label">
+        <el-option v-for="item in prevTasks" :key="item.code" :value="item.name" :label="item.name">
         </el-option>
       </el-select>
       <el-select style="width: 116px;" size="small" v-model="el.status" :disabled="isDetails">
@@ -65,7 +65,7 @@
       dependItemList: Array,
       index: Number,
       dependTaskList: Array,
-      preNode: Array
+      prevTasks: Array
     },
     model: {
       prop: 'dependItemList',

+ 2 - 4
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/conditions.vue

@@ -53,8 +53,7 @@
               @on-delete-all="_onDeleteAll"
               @getDependTaskList="getDependTaskList"
               :index="$index"
-              :rear-list = "rearList"
-              :pre-node = "preNode">
+              :prev-tasks="prevTasks">
             </m-node-status>
           </div>
         </div>
@@ -79,8 +78,7 @@
     mixins: [disabledState],
     props: {
       backfillItem: Object,
-      preNode: Array,
-      rearList: Array
+      prevTasks: Array
     },
     methods: {
       _addDep () {

+ 46 - 56
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/pre_tasks.vue

@@ -17,22 +17,22 @@
 <template>
   <div class="pre_tasks-model">
     <m-list-box>
-      <div slot="text">{{$t('Pre tasks')}}</div>
+      <div slot="text">{{ $t("Pre tasks") }}</div>
       <div slot="content">
         <el-select
-            ref="preTasksSelector"
-            style="width: 100%;"
-            filterable
-            multiple
-            size="small"
-            v-model="preTasks"
-            :disabled="isDetails"
-            :id="preTasksSelectorId">
+          style="width: 100%"
+          filterable
+          multiple
+          size="small"
+          v-model="preTasks"
+          :disabled="isDetails"
+        >
           <el-option
-              v-for="task in preTaskList"
-              :key="task.id"
-              :value="task.id"
-              :label="task.name">
+            v-for="task in options"
+            :key="task.code"
+            :value="task.code"
+            :label="task.name"
+          >
           </el-option>
         </el-select>
       </div>
@@ -42,65 +42,55 @@
 <script>
   import disabledState from '@/module/mixin/disabledState'
   import mListBox from './_source/listBox'
+  import { mapState } from 'vuex'
+  import { findComponentDownward } from '@/module/util/'
 
   export default {
     name: 'pre_tasks',
     mixins: [disabledState],
+    inject: ['dagChart'],
     props: {
-      backfillItem: Object
+      code: {
+        type: Number,
+        default: 0
+      }
     },
     data () {
       return {
-        preTasksSelectorId: '_preTasksSelectorId', // Refresh target vue-component by changing id
-        preTasks: [],
-        preTasksOld: []
+        options: [],
+        preTasks: []
       }
     },
     mounted () {
-      this.preTasks = this.backfillItem.preTasks || this.preTasks
-      this.preTasksOld = this.preTasks
-
-      // Refresh target vue-component by changing id
-      this.$nextTick(() => {
-        this.preTasksSelectorId = 'preTasksSelectorId'
+      const canvas = this.getDagCanvasRef()
+      const edges = canvas.getEdges()
+      this.options = this.tasks.filter((task) => {
+        // The current node cannot be used as the prev node
+        if (task.code === this.code) return false
+        // The number of edges start with CONDITIONS task cannot be greater than 2
+        if (task.taskType === 'CONDITIONS') {
+          return edges.filter((e) => e.sourceId === task.code).length < 2
+        }
+        return true
       })
+      this.preTasks = canvas.getPrevNodes(this.code).map(node => node.id)
     },
     computed: {
-      preTaskList: function () {
-        let currentTaskId = this.backfillItem.id || this.id
-        let cacheTasks = Object.assign({}, this.store.state.dag.tasks)
-        let keys = Object.keys(cacheTasks)
-        for (let i = 0; i < keys.length; i++) {
-          let key = keys[i]
-          if ((!cacheTasks[key].id || !cacheTasks[key].name) || (currentTaskId && cacheTasks[key].id === currentTaskId)) {
-            // Clean undefined and current task data
-            delete cacheTasks[key]
-          }
-        }
-
-        return cacheTasks
-      },
-      // preTaskIds used to create new connection
-      preTasksToAdd: function () {
-        let toAddTasks = this.preTasks.filter(taskId => {
-          return (this.preTasksOld.indexOf(taskId) === -1)
-        })
-        return toAddTasks
-      },
-      // preTaskIds used to delete connection
-      preTasksToDelete: function () {
-        return this.preTasksOld.filter(taskId => this.preTasks.indexOf(taskId) === -1)
-      }
+      ...mapState('dag', ['tasks'])
     },
     methods: {
-      // Pass data to parent-level to process dag
-      _verification () {
-        this.$emit('on-pre-tasks', {
-          preTasks: this.preTasks,
-          preTasksToAdd: this.preTasksToAdd,
-          preTasksToDelete: this.preTasksToDelete
-        })
-        return true
+      getDagCanvasRef () {
+        if (this.canvasRef) {
+          return this.canvasRef
+        } else {
+          const canvas = findComponentDownward(this.dagChart, 'dag-canvas')
+          this.canvasRef = canvas
+          return canvas
+        }
+      },
+      setPreNodes () {
+        const canvas = this.getDagCanvasRef()
+        canvas.setPreNodes(this.code, this.preTasks, true)
       }
     },
     components: { mListBox }