This is an automated email from the ASF dual-hosted git repository.
songjian 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 4b06b76 [Feature][UI Next] Create workflow (#8362)
4b06b76 is described below
commit 4b06b760686931a201a2f1adccb14f7368525b27
Author: wangyizhi <[email protected]>
AuthorDate: Sun Feb 13 20:16:58 2022 +0800
[Feature][UI Next] Create workflow (#8362)
---
.../src/locales/modules/en_US.ts | 3 +-
.../src/locales/modules/zh_CN.ts | 3 +-
.../service/modules/process-definition/index.ts | 6 +-
.../service/modules/process-definition/types.ts | 3 +-
.../src/views/projects/node/detail-modal.tsx | 76 ++++++++++---
.../src/views/projects/node/detail.tsx | 7 +-
.../src/views/projects/node/types.ts | 22 +---
.../projects/workflow/components/dag/dag-hooks.ts | 8 +-
.../workflow/components/dag/dag-save-modal.tsx | 3 +-
.../workflow/components/dag/dag-sidebar.tsx | 7 +-
.../projects/workflow/components/dag/index.tsx | 47 ++++++--
.../projects/workflow/components/dag/types.ts | 69 +++++++++---
.../workflow/components/dag/use-business-mapper.ts | 118 ++++++++++++++++++++
.../workflow/components/dag/use-cell-query.ts | 54 ----------
.../workflow/components/dag/use-cell-update.ts | 5 +-
.../components/dag/use-custom-cell-builder.ts | 6 +-
.../workflow/components/dag/use-dag-drag-drop.ts | 21 ++--
.../workflow/components/dag/use-node-search.ts | 9 +-
.../workflow/components/dag/use-task-edit.ts | 119 +++++++++++++++++++++
.../projects/workflow/definition/create/index.tsx | 58 +++++++++-
.../projects/workflow/definition/detail/index.tsx | 9 +-
21 files changed, 502 insertions(+), 151 deletions(-)
diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
index b308e79..d52c90b 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
@@ -545,7 +545,8 @@ const project = {
basic_info: 'Basic Information',
minute: 'Minute',
key: 'Key',
- value: 'Value'
+ value: 'Value',
+ success: 'Success'
},
node: {
current_node_settings: 'Current node settings',
diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
index fe1bd9c..4728ca4 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
@@ -543,7 +543,8 @@ const project = {
basic_info: '基本信息',
minute: '分',
key: '键',
- value: '值'
+ value: '值',
+ success: '成功'
},
node: {
current_node_settings: '当前节点设置',
diff --git
a/dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts
b/dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts
index a6d1313..4671fa7 100644
--- a/dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/process-definition/index.ts
@@ -39,11 +39,11 @@ export function queryListPaging(params: PageReq & ListReq,
code: number): any {
}
export function createProcessDefinition(
- data: ProcessDefinitionReq & NameReq,
- code: CodeReq
+ data: ProcessDefinitionReq,
+ projectCode: number
): any {
return axios({
- url: `/projects/${code}/process-definition`,
+ url: `/projects/${projectCode}/process-definition`,
method: 'post',
data
})
diff --git
a/dolphinscheduler-ui-next/src/service/modules/process-definition/types.ts
b/dolphinscheduler-ui-next/src/service/modules/process-definition/types.ts
index 2e9949a..17cb4bc 100644
--- a/dolphinscheduler-ui-next/src/service/modules/process-definition/types.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/process-definition/types.ts
@@ -53,7 +53,8 @@ interface ListReq extends PageReq {
userId?: number
}
-interface ProcessDefinitionReq extends NameReq {
+interface ProcessDefinitionReq {
+ name: string
locations: string
taskDefinitionJson: string
taskRelationJson: string
diff --git a/dolphinscheduler-ui-next/src/views/projects/node/detail-modal.tsx
b/dolphinscheduler-ui-next/src/views/projects/node/detail-modal.tsx
index 51d9a1b..dfc1e66 100644
--- a/dolphinscheduler-ui-next/src/views/projects/node/detail-modal.tsx
+++ b/dolphinscheduler-ui-next/src/views/projects/node/detail-modal.tsx
@@ -19,37 +19,71 @@ import { defineComponent, PropType, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import Modal from '@/components/modal'
import Detail from './detail'
-import type { IDataNode, ITask } from './types'
+import type { NodeData } from '@/views/projects/workflow/components/dag/types'
const props = {
show: {
type: Boolean as PropType<boolean>,
default: false
},
- nodeData: {
- type: Object as PropType<IDataNode>,
- default: {
- taskType: 'SHELL'
- }
+ taskDefinition: {
+ type: Object as PropType<NodeData>,
+ default: { code: 0, taskType: 'SHELL', name: '' }
},
- type: {
- type: String as PropType<string>,
- default: ''
+ projectCode: {
+ type: Number as PropType<number>,
+ required: true
},
- taskDefinition: {
- type: Object as PropType<ITask>
+ readonly: {
+ type: Boolean as PropType<boolean>,
+ default: false
}
}
const NodeDetailModal = defineComponent({
name: 'NodeDetailModal',
props,
- emits: ['cancel', 'update'],
+ emits: ['cancel', 'submit'],
setup(props, { emit }) {
const { t } = useI18n()
const detailRef = ref()
+
+ // TODO
+ const mapFormToTaskDefinition = (form: any) => {
+ return {
+ // "code": form.code,
+ name: form.name,
+ description: form.desc,
+ taskType: 'SHELL',
+ taskParams: {
+ resourceList: [],
+ localParams: form.localParams,
+ rawScript: form.shell,
+ dependence: {},
+ conditionResult: {
+ successNode: [],
+ failedNode: []
+ },
+ waitStartTimeout: {},
+ switchResult: {}
+ },
+ flag: form.runFlag,
+ taskPriority: 'MEDIUM',
+ workerGroup: form.workerGroup,
+ failRetryTimes: '0',
+ failRetryInterval: '1',
+ timeoutFlag: 'CLOSE',
+ timeoutNotifyStrategy: '',
+ timeout: 0,
+ delayTime: '0',
+ environmentCode: form.environmentCode
+ }
+ }
const onConfirm = () => {
- detailRef.value.onSubmit()
+ emit('submit', {
+ formRef: detailRef.value.formRef,
+ form: mapFormToTaskDefinition(detailRef.value.form)
+ })
}
const onCancel = () => {
emit('cancel')
@@ -63,7 +97,15 @@ const NodeDetailModal = defineComponent({
}
},
render() {
- const { t, show, onConfirm, onCancel } = this
+ const {
+ t,
+ show,
+ onConfirm,
+ onCancel,
+ projectCode,
+ taskDefinition,
+ readonly
+ } = this
return (
<Modal
show={show}
@@ -72,7 +114,11 @@ const NodeDetailModal = defineComponent({
confirmLoading={false}
onCancel={onCancel}
>
- <Detail ref='detailRef' taskType='SHELL' projectCode={111} />
+ <Detail
+ ref='detailRef'
+ taskType={taskDefinition.taskType}
+ projectCode={projectCode}
+ />
</Modal>
)
}
diff --git a/dolphinscheduler-ui-next/src/views/projects/node/detail.tsx
b/dolphinscheduler-ui-next/src/views/projects/node/detail.tsx
index e62796d..b833dcf 100644
--- a/dolphinscheduler-ui-next/src/views/projects/node/detail.tsx
+++ b/dolphinscheduler-ui-next/src/views/projects/node/detail.tsx
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import { defineComponent, PropType, ref, toRefs } from 'vue'
+import { defineComponent, PropType, ref, toRef, toRefs } from 'vue'
import Form from '@/components/form'
import { useTask } from './use-task'
import { useDetail } from './use-detail'
@@ -40,14 +40,15 @@ const NodeDetail = defineComponent({
const { taskType, projectCode } = props
const { json, model } = useTask({ taskType, projectCode })
- const { state, onSubmit } = useDetail()
+ const { state } = useDetail()
const jsonRef = ref(json)
const { rules, elements } = getElementByJson(jsonRef.value, model)
expose({
- onSubmit: () => void onSubmit(model)
+ formRef: toRef(state, 'formRef'),
+ form: model
})
return { rules, elements, model, ...toRefs(state) }
diff --git a/dolphinscheduler-ui-next/src/views/projects/node/types.ts
b/dolphinscheduler-ui-next/src/views/projects/node/types.ts
index 68d5e90..e8ef7d8 100644
--- a/dolphinscheduler-ui-next/src/views/projects/node/types.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/node/types.ts
@@ -18,6 +18,7 @@
import { VNode } from 'vue'
import type { SelectOption } from 'naive-ui'
import type { IFormItem, IJsonItem } from '@/components/form/types'
+import type { TaskType } from '@/views/projects/task/constants/task-type'
interface ITaskPriorityOption extends SelectOption {
icon: VNode
@@ -46,27 +47,10 @@ interface ITimeout {
timeout?: number
strategy?: string
}
-type ITaskType =
- | 'SHELL'
- | 'SUB_PROCESS'
- | 'PROCEDURE'
- | 'SQL'
- | 'SPARK'
- | 'FLINK'
- | 'MapReduce'
- | 'PYTHON'
- | 'DEPENDENT'
- | 'HTTP'
- | 'DataX'
- | 'PIGEON'
- | 'SQOOP'
- | 'CONDITIONS'
- | 'DATA_QUALITY'
- | 'SWITCH'
- | 'SEATUNNEL'
+type ITaskType = TaskType
interface ITask {
- code?: string
+ code: number
timeoutNotifyStrategy?: string
taskParams: ITaskParams
description?: string
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 303ae1f..3c69127 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
@@ -16,7 +16,7 @@
*/
import { useCanvasInit } from './use-canvas-init'
-import { useCellQuery } from './use-cell-query'
+import { useBusinessMapper } from './use-business-mapper'
import { useCellActive } from './use-cell-active'
import { useCellUpdate } from './use-cell-update'
import { useNodeSearch } from './use-node-search'
@@ -25,10 +25,11 @@ import { useTextCopy } from './use-text-copy'
import { useCustomCellBuilder } from './use-custom-cell-builder'
import { useGraphBackfill } from './use-graph-backfill'
import { useDagDragAndDrop } from './use-dag-drag-drop'
+import { useTaskEdit } from './use-task-edit'
export {
useCanvasInit,
- useCellQuery,
+ useBusinessMapper,
useCellActive,
useNodeSearch,
useGraphAutoLayout,
@@ -36,5 +37,6 @@ export {
useCustomCellBuilder,
useGraphBackfill,
useCellUpdate,
- useDagDragAndDrop
+ useDagDragAndDrop,
+ useTaskEdit
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-save-modal.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-save-modal.tsx
index be4b9ab..255ff44 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-save-modal.tsx
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/dag-save-modal.tsx
@@ -28,6 +28,7 @@ import {
NDynamicInput
} from 'naive-ui'
import { queryTenantList } from '@/service/modules/tenants'
+import { SaveForm } from './types'
import './x6-style.scss'
const props = {
@@ -67,7 +68,7 @@ export default defineComponent({
})
})
- const formValue = ref({
+ const formValue = ref<SaveForm>({
name: '',
description: '',
tenantCode: 'default',
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 2ecd498..4dfe8c7 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
@@ -16,7 +16,10 @@
*/
import { defineComponent } from 'vue'
-import { TASK_TYPES_MAP, TaskType } from '../../../task/constants/task-type'
+import {
+ TaskType,
+ TASK_TYPES_MAP
+} from '@/views/projects/task/constants/task-type'
import Styles from './dag.module.scss'
export default defineComponent({
@@ -35,7 +38,7 @@ export default defineComponent({
class={Styles.draggable}
draggable='true'
onDragstart={(e) => {
- context.emit('dragStart', e, task.type)
+ context.emit('dragStart', e, task.type as TaskType)
}}
>
<em
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 32ceea1..1f56016 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
@@ -25,12 +25,15 @@ import DagAutoLayoutModal from './dag-auto-layout-modal'
import {
useGraphAutoLayout,
useGraphBackfill,
- useDagDragAndDrop
+ useDagDragAndDrop,
+ useTaskEdit,
+ useBusinessMapper
} from './dag-hooks'
import { useThemeStore } from '@/store/theme/theme'
import VersionModal from '../../definition/components/version-modal'
import { WorkflowDefinition } from './types'
import DagSaveModal from './dag-save-modal'
+import TaskModal from '@/views/projects/node/detail-modal'
import './x6-style.scss'
const props = {
@@ -42,13 +45,17 @@ const props = {
readonly: {
type: Boolean as PropType<boolean>,
default: false
+ },
+ projectCode: {
+ type: Number as PropType<number>,
+ default: 0
}
}
export default defineComponent({
name: 'workflow-dag',
props,
- emits: ['refresh'],
+ emits: ['refresh', 'save'],
setup(props, context) {
const theme = useThemeStore()
@@ -68,9 +75,20 @@ export default defineComponent({
cancel
} = useGraphAutoLayout({ graph })
+ // Edit task
+ const {
+ taskConfirm,
+ taskModalVisible,
+ currTask,
+ taskCancel,
+ appendTask,
+ taskDefinitions
+ } = useTaskEdit({ graph })
+
const { onDragStart, onDrop } = useDagDragAndDrop({
graph,
- readonly: toRef(props, 'readonly')
+ readonly: toRef(props, 'readonly'),
+ appendTask
})
// backfill
@@ -99,9 +117,19 @@ export default defineComponent({
saveModalShow.value = !versionModalShow.value
}
}
- const onSave = (form: any) => {
- // TODO
- console.log(form)
+ const { getConnects, getLocations } = useBusinessMapper()
+ const onSave = (saveForm: any) => {
+ const edges = graph.value?.getEdges() || []
+ const nodes = graph.value?.getNodes() || []
+ const connects = getConnects(nodes, edges, taskDefinitions.value as any)
+ const locations = getLocations(nodes)
+ context.emit('save', {
+ taskDefinitions: taskDefinitions.value,
+ saveForm,
+ connects,
+ locations
+ })
+ saveModelToggle(false)
}
return () => (
@@ -136,6 +164,13 @@ export default defineComponent({
/>
)}
<DagSaveModal v-model:show={saveModalShow.value} onSave={onSave} />
+ <TaskModal
+ show={taskModalVisible.value}
+ projectCode={props.projectCode}
+ taskDefinition={currTask.value}
+ onSubmit={taskConfirm}
+ onCancel={taskCancel}
+ />
</div>
)
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/types.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/types.ts
index 77f97db..3e6b97f 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/types.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/types.ts
@@ -15,6 +15,8 @@
* limitations under the License.
*/
+import { TaskType } from '@/views/projects/task/constants/task-type'
+
export interface ProcessDefinition {
id: number
code: number
@@ -41,37 +43,37 @@ export interface ProcessDefinition {
warningGroupId: number
}
-export interface ProcessTaskRelationList {
- id: number
+export interface Connect {
+ id?: number
name: string
- processDefinitionVersion: number
- projectCode: any
- processDefinitionCode: any
+ processDefinitionVersion?: number
+ projectCode?: number
+ processDefinitionCode?: number
preTaskCode: number
preTaskVersion: number
- postTaskCode: any
+ postTaskCode: number
postTaskVersion: number
conditionType: string
conditionParams: any
- createTime: string
- updateTime: string
+ createTime?: string
+ updateTime?: string
}
-export interface TaskDefinitionList {
+export interface TaskDefinition {
id: number
- code: any
+ code: number
name: string
version: number
description: string
projectCode: any
userId: number
- taskType: string
+ taskType: TaskType
taskParams: any
taskParamList: any[]
taskParamMap: any
flag: string
taskPriority: string
- userName?: any
+ userName: any
projectName?: any
workerGroup: string
environmentCode: number
@@ -84,12 +86,49 @@ export interface TaskDefinitionList {
resourceIds: string
createTime: string
updateTime: string
- modifyBy?: any
+ modifyBy: any
dependence: string
}
+export type NodeData = {
+ code: number
+ taskType: TaskType
+ name: string
+} & Partial<TaskDefinition>
+
export interface WorkflowDefinition {
processDefinition: ProcessDefinition
- processTaskRelationList: ProcessTaskRelationList[]
- taskDefinitionList: TaskDefinitionList[]
+ processTaskRelationList: Connect[]
+ taskDefinitionList: TaskDefinition[]
+}
+
+export interface Dragged {
+ x: number
+ y: number
+ type: TaskType
+}
+
+export interface Coordinate {
+ x: number
+ y: number
+}
+
+export interface GlobalParam {
+ key: string
+ value: string
+}
+
+export interface SaveForm {
+ name: string
+ description: string
+ tenantCode: string
+ timeoutFlag: boolean
+ timeout: number
+ globalParams: GlobalParam[]
+}
+
+export interface Location {
+ taskCode: number
+ x: number
+ y: number
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-business-mapper.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-business-mapper.ts
new file mode 100644
index 0000000..d8cb125
--- /dev/null
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-business-mapper.ts
@@ -0,0 +1,118 @@
+/*
+ * 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, Edge } from '@antv/x6'
+import { Connect, Location, TaskDefinition } from './types'
+import { get } from 'lodash'
+
+/**
+ * Handling business entity and x6 entity conversion
+ * @param {Options} options
+ */
+export function useBusinessMapper() {
+ /**
+ * Get connects, connects and processTaskRelationList are the same
+ * @param {Node[]} nodes
+ * @param {Edge[]} edges
+ * @param {TaskDefinition[]} taskDefinitions
+ * @returns {Connect[]}
+ */
+ function getConnects(
+ nodes: Node[],
+ edges: Edge[],
+ taskDefinitions: TaskDefinition[]
+ ): Connect[] {
+ interface TailNodes {
+ [code: string]: boolean
+ }
+ // Nodes in DAG whose in-degree is not 0
+ const tailNodes: TailNodes = {}
+ // If there is an edge target to a node, the node is tailNode
+ edges.forEach((edge) => {
+ const targetId = edge.getTargetCellId()
+ tailNodes[targetId] = true
+ })
+ const isHeadNode = (code: string) => !tailNodes[code]
+
+ interface TasksMap {
+ [code: string]: TaskDefinition
+ }
+ const tasksMap: TasksMap = {}
+ nodes.forEach((node) => {
+ const code = node.id
+ const task = taskDefinitions.find((t) => t.code === Number(code))
+ if (task) {
+ tasksMap[code] = task
+ }
+ })
+
+ const headConnects: Connect[] = nodes
+ .filter((node) => isHeadNode(node.id))
+ .map((node) => {
+ const task = tasksMap[node.id]
+ return {
+ name: '',
+ preTaskCode: 0,
+ preTaskVersion: 0,
+ postTaskCode: task.code,
+ postTaskVersion: task.version || 0,
+ // conditionType and conditionParams are reserved
+ conditionType: 'NONE',
+ conditionParams: {}
+ }
+ })
+
+ const tailConnects: Connect[] = edges.map((edge) => {
+ const labels = edge.getLabels()
+ const labelName = get(labels, ['0', 'attrs', 'label', 'text'], '')
+ const sourceId = edge.getSourceCellId()
+ const prevTask = tasksMap[sourceId]
+ const targetId = edge.getTargetCellId()
+ const task = tasksMap[targetId]
+
+ return {
+ name: labelName,
+ preTaskCode: prevTask.code,
+ preTaskVersion: prevTask.version || 0,
+ postTaskCode: task.code,
+ postTaskVersion: task.version || 0,
+ // conditionType and conditionParams are reserved
+ conditionType: 'NONE',
+ conditionParams: {}
+ }
+ })
+
+ return headConnects.concat(tailConnects)
+ }
+
+ function getLocations(nodes: Node[]): Location[] {
+ return nodes.map((node) => {
+ const code = +node.id
+ const { x, y } = node.getPosition()
+ return {
+ taskCode: code,
+ x,
+ y
+ }
+ })
+ }
+
+ return {
+ getLocations,
+ getConnects
+ }
+}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-cell-query.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-cell-query.ts
deleted file mode 100644
index 243e6c7..0000000
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-cell-query.ts
+++ /dev/null
@@ -1,54 +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 type { Ref } from 'vue'
-import type { Graph } from '@antv/x6'
-import { TaskType } from '../../../task/constants/task-type'
-
-interface Options {
- graph: Ref<Graph | undefined>
-}
-
-/**
- * Expose some cell-related query methods and refs
- * @param {Options} options
- */
-export function useCellQuery(options: Options) {
- const { graph } = options
-
- /**
- * Get all 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 as string,
- type: data.taskType as TaskType
- }
- })
- }
-
- return {
- getNodes
- }
-}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-cell-update.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-cell-update.ts
index b69033f..faae315 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-cell-update.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-cell-update.ts
@@ -18,9 +18,9 @@
import type { Ref } from 'vue'
import type { Graph } from '@antv/x6'
import type { TaskType } from '@/views/projects/task/constants/task-type'
+import type { Coordinate } from './types'
import { TASK_TYPES_MAP } from '@/views/projects/task/constants/task-type'
import { useCustomCellBuilder } from './dag-hooks'
-import type { Coordinate } from './use-custom-cell-builder'
import utils from '@/utils'
interface Options {
@@ -59,13 +59,14 @@ export function useCellUpdate(options: Options) {
function addNode(
id: string,
type: string,
+ name: string,
coordinate: Coordinate = { x: 100, y: 100 }
) {
if (!TASK_TYPES_MAP[type as TaskType]) {
console.warn(`taskType:${type} is invalid!`)
return
}
- const node = buildNode(id, type, '', coordinate)
+ const node = buildNode(id, type, name, coordinate)
graph.value?.addNode(node)
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-custom-cell-builder.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-custom-cell-builder.ts
index 390b28c..7d9c5ed 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-custom-cell-builder.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-custom-cell-builder.ts
@@ -18,9 +18,7 @@
import type { Node, Edge } from '@antv/x6'
import { X6_NODE_NAME, X6_EDGE_NAME } from './dag-config'
import utils from '@/utils'
-import { WorkflowDefinition } from './types'
-
-export type Coordinate = { x: number; y: number }
+import { WorkflowDefinition, Coordinate } from './types'
export function useCustomCellBuilder() {
/**
@@ -110,7 +108,7 @@ export function useCustomCellBuilder() {
tasks.forEach((task) => {
const location = locations.find((l) => l.taskCode === task.code) || {}
- const node = buildNode(task.code, task.taskType, task.name, {
+ const node = buildNode(task.code + '', task.taskType, task.name, {
x: location.x,
y: location.y
})
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-dag-drag-drop.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-dag-drag-drop.ts
index 046c742..0cc22f3 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-dag-drag-drop.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-dag-drag-drop.ts
@@ -19,39 +19,33 @@ import { ref } from 'vue'
import type { Ref } from 'vue'
import type { Graph } from '@antv/x6'
import { genTaskCodeList } from '@/service/modules/task-definition'
-import { useCellUpdate } from './dag-hooks'
+import { Dragged } from './types'
+import { TaskType } from '@/views/projects/task/constants/task-type'
import { useRoute } from 'vue-router'
interface Options {
readonly: Ref<boolean>
graph: Ref<Graph | undefined>
-}
-
-interface Dragged {
- x: number
- y: number
- type: string
+ appendTask: (code: number, type: TaskType, coor: Coordinate) => void
}
/**
* Sidebar item drag && drop in canvas
*/
export function useDagDragAndDrop(options: Options) {
- const { readonly, graph } = options
+ const { readonly, graph, appendTask } = options
const route = useRoute()
const projectCode = Number(route.params.projectCode)
- const { addNode } = useCellUpdate({ graph })
-
// The element currently being dragged up
const dragged = ref<Dragged>({
x: 0,
y: 0,
- type: ''
+ type: 'SHELL'
})
- function onDragStart(e: DragEvent, type: string) {
+ function onDragStart(e: DragEvent, type: TaskType) {
if (readonly.value) {
e.preventDefault()
return
@@ -75,8 +69,7 @@ export function useDagDragAndDrop(options: Options) {
const genNums = 1
genTaskCodeList(genNums, projectCode).then((res) => {
const [code] = res
- addNode(code + '', type, { x: x - eX, y: y - eY })
- // openTaskConfigModel(code, type)
+ appendTask(code, type, { x: x - eX, y: y - eY })
})
}
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-node-search.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-node-search.ts
index 27eae9f..c5a81ab 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-node-search.ts
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-node-search.ts
@@ -17,7 +17,6 @@
import type { Graph } from '@antv/x6'
import { ref, Ref } from 'vue'
-import { useCellQuery } from './dag-hooks'
interface Options {
graph: Ref<Graph | undefined>
@@ -40,12 +39,12 @@ export function useNodeSearch(options: Options) {
/**
* Search dropdown control
*/
- const { getNodes } = useCellQuery({ graph })
const nodesDropdown = ref<{ label: string; value: string }[]>([])
const reQueryNodes = () => {
- nodesDropdown.value = getNodes().map((node) => ({
- label: node.name,
- value: node.code
+ const nodes = graph.value?.getNodes() || []
+ nodesDropdown.value = nodes.map((node) => ({
+ label: node.getData().taskName,
+ value: node.id
}))
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-task-edit.ts
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-task-edit.ts
new file mode 100644
index 0000000..9306e34
--- /dev/null
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/components/dag/use-task-edit.ts
@@ -0,0 +1,119 @@
+/*
+ * 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, onMounted } from 'vue'
+import type { Ref } from 'vue'
+import type { Graph } from '@antv/x6'
+import type { Coordinate, NodeData } from './types'
+import { TaskType } from '@/views/projects/task/constants/task-type'
+import { useCellUpdate } from './dag-hooks'
+
+interface Options {
+ graph: Ref<Graph | undefined>
+}
+
+/**
+ * Edit task configuration when dbclick
+ * @param {Options} options
+ * @returns
+ */
+export function useTaskEdit(options: Options) {
+ const { graph } = options
+
+ const { addNode, setNodeName } = useCellUpdate({ graph })
+
+ const taskDefinitions = ref<NodeData[]>([])
+ const currTask = ref<NodeData>({
+ taskType: 'SHELL',
+ code: 0,
+ name: ''
+ })
+ const taskModalVisible = ref(false)
+
+ /**
+ * Append a new task
+ */
+ function appendTask(code: number, type: TaskType, coordinate: Coordinate) {
+ addNode(code + '', type, '', coordinate)
+ taskDefinitions.value.push({
+ code,
+ taskType: type,
+ name: ''
+ })
+ openTaskModal({ code, taskType: type, name: '' })
+ }
+
+ function openTaskModal(task: NodeData) {
+ currTask.value = task
+ taskModalVisible.value = true
+ }
+
+ /**
+ * The confirm event in task config modal
+ * @param formRef
+ * @param from
+ */
+ function taskConfirm({ formRef, form }: any) {
+ formRef.validate((errors: any) => {
+ if (!errors) {
+ // override target config
+ taskDefinitions.value = taskDefinitions.value.map((task) => {
+ if (task.code === currTask.value?.code) {
+ setNodeName(task.code + '', form.name)
+ console.log(form)
+ console.log(JSON.stringify(form))
+ return {
+ code: task.code,
+ ...form
+ }
+ }
+ return task
+ })
+ taskModalVisible.value = false
+ }
+ })
+ }
+
+ /**
+ * The cancel event in task config modal
+ */
+ function taskCancel() {
+ taskModalVisible.value = false
+ }
+
+ onMounted(() => {
+ if (graph.value) {
+ graph.value.on('cell:dblclick', ({ cell }) => {
+ const code = Number(cell.id)
+ const definition = taskDefinitions.value.find((t) => t.code === code)
+ if (definition) {
+ currTask.value = definition
+ }
+ taskModalVisible.value = true
+ })
+ }
+ })
+
+ return {
+ currTask,
+ taskModalVisible,
+ taskConfirm,
+ taskCancel,
+ appendTask,
+ taskDefinitions
+ }
+}
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 7462b42..f2cc259 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
@@ -16,15 +16,71 @@
*/
import { defineComponent } from 'vue'
+import { useMessage } from 'naive-ui'
import Dag from '../../components/dag'
import { useThemeStore } from '@/store/theme/theme'
+import { useRoute, useRouter } from 'vue-router'
+import {
+ SaveForm,
+ TaskDefinition,
+ Connect,
+ Location
+} from '../../components/dag/types'
+import { createProcessDefinition } from '@/service/modules/process-definition'
+import { useI18n } from 'vue-i18n'
import Styles from './index.module.scss'
+interface SaveData {
+ saveForm: SaveForm
+ taskDefinitions: TaskDefinition[]
+ connects: Connect[]
+ locations: Location[]
+}
+
export default defineComponent({
name: 'WorkflowDefinitionCreate',
setup() {
const theme = useThemeStore()
+ const message = useMessage()
+ const { t } = useI18n()
+ const route = useRoute()
+ const router = useRouter()
+ const projectCode = Number(route.params.projectCode)
+
+ const onSave = ({
+ taskDefinitions,
+ saveForm,
+ connects,
+ locations
+ }: SaveData) => {
+ const globalParams = saveForm.globalParams.map((p) => {
+ return {
+ prop: p.key,
+ value: p.value,
+ direct: 'IN',
+ type: 'VARCHAR'
+ }
+ })
+
+ createProcessDefinition(
+ {
+ taskDefinitionJson: JSON.stringify(taskDefinitions),
+ taskRelationJson: JSON.stringify(connects),
+ locations: JSON.stringify(locations),
+ name: saveForm.name,
+ tenantCode: saveForm.tenantCode,
+ description: saveForm.description,
+ globalParams: JSON.stringify(globalParams),
+ timeout: saveForm.timeoutFlag ? saveForm.timeout : 0
+ },
+ projectCode
+ ).then((res: any) => {
+ message.success(t('project.dag.success'))
+ router.push({ path: `/projects/${projectCode}/workflow-definition` })
+ })
+ }
+
return () => (
<div
class={[
@@ -32,7 +88,7 @@ export default defineComponent({
theme.darkTheme ? Styles['dark'] : Styles['light']
]}
>
- <Dag />
+ <Dag projectCode={projectCode} onSave={onSave} />
</div>
)
}
diff --git
a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/detail/index.tsx
b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/detail/index.tsx
index fd7200d..1342cb9 100644
---
a/dolphinscheduler-ui-next/src/views/projects/workflow/definition/detail/index.tsx
+++
b/dolphinscheduler-ui-next/src/views/projects/workflow/definition/detail/index.tsx
@@ -39,6 +39,8 @@ export default defineComponent({
})
}
+ const save = () => {}
+
onMounted(() => {
if (!code || !projectCode) return
refresh()
@@ -51,7 +53,12 @@ export default defineComponent({
theme.darkTheme ? Styles['dark'] : Styles['light']
]}
>
- <Dag definition={definition.value} onRefresh={refresh} />
+ <Dag
+ definition={definition.value}
+ onRefresh={refresh}
+ projectCode={projectCode}
+ onSave={save}
+ />
</div>
)
}