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

* Add the prev tasks selector

* fix CONDITIONS node bugs

* fix code smells
This commit is contained in:
Wangyizhi1 2021-09-09 20:36:39 +08:00 committed by GitHub
parent bcb1ccba6f
commit cca48d0a92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 244 additions and 186 deletions

View File

@ -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)
})
}
}
}

View File

@ -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
*/

View File

@ -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>

View File

@ -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',

View File

@ -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 () {

View File

@ -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 }