[Feature][UI Next] Add workflow relation layout and format. (#8125)
parent
45f6c4197b
commit
8ef72fcffc
|
|
@ -20,129 +20,133 @@ import initChart from '@/components/chart'
|
|||
import type { Ref } from 'vue'
|
||||
|
||||
const props = {
|
||||
height: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: 400
|
||||
},
|
||||
width: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: '100%'
|
||||
},
|
||||
tooltipFormat: {
|
||||
type: String as PropType<string>,
|
||||
default: ''
|
||||
},
|
||||
legendData: {
|
||||
type: Array as PropType<Array<string>>,
|
||||
default: () => []
|
||||
},
|
||||
seriesData: {
|
||||
type: Array as PropType<Array<string>>,
|
||||
default: () => []
|
||||
},
|
||||
labelShow: {
|
||||
type: Array as PropType<Array<string>>,
|
||||
default: () => []
|
||||
},
|
||||
linksData: {
|
||||
type: Array as PropType<Array<string>>,
|
||||
default: () => []
|
||||
},
|
||||
labelFormat: {
|
||||
type: String as PropType<string>,
|
||||
default: ''
|
||||
}
|
||||
height: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: 400
|
||||
},
|
||||
width: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: '100%'
|
||||
},
|
||||
tooltipFormat: {
|
||||
type: String as PropType<string>,
|
||||
default: ''
|
||||
},
|
||||
legendData: {
|
||||
type: Array as PropType<Array<string>>,
|
||||
default: () => []
|
||||
},
|
||||
seriesData: {
|
||||
type: Array as PropType<Array<string>>,
|
||||
default: () => []
|
||||
},
|
||||
labelShow: {
|
||||
type: Array as PropType<Array<string>>,
|
||||
default: () => []
|
||||
},
|
||||
linksData: {
|
||||
type: Array as PropType<Array<string>>,
|
||||
default: () => []
|
||||
},
|
||||
labelFormat: {
|
||||
type: String as PropType<string>,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
|
||||
const GraphChart = defineComponent({
|
||||
name: 'GraphChart',
|
||||
props,
|
||||
setup(props) {
|
||||
const graphChartRef: Ref<HTMLDivElement | null> = ref(null)
|
||||
name: 'GraphChart',
|
||||
props,
|
||||
setup(props) {
|
||||
const graphChartRef: Ref<HTMLDivElement | null> = ref(null)
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
triggerOn: 'mousemove',
|
||||
backgroundColor: '#2D303A',
|
||||
padding: [8, 12],
|
||||
formatter: props.tooltipFormat,
|
||||
color: '#2D303A',
|
||||
textStyle: {
|
||||
rich: {
|
||||
a: {
|
||||
fontSize: 12,
|
||||
color: '#2D303A',
|
||||
lineHeight: 12,
|
||||
align: 'left',
|
||||
padding: [4, 4, 4, 4]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: [{
|
||||
orient: 'horizontal',
|
||||
top: 6,
|
||||
left: 6,
|
||||
data: props.legendData
|
||||
}],
|
||||
series: [{
|
||||
type: 'graph',
|
||||
layout: 'force',
|
||||
nodeScaleRatio: 1.2,
|
||||
draggable: true,
|
||||
animation: false,
|
||||
data: props.seriesData,
|
||||
roam: true,
|
||||
symbol: 'roundRect',
|
||||
symbolSize: 70,
|
||||
categories: props.legendData,
|
||||
label: {
|
||||
show: props.labelShow,
|
||||
position: 'inside',
|
||||
formatter: props.labelFormat,
|
||||
color: '#222222',
|
||||
textStyle: {
|
||||
rich: {
|
||||
a: {
|
||||
fontSize: 12,
|
||||
color: '#222222',
|
||||
lineHeight: 12,
|
||||
align: 'left',
|
||||
padding: [4, 4, 4, 4]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
edgeSymbol: ['circle', 'arrow'],
|
||||
edgeSymbolSize: [4, 12],
|
||||
force: {
|
||||
repulsion: 1000,
|
||||
edgeLength: 300
|
||||
},
|
||||
links: props.linksData,
|
||||
lineStyle: {
|
||||
color: '#999999'
|
||||
}
|
||||
}]
|
||||
}
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
triggerOn: 'mousemove',
|
||||
backgroundColor: '#2D303A',
|
||||
padding: [8, 12],
|
||||
formatter: props.tooltipFormat,
|
||||
color: '#2D303A',
|
||||
textStyle: {
|
||||
rich: {
|
||||
a: {
|
||||
fontSize: 12,
|
||||
color: '#2D303A',
|
||||
lineHeight: 12,
|
||||
align: 'left',
|
||||
padding: [4, 4, 4, 4]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: [
|
||||
{
|
||||
orient: 'horizontal',
|
||||
top: 6,
|
||||
left: 6,
|
||||
data: props.legendData
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: 'graph',
|
||||
layout: 'force',
|
||||
nodeScaleRatio: 1.2,
|
||||
draggable: true,
|
||||
animation: false,
|
||||
data: props.seriesData,
|
||||
roam: true,
|
||||
symbol: 'roundRect',
|
||||
symbolSize: 70,
|
||||
categories: props.legendData,
|
||||
label: {
|
||||
show: props.labelShow,
|
||||
position: 'inside',
|
||||
formatter: props.labelFormat,
|
||||
color: '#222222',
|
||||
textStyle: {
|
||||
rich: {
|
||||
a: {
|
||||
fontSize: 12,
|
||||
color: '#222222',
|
||||
lineHeight: 12,
|
||||
align: 'left',
|
||||
padding: [4, 4, 4, 4]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
edgeSymbol: ['circle', 'arrow'],
|
||||
edgeSymbolSize: [4, 12],
|
||||
force: {
|
||||
repulsion: 1000,
|
||||
edgeLength: 300
|
||||
},
|
||||
links: props.linksData,
|
||||
lineStyle: {
|
||||
color: '#999999'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
initChart(graphChartRef, option)
|
||||
initChart(graphChartRef, option)
|
||||
|
||||
return { graphChartRef }
|
||||
},
|
||||
render() {
|
||||
const { height, width } = this
|
||||
return (
|
||||
<div
|
||||
ref='graphChartRef'
|
||||
style={{
|
||||
height: typeof height === 'number' ? height + 'px' : height,
|
||||
width: typeof width === 'number' ? width + 'px' : width
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return { graphChartRef }
|
||||
},
|
||||
render() {
|
||||
const { height, width } = this
|
||||
return (
|
||||
<div
|
||||
ref='graphChartRef'
|
||||
style={{
|
||||
height: typeof height === 'number' ? height + 'px' : height,
|
||||
width: typeof width === 'number' ? width + 'px' : width
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default GraphChart
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ export function useDataList() {
|
|||
icon: renderIcon(FundProjectionScreenOutlined)
|
||||
},
|
||||
{
|
||||
label: t('menu.workflow_relationships'),
|
||||
key: 'workflow-relationships',
|
||||
label: t('menu.workflow_relation'),
|
||||
key: 'workflow-relation',
|
||||
icon: renderIcon(PartitionOutlined)
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const menu = {
|
|||
monitor: 'Monitor',
|
||||
security: 'Security',
|
||||
workflow_monitoring: 'Workflow Monitoring',
|
||||
workflow_relationships: 'Workflow Relationships',
|
||||
workflow_relation: 'Workflow Relation',
|
||||
workflow: 'Workflow',
|
||||
workflow_definition: 'Workflow Definition',
|
||||
workflow_instance: 'Workflow Instance',
|
||||
|
|
@ -287,8 +287,11 @@ const project = {
|
|||
cancel: 'Cancel',
|
||||
delete_confirm: 'Delete?'
|
||||
},
|
||||
workflow_relation: {
|
||||
workflow_relation: 'Workflow Relation'
|
||||
},
|
||||
dag: {
|
||||
createWorkflow: "Create Workflow",
|
||||
createWorkflow: 'Create Workflow',
|
||||
search: 'Search',
|
||||
download_png: 'Download PNG',
|
||||
fullscreen_open: 'Open Fullscreen',
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const menu = {
|
|||
monitor: '监控中心',
|
||||
security: '安全中心',
|
||||
workflow_monitoring: '工作流监控',
|
||||
workflow_relationships: '工作流关系',
|
||||
workflow_relation: '工作流关系',
|
||||
workflow: '工作流',
|
||||
workflow_definition: '工作流定义',
|
||||
workflow_instance: '工作流实例',
|
||||
|
|
@ -287,8 +287,11 @@ const project = {
|
|||
cancel: '取消',
|
||||
delete_confirm: '确定删除吗?'
|
||||
},
|
||||
workflow_relation: {
|
||||
workflow_relation: '工作流关系'
|
||||
},
|
||||
dag: {
|
||||
createWorkflow: "创建工作流",
|
||||
createWorkflow: '创建工作流',
|
||||
search: '搜索',
|
||||
download_png: '下载工作流图片',
|
||||
fullscreen_open: '全屏',
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ router.beforeEach(
|
|||
) => {
|
||||
NProgress.start()
|
||||
const menuStore = useMenuStore()
|
||||
const metaData:metaData = to.meta
|
||||
const metaData: metaData = to.meta
|
||||
menuStore.setShowSideStatus(metaData.showSide || false)
|
||||
next()
|
||||
NProgress.done()
|
||||
|
|
|
|||
|
|
@ -47,21 +47,29 @@ export default {
|
|||
showSide: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectCode/workflow-relation',
|
||||
name: 'workflow-relation',
|
||||
component: components['workflow-relation'],
|
||||
meta: {
|
||||
title: '工作流定义'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectCode/workflow/definitions/create',
|
||||
name: 'workflow-definition-create',
|
||||
component: components['workflow-definition-create'],
|
||||
meta: {
|
||||
title: '创建工作流定义',
|
||||
},
|
||||
title: '创建工作流定义'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectCode/workflow/definitions/:code',
|
||||
name: 'workflow-definition-details',
|
||||
component: components['workflow-definition-details'],
|
||||
meta: {
|
||||
title: '工作流定义详情',
|
||||
},
|
||||
title: '工作流定义详情'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,10 +49,7 @@ export function save(
|
|||
})
|
||||
}
|
||||
|
||||
export function genTaskCodeList(
|
||||
num: number,
|
||||
projectCode: number
|
||||
) {
|
||||
export function genTaskCodeList(num: number, projectCode: number) {
|
||||
return axios.request<unknown, number[]>({
|
||||
url: `/projects/${projectCode}/task-definition/gen-task-codes`,
|
||||
method: 'get',
|
||||
|
|
|
|||
|
|
@ -46,6 +46,6 @@ export const useMenuStore = defineStore({
|
|||
},
|
||||
setSideMenuKey(sideMenuKey: string): void {
|
||||
this.sideMenuKey = sideMenuKey
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
*/
|
||||
|
||||
interface MenuState {
|
||||
menuKey: string,
|
||||
isShowSide: boolean,
|
||||
menuKey: string
|
||||
isShowSide: boolean
|
||||
sideMenuKey: string
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@
|
|||
|
||||
import mapping from './mapping'
|
||||
import regex from './regex'
|
||||
import truncateText from './truncate-text'
|
||||
import truncateText from './truncate-text'
|
||||
|
||||
const utils = {
|
||||
mapping,
|
||||
regex,
|
||||
truncateText,
|
||||
truncateText
|
||||
}
|
||||
|
||||
export default utils
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* truncateText('ALongText', 4) => 'ALon...'
|
||||
* @param {number} limit
|
||||
* @param {string} text
|
||||
* Each Chinese character is equal to two chars
|
||||
*/
|
||||
* truncateText('ALongText', 4) => 'ALon...'
|
||||
* @param {number} limit
|
||||
* @param {string} text
|
||||
* Each Chinese character is equal to two chars
|
||||
*/
|
||||
export default function truncateText(text: string, n: number) {
|
||||
const exp = /[\u4E00-\u9FA5]/
|
||||
let res = ''
|
||||
|
|
@ -48,4 +48,4 @@ export default function truncateText(text: string, n: number) {
|
|||
res = text
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@
|
|||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: "Projects",
|
||||
name: 'Projects',
|
||||
setup() {
|
||||
return () => (
|
||||
<div>Projects</div>
|
||||
)
|
||||
return () => <div>Projects</div>
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -15,53 +15,53 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const ALL_TASK_TYPES:any = {
|
||||
export const ALL_TASK_TYPES: any = {
|
||||
SHELL: {
|
||||
alias: 'SHELL',
|
||||
alias: 'SHELL'
|
||||
},
|
||||
SUB_PROCESS: {
|
||||
alias: 'SUB_PROCESS',
|
||||
alias: 'SUB_PROCESS'
|
||||
},
|
||||
PROCEDURE: {
|
||||
alias: 'PROCEDURE',
|
||||
alias: 'PROCEDURE'
|
||||
},
|
||||
SQL: {
|
||||
alias: 'SQL',
|
||||
alias: 'SQL'
|
||||
},
|
||||
SPARK: {
|
||||
alias: 'SPARK',
|
||||
alias: 'SPARK'
|
||||
},
|
||||
FLINK: {
|
||||
alias: 'FLINK',
|
||||
alias: 'FLINK'
|
||||
},
|
||||
MR: {
|
||||
alias: 'MapReduce',
|
||||
alias: 'MapReduce'
|
||||
},
|
||||
PYTHON: {
|
||||
alias: 'PYTHON',
|
||||
alias: 'PYTHON'
|
||||
},
|
||||
DEPENDENT: {
|
||||
alias: 'DEPENDENT',
|
||||
alias: 'DEPENDENT'
|
||||
},
|
||||
HTTP: {
|
||||
alias: 'HTTP',
|
||||
alias: 'HTTP'
|
||||
},
|
||||
DATAX: {
|
||||
alias: 'DataX',
|
||||
alias: 'DataX'
|
||||
},
|
||||
PIGEON: {
|
||||
alias: 'PIGEON',
|
||||
alias: 'PIGEON'
|
||||
},
|
||||
SQOOP: {
|
||||
alias: 'SQOOP',
|
||||
alias: 'SQOOP'
|
||||
},
|
||||
CONDITIONS: {
|
||||
alias: 'CONDITIONS',
|
||||
alias: 'CONDITIONS'
|
||||
},
|
||||
SWITCH: {
|
||||
alias: 'SWITCH',
|
||||
alias: 'SWITCH'
|
||||
},
|
||||
SEATUNNEL: {
|
||||
alias: 'WATERDROP',
|
||||
alias: 'WATERDROP'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@
|
|||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: "TaskConfigModal",
|
||||
name: 'TaskConfigModal',
|
||||
setup() {
|
||||
return () => (
|
||||
<div>TaskConfigModal</div>
|
||||
)
|
||||
return () => <div>TaskConfigModal</div>
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 { defineComponent } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { NSelect, NButton, NIcon } from 'naive-ui'
|
||||
import { ReloadOutlined, EyeOutlined } from '@vicons/antd'
|
||||
import Card from '@/components/card'
|
||||
|
||||
const workflowRelation = defineComponent({
|
||||
name: 'workflow-relation',
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
|
||||
return { t }
|
||||
},
|
||||
render() {
|
||||
const { t } = this
|
||||
|
||||
return (
|
||||
<Card title={t('project.workflow_relation.workflow_relation')}>
|
||||
<div>
|
||||
<NSelect />
|
||||
<NButton strong secondary circle type='info'>
|
||||
<NIcon>
|
||||
<ReloadOutlined />
|
||||
</NIcon>
|
||||
</NButton>
|
||||
<NButton strong secondary circle type='info'>
|
||||
<NIcon>
|
||||
<EyeOutlined />
|
||||
</NIcon>
|
||||
</NButton>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default workflowRelation
|
||||
|
|
@ -19,7 +19,12 @@ import { defineComponent, ref, inject } from 'vue'
|
|||
import Styles from './dag.module.scss'
|
||||
import type { PropType, Ref } from 'vue'
|
||||
import type { Dragged } from './dag'
|
||||
import { useCanvasInit, useGraphOperations, useCellActive, useCanvasDrop } from './dag-hooks';
|
||||
import {
|
||||
useCanvasInit,
|
||||
useGraphOperations,
|
||||
useCellActive,
|
||||
useCanvasDrop
|
||||
} from './dag-hooks'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const props = {
|
||||
|
|
@ -29,32 +34,45 @@ const props = {
|
|||
x: 0,
|
||||
y: 0,
|
||||
type: ''
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: "workflow-dag-canvas",
|
||||
name: 'workflow-dag-canvas',
|
||||
props,
|
||||
setup(props, context) {
|
||||
const readonly = inject('readonly', ref(false));
|
||||
const graph = inject('graph', ref());
|
||||
const route = useRoute();
|
||||
const projectCode = route.params.projectCode as string;
|
||||
const readonly = inject('readonly', ref(false))
|
||||
const graph = inject('graph', ref())
|
||||
const route = useRoute()
|
||||
const projectCode = route.params.projectCode as string
|
||||
|
||||
const { paper, minimap, container } = useCanvasInit({ readonly, graph });
|
||||
const { paper, minimap, container } = useCanvasInit({ readonly, graph })
|
||||
|
||||
// Change the style on cell hover and select
|
||||
useCellActive({ graph });
|
||||
useCellActive({ graph })
|
||||
|
||||
// Drop sidebar item in canvas
|
||||
const { onDrop, onDragenter, onDragover, onDragleave } = useCanvasDrop({ readonly, dragged: props.dragged, graph, container, projectCode });
|
||||
const { onDrop, onDragenter, onDragover, onDragleave } = useCanvasDrop({
|
||||
readonly,
|
||||
dragged: props.dragged,
|
||||
graph,
|
||||
container,
|
||||
projectCode
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div ref={container} class={Styles.canvas} onDrop={onDrop} onDragenter={onDragenter} onDragover={onDragover} onDragleave={onDragleave}>
|
||||
<div
|
||||
ref={container}
|
||||
class={Styles.canvas}
|
||||
onDrop={onDrop}
|
||||
onDragenter={onDragenter}
|
||||
onDragover={onDragover}
|
||||
onDragleave={onDragleave}
|
||||
>
|
||||
<div ref={paper} class={Styles.paper}></div>
|
||||
<div ref={minimap} class={Styles.minimap}></div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -119,21 +119,25 @@ export const PORT_SELECTED = {
|
|||
}
|
||||
}
|
||||
|
||||
export const NODE_STATUS_MARKUP = [{
|
||||
tagName: 'foreignObject',
|
||||
selector: 'fo',
|
||||
children: [
|
||||
{
|
||||
tagName: 'body',
|
||||
selector: 'fo-body',
|
||||
ns: 'http://www.w3.org/1999/xhtml',
|
||||
children: [{
|
||||
tagName: 'div',
|
||||
selector: 'status'
|
||||
}]
|
||||
}
|
||||
]
|
||||
}]
|
||||
export const NODE_STATUS_MARKUP = [
|
||||
{
|
||||
tagName: 'foreignObject',
|
||||
selector: 'fo',
|
||||
children: [
|
||||
{
|
||||
tagName: 'body',
|
||||
selector: 'fo-body',
|
||||
ns: 'http://www.w3.org/1999/xhtml',
|
||||
children: [
|
||||
{
|
||||
tagName: 'div',
|
||||
selector: 'status'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
export const NODE = {
|
||||
width: 220,
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useCanvasInit } from './use-canvas-init';
|
||||
import { useGraphOperations } from './use-graph-operations';
|
||||
import { useCellActive } from './use-cell-active';
|
||||
import { useSidebarDrag } from './use-sidebar-drag';
|
||||
import { useCanvasDrop } from './use-canvas-drop';
|
||||
import { useNodeSearch } from './use-node-search';
|
||||
import { useCanvasInit } from './use-canvas-init'
|
||||
import { useGraphOperations } from './use-graph-operations'
|
||||
import { useCellActive } from './use-cell-active'
|
||||
import { useSidebarDrag } from './use-sidebar-drag'
|
||||
import { useCanvasDrop } from './use-canvas-drop'
|
||||
import { useNodeSearch } from './use-node-search'
|
||||
|
||||
export {
|
||||
useCanvasInit,
|
||||
|
|
@ -28,5 +28,5 @@ export {
|
|||
useCellActive,
|
||||
useSidebarDrag,
|
||||
useCanvasDrop,
|
||||
useNodeSearch,
|
||||
}
|
||||
useNodeSearch
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { PropType, Ref } from 'vue';
|
||||
import type { Dragged } from './dag';
|
||||
import type { PropType, Ref } from 'vue'
|
||||
import type { Dragged } from './dag'
|
||||
import { defineComponent, ref, inject } from 'vue'
|
||||
import { ALL_TASK_TYPES } from '../task/config';
|
||||
import { useSidebarDrag } from './dag-hooks';
|
||||
import Styles from './dag.module.scss';
|
||||
import { ALL_TASK_TYPES } from '../task/config'
|
||||
import { useSidebarDrag } from './dag-hooks'
|
||||
import Styles from './dag.module.scss'
|
||||
|
||||
const props = {
|
||||
dragged: {
|
||||
|
|
@ -29,40 +29,42 @@ const props = {
|
|||
x: 0,
|
||||
y: 0,
|
||||
type: ''
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: "workflow-dag-sidebar",
|
||||
name: 'workflow-dag-sidebar',
|
||||
props,
|
||||
setup(props) {
|
||||
const readonly = inject('readonly', ref(false))
|
||||
const dragged = props.dragged;
|
||||
const dragged = props.dragged
|
||||
const { onDragStart } = useSidebarDrag({
|
||||
readonly,
|
||||
dragged
|
||||
});
|
||||
const allTaskTypes = Object.keys(ALL_TASK_TYPES).map(type => ({
|
||||
})
|
||||
const allTaskTypes = Object.keys(ALL_TASK_TYPES).map((type) => ({
|
||||
type,
|
||||
...ALL_TASK_TYPES[type]
|
||||
}));
|
||||
}))
|
||||
|
||||
return () => (
|
||||
<div class={Styles.sidebar}>
|
||||
{
|
||||
allTaskTypes.map(task => (
|
||||
<div
|
||||
class={Styles.draggable}
|
||||
draggable="true"
|
||||
onDragstart={(e) => onDragStart(e, task.type)}
|
||||
>
|
||||
<em class={`${Styles['sidebar-icon']} ${Styles['icon-' + task.type.toLocaleLowerCase()]}`}></em>
|
||||
<span>{task.alias}</span>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{allTaskTypes.map((task) => (
|
||||
<div
|
||||
class={Styles.draggable}
|
||||
draggable='true'
|
||||
onDragstart={(e) => onDragStart(e, task.type)}
|
||||
>
|
||||
<em
|
||||
class={`${Styles['sidebar-icon']} ${
|
||||
Styles['icon-' + task.type.toLocaleLowerCase()]
|
||||
}`}
|
||||
></em>
|
||||
<span>{task.alias}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -18,19 +18,26 @@
|
|||
import { defineComponent, ref, inject } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Styles from './dag.module.scss'
|
||||
import { NTooltip, NIcon, NButton, NSelect } from 'naive-ui';
|
||||
import { SearchOutlined, DownloadOutlined, FullscreenOutlined, FullscreenExitOutlined, InfoCircleOutlined, FormatPainterOutlined } from '@vicons/antd';
|
||||
import { useNodeSearch } from './dag-hooks';
|
||||
import { NTooltip, NIcon, NButton, NSelect } from 'naive-ui'
|
||||
import {
|
||||
SearchOutlined,
|
||||
DownloadOutlined,
|
||||
FullscreenOutlined,
|
||||
FullscreenExitOutlined,
|
||||
InfoCircleOutlined,
|
||||
FormatPainterOutlined
|
||||
} from '@vicons/antd'
|
||||
import { useNodeSearch } from './dag-hooks'
|
||||
import { DataUri } from '@antv/x6'
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useFullscreen } from '@vueuse/core'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
export default defineComponent({
|
||||
name: "workflow-dag-toolbar",
|
||||
name: 'workflow-dag-toolbar',
|
||||
setup(props, context) {
|
||||
const { t } = useI18n();
|
||||
const graph = inject('graph', ref());
|
||||
const router = useRouter();
|
||||
const { t } = useI18n()
|
||||
const graph = inject('graph', ref())
|
||||
const router = useRouter()
|
||||
|
||||
/**
|
||||
* Node search and navigate
|
||||
|
|
@ -41,15 +48,15 @@ export default defineComponent({
|
|||
allNodes,
|
||||
toggleSearchInput,
|
||||
searchInputVisible
|
||||
} = useNodeSearch({ graph });
|
||||
} = useNodeSearch({ graph })
|
||||
|
||||
/**
|
||||
* Download Workflow Image
|
||||
* @param {string} fileName
|
||||
* @param {string} bgColor
|
||||
* @param {string} bgColor
|
||||
*/
|
||||
const downloadPNG = (options = { fileName: 'dag', bgColor: '#f2f3f7' }) => {
|
||||
const { fileName, bgColor } = options;
|
||||
const { fileName, bgColor } = options
|
||||
graph.value?.toPNG(
|
||||
(dataUri: string) => {
|
||||
DataUri.downloadDataUri(dataUri, `${fileName}.png`)
|
||||
|
|
@ -69,8 +76,7 @@ export default defineComponent({
|
|||
/**
|
||||
* Toggle fullscreen
|
||||
*/
|
||||
const { isFullscreen, toggle } = useFullscreen();
|
||||
|
||||
const { isFullscreen, toggle } = useFullscreen()
|
||||
|
||||
/**
|
||||
* Open workflow version modal
|
||||
|
|
@ -82,9 +88,7 @@ export default defineComponent({
|
|||
/**
|
||||
* Open DAG format modal
|
||||
*/
|
||||
const openDagFormatModal = () => {
|
||||
|
||||
}
|
||||
const openDagFormatModal = () => {}
|
||||
|
||||
const onClose = () => {
|
||||
router.go(-1)
|
||||
|
|
@ -92,89 +96,160 @@ export default defineComponent({
|
|||
|
||||
return () => (
|
||||
<div class={Styles.toolbar}>
|
||||
<span class={Styles['workflow-name']}>{t("project.dag.createWorkflow")}</span>
|
||||
<span class={Styles['workflow-name']}>
|
||||
{t('project.dag.createWorkflow')}
|
||||
</span>
|
||||
<div class={Styles['toolbar-right-part']}>
|
||||
{/* Search node */}
|
||||
<NTooltip v-slots={{
|
||||
trigger: () => (
|
||||
<NButton class={Styles['toolbar-right-item']} strong secondary circle type="info" onClick={toggleSearchInput} v-slots={{
|
||||
icon: () => (
|
||||
<NIcon>
|
||||
<SearchOutlined />
|
||||
</NIcon>
|
||||
)
|
||||
}} />
|
||||
),
|
||||
default: () => t('project.dag.search')
|
||||
}}>
|
||||
</NTooltip>
|
||||
<NTooltip
|
||||
v-slots={{
|
||||
trigger: () => (
|
||||
<NButton
|
||||
class={Styles['toolbar-right-item']}
|
||||
strong
|
||||
secondary
|
||||
circle
|
||||
type='info'
|
||||
onClick={toggleSearchInput}
|
||||
v-slots={{
|
||||
icon: () => (
|
||||
<NIcon>
|
||||
<SearchOutlined />
|
||||
</NIcon>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
),
|
||||
default: () => t('project.dag.search')
|
||||
}}
|
||||
></NTooltip>
|
||||
<div
|
||||
class={`${Styles['toolbar-right-item']} ${Styles['node-selector']} ${searchInputVisible.value ? Styles['visible'] : ''}`}
|
||||
class={`${Styles['toolbar-right-item']} ${
|
||||
Styles['node-selector']
|
||||
} ${searchInputVisible.value ? Styles['visible'] : ''}`}
|
||||
>
|
||||
<NSelect size="small" options={allNodes.value} onFocus={getAllNodes} onUpdateValue={searchNode} filterable />
|
||||
<NSelect
|
||||
size='small'
|
||||
options={allNodes.value}
|
||||
onFocus={getAllNodes}
|
||||
onUpdateValue={searchNode}
|
||||
filterable
|
||||
/>
|
||||
</div>
|
||||
{/* Download workflow PNG */}
|
||||
<NTooltip v-slots={{
|
||||
trigger: () => (
|
||||
<NButton class={Styles['toolbar-right-item']} strong secondary circle type="info" onClick={() => downloadPNG()} v-slots={{
|
||||
icon: () => (
|
||||
<NIcon>
|
||||
<DownloadOutlined />
|
||||
</NIcon>
|
||||
)
|
||||
}} />
|
||||
),
|
||||
default: () => t('project.dag.download_png')
|
||||
}}>
|
||||
</NTooltip>
|
||||
<NTooltip
|
||||
v-slots={{
|
||||
trigger: () => (
|
||||
<NButton
|
||||
class={Styles['toolbar-right-item']}
|
||||
strong
|
||||
secondary
|
||||
circle
|
||||
type='info'
|
||||
onClick={() => downloadPNG()}
|
||||
v-slots={{
|
||||
icon: () => (
|
||||
<NIcon>
|
||||
<DownloadOutlined />
|
||||
</NIcon>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
),
|
||||
default: () => t('project.dag.download_png')
|
||||
}}
|
||||
></NTooltip>
|
||||
{/* Toggle fullscreen */}
|
||||
<NTooltip v-slots={{
|
||||
trigger: () => (
|
||||
<NButton class={Styles['toolbar-right-item']} strong secondary circle type="info" onClick={toggle} v-slots={{
|
||||
icon: () => (
|
||||
<NIcon>
|
||||
{isFullscreen.value ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
|
||||
</NIcon>
|
||||
)
|
||||
}} />
|
||||
),
|
||||
default: () => isFullscreen.value ? t('project.dag.fullscreen_close') : t('project.dag.fullscreen_open')
|
||||
}}>
|
||||
</NTooltip>
|
||||
<NTooltip
|
||||
v-slots={{
|
||||
trigger: () => (
|
||||
<NButton
|
||||
class={Styles['toolbar-right-item']}
|
||||
strong
|
||||
secondary
|
||||
circle
|
||||
type='info'
|
||||
onClick={toggle}
|
||||
v-slots={{
|
||||
icon: () => (
|
||||
<NIcon>
|
||||
{isFullscreen.value ? (
|
||||
<FullscreenExitOutlined />
|
||||
) : (
|
||||
<FullscreenOutlined />
|
||||
)}
|
||||
</NIcon>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
),
|
||||
default: () =>
|
||||
isFullscreen.value
|
||||
? t('project.dag.fullscreen_close')
|
||||
: t('project.dag.fullscreen_open')
|
||||
}}
|
||||
></NTooltip>
|
||||
{/* DAG Format */}
|
||||
<NTooltip v-slots={{
|
||||
trigger: () => (
|
||||
<NButton class={Styles['toolbar-right-item']} strong secondary circle type="info" onClick={openDagFormatModal} v-slots={{
|
||||
icon: () => (
|
||||
<NIcon>
|
||||
<FormatPainterOutlined />
|
||||
</NIcon>
|
||||
)
|
||||
}} />
|
||||
),
|
||||
default: () => t('project.dag.format')
|
||||
}}>
|
||||
</NTooltip>
|
||||
<NTooltip
|
||||
v-slots={{
|
||||
trigger: () => (
|
||||
<NButton
|
||||
class={Styles['toolbar-right-item']}
|
||||
strong
|
||||
secondary
|
||||
circle
|
||||
type='info'
|
||||
onClick={openDagFormatModal}
|
||||
v-slots={{
|
||||
icon: () => (
|
||||
<NIcon>
|
||||
<FormatPainterOutlined />
|
||||
</NIcon>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
),
|
||||
default: () => t('project.dag.format')
|
||||
}}
|
||||
></NTooltip>
|
||||
{/* Version info */}
|
||||
<NTooltip v-slots={{
|
||||
trigger: () => (
|
||||
<NButton class={Styles['toolbar-right-item']} strong secondary circle type="info" onClick={openVersionModal} v-slots={{
|
||||
icon: () => (
|
||||
<NIcon>
|
||||
<InfoCircleOutlined />
|
||||
</NIcon>
|
||||
)
|
||||
}} />
|
||||
),
|
||||
default: () => t('project.dag.workflow_version')
|
||||
}}>
|
||||
</NTooltip>
|
||||
<NTooltip
|
||||
v-slots={{
|
||||
trigger: () => (
|
||||
<NButton
|
||||
class={Styles['toolbar-right-item']}
|
||||
strong
|
||||
secondary
|
||||
circle
|
||||
type='info'
|
||||
onClick={openVersionModal}
|
||||
v-slots={{
|
||||
icon: () => (
|
||||
<NIcon>
|
||||
<InfoCircleOutlined />
|
||||
</NIcon>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
),
|
||||
default: () => t('project.dag.workflow_version')
|
||||
}}
|
||||
></NTooltip>
|
||||
{/* Save workflow */}
|
||||
<NButton class={Styles['toolbar-right-item']} type="info" secondary round>{t('project.dag.save')}</NButton>
|
||||
<NButton
|
||||
class={Styles['toolbar-right-item']}
|
||||
type='info'
|
||||
secondary
|
||||
round
|
||||
>
|
||||
{t('project.dag.save')}
|
||||
</NButton>
|
||||
{/* Return to previous page */}
|
||||
<NButton secondary round onClick={onClose}>{t('project.dag.close')}</NButton>
|
||||
<NButton secondary round onClick={onClose}>
|
||||
{t('project.dag.close')}
|
||||
</NButton>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -15,31 +15,29 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Graph } from '@antv/x6';
|
||||
import type { Graph } from '@antv/x6'
|
||||
import { defineComponent, ref, provide } from 'vue'
|
||||
import DagToolbar from './dag-toolbar';
|
||||
import DagCanvas from './dag-canvas';
|
||||
import DagSidebar from './dag-sidebar';
|
||||
import Styles from './dag.module.scss';
|
||||
import "./x6-style.scss";
|
||||
|
||||
import DagToolbar from './dag-toolbar'
|
||||
import DagCanvas from './dag-canvas'
|
||||
import DagSidebar from './dag-sidebar'
|
||||
import Styles from './dag.module.scss'
|
||||
import './x6-style.scss'
|
||||
|
||||
export interface Dragged {
|
||||
x: number;
|
||||
y: number;
|
||||
type: string;
|
||||
x: number
|
||||
y: number
|
||||
type: string
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: "workflow-dag",
|
||||
name: 'workflow-dag',
|
||||
setup(props, context) {
|
||||
|
||||
// Whether the graph can be operated
|
||||
const readonly = ref(false);
|
||||
provide('readonly', readonly);
|
||||
const readonly = ref(false)
|
||||
provide('readonly', readonly)
|
||||
|
||||
const graph = ref<Graph>();
|
||||
provide('graph', graph);
|
||||
const graph = ref<Graph>()
|
||||
provide('graph', graph)
|
||||
|
||||
// The sidebar slots
|
||||
const toolbarSlots = {
|
||||
|
|
@ -52,7 +50,7 @@ export default defineComponent({
|
|||
x: 0,
|
||||
y: 0,
|
||||
type: ''
|
||||
});
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div class={Styles.dag}>
|
||||
|
|
@ -64,4 +62,4 @@ export default defineComponent({
|
|||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -29,12 +29,8 @@ interface Options {
|
|||
* 3. Register custom graphics
|
||||
*/
|
||||
export function useCanvasInit(options: Options) {
|
||||
|
||||
// Whether the graph can be operated
|
||||
const { } = options;
|
||||
const {} = options
|
||||
|
||||
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,56 +15,54 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Ref } from 'vue';
|
||||
import type { Ref } from 'vue'
|
||||
import type { Graph } from '@antv/x6'
|
||||
import type { Dragged } from './dag'
|
||||
import { genTaskCodeList } from '@/service/modules/task-definition';
|
||||
import { useGraphOperations } from './dag-hooks';
|
||||
import { genTaskCodeList } from '@/service/modules/task-definition'
|
||||
import { useGraphOperations } from './dag-hooks'
|
||||
|
||||
interface Options {
|
||||
readonly: Ref<boolean>;
|
||||
graph: Ref<Graph | undefined>;
|
||||
container: Ref<HTMLElement | undefined>;
|
||||
dragged: Ref<Dragged>;
|
||||
projectCode: string;
|
||||
readonly: Ref<boolean>
|
||||
graph: Ref<Graph | undefined>
|
||||
container: Ref<HTMLElement | undefined>
|
||||
dragged: Ref<Dragged>
|
||||
projectCode: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop sidebar item in canvas
|
||||
*/
|
||||
export function useCanvasDrop(options: Options) {
|
||||
const { readonly, graph, container, dragged, projectCode } = options
|
||||
|
||||
const { readonly, graph, container, dragged, projectCode } = options;
|
||||
|
||||
const { addNode } = useGraphOperations({ graph });
|
||||
const { addNode } = useGraphOperations({ graph })
|
||||
|
||||
const onDrop = (e: DragEvent) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
if (readonly.value) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (dragged.value && graph.value && container.value && projectCode) {
|
||||
const { type, x: eX, y: eY } = dragged.value;
|
||||
const { x, y } = graph.value.clientToLocal(e.clientX, e.clientY);
|
||||
const genNums = 1;
|
||||
genTaskCodeList(genNums, Number(projectCode))
|
||||
.then((res) => {
|
||||
const [code] = res
|
||||
addNode(code + '', type, { x: x - eX, y: y - eY })
|
||||
// openTaskConfigModel(code, type)
|
||||
})
|
||||
const { type, x: eX, y: eY } = dragged.value
|
||||
const { x, y } = graph.value.clientToLocal(e.clientX, e.clientY)
|
||||
const genNums = 1
|
||||
genTaskCodeList(genNums, Number(projectCode)).then((res) => {
|
||||
const [code] = res
|
||||
addNode(code + '', type, { x: x - eX, y: y - eY })
|
||||
// openTaskConfigModel(code, type)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const preventDefault = (e: DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
return {
|
||||
onDrop,
|
||||
onDragenter: preventDefault,
|
||||
onDragover: preventDefault,
|
||||
onDragleave: preventDefault,
|
||||
onDragleave: preventDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,20 +15,15 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Node } from '@antv/x6';
|
||||
import type { Node } from '@antv/x6'
|
||||
import { ref, onMounted, Ref, onUnmounted } from 'vue'
|
||||
import { Graph } from '@antv/x6'
|
||||
import {
|
||||
NODE,
|
||||
EDGE,
|
||||
X6_NODE_NAME,
|
||||
X6_EDGE_NAME,
|
||||
} from './dag-config'
|
||||
import { debounce } from 'lodash';
|
||||
import { NODE, EDGE, X6_NODE_NAME, X6_EDGE_NAME } from './dag-config'
|
||||
import { debounce } from 'lodash'
|
||||
|
||||
interface Options {
|
||||
readonly: Ref<boolean>;
|
||||
graph: Ref<Graph | undefined>;
|
||||
readonly: Ref<boolean>
|
||||
graph: Ref<Graph | undefined>
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -38,13 +33,12 @@ interface Options {
|
|||
* 3. Register custom graphics
|
||||
*/
|
||||
export function useCanvasInit(options: Options) {
|
||||
|
||||
// Whether the graph can be operated
|
||||
const { readonly, graph } = options;
|
||||
const { readonly, graph } = options
|
||||
|
||||
const paper = ref<HTMLElement>(); // The graph mount HTMLElement
|
||||
const minimap = ref<HTMLElement>(); // The minimap mount HTMLElement
|
||||
const container = ref<HTMLElement>(); // The container of paper and minimap
|
||||
const paper = ref<HTMLElement>() // The graph mount HTMLElement
|
||||
const minimap = ref<HTMLElement>() // The minimap mount HTMLElement
|
||||
const container = ref<HTMLElement>() // The container of paper and minimap
|
||||
|
||||
/**
|
||||
* Graph Init, bind graph to the dom
|
||||
|
|
@ -129,7 +123,7 @@ export function useCanvasInit(options: Options) {
|
|||
}
|
||||
|
||||
onMounted(() => {
|
||||
graph.value = graphInit();
|
||||
graph.value = graphInit()
|
||||
// Make sure the edge starts with node, not port
|
||||
graph.value.on('edge:connected', ({ isNew, edge }) => {
|
||||
if (isNew) {
|
||||
|
|
@ -143,10 +137,10 @@ export function useCanvasInit(options: Options) {
|
|||
* Redraw when the page is resized
|
||||
*/
|
||||
const paperResize = debounce(() => {
|
||||
if (!container.value) return;
|
||||
if (!container.value) return
|
||||
const w = container.value.offsetWidth
|
||||
const h = container.value.offsetHeight
|
||||
graph.value?.resize(w, h);
|
||||
graph.value?.resize(w, h)
|
||||
}, 200)
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', paperResize)
|
||||
|
|
@ -174,4 +168,4 @@ export function useCanvasInit(options: Options) {
|
|||
minimap,
|
||||
container
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@
|
|||
*/
|
||||
|
||||
import type { Ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue'
|
||||
import type { Node, Graph, Edge, Cell } from '@antv/x6'
|
||||
import _ from 'lodash';
|
||||
import _ from 'lodash'
|
||||
import {
|
||||
X6_PORT_OUT_NAME,
|
||||
PORT_HOVER,
|
||||
|
|
@ -30,7 +30,7 @@ import {
|
|||
EDGE,
|
||||
EDGE_SELECTED,
|
||||
EDGE_HOVER
|
||||
} from './dag-config';
|
||||
} from './dag-config'
|
||||
|
||||
interface Options {
|
||||
graph: Ref<Graph | undefined>
|
||||
|
|
@ -40,17 +40,19 @@ interface Options {
|
|||
* Change the style on cell hover and select
|
||||
*/
|
||||
export function useCellActive(options: Options) {
|
||||
|
||||
const { graph } = options;
|
||||
const hoverCell = ref();
|
||||
const { graph } = options
|
||||
const hoverCell = ref()
|
||||
|
||||
const isStatusIcon = (tagName: string) => {
|
||||
if (!tagName) return false;
|
||||
return tagName.toLocaleLowerCase() === 'em' || tagName.toLocaleLowerCase() === 'body'
|
||||
if (!tagName) return false
|
||||
return (
|
||||
tagName.toLocaleLowerCase() === 'em' ||
|
||||
tagName.toLocaleLowerCase() === 'body'
|
||||
)
|
||||
}
|
||||
|
||||
function setEdgeStyle(edge: Edge) {
|
||||
const isHover = edge === hoverCell.value;
|
||||
const isHover = edge === hoverCell.value
|
||||
const isSelected = graph.value?.isSelected(edge)
|
||||
// TODO
|
||||
// const labelName = this.getEdgeLabelName ? this.getEdgeLabelName(edge) : ''
|
||||
|
|
@ -70,7 +72,7 @@ export function useCellActive(options: Options) {
|
|||
..._.merge(
|
||||
{
|
||||
attrs: _.cloneDeep(edgeProps.defaultLabel.attrs)
|
||||
},
|
||||
}
|
||||
// {
|
||||
// attrs: { label: { text: labelName } }
|
||||
// }
|
||||
|
|
@ -83,7 +85,9 @@ export function useCellActive(options: Options) {
|
|||
const isHover = node === hoverCell.value
|
||||
const isSelected = graph.value?.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 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)
|
||||
|
|
@ -108,11 +112,7 @@ export function useCellActive(options: Options) {
|
|||
}
|
||||
node.setAttrByPath('image/xlink:href', img)
|
||||
node.setAttrs(nodeAttrs)
|
||||
node.setPortProp(
|
||||
X6_PORT_OUT_NAME,
|
||||
'attrs',
|
||||
portAttrs
|
||||
)
|
||||
node.setPortProp(X6_PORT_OUT_NAME, 'attrs', portAttrs)
|
||||
}
|
||||
|
||||
function updateCellStyle(cell: Cell) {
|
||||
|
|
@ -151,4 +151,4 @@ export function useCellActive(options: Options) {
|
|||
return {
|
||||
hoverCell
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,27 +17,22 @@
|
|||
|
||||
import type { Ref } from 'vue'
|
||||
import type { Node, Graph, Edge } from '@antv/x6'
|
||||
import {
|
||||
X6_NODE_NAME,
|
||||
X6_EDGE_NAME,
|
||||
} from './dag-config'
|
||||
import { ALL_TASK_TYPES } from '../task/config';
|
||||
import utils from '@/utils';
|
||||
import { X6_NODE_NAME, X6_EDGE_NAME } from './dag-config'
|
||||
import { ALL_TASK_TYPES } from '../task/config'
|
||||
import utils from '@/utils'
|
||||
|
||||
interface Options {
|
||||
graph: Ref<Graph | undefined>
|
||||
}
|
||||
|
||||
type Coordinate = { x: number; y: number; }
|
||||
type Coordinate = { x: number; y: number }
|
||||
|
||||
/**
|
||||
* Expose some graph operation methods
|
||||
* @param {Options} options
|
||||
*/
|
||||
export function useGraphOperations(options: Options) {
|
||||
|
||||
const { graph } = options;
|
||||
|
||||
const { graph } = options
|
||||
|
||||
/**
|
||||
* Build edge metadata
|
||||
|
|
@ -45,7 +40,11 @@ export function useGraphOperations(options: Options) {
|
|||
* @param {string} targetId
|
||||
* @param {string} label
|
||||
*/
|
||||
function buildEdgeMetadata(sourceId: string, targetId: string, label: string = ''): Edge.Metadata {
|
||||
function buildEdgeMetadata(
|
||||
sourceId: string,
|
||||
targetId: string,
|
||||
label: string = ''
|
||||
): Edge.Metadata {
|
||||
return {
|
||||
shape: X6_EDGE_NAME,
|
||||
source: {
|
||||
|
|
@ -64,8 +63,13 @@ export function useGraphOperations(options: Options) {
|
|||
* @param {string} taskType
|
||||
* @param {Coordinate} coordinate Default is { x: 100, y: 100 }
|
||||
*/
|
||||
function buildNodeMetadata(id: string, type: string, taskName: string, coordinate: Coordinate = { x: 100, y: 100 }): Node.Metadata {
|
||||
const truncation = taskName ? utils.truncateText(taskName, 18) : id;
|
||||
function buildNodeMetadata(
|
||||
id: string,
|
||||
type: string,
|
||||
taskName: string,
|
||||
coordinate: Coordinate = { x: 100, y: 100 }
|
||||
): Node.Metadata {
|
||||
const truncation = taskName ? utils.truncateText(taskName, 18) : id
|
||||
return {
|
||||
id: id,
|
||||
shape: X6_NODE_NAME,
|
||||
|
|
@ -93,7 +97,11 @@ export function useGraphOperations(options: Options) {
|
|||
* @param {string} taskType
|
||||
* @param {Coordinate} coordinate Default is { x: 100, y: 100 }
|
||||
*/
|
||||
function addNode(id: string, type: string, coordinate: Coordinate = { x: 100, y: 100 }) {
|
||||
function addNode(
|
||||
id: string,
|
||||
type: string,
|
||||
coordinate: Coordinate = { x: 100, y: 100 }
|
||||
) {
|
||||
if (!ALL_TASK_TYPES[type]) {
|
||||
console.warn(`taskType:${type} is invalid!`)
|
||||
return
|
||||
|
|
@ -139,12 +147,12 @@ export function useGraphOperations(options: Options) {
|
|||
* @param {string} code
|
||||
*/
|
||||
function navigateTo(code: string) {
|
||||
if (!graph.value) return;
|
||||
if (!graph.value) return
|
||||
const cell = graph.value.getCellById(code)
|
||||
graph.value.scrollToCell(cell, { animation: { duration: 600 } })
|
||||
graph.value.cleanSelection()
|
||||
graph.value.select(cell)
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
buildEdgeMetadata,
|
||||
|
|
@ -152,6 +160,6 @@ export function useGraphOperations(options: Options) {
|
|||
addNode,
|
||||
setNodeName,
|
||||
getNodes,
|
||||
navigateTo,
|
||||
navigateTo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,34 +15,32 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Graph } from '@antv/x6';
|
||||
import type { Graph } from '@antv/x6'
|
||||
import { ref, Ref } from 'vue'
|
||||
import { useGraphOperations } from './dag-hooks';
|
||||
|
||||
import { useGraphOperations } from './dag-hooks'
|
||||
|
||||
interface Options {
|
||||
graph: Ref<Graph | undefined>;
|
||||
graph: Ref<Graph | undefined>
|
||||
}
|
||||
|
||||
/**
|
||||
* Node search and navigate
|
||||
*/
|
||||
export function useNodeSearch(options: Options) {
|
||||
const { graph } = options
|
||||
|
||||
const { graph } = options;
|
||||
|
||||
const searchInputVisible = ref(false);
|
||||
const allNodes = ref<any>([]);
|
||||
const searchInputVisible = ref(false)
|
||||
const allNodes = ref<any>([])
|
||||
const toggleSearchInput = () => {
|
||||
searchInputVisible.value = !searchInputVisible.value;
|
||||
searchInputVisible.value = !searchInputVisible.value
|
||||
}
|
||||
const { getNodes, navigateTo } = useGraphOperations({ graph });
|
||||
const { getNodes, navigateTo } = useGraphOperations({ graph })
|
||||
const searchNode = (val: string) => {
|
||||
navigateTo(val)
|
||||
}
|
||||
const getAllNodes = () => {
|
||||
const nodes = getNodes();
|
||||
allNodes.value = nodes.map(node => {
|
||||
const nodes = getNodes()
|
||||
allNodes.value = nodes.map((node) => {
|
||||
return {
|
||||
label: node.name,
|
||||
value: node.code
|
||||
|
|
@ -55,6 +53,6 @@ export function useNodeSearch(options: Options) {
|
|||
getAllNodes,
|
||||
allNodes,
|
||||
toggleSearchInput,
|
||||
searchInputVisible,
|
||||
searchInputVisible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,20 +15,19 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Ref } from 'vue';
|
||||
import type { Dragged } from './dag';
|
||||
import type { Ref } from 'vue'
|
||||
import type { Dragged } from './dag'
|
||||
|
||||
interface Options {
|
||||
readonly: Ref<boolean>;
|
||||
dragged: Ref<Dragged>;
|
||||
readonly: Ref<boolean>
|
||||
dragged: Ref<Dragged>
|
||||
}
|
||||
|
||||
/**
|
||||
* Sidebar drag
|
||||
*/
|
||||
export function useSidebarDrag(options: Options) {
|
||||
|
||||
const { readonly, dragged } = options;
|
||||
const { readonly, dragged } = options
|
||||
|
||||
const onDragStart = (e: DragEvent, type: string) => {
|
||||
if (readonly.value) {
|
||||
|
|
@ -45,4 +44,4 @@ export function useSidebarDrag(options: Options) {
|
|||
return {
|
||||
onDragStart
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,18 +16,17 @@
|
|||
*/
|
||||
|
||||
import { defineComponent } from 'vue'
|
||||
import Dag from './dag';
|
||||
import { NCard } from 'naive-ui';
|
||||
import styles from './workflow-definition-create.module.scss';
|
||||
import Dag from './dag'
|
||||
import { NCard } from 'naive-ui'
|
||||
import styles from './workflow-definition-create.module.scss'
|
||||
|
||||
export default defineComponent({
|
||||
name: "WorkflowDefinitionCreate",
|
||||
name: 'WorkflowDefinitionCreate',
|
||||
setup() {
|
||||
|
||||
const slots = {
|
||||
toolbarLeft: () => <span>left-operations</span>,
|
||||
toolbarRight: () => <span>right-operations</span>
|
||||
};
|
||||
}
|
||||
|
||||
return () => (
|
||||
<NCard class={styles.container}>
|
||||
|
|
@ -35,4 +34,4 @@ export default defineComponent({
|
|||
</NCard>
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@
|
|||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: "WorkflowDefinitionDetails",
|
||||
name: 'WorkflowDefinitionDetails',
|
||||
setup() {
|
||||
return () => (
|
||||
<div>WorkflowDefinitionDetails</div>
|
||||
)
|
||||
return () => <div>WorkflowDefinitionDetails</div>
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@
|
|||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: "WorkflowDefinitionList",
|
||||
name: 'WorkflowDefinitionList',
|
||||
setup() {
|
||||
return () => (
|
||||
<div>WorkflowDefinitionList</div>
|
||||
)
|
||||
return () => <div>WorkflowDefinitionList</div>
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@
|
|||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: "WorkflowInstanceDetails",
|
||||
name: 'WorkflowInstanceDetails',
|
||||
setup() {
|
||||
return () => (
|
||||
<div>WorkflowInstanceDetails</div>
|
||||
)
|
||||
return () => <div>WorkflowInstanceDetails</div>
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -18,10 +18,8 @@
|
|||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: "WorkflowInstanceList",
|
||||
name: 'WorkflowInstanceList',
|
||||
setup() {
|
||||
return () => (
|
||||
<div>WorkflowInstanceList</div>
|
||||
)
|
||||
return () => <div>WorkflowInstanceList</div>
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue