This is an automated email from the ASF dual-hosted git repository.
caishunfeng pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git
The following commit(s) were added to refs/heads/dev by this push:
new 45f6c41 [Feature][UI Next] Workflow create (#8123)
45f6c41 is described below
commit 45f6c4197b03566895008577de964f0e5f1c80c8
Author: wangyizhi <[email protected]>
AuthorDate: Wed Jan 19 18:46:54 2022 +0800
[Feature][UI Next] Workflow create (#8123)
---
dolphinscheduler-ui-next/package.json | 1 +
dolphinscheduler-ui-next/pnpm-lock.yaml | 30 ++
.../src/assets/images/task-icons/conditions.png | Bin 0 -> 812 bytes
.../assets/images/task-icons/conditions_hover.png | Bin 0 -> 736 bytes
.../src/assets/images/task-icons/datax.png | Bin 0 -> 1122 bytes
.../src/assets/images/task-icons/datax_hover.png | Bin 0 -> 1127 bytes
.../src/assets/images/task-icons/dependent.png | Bin 0 -> 743 bytes
.../assets/images/task-icons/dependent_hover.png | Bin 0 -> 745 bytes
.../src/assets/images/task-icons/flink.png | Bin 0 -> 1443 bytes
.../src/assets/images/task-icons/flink_hover.png | Bin 0 -> 1348 bytes
.../src/assets/images/task-icons/http.png | Bin 0 -> 707 bytes
.../src/assets/images/task-icons/http_hover.png | Bin 0 -> 709 bytes
.../src/assets/images/task-icons/mr.png | Bin 0 -> 930 bytes
.../src/assets/images/task-icons/mr_hover.png | Bin 0 -> 862 bytes
.../src/assets/images/task-icons/pigeon.png | Bin 0 -> 1192 bytes
.../src/assets/images/task-icons/pigeon_hover.png | Bin 0 -> 1167 bytes
.../src/assets/images/task-icons/procedure.png | Bin 0 -> 1555 bytes
.../assets/images/task-icons/procedure_hover.png | Bin 0 -> 1436 bytes
.../src/assets/images/task-icons/python.png | Bin 0 -> 1618 bytes
.../src/assets/images/task-icons/python_hover.png | Bin 0 -> 1233 bytes
.../src/assets/images/task-icons/seatunnel.png | Bin 0 -> 1086 bytes
.../assets/images/task-icons/seatunnel_hover.png | Bin 0 -> 1054 bytes
.../src/assets/images/task-icons/shell.png | Bin 0 -> 747 bytes
.../src/assets/images/task-icons/shell_hover.png | Bin 0 -> 745 bytes
.../src/assets/images/task-icons/spark.png | Bin 0 -> 1067 bytes
.../src/assets/images/task-icons/spark_hover.png | Bin 0 -> 1066 bytes
.../src/assets/images/task-icons/sql.png | Bin 0 -> 1317 bytes
.../src/assets/images/task-icons/sql_hover.png | Bin 0 -> 1262 bytes
.../src/assets/images/task-icons/sqoop.png | Bin 0 -> 896 bytes
.../src/assets/images/task-icons/sqoop_hover.png | Bin 0 -> 897 bytes
.../src/assets/images/task-icons/sub_process.png | Bin 0 -> 692 bytes
.../assets/images/task-icons/sub_process_hover.png | Bin 0 -> 693 bytes
.../src/assets/images/task-icons/switch.png | Bin 0 -> 885 bytes
.../src/assets/images/task-icons/switch_hover.png | Bin 0 -> 825 bytes
.../src/locales/modules/en_US.ts | 11 +
.../src/locales/modules/zh_CN.ts | 11 +
.../src/router/modules/projects.ts | 16 +
.../src/service/modules/task-definition/index.ts | 13 +-
.../src/service/modules/task-definition/types.ts | 4 -
dolphinscheduler-ui-next/src/utils/index.ts | 4 +-
.../src/utils/{index.ts => truncate-text.ts} | 43 ++-
.../{utils/index.ts => views/projects/index.tsx} | 17 +-
.../index.ts => views/projects/task/config.ts} | 59 +++-
.../projects/task/task-config.tsx} | 17 +-
.../src/views/projects/workflow/dag-canvas.tsx | 60 ++++
.../src/views/projects/workflow/dag-config.ts | 339 +++++++++++++++++++++
.../projects/workflow/dag-hooks.ts} | 22 +-
.../src/views/projects/workflow/dag-sidebar.tsx | 68 +++++
.../src/views/projects/workflow/dag-toolbar.tsx | 180 +++++++++++
.../src/views/projects/workflow/dag.module.scss | 217 +++++++++++++
.../src/views/projects/workflow/dag.tsx | 67 ++++
.../projects/workflow/hook-demo.ts} | 26 +-
.../src/views/projects/workflow/use-canvas-drop.ts | 70 +++++
.../src/views/projects/workflow/use-canvas-init.ts | 177 +++++++++++
.../src/views/projects/workflow/use-cell-active.ts | 154 ++++++++++
.../projects/workflow/use-graph-operations.ts | 157 ++++++++++
.../src/views/projects/workflow/use-node-search.ts | 60 ++++
.../projects/workflow/use-sidebar-drag.ts} | 34 ++-
.../workflow-definition-create.module.scss} | 14 +-
.../workflow/workflow-definition-create.tsx} | 26 +-
.../workflow/workflow-definition-details.tsx} | 17 +-
.../workflow/workflow-definition-list.tsx} | 17 +-
.../workflow/workflow-instance-details.tsx} | 17 +-
.../projects/workflow/workflow-instance-list.tsx} | 17 +-
.../projects/workflow/x6-style.scss} | 29 +-
65 files changed, 1871 insertions(+), 123 deletions(-)
diff --git a/dolphinscheduler-ui-next/package.json
b/dolphinscheduler-ui-next/package.json
index c56b683..941d81f 100644
--- a/dolphinscheduler-ui-next/package.json
+++ b/dolphinscheduler-ui-next/package.json
@@ -10,6 +10,7 @@
"prettier": "prettier --write \"src/**/*.{vue,ts,tsx}\""
},
"dependencies": {
+ "@antv/x6": "^1.29.5",
"@vueuse/core": "^7.5.3",
"axios": "^0.24.0",
"date-fns": "^2.27.0",
diff --git a/dolphinscheduler-ui-next/pnpm-lock.yaml
b/dolphinscheduler-ui-next/pnpm-lock.yaml
index 142dc18..e446f5a 100644
--- a/dolphinscheduler-ui-next/pnpm-lock.yaml
+++ b/dolphinscheduler-ui-next/pnpm-lock.yaml
@@ -18,6 +18,7 @@
lockfileVersion: 5.3
specifiers:
+ '@antv/x6': ^1.29.5
'@types/node': ^16.11.19
'@types/nprogress': ^0.2.0
'@types/qs': ^6.9.7
@@ -56,6 +57,7 @@ specifiers:
vue-tsc: ^0.28.10
dependencies:
+ '@antv/x6': 1.29.5
'@vueuse/core': [email protected]
axios: 0.24.0
date-fns: 2.28.0
@@ -96,6 +98,18 @@ devDependencies:
vue-tsc: [email protected]
packages:
+
+ /@antv/x6/1.29.5:
+ resolution: {integrity:
sha512-U5gg40jo+UtzjdX/7QFenVZgGKOtDFDo60AMNGEvIEzGnixV+2zV0EBJ2f8We4Fp1ZVP0G2pm6uS7ajuuuLsvg==}
+ dependencies:
+ csstype: 3.0.10
+ jquery: 3.6.0
+ jquery-mousewheel: 3.1.13
+ lodash-es: 4.17.21
+ mousetrap: 1.6.5
+ utility-types: 3.10.0
+ dev: false
+
/@babel/code-frame/7.16.7:
resolution:
{
@@ -2792,6 +2806,14 @@ packages:
engines: { node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0 }
dev: false
+ /jquery-mousewheel/3.1.13:
+ resolution: {integrity: sha1-BvAzXxbjU6aV5yBr9QUDy1I6buU=}
+ dev: false
+
+ /jquery/3.6.0:
+ resolution: {integrity:
sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==}
+ dev: false
+
/js-stringify/1.0.2:
resolution: { integrity: sha1-Fzb939lyTyijaCrcYjCufk6Weds= }
dev: true
@@ -3064,6 +3086,9 @@ packages:
{
integrity:
sha512-FYPwxGZAeP6mRRyrr5XTGHD9gRXVjy7GUzF4IPChnyt3fS5WrNxIkS8DNujWf6EQy0Zlzpxw8oTVE+mWI2/D1Q==
}
+
+ /mousetrap/1.6.5:
+ resolution: {integrity:
sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==}
dev: false
/ms/2.0.0:
@@ -4117,6 +4142,11 @@ packages:
deprecated: Please see https://github.com/lydell/urix#deprecated
dev: true
+ /utility-types/3.10.0:
+ resolution: {integrity:
sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==}
+ engines: {node: '>= 4'}
+ dev: false
+
/v8-compile-cache/2.3.0:
resolution:
{
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/conditions.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/conditions.png
new file mode 100755
index 0000000..0849964
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/conditions.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/conditions_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/conditions_hover.png
new file mode 100755
index 0000000..a0c4551
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/conditions_hover.png
differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/datax.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/datax.png
new file mode 100755
index 0000000..22519a9
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/datax.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/datax_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/datax_hover.png
new file mode 100755
index 0000000..986470d
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/datax_hover.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/dependent.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/dependent.png
new file mode 100755
index 0000000..3f0b732
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/dependent.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/dependent_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/dependent_hover.png
new file mode 100755
index 0000000..4b4b866
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/dependent_hover.png
differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/flink.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/flink.png
new file mode 100755
index 0000000..568efbe
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/flink.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/flink_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/flink_hover.png
new file mode 100755
index 0000000..7c8e521
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/flink_hover.png differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/http.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/http.png
new file mode 100755
index 0000000..1d80cd0
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/http.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/http_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/http_hover.png
new file mode 100755
index 0000000..31403be
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/http_hover.png differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/mr.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/mr.png
new file mode 100755
index 0000000..59d082f
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/mr.png differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/mr_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/mr_hover.png
new file mode 100755
index 0000000..e4cfd96
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/mr_hover.png differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/pigeon.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/pigeon.png
new file mode 100644
index 0000000..6fe21d2
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/pigeon.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/pigeon_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/pigeon_hover.png
new file mode 100644
index 0000000..d9d651b
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/pigeon_hover.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/procedure.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/procedure.png
new file mode 100755
index 0000000..e681c28
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/procedure.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/procedure_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/procedure_hover.png
new file mode 100755
index 0000000..82ad43d
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/procedure_hover.png
differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/python.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/python.png
new file mode 100755
index 0000000..8bc4d51
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/python.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/python_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/python_hover.png
new file mode 100755
index 0000000..f94a4f7
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/python_hover.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/seatunnel.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/seatunnel.png
new file mode 100755
index 0000000..bf2f83e
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/seatunnel.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/seatunnel_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/seatunnel_hover.png
new file mode 100755
index 0000000..e6affd6
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/seatunnel_hover.png
differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/shell.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/shell.png
new file mode 100755
index 0000000..4e40b6e
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/shell.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/shell_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/shell_hover.png
new file mode 100755
index 0000000..b615f55
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/shell_hover.png differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/spark.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/spark.png
new file mode 100755
index 0000000..e9ff012
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/spark.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/spark_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/spark_hover.png
new file mode 100755
index 0000000..b0fbc56
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/spark_hover.png differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/sql.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sql.png
new file mode 100755
index 0000000..3415486
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sql.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/sql_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sql_hover.png
new file mode 100755
index 0000000..fabce22
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sql_hover.png differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/sqoop.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sqoop.png
new file mode 100755
index 0000000..2c754d3
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sqoop.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/sqoop_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sqoop_hover.png
new file mode 100755
index 0000000..dd64890
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sqoop_hover.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/sub_process.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sub_process.png
new file mode 100755
index 0000000..fb12061
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sub_process.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/sub_process_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sub_process_hover.png
new file mode 100755
index 0000000..d6b4abc
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/sub_process_hover.png
differ
diff --git a/dolphinscheduler-ui-next/src/assets/images/task-icons/switch.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/switch.png
new file mode 100755
index 0000000..02717ea
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/switch.png differ
diff --git
a/dolphinscheduler-ui-next/src/assets/images/task-icons/switch_hover.png
b/dolphinscheduler-ui-next/src/assets/images/task-icons/switch_hover.png
new file mode 100755
index 0000000..0f9f0c1
Binary files /dev/null and
b/dolphinscheduler-ui-next/src/assets/images/task-icons/switch_hover.png differ
diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
index b26fd0d..f49adf8 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
@@ -286,6 +286,17 @@ const project = {
confirm: 'Confirm',
cancel: 'Cancel',
delete_confirm: 'Delete?'
+ },
+ dag: {
+ createWorkflow: "Create Workflow",
+ search: 'Search',
+ download_png: 'Download PNG',
+ fullscreen_open: 'Open Fullscreen',
+ fullscreen_close: 'Close Fullscreen',
+ workflow_version: 'Workflow Version Info',
+ save: 'Save',
+ close: 'Close',
+ format: 'Format'
}
}
diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
index c5f4264..517f819 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
@@ -286,6 +286,17 @@ const project = {
confirm: '确定',
cancel: '取消',
delete_confirm: '确定删除吗?'
+ },
+ dag: {
+ createWorkflow: "创建工作流",
+ search: '搜索',
+ download_png: '下载工作流图片',
+ fullscreen_open: '全屏',
+ fullscreen_close: '退出全屏',
+ workflow_version: '工作流版本信息',
+ save: '保存',
+ close: '关闭',
+ format: '格式化'
}
}
diff --git a/dolphinscheduler-ui-next/src/router/modules/projects.ts
b/dolphinscheduler-ui-next/src/router/modules/projects.ts
index 5fcbba2..56454a5 100644
--- a/dolphinscheduler-ui-next/src/router/modules/projects.ts
+++ b/dolphinscheduler-ui-next/src/router/modules/projects.ts
@@ -46,6 +46,22 @@ export default {
title: '工作流监控',
showSide: true
}
+ },
+ {
+ path: '/projects/:projectCode/workflow/definitions/create',
+ name: 'workflow-definition-create',
+ component: components['workflow-definition-create'],
+ meta: {
+ title: '创建工作流定义',
+ },
+ },
+ {
+ path: '/projects/:projectCode/workflow/definitions/:code',
+ name: 'workflow-definition-details',
+ component: components['workflow-definition-details'],
+ meta: {
+ title: '工作流定义详情',
+ },
}
]
}
diff --git
a/dolphinscheduler-ui-next/src/service/modules/task-definition/index.ts
b/dolphinscheduler-ui-next/src/service/modules/task-definition/index.ts
index c2c0020..0770c86 100644
--- a/dolphinscheduler-ui-next/src/service/modules/task-definition/index.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/task-definition/index.ts
@@ -21,7 +21,6 @@ import {
ProjectCodeReq,
TaskDefinitionListReq,
TaskDefinitionJsonReq,
- GenNumReq,
CodeReq,
TaskDefinitionJsonObjReq,
ReleaseStateReq,
@@ -51,13 +50,15 @@ export function save(
}
export function genTaskCodeList(
- params: GenNumReq,
- projectCode: ProjectCodeReq
-): any {
- return axios({
+ num: number,
+ projectCode: number
+) {
+ return axios.request<unknown, number[]>({
url: `/projects/${projectCode}/task-definition/gen-task-codes`,
method: 'get',
- params
+ params: {
+ genNum: num
+ }
})
}
diff --git
a/dolphinscheduler-ui-next/src/service/modules/task-definition/types.ts
b/dolphinscheduler-ui-next/src/service/modules/task-definition/types.ts
index e0d75f2..2207e54 100644
--- a/dolphinscheduler-ui-next/src/service/modules/task-definition/types.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/task-definition/types.ts
@@ -37,10 +37,6 @@ interface TaskDefinitionJsonReq {
taskDefinitionJson: string
}
-interface GenNumReq {
- genNum: number
-}
-
interface CodeReq {
code: number
}
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/utils/index.ts
index efca1e8..4639c2c 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++ b/dolphinscheduler-ui-next/src/utils/index.ts
@@ -17,10 +17,12 @@
import mapping from './mapping'
import regex from './regex'
+import truncateText from './truncate-text'
const utils = {
mapping,
- regex
+ regex,
+ truncateText,
}
export default utils
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/utils/truncate-text.ts
similarity index 54%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to dolphinscheduler-ui-next/src/utils/truncate-text.ts
index efca1e8..2605ac0 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++ b/dolphinscheduler-ui-next/src/utils/truncate-text.ts
@@ -15,12 +15,37 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
-
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+/**
+* 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 = ''
+ let len = text.length
+ let chinese = text.match(new RegExp(exp, 'g'))
+ if (chinese) {
+ len += chinese.length
+ }
+ if (len > n) {
+ let i = 0
+ let acc = 0
+ while (true) {
+ let char = text[i]
+ if (exp.test(char)) {
+ acc += 2
+ } else {
+ acc++
+ }
+ if (acc > n) break
+ res += char
+ i++
+ }
+ res += '...'
+ } else {
+ res = text
+ }
+ return res
+}
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/index.tsx
similarity index 83%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to dolphinscheduler-ui-next/src/views/projects/index.tsx
index efca1e8..e6769c4 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/index.tsx
@@ -15,12 +15,13 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
+import { defineComponent } from 'vue'
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+export default defineComponent({
+ name: "Projects",
+ setup() {
+ return () => (
+ <div>Projects</div>
+ )
+ }
+})
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/task/config.ts
similarity index 54%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to dolphinscheduler-ui-next/src/views/projects/task/config.ts
index efca1e8..f19efb7 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/config.ts
@@ -15,12 +15,53 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
-
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+export const ALL_TASK_TYPES:any = {
+ SHELL: {
+ alias: 'SHELL',
+ },
+ SUB_PROCESS: {
+ alias: 'SUB_PROCESS',
+ },
+ PROCEDURE: {
+ alias: 'PROCEDURE',
+ },
+ SQL: {
+ alias: 'SQL',
+ },
+ SPARK: {
+ alias: 'SPARK',
+ },
+ FLINK: {
+ alias: 'FLINK',
+ },
+ MR: {
+ alias: 'MapReduce',
+ },
+ PYTHON: {
+ alias: 'PYTHON',
+ },
+ DEPENDENT: {
+ alias: 'DEPENDENT',
+ },
+ HTTP: {
+ alias: 'HTTP',
+ },
+ DATAX: {
+ alias: 'DataX',
+ },
+ PIGEON: {
+ alias: 'PIGEON',
+ },
+ SQOOP: {
+ alias: 'SQOOP',
+ },
+ CONDITIONS: {
+ alias: 'CONDITIONS',
+ },
+ SWITCH: {
+ alias: 'SWITCH',
+ },
+ SEATUNNEL: {
+ alias: 'WATERDROP',
+ }
+};
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/task/task-config.tsx
similarity index 82%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to dolphinscheduler-ui-next/src/views/projects/task/task-config.tsx
index efca1e8..3ae6873 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/task-config.tsx
@@ -15,12 +15,13 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
+import { defineComponent } from 'vue'
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+export default defineComponent({
+ name: "TaskConfigModal",
+ setup() {
+ return () => (
+ <div>TaskConfigModal</div>
+ )
+ }
+})
\ No newline at end of file
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/dag-canvas.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/dag-canvas.tsx
new file mode 100644
index 0000000..797c876
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/dag-canvas.tsx
@@ -0,0 +1,60 @@
+/*
+ * 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, 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 { useRoute } from 'vue-router'
+
+const props = {
+ dragged: {
+ type: Object as PropType<Ref<Dragged>>,
+ default: ref({
+ x: 0,
+ y: 0,
+ type: ''
+ }),
+ }
+}
+
+export default defineComponent({
+ 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 { paper, minimap, container } = useCanvasInit({ readonly, graph });
+
+ // Change the style on cell hover and select
+ useCellActive({ graph });
+
+ // Drop sidebar item in canvas
+ 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={paper} class={Styles.paper}></div>
+ <div ref={minimap} class={Styles.minimap}></div>
+ </div>
+ );
+ }
+})
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/dag-config.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/dag-config.ts
new file mode 100644
index 0000000..3f8238f
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/dag-config.ts
@@ -0,0 +1,339 @@
+/*
+ * 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.
+ */
+
+export const X6_NODE_NAME = 'dag-task'
+export const X6_EDGE_NAME = 'dag-edge'
+export const X6_PORT_OUT_NAME = 'dag-port-out'
+
+const EDGE_COLOR = '#999999'
+const BG_BLUE = '#DFE9F7'
+const BG_WHITE = '#FFFFFF'
+const NODE_BORDER = '#CCCCCC'
+const TITLE = '#333333'
+const STROKE_BLUE = '#288FFF'
+const NODE_SHADOW = 'drop-shadow(3px 3px 4px rgba(0, 0, 0, 0.2))'
+const EDGE_SHADOW = 'drop-shadow(3px 3px 2px rgba(0, 0, 0, 0.2))'
+
+export const PORT = {
+ groups: {
+ [X6_PORT_OUT_NAME]: {
+ position: {
+ name: 'absolute',
+ args: {
+ x: 200,
+ y: 24
+ }
+ },
+ markup: [
+ {
+ tagName: 'g',
+ selector: 'body',
+ children: [
+ {
+ tagName: 'circle',
+ selector: 'circle-outer'
+ },
+ {
+ tagName: 'text',
+ selector: 'plus-text'
+ },
+ {
+ tagName: 'circle',
+ selector: 'circle-inner'
+ }
+ ]
+ }
+ ],
+ attrs: {
+ body: {
+ magnet: true
+ },
+ 'plus-text': {
+ fontSize: 12,
+ fill: NODE_BORDER,
+ text: '+',
+ textAnchor: 'middle',
+ x: 0,
+ y: 3
+ },
+ 'circle-outer': {
+ stroke: NODE_BORDER,
+ strokeWidth: 1,
+ r: 6,
+ fill: BG_WHITE
+ },
+ 'circle-inner': {
+ r: 4,
+ fill: 'transparent'
+ }
+ }
+ }
+ }
+}
+
+export const PORT_HOVER = {
+ groups: {
+ [X6_PORT_OUT_NAME]: {
+ attrs: {
+ 'circle-outer': {
+ stroke: STROKE_BLUE,
+ fill: BG_BLUE,
+ r: 8
+ },
+ 'circle-inner': {
+ fill: STROKE_BLUE,
+ r: 6
+ }
+ }
+ }
+ }
+}
+
+export const PORT_SELECTED = {
+ groups: {
+ [X6_PORT_OUT_NAME]: {
+ attrs: {
+ 'plus-text': {
+ fill: STROKE_BLUE
+ },
+ 'circle-outer': {
+ stroke: STROKE_BLUE,
+ fill: BG_WHITE
+ }
+ }
+ }
+ }
+}
+
+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,
+ height: 48,
+ markup: [
+ {
+ tagName: 'rect',
+ selector: 'body',
+ className: 'dag-task-body'
+ },
+ {
+ tagName: 'image',
+ selector: 'image'
+ },
+ {
+ tagName: 'text',
+ selector: 'title'
+ }
+ ],
+ attrs: {
+ body: {
+ refWidth: '100%',
+ refHeight: '100%',
+ rx: 6,
+ ry: 6,
+ pointerEvents: 'visiblePainted',
+ fill: BG_WHITE,
+ stroke: NODE_BORDER,
+ strokeWidth: 1,
+ strokeDasharray: 'none',
+ filter: 'none'
+ },
+ image: {
+ width: 30,
+ height: 30,
+ refX: 12,
+ refY: 9
+ },
+ title: {
+ refX: 45,
+ refY: 18,
+ fontFamily: 'Microsoft Yahei',
+ fontSize: 12,
+ fontWeight: 'bold',
+ fill: TITLE,
+ strokeWidth: 0
+ },
+ fo: {
+ refX: '46%',
+ refY: -25,
+ width: 18,
+ height: 18
+ }
+ },
+ ports: {
+ ...PORT,
+ items: [
+ {
+ id: X6_PORT_OUT_NAME,
+ group: X6_PORT_OUT_NAME
+ }
+ ]
+ }
+}
+
+export const NODE_HOVER = {
+ attrs: {
+ body: {
+ fill: BG_BLUE,
+ stroke: STROKE_BLUE,
+ strokeDasharray: '5,2'
+ },
+ title: {
+ fill: STROKE_BLUE
+ }
+ }
+}
+
+export const NODE_SELECTED = {
+ attrs: {
+ body: {
+ filter: NODE_SHADOW,
+ fill: BG_WHITE,
+ stroke: STROKE_BLUE,
+ strokeDasharray: '5,2',
+ strokeWidth: '1.5'
+ },
+ title: {
+ fill: STROKE_BLUE
+ }
+ }
+}
+
+export const EDGE = {
+ attrs: {
+ line: {
+ stroke: EDGE_COLOR,
+ strokeWidth: 1,
+ targetMarker: {
+ tagName: 'path',
+ fill: EDGE_COLOR,
+ strokeWidth: 0,
+ d: 'M 6 -3 0 0 6 3 Z'
+ },
+ filter: 'none'
+ }
+ },
+ connector: {
+ name: 'rounded'
+ },
+ router: {
+ name: 'manhattan',
+ args: {
+ endDirections: ['top', 'bottom', 'left']
+ }
+ },
+ defaultLabel: {
+ markup: [
+ {
+ tagName: 'rect',
+ selector: 'body'
+ },
+ {
+ tagName: 'text',
+ selector: 'label'
+ }
+ ],
+ attrs: {
+ label: {
+ fill: EDGE_COLOR,
+ fontSize: 14,
+ textAnchor: 'middle',
+ textVerticalAnchor: 'middle',
+ pointerEvents: 'none'
+ },
+ body: {
+ ref: 'label',
+ fill: BG_WHITE,
+ stroke: EDGE_COLOR,
+ strokeWidth: 1,
+ rx: 4,
+ ry: 4,
+ refWidth: '140%',
+ refHeight: '140%',
+ refX: '-20%',
+ refY: '-20%'
+ }
+ },
+ position: {
+ distance: 0.5,
+ options: {
+ absoluteDistance: true,
+ reverseDistance: true
+ }
+ }
+ }
+}
+
+export const EDGE_HOVER = {
+ attrs: {
+ line: {
+ stroke: STROKE_BLUE,
+ targetMarker: {
+ fill: STROKE_BLUE
+ }
+ }
+ },
+ defaultLabel: {
+ attrs: {
+ label: {
+ fill: STROKE_BLUE
+ },
+ body: {
+ fill: BG_WHITE,
+ stroke: STROKE_BLUE
+ }
+ }
+ }
+}
+
+export const EDGE_SELECTED = {
+ attrs: {
+ line: {
+ stroke: STROKE_BLUE,
+ targetMarker: {
+ fill: STROKE_BLUE
+ },
+ strokeWidth: 2,
+ filter: EDGE_SHADOW
+ }
+ },
+ defaultLabel: {
+ attrs: {
+ label: {
+ fill: STROKE_BLUE
+ },
+ body: {
+ fill: BG_WHITE,
+ stroke: STROKE_BLUE
+ }
+ }
+ }
+}
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/dag-hooks.ts
similarity index 64%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to dolphinscheduler-ui-next/src/views/projects/workflow/dag-hooks.ts
index efca1e8..0823ad3 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/dag-hooks.ts
@@ -15,12 +15,18 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
+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';
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+export {
+ useCanvasInit,
+ useGraphOperations,
+ useCellActive,
+ useSidebarDrag,
+ useCanvasDrop,
+ useNodeSearch,
+}
\ No newline at end of file
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/dag-sidebar.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/dag-sidebar.tsx
new file mode 100644
index 0000000..c1c6b3d
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/dag-sidebar.tsx
@@ -0,0 +1,68 @@
+/*
+ * 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 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';
+
+const props = {
+ dragged: {
+ type: Object as PropType<Ref<Dragged>>,
+ default: ref({
+ x: 0,
+ y: 0,
+ type: ''
+ }),
+ },
+}
+
+export default defineComponent({
+ name: "workflow-dag-sidebar",
+ props,
+ setup(props) {
+ const readonly = inject('readonly', ref(false))
+ const dragged = props.dragged;
+ const { onDragStart } = useSidebarDrag({
+ readonly,
+ dragged
+ });
+ 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>
+ ))
+ }
+ </div>
+ )
+ }
+})
\ No newline at end of file
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/dag-toolbar.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/dag-toolbar.tsx
new file mode 100644
index 0000000..599664c
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/dag-toolbar.tsx
@@ -0,0 +1,180 @@
+/*
+ * 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, 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 { DataUri } from '@antv/x6'
+import { useFullscreen } from '@vueuse/core';
+import { useRouter } from 'vue-router';
+
+export default defineComponent({
+ name: "workflow-dag-toolbar",
+ setup(props, context) {
+ const { t } = useI18n();
+ const graph = inject('graph', ref());
+ const router = useRouter();
+
+ /**
+ * Node search and navigate
+ */
+ const {
+ searchNode,
+ getAllNodes,
+ allNodes,
+ toggleSearchInput,
+ searchInputVisible
+ } = useNodeSearch({ graph });
+
+ /**
+ * Download Workflow Image
+ * @param {string} fileName
+ * @param {string} bgColor
+ */
+ const downloadPNG = (options = { fileName: 'dag', bgColor: '#f2f3f7' }) =>
{
+ const { fileName, bgColor } = options;
+ graph.value?.toPNG(
+ (dataUri: string) => {
+ DataUri.downloadDataUri(dataUri, `${fileName}.png`)
+ },
+ {
+ padding: {
+ top: 50,
+ right: 50,
+ bottom: 50,
+ left: 50
+ },
+ backgroundColor: bgColor
+ }
+ )
+ }
+
+ /**
+ * Toggle fullscreen
+ */
+ const { isFullscreen, toggle } = useFullscreen();
+
+
+ /**
+ * Open workflow version modal
+ */
+ const openVersionModal = () => {
+ //TODO, same as the version popup in the workflow list page
+ }
+
+ /**
+ * Open DAG format modal
+ */
+ const openDagFormatModal = () => {
+
+ }
+
+ const onClose = () => {
+ router.go(-1)
+ }
+
+ return () => (
+ <div class={Styles.toolbar}>
+ <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>
+ <div
+ class={`${Styles['toolbar-right-item']} ${Styles['node-selector']}
${searchInputVisible.value ? Styles['visible'] : ''}`}
+ >
+ <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>
+ {/* 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>
+ {/* 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>
+ {/* 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>
+ {/* Save workflow */}
+ <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>
+ </div>
+ </div>
+ )
+ }
+})
\ No newline at end of file
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/dag.module.scss
b/dolphinscheduler-ui-next/src/views/projects/workflow/dag.module.scss
new file mode 100644
index 0000000..2298363
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/dag.module.scss
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+$blue: #288fff;
+$blueBg: rgba(40, 143, 255, 0.1);
+$toolbarHeight: 50px;
+
+.dag {
+ height: 100%;
+}
+
+.content {
+ display: flex;
+ height: calc(100% - $toolbarHeight - 20px);
+ margin-top: 20px;
+}
+
+.toolbar {
+ height: $toolbarHeight;
+ display: flex;
+ align-items: center;
+ padding: 0 20px;
+ border: 1px solid var(--n-border-color);
+ border-radius: 4px;
+ justify-content: space-between;
+}
+
+.canvas {
+ width: 100%;
+ height: 100%;
+ position: relative;
+ overflow: hidden;
+ display: flex;
+}
+
+.paper {
+ width: 100%;
+ height: 100%;
+}
+
+.sidebar {
+ width: 190px;
+ height: 100%;
+ margin-right: 20px;
+}
+
+.workflow-name {
+ font-size: 14px;
+}
+
+.draggable {
+ display: flex;
+ width: 100%;
+ height: 32px;
+ margin-bottom: 10px;
+ align-items: center;
+ border: 1px solid var(--n-border-color);
+ padding: 0 10px;
+ border-radius: 4px;
+ transform: translate(0, 0);
+ box-sizing: border-box;
+ cursor: move;
+ font-size: 12px;
+
+ .sidebar-icon {
+ display: block;
+ width: 18px;
+ height: 18px;
+ background-size: 100% 100%;
+ margin-right: 10px;
+ &.icon-shell {
+ background-image: url("../../../assets/images/task-icons/shell.png");
+ }
+ &.icon-sub_process {
+ background-image:
url("../../../assets/images/task-icons/sub_process.png");
+ }
+ &.icon-procedure {
+ background-image: url("../../../assets/images/task-icons/procedure.png");
+ }
+ &.icon-sql {
+ background-image: url("../../../assets/images/task-icons/sql.png");
+ }
+ &.icon-flink {
+ background-image: url("../../../assets/images/task-icons/flink.png");
+ }
+ &.icon-mr {
+ background-image: url("../../../assets/images/task-icons/mr.png");
+ }
+ &.icon-python {
+ background-image: url("../../../assets/images/task-icons/python.png");
+ }
+ &.icon-dependent {
+ background-image: url("../../../assets/images/task-icons/dependent.png");
+ }
+ &.icon-http {
+ background-image: url("../../../assets/images/task-icons/http.png");
+ }
+ &.icon-datax {
+ background-image: url("../../../assets/images/task-icons/datax.png");
+ }
+ &.icon-pigeon {
+ background-image: url("../../../assets/images/task-icons/pigeon.png");
+ }
+ &.icon-sqoop {
+ background-image: url("../../../assets/images/task-icons/sqoop.png");
+ }
+ &.icon-conditions {
+ background-image:
url("../../../assets/images/task-icons/conditions.png");
+ }
+ &.icon-seatunnel {
+ background-image: url("../../../assets/images/task-icons/seatunnel.png");
+ }
+ &.icon-spark {
+ background-image: url("../../../assets/images/task-icons/spark.png");
+ }
+ &.icon-switch {
+ background-image: url("../../../assets/images/task-icons/switch.png");
+ }
+ }
+
+ &:hover {
+ color: $blue;
+ border: 1px dashed $blue;
+ background-color: $blueBg;
+ .sidebar-icon {
+ &.icon-shell {
+ background-image:
url("../../../assets/images/task-icons/shell_hover.png");
+ }
+ &.icon-sub_process {
+ background-image:
url("../../../assets/images/task-icons/sub_process_hover.png");
+ }
+ &.icon-procedure {
+ background-image:
url("../../../assets/images/task-icons/procedure_hover.png");
+ }
+ &.icon-sql {
+ background-image:
url("../../../assets/images/task-icons/sql_hover.png");
+ }
+ &.icon-flink {
+ background-image:
url("../../../assets/images/task-icons/flink_hover.png");
+ }
+ &.icon-mr {
+ background-image:
url("../../../assets/images/task-icons/mr_hover.png");
+ }
+ &.icon-python {
+ background-image:
url("../../../assets/images/task-icons/python_hover.png");
+ }
+ &.icon-dependent {
+ background-image:
url("../../../assets/images/task-icons/dependent_hover.png");
+ }
+ &.icon-http {
+ background-image:
url("../../../assets/images/task-icons/http_hover.png");
+ }
+ &.icon-datax {
+ background-image:
url("../../../assets/images/task-icons/datax_hover.png");
+ }
+ &.icon-pigeon {
+ background-image:
url("../../../assets/images/task-icons/pigeon_hover.png");
+ }
+ &.icon-sqoop {
+ background-image:
url("../../../assets/images/task-icons/sqoop_hover.png");
+ }
+ &.icon-conditions {
+ background-image:
url("../../../assets/images/task-icons/conditions_hover.png");
+ }
+ &.icon-seatunnel {
+ background-image:
url("../../../assets/images/task-icons/seatunnel_hover.png");
+ }
+ &.icon-spark {
+ background-image:
url("../../../assets/images/task-icons/spark_hover.png");
+ }
+ &.icon-switch {
+ background-image:
url("../../../assets/images/task-icons/switch_hover.png");
+ }
+ }
+ }
+}
+
+.minimap {
+ position: absolute;
+ right: 0px;
+ bottom: 0px;
+ border: dashed 1px #e4e4e4;
+ z-index: 9;
+}
+
+.toolbar-right-part {
+ display: flex;
+ align-items: center;
+ .toolbar-right-item {
+ margin-right: 10px;
+ }
+ .node-selector {
+ width: 0;
+ overflow: hidden;
+ transition: all 0.5s;
+ margin-right: 0;
+
+ &.visible {
+ width: 200px;
+ margin-right: 10px;
+ }
+ }
+}
diff --git a/dolphinscheduler-ui-next/src/views/projects/workflow/dag.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/dag.tsx
new file mode 100644
index 0000000..2f0ce4a
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/dag.tsx
@@ -0,0 +1,67 @@
+/*
+ * 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 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";
+
+
+export interface Dragged {
+ x: number;
+ y: number;
+ type: string;
+}
+
+export default defineComponent({
+ name: "workflow-dag",
+ setup(props, context) {
+
+ // Whether the graph can be operated
+ const readonly = ref(false);
+ provide('readonly', readonly);
+
+ const graph = ref<Graph>();
+ provide('graph', graph);
+
+ // The sidebar slots
+ const toolbarSlots = {
+ left: context.slots.toolbarLeft,
+ right: context.slots.toolbarRight
+ }
+
+ // The element currently being dragged up
+ const dragged = ref<Dragged>({
+ x: 0,
+ y: 0,
+ type: ''
+ });
+
+ return () => (
+ <div class={Styles.dag}>
+ <DagToolbar v-slots={toolbarSlots} />
+ <div class={Styles.content}>
+ <DagSidebar dragged={dragged} />
+ <DagCanvas dragged={dragged} />
+ </div>
+ </div>
+ )
+ }
+})
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/hook-demo.ts
similarity index 66%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to dolphinscheduler-ui-next/src/views/projects/workflow/hook-demo.ts
index efca1e8..0e5f0e0 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/hook-demo.ts
@@ -15,12 +15,26 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
+import { ref, onMounted, Ref, onUnmounted } from 'vue'
-const utils = {
- mapping,
- regex
+interface Options {
+ // readonly: Ref<boolean>;
+ // canvas: Ref<HTMLElement | undefined>;
}
-export default utils
+/**
+ * Canvas Init
+ * 1. Bind the graph to the dom
+ * 2. Redraw when the page is resized
+ * 3. Register custom graphics
+ */
+export function useCanvasInit(options: Options) {
+
+ // Whether the graph can be operated
+ const { } = options;
+
+
+ return {
+
+ }
+}
\ No newline at end of file
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/use-canvas-drop.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/use-canvas-drop.ts
new file mode 100644
index 0000000..32fb0d0
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/use-canvas-drop.ts
@@ -0,0 +1,70 @@
+/*
+ * 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 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';
+
+interface Options {
+ 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 { addNode } = useGraphOperations({ graph });
+
+ const onDrop = (e: DragEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ if (readonly.value) {
+ 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 preventDefault = (e: DragEvent) => {
+ e.preventDefault();
+ }
+
+ return {
+ onDrop,
+ onDragenter: preventDefault,
+ onDragover: preventDefault,
+ onDragleave: preventDefault,
+ }
+}
\ No newline at end of file
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/use-canvas-init.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/use-canvas-init.ts
new file mode 100644
index 0000000..16c4479
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/use-canvas-init.ts
@@ -0,0 +1,177 @@
+/*
+ * 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 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';
+
+interface Options {
+ readonly: Ref<boolean>;
+ graph: Ref<Graph | undefined>;
+}
+
+/**
+ * Canvas Init
+ * 1. Bind the graph to the dom
+ * 2. Redraw when the page is resized
+ * 3. Register custom graphics
+ */
+export function useCanvasInit(options: Options) {
+
+ // Whether the graph can be operated
+ 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
+
+ /**
+ * Graph Init, bind graph to the dom
+ */
+ function graphInit() {
+ return new Graph({
+ container: paper.value,
+ selecting: {
+ enabled: true,
+ multiple: true,
+ rubberband: true,
+ rubberEdge: true,
+ movable: true,
+ showNodeSelectionBox: false
+ },
+ scaling: {
+ min: 0.2,
+ max: 2
+ },
+ mousewheel: {
+ enabled: true,
+ modifiers: ['ctrl', 'meta']
+ },
+ scroller: true,
+ grid: {
+ size: 10,
+ visible: true
+ },
+ snapline: true,
+ minimap: {
+ enabled: true,
+ container: minimap.value,
+ scalable: false,
+ width: 200,
+ height: 120
+ },
+ interacting: {
+ edgeLabelMovable: false,
+ nodeMovable: !readonly.value,
+ magnetConnectable: !readonly.value
+ },
+ connecting: {
+ // Whether multiple edges can be created between the same start node
and end
+ allowMulti: false,
+ // Whether a point is allowed to connect to a blank position on the
canvas
+ allowBlank: false,
+ // The start node and the end node are the same node
+ allowLoop: false,
+ // Whether an edge is allowed to link to another edge
+ allowEdge: false,
+ // Whether edges are allowed to link to nodes
+ allowNode: true,
+ // Whether to allow edge links to ports
+ allowPort: false,
+ // Whether all available ports or nodes are highlighted when you drag
the edge
+ highlight: true,
+ createEdge() {
+ return graph.value?.createEdge({ shape: X6_EDGE_NAME })
+ }
+ },
+ highlighting: {
+ nodeAvailable: {
+ name: 'className',
+ args: {
+ className: 'available'
+ }
+ },
+ magnetAvailable: {
+ name: 'className',
+ args: {
+ className: 'available'
+ }
+ },
+ magnetAdsorbed: {
+ name: 'className',
+ args: {
+ className: 'adsorbed'
+ }
+ }
+ }
+ })
+ }
+
+ onMounted(() => {
+ graph.value = graphInit();
+ // Make sure the edge starts with node, not port
+ graph.value.on('edge:connected', ({ isNew, edge }) => {
+ if (isNew) {
+ const sourceNode = edge.getSourceNode() as Node
+ edge.setSource(sourceNode)
+ }
+ })
+ })
+
+ /**
+ * Redraw when the page is resized
+ */
+ const paperResize = debounce(() => {
+ if (!container.value) return;
+ const w = container.value.offsetWidth
+ const h = container.value.offsetHeight
+ graph.value?.resize(w, h);
+ }, 200)
+ onMounted(() => {
+ window.addEventListener('resize', paperResize)
+ })
+ onUnmounted(() => {
+ window.removeEventListener('resize', paperResize)
+ })
+
+ /**
+ * Register custom cells
+ */
+ function registerCustomCells() {
+ Graph.unregisterNode(X6_NODE_NAME)
+ Graph.unregisterEdge(X6_EDGE_NAME)
+ Graph.registerNode(X6_NODE_NAME, { ...NODE })
+ Graph.registerEdge(X6_EDGE_NAME, { ...EDGE })
+ }
+ onMounted(() => {
+ registerCustomCells()
+ })
+
+ return {
+ graph,
+ paper,
+ minimap,
+ container
+ }
+}
\ No newline at end of file
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/use-cell-active.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/use-cell-active.ts
new file mode 100644
index 0000000..341f3d0
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/use-cell-active.ts
@@ -0,0 +1,154 @@
+/*
+ * 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 type { Ref } from 'vue'
+import { onMounted, ref } from 'vue';
+import type { Node, Graph, Edge, Cell } from '@antv/x6'
+import _ from 'lodash';
+import {
+ X6_PORT_OUT_NAME,
+ PORT_HOVER,
+ PORT_SELECTED,
+ PORT,
+ NODE,
+ NODE_HOVER,
+ NODE_SELECTED,
+ EDGE,
+ EDGE_SELECTED,
+ EDGE_HOVER
+} from './dag-config';
+
+interface Options {
+ graph: Ref<Graph | undefined>
+}
+
+/**
+ * Change the style on cell hover and select
+ */
+export function useCellActive(options: Options) {
+
+ const { graph } = options;
+ const hoverCell = ref();
+
+ const isStatusIcon = (tagName: string) => {
+ if (!tagName) return false;
+ return tagName.toLocaleLowerCase() === 'em' || tagName.toLocaleLowerCase()
=== 'body'
+ }
+
+ function setEdgeStyle(edge: Edge) {
+ const isHover = edge === hoverCell.value;
+ const isSelected = graph.value?.isSelected(edge)
+ // TODO
+ // const labelName = this.getEdgeLabelName ? this.getEdgeLabelName(edge) :
''
+ let edgeProps = null
+
+ if (isHover) {
+ edgeProps = _.merge(_.cloneDeep(EDGE), EDGE_HOVER)
+ } else if (isSelected) {
+ edgeProps = _.merge(_.cloneDeep(EDGE), EDGE_SELECTED)
+ } else {
+ edgeProps = _.cloneDeep(EDGE)
+ }
+
+ edge.setAttrs(edgeProps.attrs)
+ edge.setLabels([
+ {
+ ..._.merge(
+ {
+ attrs: _.cloneDeep(edgeProps.defaultLabel.attrs)
+ },
+ // {
+ // attrs: { label: { text: labelName } }
+ // }
+ )
+ }
+ ])
+ }
+
+ function setNodeStyle(node: Node) {
+ 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 portDefault = _.cloneDeep(PORT.groups[X6_PORT_OUT_NAME].attrs)
+ const nodeHover = _.merge(_.cloneDeep(NODE.attrs), NODE_HOVER.attrs)
+ const nodeSelected = _.merge(_.cloneDeep(NODE.attrs), NODE_SELECTED.attrs)
+
+ let img = null
+ let nodeAttrs = null
+ let portAttrs = null
+
+ if (isHover || isSelected) {
+ img =
`/src/assets/images/task-icons/${node.data.taskType.toLocaleLowerCase()}_hover.png`
+ if (isHover) {
+ nodeAttrs = nodeHover
+ portAttrs = _.merge(portDefault, portHover)
+ } else {
+ nodeAttrs = nodeSelected
+ portAttrs = _.merge(portDefault, portSelected)
+ }
+ } else {
+ img =
`/src/assets/images/task-icons/${node.data.taskType.toLocaleLowerCase()}.png`
+ nodeAttrs = NODE.attrs
+ portAttrs = portDefault
+ }
+ node.setAttrByPath('image/xlink:href', img)
+ node.setAttrs(nodeAttrs)
+ node.setPortProp(
+ X6_PORT_OUT_NAME,
+ 'attrs',
+ portAttrs
+ )
+ }
+
+ function updateCellStyle(cell: Cell) {
+ if (cell.isEdge()) {
+ setEdgeStyle(cell)
+ } else if (cell.isNode()) {
+ setNodeStyle(cell)
+ }
+ }
+
+ onMounted(() => {
+ if (graph.value) {
+ // hover
+ graph.value.on('cell:mouseenter', (data) => {
+ const { cell, e } = data
+ if (!isStatusIcon(e.target.tagName)) {
+ hoverCell.value = cell
+ updateCellStyle(cell)
+ }
+ })
+ graph.value.on('cell:mouseleave', ({ cell }) => {
+ hoverCell.value = undefined
+ updateCellStyle(cell)
+ })
+
+ // select
+ graph.value.on('cell:selected', ({ cell }) => {
+ updateCellStyle(cell)
+ })
+ graph.value.on('cell:unselected', ({ cell }) => {
+ updateCellStyle(cell)
+ })
+ }
+ })
+
+ return {
+ hoverCell
+ }
+}
\ No newline at end of file
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/use-graph-operations.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/use-graph-operations.ts
new file mode 100644
index 0000000..c48eb6a
--- /dev/null
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/use-graph-operations.ts
@@ -0,0 +1,157 @@
+/*
+ * 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 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';
+
+interface Options {
+ graph: Ref<Graph | undefined>
+}
+
+type Coordinate = { x: number; y: number; }
+
+/**
+ * Expose some graph operation methods
+ * @param {Options} options
+ */
+export function useGraphOperations(options: Options) {
+
+ const { graph } = options;
+
+
+ /**
+ * Build edge metadata
+ * @param {string} sourceId
+ * @param {string} targetId
+ * @param {string} label
+ */
+ function buildEdgeMetadata(sourceId: string, targetId: string, label: string
= ''): Edge.Metadata {
+ return {
+ shape: X6_EDGE_NAME,
+ source: {
+ cell: sourceId
+ },
+ target: {
+ cell: targetId
+ },
+ labels: label ? [label] : undefined
+ }
+ }
+
+ /**
+ * Build node metadata
+ * @param {string} id
+ * @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;
+ return {
+ id: id,
+ shape: X6_NODE_NAME,
+ x: coordinate.x,
+ y: coordinate.y,
+ data: {
+ taskType: type,
+ taskName: taskName || id
+ },
+ attrs: {
+ image: {
+ // Use href instead of xlink:href, you may lose the icon when
downloadPNG
+ 'xlink:href':
`/src/assets/images/task-icons/${type.toLocaleLowerCase()}.png`
+ },
+ title: {
+ text: truncation
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a node to the graph
+ * @param {string} id
+ * @param {string} taskType
+ * @param {Coordinate} coordinate Default is { 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
+ }
+ const node = buildNodeMetadata(id, type, '', coordinate)
+ graph.value?.addNode(node)
+ }
+
+ /**
+ * Set node name by id
+ * @param {string} id
+ * @param {string} name
+ */
+ function setNodeName(id: string, newName: string) {
+ const node = graph.value?.getCellById(id)
+ if (node) {
+ const truncation = utils.truncateText(newName, 18)
+ node.attr('title/text', truncation)
+ node.setData({ taskName: newName })
+ }
+ }
+
+ /**
+ * Get nodes
+ */
+ function getNodes() {
+ const nodes = graph.value?.getNodes()
+ if (!nodes) return []
+ return nodes.map((node) => {
+ const position = node.getPosition()
+ const data = node.getData()
+ return {
+ code: node.id,
+ position: position,
+ name: data.taskName,
+ type: data.taskType
+ }
+ })
+ }
+
+ /**
+ * Navigate to cell
+ * @param {string} code
+ */
+ function navigateTo(code: string) {
+ 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,
+ buildNodeMetadata,
+ addNode,
+ setNodeName,
+ getNodes,
+ navigateTo,
+ }
+}
\ No newline at end of file
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/use-node-search.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/use-node-search.ts
new file mode 100644
index 0000000..0b26f30
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/use-node-search.ts
@@ -0,0 +1,60 @@
+/*
+ * 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 type { Graph } from '@antv/x6';
+import { ref, Ref } from 'vue'
+import { useGraphOperations } from './dag-hooks';
+
+
+interface Options {
+ graph: Ref<Graph | undefined>;
+}
+
+/**
+ * Node search and navigate
+ */
+export function useNodeSearch(options: Options) {
+
+ const { graph } = options;
+
+ const searchInputVisible = ref(false);
+ const allNodes = ref<any>([]);
+ const toggleSearchInput = () => {
+ searchInputVisible.value = !searchInputVisible.value;
+ }
+ const { getNodes, navigateTo } = useGraphOperations({ graph });
+ const searchNode = (val: string) => {
+ navigateTo(val)
+ }
+ const getAllNodes = () => {
+ const nodes = getNodes();
+ allNodes.value = nodes.map(node => {
+ return {
+ label: node.name,
+ value: node.code
+ }
+ })
+ }
+
+ return {
+ searchNode,
+ getAllNodes,
+ allNodes,
+ toggleSearchInput,
+ searchInputVisible,
+ }
+}
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/use-sidebar-drag.ts
similarity index 61%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to dolphinscheduler-ui-next/src/views/projects/workflow/use-sidebar-drag.ts
index efca1e8..b501453 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/use-sidebar-drag.ts
@@ -15,12 +15,34 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
+import type { Ref } from 'vue';
+import type { Dragged } from './dag';
-const utils = {
- mapping,
- regex
+interface Options {
+ readonly: Ref<boolean>;
+ dragged: Ref<Dragged>;
}
-export default utils
+/**
+ * Sidebar drag
+ */
+export function useSidebarDrag(options: Options) {
+
+ const { readonly, dragged } = options;
+
+ const onDragStart = (e: DragEvent, type: string) => {
+ if (readonly.value) {
+ e.preventDefault()
+ return
+ }
+ dragged.value = {
+ x: e.offsetX,
+ y: e.offsetY,
+ type: type
+ }
+ }
+
+ return {
+ onDragStart
+ }
+}
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-create.module.scss
similarity index 86%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-create.module.scss
index efca1e8..182fdc3 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-create.module.scss
@@ -15,12 +15,8 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
-
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+.container{
+ width: 100%;
+ box-sizing: border-box;
+ height: calc(100vh - 100px);
+ }
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-create.tsx
similarity index 61%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-create.tsx
index efca1e8..eff2932 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-create.tsx
@@ -15,12 +15,24 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
+import { defineComponent } from 'vue'
+import Dag from './dag';
+import { NCard } from 'naive-ui';
+import styles from './workflow-definition-create.module.scss';
-const utils = {
- mapping,
- regex
-}
+export default defineComponent({
+ name: "WorkflowDefinitionCreate",
+ setup() {
-export default utils
+ const slots = {
+ toolbarLeft: () => <span>left-operations</span>,
+ toolbarRight: () => <span>right-operations</span>
+ };
+
+ return () => (
+ <NCard class={styles.container}>
+ <Dag v-slots={slots} />
+ </NCard>
+ )
+ }
+})
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-details.tsx
similarity index 80%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-details.tsx
index efca1e8..ea9c726 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-details.tsx
@@ -15,12 +15,13 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
+import { defineComponent } from 'vue'
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+export default defineComponent({
+ name: "WorkflowDefinitionDetails",
+ setup() {
+ return () => (
+ <div>WorkflowDefinitionDetails</div>
+ )
+ }
+})
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-list.tsx
similarity index 81%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-list.tsx
index efca1e8..2878ba5 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-definition-list.tsx
@@ -15,12 +15,13 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
+import { defineComponent } from 'vue'
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+export default defineComponent({
+ name: "WorkflowDefinitionList",
+ setup() {
+ return () => (
+ <div>WorkflowDefinitionList</div>
+ )
+ }
+})
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-instance-details.tsx
similarity index 80%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-instance-details.tsx
index efca1e8..137c442 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-instance-details.tsx
@@ -15,12 +15,13 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
+import { defineComponent } from 'vue'
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+export default defineComponent({
+ name: "WorkflowInstanceDetails",
+ setup() {
+ return () => (
+ <div>WorkflowInstanceDetails</div>
+ )
+ }
+})
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-instance-list.tsx
similarity index 81%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to
dolphinscheduler-ui-next/src/views/projects/workflow/workflow-instance-list.tsx
index efca1e8..619e6ca 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/workflow-instance-list.tsx
@@ -15,12 +15,13 @@
* limitations under the License.
*/
-import mapping from './mapping'
-import regex from './regex'
+import { defineComponent } from 'vue'
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+export default defineComponent({
+ name: "WorkflowInstanceList",
+ setup() {
+ return () => (
+ <div>WorkflowInstanceList</div>
+ )
+ }
+})
\ No newline at end of file
diff --git a/dolphinscheduler-ui-next/src/utils/index.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/x6-style.scss
similarity index 72%
copy from dolphinscheduler-ui-next/src/utils/index.ts
copy to dolphinscheduler-ui-next/src/views/projects/workflow/x6-style.scss
index efca1e8..549be67 100644
--- a/dolphinscheduler-ui-next/src/utils/index.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/workflow/x6-style.scss
@@ -14,13 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import mapping from './mapping'
-import regex from './regex'
-
-const utils = {
- mapping,
- regex
-}
-
-export default utils
+
+ $STROKE_BLUE: #288fff;
+ $BG_WHITE: #ffffff;
+
+ .x6-node[data-shape="dag-task"] {
+ &.available {
+ .dag-task-body {
+ stroke: $STROKE_BLUE;
+ stroke-width: 1;
+ stroke-dasharray: 5, 2;
+ }
+ &.adsorbed {
+ .dag-task-body {
+ stroke-width: 3;
+ }
+ }
+ }
+ }
+
\ No newline at end of file