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 c61b81e0c6 [Improvement-15603][API] When removing or modifying a
workflow the system can check if there any tasks depend on it. (#15681)
c61b81e0c6 is described below
commit c61b81e0c6ae57526f86544026780eab6d35695e
Author: calvin <[email protected]>
AuthorDate: Sun Mar 10 18:55:12 2024 +0800
[Improvement-15603][API] When removing or modifying a workflow the system
can check if there any tasks depend on it. (#15681)
* modify the function of queryTaskSubProcessDepOnProcess
* add a function to query downstream dependent tasks
* confirm to make the workflow offline
* query dependent tasks
* check dependencies
* done
* done
* done
* done
* improve the test case
* improve the test case
* improve codes
* prettier the codes
* prettier the codes
---
.../controller/ProjectWorkerGroupController.java | 2 +-
.../api/controller/WorkFlowLineageController.java | 16 +++
.../api/service/WorkFlowLineageService.java | 9 ++
.../service/impl/ProcessDefinitionServiceImpl.java | 1 +
.../service/impl/WorkFlowLineageServiceImpl.java | 21 ++-
.../controller/WorkFlowLineageControllerTest.java | 13 ++
.../dolphinscheduler/dao/entity/TaskMainInfo.java | 5 +
.../dao/mapper/WorkFlowLineageMapper.java | 6 +-
.../dao/mapper/WorkFlowLineageMapper.xml | 9 +-
dolphinscheduler-ui/src/locales/en_US/project.ts | 10 +-
dolphinscheduler-ui/src/locales/zh_CN/project.ts | 10 +-
.../src/service/modules/lineages/index.ts | 10 +-
.../src/service/modules/lineages/types.ts | 5 +
.../components/dependencies/dependencies-modal.tsx | 129 +++++++++++++++++
.../components/dependencies/use-dependencies.ts | 122 ++++++++++++++++
.../views/projects/task/definition/batch-task.tsx | 8 ++
.../views/projects/task/definition/use-table.ts | 44 ++++--
.../workflow/components/dag/dag-context-menu.tsx | 33 ++++-
.../workflow/components/dag/dag-toolbar.tsx | 24 +++-
.../projects/workflow/components/dag/index.tsx | 19 ++-
.../definition/components/table-action.tsx | 12 +-
.../views/projects/workflow/definition/index.tsx | 11 +-
.../projects/workflow/definition/timing/index.tsx | 8 ++
.../workflow/definition/timing/use-table.ts | 88 ++++++++++--
.../projects/workflow/definition/use-table.ts | 157 ++++++++++++++++-----
.../src/views/projects/workflow/timing/index.tsx | 12 +-
26 files changed, 692 insertions(+), 92 deletions(-)
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectWorkerGroupController.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectWorkerGroupController.java
index a9ac074798..24bd3eddd9 100644
---
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectWorkerGroupController.java
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectWorkerGroupController.java
@@ -68,7 +68,7 @@ public class ProjectWorkerGroupController extends
BaseController {
@ @RequestParam(value = "workerGroups", required = false) String
workerGroups
* @return create result code
*/
- @Operation(summary = "assignWorkerGroups", description =
"CREATE_PROCESS_DEFINITION_NOTES")
+ @Operation(summary = "assignWorkerGroups", description =
"ASSIGN_WORKER_GROUPS_NOTES")
@Parameters({
@Parameter(name = "projectCode", description = "PROJECT_CODE",
schema = @Schema(implementation = long.class, example = "123456")),
@Parameter(name = "workerGroups", description =
"WORKER_GROUP_LIST", schema = @Schema(implementation = List.class))
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/WorkFlowLineageController.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/WorkFlowLineageController.java
index d37928610e..6a6b110d6e 100644
---
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/WorkFlowLineageController.java
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/WorkFlowLineageController.java
@@ -135,4 +135,20 @@ public class WorkFlowLineageController extends
BaseController {
putMsg(result, Status.SUCCESS);
return result;
}
+
+ @Operation(summary = "queryDownstreamDependentTaskList", description =
"QUERY_DOWNSTREAM_DEPENDENT_TASK_NOTES")
+ @Parameters({
+ @Parameter(name = "workFlowCode", description =
"PROCESS_DEFINITION_CODE", required = true, schema = @Schema(implementation =
Long.class)),
+ @Parameter(name = "taskCode", description =
"TASK_DEFINITION_CODE", required = false, schema = @Schema(implementation =
Long.class, example = "123456789")),
+ })
+ @GetMapping(value = "/query-dependent-tasks")
+ @ResponseStatus(HttpStatus.OK)
+ @ApiException(QUERY_WORKFLOW_LINEAGE_ERROR)
+ public Result<Map<String, Object>>
queryDownstreamDependentTaskList(@Parameter(hidden = true)
@RequestAttribute(value = SESSION_USER) User loginUser,
+
@RequestParam(value = "workFlowCode") Long workFlowCode,
+
@RequestParam(value = "taskCode", required = false, defaultValue = "0") Long
taskCode) {
+ Map<String, Object> result =
+
workFlowLineageService.queryDownstreamDependentTasks(workFlowCode, taskCode);
+ return returnDataList(result);
+ }
}
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/WorkFlowLineageService.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/WorkFlowLineageService.java
index 5b36555360..2e535f3307 100644
---
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/WorkFlowLineageService.java
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/WorkFlowLineageService.java
@@ -45,6 +45,15 @@ public interface WorkFlowLineageService {
*/
Set<TaskMainInfo> queryTaskDepOnProcess(long projectCode, long
processDefinitionCode);
+ /**
+ * Query downstream tasks depend on a process definition or a task
+ *
+ * @param processDefinitionCode Process definition code want to query
tasks dependence
+ * @param taskCode Task code want to query tasks dependence
+ * @return downstream dependent tasks
+ */
+ Map<String, Object> queryDownstreamDependentTasks(Long
processDefinitionCode, Long taskCode);
+
/**
* Query and return tasks dependence with string format, is a wrapper of
queryTaskDepOnTask and task query method.
*
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
index 5624f4de4f..173268c53a 100644
---
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
@@ -2537,6 +2537,7 @@ public class ProcessDefinitionServiceImpl extends
BaseServiceImpl implements Pro
// do nothing if the workflow is already offline
return;
}
+
workflowDefinition.setReleaseState(ReleaseState.OFFLINE);
processDefinitionDao.updateById(workflowDefinition);
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkFlowLineageServiceImpl.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkFlowLineageServiceImpl.java
index 15f39d696f..014d22af57 100644
---
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkFlowLineageServiceImpl.java
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkFlowLineageServiceImpl.java
@@ -49,6 +49,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -278,11 +279,29 @@ public class WorkFlowLineageServiceImpl extends
BaseServiceImpl implements WorkF
public Set<TaskMainInfo> queryTaskDepOnProcess(long projectCode, long
processDefinitionCode) {
Set<TaskMainInfo> taskMainInfos = new HashSet<>();
List<TaskMainInfo> taskDependents =
-
workFlowLineageMapper.queryTaskDependentDepOnProcess(projectCode,
processDefinitionCode);
+
workFlowLineageMapper.queryTaskDependentOnProcess(processDefinitionCode, 0);
List<TaskMainInfo> taskSubProcess =
workFlowLineageMapper.queryTaskSubProcessDepOnProcess(projectCode,
processDefinitionCode);
taskMainInfos.addAll(taskDependents);
taskMainInfos.addAll(taskSubProcess);
return taskMainInfos;
}
+
+ /**
+ * Query downstream tasks depend on a process definition or a task
+ *
+ * @param processDefinitionCode Process definition code want to query
tasks dependence
+ * @param taskCode Task code want to query tasks dependence
+ * @return downstream dependent tasks
+ */
+ @Override
+ public Map<String, Object> queryDownstreamDependentTasks(Long
processDefinitionCode, Long taskCode) {
+ Map<String, Object> result = new HashMap<>();
+ List<TaskMainInfo> taskDependents =
+
workFlowLineageMapper.queryTaskDependentOnProcess(processDefinitionCode,
+ Objects.isNull(taskCode) ? 0 : taskCode.longValue());
+ result.put(Constants.DATA_LIST, taskDependents);
+ putMsg(result, Status.SUCCESS);
+ return result;
+ }
}
diff --git
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/WorkFlowLineageControllerTest.java
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/WorkFlowLineageControllerTest.java
index b0f7bbc362..6329cc584a 100644
---
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/WorkFlowLineageControllerTest.java
+++
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/WorkFlowLineageControllerTest.java
@@ -86,4 +86,17 @@ public class WorkFlowLineageControllerTest {
Mockito.when(workFlowLineageService.queryWorkFlowLineageByCode(projectCode,
code)).thenReturn(new HashMap<>());
assertDoesNotThrow(() ->
workFlowLineageController.queryWorkFlowLineageByCode(user, projectCode, code));
}
+
+ @Test
+ public void testQueryDownstreamDependentTaskList() {
+ long code = 1L;
+ long taskCode = 1L;
+ Map<String, Object> result = new HashMap<>();
+ result.put(Constants.STATUS, Status.SUCCESS);
+
Mockito.when(workFlowLineageService.queryDownstreamDependentTasks(code,
taskCode))
+ .thenReturn(result);
+
+ assertDoesNotThrow(
+ () ->
workFlowLineageController.queryDownstreamDependentTaskList(user, code,
taskCode));
+ }
}
diff --git
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TaskMainInfo.java
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TaskMainInfo.java
index 7b5492b75b..16b5887834 100644
---
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TaskMainInfo.java
+++
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TaskMainInfo.java
@@ -62,6 +62,11 @@ public class TaskMainInfo {
*/
private Date taskUpdateTime;
+ /**
+ * projectCode
+ */
+ private long projectCode;
+
/**
* processDefinitionCode
*/
diff --git
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/WorkFlowLineageMapper.java
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/WorkFlowLineageMapper.java
index b47731c591..649e188e9c 100644
---
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/WorkFlowLineageMapper.java
+++
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/WorkFlowLineageMapper.java
@@ -124,12 +124,12 @@ public interface WorkFlowLineageMapper {
* current method `queryTaskDepOnProcess`. Which mean with the same
parameter processDefinitionCode, all tasks in
* `queryTaskDepOnTask` are in the result of method
`queryTaskDepOnProcess`.
*
- * @param projectCode Project code want to query tasks dependence
* @param processDefinitionCode Process definition code want to query
tasks dependence
+ * @param taskCode Task code want to query tasks dependence
* @return List of TaskMainInfo
*/
- List<TaskMainInfo> queryTaskDependentDepOnProcess(@Param("projectCode")
long projectCode,
-
@Param("processDefinitionCode") long processDefinitionCode);
+ List<TaskMainInfo>
queryTaskDependentOnProcess(@Param("processDefinitionCode") long
processDefinitionCode,
+ @Param("taskCode") long
taskCode);
/**
* Query all tasks depend on task, only downstream task support
currently(from dependent task type).
diff --git
a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/WorkFlowLineageMapper.xml
b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/WorkFlowLineageMapper.xml
index 73ecd12410..51c60394be 100644
---
a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/WorkFlowLineageMapper.xml
+++
b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/WorkFlowLineageMapper.xml
@@ -191,12 +191,13 @@
</where>
</select>
- <select id="queryTaskDependentDepOnProcess"
resultType="org.apache.dolphinscheduler.dao.entity.TaskMainInfo">
+ <select id="queryTaskDependentOnProcess"
resultType="org.apache.dolphinscheduler.dao.entity.TaskMainInfo">
select td.id
, td.name as taskName
, td.code as taskCode
, td.version as taskVersion
, td.task_type as taskType
+ , pd.project_code as projectCode
, ptr.process_definition_code as processDefinitionCode
, pd.name as processDefinitionName
, pd.version as processDefinitionVersion
@@ -205,9 +206,6 @@
join t_ds_process_task_relation ptr on ptr.post_task_code = td.code
and td.version = ptr.post_task_version
join t_ds_process_definition pd on pd.code =
ptr.process_definition_code and pd.version = ptr.process_definition_version
<where>
- <if test="projectCode != 0">
- and ptr.project_code = #{projectCode}
- </if>
<!-- ptr.process_definition_code != #{processDefinitionCode} query
task not in current workflow -->
<!-- For dependnet task type, using `like
concat('%"definitionCode":', #{processDefinitionCode}, '%')` -->
<if test="processDefinitionCode != 0">
@@ -215,6 +213,9 @@
and ptr.process_definition_code != #{processDefinitionCode}
and td.task_params like concat('%"definitionCode":',
#{processDefinitionCode}, '%')
</if>
+ <if test="taskCode != 0">
+ and (td.task_params like concat('%"depTaskCode":',
#{taskCode}, '%') or td.task_params like concat('%"depTaskCode":-1%'))
+ </if>
</where>
</select>
diff --git a/dolphinscheduler-ui/src/locales/en_US/project.ts
b/dolphinscheduler-ui/src/locales/en_US/project.ts
index 69aee6a0e2..b3238fc266 100644
--- a/dolphinscheduler-ui/src/locales/en_US/project.ts
+++ b/dolphinscheduler-ui/src/locales/en_US/project.ts
@@ -238,6 +238,13 @@ export default {
confirm_to_offline: 'Confirm to make the workflow offline?',
time_to_online: 'Confirm to make the Scheduler online?',
time_to_offline: 'Confirm to make the Scheduler offline?',
+ warning_dependent_tasks_title: 'Warning',
+ warning_dependent_tasks_desc: 'The downstream dependent tasks exists. Are
you sure to make the workflow offline?',
+ warning_dependencies: 'Dependencies:',
+ delete_validate_dependent_tasks_desc: 'The downstream dependent tasks
exists. You can not delete the workflow.',
+ warning_offline_scheduler_dependent_tasks_desc: 'The downstream dependent
tasks exists. Are you sure to make the scheduler offline?',
+ delete_task_validate_dependent_tasks_desc: 'The downstream dependent tasks
exists. You can not delete the task.',
+ warning_delete_scheduler_dependent_tasks_desc: 'The downstream dependent
tasks exists. Are you sure to delete the scheduler?',
},
task: {
on_line: 'Online',
@@ -306,7 +313,8 @@ export default {
startup_parameter: 'Startup Parameter',
whether_dry_run: 'Whether Dry-Run',
please_choose: 'Please Choose',
- remove_task_cache: 'Clear cache'
+ remove_task_cache: 'Clear cache',
+ delete_validate_dependent_tasks_desc: 'The downstream dependent tasks
exists. You can not delete the task.',
},
dag: {
create: 'Create Workflow',
diff --git a/dolphinscheduler-ui/src/locales/zh_CN/project.ts
b/dolphinscheduler-ui/src/locales/zh_CN/project.ts
index 8b84cc7f13..21d35e2a71 100644
--- a/dolphinscheduler-ui/src/locales/zh_CN/project.ts
+++ b/dolphinscheduler-ui/src/locales/zh_CN/project.ts
@@ -236,6 +236,13 @@ export default {
confirm_to_offline: '是否确定下线该工作流?',
time_to_online: '是否确定上线该定时?',
time_to_offline: '是否确定下线该定时?',
+ warning_dependent_tasks_title: '警告',
+ warning_dependent_tasks_desc: '下游存在依赖, 下线操作可能会对下游任务产生影响. 你确定要下线该工作流嘛?',
+ warning_dependencies: '依赖如下:',
+ delete_validate_dependent_tasks_desc: '下游存在依赖,你不能删除该工作流',
+ warning_offline_scheduler_dependent_tasks_desc: '下游存在依赖, 下线操作可能会对下游任务产生影响.
你确定要下线该定时嘛?',
+ delete_task_validate_dependent_tasks_desc: '下游存在依赖,你不能删除该任务.',
+ warning_delete_scheduler_dependent_tasks_desc: '下游存在依赖, 删除定时可能会对下游任务产生影响.
你确定要删除该定时嘛?',
},
task: {
on_line: '线上',
@@ -304,7 +311,8 @@ export default {
startup_parameter: '启动参数',
whether_dry_run: '是否空跑',
please_choose: '请选择',
- remove_task_cache: '清除缓存'
+ remove_task_cache: '清除缓存',
+ delete_validate_dependent_tasks_desc: '下游存在依赖,你不能删除该任务定义',
},
dag: {
create: '创建工作流',
diff --git a/dolphinscheduler-ui/src/service/modules/lineages/index.ts
b/dolphinscheduler-ui/src/service/modules/lineages/index.ts
index 2eca2d18b0..d43e69276c 100644
--- a/dolphinscheduler-ui/src/service/modules/lineages/index.ts
+++ b/dolphinscheduler-ui/src/service/modules/lineages/index.ts
@@ -16,7 +16,7 @@
*/
import { axios } from '@/service/service'
-import { ProjectCodeReq, WorkflowCodeReq } from './types'
+import {DependentTaskReq, ProjectCodeReq, WorkflowCodeReq} from './types'
export function queryWorkFlowList(projectCode: ProjectCodeReq): any {
return axios({
@@ -41,3 +41,11 @@ export function queryLineageByWorkFlowCode(
method: 'get'
})
}
+
+export function queryDependentTasks(projectCode: number, params:
DependentTaskReq): any {
+ return axios({
+ url: `/projects/${projectCode}/lineages/query-dependent-tasks`,
+ method: 'get',
+ params
+ })
+}
\ No newline at end of file
diff --git a/dolphinscheduler-ui/src/service/modules/lineages/types.ts
b/dolphinscheduler-ui/src/service/modules/lineages/types.ts
index 63294b7b7e..8434491053 100644
--- a/dolphinscheduler-ui/src/service/modules/lineages/types.ts
+++ b/dolphinscheduler-ui/src/service/modules/lineages/types.ts
@@ -47,10 +47,15 @@ interface WorkflowRes {
workFlowRelationList: WorkFlowRelationList[]
}
+interface DependentTaskReq extends WorkflowCodeReq {
+ taskCode?: number
+}
+
export {
ProjectCodeReq,
WorkflowCodeReq,
WorkFlowNameReq,
+ DependentTaskReq,
WorkflowRes,
WorkFlowListRes
}
diff --git
a/dolphinscheduler-ui/src/views/projects/components/dependencies/dependencies-modal.tsx
b/dolphinscheduler-ui/src/views/projects/components/dependencies/dependencies-modal.tsx
new file mode 100644
index 0000000000..fbb09b3071
--- /dev/null
+++
b/dolphinscheduler-ui/src/views/projects/components/dependencies/dependencies-modal.tsx
@@ -0,0 +1,129 @@
+/*
+ * 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,
+ h,
+ ref, watch
+} from 'vue'
+import { useI18n } from 'vue-i18n'
+import {NEllipsis, NModal, NSpace} from 'naive-ui'
+import {IDefinitionData} from "@/views/projects/workflow/definition/types";
+import ButtonLink from "@/components/button-link";
+
+const props = {
+ row: {
+ type: Object as PropType<IDefinitionData>,
+ default: {},
+ required: false
+ },
+ show: {
+ type: Boolean as PropType<boolean>,
+ default: false
+ },
+ required: {
+ type: Boolean as PropType<boolean>,
+ default: true
+ },
+ taskLinks: {
+ type: Array,
+ default: []
+ },
+ content: {
+ type: String,
+ default: ''
+ }
+}
+
+export default defineComponent({
+ name: 'dependenciesConfirm',
+ props,
+ emits: ['update:show', 'update:row', 'confirm'],
+ setup(props, ctx) {
+ const { t } = useI18n()
+
+ const showRef = ref(props.show)
+
+ const confirmToHandle = () => {
+ ctx.emit('confirm')
+ }
+
+ const cancelToHandle = () => {
+ ctx.emit('update:show', showRef)
+ }
+
+ const renderDownstreamDependencies = () => {
+ return h(
+ <NSpace vertical>
+ <div>{props.content}</div>
+ <div>{t('project.workflow.warning_dependencies')}</div>
+ {props.taskLinks.map((item: any) => {
+ return (
+ <ButtonLink
+ onClick={item.action}
+ disabled={false}
+ >
+ {{
+ default: () =>
+ h(NEllipsis,
+ {
+ style: 'max-width: 350px;line-height: 1.5'
+ },
+ () => item.text
+ )
+ }}
+ </ButtonLink>
+ )
+ })}
+ </NSpace>
+ )
+ }
+
+ watch(()=> props.show,
+ () => {
+ showRef.value = props.show
+ })
+
+ return {renderDownstreamDependencies, confirmToHandle, cancelToHandle,
showRef}
+ },
+
+ render() {
+ const { t } = useI18n()
+
+ return (
+ <NModal
+ v-model:show={this.showRef}
+ preset={'dialog'}
+ type={this.$props.required? 'error':'warning'}
+ title={t('project.workflow.warning_dependent_tasks_title')}
+ positiveText={this.$props.required?
'':t('project.workflow.confirm')}
+ negativeText={t('project.workflow.cancel')}
+ maskClosable={false}
+ onNegativeClick={this.cancelToHandle}
+ onPositiveClick={this.confirmToHandle}
+ onClose={this.cancelToHandle}
+ >
+ {{
+ default: () => (
+ this.renderDownstreamDependencies()
+ )
+ }}
+ </NModal>
+ )
+ }
+})
diff --git
a/dolphinscheduler-ui/src/views/projects/components/dependencies/use-dependencies.ts
b/dolphinscheduler-ui/src/views/projects/components/dependencies/use-dependencies.ts
new file mode 100644
index 0000000000..0e35cfbb89
--- /dev/null
+++
b/dolphinscheduler-ui/src/views/projects/components/dependencies/use-dependencies.ts
@@ -0,0 +1,122 @@
+/*
+ * 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 {DependentTaskReq} from "@/service/modules/lineages/types";
+import {queryDependentTasks} from "@/service/modules/lineages";
+import {TASK_TYPES_MAP} from "@/store/project";
+
+export function useDependencies() {
+
+ const getDependentTasksBySingleTask = async (projectCode: any, workflowCode:
any, taskCode: any) => {
+ let tasks = [] as any
+ if (workflowCode && taskCode) {
+ let dependentTaskReq = {workFlowCode: workflowCode, taskCode: taskCode}
as DependentTaskReq
+ const res = await queryDependentTasks(projectCode, dependentTaskReq)
+ res.filter((item: any) => item.processDefinitionCode !== workflowCode &&
item.taskType === TASK_TYPES_MAP.DEPENDENT.alias)
+ .forEach((item: any) => {
+ tasks.push(item.processDefinitionName + '->' + item.taskName)
+ })
+ }
+ return tasks
+ }
+
+ const getDependentTasksByWorkflow = async (projectCode: any, workflowCode:
any) => {
+ let tasks = [] as any
+ if (workflowCode) {
+ let dependentTaskReq = {workFlowCode: workflowCode} as DependentTaskReq
+ const res = await queryDependentTasks(projectCode, dependentTaskReq)
+ res.filter((item: any) => item.processDefinitionCode !== workflowCode &&
item.taskType === TASK_TYPES_MAP.DEPENDENT.alias)
+ .forEach((item: any) => {
+ tasks.push(item.processDefinitionName + '->' + item.taskName)
+ })
+ }
+ return tasks
+ }
+
+ const getDependentTasksByMultipleTasks = async (projectCode: any,
workflowCode: any, taskCodes: any[]) => {
+ let tasks = [] as any
+ if (workflowCode && taskCodes?.length>0) {
+ for(const taskCode of taskCodes) {
+ const res = await getDependentTasksBySingleTask(projectCode,
workflowCode, taskCode)
+ if (res?.length >0) {
+ tasks = tasks.concat(res)
+ }
+ }
+ }
+ return tasks
+ }
+
+ const getDependentTaskLinksByMultipleTasks = async (projectCode: any,
workflowCode: any, taskCodes: any[]) => {
+ let dependentTaskLinks = [] as any
+ if (workflowCode && projectCode) {
+ for (const taskCode of taskCodes) {
+ await getDependentTaskLinksByTask(projectCode, workflowCode,
taskCode).then((res: any) => {
+ dependentTaskLinks = dependentTaskLinks.concat(res)
+ })
+ }
+ }
+ return dependentTaskLinks
+ }
+
+ const getDependentTaskLinks = async (projectCode: any, workflowCode: any) =>
{
+ let dependentTaskReq = {workFlowCode: workflowCode} as DependentTaskReq
+ let dependentTaskLinks = [] as any
+ if (workflowCode && projectCode) {
+ await queryDependentTasks(projectCode, dependentTaskReq).then((res: any)
=> {
+ res.filter((item: any) => item.processDefinitionCode !== workflowCode
&& item.taskType === TASK_TYPES_MAP.DEPENDENT.alias)
+ .forEach((item: any) => {
+ dependentTaskLinks.push(
+ {
+ text: item.processDefinitionName + '->' + item.taskName,
+ show: true,
+ action: () => {
+ const url =
`/projects/${item.projectCode}/workflow/definitions/${item.processDefinitionCode}`
+ window.open(url, '_blank')
+ },
+ }
+ )
+ })
+ })
+ }
+ return dependentTaskLinks
+ }
+
+ const getDependentTaskLinksByTask = async (projectCode: any, workflowCode:
any, taskCode: any) => {
+ let dependentTaskReq = {workFlowCode: workflowCode, taskCode: taskCode} as
DependentTaskReq
+ let dependentTaskLinks = [] as any
+ if (workflowCode && projectCode) {
+ await queryDependentTasks(projectCode, dependentTaskReq).then((res: any)
=> {
+ res.filter((item: any) => item.processDefinitionCode !== workflowCode
&& item.taskType === TASK_TYPES_MAP.DEPENDENT.alias)
+ .forEach((item: any) => {
+ dependentTaskLinks.push(
+ {
+ text: item.processDefinitionName + '->' + item.taskName,
+ show: true,
+ action: () => {
+ const url =
`/projects/${item.projectCode}/workflow/definitions/${item.processDefinitionCode}`
+ window.open(url, '_blank')
+ },
+ }
+ )
+ })
+ })
+ }
+ return dependentTaskLinks
+ }
+
+ return { getDependentTasksBySingleTask, getDependentTasksByMultipleTasks,
getDependentTaskLinks, getDependentTasksByWorkflow,
getDependentTaskLinksByTask, getDependentTaskLinksByMultipleTasks }
+}
diff --git
a/dolphinscheduler-ui/src/views/projects/task/definition/batch-task.tsx
b/dolphinscheduler-ui/src/views/projects/task/definition/batch-task.tsx
index 500d63ddb6..fc51cb84d0 100644
--- a/dolphinscheduler-ui/src/views/projects/task/definition/batch-task.tsx
+++ b/dolphinscheduler-ui/src/views/projects/task/definition/batch-task.tsx
@@ -41,6 +41,7 @@ import Card from '@/components/card'
import VersionModal from './components/version-modal'
import TaskModal from '@/views/projects/task/components/node/detail-modal'
import type { INodeData } from './types'
+import DependenciesModal from
"@/views/projects/components/dependencies/dependencies-modal";
const BatchTaskDefinition = defineComponent({
name: 'batch-task-definition',
@@ -213,6 +214,13 @@ const BatchTaskDefinition = defineComponent({
readonly={this.taskReadonly}
saving={this.taskSaving}
/>
+ <DependenciesModal
+ v-model:show={this.dependenciesData.showRef}
+ v-model:taskLinks={this.dependenciesData.taskLinks}
+ required={this.dependenciesData.required}
+ content={this.dependenciesData.tip}
+ onConfirm={this.dependenciesData.action}
+ />
</NSpace>
)
}
diff --git
a/dolphinscheduler-ui/src/views/projects/task/definition/use-table.ts
b/dolphinscheduler-ui/src/views/projects/task/definition/use-table.ts
index 78e59b9e70..341fa61081 100644
--- a/dolphinscheduler-ui/src/views/projects/task/definition/use-table.ts
+++ b/dolphinscheduler-ui/src/views/projects/task/definition/use-table.ts
@@ -49,11 +49,15 @@ import type {
} from '@/service/modules/task-definition/types'
import type { IRecord } from './types'
+import { useDependencies } from
'../../components/dependencies/use-dependencies'
+
export function useTable(onEdit: Function) {
const { t } = useI18n()
const route = useRoute()
const projectCode = Number(route.params.projectCode)
+ const {getDependentTaskLinksByTask} = useDependencies()
+
const createColumns = (variables: any) => {
variables.columns = [
{
@@ -260,22 +264,38 @@ export function useTable(onEdit: Function) {
totalPage: ref(1),
taskType: ref(null),
showVersionModalRef: ref(false),
+ dependentTasksShowRef: ref(false),
+ dependentTaskLinksRef: ref([]),
row: {},
- loadingRef: ref(false)
+ loadingRef: ref(false),
+ dependenciesData: ref({showRef: ref(false), taskLinks: ref([]), required:
ref(false), tip: ref(''), action:() => {}}),
})
const handleDelete = (row: any) => {
- deleteTaskDefinition({ code: row.taskCode }, { projectCode }).then(() => {
- getTableData({
- pageSize: variables.pageSize,
- pageNo:
- variables.tableData.length === 1 && variables.page > 1
- ? variables.page - 1
- : variables.page,
- searchTaskName: variables.searchTaskName,
- searchWorkflowName: variables.searchWorkflowName,
- taskType: variables.taskType
- })
+ variables.row = row
+ getDependentTaskLinksByTask(projectCode, row.processDefinitionCode,
row.taskCode).then((res: any) =>{
+ if (res && res.length > 0) {
+ variables.dependenciesData = {
+ showRef: true,
+ taskLinks: res,
+ tip: t('project.workflow.delete_validate_dependent_tasks_desc'),
+ required: true,
+ action: () => {}
+ }
+ } else {
+ deleteTaskDefinition({ code: row.taskCode }, { projectCode }).then(()
=> {
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo:
+ variables.tableData.length === 1 && variables.page > 1
+ ? variables.page - 1
+ : variables.page,
+ searchTaskName: variables.searchTaskName,
+ searchWorkflowName: variables.searchWorkflowName,
+ taskType: variables.taskType
+ })
+ })
+ }
})
}
diff --git
a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag-context-menu.tsx
b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag-context-menu.tsx
index 3fd3ca0b5a..517a67d0af 100644
---
a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag-context-menu.tsx
+++
b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag-context-menu.tsx
@@ -23,7 +23,8 @@ import { useRoute } from 'vue-router'
import styles from './menu.module.scss'
import { uuid } from '@/common/common'
import { IWorkflowTaskInstance } from './types'
-import { NButton } from 'naive-ui'
+import {NButton} from 'naive-ui'
+import {useDependencies} from
"@/views/projects/components/dependencies/use-dependencies"
const props = {
startDisplay: {
@@ -57,6 +58,10 @@ const props = {
top: {
type: Number as PropType<number>,
default: 0
+ },
+ dependenciesData: {
+ type: Object as PropType<any>,
+ require: false
}
}
@@ -77,6 +82,12 @@ export default defineComponent({
const graph = inject('graph', ref())
const route = useRoute()
const projectCode = Number(route.params.projectCode)
+ const workflowCode = Number(route.params.code)
+ const { t } = useI18n()
+
+ const { getDependentTaskLinksByTask } = useDependencies()
+
+ const dependenciesData = props.dependenciesData
const hide = () => {
ctx.emit('hide', false)
@@ -134,9 +145,19 @@ export default defineComponent({
})
}
- const handleDelete = () => {
- graph.value?.removeCell(props.cell)
- ctx.emit('removeTasks', [Number(props.cell?.id)])
+ const handleDelete = async () => {
+ let taskCode = props.cell?.id
+ let res = await getDependentTaskLinksByTask(projectCode, workflowCode,
taskCode)
+ dependenciesData.showRef = false
+ if (res.length > 0) {
+ dependenciesData.showRef = true
+ dependenciesData.taskLinks = res
+ dependenciesData.tip =
t('project.task.delete_validate_dependent_tasks_desc')
+ dependenciesData.required = true
+ } else {
+ graph.value?.removeCell(props.cell)
+ ctx.emit('removeTasks', [Number(props.cell?.id)])
+ }
}
onMounted(() => {
@@ -189,8 +210,8 @@ export default defineComponent({
{t('project.node.copy')}
</NButton>
<NButton
- class={`${styles['menu-item']}`}
- onClick={this.handleDelete}
+ class={`${styles['menu-item']}`}
+ onClick={this.handleDelete}
>
{t('project.node.delete')}
</NButton>
diff --git
a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag-toolbar.tsx
b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag-toolbar.tsx
index d7d517b867..5dc191db9b 100644
---
a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag-toolbar.tsx
+++
b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag-toolbar.tsx
@@ -49,6 +49,7 @@ import type { Graph } from '@antv/x6'
import StartupParam from './dag-startup-param'
import VariablesView from
'@/views/projects/workflow/instance/components/variables-view'
import { WorkflowDefinition, WorkflowInstance } from './types'
+import { useDependencies } from
"@/views/projects/components/dependencies/use-dependencies"
const props = {
layoutToggle: {
@@ -64,6 +65,10 @@ const props = {
// The same as the structure responsed by the queryProcessDefinitionByCode
api
type: Object as PropType<WorkflowDefinition>,
default: null
+ },
+ dependenciesData: {
+ type: Object as PropType<any>,
+ require: false
}
}
@@ -79,6 +84,11 @@ export default defineComponent({
const graph = inject<Ref<Graph | undefined>>('graph', ref())
const router = useRouter()
const route = useRoute()
+ const projectCode = Number(route.params.projectCode)
+ const workflowCode = Number(route.params.code)
+ const { getDependentTaskLinksByMultipleTasks } = useDependencies()
+
+ const dependenciesData = props.dependenciesData
/**
* Node search and navigate
@@ -164,15 +174,23 @@ export default defineComponent({
/**
* Delete selected edges and nodes
*/
- const removeCells = () => {
+ const removeCells = async () => {
if (graph.value) {
const cells = graph.value.getSelectedCells()
if (cells) {
const codes = cells
.filter((cell) => cell.isNode())
.map((cell) => +cell.id)
- context.emit('removeTasks', codes, cells)
- graph.value?.removeCells(cells)
+ const res = await getDependentTaskLinksByMultipleTasks(projectCode,
workflowCode, codes)
+ if (res.length > 0) {
+ dependenciesData.showRef = true
+ dependenciesData.taskLinks = res
+ dependenciesData.tip =
t('project.task.delete_validate_dependent_tasks_desc')
+ dependenciesData.required = true
+ } else {
+ context.emit('removeTasks', codes, cells)
+ graph.value?.removeCells(cells)
+ }
}
}
}
diff --git
a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/index.tsx
b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/index.tsx
index c41485db21..e04afecd09 100644
--- a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/index.tsx
+++ b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/index.tsx
@@ -24,7 +24,7 @@ import {
toRef,
watch,
onBeforeUnmount,
- computed
+ computed, reactive
} from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute } from 'vue-router'
@@ -57,6 +57,7 @@ import utils from '@/utils'
import { useUISettingStore } from '@/store/ui-setting/ui-setting'
import { executeTask } from '@/service/modules/executors'
import { removeTaskInstanceCache } from '@/service/modules/task-instances'
+import DependenciesModal from
"@/views/projects/components/dependencies/dependencies-modal";
const props = {
// If this prop is passed, it means from definition detail
@@ -333,6 +334,13 @@ export default defineComponent({
}
}
+ const dependenciesData = reactive({
+ showRef: ref(false),
+ taskLinks: ref([]),
+ required: ref(false),
+ tip: ref(''), action: () => {}
+ })
+
watch(
() => props.definition,
() => {
@@ -373,6 +381,7 @@ export default defineComponent({
onSaveModelToggle={saveModelToggle}
onRemoveTasks={removeTasks}
onRefresh={refreshTaskStatus}
+ v-model:dependenciesData={dependenciesData}
/>
<div class={Styles.content}>
<DagSidebar onDragStart={onDragStart} />
@@ -428,6 +437,14 @@ export default defineComponent({
onViewLog={handleViewLog}
onExecuteTask={handleExecuteTask}
onRemoveTaskInstanceCache={handleRemoveTaskInstanceCache}
+ v-model:dependenciesData={dependenciesData}
+ />
+ <DependenciesModal
+ v-model:show={dependenciesData.showRef}
+ v-model:taskLinks={dependenciesData.taskLinks}
+ required={dependenciesData.required}
+ content={dependenciesData.tip}
+ onConfirm={dependenciesData.action}
/>
{!!props.definition && (
<StartModal
diff --git
a/dolphinscheduler-ui/src/views/projects/workflow/definition/components/table-action.tsx
b/dolphinscheduler-ui/src/views/projects/workflow/definition/components/table-action.tsx
index 0cc08bc44c..1453e7ed4f 100644
---
a/dolphinscheduler-ui/src/views/projects/workflow/definition/components/table-action.tsx
+++
b/dolphinscheduler-ui/src/views/projects/workflow/definition/components/table-action.tsx
@@ -33,6 +33,7 @@ import {
} from '@vicons/antd'
import { useI18n } from 'vue-i18n'
import { IDefinitionData } from '../types'
+
const props = {
row: {
type: Object as PropType<IDefinitionData>
@@ -95,6 +96,7 @@ export default defineComponent({
const handleReleaseScheduler = () => {
ctx.emit('releaseScheduler')
}
+
return {
handleEditWorkflow,
handleStartWorkflow,
@@ -114,6 +116,7 @@ export default defineComponent({
const releaseState = this.row?.releaseState
const scheduleReleaseState = this.row?.scheduleReleaseState
const schedule = this.row?.schedule
+
return (
<NSpace>
<NTooltip trigger={'hover'}>
@@ -166,10 +169,7 @@ export default defineComponent({
trigger: () => (
<NPopconfirm onPositiveClick={this.handleReleaseWorkflow}>
{{
- default: () =>
- releaseState === 'ONLINE'
- ? t('project.workflow.confirm_to_offline')
- : t('project.workflow.confirm_to_online'),
+ default: () => releaseState === 'OFFLINE' ?
t('project.workflow.confirm_to_online'):t('project.workflow.confirm_to_offline'),
trigger: () => (
<NButton
size='small'
@@ -220,9 +220,7 @@ export default defineComponent({
<NPopconfirm onPositiveClick={this.handleReleaseScheduler}>
{{
default: () =>
- scheduleReleaseState === 'ONLINE'
- ? t('project.workflow.time_to_offline')
- : t('project.workflow.time_to_online'),
+ scheduleReleaseState === 'OFFLINE' ?
t('project.workflow.time_to_online'):t('project.workflow.time_to_offline'),
trigger: () => (
<NButton
size='small'
diff --git
a/dolphinscheduler-ui/src/views/projects/workflow/definition/index.tsx
b/dolphinscheduler-ui/src/views/projects/workflow/definition/index.tsx
index 3eff91673f..90b55adf17 100644
--- a/dolphinscheduler-ui/src/views/projects/workflow/definition/index.tsx
+++ b/dolphinscheduler-ui/src/views/projects/workflow/definition/index.tsx
@@ -24,7 +24,7 @@ import {
NSpace,
NTooltip,
NPopconfirm,
- NModal
+ NModal,
} from 'naive-ui'
import {
defineComponent,
@@ -45,6 +45,7 @@ import VersionModal from './components/version-modal'
import CopyModal from './components/copy-modal'
import type { Router } from 'vue-router'
import Search from '@/components/input-search'
+import DependenciesModal from
'@/views/projects/components/dependencies/dependencies-modal'
export default defineComponent({
name: 'WorkflowDefinitionList',
@@ -318,6 +319,14 @@ export default defineComponent({
maskClosable={false}
onPositiveClick={this.confirmToSetWorkflowTiming}
/>
+ <DependenciesModal
+ v-model:row={this.row}
+ v-model:show={this.dependenciesData.showRef}
+ v-model:taskLinks={this.dependenciesData.taskLinks}
+ required={this.dependenciesData.required}
+ content={this.dependenciesData.tip}
+ onConfirm={this.dependenciesData.action}
+ />
</NSpace>
)
}
diff --git
a/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/index.tsx
b/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/index.tsx
index bd348fb8d7..9450138e0f 100644
---
a/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/index.tsx
+++
b/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/index.tsx
@@ -24,6 +24,7 @@ import { useTable } from './use-table'
import Card from '@/components/card'
import TimingModal from '../components/timing-modal'
import type { Router } from 'vue-router'
+import DependenciesModal from
"@/views/projects/components/dependencies/dependencies-modal";
export default defineComponent({
name: 'WorkflowDefinitionTiming',
@@ -115,6 +116,13 @@ export default defineComponent({
v-model:show={this.showRef}
onUpdateList={this.handleUpdateList}
/>
+ <DependenciesModal
+ v-model:show={this.dependenciesData.showRef}
+ v-model:taskLinks={this.dependenciesData.taskLinks}
+ required={this.dependenciesData.required}
+ content={this.dependenciesData.tip}
+ onConfirm={this.dependenciesData.action}
+ />
</NSpace>
)
}
diff --git
a/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/use-table.ts
b/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/use-table.ts
index a339e20e46..4c86637d04 100644
---
a/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/use-table.ts
+++
b/dolphinscheduler-ui/src/views/projects/workflow/definition/timing/use-table.ts
@@ -39,15 +39,18 @@ import {
import { format } from 'date-fns-tz'
import { ISearchParam } from './types'
import type { Router } from 'vue-router'
+import { useDependencies } from
"@/views/projects/components/dependencies/use-dependencies"
export function useTable() {
const { t } = useI18n()
const router: Router = useRouter()
+ const {getDependentTaskLinks} = useDependencies()
+
const variables = reactive({
columns: [],
tableWidth: DefaultTableWidth,
- row: {},
+ row: {} as any,
tableData: [],
projectCode: ref(Number(router.currentRoute.value.params.projectCode)),
page: ref(1),
@@ -58,7 +61,8 @@ export function useTable() {
loadingRef: ref(false),
processDefinitionCode: router.currentRoute.value.params.definitionCode
? ref(Number(router.currentRoute.value.params.definitionCode))
- : ref()
+ : ref(),
+ dependenciesData: ref({showRef: false, taskLinks: ref([]), required:
ref(false), tip: ref(''), action:() => {}}),
})
const renderTime = (time: string, timeZone: string) => {
@@ -329,7 +333,7 @@ export function useTable() {
NPopconfirm,
{
onPositiveClick: () => {
- handleDelete(row.id)
+ handleDelete(row)
}
},
{
@@ -344,7 +348,8 @@ export function useTable() {
{
circle: true,
type: 'error',
- size: 'small'
+ size: 'small',
+ disabled: row.releaseState === 'ONLINE'
},
{
icon: () => h(DeleteOutlined)
@@ -387,12 +392,43 @@ export function useTable() {
}
const handleReleaseState = (row: any) => {
- let handle = online
if (row.releaseState === 'ONLINE') {
- handle = offline
+ variables.row = row
+ getDependentTaskLinks(variables.projectCode,
row.processDefinitionCode).then((res: any) =>{
+ if (res && res.length > 0) {
+ variables.dependenciesData.showRef = true
+ variables.dependenciesData.taskLinks = res
+ variables.dependenciesData.tip =
t('project.workflow.warning_delete_scheduler_dependent_tasks_desc')
+ variables.dependenciesData.required = false
+ variables.dependenciesData.action = confirmToOfflineSchedule
+ } else {
+ offline(variables.projectCode, row.id).then(() => {
+ window.$message.success(t('project.workflow.success'))
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal,
+ projectCode: variables.projectCode,
+ processDefinitionCode: variables.processDefinitionCode
+ })
+ })
+ }})
+ } else {
+ online(variables.projectCode, row.id).then(() => {
+ window.$message.success(t('project.workflow.success'))
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal,
+ projectCode: variables.projectCode,
+ processDefinitionCode: variables.processDefinitionCode
+ })
+ })
}
+ }
- handle(variables.projectCode, row.id).then(() => {
+ const confirmToOfflineSchedule = () => {
+ offline(variables.projectCode, variables.row.id).then(() => {
window.$message.success(t('project.workflow.success'))
getTableData({
pageSize: variables.pageSize,
@@ -402,14 +438,11 @@ export function useTable() {
processDefinitionCode: variables.processDefinitionCode
})
})
+ variables.dependenciesData.showRef = false
}
- const handleDelete = (id: number) => {
- /* after deleting data from the current page, you need to jump forward
when the page is empty. */
- if (variables.tableData.length === 1 && variables.page > 1) {
- variables.page -= 1
- }
- deleteScheduleById(id, variables.projectCode).then(() => {
+ const confirmToDeleteSchedule = () => {
+ deleteScheduleById(variables.row.id, variables.projectCode).then(() => {
window.$message.success(t('project.workflow.success'))
getTableData({
pageSize: variables.pageSize,
@@ -419,6 +452,35 @@ export function useTable() {
processDefinitionCode: variables.processDefinitionCode
})
})
+ variables.dependenciesData.showRef = false
+ }
+
+ const handleDelete = (row: any) => {
+ /* after deleting data from the current page, you need to jump forward
when the page is empty. */
+ if (variables.tableData.length === 1 && variables.page > 1) {
+ variables.page -= 1
+ }
+ variables.row = row
+ getDependentTaskLinks(variables.projectCode,
row.processDefinitionCode).then((res: any) =>{
+ if (res && res.length > 0) {
+ variables.dependenciesData.showRef = true
+ variables.dependenciesData.taskLinks = res
+ variables.dependenciesData.tip =
t('project.workflow.warning_delete_scheduler_dependent_tasks_desc')
+ variables.dependenciesData.required = false
+ variables.dependenciesData.action = confirmToDeleteSchedule
+ } else {
+ deleteScheduleById(row.id, variables.projectCode).then(() => {
+ window.$message.success(t('project.workflow.success'))
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal,
+ projectCode: variables.projectCode,
+ processDefinitionCode: variables.processDefinitionCode
+ })
+ })
+ }
+ })
}
return {
diff --git
a/dolphinscheduler-ui/src/views/projects/workflow/definition/use-table.ts
b/dolphinscheduler-ui/src/views/projects/workflow/definition/use-table.ts
index 4fe520aa1c..04228d532f 100644
--- a/dolphinscheduler-ui/src/views/projects/workflow/definition/use-table.ts
+++ b/dolphinscheduler-ui/src/views/projects/workflow/definition/use-table.ts
@@ -43,11 +43,14 @@ import {
import type { IDefinitionParam } from './types'
import type { Router } from 'vue-router'
import type { TableColumns, RowKey } from
'naive-ui/es/data-table/src/interface'
+import {useDependencies} from '../../components/dependencies/use-dependencies'
export function useTable() {
const { t } = useI18n()
const router: Router = useRouter()
const { copy } = useTextCopy()
+ const { getDependentTaskLinks } = useDependencies()
+
const variables = reactive({
columns: [],
tableWidth: DefaultTableWidth,
@@ -67,7 +70,8 @@ export function useTable() {
versionShowRef: ref(false),
copyShowRef: ref(false),
loadingRef: ref(false),
- setTimingDialogShowRef: ref(false)
+ setTimingDialogShowRef: ref(false),
+ dependenciesData: ref({showRef: false, taskLinks: ref([]), required:
ref(false), tip: ref(''), action:() => {}}),
})
const createColumns = (variables: any) => {
@@ -304,17 +308,6 @@ export function useTable() {
variables.row = row
}
- const deleteWorkflow = (row: any) => {
- deleteByCode(variables.projectCode, row.code).then(() => {
- window.$message.success(t('project.workflow.success'))
- getTableData({
- pageSize: variables.pageSize,
- pageNo: variables.page,
- searchVal: variables.searchVal
- })
- })
- }
-
const batchDeleteWorkflow = () => {
const data = {
codes: _.join(variables.checkedRowKeys, ',')
@@ -354,48 +347,142 @@ export function useTable() {
const batchCopyWorkflow = () => {}
- const releaseWorkflow = (row: any) => {
+ const confirmToOfflineWorkflow = () => {
+ const row: any = variables.row
const data = {
name: row.name,
releaseState: (row.releaseState === 'ONLINE' ? 'OFFLINE' : 'ONLINE') as
- | 'OFFLINE'
- | 'ONLINE'
+ | 'OFFLINE'
+ | 'ONLINE'
}
+ if (data.releaseState === 'OFFLINE') {
+ release(data, variables.projectCode, row.code).then(() => {
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal
+ })
+ window.$message.success(t('project.workflow.success'))
+ })
+ }
+ variables.dependenciesData.showRef = false
+ }
+
+ const confirmToOfflineScheduler = () => {
+ const row: any = variables.row
+ offline(variables.projectCode, row.schedule.id).then(() => {
+ window.$message.success(t('project.workflow.success'))
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal
+ })
+ })
+ variables.dependenciesData.showRef = false
+ }
- release(data, variables.projectCode, row.code).then(() => {
- if (data.releaseState === 'ONLINE') {
+ const releaseWorkflow = (row: any) => {
+ const data = {
+ name: row.name,
+ releaseState: (row.releaseState === 'ONLINE' ? 'OFFLINE' : 'ONLINE') as
+ | 'OFFLINE'
+ | 'ONLINE'
+ }
+ variables.row = row
+ if (data.releaseState === 'ONLINE') {
+ release(data, variables.projectCode, row.code).then(() => {
variables.setTimingDialogShowRef = true
- variables.row = row
if (row?.schedule) {
variables.row = row.schedule
variables.timingType = 'update'
variables.timingState = row.scheduleReleaseState
}
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal
+ })
+ })
+ } else {
+ getDependentTaskLinks(variables.projectCode, row.code).then((res: any)
=> {
+ if (res && res.length > 0) {
+ variables.dependenciesData = {
+ showRef: true,
+ taskLinks: res,
+ tip: t('project.workflow.warning_dependent_tasks_desc'),
+ required: false,
+ action: confirmToOfflineWorkflow
+ }
+ } else {
+ release(data, variables.projectCode, row.code).then(() => {
+ window.$message.success(t('project.workflow.success'))
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal
+ })
+ })
+ }
+ })
+ }
+ }
+
+ const deleteWorkflow = (row: any) => {
+ getDependentTaskLinks(variables.projectCode, row.code).then((res: any) => {
+ if (res && res.length > 0) {
+ variables.dependenciesData = {
+ showRef: true,
+ taskLinks: res,
+ tip: t('project.workflow.delete_validate_dependent_tasks_desc'),
+ required: true,
+ action: () => {}
+ }
} else {
- window.$message.success(t('project.workflow.success'))
+ deleteByCode(variables.projectCode, row.code).then(() => {
+ window.$message.success(t('project.workflow.success'))
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal
+ })
+ })
}
- getTableData({
- pageSize: variables.pageSize,
- pageNo: variables.page,
- searchVal: variables.searchVal
- })
})
}
const releaseScheduler = (row: any) => {
+ variables.row = row
if (row.schedule) {
- let handle = online
if (row.schedule.releaseState === 'ONLINE') {
- handle = offline
- }
- handle(variables.projectCode, row.schedule.id).then(() => {
- window.$message.success(t('project.workflow.success'))
- getTableData({
- pageSize: variables.pageSize,
- pageNo: variables.page,
- searchVal: variables.searchVal
+ getDependentTaskLinks(variables.projectCode, row.code).then((res: any)
=> {
+ if (res && res.length > 0) {
+ variables.dependenciesData = {
+ showRef: true,
+ taskLinks: res,
+ tip:
t('project.workflow.warning_offline_scheduler_dependent_tasks_desc'),
+ required: false,
+ action: confirmToOfflineScheduler
+ }
+ } else {
+ offline(variables.projectCode, row.schedule.id).then(() => {
+ window.$message.success(t('project.workflow.success'))
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal
+ })
+ })
+ }})
+ } else {
+ online(variables.projectCode, row.schedule.id).then(() => {
+ window.$message.success(t('project.workflow.success'))
+ getTableData({
+ pageSize: variables.pageSize,
+ pageNo: variables.page,
+ searchVal: variables.searchVal
+ })
})
- })
+ }
}
}
@@ -479,6 +566,6 @@ export function useTable() {
getTableData,
batchDeleteWorkflow,
batchExportWorkflow,
- batchCopyWorkflow
+ batchCopyWorkflow,
}
}
diff --git a/dolphinscheduler-ui/src/views/projects/workflow/timing/index.tsx
b/dolphinscheduler-ui/src/views/projects/workflow/timing/index.tsx
index 1228cfd835..37a33447d5 100644
--- a/dolphinscheduler-ui/src/views/projects/workflow/timing/index.tsx
+++ b/dolphinscheduler-ui/src/views/projects/workflow/timing/index.tsx
@@ -15,14 +15,15 @@
* limitations under the License.
*/
-import { NDataTable, NPagination, NSpace } from 'naive-ui'
-import { defineComponent, onMounted, toRefs, watch } from 'vue'
+import {NDataTable, NPagination, NSpace} from 'naive-ui'
+import {defineComponent, onMounted, toRefs, watch} from 'vue'
import { useI18n } from 'vue-i18n'
import { useTable } from '../definition/timing/use-table'
import Card from '@/components/card'
import TimingModal from '../definition/components/timing-modal'
import TimingCondition from
'@/views/projects/workflow/timing/components/timing-condition'
import { ITimingSearch } from '@/views/projects/workflow/timing/types'
+import DependenciesModal from
"@/views/projects/components/dependencies/dependencies-modal";
export default defineComponent({
name: 'WorkflowTimingList',
@@ -110,6 +111,13 @@ export default defineComponent({
v-model:show={this.showRef}
onUpdateList={this.handleUpdateList}
/>
+ <DependenciesModal
+ v-model:show={this.dependenciesData.showRef}
+ v-model:taskLinks={this.dependenciesData.taskLinks}
+ required={this.dependenciesData.required}
+ content={this.dependenciesData.tip}
+ onConfirm={this.dependenciesData.action}
+ />
</NSpace>
)
}