[2.0.1-cherrypick][Improvement][UI] DAG page interaction optimization (#7137)
* [Feature-6918][UI] DAG page interaction optimization (#6919) * [Feature] Add grid layout and optimize DAG style * [Improvement] Add process definition status label and code optimization * [Feature] add DAG node search bar * [Feature] Add DAG scale bar * [Improvement] Open pre-tasks settings for all tasks * [Fix] Fix ut * [Fix] Replace /deep/ with ::v-deep * [Fix] Fix code smell * [Improvement-7092][UI] Optimize DAG to adapt to situations without locations (#7102)
This commit is contained in:
parent
e96a39f57c
commit
b2143c31e6
|
|
@ -34,14 +34,35 @@
|
|||
|
||||
.minimap {
|
||||
position: absolute;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
border: dashed 1px #e4e4e4;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.scale-slider{
|
||||
position: absolute;
|
||||
height: 140px;
|
||||
width: 70px;
|
||||
right: 0px;
|
||||
bottom: 140px;
|
||||
z-index: 9;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
::v-deep .el-slider__runway{
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.scale-title{
|
||||
position: absolute;
|
||||
top: -30px;
|
||||
left: 22px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu{
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
|
|
|
|||
|
|
@ -27,8 +27,21 @@
|
|||
>
|
||||
<div ref="paper" class="paper"></div>
|
||||
<div ref="minimap" class="minimap"></div>
|
||||
<div class="scale-slider">
|
||||
<span class="scale-title">{{$t('dagScale')}}</span>
|
||||
<el-slider
|
||||
v-model="scale"
|
||||
vertical
|
||||
:max="2"
|
||||
:min="0.2"
|
||||
:step="0.2"
|
||||
:marks="SCALE_MARKS"
|
||||
@input='scaleChange'
|
||||
/>
|
||||
</div>
|
||||
<context-menu ref="contextMenu" />
|
||||
</div>
|
||||
<layout-config-modal ref="layoutModal" @submit="format" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -37,23 +50,25 @@
|
|||
import { Graph, DataUri } from '@antv/x6'
|
||||
import dagTaskbar from './taskbar.vue'
|
||||
import contextMenu from './contextMenu.vue'
|
||||
import layoutConfigModal, { LAYOUT_TYPE, DEFAULT_LAYOUT_CONFIG } from './layoutConfigModal.vue'
|
||||
import {
|
||||
NODE_PROPS,
|
||||
EDGE_PROPS,
|
||||
PORT_PROPS,
|
||||
NODE,
|
||||
EDGE,
|
||||
X6_NODE_NAME,
|
||||
X6_PORT_OUT_NAME,
|
||||
X6_PORT_IN_NAME,
|
||||
X6_EDGE_NAME,
|
||||
NODE_HIGHLIGHT_PROPS,
|
||||
PORT_HIGHLIGHT_PROPS,
|
||||
EDGE_HIGHLIGHT_PROPS,
|
||||
NODE_STATUS_MARKUP
|
||||
} from './x6-helper'
|
||||
import { DagreLayout } from '@antv/layout'
|
||||
import { DagreLayout, GridLayout } from '@antv/layout'
|
||||
import { tasksType, tasksState } from '../config'
|
||||
import { mapActions, mapMutations, mapState } from 'vuex'
|
||||
import nodeStatus from './nodeStatus'
|
||||
import x6StyleMixin from './x6-style-mixin'
|
||||
|
||||
const SCALE_MARKS = {
|
||||
0.2: '0.2',
|
||||
1: '1',
|
||||
2: '2'
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'dag-canvas',
|
||||
|
|
@ -71,7 +86,10 @@
|
|||
x: 0,
|
||||
y: 0,
|
||||
type: ''
|
||||
}
|
||||
},
|
||||
// The canvas scale
|
||||
scale: 1,
|
||||
SCALE_MARKS
|
||||
}
|
||||
},
|
||||
provide () {
|
||||
|
|
@ -79,10 +97,12 @@
|
|||
dagCanvas: this
|
||||
}
|
||||
},
|
||||
mixins: [x6StyleMixin],
|
||||
inject: ['dagChart'],
|
||||
components: {
|
||||
dagTaskbar,
|
||||
contextMenu
|
||||
contextMenu,
|
||||
layoutConfigModal
|
||||
},
|
||||
computed: {
|
||||
...mapState('dag', ['tasks'])
|
||||
|
|
@ -118,6 +138,14 @@
|
|||
movable: true,
|
||||
showNodeSelectionBox: false
|
||||
},
|
||||
scaling: {
|
||||
min: 0.2,
|
||||
max: 2
|
||||
},
|
||||
mousewheel: {
|
||||
enabled: true,
|
||||
modifiers: ['ctrl', 'meta']
|
||||
},
|
||||
scroller: true,
|
||||
grid: {
|
||||
size: 10,
|
||||
|
|
@ -126,7 +154,10 @@
|
|||
snapline: true,
|
||||
minimap: {
|
||||
enabled: true,
|
||||
container: minimap
|
||||
container: minimap,
|
||||
scalable: false,
|
||||
width: 200,
|
||||
height: 120
|
||||
},
|
||||
interacting: {
|
||||
edgeLabelMovable: false,
|
||||
|
|
@ -134,9 +165,6 @@
|
|||
magnetConnectable: !!editable
|
||||
},
|
||||
connecting: {
|
||||
snap: {
|
||||
radius: 30
|
||||
},
|
||||
// Whether multiple edges can be created between the same start node and end
|
||||
allowMulti: false,
|
||||
// Whether a point is allowed to connect to a blank position on the canvas
|
||||
|
|
@ -148,32 +176,14 @@
|
|||
// Whether edges are allowed to link to nodes
|
||||
allowNode: true,
|
||||
// Whether to allow edge links to ports
|
||||
allowPort: true,
|
||||
allowPort: false,
|
||||
// Whether all available ports or nodes are highlighted when you drag the edge
|
||||
highlight: true,
|
||||
createEdge () {
|
||||
return graph.createEdge({ shape: X6_EDGE_NAME })
|
||||
},
|
||||
validateMagnet ({ magnet }) {
|
||||
return magnet.getAttribute('port-group') !== X6_PORT_IN_NAME
|
||||
},
|
||||
validateConnection (data) {
|
||||
const { sourceCell, targetCell, sourceMagnet, targetMagnet } = data
|
||||
// Connections can only be created from the output link post
|
||||
if (
|
||||
!sourceMagnet ||
|
||||
sourceMagnet.getAttribute('port-group') !== X6_PORT_OUT_NAME
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Can only be connected to the input link post
|
||||
if (
|
||||
!targetMagnet ||
|
||||
targetMagnet.getAttribute('port-group') !== X6_PORT_IN_NAME
|
||||
) {
|
||||
return false
|
||||
}
|
||||
const { sourceCell, targetCell } = data
|
||||
|
||||
if (
|
||||
sourceCell &&
|
||||
|
|
@ -214,6 +224,7 @@
|
|||
}
|
||||
}
|
||||
}))
|
||||
|
||||
this.registerX6Shape()
|
||||
this.bindGraphEvent()
|
||||
this.originalScrollPosition = graph.getScrollbarPosition()
|
||||
|
|
@ -224,37 +235,17 @@
|
|||
registerX6Shape () {
|
||||
Graph.unregisterNode(X6_NODE_NAME)
|
||||
Graph.unregisterEdge(X6_EDGE_NAME)
|
||||
Graph.registerNode(X6_NODE_NAME, { ...NODE_PROPS })
|
||||
Graph.registerEdge(X6_EDGE_NAME, { ...EDGE_PROPS })
|
||||
Graph.registerNode(X6_NODE_NAME, { ...NODE })
|
||||
Graph.registerEdge(X6_EDGE_NAME, { ...EDGE })
|
||||
},
|
||||
/**
|
||||
* Bind grap event
|
||||
*/
|
||||
bindGraphEvent () {
|
||||
// nodes and edges hover
|
||||
this.graph.on('cell:mouseenter', (data) => {
|
||||
const { cell, e } = data
|
||||
const isStatusIcon = (tagName) =>
|
||||
tagName &&
|
||||
(tagName.toLocaleLowerCase() === 'em' ||
|
||||
tagName.toLocaleLowerCase() === 'body')
|
||||
if (!isStatusIcon(e.target.tagName)) {
|
||||
this.setHighlight(cell)
|
||||
}
|
||||
})
|
||||
this.graph.on('cell:mouseleave', ({ cell }) => {
|
||||
if (!this.graph.isSelected(cell)) {
|
||||
this.resetHighlight(cell)
|
||||
}
|
||||
})
|
||||
// select
|
||||
this.graph.on('cell:selected', ({ cell }) => {
|
||||
this.setHighlight(cell)
|
||||
})
|
||||
this.graph.on('cell:unselected', ({ cell }) => {
|
||||
if (!this.graph.isSelected(cell)) {
|
||||
this.resetHighlight(cell)
|
||||
}
|
||||
this.bindStyleEvent(this.graph)
|
||||
// update scale bar
|
||||
this.graph.on('scale', ({ sx }) => {
|
||||
this.scale = sx
|
||||
})
|
||||
// right click
|
||||
this.graph.on('node:contextmenu', ({ x, y, cell }) => {
|
||||
|
|
@ -279,6 +270,13 @@
|
|||
label: labelName
|
||||
})
|
||||
})
|
||||
// Make sure the edge starts with node, not port
|
||||
this.graph.on('edge:connected', ({ isNew, edge }) => {
|
||||
if (isNew) {
|
||||
const sourceNode = edge.getSourceNode()
|
||||
edge.setSource(sourceNode)
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @param {Edge|string} edge
|
||||
|
|
@ -297,9 +295,6 @@
|
|||
setEdgeLabel (id, label) {
|
||||
const edge = this.graph.getCellById(id)
|
||||
edge.setLabels(label)
|
||||
if (this.graph.isSelected(edge)) {
|
||||
this.setEdgeHighlight(edge)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {number} limit
|
||||
|
|
@ -348,94 +343,6 @@
|
|||
node.setData({ taskName: name })
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Set node highlight
|
||||
* @param {Node} node
|
||||
*/
|
||||
setNodeHighlight (node) {
|
||||
const url = require(`../images/task-icos/${node.data.taskType.toLocaleLowerCase()}_hover.png`)
|
||||
node.setAttrs(NODE_HIGHLIGHT_PROPS.attrs)
|
||||
node.setAttrByPath('image/xlink:href', url)
|
||||
node.setPortProp(
|
||||
X6_PORT_OUT_NAME,
|
||||
'attrs',
|
||||
PORT_HIGHLIGHT_PROPS[X6_PORT_OUT_NAME].attrs
|
||||
)
|
||||
},
|
||||
/**
|
||||
* Reset node style
|
||||
* @param {Node} node
|
||||
*/
|
||||
resetNodeStyle (node) {
|
||||
const url = require(`../images/task-icos/${node.data.taskType.toLocaleLowerCase()}.png`)
|
||||
node.setAttrs(NODE_PROPS.attrs)
|
||||
node.setAttrByPath('image/xlink:href', url)
|
||||
node.setPortProp(
|
||||
X6_PORT_OUT_NAME,
|
||||
'attrs',
|
||||
PORT_PROPS.groups[X6_PORT_OUT_NAME].attrs
|
||||
)
|
||||
},
|
||||
/**
|
||||
* Set edge highlight
|
||||
* @param {Edge} edge
|
||||
*/
|
||||
setEdgeHighlight (edge) {
|
||||
const labelName = this.getEdgeLabelName(edge)
|
||||
edge.setAttrs(EDGE_HIGHLIGHT_PROPS.attrs)
|
||||
edge.setLabels([
|
||||
_.merge(
|
||||
{
|
||||
attrs: _.cloneDeep(EDGE_HIGHLIGHT_PROPS.defaultLabel.attrs)
|
||||
},
|
||||
{
|
||||
attrs: { label: { text: labelName } }
|
||||
}
|
||||
)
|
||||
])
|
||||
},
|
||||
/**
|
||||
* Reset edge style
|
||||
* @param {Edge} edge
|
||||
*/
|
||||
resetEdgeStyle (edge) {
|
||||
const labelName = this.getEdgeLabelName(edge)
|
||||
edge.setAttrs(EDGE_PROPS.attrs)
|
||||
edge.setLabels([
|
||||
{
|
||||
..._.merge(
|
||||
{
|
||||
attrs: _.cloneDeep(EDGE_PROPS.defaultLabel.attrs)
|
||||
},
|
||||
{
|
||||
attrs: { label: { text: labelName } }
|
||||
}
|
||||
)
|
||||
}
|
||||
])
|
||||
},
|
||||
/**
|
||||
* Set cell highlight
|
||||
* @param {Cell} cell
|
||||
*/
|
||||
setHighlight (cell) {
|
||||
if (cell.isEdge()) {
|
||||
this.setEdgeHighlight(cell)
|
||||
} else if (cell.isNode()) {
|
||||
this.setNodeHighlight(cell)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Reset cell highlight
|
||||
* @param {Cell} cell
|
||||
*/
|
||||
resetHighlight (cell) {
|
||||
if (cell.isEdge()) {
|
||||
this.resetEdgeStyle(cell)
|
||||
} else if (cell.isNode()) {
|
||||
this.resetNodeStyle(cell)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Convert the graph to JSON
|
||||
* @return {{cells:Cell[]}}
|
||||
|
|
@ -512,38 +419,70 @@
|
|||
}
|
||||
)
|
||||
},
|
||||
showLayoutModal () {
|
||||
const layoutModal = this.$refs.layoutModal
|
||||
if (layoutModal) {
|
||||
layoutModal.show()
|
||||
}
|
||||
},
|
||||
/**
|
||||
* format
|
||||
* @desc Auto layout use @antv/layout
|
||||
*/
|
||||
format () {
|
||||
const dagreLayout = new DagreLayout({
|
||||
type: 'dagre',
|
||||
rankdir: 'LR',
|
||||
align: 'UL',
|
||||
// Calculate the node spacing based on the edge label length
|
||||
ranksepFunc: (d) => {
|
||||
const edges = this.graph.getOutgoingEdges(d.id)
|
||||
let max = 0
|
||||
if (edges && edges.length > 0) {
|
||||
edges.forEach((edge) => {
|
||||
const edgeView = this.graph.findViewByCell(edge)
|
||||
const labelWidth = +edgeView.findAttr(
|
||||
'width',
|
||||
_.get(edgeView, ['labelSelectors', '0', 'body'], null)
|
||||
)
|
||||
max = Math.max(max, labelWidth)
|
||||
})
|
||||
}
|
||||
return 50 + max
|
||||
},
|
||||
nodesep: 50,
|
||||
controlPoints: true
|
||||
})
|
||||
format (layoutConfig) {
|
||||
if (!layoutConfig) {
|
||||
layoutConfig = DEFAULT_LAYOUT_CONFIG
|
||||
}
|
||||
this.graph.cleanSelection()
|
||||
|
||||
let layoutFunc = null
|
||||
if (layoutConfig.type === LAYOUT_TYPE.DAGRE) {
|
||||
layoutFunc = new DagreLayout({
|
||||
type: LAYOUT_TYPE.DAGRE,
|
||||
rankdir: 'LR',
|
||||
align: 'UL',
|
||||
// Calculate the node spacing based on the edge label length
|
||||
ranksepFunc: (d) => {
|
||||
const edges = this.graph.getOutgoingEdges(d.id)
|
||||
let max = 0
|
||||
if (edges && edges.length > 0) {
|
||||
edges.forEach((edge) => {
|
||||
const edgeView = this.graph.findViewByCell(edge)
|
||||
const labelWidth = +edgeView.findAttr(
|
||||
'width',
|
||||
_.get(edgeView, ['labelSelectors', '0', 'body'], null)
|
||||
)
|
||||
max = Math.max(max, labelWidth)
|
||||
})
|
||||
}
|
||||
return layoutConfig.ranksep + max
|
||||
},
|
||||
nodesep: layoutConfig.nodesep,
|
||||
controlPoints: true
|
||||
})
|
||||
} else if (layoutConfig.type === LAYOUT_TYPE.GRID) {
|
||||
layoutFunc = new GridLayout({
|
||||
type: LAYOUT_TYPE.GRID,
|
||||
preventOverlap: true,
|
||||
preventOverlapPadding: layoutConfig.padding,
|
||||
sortBy: '_index',
|
||||
rows: layoutConfig.rows || undefined,
|
||||
cols: layoutConfig.cols || undefined,
|
||||
nodeSize: 220
|
||||
})
|
||||
}
|
||||
const json = this.toJSON()
|
||||
const nodes = json.cells.filter((cell) => cell.shape === X6_NODE_NAME)
|
||||
const nodes = json.cells
|
||||
.filter((cell) => cell.shape === X6_NODE_NAME)
|
||||
.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
// sort by code aesc
|
||||
_index: -item.id
|
||||
}
|
||||
})
|
||||
const edges = json.cells.filter((cell) => cell.shape === X6_EDGE_NAME)
|
||||
const newModel = dagreLayout.layout({
|
||||
const newModel = layoutFunc.layout({
|
||||
nodes: nodes,
|
||||
edges: edges
|
||||
})
|
||||
|
|
@ -606,12 +545,10 @@
|
|||
return {
|
||||
shape: X6_EDGE_NAME,
|
||||
source: {
|
||||
cell: sourceId,
|
||||
port: X6_PORT_OUT_NAME
|
||||
cell: sourceId
|
||||
},
|
||||
target: {
|
||||
cell: targetId,
|
||||
port: X6_PORT_IN_NAME
|
||||
cell: targetId
|
||||
},
|
||||
labels: label ? [label] : undefined
|
||||
}
|
||||
|
|
@ -688,7 +625,7 @@
|
|||
if (node) {
|
||||
// Destroy the previous dom
|
||||
node.removeMarkup()
|
||||
node.setMarkup(NODE_PROPS.markup.concat(NODE_STATUS_MARKUP))
|
||||
node.setMarkup(NODE.markup.concat(NODE_STATUS_MARKUP))
|
||||
const nodeView = this.graph.findViewByCell(node)
|
||||
const el = nodeView.find('div')[0]
|
||||
nodeStatus({
|
||||
|
|
@ -828,6 +765,28 @@
|
|||
const edge = this.genEdgeJSON(code, postCode)
|
||||
this.graph.addEdge(edge)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* Navigate to cell
|
||||
* @param {string} taskName
|
||||
*/
|
||||
navigateTo (taskName) {
|
||||
const nodes = this.getNodes()
|
||||
nodes.forEach((node) => {
|
||||
if (node.data.taskName === taskName) {
|
||||
const id = node.id
|
||||
const cell = this.graph.getCellById(id)
|
||||
this.graph.scrollToCell(cell, { animation: { duration: 600 } })
|
||||
this.graph.cleanSelection()
|
||||
this.graph.select(cell)
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* Canvas scale
|
||||
*/
|
||||
scaleChange (val) {
|
||||
this.graph.zoomTo(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="$t('Format DAG')"
|
||||
:visible.sync="visible"
|
||||
width="500px"
|
||||
class="dag-layout-modal"
|
||||
:append-to-body="true"
|
||||
>
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="form"
|
||||
label-width="100px"
|
||||
class="dag-layout-form"
|
||||
>
|
||||
<el-form-item :label="$t('layoutType')">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio label="grid">{{ $t("gridLayout") }}</el-radio>
|
||||
<el-radio label="dagre">{{ $t("dagreLayout") }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('rows')" v-if="form.type === LAYOUT_TYPE.GRID">
|
||||
<el-input-number
|
||||
v-model="form.rows"
|
||||
:min="0"
|
||||
size="small"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('cols')" v-if="form.type === LAYOUT_TYPE.GRID">
|
||||
<el-input-number
|
||||
v-model="form.cols"
|
||||
:min="0"
|
||||
size="small"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click="close">{{ $t("Cancel") }}</el-button>
|
||||
<el-button size="small" type="primary" @click="submit">{{
|
||||
$t("Confirm")
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
export const LAYOUT_TYPE = {
|
||||
GRID: 'grid',
|
||||
DAGRE: 'dagre'
|
||||
}
|
||||
|
||||
export const DEFAULT_LAYOUT_CONFIG = {
|
||||
cols: 0,
|
||||
nodesep: 50,
|
||||
padding: 50,
|
||||
ranksep: 50,
|
||||
rows: 0,
|
||||
type: LAYOUT_TYPE.DAGRE
|
||||
}
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
visible: false,
|
||||
form: { ...DEFAULT_LAYOUT_CONFIG },
|
||||
LAYOUT_TYPE
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
show () {
|
||||
this.visible = true
|
||||
},
|
||||
close () {
|
||||
this.visible = false
|
||||
},
|
||||
submit () {
|
||||
this.$emit('submit', this.form)
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.dag-layout-modal {
|
||||
::v-deep .el-dialog__header {
|
||||
border-bottom: solid 1px #d4d4d4;
|
||||
}
|
||||
|
||||
::v-deep .dag-layout-form {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
::v-deep .el-radio {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -174,6 +174,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled{
|
||||
cursor: default
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@
|
|||
<draggable-box
|
||||
:key="taskType.name"
|
||||
@onDragstart="(e) => $emit('on-drag-start', e, taskType)"
|
||||
:class="{
|
||||
disabled: isDetails
|
||||
}"
|
||||
>
|
||||
<div class="task-item">
|
||||
<em :class="`icos-${taskType.name.toLocaleLowerCase()}`"></em>
|
||||
|
|
@ -38,6 +41,7 @@
|
|||
<script>
|
||||
import draggableBox from './draggableBox.vue'
|
||||
import { tasksType } from '../config.js'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'dag-taskbar',
|
||||
|
|
@ -55,6 +59,11 @@
|
|||
return {
|
||||
tasksTypeList
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('dag', [
|
||||
'isDetails'
|
||||
])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -110,4 +110,18 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.process-online-tag{
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.search-box{
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
transition: all 0.5s;
|
||||
|
||||
&.visible{
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,61 +23,82 @@
|
|||
:content="$t('Copy name')"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="el-icon-copy-document" @click="copyName"></i>
|
||||
<em class="el-icon-copy-document" @click="copyName"></em>
|
||||
</el-tooltip>
|
||||
<textarea ref="textarea" cols="30" rows="10" class="transparent"></textarea>
|
||||
<div class="toolbar-left">
|
||||
<el-tag
|
||||
class="process-online-tag"
|
||||
size="small"
|
||||
v-if="dagChart.type === 'definition' && releaseState === 'ONLINE'"
|
||||
>{{ $t("processOnline") }}</el-tag
|
||||
>
|
||||
<el-tooltip
|
||||
:content="$t('View variables')"
|
||||
placement="bottom"
|
||||
class="toolbar-operation"
|
||||
>
|
||||
<i
|
||||
<em
|
||||
class="custom-ico view-variables"
|
||||
v-if="$route.name === 'projects-instance-details'"
|
||||
@click="toggleVariableView"
|
||||
></i>
|
||||
></em>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
:content="$t('Startup parameter')"
|
||||
placement="bottom"
|
||||
class="toolbar-operation"
|
||||
>
|
||||
<i
|
||||
<em
|
||||
class="custom-ico startup-parameters"
|
||||
v-if="$route.name === 'projects-instance-details'"
|
||||
@click="toggleParamView"
|
||||
></i>
|
||||
></em>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<el-tooltip
|
||||
class="toolbar-operation"
|
||||
:content="$t('searchNode')"
|
||||
placement="bottom"
|
||||
v-if="!searchInputVisible"
|
||||
>
|
||||
<em
|
||||
class="el-icon-search"
|
||||
@click="showSearchInput"
|
||||
></em>
|
||||
</el-tooltip>
|
||||
<div
|
||||
:class="{
|
||||
'search-box': true,
|
||||
'visible': searchInputVisible
|
||||
}"
|
||||
>
|
||||
<el-input
|
||||
v-model="searchText"
|
||||
placeholder=""
|
||||
prefix-icon="el-icon-search"
|
||||
size="mini"
|
||||
@keyup.enter.native="onSearch"
|
||||
clearable
|
||||
@blur="searchInputBlur"
|
||||
ref="searchInput"
|
||||
></el-input>
|
||||
</div>
|
||||
<el-tooltip
|
||||
class="toolbar-operation"
|
||||
:content="$t('Delete selected lines or nodes')"
|
||||
placement="bottom"
|
||||
v-if="!isDetails"
|
||||
>
|
||||
<i class="el-icon-delete" @click="removeCells"></i>
|
||||
<em class="el-icon-delete" @click="removeCells"></em>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
class="toolbar-operation"
|
||||
:content="$t('Download')"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="el-icon-download" @click="downloadPNG"></i>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
class="toolbar-operation"
|
||||
:content="$t('Full Screen')"
|
||||
placement="bottom"
|
||||
>
|
||||
<i
|
||||
:class="[
|
||||
'custom-ico',
|
||||
dagChart.fullScreen ? 'full-screen-close' : 'full-screen-open',
|
||||
]"
|
||||
@click="toggleFullScreen"
|
||||
></i>
|
||||
<em class="el-icon-download" @click="downloadPNG"></em>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
class="toolbar-operation"
|
||||
|
|
@ -85,14 +106,28 @@
|
|||
placement="bottom"
|
||||
v-if="dagChart.type === 'instance'"
|
||||
>
|
||||
<i class="el-icon-refresh" @click="refreshTaskStatus"></i>
|
||||
<em class="el-icon-refresh" @click="refreshTaskStatus"></em>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
class="toolbar-operation"
|
||||
:content="$t('Format DAG')"
|
||||
placement="bottom"
|
||||
v-if="!isDetails"
|
||||
>
|
||||
<em class="custom-ico graph-format" @click="chartFormat"></em>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
class="toolbar-operation last"
|
||||
:content="$t('Format DAG')"
|
||||
:content="$t('Full Screen')"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="custom-ico graph-format" @click="chartFormat"></i>
|
||||
<em
|
||||
:class="[
|
||||
'custom-ico',
|
||||
dagChart.fullScreen ? 'full-screen-close' : 'full-screen-open',
|
||||
]"
|
||||
@click="toggleFullScreen"
|
||||
></em>
|
||||
</el-tooltip>
|
||||
<el-button
|
||||
class="toolbar-el-btn"
|
||||
|
|
@ -101,7 +136,7 @@
|
|||
v-if="dagChart.type === 'definition'"
|
||||
@click="showVersions"
|
||||
icon="el-icon-info"
|
||||
>{{$t('Version Info')}}</el-button
|
||||
>{{ $t("Version Info") }}</el-button
|
||||
>
|
||||
<el-button
|
||||
class="toolbar-el-btn"
|
||||
|
|
@ -125,7 +160,6 @@
|
|||
type="primary"
|
||||
icon="el-icon-switch-button"
|
||||
size="mini"
|
||||
v-if="type === 'instance' || 'definition'"
|
||||
@click="returnToListPage"
|
||||
>
|
||||
{{ $t("Close") }}
|
||||
|
|
@ -143,15 +177,28 @@
|
|||
inject: ['dagChart'],
|
||||
data () {
|
||||
return {
|
||||
canvasRef: null
|
||||
canvasRef: null,
|
||||
searchText: '',
|
||||
searchInputVisible: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('dag', [
|
||||
'isDetails'
|
||||
])
|
||||
...mapState('dag', ['isDetails', 'releaseState'])
|
||||
},
|
||||
methods: {
|
||||
onSearch () {
|
||||
const canvas = this.getDagCanvasRef()
|
||||
canvas.navigateTo(this.searchText)
|
||||
},
|
||||
showSearchInput () {
|
||||
this.searchInputVisible = true
|
||||
this.$refs.searchInput.focus()
|
||||
},
|
||||
searchInputBlur () {
|
||||
if (!this.searchText) {
|
||||
this.searchInputVisible = false
|
||||
}
|
||||
},
|
||||
getDagCanvasRef () {
|
||||
if (this.canvasRef) {
|
||||
return this.canvasRef
|
||||
|
|
@ -200,7 +247,7 @@
|
|||
},
|
||||
chartFormat () {
|
||||
const canvas = this.getDagCanvasRef()
|
||||
canvas.format()
|
||||
canvas.showLayoutModal()
|
||||
},
|
||||
refreshTaskStatus () {
|
||||
this.dagChart.refreshTaskStatus()
|
||||
|
|
|
|||
|
|
@ -17,16 +17,17 @@
|
|||
export const X6_NODE_NAME = 'dag-task'
|
||||
export const X6_EDGE_NAME = 'dag-edge'
|
||||
export const X6_PORT_OUT_NAME = 'dag-port-out'
|
||||
export const X6_PORT_IN_NAME = 'dag-port-in'
|
||||
|
||||
const EDGE = '#999999'
|
||||
const BG_BLUE = 'rgba(40, 143, 255, 0.1)'
|
||||
const EDGE_COLOR = '#999999'
|
||||
const BG_BLUE = '#DFE9F7'
|
||||
const BG_WHITE = '#FFFFFF'
|
||||
const NODE_BORDER = '#e4e4e4'
|
||||
const TITLE = '#333'
|
||||
const NODE_BORDER = '#CCCCCC'
|
||||
const TITLE = '#333333'
|
||||
const STROKE_BLUE = '#288FFF'
|
||||
const NODE_SHADOW = 'drop-shadow(3px 3px 4px rgba(0, 0, 0, 0.2))'
|
||||
const EDGE_SHADOW = 'drop-shadow(3px 3px 2px rgba(0, 0, 0, 0.2))'
|
||||
|
||||
export const PORT_PROPS = {
|
||||
export const PORT = {
|
||||
groups: {
|
||||
[X6_PORT_OUT_NAME]: {
|
||||
position: {
|
||||
|
|
@ -62,14 +63,14 @@ export const PORT_PROPS = {
|
|||
},
|
||||
'plus-text': {
|
||||
fontSize: 12,
|
||||
fill: EDGE,
|
||||
fill: NODE_BORDER,
|
||||
text: '+',
|
||||
textAnchor: 'middle',
|
||||
x: 0,
|
||||
y: 3
|
||||
},
|
||||
'circle-outer': {
|
||||
stroke: EDGE,
|
||||
stroke: NODE_BORDER,
|
||||
strokeWidth: 1,
|
||||
r: 6,
|
||||
fill: BG_WHITE
|
||||
|
|
@ -79,57 +80,42 @@ export const PORT_PROPS = {
|
|||
fill: 'transparent'
|
||||
}
|
||||
}
|
||||
},
|
||||
[X6_PORT_IN_NAME]: {
|
||||
position: {
|
||||
name: 'absolute',
|
||||
args: {
|
||||
x: 0,
|
||||
y: 24
|
||||
}
|
||||
},
|
||||
markup: [
|
||||
{
|
||||
tagName: 'g',
|
||||
selector: 'body',
|
||||
className: 'in-port-body',
|
||||
children: [{
|
||||
tagName: 'circle',
|
||||
selector: 'circle',
|
||||
className: 'circle'
|
||||
}]
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const PORT_HOVER = {
|
||||
groups: {
|
||||
[X6_PORT_OUT_NAME]: {
|
||||
attrs: {
|
||||
body: {
|
||||
magnet: true
|
||||
'circle-outer': {
|
||||
stroke: STROKE_BLUE,
|
||||
fill: BG_BLUE,
|
||||
r: 8
|
||||
},
|
||||
circle: {
|
||||
r: 4,
|
||||
strokeWidth: 0,
|
||||
fill: 'transparent'
|
||||
'circle-inner': {
|
||||
fill: STROKE_BLUE,
|
||||
r: 6
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const PORT_HIGHLIGHT_PROPS = {
|
||||
[X6_PORT_OUT_NAME]: {
|
||||
attrs: {
|
||||
'circle-outer': {
|
||||
stroke: STROKE_BLUE,
|
||||
fill: BG_BLUE
|
||||
},
|
||||
'plus-text': {
|
||||
fill: STROKE_BLUE
|
||||
},
|
||||
'circle-inner': {
|
||||
fill: STROKE_BLUE
|
||||
export const PORT_SELECTED = {
|
||||
groups: {
|
||||
[X6_PORT_OUT_NAME]: {
|
||||
attrs: {
|
||||
'plus-text': {
|
||||
fill: STROKE_BLUE
|
||||
},
|
||||
'circle-outer': {
|
||||
stroke: STROKE_BLUE,
|
||||
fill: BG_WHITE
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[X6_PORT_IN_NAME]: {}
|
||||
}
|
||||
}
|
||||
|
||||
export const NODE_STATUS_MARKUP = [{
|
||||
|
|
@ -148,13 +134,14 @@ export const NODE_STATUS_MARKUP = [{
|
|||
]
|
||||
}]
|
||||
|
||||
export const NODE_PROPS = {
|
||||
export const NODE = {
|
||||
width: 220,
|
||||
height: 48,
|
||||
markup: [
|
||||
{
|
||||
tagName: 'rect',
|
||||
selector: 'body'
|
||||
selector: 'body',
|
||||
className: 'dag-task-body'
|
||||
},
|
||||
{
|
||||
tagName: 'image',
|
||||
|
|
@ -174,7 +161,9 @@ export const NODE_PROPS = {
|
|||
pointerEvents: 'visiblePainted',
|
||||
fill: BG_WHITE,
|
||||
stroke: NODE_BORDER,
|
||||
strokeWidth: 1
|
||||
strokeWidth: 1,
|
||||
strokeDasharray: 'none',
|
||||
filter: 'none'
|
||||
},
|
||||
image: {
|
||||
width: 30,
|
||||
|
|
@ -199,21 +188,17 @@ export const NODE_PROPS = {
|
|||
}
|
||||
},
|
||||
ports: {
|
||||
...PORT_PROPS,
|
||||
...PORT,
|
||||
items: [
|
||||
{
|
||||
id: X6_PORT_OUT_NAME,
|
||||
group: X6_PORT_OUT_NAME
|
||||
},
|
||||
{
|
||||
id: X6_PORT_IN_NAME,
|
||||
group: X6_PORT_IN_NAME
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export const NODE_HIGHLIGHT_PROPS = {
|
||||
export const NODE_HOVER = {
|
||||
attrs: {
|
||||
body: {
|
||||
fill: BG_BLUE,
|
||||
|
|
@ -226,28 +211,42 @@ export const NODE_HIGHLIGHT_PROPS = {
|
|||
}
|
||||
}
|
||||
|
||||
export const EDGE_PROPS = {
|
||||
export const NODE_SELECTED = {
|
||||
attrs: {
|
||||
body: {
|
||||
filter: NODE_SHADOW,
|
||||
fill: BG_WHITE,
|
||||
stroke: STROKE_BLUE,
|
||||
strokeDasharray: '5,2',
|
||||
strokeWidth: '1.5'
|
||||
},
|
||||
title: {
|
||||
fill: STROKE_BLUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const EDGE = {
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: EDGE,
|
||||
strokeWidth: 0.8,
|
||||
stroke: EDGE_COLOR,
|
||||
strokeWidth: 1,
|
||||
targetMarker: {
|
||||
tagName: 'path',
|
||||
fill: EDGE,
|
||||
fill: EDGE_COLOR,
|
||||
strokeWidth: 0,
|
||||
d: 'M 6 -3 0 0 6 3 Z'
|
||||
}
|
||||
},
|
||||
filter: 'none'
|
||||
}
|
||||
},
|
||||
connector: {
|
||||
name: 'rounded'
|
||||
},
|
||||
router: {
|
||||
name: 'er',
|
||||
name: 'manhattan',
|
||||
args: {
|
||||
offset: 20,
|
||||
min: 20,
|
||||
direction: 'L'
|
||||
endDirections: ['top', 'bottom', 'left']
|
||||
}
|
||||
},
|
||||
defaultLabel: {
|
||||
|
|
@ -263,7 +262,7 @@ export const EDGE_PROPS = {
|
|||
],
|
||||
attrs: {
|
||||
label: {
|
||||
fill: EDGE,
|
||||
fill: EDGE_COLOR,
|
||||
fontSize: 14,
|
||||
textAnchor: 'middle',
|
||||
textVerticalAnchor: 'middle',
|
||||
|
|
@ -272,7 +271,7 @@ export const EDGE_PROPS = {
|
|||
body: {
|
||||
ref: 'label',
|
||||
fill: BG_WHITE,
|
||||
stroke: EDGE,
|
||||
stroke: EDGE_COLOR,
|
||||
strokeWidth: 1,
|
||||
rx: 4,
|
||||
ry: 4,
|
||||
|
|
@ -292,7 +291,7 @@ export const EDGE_PROPS = {
|
|||
}
|
||||
}
|
||||
|
||||
export const EDGE_HIGHLIGHT_PROPS = {
|
||||
export const EDGE_HOVER = {
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: STROKE_BLUE,
|
||||
|
|
@ -313,3 +312,27 @@ export const EDGE_HIGHLIGHT_PROPS = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const EDGE_SELECTED = {
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: STROKE_BLUE,
|
||||
targetMarker: {
|
||||
fill: STROKE_BLUE
|
||||
},
|
||||
strokeWidth: 2,
|
||||
filter: EDGE_SHADOW
|
||||
}
|
||||
},
|
||||
defaultLabel: {
|
||||
attrs: {
|
||||
label: {
|
||||
fill: STROKE_BLUE
|
||||
},
|
||||
body: {
|
||||
fill: BG_WHITE,
|
||||
stroke: STROKE_BLUE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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 {
|
||||
NODE,
|
||||
EDGE,
|
||||
PORT,
|
||||
NODE_HOVER,
|
||||
PORT_HOVER,
|
||||
EDGE_HOVER,
|
||||
PORT_SELECTED,
|
||||
NODE_SELECTED,
|
||||
EDGE_SELECTED,
|
||||
X6_PORT_OUT_NAME
|
||||
} from './x6-helper'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
hoverCell: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
bindStyleEvent (graph) {
|
||||
// nodes and edges hover
|
||||
graph.on('cell:mouseenter', (data) => {
|
||||
const { cell, e } = data
|
||||
const isStatusIcon = (tagName) =>
|
||||
tagName &&
|
||||
(tagName.toLocaleLowerCase() === 'em' ||
|
||||
tagName.toLocaleLowerCase() === 'body')
|
||||
if (!isStatusIcon(e.target.tagName)) {
|
||||
this.hoverCell = cell
|
||||
this.updateCellStyle(cell, graph)
|
||||
}
|
||||
})
|
||||
graph.on('cell:mouseleave', ({ cell }) => {
|
||||
this.hoverCell = null
|
||||
this.updateCellStyle(cell, graph)
|
||||
})
|
||||
// select
|
||||
graph.on('cell:selected', ({ cell }) => {
|
||||
this.updateCellStyle(cell, graph)
|
||||
})
|
||||
graph.on('cell:unselected', ({ cell }) => {
|
||||
this.updateCellStyle(cell, graph)
|
||||
})
|
||||
},
|
||||
updateCellStyle (cell, graph) {
|
||||
if (cell.isEdge()) {
|
||||
this.setEdgeStyle(cell, graph)
|
||||
} else if (cell.isNode()) {
|
||||
this.setNodeStyle(cell, graph)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Set node style
|
||||
* @param {Node} node
|
||||
* @param {Graph} graph
|
||||
*/
|
||||
setNodeStyle (node, graph) {
|
||||
const isHover = node === this.hoverCell
|
||||
const isSelected = graph.isSelected(node)
|
||||
const portHover = _.cloneDeep(PORT_HOVER.groups[X6_PORT_OUT_NAME].attrs)
|
||||
const portSelected = _.cloneDeep(PORT_SELECTED.groups[X6_PORT_OUT_NAME].attrs)
|
||||
const portDefault = _.cloneDeep(PORT.groups[X6_PORT_OUT_NAME].attrs)
|
||||
const nodeHover = _.merge(_.cloneDeep(NODE.attrs), NODE_HOVER.attrs)
|
||||
const nodeSelected = _.merge(_.cloneDeep(NODE.attrs), NODE_SELECTED.attrs)
|
||||
|
||||
let img = null
|
||||
let nodeAttrs = null
|
||||
let portAttrs = null
|
||||
|
||||
if (isHover || isSelected) {
|
||||
img = require(`../images/task-icos/${node.data.taskType.toLocaleLowerCase()}_hover.png`)
|
||||
if (isHover) {
|
||||
nodeAttrs = nodeHover
|
||||
portAttrs = _.merge(portDefault, portHover)
|
||||
} else {
|
||||
nodeAttrs = nodeSelected
|
||||
portAttrs = _.merge(portDefault, portSelected)
|
||||
}
|
||||
} else {
|
||||
img = require(`../images/task-icos/${node.data.taskType.toLocaleLowerCase()}.png`)
|
||||
nodeAttrs = NODE.attrs
|
||||
portAttrs = portDefault
|
||||
}
|
||||
node.setAttrByPath('image/xlink:href', img)
|
||||
node.setAttrs(nodeAttrs)
|
||||
node.setPortProp(
|
||||
X6_PORT_OUT_NAME,
|
||||
'attrs',
|
||||
portAttrs
|
||||
)
|
||||
},
|
||||
/**
|
||||
* Set edge style
|
||||
* @param {Edge} edge
|
||||
* @param {Graph} graph
|
||||
*/
|
||||
setEdgeStyle (edge, graph) {
|
||||
const isHover = edge === this.hoverCell
|
||||
const isSelected = graph.isSelected(edge)
|
||||
const labelName = this.getEdgeLabelName ? this.getEdgeLabelName(edge) : ''
|
||||
let edgeProps = null
|
||||
|
||||
if (isHover) {
|
||||
edgeProps = _.merge(_.cloneDeep(EDGE), EDGE_HOVER)
|
||||
} else if (isSelected) {
|
||||
edgeProps = _.merge(_.cloneDeep(EDGE), EDGE_SELECTED)
|
||||
} else {
|
||||
edgeProps = _.cloneDeep(EDGE)
|
||||
}
|
||||
|
||||
edge.setAttrs(edgeProps.attrs)
|
||||
edge.setLabels([
|
||||
{
|
||||
..._.merge(
|
||||
{
|
||||
attrs: _.cloneDeep(edgeProps.defaultLabel.attrs)
|
||||
},
|
||||
{
|
||||
attrs: { label: { text: labelName } }
|
||||
}
|
||||
)
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,16 +14,19 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
$STROKE_BLUE: #288FFF;
|
||||
$BG_WHITE: #FFFFFF;
|
||||
$STROKE_BLUE: #288fff;
|
||||
$BG_WHITE: #ffffff;
|
||||
|
||||
.x6-node[data-shape="dag-task"]{
|
||||
.in-port-body{
|
||||
&.adsorbed,&.available{
|
||||
.circle {
|
||||
stroke: $STROKE_BLUE;
|
||||
stroke-width: 4;
|
||||
fill: $BG_WHITE;
|
||||
.x6-node[data-shape="dag-task"] {
|
||||
&.available {
|
||||
.dag-task-body {
|
||||
stroke: $STROKE_BLUE;
|
||||
stroke-width: 1;
|
||||
stroke-dasharray: 5, 2;
|
||||
}
|
||||
&.adsorbed {
|
||||
.dag-task-body {
|
||||
stroke-width: 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@
|
|||
</el-dialog>
|
||||
<edge-edit-model ref="edgeEditModel" />
|
||||
<el-drawer :visible.sync="versionDrawer" size="" :with-header="false">
|
||||
<!-- fix the bug that Element-ui(2.13.2) auto focus on the first input -->
|
||||
<div style="width: 0px; height: 0px; overflow: hidden">
|
||||
<el-input type="text" />
|
||||
</div>
|
||||
<m-versions
|
||||
:versionData="versionData"
|
||||
:isInstance="type === 'instance'"
|
||||
|
|
@ -187,7 +191,6 @@
|
|||
},
|
||||
beforeDestroy () {
|
||||
this.resetParams()
|
||||
|
||||
clearInterval(this.statusTimer)
|
||||
window.removeEventListener('resize', this.resizeDebounceFunc)
|
||||
},
|
||||
|
|
@ -400,6 +403,7 @@
|
|||
buildGraphJSON (tasks, locations, connects) {
|
||||
const nodes = []
|
||||
const edges = []
|
||||
if (!locations) { locations = [] }
|
||||
tasks.forEach((task) => {
|
||||
const location = locations.find((l) => l.taskCode === task.code) || {}
|
||||
const node = this.$refs.canvas.genNodeJSON(
|
||||
|
|
@ -484,6 +488,10 @@
|
|||
const connects = this.connects
|
||||
const json = this.buildGraphJSON(tasks, locations, connects)
|
||||
this.$refs.canvas.fromJSON(json)
|
||||
// Auto format
|
||||
if (!locations) {
|
||||
this.$refs.canvas.format()
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Return to the previous process
|
||||
|
|
|
|||
|
|
@ -398,7 +398,6 @@
|
|||
<!-- Pre-tasks in workflow -->
|
||||
<m-pre-tasks
|
||||
ref="preTasks"
|
||||
v-if="['SHELL', 'SUB_PROCESS'].indexOf(nodeData.taskType) > -1"
|
||||
:code="code"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,16 @@
|
|||
import _ from 'lodash'
|
||||
import io from '@/module/io'
|
||||
|
||||
// Avoid passing in illegal values when users directly call third-party interfaces
|
||||
const convertLocations = (locationStr) => {
|
||||
let locations = null
|
||||
if (!locationStr) return locations
|
||||
try {
|
||||
locations = JSON.parse(locationStr)
|
||||
} catch (error) {}
|
||||
return Array.isArray(locations) ? locations : null
|
||||
}
|
||||
|
||||
export default {
|
||||
/**
|
||||
* Task status acquisition
|
||||
|
|
@ -133,12 +143,14 @@ export default {
|
|||
state.version = res.data.processDefinition.version
|
||||
// name
|
||||
state.name = res.data.processDefinition.name
|
||||
// releaseState
|
||||
state.releaseState = res.data.processDefinition.releaseState
|
||||
// description
|
||||
state.description = res.data.processDefinition.description
|
||||
// taskRelationJson
|
||||
state.connects = res.data.processTaskRelationList
|
||||
// locations
|
||||
state.locations = JSON.parse(res.data.processDefinition.locations)
|
||||
state.locations = convertLocations(res.data.processDefinition.locations)
|
||||
// global params
|
||||
state.globalParams = res.data.processDefinition.globalParamList
|
||||
// timeout
|
||||
|
|
@ -164,6 +176,7 @@ export default {
|
|||
'timeout',
|
||||
'environmentCode'
|
||||
]))
|
||||
|
||||
resolve(res.data)
|
||||
}).catch(res => {
|
||||
reject(res)
|
||||
|
|
@ -235,7 +248,7 @@ export default {
|
|||
// connects
|
||||
state.connects = processTaskRelationList
|
||||
// locations
|
||||
state.locations = JSON.parse(processDefinition.locations)
|
||||
state.locations = convertLocations(processDefinition.locations)
|
||||
// global params
|
||||
state.globalParams = processDefinition.globalParamList
|
||||
// timeout
|
||||
|
|
|
|||
Loading…
Reference in New Issue