This is an automated email from the ASF dual-hosted git repository.
kirs 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 78cac08 [Feature][UI Next] Auto layout modal (#8298)
78cac08 is described below
commit 78cac085323b1a28d866ed10357c89f2122d06a3
Author: wangyizhi <[email protected]>
AuthorDate: Mon Feb 7 22:05:36 2022 +0800
[Feature][UI Next] Auto layout modal (#8298)
---
dolphinscheduler-ui-next/package.json | 3 +-
dolphinscheduler-ui-next/pnpm-lock.yaml | 202 +++++++++++++++++++++
.../src/components/modal/index.tsx | 5 +
.../src/locales/modules/en_US.ts | 10 +-
.../src/locales/modules/zh_CN.ts | 10 +-
.../components/dag/dag-auto-layout-modal.tsx | 105 +++++++++++
.../workflow/components/dag/dag-canvas.tsx | 2 +-
.../workflow/components/dag/dag-format-modal.tsx | 35 ----
.../projects/workflow/components/dag/dag-hooks.ts | 4 +-
.../workflow/components/dag/dag-sidebar.tsx | 5 +-
.../workflow/components/dag/dag-toolbar.tsx | 46 +++--
.../workflow/components/dag/dag.module.scss | 100 ++++++----
.../projects/workflow/components/dag/index.tsx | 41 +++--
.../workflow/components/dag/use-canvas-init.ts | 19 +-
.../components/dag/use-graph-auto-layout.ts | 177 ++++++++++++++++++
.../workflow/definition/create/index.module.scss | 18 ++
.../projects/workflow/definition/create/index.tsx | 15 +-
17 files changed, 669 insertions(+), 128 deletions(-)
diff --git a/dolphinscheduler-ui-next/package.json
b/dolphinscheduler-ui-next/package.json
index 948e7c3..a0b4ce1 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/layout": "^0.1.31",
"@antv/x6": "^1.29.5",
"@vueuse/core": "^7.5.3",
"axios": "^0.24.0",
@@ -36,7 +37,7 @@
"@vicons/antd": "^0.11.0",
"@vitejs/plugin-vue": "^1.10.2",
"@vitejs/plugin-vue-jsx": "^1.3.3",
- "dart-sass": "^1.48.0",
+ "dart-sass": "^1.25.0",
"eslint": "^8.6.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
diff --git a/dolphinscheduler-ui-next/pnpm-lock.yaml
b/dolphinscheduler-ui-next/pnpm-lock.yaml
index bab0b61..d0f19e8 100644
--- a/dolphinscheduler-ui-next/pnpm-lock.yaml
+++ b/dolphinscheduler-ui-next/pnpm-lock.yaml
@@ -18,6 +18,7 @@
lockfileVersion: 5.3
specifiers:
+ '@antv/layout': ^0.1.31
'@antv/x6': ^1.29.5
'@types/node': ^16.11.19
'@types/nprogress': ^0.2.0
@@ -57,6 +58,7 @@ specifiers:
vue-tsc: ^0.28.10
dependencies:
+ '@antv/layout': 0.1.31
'@antv/x6': 1.29.5
'@vueuse/core': [email protected]
axios: 0.24.0
@@ -99,6 +101,58 @@ devDependencies:
packages:
+ /@antv/g-webgpu-core/0.5.6:
+ resolution: {integrity:
sha512-DPiH3GkAUiT0Q+LAKeImpI+IOQ/gP2w6HstYKivpFIpBPIvZ/9equM3icVrn1iDfDkZANVXQ1PppcO3xBv1ZTw==}
+ dependencies:
+ eventemitter3: 4.0.7
+ gl-matrix: 3.4.3
+ inversify: 5.1.1
+ inversify-inject-decorators: 3.1.0
+ probe.gl: 3.5.0
+ reflect-metadata: 0.1.13
+ dev: false
+
+ /@antv/g-webgpu-engine/0.5.6:
+ resolution: {integrity:
sha512-D311qYUefdEFwLayutIHqucrAY3cAGH3BdnXS37nq+0nsglrHcNP0Ab1YTinn9RihLoY3yXFTLzrYkJHJbZXDg==}
+ dependencies:
+ '@antv/g-webgpu-core': 0.5.6
+ '@webgpu/glslang': 0.0.15
+ '@webgpu/types': 0.0.31
+ gl-matrix: 3.4.3
+ hammerjs: 2.0.8
+ inversify: 5.1.1
+ inversify-inject-decorators: 3.1.0
+ probe.gl: 3.5.0
+ reflect-metadata: 0.1.13
+ regl: 1.7.0
+ dev: false
+
+ /@antv/g-webgpu/0.5.5:
+ resolution: {integrity:
sha512-TxtBniINFq1jFGEPo46xjJfrbJbUqkFd5wmsRs3tcg/7J7xoldOP1kEadpI3AJG9knMYdE92VpILw1VPd6DgzQ==}
+ dependencies:
+ '@antv/g-webgpu-core': 0.5.6
+ '@antv/g-webgpu-engine': 0.5.6
+ '@webgpu/types': 0.0.31
+ gl-matrix: 3.4.3
+ gl-vec2: 1.3.0
+ hammerjs: 2.0.8
+ inversify: 5.1.1
+ inversify-inject-decorators: 3.1.0
+ polyline-miter-util: 1.0.1
+ polyline-normals: 2.0.2
+ probe.gl: 3.5.0
+ reflect-metadata: 0.1.13
+ dev: false
+
+ /@antv/layout/0.1.31:
+ resolution: {integrity:
sha512-iz9i19dOJGiZr5xBWI5sfG+2K3QVMNAGOBrbjWKH2RGLvGpf2TSFySidhz0siDrcQA46cDsjLmGstezQdgeGzA==}
+ dependencies:
+ '@antv/g-webgpu': 0.5.5
+ '@dagrejs/graphlib': 2.1.4
+ d3-force: 2.1.1
+ ml-matrix: 6.8.2
+ dev: false
+
/@antv/x6/1.29.5:
resolution: {integrity:
sha512-U5gg40jo+UtzjdX/7QFenVZgGKOtDFDo60AMNGEvIEzGnixV+2zV0EBJ2f8We4Fp1ZVP0G2pm6uS7ajuuuLsvg==}
dependencies:
@@ -369,6 +423,13 @@ packages:
- supports-color
dev: true
+ /@babel/runtime/7.17.0:
+ resolution: {integrity:
sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ regenerator-runtime: 0.13.9
+ dev: false
+
/@babel/template/7.16.7:
resolution: {integrity:
sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==}
engines: {node: '>=6.9.0'}
@@ -420,6 +481,12 @@ packages:
vue: 3.2.26
dev: false
+ /@dagrejs/graphlib/2.1.4:
+ resolution: {integrity:
sha512-QCg9sL4uhjn468FDEsb/S9hS2xUZSrv/+dApb1Ze5VKO96pTXKNJZ6MGhIpgWkc1TVhbVGH9/7rq/Mf8/jWicw==}
+ dependencies:
+ lodash: 4.17.21
+ dev: false
+
/@emmetio/abbreviation/2.2.2:
resolution: {integrity:
sha512-TtE/dBnkTCct8+LntkqVrwqQao6EnPAs1YN3cUgxOxTaBlesBCY37ROUAVZrRlG64GNnVShdl/b70RfAI3w5lw==}
dependencies:
@@ -531,6 +598,25 @@ packages:
fastq: 1.13.0
dev: true
+ /@probe.gl/env/3.5.0:
+ resolution: {integrity:
sha512-YdlpZZshhyYxvWDBmZ5RIW2pTR14Pw4p9czMlt/v7F6HbFzWfAdmH7q6xVwFRYxUpQLwhWensWyv4aFysiWl4g==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ dev: false
+
+ /@probe.gl/log/3.5.0:
+ resolution: {integrity:
sha512-nW/qz2X1xY08WU/TsmJP6/6IPNcaY5fS/vLjpC4ahJuE2Mezga4hGM/R2X5JWE/nkPc+BsC5GnAnD13rwAxS7g==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@probe.gl/env': 3.5.0
+ dev: false
+
+ /@probe.gl/stats/3.5.0:
+ resolution: {integrity:
sha512-IH2M+F3c8HR1DTroBARePUFG7wIewumtKA0UFqx51Z7S4hKrD60wFbpMmg0AcF4FvHAXMBoC+kYi1UKW9XbAOw==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ dev: false
+
/@rollup/pluginutils/4.1.2:
resolution: {integrity:
sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ==}
engines: {node: '>= 8.0.0'}
@@ -916,6 +1002,14 @@ packages:
vue-demi: [email protected]
dev: false
+ /@webgpu/glslang/0.0.15:
+ resolution: {integrity:
sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==}
+ dev: false
+
+ /@webgpu/types/0.0.31:
+ resolution: {integrity:
sha512-cvvCMSZBT4VsRNtt0lI6XQqvOIIWw6+NRUtnPUMDVDgsI4pCZColz3qzF5QcP9wIYOHEc3jssIBse8UWONKhlQ==}
+ dev: false
+
/acorn-jsx/[email protected]:
resolution: {integrity:
sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@@ -1213,6 +1307,26 @@ packages:
resolution: {integrity:
sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==}
dev: false
+ /d3-dispatch/2.0.0:
+ resolution: {integrity:
sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==}
+ dev: false
+
+ /d3-force/2.1.1:
+ resolution: {integrity:
sha512-nAuHEzBqMvpFVMf9OX75d00OxvOXdxY+xECIXjW6Gv8BRrXu6gAWbv/9XKrvfJ5i5DCokDW7RYE50LRoK092ew==}
+ dependencies:
+ d3-dispatch: 2.0.0
+ d3-quadtree: 2.0.0
+ d3-timer: 2.0.0
+ dev: false
+
+ /d3-quadtree/2.0.0:
+ resolution: {integrity:
sha512-b0Ed2t1UUalJpc3qXzKi+cPGxeXRr4KU9YSlocN74aTzp6R/Ud43t79yLLqxHRWZfsvWXmbDWPpoENK1K539xw==}
+ dev: false
+
+ /d3-timer/2.0.0:
+ resolution: {integrity:
sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==}
+ dev: false
+
/dart-sass/1.25.0:
resolution: {integrity:
sha512-syNOAstJXAmvD3RifcDk3fiPMyYE2fY8so6w9gf2/wNlKpG0zyH+oiXubEYVOy1WAWkzOc72pbAxwx+3OU4JJA==}
engines: {node: '>=8.9.0'}
@@ -1720,6 +1834,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /eventemitter3/4.0.7:
+ resolution: {integrity:
sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+ dev: false
+
/evtd/0.2.3:
resolution: {integrity:
sha512-tmiT1YUVqFjTY+BSBOAskL83xNx41iUfpvKP6Gcd/xMHjg3mnER98jXGXJyKnxCG19uPc6EhZiUC+MUyvoqCtw==}
dev: false
@@ -1843,6 +1961,14 @@ packages:
has: 1.0.3
has-symbols: 1.0.2
+ /gl-matrix/3.4.3:
+ resolution: {integrity:
sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==}
+ dev: false
+
+ /gl-vec2/1.3.0:
+ resolution: {integrity:
sha512-YiqaAuNsheWmUV0Sa8k94kBB0D6RWjwZztyO+trEYS8KzJ6OQB/4686gdrf59wld4hHFIvaxynO3nRxpk1Ij/A==}
+ dev: false
+
/glob-parent/5.1.2:
resolution: {integrity:
sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -1896,6 +2022,11 @@ packages:
resolution: {integrity:
sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==}
dev: true
+ /hammerjs/2.0.8:
+ resolution: {integrity: sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=}
+ engines: {node: '>=0.8.0'}
+ dev: false
+
/has-flag/3.0.0:
resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=}
engines: {node: '>=4'}
@@ -2014,6 +2145,18 @@ packages:
resolution: {integrity:
sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
+ /inversify-inject-decorators/3.1.0:
+ resolution: {integrity:
sha512-/seBlVp5bXrLQS3DpKEmlgeZL6C7Tf/QITd+IMQrbBBGuCbxb7k3hRAWu9XSreNpFzLgSboz3sClLSEmGwHphw==}
+ dev: false
+
+ /inversify/5.1.1:
+ resolution: {integrity:
sha512-j8grHGDzv1v+8T1sAQ+3boTCntFPfvxLCkNcxB1J8qA0lUN+fAlSyYd+RXKvaPRL4AGyPxViutBEJHNXOyUdFQ==}
+ dev: false
+
+ /is-any-array/2.0.0:
+ resolution: {integrity:
sha512-WdPV58rT3aOWXvvyuBydnCq4S2BM1Yz8shKxlEpk/6x+GX202XRvXOycEFtNgnHVLoc46hpexPFx8Pz1/sMS0w==}
+ dev: false
+
/is-binary-path/2.1.0:
resolution: {integrity:
sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
@@ -2286,6 +2429,32 @@ packages:
hasBin: true
dev: true
+ /ml-array-max/1.2.4:
+ resolution: {integrity:
sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ==}
+ dependencies:
+ is-any-array: 2.0.0
+ dev: false
+
+ /ml-array-min/1.2.3:
+ resolution: {integrity:
sha512-VcZ5f3VZ1iihtrGvgfh/q0XlMobG6GQ8FsNyQXD3T+IlstDv85g8kfV0xUG1QPRO/t21aukaJowDzMTc7j5V6Q==}
+ dependencies:
+ is-any-array: 2.0.0
+ dev: false
+
+ /ml-array-rescale/1.3.7:
+ resolution: {integrity:
sha512-48NGChTouvEo9KBctDfHC3udWnQKNKEWN0ziELvY3KG25GR5cA8K8wNVzracsqSW1QEkAXjTNx+ycgAv06/1mQ==}
+ dependencies:
+ is-any-array: 2.0.0
+ ml-array-max: 1.2.4
+ ml-array-min: 1.2.3
+ dev: false
+
+ /ml-matrix/6.8.2:
+ resolution: {integrity:
sha512-5o2gVLFyieDSgsStEU5mqty4MZqfeytYA/gJqBSw5/Xuob0X2UrFX/k7FDh+YAwjzG/1l8nYa0oDaJ0sGs/RlA==}
+ dependencies:
+ ml-array-rescale: 1.3.7
+ dev: false
+
/monaco-editor/0.31.1:
resolution: {integrity:
sha512-FYPwxGZAeP6mRRyrr5XTGHD9gRXVjy7GUzF4IPChnyt3fS5WrNxIkS8DNujWf6EQy0Zlzpxw8oTVE+mWI2/D1Q==}
dev: false
@@ -2470,6 +2639,18 @@ packages:
vue-demi: [email protected]
dev: false
+ /polyline-miter-util/1.0.1:
+ resolution: {integrity: sha1-tpPyOJ6g3tNqa89ezS7OS2kX2Vc=}
+ dependencies:
+ gl-vec2: 1.3.0
+ dev: false
+
+ /polyline-normals/2.0.2:
+ resolution: {integrity: sha1-oXN+ddjA3MsaWR+csn8J7vS30TU=}
+ dependencies:
+ polyline-miter-util: 1.0.1
+ dev: false
+
/postcss-filter-plugins/3.0.1:
resolution: {integrity:
sha512-tRKbW4wWBEkSSFuJtamV2wkiV9rj6Yy7P3Y13+zaynlPEEZt8EgYKn3y/RBpMeIhNmHXFlSdzofml65hD5OafA==}
dependencies:
@@ -2555,6 +2736,15 @@ packages:
react-is: 17.0.2
dev: false
+ /probe.gl/3.5.0:
+ resolution: {integrity:
sha512-KWj8u0PNytr/rVwcQFcN7O8SK7n/ITOsUZ91l4fSX95oHhKvVCI7eadrzFUzFRlXkFfBWpMWZXFHITsHHHUctw==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@probe.gl/env': 3.5.0
+ '@probe.gl/log': 3.5.0
+ '@probe.gl/stats': 3.5.0
+ dev: false
+
/progress/2.0.3:
resolution: {integrity:
sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
engines: {node: '>=0.4.0'}
@@ -2689,11 +2879,23 @@ packages:
picomatch: 2.3.1
dev: true
+ /reflect-metadata/0.1.13:
+ resolution: {integrity:
sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==}
+ dev: false
+
+ /regenerator-runtime/0.13.9:
+ resolution: {integrity:
sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==}
+ dev: false
+
/regexpp/3.2.0:
resolution: {integrity:
sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==}
engines: {node: '>=8'}
dev: true
+ /regl/1.7.0:
+ resolution: {integrity:
sha512-bEAtp/qrtKucxXSJkD4ebopFZYP0q1+3Vb2WECWv/T8yQEgKxDxJ7ztO285tAMaYZVR6mM1GgI6CCn8FROtL1w==}
+ dev: false
+
/request-light/0.5.7:
resolution: {integrity:
sha512-i/wKzvcx7Er8tZnvqSxWuNO5ZGggu2UgZAqj/RyZ0si7lBTXL7kZiI/dWxzxnQjaY7s5HEy1qK21Do4Ncr6cVw==}
dev: true
diff --git a/dolphinscheduler-ui-next/src/components/modal/index.tsx
b/dolphinscheduler-ui-next/src/components/modal/index.tsx
index c8a09b8..a5e2769 100644
--- a/dolphinscheduler-ui-next/src/components/modal/index.tsx
+++ b/dolphinscheduler-ui-next/src/components/modal/index.tsx
@@ -46,6 +46,10 @@ const props = {
confirmLoading: {
type: Boolean as PropType<boolean>,
default: false
+ },
+ autoFocus: {
+ type: Boolean as PropType<boolean>,
+ default: true
}
}
@@ -75,6 +79,7 @@ const Modal = defineComponent({
v-model={[this.show, 'show']}
class={styles.container}
mask-closable={false}
+ auto-focus={this.autoFocus}
>
<NCard title={this.title}>
{{
diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
index 240ee14..1e69969 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
@@ -482,15 +482,19 @@ const project = {
download_log: 'Download Log'
},
dag: {
- createWorkflow: 'Create Workflow',
+ create: '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'
+ format: 'Format',
+ layout_type: 'Layout Type',
+ grid_layout: 'Grid',
+ dagre_layout: 'Dagre',
+ rows: 'Rows',
+ cols: 'Cols'
}
}
diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
index 2aa8926..e0f5920 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
@@ -481,15 +481,19 @@ const project = {
download_log: '下载日志'
},
dag: {
- createWorkflow: '创建工作流',
+ create: '创建工作流',
search: '搜索',
download_png: '下载工作流图片',
fullscreen_open: '全屏',
fullscreen_close: '退出全屏',
- workflow_version: '工作流版本信息',
save: '保存',
close: '关闭',
- format: '格式化'
+ format: '格式化',
+ layout_type: '布局类型',
+ grid_layout: '网格布局',
+ dagre_layout: '层次布局',
+ rows: '行数',
+ cols: '列数'
}
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-auto-layout-modal.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-auto-layout-modal.tsx
new file mode 100644
index 0000000..2beea21
--- /dev/null
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-auto-layout-modal.tsx
@@ -0,0 +1,105 @@
+/*
+ * 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, PropType, ref } from 'vue'
+import type { Ref } from 'vue'
+import Modal from '@/components/modal'
+import { useI18n } from 'vue-i18n'
+import {
+ NForm,
+ NFormItem,
+ NInputNumber,
+ NRadioButton,
+ NRadioGroup
+} from 'naive-ui'
+import { LAYOUT_TYPE } from './use-graph-auto-layout'
+import './x6-style.scss'
+
+const props = {
+ visible: {
+ type: Boolean as PropType<boolean>,
+ default: false
+ },
+ formValue: {
+ type: Object as PropType<Ref<any>>,
+ default: ref()
+ },
+ formRef: {
+ type: Object as PropType<Ref<any>>,
+ default: ref()
+ },
+ submit: {
+ type: Function as PropType<() => void>,
+ default: () => {}
+ },
+ cancel: {
+ type: Function as PropType<() => void>,
+ default: () => {}
+ }
+}
+
+export default defineComponent({
+ name: 'dag-format-modal',
+ props,
+ setup(props, context) {
+ const { t } = useI18n()
+ const { formValue, formRef, submit, cancel } = props
+
+ return () => (
+ <Modal
+ show={props.visible}
+ title={t('project.dag.format')}
+ onConfirm={submit}
+ onCancel={cancel}
+ autoFocus={false}
+ >
+ <NForm
+ label-width='80'
+ model={formValue.value}
+ rules={{}}
+ size='medium'
+ label-placement='left'
+ ref={formRef}
+ >
+ <NFormItem label={t('project.dag.layout_type')} path='type'>
+ <NRadioGroup
+ v-model={[formValue.value.type, 'value']}
+ name='radiogroup'
+ >
+ <NRadioButton value={LAYOUT_TYPE.GRID}>
+ {t('project.dag.grid_layout')}
+ </NRadioButton>
+ <NRadioButton value={LAYOUT_TYPE.DAGRE}>
+ {t('project.dag.dagre_layout')}
+ </NRadioButton>
+ </NRadioGroup>
+ </NFormItem>
+ {formValue.value.type === LAYOUT_TYPE.GRID ? (
+ <NFormItem label={t('project.dag.rows')} path='rows'>
+ <NInputNumber v-model={[formValue.value.rows, 'value']} min={0}
/>
+ </NFormItem>
+ ) : null}
+ {formValue.value.type === LAYOUT_TYPE.GRID ? (
+ <NFormItem label={t('project.dag.cols')} path='cols'>
+ <NInputNumber v-model={[formValue.value.cols, 'value']} min={0}
/>
+ </NFormItem>
+ ) : null}
+ </NForm>
+ </Modal>
+ )
+ }
+})
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-canvas.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-canvas.tsx
index 5aaa962..221bc8e 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-canvas.tsx
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-canvas.tsx
@@ -18,7 +18,7 @@
import { defineComponent, ref, inject } from 'vue'
import Styles from './dag.module.scss'
import type { PropType, Ref } from 'vue'
-import type { Dragged } from './dag'
+import type { Dragged } from './index'
import { useCanvasInit, useCellActive, useCanvasDrop } from './dag-hooks'
import { useRoute } from 'vue-router'
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-format-modal.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-format-modal.tsx
deleted file mode 100644
index 9efc269..0000000
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-format-modal.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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, PropType } from 'vue'
-import Modal from '@/components/modal'
-import './x6-style.scss'
-
-const props = {
- show: {
- type: Boolean as PropType<boolean>,
- default: false
- }
-}
-
-export default defineComponent({
- name: 'dag-format-modal',
- props,
- setup(props, context) {
- return () => <Modal show={props.show}></Modal>
- }
-})
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-hooks.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-hooks.ts
index f9054d0..a2d57e2 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-hooks.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-hooks.ts
@@ -21,6 +21,7 @@ import { useCellActive } from './use-cell-active'
import { useSidebarDrag } from './use-sidebar-drag'
import { useCanvasDrop } from './use-canvas-drop'
import { useNodeSearch } from './use-node-search'
+import { useGraphAutoLayout } from './use-graph-auto-layout'
export {
useCanvasInit,
@@ -28,5 +29,6 @@ export {
useCellActive,
useSidebarDrag,
useCanvasDrop,
- useNodeSearch
+ useNodeSearch,
+ useGraphAutoLayout
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-sidebar.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-sidebar.tsx
index 1a56970..420d4eb 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-sidebar.tsx
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-sidebar.tsx
@@ -57,9 +57,10 @@ export default defineComponent({
onDragstart={(e) => onDragStart(e, task.type)}
>
<em
- class={`${Styles['sidebar-icon']} ${
+ class={[
+ Styles['sidebar-icon'],
Styles['icon-' + task.type.toLocaleLowerCase()]
- }`}
+ ]}
></em>
<span>{task.alias}</span>
</div>
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-toolbar.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-toolbar.tsx
index d514700..b1081ce 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-toolbar.tsx
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-toolbar.tsx
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import { defineComponent, ref, inject } from 'vue'
+import { defineComponent, ref, inject, PropType } from 'vue'
import { useI18n } from 'vue-i18n'
import Styles from './dag.module.scss'
import { NTooltip, NIcon, NButton, NSelect } from 'naive-ui'
@@ -31,11 +31,23 @@ import { useNodeSearch } from './dag-hooks'
import { DataUri } from '@antv/x6'
import { useFullscreen } from '@vueuse/core'
import { useRouter } from 'vue-router'
+import { useThemeStore } from '@/store/theme/theme'
+
+const props = {
+ layoutToggle: {
+ type: Function as PropType<(bool?: boolean) => void>,
+ default: () => {}
+ }
+}
export default defineComponent({
name: 'workflow-dag-toolbar',
+ props,
setup(props, context) {
const { t } = useI18n()
+
+ const themeStore = useThemeStore()
+
const graph = inject('graph', ref())
const router = useRouter()
@@ -88,11 +100,8 @@ export default defineComponent({
/**
* Open DAG format modal
*/
- const { openFormatModal } = inject('formatModal', {
- openFormatModal: (bool: boolean) => {}
- })
const onFormat = () => {
- openFormatModal(true)
+ props.layoutToggle(true)
}
/**
@@ -103,10 +112,13 @@ export default defineComponent({
}
return () => (
- <div class={Styles.toolbar}>
- <span class={Styles['workflow-name']}>
- {t('project.workflow.create_workflow')}
- </span>
+ <div
+ class={[
+ Styles.toolbar,
+ Styles[themeStore.darkTheme ? 'toolbar-dark' : 'toolbar-light']
+ ]}
+ >
+ <span class={Styles['workflow-name']}>{t('project.dag.create')}</span>
<div class={Styles['toolbar-right-part']}>
{/* Search node */}
<NTooltip
@@ -128,7 +140,7 @@ export default defineComponent({
}}
/>
),
- default: () => t('project.workflow.search')
+ default: () => t('project.dag.search')
}}
></NTooltip>
<div
@@ -164,7 +176,7 @@ export default defineComponent({
}}
/>
),
- default: () => t('project.workflow.download_png')
+ default: () => t('project.dag.download_png')
}}
></NTooltip>
{/* Toggle fullscreen */}
@@ -193,8 +205,8 @@ export default defineComponent({
),
default: () =>
isFullscreen.value
- ? t('project.workflow.fullscreen_close')
- : t('project.workflow.fullscreen_open')
+ ? t('project.dag.fullscreen_close')
+ : t('project.dag.fullscreen_open')
}}
></NTooltip>
{/* DAG Format */}
@@ -217,7 +229,7 @@ export default defineComponent({
}}
/>
),
- default: () => t('project.workflow.format')
+ default: () => t('project.dag.format')
}}
></NTooltip>
{/* Version info */}
@@ -240,7 +252,7 @@ export default defineComponent({
}}
/>
),
- default: () => t('project.workflow.workflow_version')
+ default: () => t('project.workflow.version_info')
}}
></NTooltip>
{/* Save workflow */}
@@ -250,11 +262,11 @@ export default defineComponent({
secondary
round
>
- {t('project.workflow.save')}
+ {t('project.dag.save')}
</NButton>
{/* Return to previous page */}
<NButton secondary round onClick={onClose}>
- {t('project.workflow.close')}
+ {t('project.dag.close')}
</NButton>
</div>
</div>
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag.module.scss
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag.module.scss
index dda1ed9..52e0edb 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag.module.scss
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag.module.scss
@@ -19,8 +19,14 @@ $blue: #288fff;
$blueBg: rgba(40, 143, 255, 0.1);
$toolbarHeight: 50px;
+$borderDark: rgba(255, 255, 255, 0.09);
+$borderLight: rgb(239, 239, 245);
+$bgDark: rgb(24, 24, 28);
+$bgLight: #ffffff;
+
.dag {
height: 100%;
+ overflow: hidden;
}
.content {
@@ -34,17 +40,25 @@ $toolbarHeight: 50px;
display: flex;
align-items: center;
padding: 0 20px;
- border: 1px solid var(--n-border-color);
border-radius: 4px;
justify-content: space-between;
}
+.dag-dark .toolbar {
+ border: 1px solid $borderDark;
+}
+
+.dag-light .toolbar-light {
+ border: 1px solid $borderLight;
+}
+
.canvas {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
display: flex;
+ flex: 1;
}
.paper {
@@ -68,7 +82,6 @@ $toolbarHeight: 50px;
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);
@@ -83,112 +96,125 @@ $toolbarHeight: 50px;
background-size: 100% 100%;
margin-right: 10px;
&.icon-shell {
- background-image: url('@/assets/images/task-icons/shell.png');
+ background-image: url("@/assets/images/task-icons/shell.png");
}
&.icon-sub_process {
- background-image: url('@/assets/images/task-icons/sub_process.png');
+ background-image: url("@/assets/images/task-icons/sub_process.png");
}
&.icon-procedure {
- background-image: url('@/assets/images/task-icons/procedure.png');
+ background-image: url("@/assets/images/task-icons/procedure.png");
}
&.icon-sql {
- background-image: url('@/assets/images/task-icons/sql.png');
+ background-image: url("@/assets/images/task-icons/sql.png");
}
&.icon-flink {
- background-image: url('@/assets/images/task-icons/flink.png');
+ background-image: url("@/assets/images/task-icons/flink.png");
}
&.icon-mr {
- background-image: url('@/assets/images/task-icons/mr.png');
+ background-image: url("@/assets/images/task-icons/mr.png");
}
&.icon-python {
- background-image: url('@/assets/images/task-icons/python.png');
+ background-image: url("@/assets/images/task-icons/python.png");
}
&.icon-dependent {
- background-image: url('@/assets/images/task-icons/dependent.png');
+ background-image: url("@/assets/images/task-icons/dependent.png");
}
&.icon-http {
- background-image: url('@/assets/images/task-icons/http.png');
+ background-image: url("@/assets/images/task-icons/http.png");
}
&.icon-datax {
- background-image: url('@/assets/images/task-icons/datax.png');
+ background-image: url("@/assets/images/task-icons/datax.png");
}
&.icon-pigeon {
- background-image: url('@/assets/images/task-icons/pigeon.png');
+ background-image: url("@/assets/images/task-icons/pigeon.png");
}
&.icon-sqoop {
- background-image: url('@/assets/images/task-icons/sqoop.png');
+ background-image: url("@/assets/images/task-icons/sqoop.png");
}
&.icon-conditions {
- background-image: url('@/assets/images/task-icons/conditions.png');
+ background-image: url("@/assets/images/task-icons/conditions.png");
}
&.icon-seatunnel {
- background-image: url('@/assets/images/task-icons/seatunnel.png');
+ background-image: url("@/assets/images/task-icons/seatunnel.png");
}
&.icon-spark {
- background-image: url('@/assets/images/task-icons/spark.png');
+ background-image: url("@/assets/images/task-icons/spark.png");
}
&.icon-switch {
- background-image: url('@/assets/images/task-icons/switch.png');
+ 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');
+ background-image: url("@/assets/images/task-icons/shell_hover.png");
}
&.icon-sub_process {
- background-image:
url('@/assets/images/task-icons/sub_process_hover.png');
+ background-image:
url("@/assets/images/task-icons/sub_process_hover.png");
}
&.icon-procedure {
- background-image:
url('@/assets/images/task-icons/procedure_hover.png');
+ background-image:
url("@/assets/images/task-icons/procedure_hover.png");
}
&.icon-sql {
- background-image: url('@/assets/images/task-icons/sql_hover.png');
+ background-image: url("@/assets/images/task-icons/sql_hover.png");
}
&.icon-flink {
- background-image: url('@/assets/images/task-icons/flink_hover.png');
+ background-image: url("@/assets/images/task-icons/flink_hover.png");
}
&.icon-mr {
- background-image: url('@/assets/images/task-icons/mr_hover.png');
+ background-image: url("@/assets/images/task-icons/mr_hover.png");
}
&.icon-python {
- background-image: url('@/assets/images/task-icons/python_hover.png');
+ background-image: url("@/assets/images/task-icons/python_hover.png");
}
&.icon-dependent {
- background-image:
url('@/assets/images/task-icons/dependent_hover.png');
+ background-image:
url("@/assets/images/task-icons/dependent_hover.png");
}
&.icon-http {
- background-image: url('@/assets/images/task-icons/http_hover.png');
+ background-image: url("@/assets/images/task-icons/http_hover.png");
}
&.icon-datax {
- background-image: url('@/assets/images/task-icons/datax_hover.png');
+ background-image: url("@/assets/images/task-icons/datax_hover.png");
}
&.icon-pigeon {
- background-image: url('@/assets/images/task-icons/pigeon_hover.png');
+ background-image: url("@/assets/images/task-icons/pigeon_hover.png");
}
&.icon-sqoop {
- background-image: url('@/assets/images/task-icons/sqoop_hover.png');
+ background-image: url("@/assets/images/task-icons/sqoop_hover.png");
}
&.icon-conditions {
- background-image:
url('@/assets/images/task-icons/conditions_hover.png');
+ background-image:
url("@/assets/images/task-icons/conditions_hover.png");
}
&.icon-seatunnel {
- background-image:
url('@/assets/images/task-icons/seatunnel_hover.png');
+ background-image:
url("@/assets/images/task-icons/seatunnel_hover.png");
}
&.icon-spark {
- background-image: url('@/assets/images/task-icons/spark_hover.png');
+ background-image: url("@/assets/images/task-icons/spark_hover.png");
}
&.icon-switch {
- background-image: url('@/assets/images/task-icons/switch_hover.png');
+ background-image: url("@/assets/images/task-icons/switch_hover.png");
}
}
}
}
+.dag-dark .draggable {
+ border: 1px solid $borderDark;
+}
+
+.dag-light .draggable {
+ border: 1px solid $borderLight;
+}
+
+.dag .draggable {
+ &:hover {
+ color: $blue;
+ border: 1px dashed $blue;
+ background-color: $blueBg;
+ }
+}
+
.minimap {
position: absolute;
right: 0px;
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/index.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/index.tsx
index 185094a..fc4665e 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/index.tsx
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/index.tsx
@@ -21,7 +21,9 @@ import DagToolbar from './dag-toolbar'
import DagCanvas from './dag-canvas'
import DagSidebar from './dag-sidebar'
import Styles from './dag.module.scss'
-import DagFormatModal from './dag-format-modal'
+import DagAutoLayoutModal from './dag-auto-layout-modal'
+import { useGraphAutoLayout } from './dag-hooks'
+import { useThemeStore } from '@/store/theme/theme'
import './x6-style.scss'
export interface Dragged {
@@ -33,6 +35,8 @@ export interface Dragged {
export default defineComponent({
name: 'workflow-dag',
setup(props, context) {
+ const theme = useThemeStore()
+
// Whether the graph can be operated
const readonly = ref(false)
provide('readonly', readonly)
@@ -53,24 +57,35 @@ export default defineComponent({
type: ''
})
- // Dag format modal visible
- const formatModalVisible = ref<boolean>(false)
- const openFormatModal = (bool: boolean) => {
- formatModalVisible.value = bool
- }
- provide('formatModal', {
- openFormatModal,
- formatModalVisible
- })
+ // Auto layout
+ const {
+ visible: layoutVisible,
+ toggle: layoutToggle,
+ formValue,
+ formRef,
+ submit,
+ cancel
+ } = useGraphAutoLayout({ graph })
return () => (
- <div class={Styles.dag}>
- <DagToolbar v-slots={toolbarSlots} />
+ <div
+ class={[
+ Styles.dag,
+ Styles[`dag-${theme.darkTheme ? 'dark' : 'light'}`]
+ ]}
+ >
+ <DagToolbar v-slots={toolbarSlots} layoutToggle={layoutToggle} />
<div class={Styles.content}>
<DagSidebar dragged={dragged} />
<DagCanvas dragged={dragged} />
</div>
- <DagFormatModal show={formatModalVisible.value} />
+ <DagAutoLayoutModal
+ visible={layoutVisible.value}
+ submit={submit}
+ cancel={cancel}
+ formValue={formValue}
+ formRef={formRef}
+ />
</div>
)
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-canvas-init.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-canvas-init.ts
index 01ea5da..8ec8d12 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-canvas-init.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-canvas-init.ts
@@ -20,6 +20,7 @@ import { ref, onMounted, Ref, onUnmounted } from 'vue'
import { Graph } from '@antv/x6'
import { NODE, EDGE, X6_NODE_NAME, X6_EDGE_NAME } from './dag-config'
import { debounce } from 'lodash'
+import { useResizeObserver } from '@vueuse/core'
interface Options {
readonly: Ref<boolean>
@@ -136,18 +137,14 @@ export function useCanvasInit(options: Options) {
/**
* 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)
+ const resize = debounce(() => {
+ if (container.value && true) {
+ 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)
- })
+ useResizeObserver(container, resize)
/**
* Register custom cells
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-graph-auto-layout.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-graph-auto-layout.ts
new file mode 100644
index 0000000..de33018
--- /dev/null
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-graph-auto-layout.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 { ref, Ref } from 'vue'
+import type { Graph } from '@antv/x6'
+import { DagreLayout, GridLayout } from '@antv/layout'
+import _ from 'lodash'
+import { X6_NODE_NAME, X6_EDGE_NAME } from './dag-config'
+
+interface Options {
+ graph: Ref<Graph | undefined>
+}
+
+interface LayoutConfig {
+ cols: number
+ nodesep: number
+ padding: number
+ ranksep: number
+ rows: number
+ type: LAYOUT_TYPE
+}
+
+export enum LAYOUT_TYPE {
+ GRID = 'grid',
+ DAGRE = 'dagre'
+}
+
+/**
+ * Auto layout graph
+ * 1. Manage the state of auto layout popups
+ * 2. Implement graph automatic layout function
+ */
+export function useGraphAutoLayout(options: Options) {
+ const DEFAULT_LAYOUT_CONFIG: LayoutConfig = {
+ cols: 0,
+ nodesep: 50,
+ padding: 50,
+ ranksep: 50,
+ rows: 0,
+ type: LAYOUT_TYPE.DAGRE
+ }
+
+ const { graph: graphRef } = options
+
+ // Auto layout config form ref
+ const formRef = ref()
+
+ // Auto layout config form value
+ const formValue = ref({
+ ...DEFAULT_LAYOUT_CONFIG
+ })
+
+ // Dag format modal visible
+ const visible = ref<boolean>(false)
+ const toggle = (bool?: boolean) => {
+ if (typeof bool === 'boolean') {
+ visible.value = bool
+ } else {
+ visible.value = !visible.value
+ }
+ }
+
+ /**
+ * Auto layout graph
+ * @param layoutConfig
+ * @returns
+ */
+ function format(layoutConfig: LayoutConfig) {
+ if (!layoutConfig) {
+ layoutConfig = DEFAULT_LAYOUT_CONFIG
+ }
+ const graph = graphRef?.value
+ if (!graph) {
+ return
+ }
+
+ graph.cleanSelection()
+
+ let layoutFunc = null
+ if (layoutConfig.type === LAYOUT_TYPE.DAGRE) {
+ layoutFunc = new DagreLayout({
+ type: LAYOUT_TYPE.DAGRE,
+ rankdir: 'LR',
+ align: 'UL',
+ // Calculate the node spacing based on the edge label length
+ ranksepFunc: (d) => {
+ const edges = graph.getOutgoingEdges(d.id)
+ let max = 0
+ if (edges && edges.length > 0) {
+ edges.forEach((edge) => {
+ const edgeView = graph.findViewByCell(edge)
+ const labelView = edgeView?.findAttr(
+ 'width',
+ _.get(edgeView, ['labelSelectors', '0', 'body'], null)
+ )
+ const labelWidth = labelView ? +labelView : 0
+ max = Math.max(max, labelWidth)
+ })
+ }
+ return layoutConfig.ranksep + max
+ },
+ nodesep: layoutConfig.nodesep,
+ controlPoints: true
+ })
+ } else if (layoutConfig.type === LAYOUT_TYPE.GRID) {
+ layoutFunc = new GridLayout({
+ type: LAYOUT_TYPE.GRID,
+ preventOverlap: true,
+ preventOverlapPadding: layoutConfig.padding,
+ sortBy: '_index',
+ rows: layoutConfig.rows || undefined,
+ cols: layoutConfig.cols || undefined,
+ nodeSize: 220
+ })
+ }
+ const json = graph.toJSON()
+ const nodes = json.cells
+ .filter((cell) => cell.shape === X6_NODE_NAME)
+ .map((item) => {
+ return {
+ ...item,
+ // sort by code aesc
+ _index: -(item.id as string)
+ }
+ })
+ const edges = json.cells.filter((cell) => cell.shape === X6_EDGE_NAME)
+ const newModel: any = layoutFunc?.layout({
+ nodes: nodes,
+ edges: edges
+ } as any)
+ graph.fromJSON(newModel)
+ }
+
+ /**
+ * Auto layout modal submit
+ */
+ function submit() {
+ if (formRef.value) {
+ formRef.value.validate((errors: unknown) => {
+ if (errors) return
+ format(formValue.value)
+ toggle(false)
+ })
+ }
+ }
+
+ /**
+ * Auto layout modal cancel
+ */
+ function cancel() {
+ toggle(false)
+ }
+
+ return {
+ format,
+ toggle,
+ visible,
+ formRef,
+ formValue,
+ cancel,
+ submit
+ }
+}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/create/index.module.scss
b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/create/index.module.scss
index b3d589b..38be4c8 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/create/index.module.scss
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/create/index.module.scss
@@ -15,8 +15,26 @@
* limitations under the License.
*/
+$borderDark: rgba(255, 255, 255, 0.09);
+$borderLight: rgb(239, 239, 245);
+$bgDark: rgb(24, 24, 28);
+$bgLight: #ffffff;
+
.container {
width: 100%;
+ padding: 20px;
box-sizing: border-box;
height: calc(100vh - 100px);
+ overflow: hidden;
+ display: block;
+}
+
+.dark {
+ border: solid 1px $borderDark;
+ background-color: $bgDark;
+}
+
+.light {
+ border: solid 1px $borderLight;
+ background-color: $bgLight;
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/create/index.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/create/index.tsx
index 101cfcf..7e2de1b6 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/create/index.tsx
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/create/index.tsx
@@ -17,21 +17,28 @@
import { defineComponent } from 'vue'
import Dag from '../../components/dag'
-import { NCard } from 'naive-ui'
-import styles from './index.module.scss'
+import { useThemeStore } from '@/store/theme/theme'
+import Styles from './index.module.scss'
export default defineComponent({
name: 'WorkflowDefinitionCreate',
setup() {
+ const theme = useThemeStore()
+
const slots = {
toolbarLeft: () => <span>left-operations</span>,
toolbarRight: () => <span>right-operations</span>
}
return () => (
- <NCard class={styles.container}>
+ <div
+ class={[
+ Styles.container,
+ theme.darkTheme ? Styles['dark'] : Styles['light']
+ ]}
+ >
<Dag v-slots={slots} />
- </NCard>
+ </div>
)
}
})