Browse Source

[Feature][UI Next] Add workflow relation layout and format. (#8125)

3.0.0/version-upgrade
songjianet 3 years ago committed by GitHub
parent
commit
8ef72fcffc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 238
      dolphinscheduler-ui-next/src/components/chart/modules/Graph.tsx
  2. 4
      dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
  3. 7
      dolphinscheduler-ui-next/src/locales/modules/en_US.ts
  4. 7
      dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
  5. 2
      dolphinscheduler-ui-next/src/router/index.ts
  6. 16
      dolphinscheduler-ui-next/src/router/modules/projects.ts
  7. 5
      dolphinscheduler-ui-next/src/service/modules/task-definition/index.ts
  8. 2
      dolphinscheduler-ui-next/src/store/menu/menu.ts
  9. 4
      dolphinscheduler-ui-next/src/store/menu/types.ts
  10. 4
      dolphinscheduler-ui-next/src/utils/index.ts
  11. 12
      dolphinscheduler-ui-next/src/utils/truncate-text.ts
  12. 8
      dolphinscheduler-ui-next/src/views/projects/index.tsx
  13. 0
      dolphinscheduler-ui-next/src/views/projects/list/components/project-modal.tsx
  14. 0
      dolphinscheduler-ui-next/src/views/projects/list/components/table-action.tsx
  15. 0
      dolphinscheduler-ui-next/src/views/projects/list/index.module.scss
  16. 0
      dolphinscheduler-ui-next/src/views/projects/list/index.tsx
  17. 0
      dolphinscheduler-ui-next/src/views/projects/list/use-form.ts
  18. 0
      dolphinscheduler-ui-next/src/views/projects/list/use-table.ts
  19. 36
      dolphinscheduler-ui-next/src/views/projects/task/config.ts
  20. 8
      dolphinscheduler-ui-next/src/views/projects/task/task-config.tsx
  21. 0
      dolphinscheduler-ui-next/src/views/projects/workflow-monitor/components/definition-card.tsx
  22. 0
      dolphinscheduler-ui-next/src/views/projects/workflow-monitor/components/state-card.tsx
  23. 0
      dolphinscheduler-ui-next/src/views/projects/workflow-monitor/index.tsx
  24. 0
      dolphinscheduler-ui-next/src/views/projects/workflow-monitor/types.ts
  25. 0
      dolphinscheduler-ui-next/src/views/projects/workflow-monitor/use-process-definition.ts
  26. 0
      dolphinscheduler-ui-next/src/views/projects/workflow-monitor/use-process-state.ts
  27. 0
      dolphinscheduler-ui-next/src/views/projects/workflow-monitor/use-table.ts
  28. 0
      dolphinscheduler-ui-next/src/views/projects/workflow-monitor/use-task-state.ts
  29. 54
      dolphinscheduler-ui-next/src/views/projects/workflow-relation/index.tsx
  30. 44
      dolphinscheduler-ui-next/src/views/projects/workflow/dag-canvas.tsx
  31. 34
      dolphinscheduler-ui-next/src/views/projects/workflow/dag-config.ts
  32. 16
      dolphinscheduler-ui-next/src/views/projects/workflow/dag-hooks.ts
  33. 52
      dolphinscheduler-ui-next/src/views/projects/workflow/dag-sidebar.tsx
  34. 251
      dolphinscheduler-ui-next/src/views/projects/workflow/dag-toolbar.tsx
  35. 34
      dolphinscheduler-ui-next/src/views/projects/workflow/dag.tsx
  36. 10
      dolphinscheduler-ui-next/src/views/projects/workflow/hook-demo.ts
  37. 50
      dolphinscheduler-ui-next/src/views/projects/workflow/use-canvas-drop.ts
  38. 32
      dolphinscheduler-ui-next/src/views/projects/workflow/use-canvas-init.ts
  39. 34
      dolphinscheduler-ui-next/src/views/projects/workflow/use-cell-active.ts
  40. 44
      dolphinscheduler-ui-next/src/views/projects/workflow/use-graph-operations.ts
  41. 26
      dolphinscheduler-ui-next/src/views/projects/workflow/use-node-search.ts
  42. 13
      dolphinscheduler-ui-next/src/views/projects/workflow/use-sidebar-drag.ts
  43. 13
      dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-create.tsx
  44. 8
      dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-details.tsx
  45. 8
      dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-list.tsx
  46. 8
      dolphinscheduler-ui-next/src/views/projects/workflow/workflow-instance-details.tsx
  47. 8
      dolphinscheduler-ui-next/src/views/projects/workflow/workflow-instance-list.tsx

238
dolphinscheduler-ui-next/src/components/chart/modules/Graph.tsx

@ -20,129 +20,133 @@ import initChart from '@/components/chart'
import type { Ref } from 'vue' import type { Ref } from 'vue'
const props = { const props = {
height: { height: {
type: [String, Number] as PropType<string | number>, type: [String, Number] as PropType<string | number>,
default: 400 default: 400
}, },
width: { width: {
type: [String, Number] as PropType<string | number>, type: [String, Number] as PropType<string | number>,
default: '100%' default: '100%'
}, },
tooltipFormat: { tooltipFormat: {
type: String as PropType<string>, type: String as PropType<string>,
default: '' default: ''
}, },
legendData: { legendData: {
type: Array as PropType<Array<string>>, type: Array as PropType<Array<string>>,
default: () => [] default: () => []
}, },
seriesData: { seriesData: {
type: Array as PropType<Array<string>>, type: Array as PropType<Array<string>>,
default: () => [] default: () => []
}, },
labelShow: { labelShow: {
type: Array as PropType<Array<string>>, type: Array as PropType<Array<string>>,
default: () => [] default: () => []
}, },
linksData: { linksData: {
type: Array as PropType<Array<string>>, type: Array as PropType<Array<string>>,
default: () => [] default: () => []
}, },
labelFormat: { labelFormat: {
type: String as PropType<string>, type: String as PropType<string>,
default: '' default: ''
} }
} }
const GraphChart = defineComponent({ const GraphChart = defineComponent({
name: 'GraphChart', name: 'GraphChart',
props, props,
setup(props) { setup(props) {
const graphChartRef: Ref<HTMLDivElement | null> = ref(null) const graphChartRef: Ref<HTMLDivElement | null> = ref(null)
const option = { const option = {
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
triggerOn: 'mousemove', triggerOn: 'mousemove',
backgroundColor: '#2D303A', backgroundColor: '#2D303A',
padding: [8, 12], padding: [8, 12],
formatter: props.tooltipFormat, formatter: props.tooltipFormat,
color: '#2D303A', color: '#2D303A',
textStyle: { textStyle: {
rich: { rich: {
a: { a: {
fontSize: 12, fontSize: 12,
color: '#2D303A', color: '#2D303A',
lineHeight: 12, lineHeight: 12,
align: 'left', align: 'left',
padding: [4, 4, 4, 4] padding: [4, 4, 4, 4]
} }
} }
} }
}, },
legend: [{ legend: [
orient: 'horizontal', {
top: 6, orient: 'horizontal',
left: 6, top: 6,
data: props.legendData left: 6,
}], data: props.legendData
series: [{ }
type: 'graph', ],
layout: 'force', series: [
nodeScaleRatio: 1.2, {
draggable: true, type: 'graph',
animation: false, layout: 'force',
data: props.seriesData, nodeScaleRatio: 1.2,
roam: true, draggable: true,
symbol: 'roundRect', animation: false,
symbolSize: 70, data: props.seriesData,
categories: props.legendData, roam: true,
label: { symbol: 'roundRect',
show: props.labelShow, symbolSize: 70,
position: 'inside', categories: props.legendData,
formatter: props.labelFormat, label: {
color: '#222222', show: props.labelShow,
textStyle: { position: 'inside',
rich: { formatter: props.labelFormat,
a: { color: '#222222',
fontSize: 12, textStyle: {
color: '#222222', rich: {
lineHeight: 12, a: {
align: 'left', fontSize: 12,
padding: [4, 4, 4, 4] color: '#222222',
} lineHeight: 12,
} align: 'left',
} padding: [4, 4, 4, 4]
}, }
edgeSymbol: ['circle', 'arrow'], }
edgeSymbolSize: [4, 12], }
force: { },
repulsion: 1000, edgeSymbol: ['circle', 'arrow'],
edgeLength: 300 edgeSymbolSize: [4, 12],
}, force: {
links: props.linksData, repulsion: 1000,
lineStyle: { edgeLength: 300
color: '#999999' },
} links: props.linksData,
}] lineStyle: {
} color: '#999999'
}
}
]
}
initChart(graphChartRef, option) initChart(graphChartRef, option)
return { graphChartRef } return { graphChartRef }
}, },
render() { render() {
const { height, width } = this const { height, width } = this
return ( return (
<div <div
ref='graphChartRef' ref='graphChartRef'
style={{ style={{
height: typeof height === 'number' ? height + 'px' : height, height: typeof height === 'number' ? height + 'px' : height,
width: typeof width === 'number' ? width + 'px' : width width: typeof width === 'number' ? width + 'px' : width
}} }}
/> />
) )
} }
}) })
export default GraphChart export default GraphChart

4
dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts

@ -92,8 +92,8 @@ export function useDataList() {
icon: renderIcon(FundProjectionScreenOutlined) icon: renderIcon(FundProjectionScreenOutlined)
}, },
{ {
label: t('menu.workflow_relationships'), label: t('menu.workflow_relation'),
key: 'workflow-relationships', key: 'workflow-relation',
icon: renderIcon(PartitionOutlined) icon: renderIcon(PartitionOutlined)
}, },
{ {

7
dolphinscheduler-ui-next/src/locales/modules/en_US.ts

@ -48,7 +48,7 @@ const menu = {
monitor: 'Monitor', monitor: 'Monitor',
security: 'Security', security: 'Security',
workflow_monitoring: 'Workflow Monitoring', workflow_monitoring: 'Workflow Monitoring',
workflow_relationships: 'Workflow Relationships', workflow_relation: 'Workflow Relation',
workflow: 'Workflow', workflow: 'Workflow',
workflow_definition: 'Workflow Definition', workflow_definition: 'Workflow Definition',
workflow_instance: 'Workflow Instance', workflow_instance: 'Workflow Instance',
@ -287,8 +287,11 @@ const project = {
cancel: 'Cancel', cancel: 'Cancel',
delete_confirm: 'Delete?' delete_confirm: 'Delete?'
}, },
workflow_relation: {
workflow_relation: 'Workflow Relation'
},
dag: { dag: {
createWorkflow: "Create Workflow", createWorkflow: 'Create Workflow',
search: 'Search', search: 'Search',
download_png: 'Download PNG', download_png: 'Download PNG',
fullscreen_open: 'Open Fullscreen', fullscreen_open: 'Open Fullscreen',

7
dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts

@ -48,7 +48,7 @@ const menu = {
monitor: '监控中心', monitor: '监控中心',
security: '安全中心', security: '安全中心',
workflow_monitoring: '工作流监控', workflow_monitoring: '工作流监控',
workflow_relationships: '工作流关系', workflow_relation: '工作流关系',
workflow: '工作流', workflow: '工作流',
workflow_definition: '工作流定义', workflow_definition: '工作流定义',
workflow_instance: '工作流实例', workflow_instance: '工作流实例',
@ -287,8 +287,11 @@ const project = {
cancel: '取消', cancel: '取消',
delete_confirm: '确定删除吗?' delete_confirm: '确定删除吗?'
}, },
workflow_relation: {
workflow_relation: '工作流关系'
},
dag: { dag: {
createWorkflow: "创建工作流", createWorkflow: '创建工作流',
search: '搜索', search: '搜索',
download_png: '下载工作流图片', download_png: '下载工作流图片',
fullscreen_open: '全屏', fullscreen_open: '全屏',

2
dolphinscheduler-ui-next/src/router/index.ts

@ -50,7 +50,7 @@ router.beforeEach(
) => { ) => {
NProgress.start() NProgress.start()
const menuStore = useMenuStore() const menuStore = useMenuStore()
const metaData:metaData = to.meta const metaData: metaData = to.meta
menuStore.setShowSideStatus(metaData.showSide || false) menuStore.setShowSideStatus(metaData.showSide || false)
next() next()
NProgress.done() NProgress.done()

16
dolphinscheduler-ui-next/src/router/modules/projects.ts

@ -47,21 +47,29 @@ export default {
showSide: true showSide: true
} }
}, },
{
path: '/projects/:projectCode/workflow-relation',
name: 'workflow-relation',
component: components['workflow-relation'],
meta: {
title: '工作流定义'
}
},
{ {
path: '/projects/:projectCode/workflow/definitions/create', path: '/projects/:projectCode/workflow/definitions/create',
name: 'workflow-definition-create', name: 'workflow-definition-create',
component: components['workflow-definition-create'], component: components['workflow-definition-create'],
meta: { meta: {
title: '创建工作流定义', title: '创建工作流定义'
}, }
}, },
{ {
path: '/projects/:projectCode/workflow/definitions/:code', path: '/projects/:projectCode/workflow/definitions/:code',
name: 'workflow-definition-details', name: 'workflow-definition-details',
component: components['workflow-definition-details'], component: components['workflow-definition-details'],
meta: { meta: {
title: '工作流定义详情', title: '工作流定义详情'
}, }
} }
] ]
} }

5
dolphinscheduler-ui-next/src/service/modules/task-definition/index.ts

@ -49,10 +49,7 @@ export function save(
}) })
} }
export function genTaskCodeList( export function genTaskCodeList(num: number, projectCode: number) {
num: number,
projectCode: number
) {
return axios.request<unknown, number[]>({ return axios.request<unknown, number[]>({
url: `/projects/${projectCode}/task-definition/gen-task-codes`, url: `/projects/${projectCode}/task-definition/gen-task-codes`,
method: 'get', method: 'get',

2
dolphinscheduler-ui-next/src/store/menu/menu.ts

@ -46,6 +46,6 @@ export const useMenuStore = defineStore({
}, },
setSideMenuKey(sideMenuKey: string): void { setSideMenuKey(sideMenuKey: string): void {
this.sideMenuKey = sideMenuKey this.sideMenuKey = sideMenuKey
}, }
} }
}) })

4
dolphinscheduler-ui-next/src/store/menu/types.ts

@ -16,8 +16,8 @@
*/ */
interface MenuState { interface MenuState {
menuKey: string, menuKey: string
isShowSide: boolean, isShowSide: boolean
sideMenuKey: string sideMenuKey: string
} }

4
dolphinscheduler-ui-next/src/utils/index.ts

@ -17,12 +17,12 @@
import mapping from './mapping' import mapping from './mapping'
import regex from './regex' import regex from './regex'
import truncateText from './truncate-text' import truncateText from './truncate-text'
const utils = { const utils = {
mapping, mapping,
regex, regex,
truncateText, truncateText
} }
export default utils export default utils

12
dolphinscheduler-ui-next/src/utils/truncate-text.ts

@ -16,11 +16,11 @@
*/ */
/** /**
* truncateText('ALongText', 4) => 'ALon...' * truncateText('ALongText', 4) => 'ALon...'
* @param {number} limit * @param {number} limit
* @param {string} text * @param {string} text
* Each Chinese character is equal to two chars * Each Chinese character is equal to two chars
*/ */
export default function truncateText(text: string, n: number) { export default function truncateText(text: string, n: number) {
const exp = /[\u4E00-\u9FA5]/ const exp = /[\u4E00-\u9FA5]/
let res = '' let res = ''
@ -48,4 +48,4 @@ export default function truncateText(text: string, n: number) {
res = text res = text
} }
return res return res
} }

8
dolphinscheduler-ui-next/src/views/projects/index.tsx

@ -18,10 +18,8 @@
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
export default defineComponent({ export default defineComponent({
name: "Projects", name: 'Projects',
setup() { setup() {
return () => ( return () => <div>Projects</div>
<div>Projects</div>
)
} }
}) })

0
dolphinscheduler-ui-next/src/views/project/list/components/project-modal.tsx → dolphinscheduler-ui-next/src/views/projects/list/components/project-modal.tsx

0
dolphinscheduler-ui-next/src/views/project/list/components/table-action.tsx → dolphinscheduler-ui-next/src/views/projects/list/components/table-action.tsx

0
dolphinscheduler-ui-next/src/views/project/list/index.module.scss → dolphinscheduler-ui-next/src/views/projects/list/index.module.scss

0
dolphinscheduler-ui-next/src/views/project/list/index.tsx → dolphinscheduler-ui-next/src/views/projects/list/index.tsx

0
dolphinscheduler-ui-next/src/views/project/list/use-form.ts → dolphinscheduler-ui-next/src/views/projects/list/use-form.ts

0
dolphinscheduler-ui-next/src/views/project/list/use-table.ts → dolphinscheduler-ui-next/src/views/projects/list/use-table.ts

36
dolphinscheduler-ui-next/src/views/projects/task/config.ts

@ -15,53 +15,53 @@
* limitations under the License. * limitations under the License.
*/ */
export const ALL_TASK_TYPES:any = { export const ALL_TASK_TYPES: any = {
SHELL: { SHELL: {
alias: 'SHELL', alias: 'SHELL'
}, },
SUB_PROCESS: { SUB_PROCESS: {
alias: 'SUB_PROCESS', alias: 'SUB_PROCESS'
}, },
PROCEDURE: { PROCEDURE: {
alias: 'PROCEDURE', alias: 'PROCEDURE'
}, },
SQL: { SQL: {
alias: 'SQL', alias: 'SQL'
}, },
SPARK: { SPARK: {
alias: 'SPARK', alias: 'SPARK'
}, },
FLINK: { FLINK: {
alias: 'FLINK', alias: 'FLINK'
}, },
MR: { MR: {
alias: 'MapReduce', alias: 'MapReduce'
}, },
PYTHON: { PYTHON: {
alias: 'PYTHON', alias: 'PYTHON'
}, },
DEPENDENT: { DEPENDENT: {
alias: 'DEPENDENT', alias: 'DEPENDENT'
}, },
HTTP: { HTTP: {
alias: 'HTTP', alias: 'HTTP'
}, },
DATAX: { DATAX: {
alias: 'DataX', alias: 'DataX'
}, },
PIGEON: { PIGEON: {
alias: 'PIGEON', alias: 'PIGEON'
}, },
SQOOP: { SQOOP: {
alias: 'SQOOP', alias: 'SQOOP'
}, },
CONDITIONS: { CONDITIONS: {
alias: 'CONDITIONS', alias: 'CONDITIONS'
}, },
SWITCH: { SWITCH: {
alias: 'SWITCH', alias: 'SWITCH'
}, },
SEATUNNEL: { SEATUNNEL: {
alias: 'WATERDROP', alias: 'WATERDROP'
} }
}; }

8
dolphinscheduler-ui-next/src/views/projects/task/task-config.tsx

@ -18,10 +18,8 @@
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
export default defineComponent({ export default defineComponent({
name: "TaskConfigModal", name: 'TaskConfigModal',
setup() { setup() {
return () => ( return () => <div>TaskConfigModal</div>
<div>TaskConfigModal</div>
)
} }
}) })

0
dolphinscheduler-ui-next/src/views/project/workflow-monitor/components/definition-card.tsx → dolphinscheduler-ui-next/src/views/projects/workflow-monitor/components/definition-card.tsx

0
dolphinscheduler-ui-next/src/views/project/workflow-monitor/components/state-card.tsx → dolphinscheduler-ui-next/src/views/projects/workflow-monitor/components/state-card.tsx

0
dolphinscheduler-ui-next/src/views/project/workflow-monitor/index.tsx → dolphinscheduler-ui-next/src/views/projects/workflow-monitor/index.tsx

0
dolphinscheduler-ui-next/src/views/project/workflow-monitor/types.ts → dolphinscheduler-ui-next/src/views/projects/workflow-monitor/types.ts

0
dolphinscheduler-ui-next/src/views/project/workflow-monitor/use-process-definition.ts → dolphinscheduler-ui-next/src/views/projects/workflow-monitor/use-process-definition.ts

0
dolphinscheduler-ui-next/src/views/project/workflow-monitor/use-process-state.ts → dolphinscheduler-ui-next/src/views/projects/workflow-monitor/use-process-state.ts

0
dolphinscheduler-ui-next/src/views/project/workflow-monitor/use-table.ts → dolphinscheduler-ui-next/src/views/projects/workflow-monitor/use-table.ts

0
dolphinscheduler-ui-next/src/views/project/workflow-monitor/use-task-state.ts → dolphinscheduler-ui-next/src/views/projects/workflow-monitor/use-task-state.ts

54
dolphinscheduler-ui-next/src/views/projects/workflow-relation/index.tsx

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

44
dolphinscheduler-ui-next/src/views/projects/workflow/dag-canvas.tsx

@ -19,7 +19,12 @@ import { defineComponent, ref, inject } from 'vue'
import Styles from './dag.module.scss' import Styles from './dag.module.scss'
import type { PropType, Ref } from 'vue' import type { PropType, Ref } from 'vue'
import type { Dragged } from './dag' 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' import { useRoute } from 'vue-router'
const props = { const props = {
@ -29,32 +34,45 @@ const props = {
x: 0, x: 0,
y: 0, y: 0,
type: '' type: ''
}), })
} }
} }
export default defineComponent({ export default defineComponent({
name: "workflow-dag-canvas", name: 'workflow-dag-canvas',
props, props,
setup(props, context) { setup(props, context) {
const readonly = inject('readonly', ref(false)); const readonly = inject('readonly', ref(false))
const graph = inject('graph', ref()); const graph = inject('graph', ref())
const route = useRoute(); const route = useRoute()
const projectCode = route.params.projectCode as string; 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 // Change the style on cell hover and select
useCellActive({ graph }); useCellActive({ graph })
// Drop sidebar item in canvas // 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 () => ( 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={paper} class={Styles.paper}></div>
<div ref={minimap} class={Styles.minimap}></div> <div ref={minimap} class={Styles.minimap}></div>
</div> </div>
); )
} }
}) })

34
dolphinscheduler-ui-next/src/views/projects/workflow/dag-config.ts

@ -119,21 +119,25 @@ export const PORT_SELECTED = {
} }
} }
export const NODE_STATUS_MARKUP = [{ export const NODE_STATUS_MARKUP = [
tagName: 'foreignObject', {
selector: 'fo', tagName: 'foreignObject',
children: [ selector: 'fo',
{ children: [
tagName: 'body', {
selector: 'fo-body', tagName: 'body',
ns: 'http://www.w3.org/1999/xhtml', selector: 'fo-body',
children: [{ ns: 'http://www.w3.org/1999/xhtml',
tagName: 'div', children: [
selector: 'status' {
}] tagName: 'div',
} selector: 'status'
] }
}] ]
}
]
}
]
export const NODE = { export const NODE = {
width: 220, width: 220,

16
dolphinscheduler-ui-next/src/views/projects/workflow/dag-hooks.ts

@ -15,12 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { useCanvasInit } from './use-canvas-init'; import { useCanvasInit } from './use-canvas-init'
import { useGraphOperations } from './use-graph-operations'; import { useGraphOperations } from './use-graph-operations'
import { useCellActive } from './use-cell-active'; import { useCellActive } from './use-cell-active'
import { useSidebarDrag } from './use-sidebar-drag'; import { useSidebarDrag } from './use-sidebar-drag'
import { useCanvasDrop } from './use-canvas-drop'; import { useCanvasDrop } from './use-canvas-drop'
import { useNodeSearch } from './use-node-search'; import { useNodeSearch } from './use-node-search'
export { export {
useCanvasInit, useCanvasInit,
@ -28,5 +28,5 @@ export {
useCellActive, useCellActive,
useSidebarDrag, useSidebarDrag,
useCanvasDrop, useCanvasDrop,
useNodeSearch, useNodeSearch
} }

52
dolphinscheduler-ui-next/src/views/projects/workflow/dag-sidebar.tsx

@ -15,12 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import type { PropType, Ref } from 'vue'; import type { PropType, Ref } from 'vue'
import type { Dragged } from './dag'; import type { Dragged } from './dag'
import { defineComponent, ref, inject } from 'vue' import { defineComponent, ref, inject } from 'vue'
import { ALL_TASK_TYPES } from '../task/config'; import { ALL_TASK_TYPES } from '../task/config'
import { useSidebarDrag } from './dag-hooks'; import { useSidebarDrag } from './dag-hooks'
import Styles from './dag.module.scss'; import Styles from './dag.module.scss'
const props = { const props = {
dragged: { dragged: {
@ -29,40 +29,42 @@ const props = {
x: 0, x: 0,
y: 0, y: 0,
type: '' type: ''
}), })
}, }
} }
export default defineComponent({ export default defineComponent({
name: "workflow-dag-sidebar", name: 'workflow-dag-sidebar',
props, props,
setup(props) { setup(props) {
const readonly = inject('readonly', ref(false)) const readonly = inject('readonly', ref(false))
const dragged = props.dragged; const dragged = props.dragged
const { onDragStart } = useSidebarDrag({ const { onDragStart } = useSidebarDrag({
readonly, readonly,
dragged dragged
}); })
const allTaskTypes = Object.keys(ALL_TASK_TYPES).map(type => ({ const allTaskTypes = Object.keys(ALL_TASK_TYPES).map((type) => ({
type, type,
...ALL_TASK_TYPES[type] ...ALL_TASK_TYPES[type]
})); }))
return () => ( return () => (
<div class={Styles.sidebar}> <div class={Styles.sidebar}>
{ {allTaskTypes.map((task) => (
allTaskTypes.map(task => ( <div
<div class={Styles.draggable}
class={Styles.draggable} draggable='true'
draggable="true" onDragstart={(e) => onDragStart(e, task.type)}
onDragstart={(e) => onDragStart(e, task.type)} >
> <em
<em class={`${Styles['sidebar-icon']} ${Styles['icon-' + task.type.toLocaleLowerCase()]}`}></em> class={`${Styles['sidebar-icon']} ${
<span>{task.alias}</span> Styles['icon-' + task.type.toLocaleLowerCase()]
</div> }`}
)) ></em>
} <span>{task.alias}</span>
</div>
))}
</div> </div>
) )
} }
}) })

251
dolphinscheduler-ui-next/src/views/projects/workflow/dag-toolbar.tsx

@ -18,19 +18,26 @@
import { defineComponent, ref, inject } from 'vue' import { defineComponent, ref, inject } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import Styles from './dag.module.scss' import Styles from './dag.module.scss'
import { NTooltip, NIcon, NButton, NSelect } from 'naive-ui'; import { NTooltip, NIcon, NButton, NSelect } from 'naive-ui'
import { SearchOutlined, DownloadOutlined, FullscreenOutlined, FullscreenExitOutlined, InfoCircleOutlined, FormatPainterOutlined } from '@vicons/antd'; import {
import { useNodeSearch } from './dag-hooks'; SearchOutlined,
DownloadOutlined,
FullscreenOutlined,
FullscreenExitOutlined,
InfoCircleOutlined,
FormatPainterOutlined
} from '@vicons/antd'
import { useNodeSearch } from './dag-hooks'
import { DataUri } from '@antv/x6' import { DataUri } from '@antv/x6'
import { useFullscreen } from '@vueuse/core'; import { useFullscreen } from '@vueuse/core'
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router'
export default defineComponent({ export default defineComponent({
name: "workflow-dag-toolbar", name: 'workflow-dag-toolbar',
setup(props, context) { setup(props, context) {
const { t } = useI18n(); const { t } = useI18n()
const graph = inject('graph', ref()); const graph = inject('graph', ref())
const router = useRouter(); const router = useRouter()
/** /**
* Node search and navigate * Node search and navigate
@ -41,15 +48,15 @@ export default defineComponent({
allNodes, allNodes,
toggleSearchInput, toggleSearchInput,
searchInputVisible searchInputVisible
} = useNodeSearch({ graph }); } = useNodeSearch({ graph })
/** /**
* Download Workflow Image * Download Workflow Image
* @param {string} fileName * @param {string} fileName
* @param {string} bgColor * @param {string} bgColor
*/ */
const downloadPNG = (options = { fileName: 'dag', bgColor: '#f2f3f7' }) => { const downloadPNG = (options = { fileName: 'dag', bgColor: '#f2f3f7' }) => {
const { fileName, bgColor } = options; const { fileName, bgColor } = options
graph.value?.toPNG( graph.value?.toPNG(
(dataUri: string) => { (dataUri: string) => {
DataUri.downloadDataUri(dataUri, `${fileName}.png`) DataUri.downloadDataUri(dataUri, `${fileName}.png`)
@ -69,8 +76,7 @@ export default defineComponent({
/** /**
* Toggle fullscreen * Toggle fullscreen
*/ */
const { isFullscreen, toggle } = useFullscreen(); const { isFullscreen, toggle } = useFullscreen()
/** /**
* Open workflow version modal * Open workflow version modal
@ -82,9 +88,7 @@ export default defineComponent({
/** /**
* Open DAG format modal * Open DAG format modal
*/ */
const openDagFormatModal = () => { const openDagFormatModal = () => {}
}
const onClose = () => { const onClose = () => {
router.go(-1) router.go(-1)
@ -92,89 +96,160 @@ export default defineComponent({
return () => ( return () => (
<div class={Styles.toolbar}> <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']}> <div class={Styles['toolbar-right-part']}>
{/* Search node */} {/* Search node */}
<NTooltip v-slots={{ <NTooltip
trigger: () => ( v-slots={{
<NButton class={Styles['toolbar-right-item']} strong secondary circle type="info" onClick={toggleSearchInput} v-slots={{ trigger: () => (
icon: () => ( <NButton
<NIcon> class={Styles['toolbar-right-item']}
<SearchOutlined /> strong
</NIcon> secondary
) circle
}} /> type='info'
), onClick={toggleSearchInput}
default: () => t('project.dag.search') v-slots={{
}}> icon: () => (
</NTooltip> <NIcon>
<SearchOutlined />
</NIcon>
)
}}
/>
),
default: () => t('project.dag.search')
}}
></NTooltip>
<div <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> </div>
{/* Download workflow PNG */} {/* Download workflow PNG */}
<NTooltip v-slots={{ <NTooltip
trigger: () => ( v-slots={{
<NButton class={Styles['toolbar-right-item']} strong secondary circle type="info" onClick={() => downloadPNG()} v-slots={{ trigger: () => (
icon: () => ( <NButton
<NIcon> class={Styles['toolbar-right-item']}
<DownloadOutlined /> strong
</NIcon> secondary
) circle
}} /> type='info'
), onClick={() => downloadPNG()}
default: () => t('project.dag.download_png') v-slots={{
}}> icon: () => (
</NTooltip> <NIcon>
<DownloadOutlined />
</NIcon>
)
}}
/>
),
default: () => t('project.dag.download_png')
}}
></NTooltip>
{/* Toggle fullscreen */} {/* Toggle fullscreen */}
<NTooltip v-slots={{ <NTooltip
trigger: () => ( v-slots={{
<NButton class={Styles['toolbar-right-item']} strong secondary circle type="info" onClick={toggle} v-slots={{ trigger: () => (
icon: () => ( <NButton
<NIcon> class={Styles['toolbar-right-item']}
{isFullscreen.value ? <FullscreenExitOutlined /> : <FullscreenOutlined />} strong
</NIcon> secondary
) circle
}} /> type='info'
), onClick={toggle}
default: () => isFullscreen.value ? t('project.dag.fullscreen_close') : t('project.dag.fullscreen_open') v-slots={{
}}> icon: () => (
</NTooltip> <NIcon>
{isFullscreen.value ? (
<FullscreenExitOutlined />
) : (
<FullscreenOutlined />
)}
</NIcon>
)
}}
/>
),
default: () =>
isFullscreen.value
? t('project.dag.fullscreen_close')
: t('project.dag.fullscreen_open')
}}
></NTooltip>
{/* DAG Format */} {/* DAG Format */}
<NTooltip v-slots={{ <NTooltip
trigger: () => ( v-slots={{
<NButton class={Styles['toolbar-right-item']} strong secondary circle type="info" onClick={openDagFormatModal} v-slots={{ trigger: () => (
icon: () => ( <NButton
<NIcon> class={Styles['toolbar-right-item']}
<FormatPainterOutlined /> strong
</NIcon> secondary
) circle
}} /> type='info'
), onClick={openDagFormatModal}
default: () => t('project.dag.format') v-slots={{
}}> icon: () => (
</NTooltip> <NIcon>
<FormatPainterOutlined />
</NIcon>
)
}}
/>
),
default: () => t('project.dag.format')
}}
></NTooltip>
{/* Version info */} {/* Version info */}
<NTooltip v-slots={{ <NTooltip
trigger: () => ( v-slots={{
<NButton class={Styles['toolbar-right-item']} strong secondary circle type="info" onClick={openVersionModal} v-slots={{ trigger: () => (
icon: () => ( <NButton
<NIcon> class={Styles['toolbar-right-item']}
<InfoCircleOutlined /> strong
</NIcon> secondary
) circle
}} /> type='info'
), onClick={openVersionModal}
default: () => t('project.dag.workflow_version') v-slots={{
}}> icon: () => (
</NTooltip> <NIcon>
<InfoCircleOutlined />
</NIcon>
)
}}
/>
),
default: () => t('project.dag.workflow_version')
}}
></NTooltip>
{/* Save workflow */} {/* 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 */} {/* 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>
</div> </div>
) )
} }
}) })

34
dolphinscheduler-ui-next/src/views/projects/workflow/dag.tsx

@ -15,31 +15,29 @@
* limitations under the License. * limitations under the License.
*/ */
import type { Graph } from '@antv/x6'; import type { Graph } from '@antv/x6'
import { defineComponent, ref, provide } from 'vue' import { defineComponent, ref, provide } from 'vue'
import DagToolbar from './dag-toolbar'; import DagToolbar from './dag-toolbar'
import DagCanvas from './dag-canvas'; import DagCanvas from './dag-canvas'
import DagSidebar from './dag-sidebar'; import DagSidebar from './dag-sidebar'
import Styles from './dag.module.scss'; import Styles from './dag.module.scss'
import "./x6-style.scss"; import './x6-style.scss'
export interface Dragged { export interface Dragged {
x: number; x: number
y: number; y: number
type: string; type: string
} }
export default defineComponent({ export default defineComponent({
name: "workflow-dag", name: 'workflow-dag',
setup(props, context) { setup(props, context) {
// Whether the graph can be operated // Whether the graph can be operated
const readonly = ref(false); const readonly = ref(false)
provide('readonly', readonly); provide('readonly', readonly)
const graph = ref<Graph>(); const graph = ref<Graph>()
provide('graph', graph); provide('graph', graph)
// The sidebar slots // The sidebar slots
const toolbarSlots = { const toolbarSlots = {
@ -52,7 +50,7 @@ export default defineComponent({
x: 0, x: 0,
y: 0, y: 0,
type: '' type: ''
}); })
return () => ( return () => (
<div class={Styles.dag}> <div class={Styles.dag}>
@ -64,4 +62,4 @@ export default defineComponent({
</div> </div>
) )
} }
}) })

10
dolphinscheduler-ui-next/src/views/projects/workflow/hook-demo.ts

@ -29,12 +29,8 @@ interface Options {
* 3. Register custom graphics * 3. Register custom graphics
*/ */
export function useCanvasInit(options: Options) { export function useCanvasInit(options: Options) {
// Whether the graph can be operated // Whether the graph can be operated
const { } = options; const {} = options
return { return {}
}
}
}

50
dolphinscheduler-ui-next/src/views/projects/workflow/use-canvas-drop.ts

@ -15,56 +15,54 @@
* limitations under the License. * limitations under the License.
*/ */
import type { Ref } from 'vue'; import type { Ref } from 'vue'
import type { Graph } from '@antv/x6' import type { Graph } from '@antv/x6'
import type { Dragged } from './dag' import type { Dragged } from './dag'
import { genTaskCodeList } from '@/service/modules/task-definition'; import { genTaskCodeList } from '@/service/modules/task-definition'
import { useGraphOperations } from './dag-hooks'; import { useGraphOperations } from './dag-hooks'
interface Options { interface Options {
readonly: Ref<boolean>; readonly: Ref<boolean>
graph: Ref<Graph | undefined>; graph: Ref<Graph | undefined>
container: Ref<HTMLElement | undefined>; container: Ref<HTMLElement | undefined>
dragged: Ref<Dragged>; dragged: Ref<Dragged>
projectCode: string; projectCode: string
} }
/** /**
* Drop sidebar item in canvas * Drop sidebar item in canvas
*/ */
export function useCanvasDrop(options: Options) { 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) => { const onDrop = (e: DragEvent) => {
e.stopPropagation(); e.stopPropagation()
e.preventDefault(); e.preventDefault()
if (readonly.value) { if (readonly.value) {
return; return
} }
if (dragged.value && graph.value && container.value && projectCode) { if (dragged.value && graph.value && container.value && projectCode) {
const { type, x: eX, y: eY } = dragged.value; const { type, x: eX, y: eY } = dragged.value
const { x, y } = graph.value.clientToLocal(e.clientX, e.clientY); const { x, y } = graph.value.clientToLocal(e.clientX, e.clientY)
const genNums = 1; const genNums = 1
genTaskCodeList(genNums, Number(projectCode)) genTaskCodeList(genNums, Number(projectCode)).then((res) => {
.then((res) => { const [code] = res
const [code] = res addNode(code + '', type, { x: x - eX, y: y - eY })
addNode(code + '', type, { x: x - eX, y: y - eY }) // openTaskConfigModel(code, type)
// openTaskConfigModel(code, type) })
})
} }
} }
const preventDefault = (e: DragEvent) => { const preventDefault = (e: DragEvent) => {
e.preventDefault(); e.preventDefault()
} }
return { return {
onDrop, onDrop,
onDragenter: preventDefault, onDragenter: preventDefault,
onDragover: preventDefault, onDragover: preventDefault,
onDragleave: preventDefault, onDragleave: preventDefault
} }
} }

32
dolphinscheduler-ui-next/src/views/projects/workflow/use-canvas-init.ts

@ -15,20 +15,15 @@
* limitations under the License. * limitations under the License.
*/ */
import type { Node } from '@antv/x6'; import type { Node } from '@antv/x6'
import { ref, onMounted, Ref, onUnmounted } from 'vue' import { ref, onMounted, Ref, onUnmounted } from 'vue'
import { Graph } from '@antv/x6' import { Graph } from '@antv/x6'
import { import { NODE, EDGE, X6_NODE_NAME, X6_EDGE_NAME } from './dag-config'
NODE, import { debounce } from 'lodash'
EDGE,
X6_NODE_NAME,
X6_EDGE_NAME,
} from './dag-config'
import { debounce } from 'lodash';
interface Options { interface Options {
readonly: Ref<boolean>; readonly: Ref<boolean>
graph: Ref<Graph | undefined>; graph: Ref<Graph | undefined>
} }
/** /**
@ -38,13 +33,12 @@ interface Options {
* 3. Register custom graphics * 3. Register custom graphics
*/ */
export function useCanvasInit(options: Options) { export function useCanvasInit(options: Options) {
// Whether the graph can be operated // Whether the graph can be operated
const { readonly, graph } = options; const { readonly, graph } = options
const paper = ref<HTMLElement>(); // The graph mount HTMLElement const paper = ref<HTMLElement>() // The graph mount HTMLElement
const minimap = ref<HTMLElement>(); // The minimap mount HTMLElement const minimap = ref<HTMLElement>() // The minimap mount HTMLElement
const container = ref<HTMLElement>(); // The container of paper and minimap const container = ref<HTMLElement>() // The container of paper and minimap
/** /**
* Graph Init, bind graph to the dom * Graph Init, bind graph to the dom
@ -129,7 +123,7 @@ export function useCanvasInit(options: Options) {
} }
onMounted(() => { onMounted(() => {
graph.value = graphInit(); graph.value = graphInit()
// Make sure the edge starts with node, not port // Make sure the edge starts with node, not port
graph.value.on('edge:connected', ({ isNew, edge }) => { graph.value.on('edge:connected', ({ isNew, edge }) => {
if (isNew) { if (isNew) {
@ -143,10 +137,10 @@ export function useCanvasInit(options: Options) {
* Redraw when the page is resized * Redraw when the page is resized
*/ */
const paperResize = debounce(() => { const paperResize = debounce(() => {
if (!container.value) return; if (!container.value) return
const w = container.value.offsetWidth const w = container.value.offsetWidth
const h = container.value.offsetHeight const h = container.value.offsetHeight
graph.value?.resize(w, h); graph.value?.resize(w, h)
}, 200) }, 200)
onMounted(() => { onMounted(() => {
window.addEventListener('resize', paperResize) window.addEventListener('resize', paperResize)
@ -174,4 +168,4 @@ export function useCanvasInit(options: Options) {
minimap, minimap,
container container
} }
} }

34
dolphinscheduler-ui-next/src/views/projects/workflow/use-cell-active.ts

@ -16,9 +16,9 @@
*/ */
import type { Ref } from 'vue' 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 type { Node, Graph, Edge, Cell } from '@antv/x6'
import _ from 'lodash'; import _ from 'lodash'
import { import {
X6_PORT_OUT_NAME, X6_PORT_OUT_NAME,
PORT_HOVER, PORT_HOVER,
@ -30,7 +30,7 @@ import {
EDGE, EDGE,
EDGE_SELECTED, EDGE_SELECTED,
EDGE_HOVER EDGE_HOVER
} from './dag-config'; } from './dag-config'
interface Options { interface Options {
graph: Ref<Graph | undefined> graph: Ref<Graph | undefined>
@ -40,17 +40,19 @@ interface Options {
* Change the style on cell hover and select * Change the style on cell hover and select
*/ */
export function useCellActive(options: Options) { export function useCellActive(options: Options) {
const { graph } = options
const { graph } = options; const hoverCell = ref()
const hoverCell = ref();
const isStatusIcon = (tagName: string) => { const isStatusIcon = (tagName: string) => {
if (!tagName) return false; if (!tagName) return false
return tagName.toLocaleLowerCase() === 'em' || tagName.toLocaleLowerCase() === 'body' return (
tagName.toLocaleLowerCase() === 'em' ||
tagName.toLocaleLowerCase() === 'body'
)
} }
function setEdgeStyle(edge: Edge) { function setEdgeStyle(edge: Edge) {
const isHover = edge === hoverCell.value; const isHover = edge === hoverCell.value
const isSelected = graph.value?.isSelected(edge) const isSelected = graph.value?.isSelected(edge)
// TODO // TODO
// const labelName = this.getEdgeLabelName ? this.getEdgeLabelName(edge) : '' // const labelName = this.getEdgeLabelName ? this.getEdgeLabelName(edge) : ''
@ -70,7 +72,7 @@ export function useCellActive(options: Options) {
..._.merge( ..._.merge(
{ {
attrs: _.cloneDeep(edgeProps.defaultLabel.attrs) attrs: _.cloneDeep(edgeProps.defaultLabel.attrs)
}, }
// { // {
// attrs: { label: { text: labelName } } // attrs: { label: { text: labelName } }
// } // }
@ -83,7 +85,9 @@ export function useCellActive(options: Options) {
const isHover = node === hoverCell.value const isHover = node === hoverCell.value
const isSelected = graph.value?.isSelected(node) const isSelected = graph.value?.isSelected(node)
const portHover = _.cloneDeep(PORT_HOVER.groups[X6_PORT_OUT_NAME].attrs) 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 portDefault = _.cloneDeep(PORT.groups[X6_PORT_OUT_NAME].attrs)
const nodeHover = _.merge(_.cloneDeep(NODE.attrs), NODE_HOVER.attrs) const nodeHover = _.merge(_.cloneDeep(NODE.attrs), NODE_HOVER.attrs)
const nodeSelected = _.merge(_.cloneDeep(NODE.attrs), NODE_SELECTED.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.setAttrByPath('image/xlink:href', img)
node.setAttrs(nodeAttrs) node.setAttrs(nodeAttrs)
node.setPortProp( node.setPortProp(X6_PORT_OUT_NAME, 'attrs', portAttrs)
X6_PORT_OUT_NAME,
'attrs',
portAttrs
)
} }
function updateCellStyle(cell: Cell) { function updateCellStyle(cell: Cell) {
@ -151,4 +151,4 @@ export function useCellActive(options: Options) {
return { return {
hoverCell hoverCell
} }
} }

44
dolphinscheduler-ui-next/src/views/projects/workflow/use-graph-operations.ts

@ -17,27 +17,22 @@
import type { Ref } from 'vue' import type { Ref } from 'vue'
import type { Node, Graph, Edge } from '@antv/x6' import type { Node, Graph, Edge } from '@antv/x6'
import { import { X6_NODE_NAME, X6_EDGE_NAME } from './dag-config'
X6_NODE_NAME, import { ALL_TASK_TYPES } from '../task/config'
X6_EDGE_NAME, import utils from '@/utils'
} from './dag-config'
import { ALL_TASK_TYPES } from '../task/config';
import utils from '@/utils';
interface Options { interface Options {
graph: Ref<Graph | undefined> graph: Ref<Graph | undefined>
} }
type Coordinate = { x: number; y: number; } type Coordinate = { x: number; y: number }
/** /**
* Expose some graph operation methods * Expose some graph operation methods
* @param {Options} options * @param {Options} options
*/ */
export function useGraphOperations(options: Options) { export function useGraphOperations(options: Options) {
const { graph } = options
const { graph } = options;
/** /**
* Build edge metadata * Build edge metadata
@ -45,7 +40,11 @@ export function useGraphOperations(options: Options) {
* @param {string} targetId * @param {string} targetId
* @param {string} label * @param {string} label
*/ */
function buildEdgeMetadata(sourceId: string, targetId: string, label: string = ''): Edge.Metadata { function buildEdgeMetadata(
sourceId: string,
targetId: string,
label: string = ''
): Edge.Metadata {
return { return {
shape: X6_EDGE_NAME, shape: X6_EDGE_NAME,
source: { source: {
@ -64,8 +63,13 @@ export function useGraphOperations(options: Options) {
* @param {string} taskType * @param {string} taskType
* @param {Coordinate} coordinate Default is { x: 100, y: 100 } * @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 { function buildNodeMetadata(
const truncation = taskName ? utils.truncateText(taskName, 18) : id; id: string,
type: string,
taskName: string,
coordinate: Coordinate = { x: 100, y: 100 }
): Node.Metadata {
const truncation = taskName ? utils.truncateText(taskName, 18) : id
return { return {
id: id, id: id,
shape: X6_NODE_NAME, shape: X6_NODE_NAME,
@ -93,7 +97,11 @@ export function useGraphOperations(options: Options) {
* @param {string} taskType * @param {string} taskType
* @param {Coordinate} coordinate Default is { x: 100, y: 100 } * @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]) { if (!ALL_TASK_TYPES[type]) {
console.warn(`taskType:${type} is invalid!`) console.warn(`taskType:${type} is invalid!`)
return return
@ -139,12 +147,12 @@ export function useGraphOperations(options: Options) {
* @param {string} code * @param {string} code
*/ */
function navigateTo(code: string) { function navigateTo(code: string) {
if (!graph.value) return; if (!graph.value) return
const cell = graph.value.getCellById(code) const cell = graph.value.getCellById(code)
graph.value.scrollToCell(cell, { animation: { duration: 600 } }) graph.value.scrollToCell(cell, { animation: { duration: 600 } })
graph.value.cleanSelection() graph.value.cleanSelection()
graph.value.select(cell) graph.value.select(cell)
}; }
return { return {
buildEdgeMetadata, buildEdgeMetadata,
@ -152,6 +160,6 @@ export function useGraphOperations(options: Options) {
addNode, addNode,
setNodeName, setNodeName,
getNodes, getNodes,
navigateTo, navigateTo
} }
} }

26
dolphinscheduler-ui-next/src/views/projects/workflow/use-node-search.ts

@ -15,34 +15,32 @@
* limitations under the License. * limitations under the License.
*/ */
import type { Graph } from '@antv/x6'; import type { Graph } from '@antv/x6'
import { ref, Ref } from 'vue' import { ref, Ref } from 'vue'
import { useGraphOperations } from './dag-hooks'; import { useGraphOperations } from './dag-hooks'
interface Options { interface Options {
graph: Ref<Graph | undefined>; graph: Ref<Graph | undefined>
} }
/** /**
* Node search and navigate * Node search and navigate
*/ */
export function useNodeSearch(options: Options) { 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 = () => { const toggleSearchInput = () => {
searchInputVisible.value = !searchInputVisible.value; searchInputVisible.value = !searchInputVisible.value
} }
const { getNodes, navigateTo } = useGraphOperations({ graph }); const { getNodes, navigateTo } = useGraphOperations({ graph })
const searchNode = (val: string) => { const searchNode = (val: string) => {
navigateTo(val) navigateTo(val)
} }
const getAllNodes = () => { const getAllNodes = () => {
const nodes = getNodes(); const nodes = getNodes()
allNodes.value = nodes.map(node => { allNodes.value = nodes.map((node) => {
return { return {
label: node.name, label: node.name,
value: node.code value: node.code
@ -55,6 +53,6 @@ export function useNodeSearch(options: Options) {
getAllNodes, getAllNodes,
allNodes, allNodes,
toggleSearchInput, toggleSearchInput,
searchInputVisible, searchInputVisible
} }
} }

13
dolphinscheduler-ui-next/src/views/projects/workflow/use-sidebar-drag.ts

@ -15,20 +15,19 @@
* limitations under the License. * limitations under the License.
*/ */
import type { Ref } from 'vue'; import type { Ref } from 'vue'
import type { Dragged } from './dag'; import type { Dragged } from './dag'
interface Options { interface Options {
readonly: Ref<boolean>; readonly: Ref<boolean>
dragged: Ref<Dragged>; dragged: Ref<Dragged>
} }
/** /**
* Sidebar drag * Sidebar drag
*/ */
export function useSidebarDrag(options: Options) { export function useSidebarDrag(options: Options) {
const { readonly, dragged } = options
const { readonly, dragged } = options;
const onDragStart = (e: DragEvent, type: string) => { const onDragStart = (e: DragEvent, type: string) => {
if (readonly.value) { if (readonly.value) {
@ -45,4 +44,4 @@ export function useSidebarDrag(options: Options) {
return { return {
onDragStart onDragStart
} }
} }

13
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-create.tsx

@ -16,18 +16,17 @@
*/ */
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import Dag from './dag'; import Dag from './dag'
import { NCard } from 'naive-ui'; import { NCard } from 'naive-ui'
import styles from './workflow-definition-create.module.scss'; import styles from './workflow-definition-create.module.scss'
export default defineComponent({ export default defineComponent({
name: "WorkflowDefinitionCreate", name: 'WorkflowDefinitionCreate',
setup() { setup() {
const slots = { const slots = {
toolbarLeft: () => <span>left-operations</span>, toolbarLeft: () => <span>left-operations</span>,
toolbarRight: () => <span>right-operations</span> toolbarRight: () => <span>right-operations</span>
}; }
return () => ( return () => (
<NCard class={styles.container}> <NCard class={styles.container}>
@ -35,4 +34,4 @@ export default defineComponent({
</NCard> </NCard>
) )
} }
}) })

8
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-details.tsx

@ -18,10 +18,8 @@
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
export default defineComponent({ export default defineComponent({
name: "WorkflowDefinitionDetails", name: 'WorkflowDefinitionDetails',
setup() { setup() {
return () => ( return () => <div>WorkflowDefinitionDetails</div>
<div>WorkflowDefinitionDetails</div>
)
} }
}) })

8
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-list.tsx

@ -18,10 +18,8 @@
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
export default defineComponent({ export default defineComponent({
name: "WorkflowDefinitionList", name: 'WorkflowDefinitionList',
setup() { setup() {
return () => ( return () => <div>WorkflowDefinitionList</div>
<div>WorkflowDefinitionList</div>
)
} }
}) })

8
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-instance-details.tsx

@ -18,10 +18,8 @@
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
export default defineComponent({ export default defineComponent({
name: "WorkflowInstanceDetails", name: 'WorkflowInstanceDetails',
setup() { setup() {
return () => ( return () => <div>WorkflowInstanceDetails</div>
<div>WorkflowInstanceDetails</div>
)
} }
}) })

8
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-instance-list.tsx

@ -18,10 +18,8 @@
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
export default defineComponent({ export default defineComponent({
name: "WorkflowInstanceList", name: 'WorkflowInstanceList',
setup() { setup() {
return () => ( return () => <div>WorkflowInstanceList</div>
<div>WorkflowInstanceList</div>
)
} }
}) })

Loading…
Cancel
Save