From e4212340aa9e130beebe02696ada72709c9fd1df Mon Sep 17 00:00:00 2001 From: pegasas Date: Tue, 11 Jun 2024 09:52:10 +0800 Subject: [PATCH] trigger --- dolphinscheduler-api/pom.xml | 5 + .../api/ApiApplicationServer.java | 2 + .../api/controller/TriggerController.java | 122 +++ .../api/service/TriggerDefinitionService.java | 24 + .../impl/TriggerDefinitionServiceImpl.java | 149 ++++ .../dao/entity/TriggerDefinition.java | 93 +++ .../dao/entity/TriggerInstance.java | 99 +++ .../dao/entity/TriggerMainInfo.java | 103 +++ .../dao/entity/TriggerOffset.java | 26 + .../dao/mapper/TriggerDefinitionMapper.java | 90 +++ .../dao/mapper/TriggerInstanceMapper.java | 20 + .../dao/mapper/TriggerOffsetMapper.java | 16 + .../dao/repository/TriggerDefinitionDao.java | 27 + .../dao/repository/TriggerInstanceDao.java | 10 + .../impl/TriggerDefinitionDaoImpl.java | 50 ++ .../impl/TriggerInstanceDaoImpl.java | 50 ++ .../dao/mapper/TriggerDefinitionMapper.xml | 33 + .../resources/sql/dolphinscheduler_h2.sql | 52 +- .../resources/sql/dolphinscheduler_mysql.sql | 62 ++ .../sql/dolphinscheduler_postgresql.sql | 57 ++ .../mapper/TriggerDefinitionMapperTest.java | 54 ++ .../dao/mapper/TriggerInstanceMapperTest.java | 87 ++ .../dao/mapper/TriggerOffsetMapperTest.java | 31 + dolphinscheduler-master/pom.xml | 5 + .../server/master/MasterServer.java | 9 + .../master/runner/MasterTriggerBootstrap.java | 151 ++++ .../master/runner/TriggerExecuteRunnable.java | 139 ++++ .../runner/TriggerExecuteThreadPool.java | 58 ++ dolphinscheduler-service/pom.xml | 4 + .../dolphinscheduler-task-all/pom.xml | 5 + .../dolphinscheduler-task-trigger/pom.xml | 48 ++ .../plugin/task/trigger/TriggerException.java | 18 + .../task/trigger/TriggerParameters.java | 45 ++ .../plugin/task/trigger/TriggerStatus.java | 38 + .../plugin/task/trigger/TriggerTask.java | 103 +++ .../task/trigger/TriggerTaskChannel.java | 47 ++ .../trigger/TriggerTaskChannelFactory.java | 46 ++ .../plugin/task/trigger/TriggerTaskTest.java | 31 + dolphinscheduler-task-plugin/pom.xml | 1 + .../dolphinscheduler-trigger-all/pom.xml | 22 + .../dolphinscheduler-trigger-api/pom.xml | 29 + .../plugin/trigger/api/AbstractTrigger.java | 45 ++ .../plugin/trigger/api/TriggerCallBack.java | 4 + .../plugin/trigger/api/TriggerChannel.java | 7 + .../trigger/api/TriggerChannelFactory.java | 32 + .../plugin/trigger/api/TriggerConstants.java | 425 ++++++++++ .../plugin/trigger/api/TriggerException.java | 18 + .../trigger/api/TriggerExecutionContext.java | 128 +++ .../trigger/api/TriggerPluginManager.java | 86 ++ .../api/enums/TriggerExecutionStatus.java | 109 +++ .../api/parameters/AbstractParameters.java | 28 + .../trigger/api/parameters/IParameters.java | 4 + .../api/parameters/ParametersNode.java | 95 +++ .../dolphinscheduler-trigger-simple/pom.xml | 27 + .../plugin/trigger/simple/SimpleTrigger.java | 51 ++ .../trigger/simple/SimpleTriggerChannel.java | 20 + .../simple/SimpleTriggerChannelFactory.java | 48 ++ .../simple/SimpleTriggerPatameters.java | 11 + dolphinscheduler-trigger-plugin/pom.xml | 32 + .../content/components/sidebar/index.tsx | 1 + .../src/layouts/content/use-dataList.ts | 17 + dolphinscheduler-ui/src/locales/en_US/menu.ts | 3 + .../src/locales/en_US/project.ts | 7 + dolphinscheduler-ui/src/locales/zh_CN/menu.ts | 3 + .../src/locales/zh_CN/project.ts | 7 + .../src/router/modules/projects.ts | 22 + .../modules/trigger-definition/index.ts | 172 ++++ .../modules/trigger-definition/types.ts | 159 ++++ .../src/store/project/types.ts | 3 + .../trigger/components/node/detail-modal.tsx | 270 +++++++ .../trigger/components/node/detail.tsx | 84 ++ .../trigger/components/node/fields/index.ts | 93 +++ .../components/node/fields/use-cache.ts | 29 + .../components/node/fields/use-child-node.ts | 90 +++ .../node/fields/use-chunjun-deploy-mode.ts | 49 ++ .../components/node/fields/use-chunjun.ts | 103 +++ .../components/node/fields/use-conditions.ts | 127 +++ .../node/fields/use-custom-labels.ts | 82 ++ .../node/fields/use-custom-params.ts | 162 ++++ .../node/fields/use-data-factory.ts | 152 ++++ .../components/node/fields/use-datasource.ts | 238 ++++++ .../components/node/fields/use-datasync.ts | 85 ++ .../components/node/fields/use-datax.ts | 256 ++++++ .../components/node/fields/use-delay-time.ts | 36 + .../node/fields/use-dependent-timeout.ts | 109 +++ .../components/node/fields/use-dependent.ts | 550 +++++++++++++ .../components/node/fields/use-deploy-mode.ts | 67 ++ .../components/node/fields/use-description.ts | 33 + .../components/node/fields/use-dinky.ts | 66 ++ .../trigger/components/node/fields/use-dms.ts | 141 ++++ .../node/fields/use-driver-cores.ts | 42 + .../node/fields/use-driver-memory.ts | 47 ++ .../trigger/components/node/fields/use-dvc.ts | 171 ++++ .../components/node/fields/use-dynamic.ts | 120 +++ .../trigger/components/node/fields/use-emr.ts | 89 ++ .../node/fields/use-environment-name.ts | 105 +++ .../node/fields/use-executor-cores.ts | 42 + .../node/fields/use-executor-memory.ts | 47 ++ .../node/fields/use-executor-number.ts | 42 + .../components/node/fields/use-failed.ts | 49 ++ .../components/node/fields/use-flink.ts | 346 ++++++++ .../components/node/fields/use-hive-cli.ts | 87 ++ .../components/node/fields/use-http.ts | 244 ++++++ .../node/fields/use-java-task-main-jar.ts | 81 ++ .../components/node/fields/use-java.ts | 85 ++ .../components/node/fields/use-jupyter.ts | 127 +++ .../trigger/components/node/fields/use-k8s.ts | 127 +++ .../components/node/fields/use-kubeflow.ts | 38 + .../components/node/fields/use-linkis.ts | 94 +++ .../components/node/fields/use-main-jar.ts | 83 ++ .../node/fields/use-mlflow-models.ts | 80 ++ .../node/fields/use-mlflow-projects.ts | 322 ++++++++ .../components/node/fields/use-mlflow.ts | 69 ++ .../trigger/components/node/fields/use-mr.ts | 108 +++ .../components/node/fields/use-name.ts | 38 + .../components/node/fields/use-namespace.ts | 72 ++ .../node/fields/use-node-selectors.ts | 117 +++ .../components/node/fields/use-openmldb.ts | 87 ++ .../components/node/fields/use-pre-tasks.ts | 47 ++ .../components/node/fields/use-procedure.ts | 41 + .../node/fields/use-process-name.ts | 96 +++ .../components/node/fields/use-pytorch.ts | 139 ++++ .../components/node/fields/use-queue.ts | 32 + .../node/fields/use-relation-custom-params.ts | 99 +++ .../node/fields/use-remote-shell.ts | 37 + .../node/fields/use-resource-limit.ts | 45 ++ .../components/node/fields/use-resources.ts | 184 +++++ .../components/node/fields/use-rules.ts | 304 +++++++ .../components/node/fields/use-run-flag.ts | 40 + .../components/node/fields/use-sagemaker.ts | 37 + .../components/node/fields/use-sea-tunnel.ts | 230 ++++++ .../components/node/fields/use-shell.ts | 38 + .../components/node/fields/use-spark.ts | 224 ++++++ .../components/node/fields/use-sql-type.ts | 165 ++++ .../trigger/components/node/fields/use-sql.ts | 76 ++ .../node/fields/use-sqoop-datasource.ts | 107 +++ .../node/fields/use-sqoop-source-type.ts | 332 ++++++++ .../node/fields/use-sqoop-target-type.ts | 427 ++++++++++ .../components/node/fields/use-sqoop.ts | 128 +++ .../components/node/fields/use-switch.ts | 127 +++ .../node/fields/use-target-task-name.ts | 37 + .../node/fields/use-task-definition.ts | 46 ++ .../components/node/fields/use-task-group.ts | 85 ++ .../node/fields/use-task-priority.ts | 92 +++ .../components/node/fields/use-task-type.ts | 51 ++ .../node/fields/use-timeout-alarm.ts | 88 ++ .../components/node/fields/use-udfs.ts | 62 ++ .../node/fields/use-worker-group.ts | 60 ++ .../components/node/fields/use-zeppelin.ts | 68 ++ .../trigger/components/node/format-data.ts | 757 ++++++++++++++++++ .../trigger/components/node/index.module.scss | 56 ++ .../trigger/components/node/tasks/index.ts | 96 +++ .../components/node/tasks/use-chunjun.ts | 73 ++ .../components/node/tasks/use-conditions.ts | 69 ++ .../components/node/tasks/use-data-factory.ts | 72 ++ .../components/node/tasks/use-data-quality.ts | 107 +++ .../components/node/tasks/use-datasync.ts | 83 ++ .../components/node/tasks/use-datax.ts | 77 ++ .../components/node/tasks/use-dependent.ts | 72 ++ .../components/node/tasks/use-dinky.ts | 68 ++ .../trigger/components/node/tasks/use-dms.ts | 84 ++ .../trigger/components/node/tasks/use-dvc.ts | 69 ++ .../components/node/tasks/use-dynamic.ts | 83 ++ .../trigger/components/node/tasks/use-emr.ts | 70 ++ .../components/node/tasks/use-flink-stream.ts | 76 ++ .../components/node/tasks/use-flink.ts | 79 ++ .../components/node/tasks/use-hive-cli.ts | 82 ++ .../trigger/components/node/tasks/use-http.ts | 76 ++ .../trigger/components/node/tasks/use-java.ts | 90 +++ .../components/node/tasks/use-jupyter.ts | 71 ++ .../trigger/components/node/tasks/use-k8s.ts | 76 ++ .../components/node/tasks/use-kubeflow.ts | 68 ++ .../components/node/tasks/use-linkis.ts | 80 ++ .../components/node/tasks/use-mlflow.ts | 76 ++ .../trigger/components/node/tasks/use-mr.ts | 70 ++ .../components/node/tasks/use-openmldb.ts | 72 ++ .../components/node/tasks/use-pigeon.ts | 68 ++ .../components/node/tasks/use-procedure.ts | 73 ++ .../components/node/tasks/use-python.ts | 73 ++ .../components/node/tasks/use-pytorch.ts | 88 ++ .../components/node/tasks/use-remote-shell.ts | 74 ++ .../components/node/tasks/use-sagemaker.ts | 74 ++ .../components/node/tasks/use-sea-tunnel.ts | 104 +++ .../components/node/tasks/use-shell.ts | 72 ++ .../components/node/tasks/use-spark.ts | 79 ++ .../trigger/components/node/tasks/use-sql.ts | 78 ++ .../components/node/tasks/use-sqoop.ts | 92 +++ .../components/node/tasks/use-sub-process.ts | 74 ++ .../components/node/tasks/use-switch.ts | 71 ++ .../components/node/tasks/use-zeppelin.ts | 74 ++ .../projects/trigger/components/node/types.ts | 555 +++++++++++++ .../trigger/components/node/use-task.ts | 82 ++ .../definition/components/start-modal.tsx | 272 +++++++ .../definition/components/use-start.tsx | 156 ++++ .../definition/components/use-version.ts | 213 +++++ .../projects/trigger/definition/index.tsx | 37 + .../projects/trigger/definition/trigger.tsx | 226 ++++++ .../projects/trigger/definition/types.ts | 39 + .../projects/trigger/definition/use-table.ts | 348 ++++++++ .../trigger/definition/use-trigger.ts | 142 ++++ .../views/projects/trigger/instance/index.tsx | 37 + .../projects/trigger/instance/trigger.tsx | 318 ++++++++ .../views/projects/trigger/instance/types.ts | 39 + .../projects/trigger/instance/use-table.ts | 377 +++++++++ .../definition/components/table-action.tsx | 21 + dolphinscheduler-worker/pom.xml | 5 + .../server/worker/WorkerServer.java | 2 + pom.xml | 12 + 208 files changed, 19676 insertions(+), 1 deletion(-) create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/TriggerController.java create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/TriggerDefinitionService.java create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TriggerDefinitionServiceImpl.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerDefinition.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerInstance.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerMainInfo.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerOffset.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapper.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerInstanceMapper.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerOffsetMapper.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/TriggerDefinitionDao.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/TriggerInstanceDao.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TriggerDefinitionDaoImpl.java create mode 100644 dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TriggerInstanceDaoImpl.java create mode 100644 dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapper.xml create mode 100644 dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapperTest.java create mode 100644 dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerInstanceMapperTest.java create mode 100644 dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerOffsetMapperTest.java create mode 100644 dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/MasterTriggerBootstrap.java create mode 100644 dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/TriggerExecuteRunnable.java create mode 100644 dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/TriggerExecuteThreadPool.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/pom.xml create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerException.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerParameters.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerStatus.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTask.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskChannel.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskChannelFactory.java create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/test/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskTest.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-all/pom.xml create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/pom.xml create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/AbstractTrigger.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerCallBack.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerChannel.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerChannelFactory.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerConstants.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerException.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerExecutionContext.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerPluginManager.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/enums/TriggerExecutionStatus.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/AbstractParameters.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/IParameters.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/ParametersNode.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/pom.xml create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTrigger.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerChannel.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerChannelFactory.java create mode 100644 dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerPatameters.java create mode 100644 dolphinscheduler-trigger-plugin/pom.xml create mode 100644 dolphinscheduler-ui/src/service/modules/trigger-definition/index.ts create mode 100644 dolphinscheduler-ui/src/service/modules/trigger-definition/types.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/detail-modal.tsx create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/detail.tsx create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/index.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-cache.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-child-node.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-chunjun-deploy-mode.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-chunjun.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-conditions.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-custom-labels.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-custom-params.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-data-factory.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datasource.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datasync.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datax.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-delay-time.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dependent-timeout.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dependent.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-deploy-mode.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-description.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dinky.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dms.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-driver-cores.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-driver-memory.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dvc.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dynamic.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-emr.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-environment-name.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-cores.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-memory.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-number.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-failed.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-flink.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-hive-cli.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-http.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-java-task-main-jar.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-java.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-jupyter.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-k8s.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-kubeflow.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-linkis.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-main-jar.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow-models.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow-projects.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mr.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-name.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-namespace.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-node-selectors.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-openmldb.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-pre-tasks.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-procedure.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-process-name.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-pytorch.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-queue.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-relation-custom-params.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-remote-shell.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-resource-limit.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-resources.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-rules.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-run-flag.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sagemaker.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sea-tunnel.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-shell.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-spark.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sql-type.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sql.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-datasource.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-source-type.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-target-type.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-switch.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-target-task-name.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-definition.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-group.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-priority.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-type.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-timeout-alarm.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-udfs.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-worker-group.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-zeppelin.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/format-data.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/index.module.scss create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/index.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-chunjun.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-conditions.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-data-factory.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-data-quality.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-datasync.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-datax.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dependent.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dinky.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dms.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dvc.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dynamic.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-emr.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-flink-stream.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-flink.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-hive-cli.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-http.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-java.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-jupyter.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-k8s.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-kubeflow.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-linkis.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-mlflow.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-mr.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-openmldb.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-pigeon.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-procedure.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-python.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-pytorch.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-remote-shell.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sagemaker.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sea-tunnel.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-shell.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-spark.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sql.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sqoop.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sub-process.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-switch.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-zeppelin.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/types.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/components/node/use-task.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/definition/components/start-modal.tsx create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/definition/components/use-start.tsx create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/definition/components/use-version.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/definition/index.tsx create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/definition/trigger.tsx create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/definition/types.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/definition/use-table.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/definition/use-trigger.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/instance/index.tsx create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/instance/trigger.tsx create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/instance/types.ts create mode 100644 dolphinscheduler-ui/src/views/projects/trigger/instance/use-table.ts diff --git a/dolphinscheduler-api/pom.xml b/dolphinscheduler-api/pom.xml index 40d556a17e..5d62253175 100644 --- a/dolphinscheduler-api/pom.xml +++ b/dolphinscheduler-api/pom.xml @@ -77,6 +77,11 @@ dolphinscheduler-task-all + + org.apache.dolphinscheduler + dolphinscheduler-trigger-all + + org.apache.dolphinscheduler dolphinscheduler-ui diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/ApiApplicationServer.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/ApiApplicationServer.java index f8b705179a..cf0e28f8b1 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/ApiApplicationServer.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/ApiApplicationServer.java @@ -28,6 +28,7 @@ import org.apache.dolphinscheduler.plugin.datasource.api.plugin.DataSourceProces import org.apache.dolphinscheduler.plugin.storage.api.StorageConfiguration; import org.apache.dolphinscheduler.plugin.task.api.TaskChannelFactory; import org.apache.dolphinscheduler.plugin.task.api.TaskPluginManager; +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerPluginManager; import org.apache.dolphinscheduler.registry.api.RegistryConfiguration; import org.apache.dolphinscheduler.service.ServiceConfiguration; import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer; @@ -70,6 +71,7 @@ public class ApiApplicationServer { log.info("Received spring application context ready event will load taskPlugin and write to DB"); // install task plugin TaskPluginManager.loadPlugin(); + TriggerPluginManager.loadPlugin(); DataSourceProcessorProvider.initialize(); for (Map.Entry entry : TaskPluginManager.getTaskChannelFactoryMap().entrySet()) { String taskPluginName = entry.getKey(); diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/TriggerController.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/TriggerController.java new file mode 100644 index 0000000000..280d3b14ba --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/TriggerController.java @@ -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. + */ + +package org.apache.dolphinscheduler.api.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.apache.dolphinscheduler.api.audit.OperatorLog; +import org.apache.dolphinscheduler.api.audit.enums.AuditType; +import org.apache.dolphinscheduler.api.exceptions.ApiException; +import org.apache.dolphinscheduler.api.service.ExecutorService; +import org.apache.dolphinscheduler.api.service.TriggerDefinitionService; +import org.apache.dolphinscheduler.api.utils.Result; +import org.apache.dolphinscheduler.common.constants.Constants; +import org.apache.dolphinscheduler.common.enums.*; +import org.apache.dolphinscheduler.dao.entity.User; +import org.apache.dolphinscheduler.plugin.task.api.utils.ParameterUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +import static org.apache.dolphinscheduler.api.enums.Status.*; + +/** + * trigger definition controller + */ +@Tag(name = "TRIGGER_DEFINITION_TAG") +@RestController +@RequestMapping("projects/{projectCode}/trigger-definition") +@Slf4j +public class TriggerController extends BaseController { + + @Autowired + private ExecutorService execService; + + @Autowired + private TriggerDefinitionService triggerDefinitionService; + + /** + * create trigger definition + * + * @param loginUser login user + * @param projectCode project code + * @param triggerDefinitionJson trigger definition json + * @return create result code + */ + @Operation(summary = "save", description = "CREATE_TRIGGER_DEFINITION_NOTES") + @Parameters({ + @Parameter(name = "projectCode", description = "PROJECT_CODE", required = true, schema = @Schema(implementation = long.class)), + @Parameter(name = "triggerDefinitionJson", description = "TRIGGER_DEFINITION_JSON", required = true, schema = @Schema(implementation = String.class)) + }) + @PostMapping() + @ResponseStatus(HttpStatus.CREATED) + // change error code + @ApiException(CREATE_TASK_DEFINITION_ERROR) + // change audit type + @OperatorLog(auditType = AuditType.TASK_CREATE) + public Result createTriggerDefinition(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser, + @Parameter(name = "projectCode", description = "PROJECT_CODE", required = true) @PathVariable long projectCode, + @RequestParam(value = "triggerDefinitionJson", required = true) String triggerDefinitionJson) { + Map result = + triggerDefinitionService.createTriggerDefinition(loginUser, projectCode, triggerDefinitionJson); + return returnDataList(result); + } + + /** + * query task definition list paging + * + * @param loginUser login user + * @param projectCode project code + * @param searchTriggerName searchTaskName + * @param triggerType taskType + * @param pageNo page number + * @param pageSize page size + * @return task definition page + */ + @Operation(summary = "queryTaskDefinitionListPaging", description = "QUERY_TASK_DEFINITION_LIST_PAGING_NOTES") + @Parameters({ + @Parameter(name = "projectCode", description = "PROJECT_CODE", required = false, schema = @Schema(implementation = long.class)), + @Parameter(name = "searchWorkflowName", description = "SEARCH_WORKFLOW_NAME", required = false, schema = @Schema(implementation = String.class)), + @Parameter(name = "searchTaskName", description = "SEARCH_TASK_NAME", required = false, schema = @Schema(implementation = String.class)), + @Parameter(name = "taskType", description = "TASK_TYPE", required = false, schema = @Schema(implementation = String.class, example = "SHELL")), + @Parameter(name = "taskExecuteType", description = "TASK_EXECUTE_TYPE", required = false, schema = @Schema(implementation = TaskExecuteType.class, example = "STREAM")), + @Parameter(name = "pageNo", description = "PAGE_NO", required = true, schema = @Schema(implementation = int.class, example = "1")), + @Parameter(name = "pageSize", description = "PAGE_SIZE", required = true, schema = @Schema(implementation = int.class, example = "10")) + }) + @GetMapping() + @ResponseStatus(HttpStatus.OK) + @ApiException(QUERY_TASK_DEFINITION_LIST_PAGING_ERROR) + public Result queryTaskDefinitionListPaging(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser, + @Parameter(name = "projectCode", description = "PROJECT_CODE", required = true) @PathVariable long projectCode, + @RequestParam(value = "searchTriggerName", required = false) String searchTriggerName, + @RequestParam(value = "triggerType", required = false) String triggerType, + @RequestParam("pageNo") Integer pageNo, + @RequestParam("pageSize") Integer pageSize) { + checkPageParams(pageNo, pageSize); + searchTriggerName = ParameterUtils.handleEscapes(searchTriggerName); + return triggerDefinitionService.queryTriggerDefinitionListPaging(loginUser, projectCode, + searchTriggerName, triggerType, pageNo, pageSize); + } +} + diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/TriggerDefinitionService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/TriggerDefinitionService.java new file mode 100644 index 0000000000..bdea04b983 --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/TriggerDefinitionService.java @@ -0,0 +1,24 @@ +package org.apache.dolphinscheduler.api.service; + +import org.apache.dolphinscheduler.api.utils.Result; +import org.apache.dolphinscheduler.common.enums.TaskExecuteType; +import org.apache.dolphinscheduler.dao.entity.User; + +import java.util.Map; + +/** + * trigger definition service + */ +public interface TriggerDefinitionService { + + Map createTriggerDefinition(User loginUser, + long projectCode, + String triggerDefinitionJson); + + Result queryTriggerDefinitionListPaging(User loginUser, + long projectCode, + String searchTriggerName, + String triggerType, + Integer pageNo, + Integer pageSize); +} diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TriggerDefinitionServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TriggerDefinitionServiceImpl.java new file mode 100644 index 0000000000..f511f31d00 --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TriggerDefinitionServiceImpl.java @@ -0,0 +1,149 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.api.service.impl; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.dolphinscheduler.api.dto.task.TaskCreateRequest; +import org.apache.dolphinscheduler.api.dto.task.TaskFilterRequest; +import org.apache.dolphinscheduler.api.dto.task.TaskUpdateRequest; +import org.apache.dolphinscheduler.api.dto.taskRelation.TaskRelationUpdateUpstreamRequest; +import org.apache.dolphinscheduler.api.dto.workflow.WorkflowUpdateRequest; +import org.apache.dolphinscheduler.api.enums.Status; +import org.apache.dolphinscheduler.api.exceptions.ServiceException; +import org.apache.dolphinscheduler.api.permission.PermissionCheck; +import org.apache.dolphinscheduler.api.service.*; +import org.apache.dolphinscheduler.api.utils.PageInfo; +import org.apache.dolphinscheduler.api.utils.Result; +import org.apache.dolphinscheduler.api.vo.TaskDefinitionVO; +import org.apache.dolphinscheduler.common.constants.Constants; +import org.apache.dolphinscheduler.common.enums.*; +import org.apache.dolphinscheduler.common.utils.CodeGenerateUtils; +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.dao.entity.*; +import org.apache.dolphinscheduler.dao.mapper.*; +import org.apache.dolphinscheduler.dao.repository.ProcessTaskRelationLogDao; +import org.apache.dolphinscheduler.dao.repository.TaskDefinitionDao; +import org.apache.dolphinscheduler.plugin.task.api.TaskPluginManager; +import org.apache.dolphinscheduler.plugin.task.api.parameters.ParametersNode; +import org.apache.dolphinscheduler.service.process.ProcessService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.*; +import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.TASK_DEFINITION; + +/** + * tenant service impl + */ +@Service +@Slf4j +public class TriggerDefinitionServiceImpl extends BaseServiceImpl implements TriggerDefinitionService { + + @Autowired + private ProjectMapper projectMapper; + + @Autowired + private ProjectService projectService; + + @Autowired + private TaskDefinitionMapper taskDefinitionMapper; + + @Autowired + private TriggerDefinitionMapper triggerDefinitionMapper; + + @Autowired + private TaskDefinitionDao taskDefinitionDao; + + @Autowired + private TaskDefinitionLogMapper taskDefinitionLogMapper; + + @Autowired + private ProcessTaskRelationMapper processTaskRelationMapper; + + @Autowired + private ProcessTaskRelationLogDao processTaskRelationLogDao; + + @Autowired + private ProcessTaskRelationService processTaskRelationService; + + @Autowired + private ProcessDefinitionMapper processDefinitionMapper; + + @Autowired + private ProcessService processService; + + @Autowired + private ProcessDefinitionService processDefinitionService; + + @Autowired + private ProcessDefinitionLogMapper processDefinitionLogMapper; + + + @Transactional + @Override + public Map createTriggerDefinition(User loginUser, + long projectCode, + String triggerDefinitionJson) { + Project project = projectMapper.queryByCode(projectCode); + // check if user have write perm for project + Map result = new HashMap<>(); + return result; + } + + @Override + public Result queryTriggerDefinitionListPaging(User loginUser, + long projectCode, + String searchTriggerName, + String triggerType, + Integer pageNo, + Integer pageSize) { + Result result = new Result(); + Project project = projectMapper.queryByCode(projectCode); + // check user access for project + Map checkResult = + projectService.checkProjectAndAuth(loginUser, project, projectCode, TASK_DEFINITION); + Status resultStatus = (Status) checkResult.get(Constants.STATUS); + if (resultStatus != Status.SUCCESS) { + putMsg(result, resultStatus); + return result; + } + triggerType = triggerType == null ? StringUtils.EMPTY : triggerType; + Page page = new Page<>(pageNo, pageSize); + // first, query trigger code by page size + IPage taskMainInfoIPage = triggerDefinitionMapper.queryDefinitionListPaging(page, projectCode, + searchTriggerName, triggerType); + PageInfo pageInfo = new PageInfo<>(pageNo, pageSize); + pageInfo.setTotal((int) taskMainInfoIPage.getTotal()); +// pageInfo.setTotalList(taskMainInfoIPage.getRecords()); + result.setData(pageInfo); + putMsg(result, Status.SUCCESS); + return result; + } +} + diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerDefinition.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerDefinition.java new file mode 100644 index 0000000000..26f8bfb636 --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerDefinition.java @@ -0,0 +1,93 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.dao.entity; + +import java.util.Date; +import java.util.Objects; + +import lombok.Data; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +@Data +@TableName("t_ds_trigger_definition") +public class TriggerDefinition { + /** + * id + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * code + */ + private long code; + + /** + * name + */ + private String name; + + /** + * description + */ + private String description; + + /** + * project code + */ + private long projectCode; + + /** + * trigger user id + */ + private int userId; + + /** + * trigger type + */ + private String triggerType; + + /** + * create time + */ + private Date createTime; + + /** + * update time + */ + private Date updateTime; + + public TriggerDefinition() { + } + + public TriggerDefinition(long code) { + this.code = code; + } + + public boolean equals(Object o) { + if (o == null) { + return false; + } + TriggerDefinition that = (TriggerDefinition) o; + return Objects.equals(name, that.name) + && Objects.equals(description, that.description); + } +} diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerInstance.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerInstance.java new file mode 100644 index 0000000000..186b59475d --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerInstance.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.dao.entity; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.Data; + +import org.apache.dolphinscheduler.common.constants.Constants; +import org.apache.dolphinscheduler.common.enums.Flag; +import org.apache.dolphinscheduler.common.enums.Priority; +import org.apache.dolphinscheduler.common.enums.TaskExecuteType; +import org.apache.dolphinscheduler.common.utils.DateUtils; +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus; +import org.apache.dolphinscheduler.plugin.task.api.parameters.DependentParameters; +import org.apache.dolphinscheduler.plugin.task.api.parameters.SwitchParameters; + +import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.*; +import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.TASK_TYPE_BLOCKING; + +@Data +@TableName("t_ds_trigger_instance") +public class TriggerInstance implements Serializable { + + /** + * id + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * task name + */ + private String name; + + /** + * task type + */ + private String triggerType; + + private int processInstanceId; + + private String processInstanceName; + + private Long projectCode; + + private long triggerCode; + + @TableField(exist = false) + private String processDefinitionName; + + /** + * state + */ + private TaskExecutionStatus state; + + /** + * task first submit time. + */ + private Date firstSubmitTime; + + /** + * task submit time + */ + private Date submitTime; + + /** + * task start time + */ + private Date startTime; + + /** + * task end time + */ + private Date endTime; +} + diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerMainInfo.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerMainInfo.java new file mode 100644 index 0000000000..67446e5094 --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerMainInfo.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.dao.entity; + +import org.apache.dolphinscheduler.common.enums.ReleaseState; + +import java.util.Date; +import java.util.Map; + +import lombok.Data; + +/** + * task main info + */ +@Data +public class TriggerMainInfo { + private long id; + + /** + * task name + */ + private String taskName; + + /** + * task code + */ + private long taskCode; + + /** + * task version + */ + private int taskVersion; + + /** + * task type + */ + private String taskType; + + /** + * create time + */ + private Date taskCreateTime; + + /** + * update time + */ + private Date taskUpdateTime; + + /** + * projectCode + */ + private long projectCode; + + /** + * processDefinitionCode + */ + private long processDefinitionCode; + + /** + * processDefinitionVersion + */ + private int processDefinitionVersion; + + /** + * processDefinitionName + */ + private String processDefinitionName; + + /** + * processReleaseState + */ + private ReleaseState processReleaseState; + + /** + * upstreamTaskMap(k:code,v:name) + */ + private Map upstreamTaskMap; + + /** + * upstreamTaskCode + */ + private long upstreamTaskCode; + + /** + * upstreamTaskName + */ + private String upstreamTaskName; +} diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerOffset.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerOffset.java new file mode 100644 index 0000000000..a8c450b416 --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/TriggerOffset.java @@ -0,0 +1,26 @@ +package org.apache.dolphinscheduler.dao.entity; + +import lombok.Data; + +import com.baomidou.mybatisplus.annotation.TableName; + +@Data +@TableName("t_ds_trigger_offset") +public class TriggerOffset { + /** + * id + */ + private Integer id; + + /** + * code + */ + private long code; + + public TriggerOffset() { + } + + public TriggerOffset(long code) { + this.code = code; + } +} diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapper.java new file mode 100644 index 0000000000..5f5254073a --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapper.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.dao.mapper; + +import org.apache.dolphinscheduler.common.enums.TaskExecuteType; +import org.apache.dolphinscheduler.dao.entity.*; +import org.apache.dolphinscheduler.dao.model.WorkflowDefinitionCountDto; + +import org.apache.ibatis.annotations.MapKey; +import org.apache.ibatis.annotations.Param; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; + +/** + * trigger definition mapper interface + */ + +public interface TriggerDefinitionMapper extends BaseMapper { + + /** + * query trigger definition by name + * + * @param projectCode projectCode + * @param processCode processCode + * @param name name + * @return trigger definition + */ + TriggerDefinition queryByName(@Param("projectCode") long projectCode, + @Param("processCode") long processCode, + @Param("name") String name); + + /** + * query trigger definition by code + * + * @param code taskDefinitionCode + * @return trigger definition + */ + TriggerDefinition queryByCode(@Param("code") long code); + + /** + * query all trigger definition list + * + * @param projectCode projectCode + * @return trigger definition list + */ + List queryAllDefinitionList(@Param("projectCode") long projectCode); + + /** + * task main info page + * + * @param page page + * @param projectCode projectCode + * @param searchTriggerName searchTriggerName + * @param triggerType triggerType + * @return task main info IPage + */ + IPage queryDefinitionListPaging(IPage page, + @Param("projectCode") long projectCode, + @Param("searchTaskName") String searchTriggerName, + @Param("taskType") String triggerType); + + /** + * delete trigger definition by code + * + * @param code code + * @return int + */ + int deleteByCode(@Param("code") long code); +} + diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerInstanceMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerInstanceMapper.java new file mode 100644 index 0000000000..b79bc9d010 --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerInstanceMapper.java @@ -0,0 +1,20 @@ +package org.apache.dolphinscheduler.dao.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.dolphinscheduler.common.enums.TaskExecuteType; +import org.apache.dolphinscheduler.dao.entity.*; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +public interface TriggerInstanceMapper extends BaseMapper { + + /** + * query trigger definition by code + * + * @param code taskDefinitionCode + * @return trigger definition + */ + TriggerInstance queryByCode(@Param("code") long code); +} diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerOffsetMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerOffsetMapper.java new file mode 100644 index 0000000000..a56a371b72 --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/TriggerOffsetMapper.java @@ -0,0 +1,16 @@ +package org.apache.dolphinscheduler.dao.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.dolphinscheduler.dao.entity.*; +import org.apache.ibatis.annotations.Param; + +public interface TriggerOffsetMapper extends BaseMapper { + + /** + * query trigger definition by code + * + * @param code taskDefinitionCode + * @return trigger definition + */ + TriggerOffset queryByCode(@Param("code") long code); +} diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/TriggerDefinitionDao.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/TriggerDefinitionDao.java new file mode 100644 index 0000000000..4c59692a9b --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/TriggerDefinitionDao.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.dao.repository; + +import org.apache.dolphinscheduler.dao.entity.TriggerDefinition; + +/** + * Trigger Definition DAO + */ +public interface TriggerDefinitionDao extends IDao { + TriggerDefinition queryByCode(long triggerCode); +} \ No newline at end of file diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/TriggerInstanceDao.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/TriggerInstanceDao.java new file mode 100644 index 0000000000..4a359d0e06 --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/TriggerInstanceDao.java @@ -0,0 +1,10 @@ +package org.apache.dolphinscheduler.dao.repository; + +import org.apache.dolphinscheduler.dao.entity.TriggerInstance; + +/** + * Trigger Instance DAO + */ +public interface TriggerInstanceDao extends IDao { + TriggerInstance queryByCode(long triggerCode); +} diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TriggerDefinitionDaoImpl.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TriggerDefinitionDaoImpl.java new file mode 100644 index 0000000000..dd795b908a --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TriggerDefinitionDaoImpl.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.dao.repository.impl; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.apache.dolphinscheduler.dao.entity.*; +import org.apache.dolphinscheduler.dao.mapper.*; +import org.apache.dolphinscheduler.dao.repository.BaseDao; +import org.apache.dolphinscheduler.dao.repository.TriggerDefinitionDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +@Repository +@Slf4j +public class TriggerDefinitionDaoImpl extends BaseDao implements TriggerDefinitionDao { + + @Autowired + private ProcessDefinitionMapper processDefinitionMapper; + + @Autowired + private ProcessTaskRelationLogMapper processTaskRelationLogMapper; + + @Autowired + private TaskDefinitionLogMapper taskDefinitionLogMapper; + + public TriggerDefinitionDaoImpl(@NonNull TriggerDefinitionMapper triggerDefinitionMapper) { + super(triggerDefinitionMapper); + } + + @Override + public TriggerDefinition queryByCode(long triggerCode) { + return mybatisMapper.queryByCode(triggerCode); + } +} diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TriggerInstanceDaoImpl.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TriggerInstanceDaoImpl.java new file mode 100644 index 0000000000..b6cbe6ab14 --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TriggerInstanceDaoImpl.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.dao.repository.impl; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.apache.dolphinscheduler.dao.entity.*; +import org.apache.dolphinscheduler.dao.mapper.*; +import org.apache.dolphinscheduler.dao.repository.BaseDao; +import org.apache.dolphinscheduler.dao.repository.TriggerInstanceDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +@Repository +@Slf4j +public class TriggerInstanceDaoImpl extends BaseDao implements TriggerInstanceDao { + + @Autowired + private ProcessDefinitionMapper processDefinitionMapper; + + @Autowired + private ProcessTaskRelationLogMapper processTaskRelationLogMapper; + + @Autowired + private TaskDefinitionLogMapper taskDefinitionLogMapper; + + public TriggerInstanceDaoImpl(@NonNull TriggerInstanceMapper triggerInstanceMapper) { + super(triggerInstanceMapper); + } + + @Override + public TriggerInstance queryByCode(long triggerCode) { + return mybatisMapper.queryByCode(triggerCode); + } +} \ No newline at end of file diff --git a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapper.xml b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapper.xml new file mode 100644 index 0000000000..abf01fc543 --- /dev/null +++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapper.xml @@ -0,0 +1,33 @@ + + + + + + + diff --git a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql index a907ec69a1..d788a72127 100644 --- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql +++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql @@ -499,6 +499,57 @@ CREATE TABLE t_ds_task_definition PRIMARY KEY (id, code) ); +-- ---------------------------- +-- Table structure for t_ds_trigger_offset +-- ---------------------------- +DROP TABLE IF EXISTS t_ds_trigger_offset CASCADE; +CREATE TABLE t_ds_trigger_offset +( + id int(11) NOT NULL, + code bigint(20) NOT NULL, + PRIMARY KEY (id, code) +); + +-- ---------------------------- +-- Table structure for t_ds_trigger_definition +-- ---------------------------- +DROP TABLE IF EXISTS t_ds_trigger_definition CASCADE; +CREATE TABLE t_ds_trigger_definition +( + id int(11) NOT NULL AUTO_INCREMENT, + code bigint(20) NOT NULL, + name varchar(255) DEFAULT NULL, + description text, + project_code bigint(20) NOT NULL, + user_id int(11) DEFAULT NULL, + trigger_type varchar(50) NOT NULL, + trigger_params longtext, + create_time datetime NOT NULL, + update_time datetime DEFAULT NULL, + PRIMARY KEY (id, code) +); + +-- ---------------------------- +-- Table structure for t_ds_trigger_instance +-- ---------------------------- +DROP TABLE IF EXISTS t_ds_trigger_instance CASCADE; +CREATE TABLE t_ds_trigger_instance +( + id int(11) NOT NULL AUTO_INCREMENT, + name varchar(255) DEFAULT NULL, + trigger_type varchar(50) NOT NULL, + trigger_code bigint(20) NOT NULL, + process_instance_id int(11) DEFAULT NULL, + process_instance_name varchar(255) DEFAULT NULL, + project_code bigint(20) DEFAULT NULL, + state tinyint(4) DEFAULT NULL, + submit_time datetime DEFAULT NULL, + start_time datetime DEFAULT NULL, + end_time datetime DEFAULT NULL, + trigger_params longtext, + PRIMARY KEY (id) +); + -- ---------------------------- -- Table structure for t_ds_task_definition_log -- ---------------------------- @@ -2154,7 +2205,6 @@ CREATE TABLE t_ds_trigger_relation UNIQUE KEY t_ds_trigger_relation_UN(trigger_type,job_id,trigger_code) ); - DROP TABLE IF EXISTS t_ds_relation_sub_workflow; CREATE TABLE t_ds_relation_sub_workflow ( id BIGINT AUTO_INCREMENT NOT NULL, diff --git a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql index 3a4f17a357..3ff0408d75 100644 --- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql +++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql @@ -939,6 +939,68 @@ CREATE TABLE `t_ds_task_instance` ( -- Records of t_ds_task_instance -- ---------------------------- +-- ---------------------------- +-- Table structure for t_ds_trigger_offset +-- ---------------------------- +DROP TABLE IF EXISTS `t_ds_trigger_offset`; +CREATE TABLE `t_ds_trigger_offset` ( + `id` int(11) NOT NULL COMMENT 'self-increasing id', + `code` bigint(20) NOT NULL COMMENT 'encoding', + PRIMARY KEY (`id`,`code`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE = utf8_bin; + +-- ---------------------------- +-- Records of t_ds_trigger_offset +-- ---------------------------- + +-- ---------------------------- +-- Table structure for t_ds_trigger_definition +-- ---------------------------- +DROP TABLE IF EXISTS `t_ds_trigger_definition`; +CREATE TABLE `t_ds_trigger_definition` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'self-increasing id', + `code` bigint(20) NOT NULL COMMENT 'encoding', + `name` varchar(255) DEFAULT NULL COMMENT 'trigger definition name', + `description` text COMMENT 'description', + `project_code` bigint(20) NOT NULL COMMENT 'project code', + `user_id` int(11) DEFAULT NULL COMMENT 'trigger definition creator id', + `trigger_type` varchar(50) NOT NULL COMMENT 'trigger type', + `trigger_params` longtext COMMENT 'job custom parameters', + `create_time` datetime NOT NULL COMMENT 'create time', + `update_time` datetime NOT NULL COMMENT 'update time', + PRIMARY KEY (`id`,`code`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE = utf8_bin; + +-- ---------------------------- +-- Records of t_ds_trigger_definition +-- ---------------------------- + +-- ---------------------------- +-- Table structure for t_ds_trigger_instance +-- ---------------------------- +DROP TABLE IF EXISTS `t_ds_trigger_instance`; +CREATE TABLE `t_ds_trigger_instance` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'key', + `name` varchar(255) DEFAULT NULL COMMENT 'trigger name', + `trigger_type` varchar(50) NOT NULL COMMENT 'trigger type', + `trigger_code` bigint(20) NOT NULL COMMENT 'trigger definition code', + `process_instance_id` int(11) DEFAULT NULL COMMENT 'process instance id', + `process_instance_name` varchar(255) DEFAULT NULL COMMENT 'process instance name', + `project_code` bigint(20) DEFAULT NULL COMMENT 'project code', + `state` tinyint(4) DEFAULT NULL COMMENT 'Status: 0 commit succeeded, 1 running, 2 prepare to pause, 3 pause, 4 prepare to stop, 5 stop, 6 fail, 7 succeed, 8 need fault tolerance, 9 kill, 10 wait for thread, 11 wait for dependency to complete', + `submit_time` datetime DEFAULT NULL COMMENT 'trigger submit time', + `start_time` datetime DEFAULT NULL COMMENT 'trigger start time', + `end_time` datetime DEFAULT NULL COMMENT 'trigger end time', + `trigger_params` longtext COMMENT 'job custom parameters', + PRIMARY KEY (`id`), + KEY `process_instance_id` (`process_instance_id`) USING BTREE, + KEY `idx_code_version` (`task_code`, `task_definition_version`) USING BTREE, +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE = utf8_bin; + +-- ---------------------------- +-- Records of t_ds_trigger_instance +-- ---------------------------- + -- ---------------------------- -- Table structure for t_ds_tenant -- ---------------------------- diff --git a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql index d314c6ef09..f955dfd9de 100644 --- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql +++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql @@ -419,6 +419,61 @@ CREATE TABLE t_ds_task_definition ( create index task_definition_index on t_ds_task_definition (project_code,id); +-- +-- Table structure for table t_ds_trigger_offset +-- + +DROP TABLE IF EXISTS t_ds_trigger_offset; +CREATE TABLE t_ds_trigger_offset ( + id int NOT NULL , + code bigint NOT NULL, + PRIMARY KEY (id) +) ; + +-- +-- Table structure for table t_ds_trigger_definition +-- + +DROP TABLE IF EXISTS t_ds_trigger_definition; +CREATE TABLE t_ds_trigger_definition ( + id int NOT NULL , + code bigint NOT NULL, + name varchar(255) DEFAULT NULL , + description text , + project_code bigint DEFAULT NULL , + user_id int DEFAULT NULL , + trigger_type varchar(50) DEFAULT NULL , + trigger_params text , + create_time timestamp DEFAULT NULL , + update_time timestamp DEFAULT NULL , + PRIMARY KEY (id) +) ; + +create index trigger_definition_index on t_ds_trigger_definition (project_code,id); + +-- +-- Table structure for table t_ds_trigger_instance +-- + +DROP TABLE IF EXISTS t_ds_trigger_instance; +CREATE TABLE t_ds_trigger_instance ( + id int NOT NULL , + name varchar(255) DEFAULT NULL , + trigger_type varchar(50) DEFAULT NULL , + trigger_code bigint NOT NULL, + process_instance_id int DEFAULT NULL , + process_instance_name varchar(255) DEFAULT NULL, + project_code bigint DEFAULT NULL, + state int DEFAULT NULL , + submit_time timestamp DEFAULT NULL , + start_time timestamp DEFAULT NULL , + end_time timestamp DEFAULT NULL , + trigger_params text , + PRIMARY KEY (id) +) ; + +create index idx_trigger_instance_code_version on t_ds_trigger_instance (task_code, task_definition_version); + -- -- Table structure for table t_ds_task_definition_log -- @@ -838,6 +893,8 @@ CREATE TABLE t_ds_task_instance ( create index idx_task_instance_code_version on t_ds_task_instance (task_code, task_definition_version); create index idx_cache_key on t_ds_task_instance (cache_key); + + -- -- Table structure for table t_ds_tenant -- diff --git a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapperTest.java b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapperTest.java new file mode 100644 index 0000000000..99e3dec47f --- /dev/null +++ b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerDefinitionMapperTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dolphinscheduler.dao.mapper; + +import java.util.Date; + +import org.apache.dolphinscheduler.dao.BaseDaoTest; +import org.apache.dolphinscheduler.dao.entity.TaskDefinition; +import org.apache.dolphinscheduler.dao.entity.TriggerDefinition; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class TriggerDefinitionMapperTest extends BaseDaoTest { + @Autowired + private TriggerDefinitionMapper triggerDefinitionMapper; + + public TriggerDefinition insertOne() { + return insertOne(99); + } + + public TriggerDefinition insertOne(int userId) { + TriggerDefinition triggerDefinition = new TriggerDefinition(); + triggerDefinition.setCode(888888L); + triggerDefinition.setName("unit-test"); + triggerDefinition.setProjectCode(1L); + triggerDefinition.setUserId(userId); + triggerDefinition.setCreateTime(new Date()); + triggerDefinition.setUpdateTime(new Date()); + triggerDefinition.setTriggerType("unit-test"); + triggerDefinitionMapper.insert(triggerDefinition); + return triggerDefinition; + } + + @Test + public void testInsert() { + TriggerDefinition triggerDefinition = insertOne(); + Assertions.assertNotEquals(0, triggerDefinition.getId().intValue()); + } +} diff --git a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerInstanceMapperTest.java b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerInstanceMapperTest.java new file mode 100644 index 0000000000..28cfb9cfdd --- /dev/null +++ b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerInstanceMapperTest.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.dao.mapper; + +import java.util.Date; + +import org.apache.dolphinscheduler.common.enums.WorkflowExecutionStatus; +import org.apache.dolphinscheduler.dao.BaseDaoTest; +import org.apache.dolphinscheduler.dao.entity.ProcessInstance; +import org.apache.dolphinscheduler.dao.entity.TriggerInstance; +import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class TriggerInstanceMapperTest extends BaseDaoTest { + + @Autowired + private ProcessDefinitionMapper processDefinitionMapper; + + @Autowired + private ProcessInstanceMapper processInstanceMapper; + + @Autowired + private TriggerInstanceMapper triggerInstanceMapper; + + /** + * insert + * + * @return ProcessInstance + */ + private ProcessInstance insertProcessInstance() { + ProcessInstance processInstance = new ProcessInstance(); + processInstance.setId(1); + processInstance.setName("taskName"); + processInstance.setState(WorkflowExecutionStatus.RUNNING_EXECUTION); + processInstance.setStartTime(new Date()); + processInstance.setEndTime(new Date()); + processInstance.setProcessDefinitionCode(1L); + processInstance.setProjectCode(1L); + processInstance.setTestFlag(0); + processInstanceMapper.insert(processInstance); + return processInstance; + } + + /** + * construct a task instance and then insert + */ + private TriggerInstance insertTriggerInstance(int processInstanceId) { + TriggerInstance taskInstance = new TriggerInstance(); + taskInstance.setName("us task"); + taskInstance.setState(TaskExecutionStatus.RUNNING_EXECUTION); + taskInstance.setStartTime(new Date()); + taskInstance.setEndTime(new Date()); + taskInstance.setTriggerType("asd"); + taskInstance.setProcessInstanceId(processInstanceId); + taskInstance.setProjectCode(1L); + triggerInstanceMapper.insert(taskInstance); + return taskInstance; + } + + /** + * test update + */ + @Test + public void testUpdate() { + // insert ProcessInstance + ProcessInstance processInstance = insertProcessInstance(); + + // insert taskInstance + TriggerInstance triggerInstance = insertTriggerInstance(processInstance.getId()); + } +} diff --git a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerOffsetMapperTest.java b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerOffsetMapperTest.java new file mode 100644 index 0000000000..88c2f13881 --- /dev/null +++ b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/TriggerOffsetMapperTest.java @@ -0,0 +1,31 @@ +package org.apache.dolphinscheduler.dao.mapper; + +import org.apache.dolphinscheduler.dao.BaseDaoTest; +import org.apache.dolphinscheduler.dao.entity.TriggerOffset; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Date; + +public class TriggerOffsetMapperTest extends BaseDaoTest { + @Autowired + private TriggerOffsetMapper triggerOffsetMapper; + + public TriggerOffset insertOne() { + return insertOne(99); + } + + public TriggerOffset insertOne(int userId) { + TriggerOffset triggerOffset = new TriggerOffset(); + triggerOffset.setId(1); + triggerOffset.setCode(888888L); + return triggerOffset; + } + + @Test + public void testInsert() { + TriggerOffset triggerDefinition = insertOne(); + Assertions.assertNotEquals(0, triggerDefinition.getId().intValue()); + } +} diff --git a/dolphinscheduler-master/pom.xml b/dolphinscheduler-master/pom.xml index 1b99dd97f3..7eb9de4ef7 100644 --- a/dolphinscheduler-master/pom.xml +++ b/dolphinscheduler-master/pom.xml @@ -69,6 +69,11 @@ dolphinscheduler-task-all + + org.apache.dolphinscheduler + dolphinscheduler-trigger-all + + org.apache.dolphinscheduler dolphinscheduler-storage-all diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/MasterServer.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/MasterServer.java index 9b507500b9..14ae216872 100644 --- a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/MasterServer.java +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/MasterServer.java @@ -29,6 +29,7 @@ import org.apache.dolphinscheduler.meter.metrics.SystemMetrics; import org.apache.dolphinscheduler.plugin.datasource.api.plugin.DataSourceProcessorProvider; import org.apache.dolphinscheduler.plugin.storage.api.StorageConfiguration; import org.apache.dolphinscheduler.plugin.task.api.TaskPluginManager; +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerPluginManager; import org.apache.dolphinscheduler.registry.api.RegistryConfiguration; import org.apache.dolphinscheduler.scheduler.api.SchedulerApi; import org.apache.dolphinscheduler.server.master.metrics.MasterServerMetrics; @@ -38,6 +39,7 @@ import org.apache.dolphinscheduler.server.master.rpc.MasterRpcServer; import org.apache.dolphinscheduler.server.master.runner.EventExecuteService; import org.apache.dolphinscheduler.server.master.runner.FailoverExecuteThread; import org.apache.dolphinscheduler.server.master.runner.MasterSchedulerBootstrap; +import org.apache.dolphinscheduler.server.master.runner.MasterTriggerBootstrap; import org.apache.dolphinscheduler.server.master.runner.taskgroup.TaskGroupCoordinator; import org.apache.dolphinscheduler.service.ServiceConfiguration; import org.apache.dolphinscheduler.service.bean.SpringApplicationContext; @@ -70,6 +72,9 @@ public class MasterServer implements IStoppable { @Autowired private MasterSchedulerBootstrap masterSchedulerBootstrap; + @Autowired + private MasterTriggerBootstrap masterTriggerBootstrap; + @Autowired private SchedulerApi schedulerApi; @@ -109,6 +114,7 @@ public class MasterServer implements IStoppable { // install task plugin TaskPluginManager.loadPlugin(); + TriggerPluginManager.loadPlugin(); DataSourceProcessorProvider.initialize(); this.masterSlotManager.start(); @@ -119,6 +125,8 @@ public class MasterServer implements IStoppable { this.masterSchedulerBootstrap.start(); + this.masterTriggerBootstrap.start(); + this.eventExecuteService.start(); this.failoverExecuteThread.start(); @@ -162,6 +170,7 @@ public class MasterServer implements IStoppable { try ( SchedulerApi closedSchedulerApi = schedulerApi; MasterSchedulerBootstrap closedSchedulerBootstrap = masterSchedulerBootstrap; + MasterTriggerBootstrap closedTriggerBootstrap = masterTriggerBootstrap; MasterRpcServer closedRpcServer = masterRPCServer; MasterRegistryClient closedMasterRegistryClient = masterRegistryClient; // close spring Context and will invoke method with @PreDestroy annotation to destroy beans. diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/MasterTriggerBootstrap.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/MasterTriggerBootstrap.java new file mode 100644 index 0000000000..297cb3c4fe --- /dev/null +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/MasterTriggerBootstrap.java @@ -0,0 +1,151 @@ +package org.apache.dolphinscheduler.server.master.runner; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.dolphinscheduler.common.constants.Constants; +import org.apache.dolphinscheduler.common.lifecycle.ServerLifeCycleManager; +import org.apache.dolphinscheduler.common.thread.BaseDaemonThread; +import org.apache.dolphinscheduler.common.thread.ThreadUtils; +import org.apache.dolphinscheduler.dao.entity.Command; +import org.apache.dolphinscheduler.dao.entity.ProcessInstance; +import org.apache.dolphinscheduler.meter.metrics.MetricsProvider; +import org.apache.dolphinscheduler.meter.metrics.SystemMetrics; +import org.apache.dolphinscheduler.server.master.cache.ProcessInstanceExecCacheManager; +import org.apache.dolphinscheduler.server.master.command.ICommandFetcher; +import org.apache.dolphinscheduler.server.master.config.MasterConfig; +import org.apache.dolphinscheduler.server.master.config.MasterServerLoadProtection; +import org.apache.dolphinscheduler.server.master.event.WorkflowEvent; +import org.apache.dolphinscheduler.server.master.event.WorkflowEventQueue; +import org.apache.dolphinscheduler.server.master.event.WorkflowEventType; +import org.apache.dolphinscheduler.server.master.exception.WorkflowCreateException; +import org.apache.dolphinscheduler.server.master.metrics.MasterServerMetrics; +import org.apache.dolphinscheduler.service.command.CommandService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +@Slf4j +public class MasterTriggerBootstrap extends BaseDaemonThread implements AutoCloseable { + + @Autowired + private ICommandFetcher commandFetcher; + + @Autowired + private CommandService commandService; + + @Autowired + private MasterConfig masterConfig; + + @Autowired + private ProcessInstanceExecCacheManager processInstanceExecCacheManager; + + @Autowired + private WorkflowExecuteRunnableFactory workflowExecuteRunnableFactory; + + @Autowired + private WorkflowEventQueue workflowEventQueue; + + @Autowired + private WorkflowEventLooper workflowEventLooper; + + @Autowired + private MasterTaskExecutorBootstrap masterTaskExecutorBootstrap; + + @Autowired + private MetricsProvider metricsProvider; + + protected MasterTriggerBootstrap() { + super("MasterTriggerBootstrap"); + } + + @Override + public synchronized void start() { + log.info("MasterTriggerBootstrap starting.."); + super.start(); +// workflowEventLooper.start(); +// masterTaskExecutorBootstrap.start(); + log.info("MasterTriggerBootstrap started..."); + } + + @Override + public void close() throws Exception { + log.info("MasterTriggerBootstrap stopping..."); +// try ( +// final WorkflowEventLooper workflowEventLooper1 = workflowEventLooper; +// final MasterTaskExecutorBootstrap masterTaskExecutorBootstrap1 = masterTaskExecutorBootstrap) { +// // closed the resource +// } + log.info("MasterTriggerBootstrap stopped..."); + } + + @Override + public void run() { + MasterServerLoadProtection serverLoadProtection = masterConfig.getServerLoadProtection(); + while (!ServerLifeCycleManager.isStopped()) { + try { + if (!ServerLifeCycleManager.isRunning()) { + // the current server is not at running status, cannot consume command. + log.warn("The current server is not at running status, cannot consumes commands."); + Thread.sleep(Constants.SLEEP_TIME_MILLIS); + } + + // todo: if the workflow event queue is much, we need to handle the back pressure + SystemMetrics systemMetrics = metricsProvider.getSystemMetrics(); + if (serverLoadProtection.isOverload(systemMetrics)) { + log.warn("The current server is overload, cannot consumes commands."); + MasterServerMetrics.incMasterOverload(); + Thread.sleep(Constants.SLEEP_TIME_MILLIS); + continue; + } + + + List commands = commandFetcher.fetchCommands(); + if (CollectionUtils.isEmpty(commands)) { + // indicate that no command ,sleep for 1s + Thread.sleep(Constants.SLEEP_TIME_MILLIS); + continue; + } +// +// commands.parallelStream() +// .forEach(command -> { +// try { +// Optional workflowExecuteRunnableOptional = +// workflowExecuteRunnableFactory.createWorkflowExecuteRunnable(command); +// if (!workflowExecuteRunnableOptional.isPresent()) { +// log.warn( +// "The command execute success, will not trigger a WorkflowExecuteRunnable, this workflowInstance might be in serial mode"); +// return; +// } +// WorkflowExecuteRunnable workflowExecuteRunnable = workflowExecuteRunnableOptional.get(); +// ProcessInstance processInstance = workflowExecuteRunnable +// .getWorkflowExecuteContext().getWorkflowInstance(); +// if (processInstanceExecCacheManager.contains(processInstance.getId())) { +// log.error( +// "The workflow instance is already been cached, this case shouldn't be happened"); +// } +// processInstanceExecCacheManager.cache(processInstance.getId(), workflowExecuteRunnable); +// workflowEventQueue.addEvent( +// new WorkflowEvent(WorkflowEventType.START_WORKFLOW, processInstance.getId())); +// } catch (WorkflowCreateException workflowCreateException) { +// log.error("Master handle command {} error ", command.getId(), workflowCreateException); +// commandService.moveToErrorCommand(command, workflowCreateException.toString()); +// } +// }); +// MasterServerMetrics.incMasterConsumeCommand(commands.size()); + } catch (InterruptedException interruptedException) { + log.warn("MasterTriggerBootstrap interrupted, close the loop", interruptedException); + Thread.currentThread().interrupt(); + break; + } catch (Exception e) { + log.error("MasterTriggerBootstrap error", e); + // sleep for 1s here to avoid the database down cause the exception boom + ThreadUtils.sleep(Constants.SLEEP_TIME_MILLIS); + } + } + } + +} + diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/TriggerExecuteRunnable.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/TriggerExecuteRunnable.java new file mode 100644 index 0000000000..0d372dd63c --- /dev/null +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/TriggerExecuteRunnable.java @@ -0,0 +1,139 @@ +package org.apache.dolphinscheduler.server.master.runner; + +import org.apache.dolphinscheduler.plugin.task.api.*; +import org.apache.dolphinscheduler.plugin.task.api.log.TaskInstanceLogHeader; +import org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils; +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerCallBack; + +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; + +@Slf4j +public abstract class TriggerExecuteRunnable implements Runnable { + + + protected @Nullable AbstractTask task; + + protected TriggerExecuteRunnable() { + } + + protected void executeTrigger(TriggerCallBack triggerCallBack) { + if (task == null) { + throw new IllegalArgumentException("The task plugin instance is not initialized"); + } +// task.handle(taskCallBack); + } + + protected void afterExecute() throws TaskException { +// if (task == null) { +// throw new TaskException("The current task instance is null"); +// } +// sendAlertIfNeeded(); +// +// sendTaskResult(); +// +// WorkerTaskExecutorHolder.remove(taskExecutionContext.getTaskInstanceId()); +// log.info("Remove the current task execute context from worker cache"); +// clearTaskExecPathIfNeeded(); + } + + protected void afterThrowing(Throwable throwable) throws TaskException { +// if (cancelTask()) { +// log.info("Cancel the task successfully"); +// } +// WorkerTaskExecutorHolder.remove(taskExecutionContext.getTaskInstanceId()); +// taskExecutionContext.setCurrentExecutionStatus(TaskExecutionStatus.FAILURE); +// taskExecutionContext.setEndTime(System.currentTimeMillis()); +// workerMessageSender.sendMessageWithRetry(taskExecutionContext, +// ITaskInstanceExecutionEvent.TaskInstanceExecutionEventType.FINISH); +// log.info("Get a exception when execute the task, will send the task status: {} to master: {}", +// TaskExecutionStatus.FAILURE.name(), taskExecutionContext.getHost()); + + } + + protected boolean cancelTask() { + // cancel the task + if (task == null) { + return true; + } + try { + task.cancel(); +// ProcessUtils.cancelApplication(taskExecutionContext); + return true; + } catch (Exception e) { + log.error("Cancel task failed, this will not affect the taskInstance status, but you need to check manual", + e); + return false; + } + } + + @Override + public void run() { + try { + TaskInstanceLogHeader.printInitializeTaskContextHeader(); + initializeTask(); + + TaskInstanceLogHeader.printLoadTaskInstancePluginHeader(); + beforeExecute(); + +// TaskCallBack taskCallBack = TaskCallbackImpl.builder() +// .workerMessageSender(workerMessageSender) +// .taskExecutionContext(taskExecutionContext) +// .build(); + + TaskInstanceLogHeader.printExecuteTaskHeader(); +// executeTrigger(taskCallBack); + + TaskInstanceLogHeader.printFinalizeTaskHeader(); + afterExecute(); + closeLogAppender(); + } catch (Throwable ex) { + log.error("Task execute failed, due to meet an exception", ex); + afterThrowing(ex); + closeLogAppender(); + } finally { + LogUtils.removeWorkflowAndTaskInstanceIdMDC(); + LogUtils.removeTaskInstanceLogFullPathMDC(); + } + } + + protected void initializeTask() { + log.info("Begin to initialize task"); + + long taskStartTime = System.currentTimeMillis(); +// taskExecutionContext.setStartTime(taskStartTime); + log.info("Set task startTime: {}", taskStartTime); + +// String taskAppId = String.format("%s_%s", taskExecutionContext.getProcessInstanceId(), +// taskExecutionContext.getTaskInstanceId()); +// taskExecutionContext.setTaskAppId(taskAppId); +// log.info("Set task appId: {}", taskAppId); + +// log.info("End initialize task {}", JSONUtils.toPrettyJsonString(taskExecutionContext)); + } + + protected void beforeExecute() { + } + + protected void sendAlertIfNeeded() { + + } + + protected void sendTaskResult() { + + } + + protected void clearTaskExecPathIfNeeded() { + + } + + protected void closeLogAppender() { + + } + + public @Nullable AbstractTask getTask() { + return task; + } + +} diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/TriggerExecuteThreadPool.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/TriggerExecuteThreadPool.java new file mode 100644 index 0000000000..9cd5a678f1 --- /dev/null +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/runner/TriggerExecuteThreadPool.java @@ -0,0 +1,58 @@ +package org.apache.dolphinscheduler.server.master.runner; + +import org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils; +import org.apache.dolphinscheduler.server.master.cache.ProcessInstanceExecCacheManager; +import org.apache.dolphinscheduler.server.master.config.MasterConfig; +import org.apache.dolphinscheduler.server.master.event.StateEvent; + +import java.util.concurrent.ConcurrentHashMap; + +import javax.annotation.PostConstruct; + +import lombok.extern.slf4j.Slf4j; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; +import org.springframework.util.concurrent.ListenableFuture; +import org.springframework.util.concurrent.ListenableFutureCallback; + +@Component +@Slf4j +public class TriggerExecuteThreadPool extends ThreadPoolTaskExecutor { + + @Autowired + private MasterConfig masterConfig; + + @PostConstruct + private void init() { + this.setDaemon(true); + this.setThreadNamePrefix("StreamTaskExecuteThread-"); + this.setMaxPoolSize(masterConfig.getExecThreads()); + this.setCorePoolSize(masterConfig.getExecThreads()); + } + + public void executeEvent(final TriggerExecuteRunnable triggerExecuteRunnable) { +// if (!streamTaskExecuteRunnable.isStart() || streamTaskExecuteRunnable.eventSize() == 0) { +// return; +// } +// int taskInstanceId = streamTaskExecuteRunnable.getTaskInstance().getId(); +// ListenableFuture future = this.submitListenable(streamTaskExecuteRunnable::handleEvents); +// future.addCallback(new ListenableFutureCallback() { +// +// @Override +// public void onFailure(Throwable ex) { +// LogUtils.setTaskInstanceIdMDC(taskInstanceId); +// log.error("Stream task instance events handle failed", ex); +// LogUtils.removeTaskInstanceIdMDC(); +// } +// +// @Override +// public void onSuccess(Object result) { +// LogUtils.setTaskInstanceIdMDC(taskInstanceId); +// log.info("Stream task instance is finished."); +// LogUtils.removeTaskInstanceIdMDC(); +// } +// }); + } +} diff --git a/dolphinscheduler-service/pom.xml b/dolphinscheduler-service/pom.xml index 0bca706c3b..d7fddd66a2 100644 --- a/dolphinscheduler-service/pom.xml +++ b/dolphinscheduler-service/pom.xml @@ -58,6 +58,10 @@ org.apache.dolphinscheduler dolphinscheduler-task-api + + org.apache.dolphinscheduler + dolphinscheduler-trigger-api + org.apache.dolphinscheduler diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml b/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml index 5e4c74b27a..9719960a60 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml @@ -222,6 +222,11 @@ dolphinscheduler-task-remoteshell ${project.version} + + org.apache.dolphinscheduler + dolphinscheduler-task-trigger + ${project.version} + diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/pom.xml b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/pom.xml new file mode 100644 index 0000000000..52e044c97a --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/pom.xml @@ -0,0 +1,48 @@ + + + + 4.0.0 + + org.apache.dolphinscheduler + dolphinscheduler-task-plugin + dev-SNAPSHOT + + + dolphinscheduler-task-trigger + jar + + + + org.apache.dolphinscheduler + dolphinscheduler-spi + provided + + + org.apache.dolphinscheduler + dolphinscheduler-task-api + provided + + + org.apache.dolphinscheduler + dolphinscheduler-common + provided + + + + diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerException.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerException.java new file mode 100644 index 0000000000..189204023d --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerException.java @@ -0,0 +1,18 @@ +package org.apache.dolphinscheduler.plugin.task.trigger; + +public class TriggerException extends RuntimeException { + + private static final long serialVersionUID = 8155449302457294758L; + + public TriggerException() { + super(); + } + + public TriggerException(String msg, Throwable cause) { + super(msg, cause); + } + + public TriggerException(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerParameters.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerParameters.java new file mode 100644 index 0000000000..187fd916c1 --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerParameters.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.plugin.task.trigger; + +import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters; + +import org.apache.commons.lang3.StringUtils; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@NoArgsConstructor +@ToString +public class TriggerParameters extends AbstractParameters { + + private String factoryName; + private String resourceGroupName; + private String pipelineName; + private String runId; + + @Override + public boolean checkParameters() { + return StringUtils.isNotEmpty(factoryName) && StringUtils.isNotEmpty(resourceGroupName) + && StringUtils.isNotEmpty(pipelineName); + } +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerStatus.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerStatus.java new file mode 100644 index 0000000000..1f58e945e2 --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerStatus.java @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.plugin.task.trigger; + +public enum TriggerStatus { + + Queued, + InProgress, + Succeeded, + Failed, + Canceling, + Cancelled, + ; + + /** + * Gets the status property: The status of a pipeline run. Possible values: Queued, InProgress, Succeeded, Failed, + * Canceling, Cancelled. + * + * @return the status value. + */ + TriggerStatus() { + } +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTask.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTask.java new file mode 100644 index 0000000000..f38f519d0a --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTask.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.plugin.task.trigger; + +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.task.api.AbstractRemoteTask; +import org.apache.dolphinscheduler.plugin.task.api.TaskConstants; +import org.apache.dolphinscheduler.plugin.task.api.TaskException; +import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; + +import java.util.Collections; +import java.util.List; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Setter +@Getter +@Slf4j +public class TriggerTask extends AbstractRemoteTask { + + private final TaskExecutionContext taskExecutionContext; + private TriggerParameters parameters; + + public TriggerTask(TaskExecutionContext taskExecutionContext) { + super(taskExecutionContext); + this.taskExecutionContext = taskExecutionContext; + } + + @Override + public List getApplicationIds() throws TaskException { + return Collections.emptyList(); + } + + @Override + public void init() { + parameters = JSONUtils.parseObject(taskExecutionContext.getTaskParams(), TriggerParameters.class); + log.info("Initialize Datafactory task params {}", JSONUtils.toPrettyJsonString(parameters)); + } + + @Override + public void submitApplication() throws TaskException { + try { + // start task + exitStatusCode = startDatafactoryTask(); + setExitStatusCode(exitStatusCode); + } catch (Exception e) { + setExitStatusCode(TaskConstants.EXIT_CODE_FAILURE); + throw new TaskException("data factory start task error", e); + } + // set runId to the appIds if start success + setAppIds(parameters.getRunId()); + } + + @Override + public void cancelApplication() throws TaskException { + checkApplicationId(); + exitStatusCode = TaskConstants.EXIT_CODE_KILL; + } + + @Override + public void trackApplicationStatus() throws TaskException { + checkApplicationId(); + Boolean isFinishedSuccessfully = false; + if (!isFinishedSuccessfully) { + exitStatusCode = TaskConstants.EXIT_CODE_FAILURE; + } else { + exitStatusCode = TaskConstants.EXIT_CODE_SUCCESS; + } + } + + /** + * check datafactory applicationId or get it from appId + */ + private void checkApplicationId() { + } + + public int startDatafactoryTask() { + return 0; + } + + @Override + public TriggerParameters getParameters() { + return parameters; + } + +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskChannel.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskChannel.java new file mode 100644 index 0000000000..3abcf68f8c --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskChannel.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.plugin.task.trigger; + +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.task.api.TaskChannel; +import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; +import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters; +import org.apache.dolphinscheduler.plugin.task.api.parameters.ParametersNode; +import org.apache.dolphinscheduler.plugin.task.api.parameters.resource.ResourceParametersHelper; + +public class TriggerTaskChannel implements TaskChannel { + + @Override + public void cancelApplication(boolean status) { + } + + @Override + public TriggerTask createTask(TaskExecutionContext taskRequest) { + return new TriggerTask(taskRequest); + } + + @Override + public AbstractParameters parseParameters(ParametersNode parametersNode) { + return JSONUtils.parseObject(parametersNode.getTaskParams(), TriggerParameters.class); + } + + @Override + public ResourceParametersHelper getResources(String parameters) { + return null; + } +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskChannelFactory.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskChannelFactory.java new file mode 100644 index 0000000000..e95d6825f5 --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/main/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskChannelFactory.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.plugin.task.trigger; + +import org.apache.dolphinscheduler.plugin.task.api.TaskChannel; +import org.apache.dolphinscheduler.plugin.task.api.TaskChannelFactory; +import org.apache.dolphinscheduler.spi.params.base.PluginParams; + +import java.util.Collections; +import java.util.List; + +import com.google.auto.service.AutoService; + +@AutoService(TaskChannelFactory.class) +public class TriggerTaskChannelFactory implements TaskChannelFactory { + + @Override + public TaskChannel create() { + return new TriggerTaskChannel(); + } + + @Override + public String getName() { + return "TRIGGER"; + } + + @Override + public List getParams() { + return Collections.emptyList(); + } +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/test/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskTest.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/test/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskTest.java new file mode 100644 index 0000000000..7405663f34 --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-trigger/src/test/java/org/apache/dolphinscheduler/plugin/task/trigger/TriggerTaskTest.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.plugin.task.trigger; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class TriggerTaskTest { + + +} diff --git a/dolphinscheduler-task-plugin/pom.xml b/dolphinscheduler-task-plugin/pom.xml index f4c1573226..92c420425a 100644 --- a/dolphinscheduler-task-plugin/pom.xml +++ b/dolphinscheduler-task-plugin/pom.xml @@ -63,6 +63,7 @@ dolphinscheduler-task-linkis dolphinscheduler-task-datafactory dolphinscheduler-task-remoteshell + dolphinscheduler-task-trigger diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-all/pom.xml b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-all/pom.xml new file mode 100644 index 0000000000..872d66eab0 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-all/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + org.apache.dolphinscheduler + dolphinscheduler-trigger-plugin + dev-SNAPSHOT + + + dolphinscheduler-trigger-all + + + + org.apache.dolphinscheduler + dolphinscheduler-trigger-simple + ${project.version} + + + + \ No newline at end of file diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/pom.xml b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/pom.xml new file mode 100644 index 0000000000..66425496fd --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + org.apache.dolphinscheduler + dolphinscheduler-trigger-plugin + dev-SNAPSHOT + + + dolphinscheduler-trigger-api + jar + + + + org.apache.dolphinscheduler + dolphinscheduler-common + + + org.apache.dolphinscheduler + dolphinscheduler-spi + + + com.baomidou + mybatis-plus-annotation + + + \ No newline at end of file diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/AbstractTrigger.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/AbstractTrigger.java new file mode 100644 index 0000000000..d64ff8819d --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/AbstractTrigger.java @@ -0,0 +1,45 @@ +package org.apache.dolphinscheduler.plugin.trigger.api; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.dolphinscheduler.plugin.trigger.api.enums.TriggerExecutionStatus; +import org.apache.dolphinscheduler.plugin.trigger.api.parameters.AbstractParameters; + +import java.util.Map; +import java.util.StringJoiner; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Slf4j +public abstract class AbstractTrigger { + @Getter + @Setter + protected Map taskOutputParams; + + /** + * taskExecutionContext + **/ + protected TriggerExecutionContext triggerExecutionContext; + + protected AbstractTrigger(TriggerExecutionContext triggerExecutionContext) { + this.triggerExecutionContext = triggerExecutionContext; + } + + public void init() { + } + + public abstract void handle(TriggerCallBack taskCallBack) throws TriggerException; + + public abstract void cancel() throws TriggerException; + + /** + * get task parameters + * + * @return AbstractParameters + */ + public abstract AbstractParameters getParameters(); + + +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerCallBack.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerCallBack.java new file mode 100644 index 0000000000..02083da772 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerCallBack.java @@ -0,0 +1,4 @@ +package org.apache.dolphinscheduler.plugin.trigger.api; + +public interface TriggerCallBack { +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerChannel.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerChannel.java new file mode 100644 index 0000000000..d1fb616705 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerChannel.java @@ -0,0 +1,7 @@ +package org.apache.dolphinscheduler.plugin.trigger.api; + +public interface TriggerChannel { + void cancelApplication(boolean status); + + AbstractTrigger createTrigger(TriggerExecutionContext taskRequest); +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerChannelFactory.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerChannelFactory.java new file mode 100644 index 0000000000..365d16df97 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerChannelFactory.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.plugin.trigger.api; + +import org.apache.dolphinscheduler.spi.common.UiChannelFactory; +import org.apache.dolphinscheduler.spi.plugin.PrioritySPI; +import org.apache.dolphinscheduler.spi.plugin.SPIIdentify; + +public interface TriggerChannelFactory extends UiChannelFactory, PrioritySPI { + + TriggerChannel create(); + + default SPIIdentify getIdentify() { + return SPIIdentify.builder().name(getName()).build(); + } + +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerConstants.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerConstants.java new file mode 100644 index 0000000000..aea0bd7d25 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerConstants.java @@ -0,0 +1,425 @@ +package org.apache.dolphinscheduler.plugin.trigger.api; + +import com.google.common.collect.Sets; +import org.apache.dolphinscheduler.common.constants.DateConstants; + +import java.time.Duration; +import java.util.Set; + +public class TriggerConstants { + + private TriggerConstants() { + throw new IllegalStateException("Utility class"); + } + + public static final String YARN_APPLICATION_REGEX = "application_\\d+_\\d+"; + + public static final String FLINK_APPLICATION_REGEX = "JobID \\w+"; + + /** + * exit code kill + */ + public static final int EXIT_CODE_KILL = 137; + public static final String PID = "pid"; + + /** + * QUESTION ? + */ + public static final String QUESTION = "?"; + + /** + * comma , + */ + public static final String COMMA = ","; + + /** + * hyphen + */ + public static final String HYPHEN = "-"; + + /** + * slash / + */ + public static final String SLASH = "/"; + + /** + * COLON : + */ + public static final String COLON = ":"; + + /** + * SPACE " " + */ + public static final String SPACE = " "; + + /** + * SINGLE_SLASH / + */ + public static final String SINGLE_SLASH = "/"; + + /** + * DOUBLE_SLASH // + */ + public static final String DOUBLE_SLASH = "//"; + + /** + * SINGLE_QUOTES "'" + */ + public static final String SINGLE_QUOTES = "'"; + /** + * DOUBLE_QUOTES "\"" + */ + public static final String DOUBLE_QUOTES = "\""; + + /** + * SEMICOLON ; + */ + public static final String SEMICOLON = ";"; + + /** + * EQUAL SIGN + */ + public static final String EQUAL_SIGN = "="; + /** + * AT SIGN + */ + public static final String AT_SIGN = "@"; + /** + * UNDERLINE + */ + public static final String UNDERLINE = "_"; + + /** + * sleep time + */ + public static final int SLEEP_TIME_MILLIS = 1000; + + /** + * exit code failure + */ + public static final int EXIT_CODE_FAILURE = -1; + + /** + * exit code success + */ + public static final int EXIT_CODE_SUCCESS = 0; + /** + * running code + */ + public static final int RUNNING_CODE = 1; + + public static final String SH = "sh"; + + /** + * log flush interval?output when reach the interval + */ + public static final int DEFAULT_LOG_FLUSH_INTERVAL = 1000; + + /** + * pstree, get pud and sub pid + */ + public static final String PSTREE = "pstree"; + + public static final String RWXR_XR_X = "rwxr-xr-x"; + + /** + * date format of yyyyMMddHHmmss + */ + public static final String PARAMETER_FORMAT_TIME = "yyyyMMddHHmmss"; + + /** + * new + * schedule time + */ + public static final String PARAMETER_SHECDULE_TIME = "schedule.time"; + + /** + * system date(yyyyMMddHHmmss) + */ + public static final String PARAMETER_DATETIME = DateConstants.PARAMETER_DATETIME; + + /** + * system date(yyyymmdd) today + */ + public static final String PARAMETER_CURRENT_DATE = DateConstants.PARAMETER_CURRENT_DATE; + + /** + * system date(yyyymmdd) yesterday + */ + public static final String PARAMETER_BUSINESS_DATE = DateConstants.PARAMETER_BUSINESS_DATE; + + /** + * the absolute path of current executing task + */ + public static final String PARAMETER_TASK_EXECUTE_PATH = "system.task.execute.path"; + + /** + * the instance id of current task + */ + public static final String PARAMETER_TASK_INSTANCE_ID = "system.task.instance.id"; + + /** + * the definition code of current task + */ + public static final String PARAMETER_TASK_DEFINITION_CODE = "system.task.definition.code"; + + /** + * the definition name of current task + */ + public static final String PARAMETER_TASK_DEFINITION_NAME = "system.task.definition.name"; + + /** + * the instance id of the workflow to which current task belongs + */ + public static final String PARAMETER_WORKFLOW_INSTANCE_ID = "system.workflow.instance.id"; + + /** + * the definition code of the workflow to which current task belongs + */ + public static final String PARAMETER_WORKFLOW_DEFINITION_CODE = "system.workflow.definition.code"; + + /** + * the definition name of the workflow to which current task belongs + */ + public static final String PARAMETER_WORKFLOW_DEFINITION_NAME = "system.workflow.definition.name"; + + /** + * the code of the project to which current task belongs + */ + public static final String PARAMETER_PROJECT_CODE = "system.project.code"; + + /** + * the name of the project to which current task belongs + */ + public static final String PARAMETER_PROJECT_NAME = "system.project.name"; + /** + * month_begin + */ + public static final String MONTH_BEGIN = "month_begin"; + /** + * add_months + */ + public static final String ADD_MONTHS = "add_months"; + /** + * month_end + */ + public static final String MONTH_END = "month_end"; + /** + * week_begin + */ + public static final String WEEK_BEGIN = "week_begin"; + /** + * week_end + */ + public static final String WEEK_END = "week_end"; + /** + * this_day + */ + public static final String THIS_DAY = "this_day"; + /** + * last_day + */ + public static final String LAST_DAY = "last_day"; + + /** + * month_first_day + */ + public static final String MONTH_FIRST_DAY = "month_first_day"; + + /** + * month_last_day + */ + public static final String MONTH_LAST_DAY = "month_last_day"; + + /** + * week_first_day + */ + public static final String WEEK_FIRST_DAY = "week_first_day"; + + /** + * week_last_day + */ + public static final String WEEK_LAST_DAY = "week_last_day"; + + /** + * year_week + */ + public static final String YEAR_WEEK = "year_week"; + /** + * timestamp + */ + public static final String TIMESTAMP = "timestamp"; + public static final char SUBTRACT_CHAR = '-'; + public static final char ADD_CHAR = '+'; + public static final char MULTIPLY_CHAR = '*'; + public static final char DIVISION_CHAR = '/'; + public static final char LEFT_BRACE_CHAR = '('; + public static final char RIGHT_BRACE_CHAR = ')'; + public static final String ADD_STRING = "+"; + public static final String MULTIPLY_STRING = "*"; + public static final String DIVISION_STRING = "/"; + public static final String LEFT_BRACE_STRING = "("; + public static final char P = 'P'; + public static final char N = 'N'; + public static final String SUBTRACT_STRING = "-"; + public static final String LOCAL_PARAMS_LIST = "localParamsList"; + public static final String TASK_TYPE = "taskType"; + public static final String QUEUE = "queue"; + /** + * default display rows + */ + public static final int DEFAULT_DISPLAY_ROWS = 10; + + /** + * jar + */ + public static final String JAR = "jar"; + + /** + * hadoop + */ + public static final String HADOOP = "hadoop"; + + /** + * -D = + */ + public static final String D = "-D"; + + /** + * datasource encryption salt + */ + public static final String DATASOURCE_ENCRYPTION_SALT_DEFAULT = "!@#$%^&*"; + public static final String DATASOURCE_ENCRYPTION_ENABLE = "datasource.encryption.enable"; + public static final String DATASOURCE_ENCRYPTION_SALT = "datasource.encryption.salt"; + + /** + * kerberos + */ + public static final String KERBEROS = "kerberos"; + + /** + * kerberos expire time + */ + public static final String KERBEROS_EXPIRE_TIME = "kerberos.expire.time"; + + /** + * java.security.krb5.conf + */ + public static final String JAVA_SECURITY_KRB5_CONF = "java.security.krb5.conf"; + + /** + * java.security.krb5.conf.path + */ + public static final String JAVA_SECURITY_KRB5_CONF_PATH = "java.security.krb5.conf.path"; + + /** + * loginUserFromKeytab user + */ + public static final String LOGIN_USER_KEY_TAB_USERNAME = "login.user.keytab.username"; + + /** + * loginUserFromKeytab path + */ + public static final String LOGIN_USER_KEY_TAB_PATH = "login.user.keytab.path"; + + /** + * hadoop.security.authentication + */ + public static final String HADOOP_SECURITY_AUTHENTICATION = "hadoop.security.authentication"; + + /** + * hadoop.security.authentication + */ + public static final String HADOOP_SECURITY_AUTHENTICATION_STARTUP_STATE = + "hadoop.security.authentication.startup.state"; + + /** + * hdfs/s3 configuration + * resource.storage.upload.base.path + */ + public static final String RESOURCE_UPLOAD_PATH = "resource.storage.upload.base.path"; + + /** + * data.quality.jar.dir + */ + public static final String DATA_QUALITY_JAR_DIR = "data-quality.jar.dir"; + + public static final String TASK_TYPE_CONDITIONS = "CONDITIONS"; + + public static final String TASK_TYPE_SWITCH = "SWITCH"; + + public static final String TASK_TYPE_SUB_PROCESS = "SUB_PROCESS"; + + public static final String TASK_TYPE_DYNAMIC = "DYNAMIC"; + + public static final String TASK_TYPE_DEPENDENT = "DEPENDENT"; + + public static final String TASK_TYPE_SQL = "SQL"; + + public static final String TASK_TYPE_DATA_QUALITY = "DATA_QUALITY"; + + public static final Set TASK_TYPE_SET_K8S = Sets.newHashSet("K8S", "KUBEFLOW"); + + public static final String TASK_TYPE_BLOCKING = "BLOCKING"; + + /** + * azure config + */ + public static final String AZURE_CLIENT_ID = "resource.azure.client.id"; + public static final String AZURE_CLIENT_SECRET = "resource.azure.client.secret"; + public static final String AZURE_ACCESS_SUB_ID = "resource.azure.subId"; + public static final String AZURE_SECRET_TENANT_ID = "resource.azure.tenant.id"; + public static final String QUERY_INTERVAL = "resource.query.interval"; + + /** + * aws config + */ + public static final String AWS_ACCESS_KEY_ID = "resource.aws.access.key.id"; + public static final String AWS_SECRET_ACCESS_KEY = "resource.aws.secret.access.key"; + public static final String AWS_REGION = "resource.aws.region"; + + /** + * alibaba cloud config + */ + public static final String ALIBABA_CLOUD_ACCESS_KEY_ID = "resource.alibaba.cloud.access.key.id"; + public static final String ALIBABA_CLOUD_ACCESS_KEY_SECRET = "resource.alibaba.cloud.access.key.secret"; + public static final String ALIBABA_CLOUD_REGION = "resource.alibaba.cloud.region"; + + /** + * huawei cloud config + */ + public static final String HUAWEI_CLOUD_ACCESS_KEY_ID = "resource.huawei.cloud.access.key.id"; + public static final String HUAWEI_CLOUD_ACCESS_KEY_SECRET = "resource.huawei.cloud.access.key.secret"; + + /** + * use for k8s task + */ + public static final String API_VERSION = "batch/v1"; + public static final String RESTART_POLICY = "Never"; + public static final String MEMORY = "memory"; + public static final String CPU = "cpu"; + public static final String LAYER_LABEL = "k8s.cn/layer"; + public static final String LAYER_LABEL_VALUE = "batch"; + public static final String NAME_LABEL = "k8s.cn/name"; + public static final String TASK_INSTANCE_ID = "taskInstanceId"; + public static final String MI = "Mi"; + public static final int JOB_TTL_SECONDS = 300; + public static final int LOG_LINES = 500; + public static final String NAMESPACE_NAME = "name"; + public static final String CLUSTER = "cluster"; + + /** + * spark / flink on k8s label name + */ + public static final String UNIQUE_LABEL_NAME = "dolphinscheduler-label"; + + /** + * conda config used by jupyter task plugin + */ + public static final String CONDA_PATH = "conda.path"; + + // Loop task constants + public static final Duration DEFAULT_LOOP_STATUS_INTERVAL = Duration.ofSeconds(5L); + +} + diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerException.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerException.java new file mode 100644 index 0000000000..c41175e0c8 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerException.java @@ -0,0 +1,18 @@ +package org.apache.dolphinscheduler.plugin.trigger.api; + +public class TriggerException extends RuntimeException { + + private static final long serialVersionUID = 8155449302457294758L; + + public TriggerException() { + super(); + } + + public TriggerException(String msg, Throwable cause) { + super(msg, cause); + } + + public TriggerException(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerExecutionContext.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerExecutionContext.java new file mode 100644 index 0000000000..c5793ec81a --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerExecutionContext.java @@ -0,0 +1,128 @@ +package org.apache.dolphinscheduler.plugin.trigger.api; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * to master/worker task transport + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class TriggerExecutionContext implements Serializable { + + private static final long serialVersionUID = -1L; + + /** + * trigger id + */ + private int triggerInstanceId; + + /** + * trigger name + */ + private String triggerName; + + /** + * trigger first submit time. + */ + private long firstSubmitTime; + + /** + * trigger start time + */ + private long startTime; + + /** + * trigger type + */ + private String triggerType; + + /** + * trigger json + */ + private String triggerJson; + + /** + * processId + */ + private int processId; + + /** + * processCode + */ + private Long processDefineCode; + + /** + * processVersion + */ + private int processDefineVersion; + + /** + * appIds + */ + private String appIds; + + /** + * process instance id + */ + private int processInstanceId; + + /** + * process instance schedule time + */ + private long scheduleTime; + + /** + * process instance global parameters + */ + private String globalParams; + + /** + * execute user id + */ + private int executorId; + + /** + * command type if complement + */ + private int cmdTypeIfComplement; + + /** + * tenant code + */ + private String tenantCode; + + /** + * process define id + */ + private int processDefineId; + + /** + * project id + */ + private int projectId; + + /** + * project code + */ + private long projectCode; + + /** + * taskParams + */ + private String taskParams; + + /** + * environmentConfig + */ + private String environmentConfig; +} + diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerPluginManager.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerPluginManager.java new file mode 100644 index 0000000000..4891dced38 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/TriggerPluginManager.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package org.apache.dolphinscheduler.plugin.trigger.api; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +import lombok.extern.slf4j.Slf4j; +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.trigger.api.parameters.AbstractParameters; +import org.apache.dolphinscheduler.plugin.trigger.api.parameters.ParametersNode; +import org.apache.dolphinscheduler.spi.plugin.PrioritySPIFactory; + +@Slf4j +public class TriggerPluginManager { + private static final Map taskChannelFactoryMap = new HashMap<>(); + private static final Map taskChannelMap = new HashMap<>(); + + private static final AtomicBoolean loadedFlag = new AtomicBoolean(false); + + /** + * Load task plugins from classpath. + */ + public static void loadPlugin() { + if (!loadedFlag.compareAndSet(false, true)) { + log.warn("The trigger plugin has already been loaded"); + return; + } + PrioritySPIFactory prioritySPIFactory = new PrioritySPIFactory<>(TriggerChannelFactory.class); + for (Map.Entry entry : prioritySPIFactory.getSPIMap().entrySet()) { + String factoryName = entry.getKey(); + TriggerChannelFactory factory = entry.getValue(); + + log.info("Registering trigger plugin: {} - {}", factoryName, factory.getClass().getSimpleName()); + + taskChannelFactoryMap.put(factoryName, factory); + taskChannelMap.put(factoryName, factory.create()); + + log.info("Registered trigger plugin: {} - {}", factoryName, factory.getClass().getSimpleName()); + } + + } + + public static Map getTaskChannelMap() { + return Collections.unmodifiableMap(taskChannelMap); + } + + public static Map getTaskChannelFactoryMap() { + return Collections.unmodifiableMap(taskChannelFactoryMap); + } + + public static TriggerChannel getTaskChannel(String type) { + return getTaskChannelMap().get(type); + } + + public static boolean checkTaskParameters(ParametersNode parametersNode) { + AbstractParameters abstractParameters = getParameters(parametersNode); + return abstractParameters != null; + } + + public static AbstractParameters getParameters(ParametersNode parametersNode) { + String taskType = parametersNode.getTaskType(); + if (Objects.isNull(taskType)) { + return null; + } + return null; + } +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/enums/TriggerExecutionStatus.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/enums/TriggerExecutionStatus.java new file mode 100644 index 0000000000..42c0678381 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/enums/TriggerExecutionStatus.java @@ -0,0 +1,109 @@ +package org.apache.dolphinscheduler.plugin.trigger.api.enums; + +import com.baomidou.mybatisplus.annotation.EnumValue; + +import java.util.HashMap; +import java.util.Map; + +public enum TriggerExecutionStatus { + + SUBMITTED_SUCCESS(0, "submit success"), + RUNNING_EXECUTION(1, "running"), + PAUSE(3, "pause"), + STOP(5, "stop"), + FAILURE(6, "failure"), + SUCCESS(7, "success"), + NEED_FAULT_TOLERANCE(8, "need fault tolerance"), + KILL(9, "kill"), + DELAY_EXECUTION(12, "delay execution"), + FORCED_SUCCESS(13, "forced success"), + DISPATCH(17, "dispatch"), + + ; + + private static final Map CODE_MAP = new HashMap<>(); + + static { + for (TriggerExecutionStatus executionStatus : TriggerExecutionStatus.values()) { + CODE_MAP.put(executionStatus.getCode(), executionStatus); + } + } + + /** + * Get TaskExecutionStatus by code, if the code is invalidated will throw {@link IllegalArgumentException}. + */ + public static TriggerExecutionStatus of(int code) { + TriggerExecutionStatus taskExecutionStatus = CODE_MAP.get(code); + if (taskExecutionStatus == null) { + throw new IllegalArgumentException(String.format("The task execution status code: %s is invalidated", + code)); + } + return taskExecutionStatus; + } + + public boolean isRunning() { + return this == RUNNING_EXECUTION; + } + + public boolean isSuccess() { + return this == TriggerExecutionStatus.SUCCESS; + } + + public boolean isForceSuccess() { + return this == TriggerExecutionStatus.FORCED_SUCCESS; + } + + public boolean isKill() { + return this == TriggerExecutionStatus.KILL; + } + + public boolean isFailure() { + return this == TriggerExecutionStatus.FAILURE || this == NEED_FAULT_TOLERANCE; + } + + public boolean isPause() { + return this == TriggerExecutionStatus.PAUSE; + } + + public boolean isStop() { + return this == TriggerExecutionStatus.STOP; + } + + public boolean isFinished() { + return isSuccess() || isKill() || isFailure() || isPause() || isStop() || isForceSuccess(); + } + + public boolean isNeedFaultTolerance() { + return this == NEED_FAULT_TOLERANCE; + } + + public boolean shouldFailover() { + return SUBMITTED_SUCCESS == this + || DISPATCH == this + || RUNNING_EXECUTION == this + || DELAY_EXECUTION == this; + } + + @EnumValue + private final int code; + private final String desc; + + TriggerExecutionStatus(int code, String desc) { + this.code = code; + this.desc = desc; + } + + public int getCode() { + return code; + } + + public String getDesc() { + return desc; + } + + @Override + public String toString() { + return "TaskExecutionStatus{" + "code=" + code + ", desc='" + desc + '\'' + '}'; + } + +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/AbstractParameters.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/AbstractParameters.java new file mode 100644 index 0000000000..4ca713f16c --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/AbstractParameters.java @@ -0,0 +1,28 @@ +package org.apache.dolphinscheduler.plugin.trigger.api.parameters; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.google.common.collect.Lists; +import org.apache.dolphinscheduler.common.utils.JSONUtils; + +@Getter +@Slf4j +public class AbstractParameters implements IParameters { + + +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/IParameters.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/IParameters.java new file mode 100644 index 0000000000..0f1ff1b9f6 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/IParameters.java @@ -0,0 +1,4 @@ +package org.apache.dolphinscheduler.plugin.trigger.api.parameters; + +public interface IParameters { +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/ParametersNode.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/ParametersNode.java new file mode 100644 index 0000000000..7ae8b2c1c3 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-api/src/main/java/org/apache/dolphinscheduler/plugin/trigger/api/parameters/ParametersNode.java @@ -0,0 +1,95 @@ +package org.apache.dolphinscheduler.plugin.trigger.api.parameters; + +public class ParametersNode { + + private String taskType; + + private String taskParams; + + private String dependence; + + private String switchResult; + + public static ParametersNode.ParametersNodeBuilder builder() { + return new ParametersNode.ParametersNodeBuilder(); + } + + public static class ParametersNodeBuilder { + + private String taskType; + + private String taskParams; + + private String dependence; + + private String switchResult; + + public ParametersNodeBuilder taskType(String taskType) { + this.taskType = taskType; + return this; + } + + public ParametersNodeBuilder taskParams(String taskParams) { + this.taskParams = taskParams; + return this; + } + + public ParametersNodeBuilder dependence(String dependence) { + this.dependence = dependence; + return this; + } + + public ParametersNodeBuilder switchResult(String switchResult) { + this.switchResult = switchResult; + return this; + } + + public ParametersNode build() { + return new ParametersNode(this.taskType, this.taskParams, this.dependence, this.switchResult); + } + + } + + public ParametersNode() { + + } + + public ParametersNode(String taskType, String taskParams, String dependence, String switchResult) { + this.taskType = taskType; + this.taskParams = taskParams; + this.dependence = dependence; + this.switchResult = switchResult; + } + + public String getTaskType() { + return taskType; + } + + public void setTaskType(String taskType) { + this.taskType = taskType; + } + + public String getTaskParams() { + return taskParams; + } + + public void setTaskParams(String taskParams) { + this.taskParams = taskParams; + } + + public String getDependence() { + return dependence; + } + + public void setDependence(String dependence) { + this.dependence = dependence; + } + + public String getSwitchResult() { + return switchResult; + } + + public void setSwitchResult(String switchResult) { + this.switchResult = switchResult; + } +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/pom.xml b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/pom.xml new file mode 100644 index 0000000000..84ff596759 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + org.apache.dolphinscheduler + dolphinscheduler-trigger-plugin + dev-SNAPSHOT + + + dolphinscheduler-trigger-simple + jar + + + + org.apache.dolphinscheduler + dolphinscheduler-spi + provided + + + org.apache.dolphinscheduler + dolphinscheduler-trigger-api + ${project.version} + + + \ No newline at end of file diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTrigger.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTrigger.java new file mode 100644 index 0000000000..c95098e8ac --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTrigger.java @@ -0,0 +1,51 @@ +package org.apache.dolphinscheduler.plugin.trigger.simple; + +import lombok.extern.slf4j.Slf4j; +import org.apache.dolphinscheduler.plugin.trigger.api.AbstractTrigger; +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerCallBack; +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerException; +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerExecutionContext; +import org.apache.dolphinscheduler.plugin.trigger.api.parameters.AbstractParameters; + +@Slf4j +public class SimpleTrigger extends AbstractTrigger { + + private SimpleTriggerPatameters simpleTriggerPatameters; + + private TriggerExecutionContext triggerExecutionContext; + + public SimpleTrigger(TriggerExecutionContext triggerExecutionContext) { + super(triggerExecutionContext); + + this.triggerExecutionContext = triggerExecutionContext; + } + + @Override + public void init() { + } + + @SuppressWarnings("unchecked") + @Override + public void handle(TriggerCallBack triggerCallBack) throws TriggerException { + try { + + } catch (Exception e) { + log.error("shell task error", e); + throw new TriggerException("Execute shell task error", e); + } + } + + @Override + public void cancel() throws TriggerException { + // cancel process + try { + } catch (Exception e) { + throw new TriggerException("cancel application error", e); + } + } + + public AbstractParameters getParameters() { + return simpleTriggerPatameters; + } + +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerChannel.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerChannel.java new file mode 100644 index 0000000000..eb0a9bd9c5 --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerChannel.java @@ -0,0 +1,20 @@ +package org.apache.dolphinscheduler.plugin.trigger.simple; + +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerChannel; +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerExecutionContext; +import org.apache.dolphinscheduler.plugin.trigger.api.parameters.AbstractParameters; +import org.apache.dolphinscheduler.plugin.trigger.api.parameters.ParametersNode; + +public class SimpleTriggerChannel implements TriggerChannel { + + @Override + public void cancelApplication(boolean status) { + + } + + @Override + public SimpleTrigger createTrigger(TriggerExecutionContext taskRequest) { + return new SimpleTrigger(taskRequest); + } +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerChannelFactory.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerChannelFactory.java new file mode 100644 index 0000000000..2a2fcb317f --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerChannelFactory.java @@ -0,0 +1,48 @@ +package org.apache.dolphinscheduler.plugin.trigger.simple; + +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerChannel; +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerChannelFactory; +import org.apache.dolphinscheduler.spi.params.base.ParamsOptions; +import org.apache.dolphinscheduler.spi.params.base.PluginParams; +import org.apache.dolphinscheduler.spi.params.base.Validate; +import org.apache.dolphinscheduler.spi.params.input.InputParam; +import org.apache.dolphinscheduler.spi.params.radio.RadioParam; + +import java.util.ArrayList; +import java.util.List; + +import com.google.auto.service.AutoService; + +@AutoService(TriggerChannelFactory.class) +public class SimpleTriggerChannelFactory implements TriggerChannelFactory { + + @Override + public TriggerChannel create() { + return new SimpleTriggerChannel(); + } + + @Override + public String getName() { + return "SIMPLE"; + } + + @Override + public List getParams() { + List paramsList = new ArrayList<>(); + + InputParam nodeName = InputParam.newBuilder("name", "$t('Node name')") + .addValidate(Validate.newBuilder() + .setRequired(true) + .build()) + .build(); + + RadioParam runFlag = RadioParam.newBuilder("runFlag", "RUN_FLAG") + .addParamsOptions(new ParamsOptions("NORMAL", "NORMAL", false)) + .addParamsOptions(new ParamsOptions("FORBIDDEN", "FORBIDDEN", false)) + .build(); + + paramsList.add(nodeName); + paramsList.add(runFlag); + return paramsList; + } +} diff --git a/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerPatameters.java b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerPatameters.java new file mode 100644 index 0000000000..9cfd0de87b --- /dev/null +++ b/dolphinscheduler-trigger-plugin/dolphinscheduler-trigger-simple/src/main/java/org/apache/dolphinscheduler/plugin/trigger/simple/SimpleTriggerPatameters.java @@ -0,0 +1,11 @@ +package org.apache.dolphinscheduler.plugin.trigger.simple; + +import lombok.Getter; +import lombok.Setter; +import org.apache.dolphinscheduler.plugin.trigger.api.parameters.AbstractParameters; + +@Getter +@Setter +public class SimpleTriggerPatameters extends AbstractParameters { + +} \ No newline at end of file diff --git a/dolphinscheduler-trigger-plugin/pom.xml b/dolphinscheduler-trigger-plugin/pom.xml new file mode 100644 index 0000000000..f6d0a9514e --- /dev/null +++ b/dolphinscheduler-trigger-plugin/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + org.apache.dolphinscheduler + dolphinscheduler + dev-SNAPSHOT + + + dolphinscheduler-trigger-plugin + pom + + + dolphinscheduler-trigger-all + dolphinscheduler-trigger-api + dolphinscheduler-trigger-simple + + + + + + org.apache.dolphinscheduler + dolphinscheduler-bom + ${project.version} + pom + import + + + + \ No newline at end of file diff --git a/dolphinscheduler-ui/src/layouts/content/components/sidebar/index.tsx b/dolphinscheduler-ui/src/layouts/content/components/sidebar/index.tsx index 782b966609..d9300d94d3 100644 --- a/dolphinscheduler-ui/src/layouts/content/components/sidebar/index.tsx +++ b/dolphinscheduler-ui/src/layouts/content/components/sidebar/index.tsx @@ -36,6 +36,7 @@ const Sidebar = defineComponent({ const defaultExpandedKeys = [ 'workflow', 'task', + 'trigger', 'udf-manage', 'service-manage', 'statistical-manage', diff --git a/dolphinscheduler-ui/src/layouts/content/use-dataList.ts b/dolphinscheduler-ui/src/layouts/content/use-dataList.ts index facf521db8..3156228eb0 100644 --- a/dolphinscheduler-ui/src/layouts/content/use-dataList.ts +++ b/dolphinscheduler-ui/src/layouts/content/use-dataList.ts @@ -167,6 +167,23 @@ export function useDataList() { payload: { projectName: projectName } } ] + }, + { + label: t('menu.trigger'), + key: 'trigger', + icon: renderIcon(SettingOutlined), + children: [ + { + label: t('menu.trigger_definition'), + key: `/projects/${projectCode}/trigger/definitions`, + payload: { projectName: projectName } + }, + { + label: t('menu.trigger_instance'), + key: `/projects/${projectCode}/trigger/instances`, + payload: { projectName: projectName } + } + ] } ] }, diff --git a/dolphinscheduler-ui/src/locales/en_US/menu.ts b/dolphinscheduler-ui/src/locales/en_US/menu.ts index d71f382ec0..c7cafdd362 100644 --- a/dolphinscheduler-ui/src/locales/en_US/menu.ts +++ b/dolphinscheduler-ui/src/locales/en_US/menu.ts @@ -33,6 +33,9 @@ export default { task: 'Task', task_instance: 'Task Instance', task_definition: 'Task Definition', + trigger: 'Trigger', + trigger_instance: 'Trigger Instance', + trigger_definition: 'Trigger Definition', file_manage: 'File Manage', udf_manage: 'UDF Manage', resource_manage: 'Resource Manage', diff --git a/dolphinscheduler-ui/src/locales/en_US/project.ts b/dolphinscheduler-ui/src/locales/en_US/project.ts index 68eb7b3102..dbe3c7b8c1 100644 --- a/dolphinscheduler-ui/src/locales/en_US/project.ts +++ b/dolphinscheduler-ui/src/locales/en_US/project.ts @@ -76,6 +76,7 @@ export default { modify_user: 'Modify User', operation: 'Operation', edit: 'Edit', + trigger: '触发', confirm: 'Confirm', cancel: 'Cancel', start: 'Start', @@ -323,6 +324,12 @@ export default { delete_validate_dependent_tasks_desc: 'The downstream dependent tasks exists. You can not delete the task.' }, + trigger: { + trigger: 'Trigger', + create_trigger: 'Create Trigger', + trigger_definition: 'Trigger Definition', + trigger_name: 'Trigger Name' + }, dag: { create: 'Create Workflow', search: 'Search', diff --git a/dolphinscheduler-ui/src/locales/zh_CN/menu.ts b/dolphinscheduler-ui/src/locales/zh_CN/menu.ts index 257541f3ad..1fe104911c 100644 --- a/dolphinscheduler-ui/src/locales/zh_CN/menu.ts +++ b/dolphinscheduler-ui/src/locales/zh_CN/menu.ts @@ -34,6 +34,9 @@ export default { task: '任务', task_instance: '任务实例', task_definition: '任务定义', + trigger: '触发器', + trigger_instance: '触发器实例', + trigger_definition: '触发器定义', file_manage: '文件管理', udf_manage: 'UDF管理', resource_manage: '资源管理', diff --git a/dolphinscheduler-ui/src/locales/zh_CN/project.ts b/dolphinscheduler-ui/src/locales/zh_CN/project.ts index e1bfd6f672..c7401a231f 100644 --- a/dolphinscheduler-ui/src/locales/zh_CN/project.ts +++ b/dolphinscheduler-ui/src/locales/zh_CN/project.ts @@ -76,6 +76,7 @@ export default { modify_user: '修改用户', operation: '操作', edit: '编辑', + trigger: '触发', confirm: '确定', cancel: '取消', start: '运行', @@ -319,6 +320,12 @@ export default { remove_task_cache: '清除缓存', delete_validate_dependent_tasks_desc: '下游存在依赖,你不能删除该任务定义' }, + trigger: { + trigger: '触发器', + create_trigger: '创建触发器', + trigger_definition: '触发器定义', + trigger_name: '触发器名称' + }, dag: { create: '创建工作流', search: '搜索', diff --git a/dolphinscheduler-ui/src/router/modules/projects.ts b/dolphinscheduler-ui/src/router/modules/projects.ts index 8412f5904f..0af7ed465f 100644 --- a/dolphinscheduler-ui/src/router/modules/projects.ts +++ b/dolphinscheduler-ui/src/router/modules/projects.ts @@ -201,6 +201,28 @@ export default { auth: [] } }, + { + path: '/projects/:projectCode/trigger/definitions', + name: 'trigger-definition', + component: components['projects-trigger-definition'], + meta: { + title: '触发器定义', + activeMenu: 'projects', + showSide: true, + auth: [] + } + }, + { + path: '/projects/:projectCode/trigger/instances', + name: 'trigger-instance', + component: components['projects-trigger-instance'], + meta: { + title: '触发器实例', + activeMenu: 'projects', + showSide: true, + auth: [] + } + }, { path: '/projects/:projectCode/workflow-definition/tree/:definitionCode', name: 'workflow-definition-tree', diff --git a/dolphinscheduler-ui/src/service/modules/trigger-definition/index.ts b/dolphinscheduler-ui/src/service/modules/trigger-definition/index.ts new file mode 100644 index 0000000000..8774154d32 --- /dev/null +++ b/dolphinscheduler-ui/src/service/modules/trigger-definition/index.ts @@ -0,0 +1,172 @@ +/* + * 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 { axios } from '@/service/service' +import { + PageReq, + ProjectCodeReq, + TaskDefinitionListReq, + TaskDefinitionJsonReq, + CodeReq, + TaskDefinitionJsonObjReq, + ReleaseStateReq, + VersionReq, + ISingleSaveReq, + TaskDefinitionReq +} from './types' + +export function queryTriggerDefinitionListPaging( + params: TaskDefinitionListReq, + projectCode: ProjectCodeReq +): any { + return axios({ + url: `/projects/${projectCode.projectCode}/task-definition`, + method: 'get', + params + }) +} + +export function save( + data: TaskDefinitionJsonReq, + projectCode: ProjectCodeReq +): any { + return axios({ + url: `/projects/${projectCode}/task-definition`, + method: 'post', + data + }) +} + +export function genTaskCodeList(num: number, projectCode: number) { + return axios.request({ + url: `/projects/${projectCode}/task-definition/gen-task-codes`, + method: 'get', + params: { + genNum: num + } + }) +} + +export function queryTriggerDefinitionByCode( + code: number, + projectCode: number +): any { + return axios({ + url: `/projects/${projectCode}/task-definition/${code}`, + method: 'get' + }) +} + +export function updateTrigger( + projectCode: number, + code: number, + data: TaskDefinitionJsonObjReq +): any { + return axios({ + url: `/projects/${projectCode}/task-definition/${code}`, + method: 'put', + data + }) +} + +export function deleteTriggerDefinition( + code: CodeReq, + projectCode: ProjectCodeReq +): any { + return axios({ + url: `/projects/${projectCode.projectCode}/task-definition/${code.code}`, + method: 'delete' + }) +} + +export function releaseTaskDefinition( + data: ReleaseStateReq, + code: number, + projectCode: number +): any { + return axios({ + url: `/projects/${projectCode}/task-definition/${code}/release`, + method: 'post', + data + }) +} + +export function queryTaskVersions( + params: PageReq, + code: CodeReq, + projectCode: ProjectCodeReq +): any { + return axios({ + url: `/projects/${projectCode.projectCode}/task-definition/${code.code}/versions`, + method: 'get', + params + }) +} + +export function switchVersion( + version: VersionReq, + code: CodeReq, + projectCode: ProjectCodeReq +): any { + return axios({ + url: `/projects/${projectCode.projectCode}/task-definition/${code.code}/versions/${version.version}`, + method: 'get' + }) +} + +export function deleteVersion( + version: VersionReq, + code: CodeReq, + projectCode: ProjectCodeReq +): any { + return axios({ + url: `/projects/${projectCode.projectCode}/task-definition/${code.code}/versions/${version.version}`, + method: 'delete' + }) +} + +export function saveSingle(projectCode: number, data: ISingleSaveReq) { + return axios({ + url: `/projects/${projectCode}/task-definition/save-single`, + method: 'post', + data + }) +} + +export function updateWithUpstream( + projectCode: number, + code: number, + data: ISingleSaveReq +) { + return axios({ + url: `/projects/${projectCode}/task-definition/${code}/with-upstream`, + method: 'put', + data + }) +} + +export function startTaskDefinition( + projectCode: number, + code: number, + data: TaskDefinitionReq +) { + return axios({ + url: `projects/${projectCode}/executors/task-instance/${code}/start`, + method: 'post', + data + }) +} diff --git a/dolphinscheduler-ui/src/service/modules/trigger-definition/types.ts b/dolphinscheduler-ui/src/service/modules/trigger-definition/types.ts new file mode 100644 index 0000000000..3f90b42762 --- /dev/null +++ b/dolphinscheduler-ui/src/service/modules/trigger-definition/types.ts @@ -0,0 +1,159 @@ +/* + * 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. + */ + +interface PageReq { + pageNo: number + pageSize: number +} + +interface ListReq extends PageReq { + searchVal?: string +} + +interface ProjectCodeReq { + projectCode: number +} + +interface TaskDefinitionListReq extends ListReq { + taskType?: string + userId?: number + taskExecuteType?: 'BATCH' | 'STREAM' +} + +interface TaskDefinitionJsonReq { + taskDefinitionJson: string +} + +interface CodeReq { + code: any +} + +interface TaskDefinitionJsonObjReq { + taskDefinitionJsonObj: string + taskExecuteType?: string +} + +interface ReleaseStateReq { + releaseState: 'OFFLINE' | 'ONLINE' +} + +interface VersionReq { + version: number +} + +interface TaskDefinitionItem { + taskName: string + taskCode: any + taskVersion: number + taskType: string + taskCreateTime: string + taskUpdateTime: string + processDefinitionCode: any + processDefinitionVersion: number + processDefinitionName: string + processReleaseState: string + upstreamTaskMap: any + upstreamTaskCode: number + upstreamTaskName: string +} + +interface TaskDefinitionRes { + totalList: TaskDefinitionItem[] + total: number + totalPage: number + pageSize: number + currentPage: number + start: number +} + +interface TaskDefinitionVersionItem { + id: number + code: number + name: string + version: number + description: string + projectCode: number + userId: number + taskType: string + taskParams: any + taskParamList: any[] + taskParamMap: any + flag: string + taskPriority: string + userName?: any + projectName?: any + workerGroup: string + environmentCode: number + failRetryTimes: number + failRetryInterval: number + timeoutFlag: string + timeoutNotifyStrategy?: any + timeout: number + delayTime: number + resourceIds: string + createTime: string + updateTime: string + modifyBy?: any + taskGroupId: number + taskGroupPriority: number + operator: number + operateTime: string + dependence: string +} + +interface TaskDefinitionVersionRes { + totalList: TaskDefinitionVersionItem[] + total: number + totalPage: number + pageSize: number + currentPage: number + start: number +} + +interface ISingleSaveReq { + processDefinitionCode?: string + upstreamCodes: string + taskDefinitionJsonObj: string +} + +interface TaskDefinitionReq { + version: number + warningType: string + warningGroupId: number + workerGroup?: string + environmentCode?: number + startParams?: string + dryRun?: number +} + +export { + PageReq, + ListReq, + ProjectCodeReq, + TaskDefinitionListReq, + TaskDefinitionJsonReq, + CodeReq, + TaskDefinitionJsonObjReq, + ReleaseStateReq, + VersionReq, + TaskDefinitionItem, + TaskDefinitionRes, + TaskDefinitionVersionItem, + TaskDefinitionVersionRes, + ISingleSaveReq, + TaskDefinitionReq +} diff --git a/dolphinscheduler-ui/src/store/project/types.ts b/dolphinscheduler-ui/src/store/project/types.ts index e486bd9c5c..dbb9c1d2ee 100644 --- a/dolphinscheduler-ui/src/store/project/types.ts +++ b/dolphinscheduler-ui/src/store/project/types.ts @@ -60,6 +60,8 @@ type TaskType = | 'DATA_FACTORY' | 'REMOTESHELL' +type TriggerType = 'SIMPLE' | 'TIMER' | 'KAFKA' + type ProgramType = 'JAVA' | 'SCALA' | 'PYTHON' type DependentResultType = { @@ -113,6 +115,7 @@ export { BDependentResultType, IMainJar, TaskType, + TriggerType, ITaskType, ITaskTypeItem, TaskTypeState, diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/detail-modal.tsx b/dolphinscheduler-ui/src/views/projects/trigger/components/node/detail-modal.tsx new file mode 100644 index 0000000000..b2659b3095 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/detail-modal.tsx @@ -0,0 +1,270 @@ +/* + * 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, + watch, + nextTick, + provide, + computed, + h, + Ref, + onMounted +} from 'vue' +import { useI18n } from 'vue-i18n' +import Modal from '@/components/modal' +import Detail from './detail' +import { formatModel } from './format-data' +import { + HistoryOutlined, + ProfileOutlined, + QuestionCircleTwotone, + BranchesOutlined +} from '@vicons/antd' +import { NIcon } from 'naive-ui' +import { Router, useRouter } from 'vue-router' +import { querySubProcessInstanceByTaskCode } from '@/service/modules/process-instances' +import { useTaskNodeStore } from '@/store/project/task-node' +import type { + ITriggerData, + ITriggerType, + EditWorkflowDefinition, + IWorkflowTaskInstance, + WorkflowInstance +} from './types' +import { queryProjectPreferenceByProjectCode } from '@/service/modules/projects-preference' +import { INodeData } from './types' + +const props = { + show: { + type: Boolean as PropType, + default: false + }, + data: { + type: Object as PropType, + default: { code: 0, taskType: 'SHELL', name: '' } + }, + projectCode: { + type: Number as PropType, + required: true, + default: 0 + }, + readonly: { + type: Boolean as PropType, + default: false + }, + from: { + type: Number as PropType, + default: 0 + }, + definition: { + type: Object as PropType> + }, + processInstance: { + type: Object as PropType + }, + taskInstance: { + type: Object as PropType + }, + saving: { + type: Boolean, + default: false + } +} + +const NodeDetailModal = defineComponent({ + name: 'NodeDetailModal', + props, + emits: ['cancel', 'submit', 'viewLog'], + setup(props, { emit }) { + const { t, locale } = useI18n() + const router: Router = useRouter() + const taskStore = useTaskNodeStore() + + const renderIcon = (icon: any) => { + return () => h(NIcon, null, { default: () => h(icon) }) + } + const detailRef = ref() + + const onConfirm = async () => { + await detailRef.value.value.validate() + emit('submit', { data: detailRef.value.value.getValues() }) + } + const onCancel = () => { + emit('cancel') + } + + const headerLinks = ref([] as any) + const projectPreferences = ref({} as any) + + const handleViewLog = () => { + if (props.taskInstance) { + emit('viewLog', props.taskInstance.id, props.taskInstance.taskType) + } + } + + const initProjectPreferences = (projectCode: number) => { + queryProjectPreferenceByProjectCode(projectCode).then((result: any) => { + if (result?.preferences && result.state === 1) { + projectPreferences.value = JSON.parse(result.preferences) + } + }) + } + + const restructureNodeData = (data: INodeData) => { + if (!data?.id) { + for (const item in projectPreferences.value) { + if (projectPreferences.value[item] !== null && item in data) { + Object.assign(data, { item: projectPreferences.value[item] }) + } + } + } + } + + const initHeaderLinks = (processInstance: any, taskType?: ITriggerType) => { + headerLinks.value = [ + { + text: t('project.node.instructions'), + show: !!(taskType), + action: () => { + let linkedTaskType = taskType?.toLowerCase().replace('_', '-') + if (taskType === 'PROCEDURE') linkedTaskType = 'stored-procedure' + const helpUrl = + 'https://dolphinscheduler.apache.org/' + + locale.value.toLowerCase().replace('_', '-') + + '/docs/latest/user_doc/guide/task/' + + linkedTaskType + + '.html' + window.open(helpUrl) + }, + icon: renderIcon(QuestionCircleTwotone) + }, + { + text: t('project.node.view_history'), + show: !!props.taskInstance, + action: () => { + router.push({ + name: 'task-instance', + query: { + taskCode: props.data.code + } + }) + }, + icon: renderIcon(HistoryOutlined) + }, + { + text: t('project.node.view_log'), + show: !!props.taskInstance, + action: () => { + handleViewLog() + }, + icon: renderIcon(ProfileOutlined) + }, + { + text: t('project.node.enter_this_child_node'), + show: + props.data.taskType === 'SUB_PROCESS' || + props.data.taskType === 'DYNAMIC', + disabled: + !props.data.id || + (router.currentRoute.value.name === 'workflow-instance-detail' && + !props.taskInstance), + action: () => { + if (router.currentRoute.value.name === 'workflow-instance-detail') { + querySubProcessInstanceByTaskCode( + { taskId: props.taskInstance?.id }, + { projectCode: props.projectCode } + ).then((res: any) => { + router.push({ + name: 'workflow-instance-detail', + params: { id: res.subProcessInstanceId }, + query: { code: props.data.taskParams?.processDefinitionCode } + }) + }) + } else { + router.push({ + name: 'workflow-definition-detail', + params: { code: props.data.taskParams?.processDefinitionCode } + }) + } + }, + icon: renderIcon(BranchesOutlined) + } + ] + } + + const onTaskTypeChange = (taskType: ITriggerType) => { + // eslint-disable-next-line vue/no-mutating-props + props.data.taskType = taskType + initHeaderLinks(props.processInstance, props.data.taskType) + } + + provide( + 'data', + computed(() => ({ + projectCode: props.projectCode, + data: props.data, + from: props.from, + readonly: props.readonly, + definition: props.definition + })) + ) + + onMounted(() => { + initProjectPreferences(props.projectCode) + }) + + watch( + () => [props.show, props.data], + async () => { + if (!props.show) return + initHeaderLinks(props.processInstance, props.data.taskType) + taskStore.init() + const nodeData = formatModel(props.data) + await nextTick() + restructureNodeData(nodeData) + detailRef.value.value.setValues(nodeData) + } + ) + + return () => ( + + + + ) + } +}) + +export default NodeDetailModal diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/detail.tsx b/dolphinscheduler-ui/src/views/projects/trigger/components/node/detail.tsx new file mode 100644 index 0000000000..ab8282e88c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/detail.tsx @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineComponent, ref, watch, inject, Ref, unref } from 'vue' +import Form from '@/components/form' +import { useTask } from './use-task' +import { useTaskNodeStore } from '@/store/project/task-node' +import type { ITaskData, EditWorkflowDefinition } from './types' + +interface IDetailPanel { + projectCode: number + data: ITaskData + readonly: false + from: number + detailRef?: Ref + definition?: EditWorkflowDefinition +} + +const NodeDetail = defineComponent({ + name: 'NodeDetail', + emits: ['taskTypeChange'], + setup(props, { expose, emit }) { + const taskStore = useTaskNodeStore() + + const formRef = ref() + const detailData: IDetailPanel = inject('data') || { + projectCode: 0, + data: { + taskType: 'SHELL' + }, + readonly: false, + from: 0 + } + const { data, projectCode, from, readonly, definition } = unref(detailData) + + const { elementsRef, rulesRef, model } = useTask({ + data, + projectCode, + from, + readonly, + definition + }) + watch( + () => model.taskType, + async (taskType) => { + taskStore.updateName(model.name || '') + emit('taskTypeChange', taskType) + } + ) + + expose(formRef) + + return () => ( +
+ ) + } +}) + +export default NodeDetail diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/index.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/index.ts new file mode 100644 index 0000000000..57d168867e --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/index.ts @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { useName } from './use-name' +export { useRunFlag } from './use-run-flag' +export { useCache } from './use-cache' +export { useDescription } from './use-description' +export { useTaskPriority } from './use-task-priority' +export { useWorkerGroup } from './use-worker-group' +export { useEnvironmentName } from './use-environment-name' +export { useTaskGroup } from './use-task-group' +export { useFailed } from './use-failed' +export { useResourceLimit } from './use-resource-limit' +export { useDelayTime } from './use-delay-time' +export { useTimeoutAlarm } from './use-timeout-alarm' +export { usePreTasks } from './use-pre-tasks' +export { useTaskType } from './use-task-type' +export { useProcessName } from './use-process-name' +export { useChildNode } from './use-child-node' +export { useTargetTaskName } from './use-target-task-name' +export { useDatasource } from './use-datasource' +export { useSqlType } from './use-sql-type' +export { useProcedure } from './use-procedure' +export { useCustomParams } from './use-custom-params' +export { useCustomLabels } from './use-custom-labels' +export { useNodeSelectors } from './use-node-selectors' +export { useSourceType } from './use-sqoop-source-type' +export { useTargetType } from './use-sqoop-target-type' +export { useRelationCustomParams } from './use-relation-custom-params' +export { useDependentTimeout } from './use-dependent-timeout' +export { useRules } from './use-rules' +export { useDeployMode } from './use-deploy-mode' +export { useDriverCores } from './use-driver-cores' +export { useDriverMemory } from './use-driver-memory' +export { useExecutorNumber } from './use-executor-number' +export { useExecutorMemory } from './use-executor-memory' +export { useExecutorCores } from './use-executor-cores' +export { useMainJar } from './use-main-jar' +export { useResources } from './use-resources' +export { useTaskDefinition } from './use-task-definition' +export { useJavaTaskMainJar } from './use-java-task-main-jar' + +export { useShell } from './use-shell' +export { useSpark } from './use-spark' +export { useMr } from './use-mr' +export { useFlink } from './use-flink' +export { useHttp } from './use-http' +export { useSql } from './use-sql' +export { useSqoop } from './use-sqoop' +export { useSeaTunnel } from './use-sea-tunnel' +export { useSwitch } from './use-switch' +export { useDataX } from './use-datax' +export { useConditions } from './use-conditions' +export { useDependent } from './use-dependent' +export { useEmr } from './use-emr' +export { useZeppelin } from './use-zeppelin' +export { useNamespace } from './use-namespace' +export { useK8s } from './use-k8s' +export { useJupyter } from './use-jupyter' +export { useMlflow } from './use-mlflow' +export { useMlflowProjects } from './use-mlflow-projects' +export { useMlflowModels } from './use-mlflow-models' +export { useOpenmldb } from './use-openmldb' +export { useDvc } from './use-dvc' +export { useDinky } from './use-dinky' +export { useSagemaker } from './use-sagemaker' +export { useJava } from './use-java' +export { useChunjun } from './use-chunjun' +export { useChunjunDeployMode } from './use-chunjun-deploy-mode' +export { usePytorch } from './use-pytorch' +export { useHiveCli } from './use-hive-cli' +export { useDms } from './use-dms' +export { useDatasync } from './use-datasync' +export { useKubeflow } from './use-kubeflow' +export { useLinkis } from './use-linkis' +export { useDataFactory } from './use-data-factory' +export { useRemoteShell } from './use-remote-shell' +export { useDynamic } from './use-dynamic' +export { useYarnQueue } from './use-queue' diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-cache.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-cache.ts new file mode 100644 index 0000000000..fd7e90431c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-cache.ts @@ -0,0 +1,29 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useCache(): IJsonItem { + const { t } = useI18n() + return { + type: 'switch', + field: 'isCache', + name: t('project.node.is_cache'), + span: 12 + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-child-node.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-child-node.ts new file mode 100644 index 0000000000..98b232f271 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-child-node.ts @@ -0,0 +1,90 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { + querySimpleList, + queryProcessDefinitionByCode +} from '@/service/modules/process-definition' +import type { IJsonItem } from '../types' + +export function useChildNode({ + model, + projectCode, + from, + processName, + code +}: { + model: { [field: string]: any } + projectCode: number + from?: number + processName?: number + code?: number +}): IJsonItem { + const { t } = useI18n() + + const options = ref([] as { label: string; value: string }[]) + const loading = ref(false) + + const getProcessList = async () => { + if (loading.value) return + loading.value = true + const res = await querySimpleList(projectCode) + options.value = res + .filter((option: { name: string; code: number }) => option.code !== code) + .map((option: { name: string; code: number }) => ({ + label: option.name, + value: option.code + })) + loading.value = false + } + const getProcessListByCode = async (processCode: number) => { + if (!processCode) return + const res = await queryProcessDefinitionByCode(processCode, projectCode) + model.definition = res + } + + onMounted(() => { + if (from === 1 && processName) { + getProcessListByCode(processName) + } + getProcessList() + }) + + return { + type: 'select', + field: 'processDefinitionCode', + span: 24, + name: t('project.node.child_node'), + props: { + loading: loading, + filterable: true + }, + options: options, + class: 'select-child-node', + validate: { + trigger: ['input', 'blur'], + required: true, + validator(unuse: any, value: number) { + if (!value) { + return Error(t('project.node.child_node_tips')) + } + } + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-chunjun-deploy-mode.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-chunjun-deploy-mode.ts new file mode 100644 index 0000000000..9cd5083a9c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-chunjun-deploy-mode.ts @@ -0,0 +1,49 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useChunjunDeployMode(span = 24): IJsonItem { + const { t } = useI18n() + + return { + type: 'radio', + field: 'deployMode', + name: t('project.node.deploy_mode'), + options: DEPLOY_MODES, + span + } +} + +export const DEPLOY_MODES = [ + { + label: 'local', + value: 'local' + }, + { + label: 'standlone', + value: 'standlone' + }, + { + label: 'yarn-session', + value: 'yarn-session' + }, + { + label: 'yarn-per-job', + value: 'yarn-per-job' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-chunjun.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-chunjun.ts new file mode 100644 index 0000000000..617a8e5145 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-chunjun.ts @@ -0,0 +1,103 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' +import { useChunjunDeployMode } from './' + +export function useChunjun(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const jsonEditorSpan = ref(0) + const customParameterSpan = ref(0) + + const initConstants = () => { + jsonEditorSpan.value = 24 + customParameterSpan.value = 24 + } + + onMounted(() => { + initConstants() + }) + + return [ + { + type: 'editor', + field: 'json', + name: t('project.node.chunjun_json_template'), + span: jsonEditorSpan, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.sql_empty_tips') + } + }, + { + type: 'custom-parameters', + field: 'localParams', + name: t('project.node.custom_parameters'), + span: customParameterSpan, + children: [ + { + type: 'input', + field: 'prop', + span: 10, + props: { + placeholder: t('project.node.prop_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.prop_tips')) + } + + const sameItems = model.localParams.filter( + (item: { prop: string }) => item.prop === value + ) + + if (sameItems.length > 1) { + return new Error(t('project.node.prop_repeat')) + } + } + } + }, + { + type: 'input', + field: 'value', + span: 10, + props: { + placeholder: t('project.node.value_tips'), + maxLength: 256 + } + } + ] + }, + useChunjunDeployMode(24), + { + type: 'input', + field: 'others', + name: t('project.node.option_parameters'), + props: { + type: 'textarea', + placeholder: t('project.node.option_parameters_tips') + } + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-conditions.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-conditions.ts new file mode 100644 index 0000000000..53df0bba75 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-conditions.ts @@ -0,0 +1,127 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { useTaskNodeStore } from '@/store/project/task-node' +import { useRelationCustomParams, useTimeoutAlarm } from '.' +import type { IJsonItem } from '../types' + +export function useConditions(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const taskStore = useTaskNodeStore() + + const preTaskOptions = taskStore.preTaskOptions.filter((option) => + taskStore.preTasks.includes(Number(option.value)) + ) + const stateOptions = [ + { label: t('project.node.success'), value: 'success' }, + { label: t('project.node.failed'), value: 'failed' } + ] + + return [ + { + type: 'select', + field: 'successNode', + name: t('project.node.state'), + span: 12, + props: { + disabled: true + }, + options: stateOptions + }, + { + type: 'select', + field: 'successBranch', + name: t('project.node.branch_flow'), + span: 12, + props: { + clearable: true + }, + validate: { + trigger: ['input', 'blur'], + validator: (unuse, value) => { + if (value && value === model.failedBranch) { + return new Error(t('project.node.branch_tips')) + } + } + }, + options: taskStore.getPostTaskOptions + }, + { + type: 'select', + field: 'failedNode', + name: t('project.node.state'), + span: 12, + props: { + disabled: true + }, + options: stateOptions + }, + { + type: 'select', + field: 'failedBranch', + name: t('project.node.branch_flow'), + span: 12, + props: { + clearable: true + }, + validate: { + trigger: ['input', 'blur'], + validator: (unuse, value) => { + if (value && value === model.successBranch) { + return new Error(t('project.node.branch_tips')) + } + } + }, + options: taskStore.getPostTaskOptions + }, + ...useTimeoutAlarm(model), + ...useRelationCustomParams({ + model, + children: { + type: 'custom-parameters', + field: 'dependItemList', + span: 18, + children: [ + { + type: 'select', + field: 'depTaskCode', + span: 10, + options: preTaskOptions + }, + { + type: 'select', + field: 'status', + span: 10, + options: [ + { + value: 'SUCCESS', + label: t('project.node.success') + }, + { + value: 'FAILURE', + label: t('project.node.failed') + } + ] + } + ] + }, + childrenField: 'dependItemList', + name: 'add_pre_task_check_condition' + }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-custom-labels.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-custom-labels.ts new file mode 100644 index 0000000000..915fcceab9 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-custom-labels.ts @@ -0,0 +1,82 @@ +/* + * 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 } from 'vue' +import { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useCustomLabels({ + model, + field, + name = 'custom_labels', + span = 24 +}: { + model: { [field: string]: any } + field: string + name?: string + span?: Ref | number +}): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'custom-parameters', + field: field, + name: t(`project.node.${name}`), + class: 'btn-custom-parameters', + span, + children: [ + { + type: 'input', + field: 'label', + span: 8, + class: 'customized-label-name', + props: { + placeholder: t('project.node.label_name_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.label_name_tips')) + } + + const sameItems = model[field].filter( + (item: { label: string }) => item.label === value + ) + + if (sameItems.length > 1) { + return new Error(t('project.node.label_repeat')) + } + } + } + }, + { + type: 'input', + field: 'value', + span: 14, + class: 'customized-label-value', + props: { + placeholder: t('project.node.label_value_tips'), + maxLength: 256 + } + } + ] + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-custom-params.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-custom-params.ts new file mode 100644 index 0000000000..2052f524fe --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-custom-params.ts @@ -0,0 +1,162 @@ +/* + * 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 } from 'vue' +import { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useCustomParams({ + model, + field, + isSimple, + name = 'custom_parameters', + span = 24 +}: { + model: { [field: string]: any } + field: string + isSimple: boolean + name?: string + span?: Ref | number +}): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'custom-parameters', + field: field, + name: t(`project.node.${name}`), + class: 'btn-custom-parameters', + span, + children: [ + { + type: 'input', + field: 'prop', + span: 6, + class: 'input-param-key', + props: { + placeholder: t('project.node.prop_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.prop_tips')) + } + + const sameItems = model[field].filter( + (item: { prop: string }) => item.prop === value + ) + + if (sameItems.length > 1) { + return new Error(t('project.node.prop_repeat')) + } + } + } + }, + { + type: 'select', + field: 'direct', + span: 4, + options: DIRECT_LIST, + value: 'IN', + props: { + disabled: isSimple + } + }, + { + type: 'select', + field: 'type', + span: 6, + options: TYPE_LIST, + value: 'VARCHAR', + props: { + disabled: isSimple + } + }, + { + type: 'input', + field: 'value', + span: 6, + class: 'input-param-value', + props: { + placeholder: t('project.node.value_tips'), + maxLength: 256 + } + } + ] + } + ] +} + +export const TYPE_LIST = [ + { + value: 'VARCHAR', + label: 'VARCHAR' + }, + { + value: 'INTEGER', + label: 'INTEGER' + }, + { + value: 'LONG', + label: 'LONG' + }, + { + value: 'FLOAT', + label: 'FLOAT' + }, + { + value: 'DOUBLE', + label: 'DOUBLE' + }, + { + value: 'DATE', + label: 'DATE' + }, + { + value: 'TIME', + label: 'TIME' + }, + { + value: 'TIMESTAMP', + label: 'TIMESTAMP' + }, + { + value: 'BOOLEAN', + label: 'BOOLEAN' + }, + { + value: 'LIST', + label: 'LIST' + }, + { + value: 'FILE', + label: 'FILE' + } +] + +export const DIRECT_LIST = [ + { + value: 'IN', + label: 'IN' + }, + { + value: 'OUT', + label: 'OUT' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-data-factory.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-data-factory.ts new file mode 100644 index 0000000000..8dc6f5213c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-data-factory.ts @@ -0,0 +1,152 @@ +/* + * 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 { + queryDataFactoryFactories, + queryDataFactoryPipelines, + queryDataFactoryResourceGroups +} from '@/service/modules/azure' +import { onMounted, ref, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { useCustomParams } from '.' +import type { IJsonItem } from '../types' + +export function useDataFactory(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const factoryLoading = ref(false) + const resourceGroupLoading = ref(false) + const pipelineLoading = ref(false) + + const factoryOptions = ref([] as { label: string; value: number }[]) + const resourceGroupOptions = ref([] as { label: string; value: number }[]) + const pipelineOptions = ref([] as { label: string; value: number }[]) + + const getFactoryOptions = async () => { + if (factoryLoading.value) return + factoryLoading.value = true + const factories = await queryDataFactoryFactories() + factoryOptions.value = factories.map((factory: string) => ({ + label: factory, + value: factory + })) + factoryLoading.value = false + } + + const getResourceGroupName = async () => { + if (resourceGroupLoading.value) return + resourceGroupLoading.value = true + const groupNames = await queryDataFactoryResourceGroups() + resourceGroupOptions.value = groupNames.map((groupName: string) => ({ + label: groupName, + value: groupName + })) + resourceGroupLoading.value = false + } + + const getPipelineName = async ( + factoryName: string, + resourceGroupName: string + ) => { + if (pipelineLoading.value) return + pipelineLoading.value = true + const pipelineNames = await queryDataFactoryPipelines({ + factoryName, + resourceGroupName + }) + pipelineOptions.value = pipelineNames.map((pipelineName: string) => ({ + label: pipelineName, + value: pipelineName + })) + pipelineLoading.value = false + } + + const onChange = () => { + model['pipelineName'] = '' + if (model['factoryName'] && model['resourceGroupName']) { + getPipelineName(model['factoryName'], model['resourceGroupName']) + } + } + + watch( + () => model['pipelineName'], + () => { + if (model['pipelineName'] && pipelineOptions.value.length === 0) { + getPipelineName(model['factoryName'], model['resourceGroupName']) + } + } + ) + + onMounted(() => { + getFactoryOptions() + getResourceGroupName() + }) + + return [ + { + type: 'select', + field: 'factoryName', + span: 24, + name: t('project.node.factory_name'), + options: factoryOptions, + props: { + 'on-update:value': onChange, + loading: factoryLoading + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.factory_tips') + } + }, + { + type: 'select', + field: 'resourceGroupName', + span: 24, + name: t('project.node.resource_group_name'), + options: resourceGroupOptions, + props: { + 'on-update:value': onChange, + loading: resourceGroupLoading + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.resource_group_tips') + } + }, + { + type: 'select', + field: 'pipelineName', + span: 24, + name: t('project.node.pipeline_name'), + options: pipelineOptions, + props: { + loading: pipelineLoading + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.pipeline_tips') + } + }, + ...useCustomParams({ + model, + field: 'localParams', + isSimple: true + }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datasource.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datasource.ts new file mode 100644 index 0000000000..8b4ef0b897 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datasource.ts @@ -0,0 +1,238 @@ +/* + * 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, nextTick, Ref } from 'vue' +import { useI18n } from 'vue-i18n' +import { queryDataSourceList } from '@/service/modules/data-source' +import { indexOf, find } from 'lodash' +import type { IJsonItem } from '../types' +import type { TypeReq } from '@/service/modules/data-source/types' + +export function useDatasource( + model: { [field: string]: any }, + params: { + supportedDatasourceType?: string[] + typeField?: string + sourceField?: string + span?: Ref | number + testFlag?: Ref | number + } = {} +): IJsonItem[] { + const { t } = useI18n() + + const options = ref([] as { label: string; value: string }[]) + const datasourceOptions = ref([] as { label: string; value: number }[]) + + const datasourceTypes = [ + { + id: 0, + code: 'MYSQL', + disabled: false + }, + { + id: 1, + code: 'POSTGRESQL', + disabled: false + }, + { + id: 2, + code: 'HIVE', + disabled: false + }, + { + id: 3, + code: 'SPARK', + disabled: false + }, + { + id: 4, + code: 'CLICKHOUSE', + disabled: false + }, + { + id: 5, + code: 'ORACLE', + disabled: false + }, + { + id: 6, + code: 'SQLSERVER', + disabled: false + }, + { + id: 7, + code: 'DB2', + disabled: false + }, + { + id: 8, + code: 'PRESTO', + disabled: false + }, + { + id: 10, + code: 'REDSHIFT', + disabled: false + }, + { + id: 11, + code: 'ATHENA', + disabled: false + }, + { + id: 12, + code: 'TRINO', + disabled: false + }, + { + id: 13, + code: 'STARROCKS', + disabled: false + }, + { + id: 14, + code: 'AZURESQL', + disabled: false + }, + { + id: 15, + code: 'DAMENG', + disabled: false + }, + { + id: 16, + code: 'OCEANBASE', + disabled: false + }, + { + id: 17, + code: 'SSH', + disabled: true + }, + { + id: 18, + code: 'KYUUBI', + disabled: false + }, + { + id: 19, + code: 'DATABEND', + disabled: false + }, + { + id: 21, + code: 'VERTICA', + disabled: false + }, + { + id: 22, + code: 'HANA', + disabled: false + }, + { + id: 23, + code: 'DORIS', + disabled: false + }, + { + id: 24, + code: 'ZEPPELIN', + disabled: false + }, + { + id: 25, + code: 'SAGEMAKER', + disabled: false + } + ] + + const getDatasourceTypes = async () => { + options.value = datasourceTypes + .filter((item) => { + if (item.disabled) { + return false + } + if (params.supportedDatasourceType) { + return indexOf(params.supportedDatasourceType, item.code) !== -1 + } + return true + }) + .map((item) => ({ label: item.code, value: item.code })) + } + + const refreshOptions = async () => { + const parameters = { + type: model[params.typeField || 'type'], + testFlag: 0 + } as TypeReq + const res = await queryDataSourceList(parameters) + datasourceOptions.value = res.map((item: any) => ({ + label: item.name, + value: item.id + })) + const sourceField = params.sourceField || 'datasource' + if (!res.length && model[sourceField]) model[sourceField] = null + if (res.length && model[sourceField]) { + const item = find(res, { id: model[sourceField] }) + if (!item) { + model[sourceField] = null + } + } + } + + const onChange = () => { + refreshOptions() + } + + onMounted(async () => { + getDatasourceTypes() + await nextTick() + refreshOptions() + }) + return [ + { + type: 'select', + field: params.typeField || 'type', + span: params.span || 12, + name: t('project.node.datasource_type'), + props: { + 'on-update:value': onChange + }, + options: options, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'select', + field: params.sourceField || 'datasource', + span: params.span || 12, + name: t('project.node.datasource_instances'), + options: datasourceOptions, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(unuse: any, value) { + if (!value && value !== 0) { + return Error(t('project.node.datasource_instances')) + } + } + } + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datasync.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datasync.ts new file mode 100644 index 0000000000..23ccd24d95 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datasync.ts @@ -0,0 +1,85 @@ +/* + * 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 { IJsonItem } from '../types' +import { watch, ref } from 'vue' +import { useCustomParams } from '.' + +export function useDatasync(model: { [field: string]: any }): IJsonItem[] { + const jsonSpan = ref(0) + const destinationLocationArnSpan = ref(0) + const sourceLocationArnSpan = ref(0) + const nameSpan = ref(0) + const cloudWatchLogGroupArnSpan = ref(0) + + const resetSpan = () => { + jsonSpan.value = model.jsonFormat ? 24 : 0 + destinationLocationArnSpan.value = model.jsonFormat ? 0 : 24 + sourceLocationArnSpan.value = model.jsonFormat ? 0 : 24 + nameSpan.value = model.jsonFormat ? 0 : 24 + cloudWatchLogGroupArnSpan.value = model.jsonFormat ? 0 : 24 + } + + watch( + () => [model.jsonFormat], + () => { + resetSpan() + } + ) + + resetSpan() + + return [ + { + type: 'switch', + field: 'jsonFormat', + name: 'jsonFormat', + span: 12 + }, + { + type: 'editor', + field: 'json', + name: 'json', + span: jsonSpan + }, + { + type: 'input', + field: 'destinationLocationArn', + name: 'destinationLocationArn', + span: destinationLocationArnSpan + }, + { + type: 'input', + field: 'sourceLocationArn', + name: 'sourceLocationArn', + span: sourceLocationArnSpan + }, + { + type: 'input', + field: 'name', + name: 'name', + span: nameSpan + }, + { + type: 'input', + field: 'cloudWatchLogGroupArn', + name: 'cloudWatchLogGroupArn', + span: cloudWatchLogGroupArnSpan + }, + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datax.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datax.ts new file mode 100644 index 0000000000..24552bfb0b --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-datax.ts @@ -0,0 +1,256 @@ +/* + * 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, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { useCustomParams, useDatasource, useResources } from '.' +import type { IJsonItem } from '../types' + +export function useDataX(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const jobSpeedByteOptions: any[] = [ + { + label: `0(${t('project.node.unlimited')})`, + value: 0 + }, + { + label: '1KB', + value: 1024 + }, + { + label: '10KB', + value: 10240 + }, + { + label: '50KB', + value: 51200 + }, + { + label: '100KB', + value: 102400 + }, + { + label: '512KB', + value: 524288 + } + ] + const jobSpeedRecordOptions: any[] = [ + { + label: `0(${t('project.node.unlimited')})`, + value: 0 + }, + { + label: '500', + value: 500 + }, + { + label: '1000', + value: 1000 + }, + { + label: '1500', + value: 1500 + }, + { + label: '2000', + value: 2000 + }, + { + label: '2500', + value: 2500 + }, + { + label: '3000', + value: 3000 + } + ] + const memoryLimitOptions = [ + { + label: '1G', + value: 1 + }, + { + label: '2G', + value: 2 + }, + { + label: '3G', + value: 3 + }, + { + label: '4G', + value: 4 + } + ] + + const sqlEditorSpan = ref(24) + const jsonEditorSpan = ref(0) + const datasourceSpan = ref(12) + const destinationDatasourceSpan = ref(8) + const otherStatementSpan = ref(22) + const jobSpeedSpan = ref(12) + const useResourcesSpan = ref(0) + + const initConstants = () => { + if (model.customConfig) { + sqlEditorSpan.value = 0 + jsonEditorSpan.value = 24 + datasourceSpan.value = 0 + destinationDatasourceSpan.value = 0 + otherStatementSpan.value = 0 + jobSpeedSpan.value = 0 + useResourcesSpan.value = 24 + } else { + sqlEditorSpan.value = 24 + jsonEditorSpan.value = 0 + datasourceSpan.value = 12 + destinationDatasourceSpan.value = 8 + otherStatementSpan.value = 22 + jobSpeedSpan.value = 12 + useResourcesSpan.value = 0 + } + } + const supportedDatasourceType = [ + 'MYSQL', + 'POSTGRESQL', + 'ORACLE', + 'SQLSERVER', + 'CLICKHOUSE', + 'DATABEND', + 'HIVE', + 'PRESTO' + ] + onMounted(() => { + initConstants() + }) + watch( + () => model.customConfig, + () => { + initConstants() + } + ) + + return [ + { + type: 'switch', + field: 'customConfig', + name: t('project.node.datax_custom_template') + }, + ...useDatasource(model, { + typeField: 'dsType', + sourceField: 'dataSource', + span: datasourceSpan, + supportedDatasourceType + }), + { + type: 'editor', + field: 'sql', + name: t('project.node.sql_statement'), + span: sqlEditorSpan, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.sql_empty_tips') + } + }, + { + type: 'editor', + field: 'json', + name: t('project.node.datax_json_template'), + span: jsonEditorSpan, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.sql_empty_tips') + } + }, + useResources(useResourcesSpan), + ...useDatasource(model, { + typeField: 'dtType', + sourceField: 'dataTarget', + span: destinationDatasourceSpan, + supportedDatasourceType + }), + { + type: 'input', + field: 'targetTable', + name: t('project.node.datax_target_table'), + span: destinationDatasourceSpan, + props: { + placeholder: t('project.node.datax_target_table_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'multi-input', + field: 'preStatements', + name: t('project.node.datax_target_database_pre_sql'), + span: otherStatementSpan, + props: { + placeholder: t('project.node.datax_non_query_sql_tips'), + type: 'textarea', + autosize: { minRows: 1 } + } + }, + { + type: 'multi-input', + field: 'postStatements', + name: t('project.node.datax_target_database_post_sql'), + span: otherStatementSpan, + props: { + placeholder: t('project.node.datax_non_query_sql_tips'), + type: 'textarea', + autosize: { minRows: 1 } + } + }, + { + type: 'select', + field: 'jobSpeedByte', + name: t('project.node.datax_job_speed_byte'), + span: jobSpeedSpan, + options: jobSpeedByteOptions, + value: 0 + }, + { + type: 'select', + field: 'jobSpeedRecord', + name: t('project.node.datax_job_speed_record'), + span: jobSpeedSpan, + options: jobSpeedRecordOptions, + value: 1000 + }, + { + type: 'select', + field: 'xms', + name: t('project.node.datax_job_runtime_memory_xms'), + span: 12, + options: memoryLimitOptions, + value: 1 + }, + { + type: 'select', + field: 'xmx', + name: t('project.node.datax_job_runtime_memory_xmx'), + span: 12, + options: memoryLimitOptions, + value: 1 + }, + ...useCustomParams({ model, field: 'localParams', isSimple: true }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-delay-time.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-delay-time.ts new file mode 100644 index 0000000000..12a6702362 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-delay-time.ts @@ -0,0 +1,36 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useDelayTime(model: { [field: string]: any }): IJsonItem { + const { t } = useI18n() + return { + type: 'input-number', + field: 'delayTime', + name: t('project.node.delay_execution_time'), + span: 12, + props: { + min: 0 + }, + slots: { + suffix: () => t('project.node.minute') + }, + value: model.delayTime || 0 + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dependent-timeout.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dependent-timeout.ts new file mode 100644 index 0000000000..a84e50b43d --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dependent-timeout.ts @@ -0,0 +1,109 @@ +/* + * 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 { computed, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useDependentTimeout(model: { + [field: string]: any +}): IJsonItem[] { + const { t } = useI18n() + const timeCompleteSpan = computed(() => (model.timeoutShowFlag ? 24 : 0)) + const timeCompleteEnableSpan = computed(() => + model.timeoutFlag && model.timeoutShowFlag ? 12 : 0 + ) + + const strategyOptions = [ + { + label: t('project.node.timeout_alarm'), + value: 'WARN' + }, + { + label: t('project.node.timeout_failure'), + value: 'FAILED' + } + ] + + watch( + () => model.timeoutFlag, + (timeoutFlag) => { + model.timeoutShowFlag = timeoutFlag + } + ) + + return [ + { + type: 'switch', + field: 'timeoutShowFlag', + name: t('project.node.timeout_alarm') + }, + { + type: 'switch', + field: 'timeoutFlag', + name: t('project.node.waiting_dependent_complete'), + props: { + 'on-update:value': (value: boolean) => { + if (value) { + if (!model.timeoutNotifyStrategy.length) { + model.timeoutNotifyStrategy = ['WARN'] + } + if (!model.timeout) { + model.timeout = 30 + } + } + } + }, + span: timeCompleteSpan + }, + { + type: 'input-number', + field: 'timeout', + name: t('project.node.timeout_period'), + span: timeCompleteEnableSpan, + props: { + max: Math.pow(9, 10) - 1 + }, + slots: { + suffix: () => t('project.node.minute') + }, + validate: { + trigger: ['input'], + validator(validate: any, value: number) { + if (model.timeoutFlag && !/^[1-9]\d*$/.test(String(value))) { + return new Error(t('project.node.timeout_period_tips')) + } + } + } + }, + { + type: 'checkbox', + field: 'timeoutNotifyStrategy', + name: t('project.node.timeout_strategy'), + options: strategyOptions, + span: timeCompleteEnableSpan, + validate: { + trigger: ['input'], + validator(validate: any, value: []) { + if (model.waitCompleteTimeoutEnable && !value.length) { + return new Error(t('project.node.timeout_strategy_tips')) + } + } + } + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dependent.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dependent.ts new file mode 100644 index 0000000000..4a8e8cf2c0 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dependent.ts @@ -0,0 +1,550 @@ +/* + * 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, watch, h, computed } from 'vue' +import { useI18n } from 'vue-i18n' +import { NEllipsis, NIcon } from 'naive-ui' +import { useRelationCustomParams, useDependentTimeout } from '.' +import { useTaskNodeStore } from '@/store/project/task-node' +import { queryAllProjectListForDependent } from '@/service/modules/projects' +import { tasksState } from '@/common/common' +import { + queryProcessDefinitionList, + getTasksByDefinitionList +} from '@/service/modules/process-definition' +import { Router, useRouter } from 'vue-router' +import type { + IJsonItem, + IDependentItem, + IDependentItemOptions, + IDependTaskOptions, + IDependTask, + ITaskState, + IDateType +} from '../types' +import { IRenderOption } from '../types' + +export function useDependent(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const router: Router = useRouter() + const nodeStore = useTaskNodeStore() + + const dependentFailurePolicyOptions = computed(() => { + return [ + { + label: t('project.node.dependent_failure_policy_failure'), + value: 'DEPENDENT_FAILURE_FAILURE' + }, + { + label: t('project.node.dependent_failure_policy_waiting'), + value: 'DEPENDENT_FAILURE_WAITING' + } + ] + }) + const failureWaitingTimeSpan = computed(() => + model.failurePolicy === 'DEPENDENT_FAILURE_WAITING' ? 12 : 0 + ) + const dependentResult = nodeStore.getDependentResult + const TasksStateConfig = tasksState(t) + const projectList = ref([] as IRenderOption[]) + const processCache = {} as { + [key: number]: IRenderOption[] + } + const taskCache = {} as { + [key: number]: IRenderOption[] + } + const selectOptions = ref([] as IDependTaskOptions[]) + + const DependentTypeOptions = [ + { + value: 'DEPENDENT_ON_WORKFLOW', + label: t('project.node.dependent_on_workflow') + }, + { + value: 'DEPENDENT_ON_TASK', + label: t('project.node.dependent_on_task') + } + ] + + const CYCLE_LIST = [ + { + value: 'month', + label: t('project.node.month') + }, + { + value: 'week', + label: t('project.node.week') + }, + { + value: 'day', + label: t('project.node.day') + }, + { + value: 'hour', + label: t('project.node.hour') + } + ] + const DATE_LIST = { + hour: [ + { + value: 'currentHour', + label: t('project.node.current_hour') + }, + { + value: 'last1Hour', + label: t('project.node.last_1_hour') + }, + { + value: 'last2Hours', + label: t('project.node.last_2_hour') + }, + { + value: 'last3Hours', + label: t('project.node.last_3_hour') + }, + { + value: 'last24Hours', + label: t('project.node.last_24_hour') + } + ], + day: [ + { + value: 'today', + label: t('project.node.today') + }, + { + value: 'last1Days', + label: t('project.node.last_1_days') + }, + { + value: 'last2Days', + label: t('project.node.last_2_days') + }, + { + value: 'last3Days', + label: t('project.node.last_3_days') + }, + { + value: 'last7Days', + label: t('project.node.last_7_days') + } + ], + week: [ + { + value: 'thisWeek', + label: t('project.node.this_week') + }, + { + value: 'lastWeek', + label: t('project.node.last_week') + }, + { + value: 'lastMonday', + label: t('project.node.last_monday') + }, + { + value: 'lastTuesday', + label: t('project.node.last_tuesday') + }, + { + value: 'lastWednesday', + label: t('project.node.last_wednesday') + }, + { + value: 'lastThursday', + label: t('project.node.last_thursday') + }, + { + value: 'lastFriday', + label: t('project.node.last_friday') + }, + { + value: 'lastSaturday', + label: t('project.node.last_saturday') + }, + { + value: 'lastSunday', + label: t('project.node.last_sunday') + } + ], + month: [ + { + value: 'thisMonth', + label: t('project.node.this_month') + }, + { + value: 'thisMonthBegin', + label: t('project.node.this_month_begin') + }, + { + value: 'lastMonth', + label: t('project.node.last_month') + }, + { + value: 'lastMonthBegin', + label: t('project.node.last_month_begin') + }, + { + value: 'lastMonthEnd', + label: t('project.node.last_month_end') + } + ] + } as { [key in IDateType]: { value: string; label: string }[] } + + const getProjectList = async () => { + const result = await queryAllProjectListForDependent() + projectList.value = result.map((item: { code: number; name: string }) => ({ + value: item.code, + label: () => h(NEllipsis, null, item.name), + filterLabel: item.name + })) + return projectList + } + const getProcessList = async (code: number) => { + if (processCache[code]) { + return processCache[code] + } + const result = await queryProcessDefinitionList(code) + const processList = result.map((item: { code: number; name: string }) => ({ + value: item.code, + label: () => h(NEllipsis, null, item.name), + filterLabel: item.name + })) + processCache[code] = processList + + return processList + } + + const getTaskList = async (code: number, processCode: number) => { + if (taskCache[processCode]) { + return taskCache[processCode] + } + const result = await getTasksByDefinitionList(code, processCode) + const taskList = result.map((item: { code: number; name: string }) => ({ + value: item.code, + label: () => h(NEllipsis, null, item.name), + filterLabel: item.name + })) + taskList.unshift({ + value: -1, + label: 'ALL', + filterLabel: 'ALL' + }) + taskCache[processCode] = taskList + return taskList + } + + const renderState = (item: { + definitionCode: number + depTaskCode: number + cycle: string + dateValue: string + }) => { + if (!item || router.currentRoute.value.name !== 'workflow-instance-detail') + return null + const key = `${item.definitionCode}-${item.depTaskCode}-${item.cycle}-${item.dateValue}` + const state: ITaskState = dependentResult[key] + return h(NIcon, { size: 24, color: TasksStateConfig[state]?.color }, () => + h(TasksStateConfig[state]?.icon) + ) + } + + onMounted(() => { + getProjectList() + }) + + watch( + () => model.dependTaskList, + (value) => { + selectOptions.value = [] + value.forEach((item: IDependTask, taskIndex: number) => { + if (!item.dependItemList?.length) return + + const itemListOptions = ref([] as IDependentItemOptions[]) + item.dependItemList?.forEach( + async (dependItem: IDependentItem, itemIndex: number) => { + itemListOptions.value[itemIndex] = {} + + if (!dependItem.dependentType) { + if (dependItem.depTaskCode == 0) + dependItem.dependentType = 'DEPENDENT_ON_WORKFLOW' + else dependItem.dependentType = 'DEPENDENT_ON_TASK' + } + if (dependItem.projectCode) { + itemListOptions.value[itemIndex].definitionCodeOptions = + await getProcessList(dependItem.projectCode) + } + if (dependItem.projectCode && dependItem.definitionCode) { + itemListOptions.value[itemIndex].depTaskCodeOptions = + await getTaskList( + dependItem.projectCode, + dependItem.definitionCode + ) + } + if (dependItem.cycle) { + itemListOptions.value[itemIndex].dateOptions = + DATE_LIST[dependItem.cycle] + } + } + ) + selectOptions.value[taskIndex] = {} as IDependTaskOptions + selectOptions.value[taskIndex].dependItemList = itemListOptions.value + }) + } + ) + + return [ + ...useDependentTimeout(model), + ...useRelationCustomParams({ + model, + children: (i = 0) => ({ + type: 'custom-parameters', + field: 'dependItemList', + span: 18, + children: [ + (j = 0) => ({ + type: 'select', + field: 'dependentType', + name: t('project.node.dependent_type'), + span: 24, + props: { + onUpdateValue: (dependentType: string) => { + const item = model.dependTaskList[i].dependItemList[j] + if (item.definitionCode) + item.depTaskCode = + dependentType === 'DEPENDENT_ON_WORKFLOW' ? 0 : -1 + } + }, + options: DependentTypeOptions, + value: 'DEPENDENT_ON_WORKFLOW' + }), + (j = 0) => ({ + type: 'select', + field: 'projectCode', + name: t('project.node.project_name'), + span: 24, + props: { + filterable: true, + filter: (query: string, option: IRenderOption) => { + return option.filterLabel + .toLowerCase() + .includes(query.toLowerCase()) + }, + onUpdateValue: async (projectCode: number) => { + const item = model.dependTaskList[i].dependItemList[j] + const options = selectOptions?.value[i] || {} + const itemListOptions = options?.dependItemList || [] + const itemOptions = {} as IDependentItemOptions + itemOptions.definitionCodeOptions = await getProcessList( + projectCode + ) + itemListOptions[j] = itemOptions + options.dependItemList = itemListOptions + selectOptions.value[i] = options + item.depTaskCode = null + item.definitionCode = null + item.parameterPassing = false + } + }, + options: projectList, + path: `dependTaskList.${i}.dependItemList.${j}.projectCode`, + rule: { + required: true, + trigger: ['input', 'blur'], + validator(validate: any, value: string) { + if (!value) { + return Error(t('project.node.project_name_tips')) + } + } + } + }), + (j = 0) => ({ + type: 'select', + field: 'definitionCode', + span: 24, + name: t('project.node.process_name'), + props: { + filterable: true, + filter: (query: string, option: IRenderOption) => { + return option.filterLabel + .toLowerCase() + .includes(query.toLowerCase()) + }, + onUpdateValue: async (processCode: number) => { + const item = model.dependTaskList[i].dependItemList[j] + selectOptions.value[i].dependItemList[j].depTaskCodeOptions = + await getTaskList(item.projectCode, processCode) + item.depTaskCode = + item.dependentType === 'DEPENDENT_ON_WORKFLOW' ? 0 : -1 + } + }, + options: + selectOptions.value[i]?.dependItemList[j] + ?.definitionCodeOptions || [], + path: `dependTaskList.${i}.dependItemList.${j}.definitionCode`, + rule: { + required: true, + trigger: ['input', 'blur'], + validator(validate: any, value: string) { + if (!value) { + return Error(t('project.node.process_name_tips')) + } + } + } + }), + (j = 0) => ({ + type: 'select', + field: 'depTaskCode', + span: computed(() => { + const item = model.dependTaskList[i].dependItemList[j] + return item.dependentType === 'DEPENDENT_ON_WORKFLOW' ? 0 : 24 + }), + name: t('project.node.task_name'), + props: { + filterable: true, + filter: (query: string, option: IRenderOption) => { + return option.filterLabel + .toLowerCase() + .includes(query.toLowerCase()) + } + }, + options: + selectOptions.value[i]?.dependItemList[j]?.depTaskCodeOptions || + [], + path: `dependTaskList.${i}.dependItemList.${j}.depTaskCode`, + rule: { + required: true, + trigger: ['input', 'blur'], + validator(validate: any, value: number) { + if (!value && value !== 0) { + return Error(t('project.node.task_name_tips')) + } + } + } + }), + (j = 0) => ({ + type: 'select', + field: 'cycle', + span: 10, + name: t('project.node.cycle_time'), + props: { + onUpdateValue: (value: IDateType) => { + selectOptions.value[i].dependItemList[j].dateOptions = + DATE_LIST[value] + model.dependTaskList[i].dependItemList[j].dateValue = null + } + }, + options: CYCLE_LIST, + path: `dependTaskList.${i}.dependItemList.${j}.cycle`, + rule: { + required: true, + trigger: ['input', 'blur'], + validator(validate: any, value: string) { + if (!value) { + return Error(t('project.node.cycle_time_tips')) + } + } + } + }), + (j = 0) => ({ + type: 'select', + field: 'dateValue', + span: 10, + name: ' ', + options: + selectOptions.value[i]?.dependItemList[j]?.dateOptions || [], + path: `dependTaskList.${i}.dependItemList.${j}.dateValue`, + rule: { + trigger: ['input', 'blur'], + validator(validate: any, value: string) { + if (!value) { + return Error(t('project.node.date_tips')) + } + } + } + }), + (j = 0) => ({ + type: 'switch', + field: 'parameterPassing', + span: 20, + name: t('project.node.dependent_task_parameter_passing'), + path: `dependTaskList.${i}.dependItemList.${j}.parameterPassing` + }), + (j = 0) => ({ + type: 'custom', + field: 'state', + span: 2, + name: ' ', + widget: renderState(model.dependTaskList[i]?.dependItemList[j]) + }) + ] + }), + childrenField: 'dependItemList', + name: 'add_dependency' + }), + { + type: 'input-number', + field: 'checkInterval', + name: t('project.node.check_interval'), + span: 12, + props: { + max: Math.pow(9, 10) - 1 + }, + slots: { + suffix: () => t('project.node.second') + }, + validate: { + trigger: ['input'], + validator(validate: any, value: number) { + if (!value && !/^[1-9]\d*$/.test(String(value))) { + return new Error(t('project.node.check_interval_tips')) + } + } + } + }, + { + type: 'radio', + field: 'failurePolicy', + name: t('project.node.dependent_failure_policy'), + options: dependentFailurePolicyOptions, + span: 24 + }, + { + type: 'input-number', + field: 'failureWaitingTime', + name: t('project.node.dependent_failure_waiting_time'), + span: failureWaitingTimeSpan, + props: { + max: Math.pow(9, 10) - 1 + }, + slots: { + suffix: () => t('project.node.minute') + }, + validate: { + trigger: ['input'], + required: true, + validator(validate: any, value: number) { + if (model.timeoutFlag && !/^[1-9]\d*$/.test(String(value))) { + return new Error( + t('project.node.dependent_failure_waiting_time_tips') + ) + } + } + } + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-deploy-mode.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-deploy-mode.ts new file mode 100644 index 0000000000..81587b96f0 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-deploy-mode.ts @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Ref, ref, watchEffect } from 'vue' +import { useI18n } from 'vue-i18n' +import type { IJsonItem, IOption } from '../types' + +export function useDeployMode( + span: number | Ref = 24, + showClient = ref(true), + showCluster = ref(true), + showLocal = ref(true) +): IJsonItem { + const { t } = useI18n() + + const deployModeOptions = ref(DEPLOY_MODES as IOption[]) + + watchEffect(() => { + deployModeOptions.value = DEPLOY_MODES.filter((option) => { + switch (option.value) { + case 'cluster': + return showCluster.value + case 'client': + return showClient.value + case 'local': + return showLocal.value + default: + return true + } + }) + }) + return { + type: 'radio', + field: 'deployMode', + name: t('project.node.deploy_mode'), + options: deployModeOptions, + span: span + } +} + +export const DEPLOY_MODES = [ + { + label: 'cluster', + value: 'cluster' + }, + { + label: 'client', + value: 'client' + }, + { + label: 'local', + value: 'local' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-description.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-description.ts new file mode 100644 index 0000000000..e317554c4e --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-description.ts @@ -0,0 +1,33 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useDescription(): IJsonItem { + const { t } = useI18n() + return { + type: 'input', + field: 'description', + name: t('project.node.description'), + props: { + placeholder: t('project.node.description_tips'), + rows: 2, + type: 'textarea' + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dinky.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dinky.ts new file mode 100644 index 0000000000..d043b2209d --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dinky.ts @@ -0,0 +1,66 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { useCustomParams } from '.' +import type { IJsonItem } from '../types' + +export function useDinky(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'input', + field: 'address', + name: t('project.node.dinky_address'), + props: { + placeholder: t('project.node.dinky_address_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(_validate: any, value: string) { + if (!value) { + return new Error(t('project.node.dinky_address_tips')) + } + } + } + }, + { + type: 'input', + field: 'taskId', + name: t('project.node.dinky_task_id'), + props: { + placeholder: t('project.node.dinky_task_id_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(_validate: any, value: string) { + if (!value) { + return new Error(t('project.node.dinky_task_id_tips')) + } + } + } + }, + { + type: 'switch', + field: 'online', + name: t('project.node.dinky_online') + }, + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dms.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dms.ts new file mode 100644 index 0000000000..7c566141b6 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dms.ts @@ -0,0 +1,141 @@ +/* + * 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 { IJsonItem } from '../types' +import { watch, ref } from 'vue' +import { useCustomParams, useResources } from '.' + +export function useDms(model: { [field: string]: any }): IJsonItem[] { + const jsonDataSpan = ref(0) + const replicationTaskArnSpan = ref(0) + const replicationTaskIdentifierSpan = ref(0) + const sourceEndpointArnSpan = ref(0) + const targetEndpointArnSpan = ref(0) + const replicationInstanceArnSpan = ref(0) + const migrationTypeSpan = ref(0) + const tableMappingsSpan = ref(0) + + const setFlag = () => { + model.isCreateAndNotJson = + !model.isRestartTask && !model.isJsonFormat ? true : false + model.isRestartAndNotJson = + model.isRestartTask && !model.isJsonFormat ? true : false + } + + const resetSpan = () => { + jsonDataSpan.value = model.isJsonFormat ? 24 : 0 + replicationTaskArnSpan.value = model.isRestartAndNotJson ? 24 : 0 + migrationTypeSpan.value = model.isCreateAndNotJson ? 24 : 0 + sourceEndpointArnSpan.value = model.isCreateAndNotJson ? 24 : 0 + replicationTaskIdentifierSpan.value = model.isCreateAndNotJson ? 24 : 0 + targetEndpointArnSpan.value = model.isCreateAndNotJson ? 24 : 0 + replicationInstanceArnSpan.value = model.isCreateAndNotJson ? 24 : 0 + tableMappingsSpan.value = model.isCreateAndNotJson ? 24 : 0 + } + + watch( + () => [model.isRestartTask, model.isJsonFormat], + () => { + setFlag() + resetSpan() + } + ) + + setFlag() + resetSpan() + + return [ + { + type: 'switch', + field: 'isRestartTask', + name: 'isRestartTask', + span: 12 + }, + { + type: 'switch', + field: 'isJsonFormat', + name: 'isJsonFormat', + span: 12 + }, + { + type: 'editor', + field: 'jsonData', + name: 'jsonData', + span: jsonDataSpan + }, + { + type: 'select', + field: 'migrationType', + name: 'migrationType', + span: migrationTypeSpan, + options: MIGRATION_TYPE + }, + { + type: 'input', + field: 'replicationTaskIdentifier', + name: 'replicationTaskIdentifier', + span: replicationTaskIdentifierSpan + }, + { + type: 'input', + field: 'replicationInstanceArn', + name: 'replicationInstanceArn', + span: replicationInstanceArnSpan + }, + { + type: 'input', + field: 'sourceEndpointArn', + name: 'sourceEndpointArn', + span: sourceEndpointArnSpan + }, + { + type: 'input', + field: 'targetEndpointArn', + name: 'targetEndpointArn', + span: targetEndpointArnSpan + }, + { + type: 'editor', + field: 'tableMappings', + name: 'tableMappings', + span: tableMappingsSpan + }, + { + type: 'input', + field: 'replicationTaskArn', + name: 'replicationTaskArn', + span: replicationTaskArnSpan + }, + useResources(), + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} + +export const MIGRATION_TYPE = [ + { + label: 'full-load', + value: 'full-load' + }, + { + label: 'cdc', + value: 'cdc' + }, + { + label: 'full-load-and-cdc', + value: 'full-load-and-cdc' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-driver-cores.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-driver-cores.ts new file mode 100644 index 0000000000..82b06f0277 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-driver-cores.ts @@ -0,0 +1,42 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useDriverCores(): IJsonItem { + const { t } = useI18n() + + return { + type: 'input-number', + field: 'driverCores', + name: t('project.node.driver_cores'), + span: 12, + props: { + placeholder: t('project.node.driver_cores_tips'), + min: 1 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.driver_cores_tips')) + } + } + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-driver-memory.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-driver-memory.ts new file mode 100644 index 0000000000..6ba53b137b --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-driver-memory.ts @@ -0,0 +1,47 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useDriverMemory(): IJsonItem { + const { t } = useI18n() + + return { + type: 'input', + field: 'driverMemory', + name: t('project.node.driver_memory'), + span: 12, + props: { + placeholder: t('project.node.driver_memory_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.driver_memory_tips')) + } + if (!Number.isInteger(parseInt(value))) { + return new Error( + t('project.node.driver_memory') + + t('project.node.positive_integer_tips') + ) + } + } + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dvc.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dvc.ts new file mode 100644 index 0000000000..0ceac153c3 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dvc.ts @@ -0,0 +1,171 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' +import { watch, ref } from 'vue' + +export const DVC_TASK_TYPE = [ + { + label: 'Upload', + value: 'Upload' + }, + { + label: 'Download', + value: 'Download' + }, + { + label: 'Init DVC', + value: 'Init DVC' + } +] + +export function useDvc(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const dvcLoadSaveDataPathSpan = ref(0) + const dvcDataLocationSpan = ref(0) + const dvcVersionSpan = ref(0) + const dvcMessageSpan = ref(0) + const dvcStoreUrlSpan = ref(0) + + const setFlag = () => { + model.isUpload = model.dvcTaskType === 'Upload' + model.isDownload = model.dvcTaskType === 'Download' + model.isInit = model.dvcTaskType === 'Init DVC' + } + + const resetData = () => { + dvcLoadSaveDataPathSpan.value = model.isUpload || model.isDownload ? 24 : 0 + dvcDataLocationSpan.value = model.isUpload || model.isDownload ? 24 : 0 + dvcVersionSpan.value = model.isUpload || model.isDownload ? 24 : 0 + dvcMessageSpan.value = model.isUpload ? 24 : 0 + dvcStoreUrlSpan.value = model.isInit ? 24 : 0 + } + + watch( + () => [model.dvcTaskType], + () => { + setFlag() + resetData() + } + ) + setFlag() + resetData() + + return [ + { + type: 'select', + field: 'dvcTaskType', + name: t('project.node.dvc_task_type'), + span: 12, + options: DVC_TASK_TYPE + }, + { + type: 'input', + field: 'dvcRepository', + name: t('project.node.dvc_repository'), + span: 24, + props: { + placeholder: t('project.node.dvc_repository_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + message: t('project.node.dvc_empty_tips') + } + }, + { + type: 'input', + field: 'dvcDataLocation', + name: t('project.node.dvc_data_location'), + props: { placeholder: 'dvcDataLocation' }, + span: dvcDataLocationSpan, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if ((model.isUpload || model.isDownload) && !value) { + return new Error(t('project.node.dvc_empty_tips')) + } + } + } + }, + { + type: 'input', + field: 'dvcLoadSaveDataPath', + name: t('project.node.dvc_load_save_data_path'), + span: dvcLoadSaveDataPathSpan, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if ((model.isUpload || model.isDownload) && !value) { + return new Error(t('project.node.dvc_empty_tips')) + } + } + } + }, + { + type: 'input', + field: 'dvcVersion', + name: t('project.node.dvc_version'), + span: dvcVersionSpan, + props: { + placeholder: t('project.node.dvc_version_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if ((model.isUpload || model.isDownload) && !value) { + return new Error(t('project.node.dvc_empty_tips')) + } + } + } + }, + { + type: 'input', + field: 'dvcMessage', + name: t('project.node.dvc_message'), + span: dvcMessageSpan, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (model.isUpload && !value) { + return new Error(t('project.node.dvc_empty_tips')) + } + } + } + }, + { + type: 'input', + field: 'dvcStoreUrl', + name: t('project.node.dvc_store_url'), + span: dvcStoreUrlSpan, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!model.isInit && value) { + return new Error(t('project.node.dvc_empty_tips')) + } + } + } + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dynamic.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dynamic.ts new file mode 100644 index 0000000000..08e47c2d98 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-dynamic.ts @@ -0,0 +1,120 @@ +/* + * 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 { IJsonItem } from '../types' +import { useI18n } from 'vue-i18n' + +export function useDynamic(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'input-number', + field: 'maxNumOfSubWorkflowInstances', + span: 12, + name: t('project.node.max_num_of_sub_workflow_instances'), + validate: { + required: true + } + }, + { + type: 'input-number', + field: 'degreeOfParallelism', + span: 12, + name: t('project.node.parallelism'), + validate: { + required: true + } + }, + { + type: 'custom-parameters', + field: 'listParameters', + name: t('project.node.params_value'), + span: 24, + children: [ + { + type: 'input', + field: 'name', + span: 8, + props: { + placeholder: t('project.node.dynamic_name_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.dynamic_name_tips')) + } + + const sameItems = model['listParameters'].filter( + (item: { name: string }) => item.name === value + ) + + if (sameItems.length > 1) { + return new Error(t('project.node.prop_repeat')) + } + } + } + }, + { + type: 'input', + field: 'value', + span: 8, + props: { + placeholder: t('project.node.dynamic_value_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.dynamic_value_tips')) + } + } + } + }, + { + type: 'input', + field: 'separator', + span: 4, + props: { + placeholder: t('project.node.dynamic_separator_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.dynamic_separator_tips')) + } + } + } + } + ] + }, + { + type: 'input', + field: 'filterCondition', + span: 24, + name: t('project.node.filter_condition') + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-emr.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-emr.ts new file mode 100644 index 0000000000..2d89af61d0 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-emr.ts @@ -0,0 +1,89 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { useCustomParams } from '.' +import type { IJsonItem } from '../types' +import { computed } from 'vue' + +export function useEmr(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const jobFlowDefineJsonSpan = computed(() => + model.programType === 'RUN_JOB_FLOW' ? 24 : 0 + ) + + const stepsDefineJsonSpan = computed(() => + model.programType === 'ADD_JOB_FLOW_STEPS' ? 24 : 0 + ) + + return [ + { + type: 'select', + field: 'programType', + span: 24, + name: t('project.node.program_type'), + options: PROGRAM_TYPES, + validate: { + required: true + } + }, + { + type: 'editor', + field: 'jobFlowDefineJson', + span: jobFlowDefineJsonSpan, + name: t('project.node.emr_flow_define_json'), + props: { + language: 'json' + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.emr_flow_define_json_tips') + } + }, + { + type: 'editor', + field: 'stepsDefineJson', + span: stepsDefineJsonSpan, + name: t('project.node.emr_steps_define_json'), + props: { + language: 'json' + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.emr_steps_define_json_tips') + } + }, + ...useCustomParams({ + model, + field: 'localParams', + isSimple: true + }) + ] +} + +export const PROGRAM_TYPES = [ + { + label: 'RUN_JOB_FLOW', + value: 'RUN_JOB_FLOW' + }, + { + label: 'ADD_JOB_FLOW_STEPS', + value: 'ADD_JOB_FLOW_STEPS' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-environment-name.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-environment-name.ts new file mode 100644 index 0000000000..111310a471 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-environment-name.ts @@ -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 { ref, onMounted, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { queryAllEnvironmentList } from '@/service/modules/environment' +import type { IEnvironmentNameOption, IJsonItem } from '../types' + +export function useEnvironmentName( + model: { [field: string]: any }, + isCreate: boolean +): IJsonItem { + const { t } = useI18n() + + let environmentList = [] as IEnvironmentNameOption[] + const options = ref([] as IEnvironmentNameOption[]) + const loading = ref(false) + let mounted = false + + const getEnvironmentList = async () => { + if (loading.value) return + loading.value = true + const res = await queryAllEnvironmentList() + environmentList = res.map( + (item: { code: string; name: string; workerGroups: string[] }) => ({ + label: item.name, + value: item.code, + workerGroups: item.workerGroups + }) + ) + options.value = environmentList.filter((option: IEnvironmentNameOption) => + filterByWorkerGroup(option) + ) + loading.value = false + if (options.value.length === 0) { + model.environmentCode = null + } else { + isCreate && + !model.environmentCode && + (model.environmentCode = options.value[0].value) + } + } + + const filterByWorkerGroup = (option: IEnvironmentNameOption) => { + if (!model.workerGroup) return false + if (!option?.workerGroups?.length) return false + return option.workerGroups.indexOf(model.workerGroup) !== -1 + } + + watch( + () => model.workerGroup, + () => { + if (!model.workerGroup || !mounted) return + options.value = environmentList.filter((option: IEnvironmentNameOption) => + filterByWorkerGroup(option) + ) + if (model?.environmentCode) { + if (options.value) { + const elementExists = + options.value.find( + (item) => item.value === model.environmentCode + ) !== undefined + if (!elementExists) { + model.environmentCode = null + } + } + } else { + model.environmentCode = + options.value.length === 0 ? null : options.value[0].value + } + } + ) + + onMounted(async () => { + await getEnvironmentList() + mounted = true + }) + + return { + type: 'select', + field: 'environmentCode', + class: 'env-select', + span: 12, + name: t('project.node.environment_name'), + props: { + loading: loading, + clearable: true + }, + options: options + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-cores.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-cores.ts new file mode 100644 index 0000000000..87540197c5 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-cores.ts @@ -0,0 +1,42 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useExecutorCores(): IJsonItem { + const { t } = useI18n() + + return { + type: 'input-number', + field: 'executorCores', + name: t('project.node.executor_cores'), + span: 12, + props: { + placeholder: t('project.node.executor_cores_tips'), + min: 1 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.executor_cores_tips')) + } + } + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-memory.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-memory.ts new file mode 100644 index 0000000000..b135d22751 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-memory.ts @@ -0,0 +1,47 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useExecutorMemory(): IJsonItem { + const { t } = useI18n() + + return { + type: 'input', + field: 'executorMemory', + name: t('project.node.executor_memory'), + span: 12, + props: { + placeholder: t('project.node.executor_memory_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.executor_memory_tips')) + } + if (!Number.isInteger(parseInt(value))) { + return new Error( + t('project.node.executor_memory_tips') + + t('project.node.positive_integer_tips') + ) + } + } + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-number.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-number.ts new file mode 100644 index 0000000000..34ba711d63 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-executor-number.ts @@ -0,0 +1,42 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useExecutorNumber(): IJsonItem { + const { t } = useI18n() + + return { + type: 'input-number', + field: 'numExecutors', + name: t('project.node.executor_number'), + span: 12, + props: { + placeholder: t('project.node.executor_number_tips'), + min: 1 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.executor_number_tips')) + } + } + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-failed.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-failed.ts new file mode 100644 index 0000000000..f511c8e455 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-failed.ts @@ -0,0 +1,49 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useFailed(): IJsonItem[] { + const { t } = useI18n() + return [ + { + type: 'input-number', + field: 'failRetryTimes', + name: t('project.node.number_of_failed_retries'), + span: 12, + props: { + min: 0 + }, + slots: { + suffix: () => t('project.node.times') + } + }, + { + type: 'input-number', + field: 'failRetryInterval', + name: t('project.node.failed_retry_interval'), + span: 12, + props: { + min: 0 + }, + slots: { + suffix: () => t('project.node.minute') + } + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-flink.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-flink.ts new file mode 100644 index 0000000000..aaedf5d2aa --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-flink.ts @@ -0,0 +1,346 @@ +/* + * 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 { computed, watch, watchEffect } from 'vue' +import { useI18n } from 'vue-i18n' +import { useCustomParams, useMainJar, useResources, useYarnQueue } from '.' +import type { IJsonItem } from '../types' + +export function useFlink(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const mainClassSpan = computed(() => + model.programType === 'PYTHON' || model.programType === 'SQL' ? 0 : 24 + ) + + const mainArgsSpan = computed(() => (model.programType === 'SQL' ? 0 : 24)) + + const scriptSpan = computed(() => (model.programType === 'SQL' ? 24 : 0)) + + const flinkVersionOptions = computed(() => + model.programType === 'SQL' + ? [{ label: '>=1.13', value: '>=1.13' }] + : FLINK_VERSIONS + ) + + const taskManagerNumberSpan = computed(() => + model.flinkVersion === '<1.10' && model.deployMode !== 'local' ? 12 : 0 + ) + + const deployModeSpan = computed(() => (model.deployMode !== 'local' ? 12 : 0)) + + const appNameSpan = computed(() => (model.deployMode !== 'local' ? 24 : 0)) + + const deployModeOptions = computed(() => { + if (model.programType === 'SQL') { + return [ + { + label: 'per-job/cluster', + value: 'cluster' + }, + { + label: 'local', + value: 'local' + }, + { + label: 'standalone', + value: 'standalone' + } + ] + } + if (model.flinkVersion === '<1.10') { + return [ + { + label: 'cluster', + value: 'cluster' + }, + { + label: 'local', + value: 'local' + } + ] + } else { + return [ + { + label: 'per-job/cluster', + value: 'cluster' + }, + { + label: 'application', + value: 'application' + }, + { + label: 'local', + value: 'local' + } + ] + } + }) + + watch( + () => model.flinkVersion, + () => { + if ( + model.flinkVersion === '<1.10' && + model.deployMode === 'application' + ) { + model.deployMode = 'cluster' + } + } + ) + + watchEffect(() => { + model.flinkVersion = + model.programType === 'SQL' ? '>=1.13' : model.flinkVersion + }) + + return [ + { + type: 'select', + field: 'programType', + span: 24, + name: t('project.node.program_type'), + options: PROGRAM_TYPES, + props: { + 'on-update:value': () => { + model.mainJar = null + model.mainClass = '' + } + } + }, + { + type: 'input', + field: 'mainClass', + span: mainClassSpan, + name: t('project.node.main_class'), + props: { + placeholder: t('project.node.main_class_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: model.programType !== 'PYTHON' && model.programType !== 'SQL', + validator(validate: any, value: string) { + if ( + model.programType !== 'PYTHON' && + !value && + model.programType !== 'SQL' + ) { + return new Error(t('project.node.main_class_tips')) + } + } + } + }, + useMainJar(model), + { + type: 'radio', + field: 'deployMode', + name: t('project.node.deploy_mode'), + options: deployModeOptions, + span: 24 + }, + { + type: 'editor', + field: 'initScript', + span: scriptSpan, + name: t('project.node.init_script'), + validate: { + trigger: ['input', 'trigger'], + required: false, + message: t('project.node.init_script_tips') + } + }, + { + type: 'editor', + field: 'rawScript', + span: scriptSpan, + name: t('project.node.script'), + props: { + language: 'sql' + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.script_tips') + } + }, + { + type: 'select', + field: 'flinkVersion', + name: t('project.node.flink_version'), + options: flinkVersionOptions, + value: model.flinkVersion, + span: deployModeSpan + }, + { + type: 'input', + field: 'appName', + name: t('project.node.app_name'), + props: { + placeholder: t('project.node.app_name_tips') + }, + span: appNameSpan + }, + { + type: 'input', + field: 'jobManagerMemory', + name: t('project.node.job_manager_memory'), + span: deployModeSpan, + props: { + placeholder: t('project.node.job_manager_memory_tips'), + min: 1 + }, + validate: { + trigger: ['input', 'blur'], + validator(validate: any, value: string) { + if (!value) { + return + } + if (!Number.isInteger(parseInt(value))) { + return new Error( + t('project.node.job_manager_memory_tips') + + t('project.node.positive_integer_tips') + ) + } + } + } + }, + { + type: 'input', + field: 'taskManagerMemory', + name: t('project.node.task_manager_memory'), + span: deployModeSpan, + props: { + placeholder: t('project.node.task_manager_memory_tips') + }, + validate: { + trigger: ['input', 'blur'], + validator(validate: any, value: string) { + if (!value) { + return + } + if (!Number.isInteger(parseInt(value))) { + return new Error( + t('project.node.task_manager_memory') + + t('project.node.positive_integer_tips') + ) + } + } + }, + value: model.taskManagerMemory + }, + { + type: 'input-number', + field: 'slot', + name: t('project.node.slot_number'), + span: deployModeSpan, + props: { + placeholder: t('project.node.slot_number_tips'), + min: 1 + }, + value: model.slot + }, + { + type: 'input-number', + field: 'taskManager', + name: t('project.node.task_manager_number'), + span: taskManagerNumberSpan, + props: { + placeholder: t('project.node.task_manager_number_tips'), + min: 1 + }, + value: model.taskManager + }, + { + type: 'input-number', + field: 'parallelism', + name: t('project.node.parallelism'), + span: 12, + props: { + placeholder: t('project.node.parallelism_tips'), + min: 1 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.parallelism_tips')) + } + } + }, + value: model.parallelism + }, + useYarnQueue(), + { + type: 'input', + field: 'mainArgs', + span: mainArgsSpan, + name: t('project.node.main_arguments'), + props: { + type: 'textarea', + placeholder: t('project.node.main_arguments_tips') + } + }, + { + type: 'input', + field: 'others', + name: t('project.node.option_parameters'), + props: { + type: 'textarea', + placeholder: t('project.node.option_parameters_tips') + } + }, + useResources(), + ...useCustomParams({ + model, + field: 'localParams', + isSimple: true + }) + ] +} + +const PROGRAM_TYPES = [ + { + label: 'JAVA', + value: 'JAVA' + }, + { + label: 'SCALA', + value: 'SCALA' + }, + { + label: 'PYTHON', + value: 'PYTHON' + }, + { + label: 'SQL', + value: 'SQL' + } +] + +const FLINK_VERSIONS = [ + { + label: '<1.10', + value: '<1.10' + }, + { + label: '1.11', + value: '1.11' + }, + { + label: '>=1.12', + value: '>=1.12' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-hive-cli.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-hive-cli.ts new file mode 100644 index 0000000000..b285cc2353 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-hive-cli.ts @@ -0,0 +1,87 @@ +/* + * 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 { computed, watch, ref } from 'vue' +import { useI18n } from 'vue-i18n' +import { useCustomParams, useResources } from '.' +import type { IJsonItem } from '../types' + +export function useHiveCli(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const hiveSqlScriptSpan = computed(() => + model.hiveCliTaskExecutionType === 'SCRIPT' ? 24 : 0 + ) + const resourcesRequired = ref(model.hiveCliTaskExecutionType !== 'SCRIPT') + + const resourcesLimit = computed(() => + model.hiveCliTaskExecutionType === 'SCRIPT' ? -1 : 1 + ) + + const SQL_EXECUTION_TYPES = [ + { + label: t('project.node.sql_execution_type_from_script'), + value: 'SCRIPT' + }, + { + label: t('project.node.sql_execution_type_from_file'), + value: 'FILE' + } + ] + + watch( + () => model.hiveCliTaskExecutionType, + () => { + resourcesRequired.value = model.hiveCliTaskExecutionType !== 'SCRIPT' + } + ) + + return [ + { + type: 'select', + field: 'hiveCliTaskExecutionType', + span: 12, + name: t('project.node.sql_execution_type'), + options: SQL_EXECUTION_TYPES, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'editor', + field: 'hiveSqlScript', + name: t('project.node.hive_sql_script'), + props: { + language: 'sql' + }, + validate: { + trigger: ['input', 'blur'], + required: true + }, + span: hiveSqlScriptSpan + }, + { + type: 'input', + field: 'hiveCliOptions', + name: t('project.node.hive_cli_options'), + props: { + placeholder: t('project.node.hive_cli_options_tips') + } + }, + useResources(24, resourcesRequired, resourcesLimit), + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-http.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-http.ts new file mode 100644 index 0000000000..525b05cdb7 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-http.ts @@ -0,0 +1,244 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { useCustomParams } from '.' +import type { IJsonItem } from '../types' + +export function useHttp(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const HTTP_CHECK_CONDITIONS = [ + { + label: t('project.node.status_code_default'), + value: 'STATUS_CODE_DEFAULT' + }, + { + label: t('project.node.status_code_custom'), + value: 'STATUS_CODE_CUSTOM' + }, + { + label: t('project.node.body_contains'), + value: 'BODY_CONTAINS' + }, + { + label: t('project.node.body_not_contains'), + value: 'BODY_NOT_CONTAINS' + } + ] + + return [ + { + type: 'input', + class: 'input-url-name', + field: 'url', + name: t('project.node.http_url'), + props: { + placeholder: t('project.node.http_url_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.http_url_tips')) + } + if (value.search(new RegExp(/http[s]{0,1}:\/\/\S*/, 'i'))) { + return new Error(t('project.node.http_url_validator')) + } + } + } + }, + { + type: 'select', + field: 'httpMethod', + span: 12, + name: t('project.node.http_method'), + options: HTTP_METHODS + }, + { + type: 'custom-parameters', + field: 'httpParams', + name: t('project.node.http_parameters'), + children: [ + { + type: 'input', + field: 'prop', + span: 6, + props: { + placeholder: t('project.node.prop_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.prop_tips')) + } + + const sameItems = model.httpParams.filter( + (item: { prop: string }) => item.prop === value + ) + + if (sameItems.length > 1) { + return new Error(t('project.node.prop_repeat')) + } + } + } + }, + { + type: 'select', + field: 'httpParametersType', + span: 6, + options: POSITIONS, + value: 'PARAMETER' + }, + { + type: 'input', + field: 'value', + span: 6, + props: { + placeholder: t('project.node.value_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.value_required_tips')) + } + } + } + } + ] + }, + { + type: 'input', + field: 'httpBody', + name: t('project.node.http_body'), + props: { + type: 'textarea', + placeholder: t('project.node.http_body_tips') + } + }, + { + type: 'select', + field: 'httpCheckCondition', + name: t('project.node.http_check_condition'), + options: HTTP_CHECK_CONDITIONS + }, + { + type: 'input', + field: 'condition', + name: t('project.node.http_condition'), + props: { + type: 'textarea', + placeholder: t('project.node.http_condition_tips') + } + }, + { + type: 'input-number', + field: 'connectTimeout', + name: t('project.node.connect_timeout'), + span: 12, + props: { + max: Math.pow(7, 10) - 1 + }, + slots: { + suffix: () => t('project.node.ms') + }, + validate: { + trigger: ['input', 'blur'], + validator(validate: any, value: string) { + if (!Number.isInteger(parseInt(value))) { + return new Error( + t('project.node.connect_timeout') + + t('project.node.positive_integer_tips') + ) + } + } + } + }, + { + type: 'input-number', + field: 'socketTimeout', + name: t('project.node.socket_timeout'), + span: 12, + props: { + max: Math.pow(7, 10) - 1 + }, + slots: { + suffix: () => t('project.node.ms') + }, + validate: { + trigger: ['input', 'blur'], + validator(validate: any, value: string) { + if (!Number.isInteger(parseInt(value))) { + return new Error( + t('project.node.socket_timeout') + + t('project.node.positive_integer_tips') + ) + } + } + } + }, + ...useCustomParams({ + model, + field: 'localParams', + isSimple: true + }) + ] +} + +const HTTP_METHODS = [ + { + value: 'GET', + label: 'GET' + }, + { + value: 'POST', + label: 'POST' + }, + { + value: 'HEAD', + label: 'HEAD' + }, + { + value: 'PUT', + label: 'PUT' + }, + { + value: 'DELETE', + label: 'DELETE' + } +] + +const POSITIONS = [ + { + value: 'PARAMETER', + label: 'Parameter' + }, + { + value: 'BODY', + label: 'Body' + }, + { + value: 'HEADERS', + label: 'Headers' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-java-task-main-jar.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-java-task-main-jar.ts new file mode 100644 index 0000000000..826d709fad --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-java-task-main-jar.ts @@ -0,0 +1,81 @@ +/* + * 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 { computed, ref, onMounted, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { queryResourceByProgramType } from '@/service/modules/resources' +import { useTaskNodeStore } from '@/store/project/task-node' +import utils from '@/utils' +import type { IJsonItem, ProgramType, IMainJar } from '../types' + +export function useJavaTaskMainJar(model: { [field: string]: any }): IJsonItem { + const { t } = useI18n() + const mainJarOptions = ref([] as IMainJar[]) + const taskStore = useTaskNodeStore() + + const mainJarSpan = computed(() => (model.runType === 'JAVA' ? 0 : 24)) + const getMainJars = async (programType: ProgramType) => { + const storeMainJar = taskStore.getMainJar(programType) + if (storeMainJar) { + mainJarOptions.value = storeMainJar + return + } + const res = await queryResourceByProgramType({ + type: 'FILE', + programType + }) + utils.removeUselessChildren(res) + mainJarOptions.value = res || [] + taskStore.updateMainJar(programType, res) + } + + onMounted(() => { + getMainJars(model.programType) + }) + + watch( + () => model.programType, + (value) => { + getMainJars(value) + } + ) + + return { + type: 'tree-select', + field: 'mainJar', + name: t('project.node.main_package'), + span: mainJarSpan, + props: { + checkable: true, + cascade: true, + showPath: true, + checkStrategy: 'child', + placeholder: t('project.node.main_package_tips'), + keyField: 'fullName', + labelField: 'name' + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.main_package_tips')) + } + } + }, + options: mainJarOptions + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-java.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-java.ts new file mode 100644 index 0000000000..b8a47c8935 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-java.ts @@ -0,0 +1,85 @@ +/* + * 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 { computed } from 'vue' +import { useI18n } from 'vue-i18n' +import { useCustomParams, useResources, useJavaTaskMainJar } from '.' +import type { IJsonItem } from '../types' + +export function useJava(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const rawScriptSpan = computed(() => (model.runType === 'JAR' ? 0 : 24)) + return [ + { + type: 'select', + field: 'runType', + span: 12, + name: t('project.node.run_type'), + options: RUN_TYPES, + value: model.runType + }, + { + type: 'switch', + field: 'isModulePath', + span: 24, + name: t('project.node.is_module_path'), + value: model.isModulePath + }, + { + type: 'input', + field: 'mainArgs', + name: t('project.node.main_arguments'), + props: { + type: 'textarea', + placeholder: t('project.node.main_arguments_tips') + } + }, + { + type: 'input', + field: 'jvmArgs', + name: t('project.node.jvm_args'), + props: { + type: 'textarea', + placeholder: t('project.node.jvm_args_tips') + } + }, + useJavaTaskMainJar(model), + { + type: 'editor', + field: 'rawScript', + span: rawScriptSpan, + name: t('project.node.script'), + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.script_tips') + } + }, + useResources(), + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} + +export const RUN_TYPES = [ + { + label: 'JAVA', + value: 'JAVA' + }, + { + label: 'JAR', + value: 'JAR' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-jupyter.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-jupyter.ts new file mode 100644 index 0000000000..582b308d6c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-jupyter.ts @@ -0,0 +1,127 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { useCustomParams, useResources } from '.' +import type { IJsonItem } from '../types' + +export function useJupyter(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'input', + field: 'condaEnvName', + name: t('project.node.jupyter_conda_env_name'), + props: { + placeholder: t('project.node.jupyter_conda_env_name_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.jupyter_conda_env_name_tips')) + } + } + } + }, + { + type: 'input', + field: 'inputNotePath', + name: t('project.node.jupyter_input_note_path'), + props: { + placeholder: t('project.node.jupyter_input_note_path_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.jupyter_input_note_path_tips')) + } + } + } + }, + { + type: 'input', + field: 'outputNotePath', + name: t('project.node.jupyter_output_note_path'), + props: { + placeholder: t('project.node.jupyter_output_note_path_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.jupyter_output_note_path_tips')) + } + } + } + }, + { + type: 'input', + field: 'parameters', + name: t('project.node.jupyter_parameters'), + props: { + placeholder: t('project.node.jupyter_parameters_tips') + } + }, + { + type: 'input', + field: 'kernel', + name: t('project.node.jupyter_kernel'), + props: { + placeholder: t('project.node.jupyter_kernel_tips') + } + }, + { + type: 'input', + field: 'engine', + name: t('project.node.jupyter_engine'), + props: { + placeholder: t('project.node.jupyter_engine_tips') + } + }, + { + type: 'input', + field: 'executionTimeout', + name: t('project.node.jupyter_execution_timeout'), + props: { + placeholder: t('project.node.jupyter_execution_timeout_tips') + } + }, + { + type: 'input', + field: 'startTimeout', + name: t('project.node.jupyter_start_timeout'), + props: { + placeholder: t('project.node.jupyter_start_timeout_tips') + } + }, + { + type: 'input', + field: 'others', + name: t('project.node.jupyter_others'), + props: { + placeholder: t('project.node.jupyter_others_tips') + } + }, + useResources(), + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-k8s.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-k8s.ts new file mode 100644 index 0000000000..8d2a702464 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-k8s.ts @@ -0,0 +1,127 @@ +/* + * 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 { useCustomParams, useCustomLabels, useNodeSelectors } from '.' +import type { IJsonItem } from '../types' +import { useI18n } from 'vue-i18n' + +export function useK8s(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'input-number', + field: 'minCpuCores', + span: 12, + props: { + min: 0 + }, + name: t('project.node.min_cpu'), + slots: { + suffix: () => t('project.node.cores') + } + }, + { + type: 'input-number', + field: 'minMemorySpace', + span: 12, + props: { + min: 0 + }, + name: t('project.node.min_memory'), + slots: { + suffix: () => t('project.node.mb') + } + }, + { + type: 'input', + field: 'image', + name: t('project.node.image'), + span: 18, + props: { + placeholder: t('project.node.image_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + message: t('project.node.image_tips') + } + }, + { + type: 'select', + field: 'imagePullPolicy', + name: t('project.node.image_pull_policy'), + span: 6, + options: IMAGE_PULL_POLICY_LIST, + validate: { + trigger: ['input', 'blur'], + required: true, + message: t('project.node.image_pull_policy_tips') + }, + value: 'IfNotPresent' + }, + { + type: 'input', + field: 'pullSecret', + name: t('project.node.pull_secret'), + props: { + placeholder: t('project.node.pull_secret_tips') + } + }, + { + type: 'input', + field: 'command', + name: t('project.node.command'), + props: { + placeholder: t('project.node.command_tips') + } + }, + { + type: 'input', + field: 'args', + name: t('project.node.args'), + props: { + placeholder: t('project.node.args_tips') + } + }, + ...useCustomLabels({ + model, + field: 'customizedLabels', + name: 'custom_labels' + }), + ...useNodeSelectors({ + model, + field: 'nodeSelectors', + name: 'node_selectors' + }), + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} + +export const IMAGE_PULL_POLICY_LIST = [ + { + value: 'IfNotPresent', + label: 'IfNotPresent' + }, + { + value: 'Always', + label: 'Always' + }, + { + value: 'Never', + label: 'Never' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-kubeflow.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-kubeflow.ts new file mode 100644 index 0000000000..e03e524cf3 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-kubeflow.ts @@ -0,0 +1,38 @@ +/* + * 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 { IJsonItem } from '../types' +import { useCustomParams, useNamespace } from '.' + +export function useKubeflow(model: { [field: string]: any }): IJsonItem[] { + return [ + useNamespace(), + { + type: 'editor', + field: 'yamlContent', + name: 'yamlContent', + props: { + language: 'yaml' + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: 'requestJson' + } + }, + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-linkis.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-linkis.ts new file mode 100644 index 0000000000..d4028d8d0f --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-linkis.ts @@ -0,0 +1,94 @@ +/* + * 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 { computed } from 'vue' +import { useI18n } from 'vue-i18n' +import { useCustomParams } from '.' +import type { IJsonItem } from '../types' + +export function useLinkis(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const configEditorSpan = computed(() => (model.useCustom ? 24 : 0)) + const paramEditorSpan = computed(() => (model.useCustom ? 0 : 24)) + computed(() => (model.useCustom ? 0 : 24)) + return [ + { + type: 'switch', + field: 'useCustom', + name: t('project.node.custom_config') + }, + { + type: 'custom-parameters', + field: 'paramScript', + name: t('project.node.option_parameters'), + span: paramEditorSpan, + children: [ + { + type: 'input', + field: 'prop', + span: 10, + props: { + placeholder: t('project.node.prop_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.prop_tips')) + } + + const sameItems = model.localParams.filter( + (item: { prop: string }) => item.prop === value + ) + + if (sameItems.length > 1) { + return new Error(t('project.node.prop_repeat')) + } + } + } + }, + { + type: 'input', + field: 'value', + span: 10, + props: { + placeholder: t('project.node.value_tips'), + maxLength: 256 + } + } + ] + }, + { + type: 'editor', + field: 'rawScript', + name: t('project.node.script'), + span: configEditorSpan, + validate: { + trigger: ['input', 'trigger'], + required: model.useCustom, + validator(validate: any, value: string) { + if (model.useCustom && !value) { + return new Error(t('project.node.script_tips')) + } + } + } + }, + ...useCustomParams({ model, field: 'localParams', isSimple: true }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-main-jar.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-main-jar.ts new file mode 100644 index 0000000000..79ef7a2825 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-main-jar.ts @@ -0,0 +1,83 @@ +/* + * 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 { computed, ref, onMounted, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { queryResourceByProgramType } from '@/service/modules/resources' +import { useTaskNodeStore } from '@/store/project/task-node' +import utils from '@/utils' +import type { IJsonItem, ProgramType, IMainJar } from '../types' + +export function useMainJar(model: { [field: string]: any }): IJsonItem { + const { t } = useI18n() + const mainJarOptions = ref([] as IMainJar[]) + const taskStore = useTaskNodeStore() + + const mainJarSpan = computed(() => (model.programType === 'SQL' ? 0 : 24)) + const getMainJars = async (programType: ProgramType) => { + const storeMainJar = taskStore.getMainJar(programType) + if (storeMainJar) { + mainJarOptions.value = storeMainJar + return + } + const res = await queryResourceByProgramType({ + type: 'FILE', + programType + }) + utils.removeUselessChildren(res) + mainJarOptions.value = res || [] + taskStore.updateMainJar(programType, res) + } + + onMounted(() => { + getMainJars(model.programType) + }) + + watch( + () => model.programType, + (value) => { + if (value !== 'SQL') { + getMainJars(value) + } + } + ) + + return { + type: 'tree-select', + field: 'mainJar', + name: t('project.node.main_package'), + span: mainJarSpan, + props: { + checkable: true, + cascade: true, + showPath: true, + checkStrategy: 'child', + placeholder: t('project.node.main_package_tips'), + keyField: 'fullName', + labelField: 'name' + }, + validate: { + trigger: ['input', 'blur'], + required: model.programType !== 'SQL', + validator(validate: any, value: string) { + if (!value && model.programType !== 'SQL') { + return new Error(t('project.node.main_package_tips')) + } + } + }, + options: mainJarOptions + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow-models.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow-models.ts new file mode 100644 index 0000000000..eef3837fde --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow-models.ts @@ -0,0 +1,80 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' +import { watch, ref } from 'vue' + +export function useMlflowModels(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const deployTypeSpan = ref(0) + const deployModelKeySpan = ref(0) + const deployPortSpan = ref(0) + + const setFlag = () => { + model.isModels = model.mlflowTaskType === 'MLflow Models' ? true : false + } + + const resetSpan = () => { + deployTypeSpan.value = model.isModels ? 12 : 0 + deployModelKeySpan.value = model.isModels ? 24 : 0 + deployPortSpan.value = model.isModels ? 12 : 0 + } + + watch( + () => [model.mlflowTaskType], + () => { + setFlag() + resetSpan() + } + ) + + setFlag() + resetSpan() + + return [ + { + type: 'select', + field: 'deployType', + name: t('project.node.mlflow_deployType'), + span: deployTypeSpan, + options: DEPLOY_TYPE + }, + { + type: 'input', + field: 'deployModelKey', + name: t('project.node.mlflow_deployModelKey'), + span: deployModelKeySpan + }, + { + type: 'input', + field: 'deployPort', + name: t('project.node.mlflow_deployPort'), + span: deployPortSpan + } + ] +} + +const DEPLOY_TYPE = [ + { + label: 'MLFLOW', + value: 'MLFLOW' + }, + { + label: 'DOCKER', + value: 'DOCKER' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow-projects.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow-projects.ts new file mode 100644 index 0000000000..c312ee435e --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow-projects.ts @@ -0,0 +1,322 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' +import { watch, ref } from 'vue' + +export function useMlflowProjects(model: { + [field: string]: any +}): IJsonItem[] { + const { t } = useI18n() + + const experimentNameSpan = ref(0) + const registerModelSpan = ref(0) + const modelNameSpan = ref(0) + const mlflowJobTypeSpan = ref(0) + const dataPathSpan = ref(0) + const paramsSpan = ref(0) + + const setFlag = () => { + model.isProjects = model.mlflowTaskType === 'MLflow Projects' ? true : false + } + + const resetSpan = () => { + experimentNameSpan.value = model.isProjects ? 12 : 0 + mlflowJobTypeSpan.value = model.isProjects ? 12 : 0 + paramsSpan.value = model.isProjects ? 24 : 0 + registerModelSpan.value = + model.isProjects && model.mlflowJobType != 'CustomProject' ? 6 : 0 + dataPathSpan.value = + model.isProjects && model.mlflowJobType != 'CustomProject' ? 24 : 0 + } + + watch( + () => [model.mlflowTaskType, model.mlflowJobType], + () => { + setFlag() + resetSpan() + } + ) + + watch( + () => [model.registerModel], + () => { + modelNameSpan.value = model.isProjects && model.registerModel ? 6 : 0 + } + ) + + setFlag() + resetSpan() + + return [ + { + type: 'select', + field: 'mlflowJobType', + name: t('project.node.mlflow_jobType'), + span: mlflowJobTypeSpan, + options: MLFLOW_JOB_TYPE + }, + { + type: 'input', + field: 'experimentName', + name: t('project.node.mlflow_experimentName'), + span: experimentNameSpan, + props: { + placeholder: t('project.node.mlflow_experimentName_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: false + } + }, + { + type: 'switch', + field: 'registerModel', + name: t('project.node.mlflow_registerModel'), + span: registerModelSpan + }, + { + type: 'input', + field: 'modelName', + name: t('project.node.mlflow_modelName'), + span: modelNameSpan, + props: { + placeholder: t('project.node.mlflow_modelName_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: false + } + }, + { + type: 'input', + field: 'dataPath', + name: t('project.node.mlflow_dataPath'), + span: dataPathSpan, + props: { + placeholder: t('project.node.mlflow_dataPath_tips') + } + }, + { + type: 'input', + field: 'params', + name: t('project.node.mlflow_params'), + span: paramsSpan, + props: { + placeholder: t('project.node.mlflow_params_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: false + } + }, + ...useBasicAlgorithm(model), + ...useAutoML(model), + ...useCustomProject(model) + ] +} + +export function useBasicAlgorithm(model: { + [field: string]: any +}): IJsonItem[] { + const { t } = useI18n() + + const algorithmSpan = ref(0) + const searchParamsSpan = ref(0) + + const setFlag = () => { + model.isBasicAlgorithm = + model.mlflowJobType === 'BasicAlgorithm' && + model.mlflowTaskType === 'MLflow Projects' + ? true + : false + } + + const resetSpan = () => { + algorithmSpan.value = model.isBasicAlgorithm ? 24 : 0 + searchParamsSpan.value = model.isBasicAlgorithm ? 24 : 0 + } + + watch( + () => [model.mlflowTaskType, model.mlflowJobType], + () => { + setFlag() + resetSpan() + } + ) + setFlag() + resetSpan() + + return [ + { + type: 'select', + field: 'algorithm', + name: t('project.node.mlflow_algorithm'), + span: algorithmSpan, + options: ALGORITHM + }, + { + type: 'input', + field: 'searchParams', + name: t('project.node.mlflow_searchParams'), + props: { + placeholder: t('project.node.mlflow_searchParams_tips') + }, + span: searchParamsSpan, + validate: { + trigger: ['input', 'blur'], + required: false + } + } + ] +} + +export function useAutoML(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const automlToolSpan = ref(0) + + const setFlag = () => { + model.isAutoML = + model.mlflowJobType === 'AutoML' && + model.mlflowTaskType === 'MLflow Projects' + ? true + : false + } + + const resetSpan = () => { + automlToolSpan.value = model.isAutoML ? 12 : 0 + } + + watch( + () => [model.mlflowTaskType, model.mlflowJobType], + () => { + setFlag() + resetSpan() + } + ) + + setFlag() + resetSpan() + + return [ + { + type: 'select', + field: 'automlTool', + name: t('project.node.mlflow_automlTool'), + span: automlToolSpan, + options: AutoMLTOOL + } + ] +} + +export function useCustomProject(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const mlflowProjectRepositorySpan = ref(0) + const mlflowProjectVersionSpan = ref(0) + const customParamsSpan = ref(0) + + const setFlag = () => { + model.isCustomProject = + model.mlflowJobType === 'CustomProject' && + model.mlflowTaskType === 'MLflow Projects' + ? true + : false + } + + const resetSpan = () => { + mlflowProjectRepositorySpan.value = model.isCustomProject ? 24 : 0 + mlflowProjectVersionSpan.value = model.isCustomProject ? 12 : 0 + customParamsSpan.value = model.isCustomProject ? 24 : 0 + } + + watch( + () => [model.mlflowTaskType, model.mlflowJobType], + () => { + setFlag() + resetSpan() + } + ) + + setFlag() + resetSpan() + + return [ + { + type: 'input', + field: 'mlflowProjectRepository', + name: t('project.node.mlflowProjectRepository'), + span: mlflowProjectRepositorySpan, + props: { + placeholder: t('project.node.mlflowProjectRepository_tips') + } + }, + { + type: 'input', + field: 'mlflowProjectVersion', + name: t('project.node.mlflowProjectVersion'), + span: mlflowProjectVersionSpan, + props: { + placeholder: t('project.node.mlflowProjectVersion_tips') + } + } + ] +} + +export const MLFLOW_JOB_TYPE = [ + { + label: 'Custom Project', + value: 'CustomProject' + }, + { + label: 'AutoML', + value: 'AutoML' + }, + { + label: 'BasicAlgorithm', + value: 'BasicAlgorithm' + } +] +export const ALGORITHM = [ + { + label: 'svm', + value: 'svm' + }, + { + label: 'lr', + value: 'lr' + }, + { + label: 'lightgbm', + value: 'lightgbm' + }, + { + label: 'xgboost', + value: 'xgboost' + } +] +export const AutoMLTOOL = [ + { + label: 'flaml', + value: 'flaml' + }, + { + label: 'autosklearn', + value: 'autosklearn' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow.ts new file mode 100644 index 0000000000..efed24661f --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mlflow.ts @@ -0,0 +1,69 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' +import { useMlflowProjects, useMlflowModels } from '.' +import { useCustomParams, useResources } from '.' + +export const MLFLOW_TASK_TYPE = [ + { + label: 'MLflow Models', + value: 'MLflow Models' + }, + { + label: 'MLflow Projects', + value: 'MLflow Projects' + } +] + +export function useMlflow(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'input', + field: 'mlflowTrackingUri', + name: t('project.node.mlflow_mlflowTrackingUri'), + span: 12, + props: { + placeholder: t('project.node.mlflow_mlflowTrackingUri_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: false, + validator(validate: any, value: string) { + if (!value) { + return new Error( + t('project.node.mlflow_mlflowTrackingUri_error_tips') + ) + } + } + } + }, + { + type: 'select', + field: 'mlflowTaskType', + name: t('project.node.mlflow_taskType'), + span: 12, + options: MLFLOW_TASK_TYPE + }, + ...useMlflowProjects(model), + ...useMlflowModels(model), + useResources(), + ...useCustomParams({ model, field: 'localParams', isSimple: true }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mr.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mr.ts new file mode 100644 index 0000000000..9850db57c2 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-mr.ts @@ -0,0 +1,108 @@ +/* + * 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 { computed } from 'vue' +import { useI18n } from 'vue-i18n' +import { useCustomParams, useMainJar, useResources, useYarnQueue } from '.' +import type { IJsonItem } from '../types' + +export function useMr(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const mainClassSpan = computed(() => + model.programType === 'PYTHON' || model.programType === 'SQL' ? 0 : 24 + ) + + return [ + { + type: 'select', + field: 'programType', + span: 12, + name: t('project.node.program_type'), + options: PROGRAM_TYPES, + props: { + 'on-update:value': () => { + model.mainJar = null + model.mainClass = '' + } + }, + value: model.programType + }, + { + type: 'input', + field: 'mainClass', + span: mainClassSpan, + name: t('project.node.main_class'), + props: { + placeholder: t('project.node.main_class_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: model.programType !== 'PYTHON', + validator(validate: any, value: string) { + if (model.programType !== 'PYTHON' && !value) { + return new Error(t('project.node.main_class_tips')) + } + } + } + }, + useMainJar(model), + { + type: 'input', + field: 'appName', + name: t('project.node.app_name'), + props: { + placeholder: t('project.node.app_name_tips') + } + }, + useYarnQueue(), + { + type: 'input', + field: 'mainArgs', + name: t('project.node.main_arguments'), + props: { + type: 'textarea', + placeholder: t('project.node.main_arguments_tips') + } + }, + { + type: 'input', + field: 'others', + name: t('project.node.option_parameters'), + props: { + type: 'textarea', + placeholder: t('project.node.option_parameters_tips') + } + }, + useResources(), + ...useCustomParams({ model, field: 'localParams', isSimple: true }) + ] +} + +export const PROGRAM_TYPES = [ + { + label: 'JAVA', + value: 'JAVA' + }, + { + label: 'SCALA', + value: 'SCALA' + }, + { + label: 'PYTHON', + value: 'PYTHON' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-name.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-name.ts new file mode 100644 index 0000000000..8133e6a81e --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-name.ts @@ -0,0 +1,38 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useName(from?: number): IJsonItem { + const { t } = useI18n() + return { + type: 'input', + field: 'name', + class: 'input-node-name', + name: from === 1 ? t('project.node.task_name') : t('project.node.name'), + props: { + placeholder: t('project.node.name_tips'), + maxLength: 100 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + message: t('project.node.name_tips') + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-namespace.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-namespace.ts new file mode 100644 index 0000000000..a00389ae1b --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-namespace.ts @@ -0,0 +1,72 @@ +/* + * 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 { IJsonItem } from '../types' +import { useI18n } from 'vue-i18n' +import { onMounted, ref, VNodeChild } from 'vue' +import { getAllNamespaces } from '@/service/modules/k8s-namespace' +import { SelectOption } from 'naive-ui' + +export function useNamespace(): IJsonItem { + const { t } = useI18n() + + const options = ref([]) + const loading = ref(false) + + const getNamespaceList = async () => { + if (loading.value) return + loading.value = true + const totalList = await getAllNamespaces() + options.value = (totalList || []).map( + (item: { id: string; namespace: string; clusterName: string }) => ({ + label: `${item.namespace}(${item.clusterName})`, + value: JSON.stringify({ + name: item.namespace, + cluster: item.clusterName + }) + }) + ) + loading.value = false + } + + onMounted(() => { + getNamespaceList() + }) + + const renderLabel = (option: SelectOption): VNodeChild => { + if (option.type === 'group') return option.label as string + return [option.label as string] + } + + return { + type: 'select', + field: 'namespace', + name: t('project.node.namespace_cluster'), + props: { + loading, + 'render-label': renderLabel, + clearable: true + }, + options: [ + { + type: 'group', + label: t('project.node.namespace_cluster'), + key: t('project.node.namespace_cluster'), + children: options as any + } + ] + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-node-selectors.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-node-selectors.ts new file mode 100644 index 0000000000..48ca120127 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-node-selectors.ts @@ -0,0 +1,117 @@ +/* + * 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 } from 'vue' +import { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useNodeSelectors({ + model, + field, + name, + span = 24 +}: { + model: { [field: string]: any } + field: string + name?: string + span?: Ref | number +}): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'custom-parameters', + field: field, + name: t(`project.node.${name}`), + class: 'btn-custom-parameters', + span, + children: [ + { + type: 'input', + field: 'key', + span: 8, + class: 'node-selector-label-name', + props: { + placeholder: t('project.node.expression_name_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.expression_name_tips')) + } + + const sameItems = model[field].filter( + (item: { label: string }) => item.label === value + ) + + if (sameItems.length > 1) { + return new Error(t('project.node.label_repeat')) + } + } + } + }, + { + type: 'select', + field: 'operator', + span: 4, + options: OPERATOR_LIST, + value: 'In' + }, + { + type: 'input', + field: 'values', + span: 10, + class: 'node-selector-label-value', + props: { + placeholder: t('project.node.expression_value_tips'), + maxLength: 256, + disabled: false + } + } + ] + } + ] +} + +export const OPERATOR_LIST = [ + { + value: 'In', + label: 'In' + }, + { + value: 'NotIn', + label: 'NotIn' + }, + { + value: 'Exists', + label: 'Exists' + }, + { + value: 'DoesNotExist', + label: 'DoesNotExist' + }, + { + value: 'Gt', + label: 'Gt' + }, + { + value: 'Lt', + label: 'Lt' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-openmldb.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-openmldb.ts new file mode 100644 index 0000000000..742d404900 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-openmldb.ts @@ -0,0 +1,87 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { useCustomParams, useResources } from '.' +import type { IJsonItem } from '../types' + +export function useOpenmldb(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const options = [ + { + label: t('project.node.openmldb_execute_mode_offline'), + value: 'offline' + }, + { + label: t('project.node.openmldb_execute_mode_online'), + value: 'online' + } + ] + return [ + { + type: 'input', + field: 'zk', + name: t('project.node.openmldb_zk_address'), + props: { + placeholder: t('project.node.openmldb_zk_address_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.openmldb_zk_address_tips')) + } + } + } + }, + { + type: 'input', + field: 'zkPath', + name: t('project.node.openmldb_zk_path'), + props: { + placeholder: t('project.node.openmldb_zk_path_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.openmldb_zk_path_tips')) + } + } + } + }, + { + type: 'radio', + field: 'executeMode', + name: t('project.node.openmldb_execute_mode'), + options: options + }, + { + type: 'editor', + field: 'sql', + name: t('project.node.sql_statement'), + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.sql_empty_tips') + } + }, + useResources(), + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-pre-tasks.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-pre-tasks.ts new file mode 100644 index 0000000000..80bd285e21 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-pre-tasks.ts @@ -0,0 +1,47 @@ +/* + * 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, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { useTaskNodeStore } from '@/store/project/task-node' +import type { IJsonItem } from '../types' + +export function usePreTasks(): IJsonItem { + const { t } = useI18n() + const taskStore = useTaskNodeStore() + const options = ref(taskStore.getPreTaskOptions) + + watch( + () => taskStore.getPreTaskOptions, + (value) => { + options.value = value + } + ) + + return { + type: 'select', + field: 'preTasks', + span: 24, + class: 'pre-tasks-model', + name: t('project.node.pre_tasks'), + props: { + multiple: true, + filterable: true + }, + options + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-procedure.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-procedure.ts new file mode 100644 index 0000000000..1c0b4f99a3 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-procedure.ts @@ -0,0 +1,41 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { useCustomParams } from '.' +import type { IJsonItem } from '../types' + +export function useProcedure(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'editor', + field: 'method', + name: t('project.node.procedure_method'), + props: { + language: 'sql', + placeholder: t('project.node.procedure_method_tips') + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.procedure_method_tips') + } + }, + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-process-name.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-process-name.ts new file mode 100644 index 0000000000..f9cdccc224 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-process-name.ts @@ -0,0 +1,96 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { + querySimpleList, + queryProcessDefinitionByCode +} from '@/service/modules/process-definition' +import { useTaskNodeStore } from '@/store/project/task-node' +import type { IJsonItem } from '../types' + +export function useProcessName({ + model, + projectCode, + isCreate, + from, + processName, + taskCode +}: { + model: { [field: string]: any } + projectCode: number + isCreate: boolean + from?: number + processName?: number + taskCode?: number +}): IJsonItem { + const { t } = useI18n() + const taskStore = useTaskNodeStore() + const options = ref([] as { label: string; value: string }[]) + const loading = ref(false) + + const getProcessList = async () => { + if (loading.value) return + loading.value = true + const res = await querySimpleList(projectCode) + options.value = res.map((option: { name: string; code: number }) => ({ + label: option.name, + value: option.code + })) + loading.value = false + } + const getProcessListByCode = async (processCode: number) => { + if (!processCode) return + const res = await queryProcessDefinitionByCode(processCode, projectCode) + model.definition = res + taskStore.updateDefinition(res, taskCode) + } + + const onChange = (code: number) => { + getProcessListByCode(code) + } + + onMounted(() => { + if (from === 1 && processName) { + getProcessListByCode(processName) + } + getProcessList() + }) + + return { + type: 'select', + field: 'processName', + span: 24, + name: t('project.node.workflow_name'), + props: { + loading: loading, + disabled: !isCreate, + 'on-update:value': onChange + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.workflow_name_tips')) + } + } + }, + options: options + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-pytorch.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-pytorch.ts new file mode 100644 index 0000000000..7eeebab581 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-pytorch.ts @@ -0,0 +1,139 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' +import { watch, ref } from 'vue' +import { useCustomParams, useResources } from '.' + +export function usePytorch(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const isCreateEnvironmentSpan = ref(0) + const pythonPathSpan = ref(0) + const pythonEnvToolSpan = ref(0) + const pythonCommandSpan = ref(0) + const requirementsSpan = ref(0) + const condaPythonVersionSpan = ref(0) + + const setFlag = () => { + model.showCreateEnvironment = model.isCreateEnvironment && model.otherParams + model.showCreateConda = + model.showCreateEnvironment && model.pythonEnvTool === 'conda' + ? true + : false + model.showCreateEnv = + model.showCreateEnvironment && model.pythonEnvTool === 'virtualenv' + ? true + : false + } + + const resetSpan = () => { + isCreateEnvironmentSpan.value = model.otherParams ? 12 : 0 + pythonPathSpan.value = model.otherParams ? 24 : 0 + pythonEnvToolSpan.value = model.showCreateEnvironment ? 12 : 0 + pythonCommandSpan.value = + ~model.showCreateEnvironment & model.otherParams ? 12 : 0 + requirementsSpan.value = model.showCreateEnvironment ? 24 : 0 + condaPythonVersionSpan.value = model.showCreateConda ? 24 : 0 + } + + watch( + () => [model.isCreateEnvironment, model.pythonEnvTool, model.otherParams], + () => { + setFlag() + resetSpan() + } + ) + + return [ + { + type: 'input', + field: 'script', + name: t('project.node.pytorch_script'), + span: 24 + }, + { + type: 'input', + field: 'scriptParams', + name: t('project.node.pytorch_script_params'), + span: 24 + }, + { + type: 'switch', + field: 'otherParams', + name: t('project.node.pytorch_other_params'), + span: 24 + }, + { + type: 'input', + field: 'pythonPath', + name: t('project.node.pytorch_python_path'), + span: pythonPathSpan + }, + { + type: 'switch', + field: 'isCreateEnvironment', + name: t('project.node.pytorch_is_create_environment'), + span: isCreateEnvironmentSpan + }, + { + type: 'input', + field: 'pythonCommand', + name: t('project.node.pytorch_python_command'), + span: pythonCommandSpan, + props: { + placeholder: t('project.node.pytorch_python_command_tips') + } + }, + { + type: 'select', + field: 'pythonEnvTool', + name: t('project.node.pytorch_python_env_tool'), + span: pythonEnvToolSpan, + options: PYTHON_ENV_TOOL + }, + { + type: 'input', + field: 'requirements', + name: t('project.node.pytorch_requirements'), + span: requirementsSpan + }, + { + type: 'input', + field: 'condaPythonVersion', + name: t('project.node.pytorch_conda_python_version'), + span: condaPythonVersionSpan, + props: { + placeholder: t('project.node.pytorch_conda_python_version_tips') + } + }, + useResources(), + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} + +export const PYTHON_ENV_TOOL = [ + { + label: 'conda', + value: 'conda' + }, + { + label: 'virtualenv', + value: 'virtualenv' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-queue.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-queue.ts new file mode 100644 index 0000000000..034aba1abd --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-queue.ts @@ -0,0 +1,32 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useYarnQueue(): IJsonItem { + const { t } = useI18n() + + return { + type: 'input', + field: 'yarnQueue', + name: t('project.node.yarn_queue'), + span: 12, + props: { + placeholder: t('project.node.yarn_queue_tips') + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-relation-custom-params.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-relation-custom-params.ts new file mode 100644 index 0000000000..c194f83a6d --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-relation-custom-params.ts @@ -0,0 +1,99 @@ +/* + * 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 { computed, watchEffect } from 'vue' +import { useI18n } from 'vue-i18n' +import styles from '../index.module.scss' +import type { IJsonItem } from '../types' + +export function useRelationCustomParams({ + model, + children, + childrenField, + name +}: { + model: { + [field: string]: any + } + children: IJsonItem + childrenField: string + name: string +}): IJsonItem[] { + const { t } = useI18n() + const firstLevelRelationSpan = computed(() => + model.dependTaskList.length ? 3 : 0 + ) + + watchEffect(() => { + model.dependTaskList.forEach( + (item: { [childrenField: string]: [] }, i: number) => { + if (item[childrenField].length === 0) { + model.dependTaskList.splice(i, 1) + } + } + ) + }) + return [ + { + type: 'custom', + name: t(`project.node.${name}`), + field: 'relationLabel', + span: 24, + class: styles['relaction-label'] + }, + { + type: 'switch', + field: 'relation', + props: { + round: false, + 'checked-value': 'AND', + 'unchecked-value': 'OR', + size: 'small' + }, + slots: { + checked: () => t('project.node.and'), + unchecked: () => t('project.node.or') + }, + span: firstLevelRelationSpan, + class: styles['relaction-switch'] + }, + { + type: 'custom-parameters', + field: 'dependTaskList', + span: 20, + children: [ + { + type: 'switch', + field: 'relation', + props: { + round: false, + 'checked-value': 'AND', + 'unchecked-value': 'OR', + size: 'small' + }, + slots: { + checked: () => t('project.node.and'), + unchecked: () => t('project.node.or') + }, + span: 4, + value: 'AND', + class: styles['relaction-switch'] + }, + children + ] + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-remote-shell.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-remote-shell.ts new file mode 100644 index 0000000000..a3a6f55e46 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-remote-shell.ts @@ -0,0 +1,37 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { useCustomParams } from '.' +import type { IJsonItem } from '../types' + +export function useRemoteShell(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'editor', + field: 'rawScript', + name: t('project.node.script'), + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.script_tips') + } + }, + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-resource-limit.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-resource-limit.ts new file mode 100644 index 0000000000..15c804113e --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-resource-limit.ts @@ -0,0 +1,45 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useResourceLimit(): IJsonItem[] { + const { t } = useI18n() + return [ + { + type: 'input-number', + field: 'cpuQuota', + name: t('project.node.cpu_quota'), + span: 12, + slots: { + suffix: () => '%' + }, + props: { min: -1 } + }, + { + type: 'input-number', + field: 'memoryMax', + name: t('project.node.memory_max'), + span: 12, + slots: { + suffix: () => t('project.node.mb') + }, + props: { min: -1 } + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-resources.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-resources.ts new file mode 100644 index 0000000000..90ba0a40a7 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-resources.ts @@ -0,0 +1,184 @@ +/* + * 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, Ref, isRef } from 'vue' +import { useI18n } from 'vue-i18n' +import { queryResourceList } from '@/service/modules/resources' +import { useTaskNodeStore } from '@/store/project/task-node' +import utils from '@/utils' +import type { IJsonItem, IResource } from '../types' + +export function useResources( + span: number | Ref = 24, + required: boolean | Ref = false, + limit: number | Ref = -1 +): IJsonItem { + const { t } = useI18n() + + interface ResourceOption { + name: string + fullName: string + dirctory: boolean + disable: boolean + children?: ResourceOption[] + } + + const resourcesOptions = ref([]) + const resourcesLoading = ref(false) + + const taskStore = useTaskNodeStore() + + const getResources = async () => { + if (taskStore.resources.length) { + resourcesOptions.value = taskStore.resources + return + } + if (resourcesLoading.value) return + resourcesLoading.value = true + const res = await queryResourceList({ type: 'FILE', fullName: '' }) + utils.removeUselessChildren(res) + resourcesOptions.value = res || [] + resourcesLoading.value = false + taskStore.updateResource(res) + } + + const validateResourceExist = ( + fullName: string, + parentDir: string[], + resources: ResourceOption[] + ): boolean => { + const isDirectory = (res: ResourceOption): boolean => { + return res.dirctory && new RegExp(`^${res.fullName}`).test(fullName) + } + + const processDirectory = (res: ResourceOption): boolean => { + if (!res.children) { + res.children = [] + } + parentDir.push(res.name) + return validateResourceExist( + fullName, + parentDir, + res.children as ResourceOption[] + ) + } + + if (resources.length > 0) { + for (const res of resources) { + if (isDirectory(res)) { + return processDirectory(res) + } + + if (res.fullName === fullName) { + return true + } + } + } + addResourceNode(fullName, parentDir, resources) + return false + } + + const addResourceNode = ( + fullName: string, + parentDir: string[], + resources: ResourceOption[] + ) => { + const resourceNode = { + fullName: fullName, + name: getResourceDirAfter(fullName, parentDir), + dirctory: false, + disable: true + } + resources.push(resourceNode) + } + + const getResourceDirAfter = (fullName: string, parentDir: string[]) => { + const dirctory = '/resources/' + parentDir.join('') + const delimiterIndex = fullName.indexOf(dirctory) + if (delimiterIndex !== -1) { + return fullName.substring(delimiterIndex + dirctory.length) + } else { + return fullName + } + } + + onMounted(() => { + getResources() + }) + + return { + type: 'tree-select', + field: 'resourceList', + name: t('project.node.resources'), + span: span, + options: resourcesOptions, + props: { + multiple: true, + checkable: true, + cascade: true, + showPath: true, + filterable: true, + clearFilterAfterSelect: false, + checkStrategy: 'child', + placeholder: t('project.node.resources_tips'), + keyField: 'fullName', + labelField: 'name', + disabledField: 'disable', + loading: resourcesLoading + }, + validate: { + trigger: ['blur'], + required: required, + validator(validate: any, value: string[]) { + if (value) { + const errorNames: string[] = [] + value.forEach((item) => { + if ( + !validateResourceExist( + item, + [], + resourcesOptions.value as ResourceOption[] + ) + ) { + errorNames.push(item) + } + }) + if (errorNames.length > 0) { + let errorName = ': ' + errorNames.forEach((name) => { + value.splice(value.indexOf(name), 1) + errorName += getResourceDirAfter(name, []) + ';' + }) + return new Error( + t('project.node.useless_resources_tips') + errorName + ) + } + } + + if (isRef(required) ? required.value : required) { + if (!value || value.length == 0) { + return new Error(t('project.node.resources_tips')) + } + const limit_ = isRef(limit) ? limit.value : limit + if (limit_ > 0 && value.length > limit_) { + return new Error(t('project.node.resources_limit_tips') + limit) + } + } + } + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-rules.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-rules.ts new file mode 100644 index 0000000000..71fc56cc8e --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-rules.ts @@ -0,0 +1,304 @@ +/* + * 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, computed } from 'vue' +import { useI18n } from 'vue-i18n' +import { + queryRuleList, + getRuleFormCreateJson, + getDatasourceOptionsById +} from '@/service/modules/data-quality' +import { + getDatasourceDatabasesById, + getDatasourceTablesById, + getDatasourceTableColumnsById +} from '@/service/modules/data-source' +import type { IJsonItem, IResponseJsonItem, IJsonItemParams } from '../types' + +export function useRules( + model: { [field: string]: any }, + updateRules: (items: IJsonItem[], len: number) => void +): IJsonItem[] { + const { t } = useI18n() + const rules = ref([]) + const ruleLoading = ref(false) + const srcDatasourceOptions = ref([] as { label: string; value: number }[]) + const srcDatabaseOptions = ref([] as { label: string; value: number }[]) + const srcTableOptions = ref([] as { label: string; value: number }[]) + const srcTableColumnOptions = ref([] as { label: string; value: number }[]) + const targetDatasourceOptions = ref([] as { label: string; value: number }[]) + const targetDatabaseOptions = ref([] as { label: string; value: number }[]) + const targetTableOptions = ref([] as { label: string; value: string }[]) + const targetTableColumnOptions = ref([] as { label: string; value: number }[]) + const writerDatasourceOptions = ref([] as { label: string; value: number }[]) + + const fixValueSpan = computed(() => (model.comparison_type === 1 ? 24 : 0)) + + let preItemLen = 0 + + const getRuleList = async () => { + if (ruleLoading.value) return + ruleLoading.value = true + const result = await queryRuleList() + rules.value = result.map((item: { id: number; name: string }) => { + let name = '' + if (item.name) { + name = item.name.replace('$t(', '').replace(')', '') + } + return { + value: item.id, + label: name ? t(`project.node.${name}`) : '' + } + }) + ruleLoading.value = false + } + + const getRuleById = async (ruleId: number) => { + if (ruleLoading.value) return + ruleLoading.value = true + const result = await getRuleFormCreateJson(ruleId) + const items = JSON.parse(result).map((item: IResponseJsonItem) => + formatResponseJson(item) + ) + updateRules(items, preItemLen) + preItemLen = items.length + ruleLoading.value = false + } + + const formatResponseJson = ( + responseItem: IResponseJsonItem + ): IJsonItemParams => { + const item: IJsonItemParams = { + field: responseItem.field, + options: responseItem.options, + validate: responseItem.validate, + props: responseItem.props, + value: responseItem.value + } + item.props.filterable = true + const name = responseItem.name?.replace('$t(', '').replace(')', '') + item.name = name ? t(`project.node.${name}`) : '' + + if (responseItem.type !== 'group') { + item.type = responseItem.type + } else { + item.type = 'custom-parameters' + item.children = item.props.rules.map((child: IJsonItemParams) => { + child.span = Math.floor(22 / item.props.rules.length) + return child + }) + model[item.field] = model[item.field] || [] + delete item.props.rules + } + if (responseItem.emit) { + responseItem.emit.forEach((emit) => { + if (emit === 'change') { + item.props.onUpdateValue = (value: string | number) => { + onFieldChange(value, item.field, true) + } + } + }) + } + if (responseItem.props.placeholder) { + item.props.placeholder = t( + 'project.node.' + + responseItem.props.placeholder + .split(' ') + .join('_') + .split(',') + .join('') + .toLowerCase() + ) + } + if (item.field === 'src_datasource_id') { + item.options = srcDatasourceOptions + } + if (item.field === 'src_database') { + item.options = srcDatabaseOptions + } + if (item.field === 'target_datasource_id') { + item.options = targetDatasourceOptions + } + if (item.field === 'target_database') { + item.options = targetDatabaseOptions + } + if (item.field === 'writer_datasource_id') { + item.options = writerDatasourceOptions + } + if (item.field === 'src_table') { + item.options = srcTableOptions + item.props.filterable = true + } + if (item.field === 'target_table') { + item.options = targetTableOptions + item.props.filterable = true + } + if (item.field === 'src_field') { + item.options = srcTableColumnOptions + } + if (item.field === 'target_field') { + item.options = targetTableColumnOptions + } + + if (model[item.field] !== void 0) { + onFieldChange(model[item.field], item.field, false) + item.value = model[item.field] + } + + return item + } + const onFieldChange = async ( + value: string | number, + field: string, + reset: boolean + ) => { + if (field === 'src_connector_type' && typeof value === 'number') { + const result = await getDatasourceOptionsById(value) + srcDatasourceOptions.value = result || [] + if (reset) { + srcDatabaseOptions.value = [] + srcTableOptions.value = [] + srcTableColumnOptions.value = [] + model.src_datasource_id = null + model.src_database = null + model.src_table = null + model.src_field = null + } + return + } + if (field === 'target_connector_type' && typeof value === 'number') { + const result = await getDatasourceOptionsById(value) + targetDatasourceOptions.value = result || [] + if (reset) { + targetDatabaseOptions.value = [] + targetTableOptions.value = [] + targetTableColumnOptions.value = [] + model.target_datasource_id = null + model.target_database = null + model.target_table = null + model.target_field = null + } + return + } + if (field === 'writer_connector_type' && typeof value === 'number') { + const result = await getDatasourceOptionsById(value) + writerDatasourceOptions.value = result || [] + if (reset) { + model.writer_datasource_id = null + } + return + } + if (field === 'src_datasource_id' && typeof value === 'number') { + const result = await getDatasourceDatabasesById(value) + srcDatabaseOptions.value = result || [] + if (reset) { + srcTableOptions.value = [] + srcTableColumnOptions.value = [] + model.src_database = null + model.src_table = null + model.src_field = null + } + } + if (field === 'target_datasource_id' && typeof value === 'number') { + const result = await getDatasourceDatabasesById(value) + targetDatabaseOptions.value = result || [] + if (reset) { + targetTableOptions.value = [] + targetTableColumnOptions.value = [] + model.target_database = null + model.target_table = null + model.target_field = null + } + } + + if (field === 'src_database' && typeof value === 'string') { + const result = await getDatasourceTablesById( + model.src_datasource_id, + value + ) + srcTableOptions.value = result || [] + if (reset) { + srcTableColumnOptions.value = [] + model.src_table = null + model.src_field = null + } + } + + if (field === 'target_database' && typeof value === 'string') { + const result = await getDatasourceTablesById( + model.target_datasource_id, + value + ) + targetTableOptions.value = result || [] + if (reset) { + targetTableColumnOptions.value = [] + model.target_table = null + model.target_field = null + } + } + + if (field === 'src_table' && typeof value === 'string') { + const result = await getDatasourceTableColumnsById( + model.src_datasource_id, + model.src_database, + value + ) + srcTableColumnOptions.value = result || [] + if (reset) { + model.src_field = null + } + } + if (field === 'target_table' && typeof value === 'string') { + const result = await getDatasourceTableColumnsById( + model.target_datasource_id, + model.target_database, + value + ) + targetTableColumnOptions.value = result || [] + if (reset) { + model.target_field = null + } + } + } + + onMounted(async () => { + await getRuleList() + await getRuleById(model.ruleId) + }) + + return [ + { + type: 'select', + field: 'ruleId', + name: t('project.node.rule_name'), + props: { + loading: ruleLoading, + filterable: true, + onUpdateValue: getRuleById + }, + options: rules + }, + { + type: 'input', + field: 'comparison_name', + name: t('project.node.fix_value'), + props: { + placeholder: t('project.node.fix_value') + }, + span: fixValueSpan + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-run-flag.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-run-flag.ts new file mode 100644 index 0000000000..ab61b88ce9 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-run-flag.ts @@ -0,0 +1,40 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useRunFlag(): IJsonItem { + const { t } = useI18n() + const options = [ + { + label: t('project.node.normal'), + value: 'YES' + }, + { + label: t('project.node.prohibition_execution'), + value: 'NO' + } + ] + return { + type: 'radio', + field: 'flag', + name: t('project.node.run_flag'), + options: options, + span: 12 + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sagemaker.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sagemaker.ts new file mode 100644 index 0000000000..ad78353727 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sagemaker.ts @@ -0,0 +1,37 @@ +/* + * 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 { IJsonItem } from '../types' +import { useCustomParams } from '.' + +export function useSagemaker(model: { [field: string]: any }): IJsonItem[] { + return [ + { + type: 'editor', + field: 'sagemakerRequestJson', + name: 'SagemakerRequestJson', + props: { + language: 'json' + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: 'requestJson' + } + }, + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sea-tunnel.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sea-tunnel.ts new file mode 100644 index 0000000000..7931e83049 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sea-tunnel.ts @@ -0,0 +1,230 @@ +/* + * 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 { computed, ref } from 'vue' +import { useI18n } from 'vue-i18n' +import { useDeployMode, useResources, useCustomParams } from '.' +import type { IJsonItem } from '../types' + +export function useSeaTunnel(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const configEditorSpan = computed(() => (model.useCustom ? 24 : 0)) + const resourceEditorSpan = computed(() => (model.useCustom ? 0 : 24)) + const flinkSpan = computed(() => + model.startupScript.includes('flink') ? 24 : 0 + ) + const deployModeSpan = computed(() => + model.startupScript.includes('spark') || + model.startupScript === 'seatunnel.sh' + ? 24 + : 0 + ) + const masterSpan = computed(() => + model.startupScript.includes('spark') && model.deployMode !== 'local' + ? 12 + : 0 + ) + const masterUrlSpan = computed(() => + model.startupScript.includes('spark') && + model.deployMode !== 'local' && + (model.master === 'SPARK' || model.master === 'MESOS') + ? 12 + : 0 + ) + const showClient = computed(() => model.startupScript.includes('spark')) + const showLocal = computed(() => model.startupScript === 'seatunnel.sh') + const othersSpan = computed(() => + model.startupScript.includes('flink') || + model.startupScript === 'seatunnel.sh' + ? 24 + : 0 + ) + + return [ + { + type: 'select', + field: 'startupScript', + span: 15, + name: t('project.node.startup_script'), + options: STARTUP_SCRIPT, + validate: { + trigger: ['input', 'blur'], + required: true, + message: t('project.node.startup_script_tips') + }, + props: { + 'on-update:value': (value: boolean) => { + if (value) { + if (model.startupScript === 'seatunnel.sh') { + model.deployMode = 'local' + } + if (model.startupScript.includes('spark')) { + model.deployMode = 'client' + } + } + } + } + }, + + // SeaTunnel flink parameter + { + type: 'select', + field: 'runMode', + name: t('project.node.run_mode'), + options: FLINK_RUN_MODE, + value: model.runMode, + span: flinkSpan + }, + { + type: 'input', + field: 'others', + name: t('project.node.option_parameters'), + span: othersSpan, + props: { + type: 'textarea', + placeholder: t('project.node.option_parameters_tips') + } + }, + + // SeaTunnel spark parameter + useDeployMode(deployModeSpan, showClient, ref(true), showLocal), + { + type: 'select', + field: 'master', + name: t('project.node.sea_tunnel_master'), + options: masterTypeOptions, + value: model.master, + span: masterSpan + }, + { + type: 'input', + field: 'masterUrl', + name: t('project.node.sea_tunnel_master_url'), + value: model.masterUrl, + span: masterUrlSpan, + props: { + placeholder: t('project.node.sea_tunnel_master_url_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: masterUrlSpan.value !== 0, + validator(validate: any, value: string) { + if (masterUrlSpan.value !== 0 && !value) { + return new Error(t('project.node.sea_tunnel_master_url_tips')) + } + } + } + }, + + // SeaTunnel config parameter + { + type: 'switch', + field: 'useCustom', + name: t('project.node.custom_config') + }, + { + type: 'editor', + field: 'rawScript', + name: t('project.node.script'), + span: configEditorSpan, + validate: { + trigger: ['input', 'trigger'], + required: model.useCustom, + validator(validate: any, value: string) { + if (model.useCustom && !value) { + return new Error(t('project.node.script_tips')) + } + } + } + }, + useResources(resourceEditorSpan, true, 1), + ...useCustomParams({ model, field: 'localParams', isSimple: true }) + ] +} + +export const STARTUP_SCRIPT = [ + { + label: 'seatunnel.sh', + value: 'seatunnel.sh' + }, + { + label: 'start-seatunnel-flink-13-connector-v2.sh', + value: 'start-seatunnel-flink-13-connector-v2.sh' + }, + { + label: 'start-seatunnel-flink-15-connector-v2.sh', + value: 'start-seatunnel-flink-15-connector-v2.sh' + }, + { + label: 'start-seatunnel-flink-connector-v2.sh', + value: 'start-seatunnel-flink-connector-v2.sh' + }, + { + label: 'start-seatunnel-flink.sh', + value: 'start-seatunnel-flink.sh' + }, + { + label: 'start-seatunnel-spark-2-connector-v2.sh', + value: 'start-seatunnel-spark-2-connector-v2.sh' + }, + { + label: 'start-seatunnel-spark-3-connector-v2.sh', + value: 'start-seatunnel-spark-3-connector-v2.sh' + }, + { + label: 'start-seatunnel-spark-connector-v2.sh', + value: 'start-seatunnel-spark-connector-v2.sh' + }, + { + label: 'start-seatunnel-spark.sh', + value: 'start-seatunnel-spark.sh' + } +] + +export const FLINK_RUN_MODE = [ + { + label: 'none', + value: 'NONE' + }, + { + label: 'run', + value: 'RUN' + }, + { + label: 'run-application', + value: 'RUN_APPLICATION' + } +] + +export const masterTypeOptions = [ + { + label: 'yarn', + value: 'YARN' + }, + { + label: 'local', + value: 'LOCAL' + }, + { + label: 'spark://', + value: 'SPARK' + }, + { + label: 'mesos://', + value: 'MESOS' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-shell.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-shell.ts new file mode 100644 index 0000000000..9c9f171a1f --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-shell.ts @@ -0,0 +1,38 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { useCustomParams, useResources } from '.' +import type { IJsonItem } from '../types' + +export function useShell(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'editor', + field: 'rawScript', + name: t('project.node.script'), + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.script_tips') + } + }, + useResources(), + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-spark.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-spark.ts new file mode 100644 index 0000000000..ab89e69e6d --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-spark.ts @@ -0,0 +1,224 @@ +/* + * 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 { computed, ref, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { + useCustomParams, + useDeployMode, + useDriverCores, + useDriverMemory, + useExecutorNumber, + useExecutorMemory, + useExecutorCores, + useMainJar, + useNamespace, + useResources, + useYarnQueue +} from '.' +import type { IJsonItem } from '../types' + +export function useSpark(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const mainClassSpan = computed(() => + model.programType === 'PYTHON' || model.programType === 'SQL' ? 0 : 24 + ) + + const masterSpan = computed(() => + model.programType === 'PYTHON' || model.programType === 'SQL' ? 0 : 24 + ) + + const mainArgsSpan = computed(() => (model.programType === 'SQL' ? 0 : 24)) + + const rawScriptSpan = computed(() => + model.programType === 'SQL' && model.sqlExecutionType === 'SCRIPT' ? 24 : 0 + ) + + const showCluster = computed(() => model.programType !== 'SQL') + + const resourcesRequired = ref( + model.programType === 'SQL' && model.sqlExecutionType === 'FILE' + ) + + const resourcesLimit = computed(() => + model.programType === 'SQL' && model.sqlExecutionType === 'FILE' ? 1 : -1 + ) + + const sqlExecutionTypeSpan = computed(() => + model.programType === 'SQL' ? 12 : 0 + ) + + const SQL_EXECUTION_TYPES = [ + { + label: t('project.node.sql_execution_type_from_script'), + value: 'SCRIPT' + }, + { + label: t('project.node.sql_execution_type_from_file'), + value: 'FILE' + } + ] + + watch( + () => [model.sqlExecutionType, model.programType], + () => { + resourcesRequired.value = + model.programType === 'SQL' && model.sqlExecutionType === 'FILE' + } + ) + + return [ + { + type: 'select', + field: 'programType', + span: 12, + name: t('project.node.program_type'), + options: PROGRAM_TYPES, + props: { + 'on-update:value': () => { + model.mainJar = null + model.mainClass = '' + } + } + }, + { + type: 'select', + field: 'sqlExecutionType', + span: sqlExecutionTypeSpan, + name: t('project.node.sql_execution_type'), + options: SQL_EXECUTION_TYPES, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'input', + field: 'mainClass', + span: mainClassSpan, + name: t('project.node.main_class'), + props: { + placeholder: t('project.node.main_class_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: model.programType !== 'PYTHON' && model.programType !== 'SQL', + validator(validate: any, value: string) { + if ( + model.programType !== 'PYTHON' && + !value && + model.programType !== 'SQL' + ) { + return new Error(t('project.node.main_class_tips')) + } + } + } + }, + useMainJar(model), + { + type: 'editor', + field: 'rawScript', + span: rawScriptSpan, + name: t('project.node.script'), + props: { + language: 'sql' + }, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.script_tips') + } + }, + { + type: 'input', + field: 'master', + span: masterSpan, + name: t('project.node.master'), + props: { + placeholder: t('project.node.master_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: false, + validator(validate: any, value: string) { + if ( + model.programType !== 'PYTHON' && + !value && + model.programType !== 'SQL' + ) { + return new Error(t('project.node.master_tips')) + } + } + } + }, + useDeployMode(24, ref(true), showCluster), + useNamespace(), + { + type: 'input', + field: 'appName', + name: t('project.node.app_name'), + props: { + placeholder: t('project.node.app_name_tips') + } + }, + useDriverCores(), + useDriverMemory(), + useExecutorNumber(), + useExecutorMemory(), + useExecutorCores(), + useYarnQueue(), + { + type: 'input', + field: 'mainArgs', + span: mainArgsSpan, + name: t('project.node.main_arguments'), + props: { + type: 'textarea', + placeholder: t('project.node.main_arguments_tips') + } + }, + { + type: 'input', + field: 'others', + name: t('project.node.option_parameters'), + props: { + type: 'textarea', + placeholder: t('project.node.option_parameters_tips') + } + }, + useResources(24, resourcesRequired, resourcesLimit), + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} + +export const PROGRAM_TYPES = [ + { + label: 'JAVA', + value: 'JAVA' + }, + { + label: 'SCALA', + value: 'SCALA' + }, + { + label: 'PYTHON', + value: 'PYTHON' + }, + { + label: 'SQL', + value: 'SQL' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sql-type.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sql-type.ts new file mode 100644 index 0000000000..f54b922b00 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sql-type.ts @@ -0,0 +1,165 @@ +/* + * 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, computed, h } from 'vue' +import { useI18n } from 'vue-i18n' +import { listNormalAlertGroupById } from '@/service/modules/alert-group' +import styles from '../index.module.scss' +import type { IJsonItem } from '../types' + +export function useSqlType(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const querySpan = computed(() => (model.sqlType === '0' ? 6 : 0)) + const emailSpan = computed(() => + model.sqlType === '0' && model.sendEmail ? 24 : 0 + ) + const groups = ref([]) + const groupsLoading = ref(false) + const SQL_TYPES = [ + { + value: '0', + label: t('project.node.sql_type_query') + }, + { + value: '1', + label: t('project.node.sql_type_non_query') + } + ] + + const getGroups = async () => { + if (groupsLoading.value) return + groupsLoading.value = true + const res = await listNormalAlertGroupById() + groups.value = res.map((item: { id: number; groupName: string }) => ({ + label: item.groupName, + value: item.id + })) + groupsLoading.value = false + } + + onMounted(() => { + getGroups() + }) + + return [ + { + type: 'select', + field: 'sqlType', + span: 6, + name: t('project.node.sql_type'), + options: SQL_TYPES, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'switch', + field: 'sendEmail', + span: querySpan, + name: t('project.node.send_email') + }, + { + type: 'select', + field: 'displayRows', + span: querySpan, + name: t('project.node.log_display'), + options: DISPLAY_ROWS, + props: { + filterable: true, + tag: true + }, + validate: { + trigger: ['input', 'blur'], + validator(unuse, value) { + if (!/^\+?[1-9][0-9]*$/.test(value)) { + return new Error(t('project.node.integer_tips')) + } + } + } + }, + { + type: 'custom', + field: 'displayRowsTips', + span: querySpan, + widget: h( + 'div', + { class: styles['display-rows-tips'] }, + t('project.node.rows_of_result') + ) + }, + { + type: 'input', + field: 'title', + name: t('project.node.title'), + props: { + placeholder: t('project.node.title_tips') + }, + span: emailSpan, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(unuse, value) { + if (model.sendEmail && !value) + return new Error(t('project.node.title_tips')) + } + } + }, + { + type: 'select', + field: 'groupId', + name: t('project.node.alarm_group'), + options: groups, + span: emailSpan, + props: { + loading: groupsLoading, + placeholder: t('project.node.alarm_group_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(unuse, value) { + if (model.sendEmail && !value) + return new Error(t('project.node.alarm_group_tips')) + } + } + } + ] +} + +const DISPLAY_ROWS = [ + { + label: '1', + value: 1 + }, + { + label: '10', + value: 10 + }, + { + label: '25', + value: 25 + }, + { + label: '50', + value: 50 + }, + { + label: '100', + value: 100 + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sql.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sql.ts new file mode 100644 index 0000000000..46e489d40e --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sql.ts @@ -0,0 +1,76 @@ +/* + * 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 { computed } from 'vue' +import { useI18n } from 'vue-i18n' +import { useCustomParams } from '.' +import { useUdfs } from './use-udfs' +import type { IJsonItem } from '../types' + +export function useSql(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const hiveSpan = computed(() => (model.type === 'HIVE' ? 24 : 0)) + + return [ + { + type: 'input', + field: 'connParams', + name: t('project.node.sql_parameter'), + props: { + placeholder: + t('project.node.format_tips') + ' key1=value1;key2=value2...' + }, + span: hiveSpan + }, + { + type: 'editor', + field: 'sql', + name: t('project.node.sql_statement'), + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.sql_empty_tips') + }, + props: { + language: 'sql' + } + }, + useUdfs(model), + ...useCustomParams({ model, field: 'localParams', isSimple: false }), + { + type: 'multi-input', + field: 'preStatements', + name: t('project.node.pre_sql_statement'), + span: 22, + props: { + placeholder: t('project.node.sql_input_placeholder'), + type: 'textarea', + autosize: { minRows: 1 } + } + }, + { + type: 'multi-input', + field: 'postStatements', + name: t('project.node.post_sql_statement'), + span: 22, + props: { + placeholder: t('project.node.sql_input_placeholder'), + type: 'textarea', + autosize: { minRows: 1 } + } + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-datasource.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-datasource.ts new file mode 100644 index 0000000000..399c88b387 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-datasource.ts @@ -0,0 +1,107 @@ +/* + * 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 { onMounted, ref, Ref, watch } from 'vue' +import { queryDataSourceList } from '@/service/modules/data-source' +import { useI18n } from 'vue-i18n' +import type { IJsonItem, IDataBase } from '../types' +import type { TypeReq } from '@/service/modules/data-source/types' + +export function useDatasource( + model: { [field: string]: any }, + span: Ref, + fieldType: string, + fieldDatasource: string +): IJsonItem[] { + const { t } = useI18n() + const dataSourceList = ref([]) + const loading = ref(false) + const hadoopSourceTypes = ref(['HIVE', 'HDFS']) + const getDataSource = async (type: IDataBase) => { + if (hadoopSourceTypes.value.some((source) => source === type)) { + loading.value = false + return + } + loading.value = true + if (model.modelType === 'import') { + model.sourceMysqlDatasource = model.sourceMysqlDatasource + ? model.sourceMysqlDatasource + : '' + model.sourceMysqlType = type + } else { + model.sourceMysqlDatasource = model.targetMysqlDatasource + ? model.targetMysqlDatasource + : '' + model.targetMysqlType = type + } + const params = { type, testFlag: 0 } as TypeReq + const result = await queryDataSourceList(params) + dataSourceList.value = result.map((item: { name: string; id: number }) => ({ + label: item.name, + value: item.id + })) + loading.value = false + } + onMounted(() => { + getDataSource(model.sourceType) + }) + + watch( + () => [model.sourceType], + () => { + getDataSource(model.sourceType) + } + ) + + watch( + () => [model.targetType], + () => { + getDataSource(model.targetType) + } + ) + return [ + { + type: 'input', + field: fieldType, + name: t('project.node.datasource'), + span: 0, + validate: { + required: true + } + }, + { + type: 'select', + field: fieldDatasource, + name: t('project.node.datasource'), + span: span, + props: { + placeholder: t('project.node.datasource_tips'), + filterable: true, + loading + }, + options: dataSourceList, + validate: { + trigger: ['blur', 'input'], + validator(validate, value) { + if (!value) { + return new Error(t('project.node.datasource_tips')) + } + } + } + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-source-type.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-source-type.ts new file mode 100644 index 0000000000..d5554e7a14 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-source-type.ts @@ -0,0 +1,332 @@ +/* + * 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 { h, onMounted, Ref, ref, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { useDatasource } from './use-sqoop-datasource' +import { useCustomParams } from '.' +import styles from '../index.module.scss' +import type { IJsonItem, IOption, ModelType } from '../types' + +export function useSourceType( + model: { [field: string]: any }, + unCustomSpan: Ref +): IJsonItem[] { + const { t } = useI18n() + const rdbmsSpan = ref(24) + const tableSpan = ref(0) + const editorSpan = ref(24) + const columnSpan = ref(0) + const hiveSpan = ref(0) + const hdfsSpan = ref(0) + const datasourceSpan = ref(24) + const isChange: any = ref(false) + const rdbmsSourceTypes = ref([ + { + label: 'MYSQL', + value: 'MYSQL' + }, + { + label: 'ORACLE', + value: 'ORACLE' + }, + { + label: 'SQLSERVER', + value: 'SQLSERVER' + }, + { + label: 'HANA', + value: 'HANA' + } + ] as IOption[]) + const hadoopSourceTypes = ref([ + { + label: 'HIVE', + value: 'HIVE' + }, + { + label: 'HDFS', + value: 'HDFS' + } + ] as IOption[]) + const sourceTypes = ref() + const resetSpan = () => { + rdbmsSpan.value = + unCustomSpan.value && + rdbmsSourceTypes.value.some((source) => source.value === model.sourceType) + ? 24 + : 0 + tableSpan.value = rdbmsSpan.value && model.srcQueryType === '0' ? 24 : 0 + editorSpan.value = rdbmsSpan.value && model.srcQueryType === '1' ? 24 : 0 + columnSpan.value = tableSpan.value && model.srcColumnType === '1' ? 24 : 0 + hiveSpan.value = unCustomSpan.value && model.sourceType === 'HIVE' ? 24 : 0 + hdfsSpan.value = unCustomSpan.value && model.sourceType === 'HDFS' ? 24 : 0 + datasourceSpan.value = + unCustomSpan.value && + rdbmsSourceTypes.value.some((source) => source.value === model.sourceType) + ? 24 + : 0 + } + const resetValue = () => { + if (!isChange.value) { + isChange.value = true + return + } + switch (model.modelType) { + case 'import': + model.sourceMysqlDatasource = '' + break + case 'export': + model.sourceHiveDatabase = '' + model.sourceHiveTable = '' + model.sourceHivePartitionKey = '' + model.sourceHivePartitionValue = '' + model.sourceHdfsExportDir = '' + break + default: + model.sourceMysqlDatasource = '' + } + } + const getSourceTypesByModelType = (modelType: ModelType): IOption[] => { + switch (modelType) { + case 'import': + return rdbmsSourceTypes.value + case 'export': + return hadoopSourceTypes.value + default: + return rdbmsSourceTypes.value + } + } + + onMounted(() => { + sourceTypes.value = [...rdbmsSourceTypes.value] + }) + + watch( + () => model.modelType, + (modelType: ModelType) => { + sourceTypes.value = getSourceTypesByModelType(modelType) + model.sourceType = sourceTypes.value[0].value + } + ) + watch( + () => [ + unCustomSpan.value, + model.sourceType, + model.srcQueryType, + model.srcColumnType + ], + () => { + resetValue() + resetSpan() + } + ) + + return [ + { + type: 'custom', + field: 'custom-title-source', + span: unCustomSpan, + widget: h( + 'div', + { class: styles['field-title'] }, + t('project.node.data_source') + ) + }, + { + type: 'select', + field: 'sourceType', + name: t('project.node.type'), + span: unCustomSpan, + options: sourceTypes + }, + ...useDatasource( + model, + datasourceSpan, + 'sourceMysqlType', + 'sourceMysqlDatasource' + ), + { + type: 'radio', + field: 'srcQueryType', + name: t('project.node.model_type'), + span: rdbmsSpan, + options: [ + { + label: t('project.node.form'), + value: '0' + }, + { + label: 'SQL', + value: '1' + } + ], + props: { + 'on-update:value': (value: '0' | '1') => { + model.targetType = value === '0' ? 'HIVE' : 'HDFS' + } + } + }, + { + type: 'input', + field: 'srcTable', + name: t('project.node.table'), + span: tableSpan, + props: { + placeholder: t('project.node.table_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate, value) { + if (tableSpan.value && !value) { + return new Error(t('project.node.table_tips')) + } + } + } + }, + { + type: 'radio', + field: 'srcColumnType', + name: t('project.node.column_type'), + span: tableSpan, + options: [ + { label: t('project.node.all_columns'), value: '0' }, + { label: t('project.node.some_columns'), value: '1' } + ] + }, + { + type: 'input', + field: 'srcColumns', + name: t('project.node.column'), + span: columnSpan, + props: { + placeholder: t('project.node.column_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate, value) { + if (!!columnSpan.value && !value) { + return new Error(t('project.node.column_tips')) + } + } + } + }, + { + type: 'input', + field: 'sourceHiveDatabase', + name: t('project.node.database'), + span: hiveSpan, + props: { + placeholder: t('project.node.database_tips') + }, + validate: { + trigger: ['blur', 'input'], + required: true, + validator(validate, value) { + if (hiveSpan.value && !value) { + return new Error(t('project.node.database_tips')) + } + } + } + }, + { + type: 'input', + field: 'sourceHiveTable', + name: t('project.node.table'), + span: hiveSpan, + props: { + placeholder: t('project.node.hive_table_tips') + }, + validate: { + trigger: ['blur', 'input'], + required: true, + validator(validate, value) { + if (hiveSpan.value && !value) { + return new Error(t('project.node.hive_table_tips')) + } + } + } + }, + { + type: 'input', + field: 'sourceHivePartitionKey', + name: t('project.node.hive_partition_keys'), + span: hiveSpan, + props: { + placeholder: t('project.node.hive_partition_keys_tips') + } + }, + { + type: 'input', + field: 'sourceHivePartitionValue', + name: t('project.node.hive_partition_values'), + span: hiveSpan, + props: { + placeholder: t('project.node.hive_partition_values_tips') + } + }, + { + type: 'input', + field: 'sourceHdfsExportDir', + name: t('project.node.export_dir'), + span: hdfsSpan, + props: { + placeholder: t('project.node.export_dir_tips') + }, + validate: { + trigger: ['blur', 'input'], + required: true, + validator(validate, value) { + if (hdfsSpan.value && !value) { + return new Error(t('project.node.export_dir_tips')) + } + } + } + }, + { + type: 'editor', + field: 'sourceMysqlSrcQuerySql', + name: t('project.node.sql_statement'), + span: editorSpan, + validate: { + trigger: ['blur', 'input'], + required: true, + validator(validate, value) { + if (editorSpan.value && !value) { + return new Error(t('project.node.sql_statement_tips')) + } + } + } + }, + ...useCustomParams({ + model, + field: 'mapColumnHive', + name: 'map_column_hive', + isSimple: true, + span: rdbmsSpan + }), + ...useCustomParams({ + model, + field: 'mapColumnJava', + name: 'map_column_java', + isSimple: true, + span: rdbmsSpan + }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-target-type.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-target-type.ts new file mode 100644 index 0000000000..252ef7631a --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop-target-type.ts @@ -0,0 +1,427 @@ +/* + * 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 { h, onMounted, Ref, ref, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import { useDatasource } from './use-sqoop-datasource' +import styles from '../index.module.scss' +import type { IJsonItem, IOption, SourceType } from '../types' + +export function useTargetType( + model: { [field: string]: any }, + unCustomSpan: Ref +): IJsonItem[] { + const { t } = useI18n() + const hiveSpan = ref(24) + const hdfsSpan = ref(0) + const rdbmsSpan = ref(0) + const dataSourceSpan = ref(0) + const updateSpan = ref(0) + const isChange: any = ref(false) + const rdbmsSourceTypes = ref([ + { + label: 'MYSQL', + value: 'MYSQL' + }, + { + label: 'ORACLE', + value: 'ORACLE' + }, + { + label: 'SQLSERVER', + value: 'SQLSERVER' + }, + { + label: 'HANA', + value: 'HANA' + } + ] as IOption[]) + const hadoopSourceTypes = ref([ + { + label: 'HIVE', + value: 'HIVE' + }, + { + label: 'HDFS', + value: 'HDFS' + } + ] as IOption[]) + const targetTypes = ref() + + const resetSpan = () => { + hiveSpan.value = unCustomSpan.value && model.targetType === 'HIVE' ? 24 : 0 + hdfsSpan.value = unCustomSpan.value && model.targetType === 'HDFS' ? 24 : 0 + rdbmsSpan.value = + unCustomSpan.value && + rdbmsSourceTypes.value.some((target) => target.value === model.targetType) + ? 24 + : 0 + dataSourceSpan.value = + unCustomSpan.value && + rdbmsSourceTypes.value.some((target) => target.value === model.targetType) + ? 24 + : 0 + updateSpan.value = rdbmsSpan.value && model.targetMysqlIsUpdate ? 24 : 0 + } + + const getTargetTypesBySourceType = ( + sourceType: SourceType, + srcQueryType: string + ): IOption[] => { + switch (sourceType) { + case 'MYSQL': + if (srcQueryType === '1') { + return hadoopSourceTypes.value + } + return hadoopSourceTypes.value + case 'HDFS': + case 'HIVE': + return rdbmsSourceTypes.value + default: + return hadoopSourceTypes.value + } + } + + const resetValue = () => { + if (!isChange.value) { + isChange.value = true + return + } + switch (model.modelType) { + case 'import': + model.targetHiveDatabase = '' + model.targetHiveTable = '' + model.targetHdfsTargetPath = '' + break + case 'export': + model.targetMysqlDatasource = '' + model.targetMysqlTable = '' + model.targetMysqlColumns = '' + model.targetMysqlFieldsTerminated = '' + model.targetMysqlLinesTerminated = '' + model.targetMysqlTable = '' + break + default: + model.sourceMysqlDatasource = '' + } + } + + onMounted(() => { + targetTypes.value = [...hadoopSourceTypes.value] + }) + + watch( + () => [model.sourceType, model.srcQueryType], + ([sourceType, srcQueryType]) => { + targetTypes.value = getTargetTypesBySourceType(sourceType, srcQueryType) + model.targetType = targetTypes.value[0].value + } + ) + + watch( + () => [unCustomSpan.value, model.targetType, model.targetMysqlIsUpdate], + () => { + resetValue() + resetSpan() + } + ) + + return [ + { + type: 'custom', + field: 'custom-title-target', + span: unCustomSpan, + widget: h( + 'div', + { class: styles['field-title'] }, + t('project.node.data_target') + ) + }, + { + type: 'select', + field: 'targetType', + name: t('project.node.type'), + span: unCustomSpan, + options: targetTypes + }, + { + type: 'input', + field: 'targetHiveDatabase', + name: t('project.node.database'), + span: hiveSpan, + props: { + placeholder: t('project.node.database_tips') + }, + validate: { + trigger: ['blur', 'input'], + required: true, + validator(validate, value) { + if (hiveSpan.value && !value) { + return new Error(t('project.node.database_tips')) + } + } + } + }, + { + type: 'input', + field: 'targetHiveTable', + name: t('project.node.table'), + span: hiveSpan, + props: { + placeholder: t('project.node.table') + }, + validate: { + trigger: ['blur', 'input'], + required: true, + validator(rule, value) { + if (hiveSpan.value && !value) { + return new Error(t('project.node.table_tips')) + } + } + } + }, + { + type: 'switch', + field: 'targetHiveCreateTable', + span: hiveSpan, + name: t('project.node.create_hive_table') + }, + { + type: 'switch', + field: 'targetHiveDropDelimiter', + span: hiveSpan, + name: t('project.node.drop_delimiter') + }, + { + type: 'switch', + field: 'targetHiveOverWrite', + span: hiveSpan, + name: t('project.node.over_write_src') + }, + { + type: 'input', + field: 'targetHiveTargetDir', + name: t('project.node.hive_target_dir'), + span: hiveSpan, + props: { + placeholder: t('project.node.hive_target_dir_tips') + } + }, + { + type: 'input', + field: 'targetHiveReplaceDelimiter', + name: t('project.node.replace_delimiter'), + span: hiveSpan, + props: { + placeholder: t('project.node.replace_delimiter_tips') + } + }, + { + type: 'input', + field: 'targetHivePartitionKey', + name: t('project.node.hive_partition_keys'), + span: hiveSpan, + props: { + placeholder: t('project.node.hive_partition_keys_tips') + } + }, + { + type: 'input', + field: 'targetHivePartitionValue', + name: t('project.node.hive_partition_values'), + span: hiveSpan, + props: { + placeholder: t('project.node.hive_partition_values_tips') + } + }, + { + type: 'input', + field: 'targetHdfsTargetPath', + name: t('project.node.target_dir'), + span: hdfsSpan, + props: { + placeholder: t('project.node.target_dir_tips') + }, + validate: { + trigger: ['blur', 'input'], + required: true, + validator(rule, value) { + if (hdfsSpan.value && !value) { + return new Error(t('project.node.target_dir_tips')) + } + } + } + }, + { + type: 'switch', + field: 'targetHdfsDeleteTargetDir', + name: t('project.node.delete_target_dir'), + span: hdfsSpan + }, + { + type: 'radio', + field: 'targetHdfsCompressionCodec', + name: t('project.node.compression_codec'), + span: hdfsSpan, + options: COMPRESSIONCODECS + }, + { + type: 'radio', + field: 'targetHdfsFileType', + name: t('project.node.file_type'), + span: hdfsSpan, + options: FILETYPES + }, + { + type: 'input', + field: 'targetHdfsFieldsTerminated', + name: t('project.node.fields_terminated'), + span: hdfsSpan, + props: { + placeholder: t('project.node.fields_terminated_tips') + } + }, + { + type: 'input', + field: 'targetHdfsLinesTerminated', + name: t('project.node.lines_terminated'), + span: hdfsSpan, + props: { + placeholder: t('project.node.lines_terminated_tips') + } + }, + ...useDatasource( + model, + dataSourceSpan, + 'targetMysqlType', + 'targetMysqlDatasource' + ), + { + type: 'input', + field: 'targetMysqlTable', + name: t('project.node.table'), + span: rdbmsSpan, + props: { + placeholder: t('project.node.table_tips') + }, + validate: { + trigger: ['blur', 'input'], + required: true, + validator(validate, value) { + if (rdbmsSpan.value && !value) { + return new Error(t('project.node.table_tips')) + } + } + } + }, + { + type: 'input', + field: 'targetMysqlColumns', + name: t('project.node.column'), + span: rdbmsSpan, + props: { + placeholder: t('project.node.column_tips') + } + }, + { + type: 'input', + field: 'targetMysqlFieldsTerminated', + name: t('project.node.fields_terminated'), + span: rdbmsSpan, + props: { + placeholder: t('project.node.fields_terminated_tips') + } + }, + { + type: 'input', + field: 'targetMysqlLinesTerminated', + name: t('project.node.lines_terminated'), + span: rdbmsSpan, + props: { + placeholder: t('project.node.lines_terminated_tips') + } + }, + { + type: 'switch', + field: 'targetMysqlIsUpdate', + span: rdbmsSpan, + name: t('project.node.is_update') + }, + { + type: 'input', + field: 'targetMysqlTargetUpdateKey', + name: t('project.node.update_key'), + span: updateSpan, + props: { + placeholder: t('project.node.update_key_tips') + } + }, + { + type: 'radio', + field: 'targetMysqlUpdateMode', + name: t('project.node.update_mode'), + span: updateSpan, + options: [ + { + label: t('project.node.only_update'), + value: 'updateonly' + }, + { + label: t('project.node.allow_insert'), + value: 'allowinsert' + } + ] + } + ] +} + +const COMPRESSIONCODECS = [ + { + label: 'snappy', + value: 'snappy' + }, + { + label: 'lzo', + value: 'lzo' + }, + { + label: 'gzip', + value: 'gzip' + }, + { + label: 'no', + value: '' + } +] +const FILETYPES = [ + { + label: 'avro', + value: '--as-avrodatafile' + }, + { + label: 'sequence', + value: '--as-sequencefile' + }, + { + label: 'text', + value: '--as-textfile' + }, + { + label: 'parquet', + value: '--as-parquetfile' + } +] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop.ts new file mode 100644 index 0000000000..20db90747c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-sqoop.ts @@ -0,0 +1,128 @@ +/* + * 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 { computed } from 'vue' +import { useI18n } from 'vue-i18n' +import { useCustomParams, useSourceType, useTargetType } from '.' +import type { IJsonItem, ModelType } from '../types' + +export function useSqoop(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const customSpan = computed(() => (model.isCustomTask ? 24 : 0)) + const unCustomSpan = computed(() => (model.isCustomTask ? 0 : 24)) + + const unCustomHalfSpan = computed(() => (model.isCustomTask ? 0 : 12)) + + return [ + { + type: 'switch', + field: 'isCustomTask', + name: t('project.node.custom_job') + }, + { + type: 'input', + field: 'jobName', + name: t('project.node.sqoop_job_name'), + span: unCustomSpan, + props: { + placeholder: t('project.node.sqoop_job_name_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate, value) { + if (!model.isCustomTask && !value) { + return new Error(t('project.node.sqoop_job_name_tips')) + } + } + } + }, + { + type: 'select', + field: 'modelType', + name: t('project.node.direct'), + span: unCustomSpan, + options: MODEL_TYPES + }, + ...useCustomParams({ + model, + field: 'hadoopCustomParams', + name: 'hadoop_custom_params', + isSimple: true, + span: unCustomSpan + }), + ...useCustomParams({ + model, + field: 'sqoopAdvancedParams', + name: 'sqoop_advanced_parameters', + isSimple: true, + span: unCustomSpan + }), + ...useSourceType(model, unCustomSpan), + ...useTargetType(model, unCustomSpan), + { + type: 'input-number', + field: 'concurrency', + name: t('project.node.concurrency'), + span: unCustomHalfSpan, + props: { + placeholder: t('project.node.concurrency_tips'), + min: 1 + } + }, + { + type: 'input', + field: 'splitBy', + name: t('project.node.concurrency_column'), + span: unCustomHalfSpan, + props: { + placeholder: t('project.node.concurrency_column_tips') + } + }, + { + type: 'editor', + field: 'customShell', + name: t('project.node.custom_script'), + span: customSpan, + validate: { + trigger: ['input', 'trigger'], + required: true, + validator(rule, value) { + if (customSpan.value && !value) { + return new Error(t('project.node.custom_script')) + } + } + } + }, + ...useCustomParams({ + model, + field: 'localParams', + name: 'custom_parameters', + isSimple: true + }) + ] +} + +const MODEL_TYPES = [ + { + label: 'import', + value: 'import' + }, + { + label: 'export', + value: 'export' + } +] as { label: ModelType; value: ModelType }[] diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-switch.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-switch.ts new file mode 100644 index 0000000000..0b3a070220 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-switch.ts @@ -0,0 +1,127 @@ +/* + * 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, watch, onMounted, nextTick } from 'vue' +import { useI18n } from 'vue-i18n' +import { useTaskNodeStore } from '@/store/project/task-node' +import { queryProcessDefinitionByCode } from '@/service/modules/process-definition' +import { findIndex } from 'lodash' +import type { IJsonItem } from '../types' + +export function useSwitch( + model: { [field: string]: any }, + projectCode: number +): IJsonItem[] { + const { t } = useI18n() + const taskStore = useTaskNodeStore() + const branchFlowOptions = ref(taskStore.postTaskOptions as any) + const loading = ref(false) + const getOtherTaskDefinitionList = async () => { + if (loading.value) return + loading.value = true + branchFlowOptions.value = [] + const res = await queryProcessDefinitionByCode( + model.processName, + projectCode + ) + res?.taskDefinitionList.forEach((item: any) => { + if (item.code != model.code) { + branchFlowOptions.value.push({ label: item.name, value: item.code }) + } + }) + loading.value = false + clearUselessNode(branchFlowOptions.value) + } + + const clearUselessNode = (options: { value: number }[]) => { + if (!options || !options.length) { + model.nextNode = null + model.dependTaskList?.forEach((task: { nextNode: number | null }) => { + task.nextNode = null + }) + return + } + if ( + findIndex( + branchFlowOptions.value, + (option: { value: number }) => option.value == model.nextNode + ) === -1 + ) { + model.nextNode = null + } + model.dependTaskList?.forEach((task: { nextNode: number | null }) => { + if ( + findIndex( + branchFlowOptions.value, + (option: { value: number }) => option.value == task.nextNode + ) === -1 + ) { + task.nextNode = null + } + }) + } + + watch( + () => [model.processName, model.nextCode], + () => { + if (model.processName) { + getOtherTaskDefinitionList() + } + } + ) + + onMounted(async () => { + await nextTick() + clearUselessNode(branchFlowOptions.value) + }) + + return [ + { + type: 'custom-parameters', + field: 'dependTaskList', + name: t('project.node.switch_condition'), + children: [ + { + type: 'input', + field: 'condition', + span: 24, + props: { + loading: loading, + type: 'textarea', + autosize: { minRows: 2 } + } + }, + { + type: 'select', + field: 'nextNode', + span: 22, + name: t('project.node.switch_branch_flow'), + options: branchFlowOptions + } + ] + }, + { + type: 'select', + field: 'nextNode', + span: 24, + name: t('project.node.switch_branch_flow_default'), + props: { + loading: loading + }, + options: branchFlowOptions + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-target-task-name.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-target-task-name.ts new file mode 100644 index 0000000000..36e1adb5cd --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-target-task-name.ts @@ -0,0 +1,37 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useTargetTaskName(): IJsonItem { + const { t } = useI18n() + return { + type: 'input', + field: 'targetJobName', + name: t('project.node.target_task_name'), + props: { + placeholder: t('project.node.target_task_name_tips'), + maxLength: 100 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + message: t('project.node.target_task_name_tips') + } + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-definition.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-definition.ts new file mode 100644 index 0000000000..d740e366c1 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-definition.ts @@ -0,0 +1,46 @@ +/* + * 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 { useTaskType, useProcessName } from '.' +import type { IJsonItem, ITaskData } from '../types' + +export const useTaskDefinition = ({ + projectCode, + from = 0, + readonly, + data, + model +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData + model: { [field: string]: any } +}): IJsonItem[] => { + if (from === 0) return [] + return [ + useTaskType(model, readonly), + useProcessName({ + model, + projectCode, + isCreate: !data?.id, + from, + processName: data?.processName, + taskCode: data?.code + }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-group.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-group.ts new file mode 100644 index 0000000000..6966e4237b --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-group.ts @@ -0,0 +1,85 @@ +/* + * 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, watch, computed, onMounted } from 'vue' +import { useI18n } from 'vue-i18n' +import { queryTaskGroupListPagingByProjectCode } from '@/service/modules/task-group' +import type { IJsonItem } from '../types' + +export function useTaskGroup( + model: { [field: string]: any }, + projectCode: number +): IJsonItem[] { + const { t } = useI18n() + + const options = ref([]) + const loading = ref(false) + const priorityDisabled = computed(() => !model.taskGroupId) + + const getTaskGroupList = async () => { + if (loading.value) return + loading.value = true + const { totalList = [] } = await queryTaskGroupListPagingByProjectCode({ + pageNo: 1, + pageSize: 2147483647, + projectCode + }) + options.value = totalList.map((item: { id: string; name: string }) => ({ + label: item.name, + value: item.id + })) + loading.value = false + } + + onMounted(() => { + getTaskGroupList() + }) + + watch( + () => model.taskGroupId, + (taskGroupId) => { + if (!taskGroupId) { + model.taskGroupId = null + model.taskGroupPriority = null + } + } + ) + + return [ + { + type: 'select', + field: 'taskGroupId', + span: 12, + name: t('project.node.task_group_name'), + props: { + loading, + clearable: true + }, + options + }, + { + type: 'input-number', + field: 'taskGroupPriority', + name: t('project.node.task_group_queue_priority'), + props: { + max: Math.pow(10, 60) - 1, + disabled: priorityDisabled + }, + span: 12 + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-priority.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-priority.ts new file mode 100644 index 0000000000..3f8e860b6a --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-priority.ts @@ -0,0 +1,92 @@ +/* + * 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 { h, markRaw, VNode, VNodeChild } from 'vue' +import { NIcon } from 'naive-ui' +import { useI18n } from 'vue-i18n' +import { ArrowUpOutlined, ArrowDownOutlined } from '@vicons/antd' +import type { ITaskPriorityOption, IJsonItem } from '../types' + +export function useTaskPriority(): IJsonItem { + const { t } = useI18n() + const options = markRaw([ + { + label: 'HIGHEST', + value: 'HIGHEST', + icon: ArrowUpOutlined, + color: '#ff0000' + }, + { + label: 'HIGH', + value: 'HIGH', + icon: ArrowUpOutlined, + color: '#ff0000' + }, + { + label: 'MEDIUM', + value: 'MEDIUM', + icon: ArrowUpOutlined, + color: '#EA7D24' + }, + { + label: 'LOW', + value: 'LOW', + icon: ArrowDownOutlined, + color: '#2A8734' + }, + { + label: 'LOWEST', + value: 'LOWEST', + icon: ArrowDownOutlined, + color: '#2A8734' + } + ]) + const renderOption = ({ + node, + option + }: { + node: VNode + option: ITaskPriorityOption + }): VNodeChild => + h(node, null, { + default: () => [ + h( + NIcon, + { + color: option.color + }, + { + default: () => h(option.icon) + } + ), + h('span', { style: { 'z-index': 1 } }, option.label as string) + ] + }) + return { + type: 'select', + field: 'taskPriority', + name: t('project.node.task_priority'), + options, + validate: { + required: true + }, + props: { + renderOption + }, + value: 'MEDIUM' + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-type.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-type.ts new file mode 100644 index 0000000000..fc8e50c4c5 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-task-type.ts @@ -0,0 +1,51 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { TASK_TYPES_MAP } from '@/store/project/task-type' +import type { IJsonItem } from '../types' + +export function useTaskType( + model: { [field: string]: any }, + readonly?: boolean +): IJsonItem { + const { t } = useI18n() + const disabledTaskType = ['CONDITIONS', 'SWITCH'] + + const options = Object.keys(TASK_TYPES_MAP).map((option: string) => ({ + label: option, + value: option, + disabled: disabledTaskType.includes(option) + })) + return { + type: 'select', + field: 'taskType', + span: 24, + name: t('project.node.task_type'), + props: { + disabled: readonly || ['CONDITIONS', 'SWITCH'].includes(model.taskType), + filterable: true + }, + options: options, + validate: { + trigger: ['input', 'blur'], + required: true, + message: t('project.node.task_type_tips') + }, + value: model.taskType ? model.taskType : 'SHELL' + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-timeout-alarm.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-timeout-alarm.ts new file mode 100644 index 0000000000..53b51bc4d7 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-timeout-alarm.ts @@ -0,0 +1,88 @@ +/* + * 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 { computed } from 'vue' +import { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' + +export function useTimeoutAlarm(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + const span = computed(() => (model.timeoutFlag ? 12 : 0)) + + const strategyOptions = [ + { + label: t('project.node.timeout_alarm'), + value: 'WARN' + }, + { + label: t('project.node.timeout_failure'), + value: 'FAILED' + } + ] + + return [ + { + type: 'switch', + field: 'timeoutFlag', + name: t('project.node.timeout_alarm'), + props: { + 'on-update:value': (value: boolean) => { + if (value) { + if (!model.timeoutNotifyStrategy.length) + model.timeoutNotifyStrategy = ['WARN'] + if (!model.timeout) model.timeout = 30 + } + } + } + }, + { + type: 'checkbox', + field: 'timeoutNotifyStrategy', + name: t('project.node.timeout_strategy'), + options: strategyOptions, + span: span, + validate: { + trigger: ['input'], + validator(validate: any, value: []) { + if (model.timeoutFlag && !value.length) { + return new Error(t('project.node.timeout_strategy_tips')) + } + } + } + }, + { + type: 'input-number', + field: 'timeout', + name: t('project.node.timeout_period'), + span, + props: { + max: Math.pow(10, 10) - 1 + }, + slots: { + suffix: () => t('project.node.minute') + }, + validate: { + trigger: ['input'], + validator(validate: any, value: number) { + if (model.timeoutFlag && !/^[1-9]\d*$/.test(String(value))) { + return new Error(t('project.node.timeout_period_tips')) + } + } + } + } + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-udfs.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-udfs.ts new file mode 100644 index 0000000000..3c2f444354 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-udfs.ts @@ -0,0 +1,62 @@ +/* + * 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, watch, computed } from 'vue' +import { useI18n } from 'vue-i18n' +import { queryUdfFuncList } from '@/service/modules/resources' +import type { IJsonItem } from '../types' + +export function useUdfs(model: { [field: string]: any }): IJsonItem { + const { t } = useI18n() + const options = ref([]) + const loading = ref(false) + const span = computed(() => + ['HIVE', 'SPARK', 'KYUUBI'].includes(model.type) ? 24 : 0 + ) + + const getUdfs = async () => { + if (loading.value) return + loading.value = true + const type = model.type === 'KYUUBI' ? 'HIVE' : model.type + const res = await queryUdfFuncList({ type }) + options.value = res.map((udf: { id: number; funcName: string }) => ({ + value: String(udf.id), + label: udf.funcName + })) + loading.value = false + } + + watch( + () => model.type, + (value) => { + if (['HIVE', 'SPARK', 'KYUUBI'].includes(value)) { + getUdfs() + } + } + ) + + return { + type: 'select', + field: 'udfs', + options: options, + name: t('project.node.udf_function'), + props: { + multiple: true, + loading + }, + span + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-worker-group.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-worker-group.ts new file mode 100644 index 0000000000..9b452b541a --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-worker-group.ts @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ref, onMounted } from 'vue' +import { useI18n } from 'vue-i18n' +import { queryWorkerGroupsByProjectCode } from '@/service/modules/projects-worker-group' +import type { IJsonItem } from '../types' + +export function useWorkerGroup(projectCode: number): IJsonItem { + const { t } = useI18n() + + const options = ref([] as { label: string; value: string }[]) + const loading = ref(false) + + const getWorkerGroups = async () => { + if (loading.value) return + loading.value = true + await queryWorkerGroupsByProjectCode(projectCode).then((res: any) => { + options.value = res.data.map((item: any) => ({ + label: item.workerGroup, + value: item.workerGroup + })) + }) + loading.value = false + } + + onMounted(() => { + getWorkerGroups() + }) + return { + type: 'select', + field: 'workerGroup', + span: 12, + name: t('project.node.worker_group'), + props: { + loading: loading + }, + options: options, + validate: { + trigger: ['input', 'blur'], + required: true, + message: t('project.node.worker_group_tips') + }, + value: 'default' + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-zeppelin.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-zeppelin.ts new file mode 100644 index 0000000000..eff4777215 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/fields/use-zeppelin.ts @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { useI18n } from 'vue-i18n' +import { useCustomParams } from '.' +import type { IJsonItem } from '../types' + +export function useZeppelin(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + return [ + { + type: 'input', + field: 'noteId', + name: t('project.node.zeppelin_note_id'), + props: { + placeholder: t('project.node.zeppelin_note_id_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.zeppelin_note_id_tips')) + } + } + } + }, + { + type: 'input', + field: 'paragraphId', + name: t('project.node.zeppelin_paragraph_id'), + props: { + placeholder: t('project.node.zeppelin_paragraph_id_tips') + } + }, + { + type: 'input', + field: 'productionNoteDirectory', + name: t('project.node.zeppelin_production_note_directory'), + props: { + placeholder: t('project.node.zeppelin_production_note_directory_tips') + } + }, + { + type: 'input', + field: 'parameters', + name: t('project.node.zeppelin_parameters'), + props: { + placeholder: t('project.node.zeppelin_parameters_tips') + } + }, + ...useCustomParams({ model, field: 'localParams', isSimple: false }) + ] +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/format-data.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/format-data.ts new file mode 100644 index 0000000000..2ab1712b6f --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/format-data.ts @@ -0,0 +1,757 @@ +/* + * 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 { omit } from 'lodash' +import type { + INodeData, + ITaskData, + ITaskParams, + ISqoopTargetParams, + ISqoopSourceParams, + ILocalParam, + IDependentParameters +} from './types' +import { ref } from 'vue' + +export function formatParams(data: INodeData): { + processDefinitionCode: string + upstreamCodes: string + taskDefinitionJsonObj: object +} { + const rdbmsSourceTypes = ref(['MYSQL', 'ORACLE', 'SQLSERVER', 'HANA']) + const taskParams: ITaskParams = {} + if (data.taskType === 'SUB_PROCESS' || data.taskType === 'DYNAMIC') { + taskParams.processDefinitionCode = data.processDefinitionCode + } + + if (data.taskType === 'JAVA') { + taskParams.runType = data.runType + taskParams.mainArgs = data.mainArgs + taskParams.jvmArgs = data.jvmArgs + taskParams.isModulePath = data.isModulePath + if (data.runType === 'JAR' && data.mainJar) { + taskParams.mainJar = { resourceName: data.mainJar } + } + } + + if ( + data.taskType && + ['SPARK', 'MR', 'FLINK', 'FLINK_STREAM'].includes(data.taskType) + ) { + taskParams.programType = data.programType + taskParams.mainClass = data.mainClass + if (data.mainJar) { + taskParams.mainJar = { resourceName: data.mainJar } + } + taskParams.deployMode = data.deployMode + taskParams.appName = data.appName + taskParams.mainArgs = data.mainArgs + taskParams.others = data.others + if (data.namespace) { + taskParams.namespace = data.namespace + } + taskParams.yarnQueue = data.yarnQueue + } + + if (data.taskType === 'SPARK') { + taskParams.master = data.master + taskParams.driverCores = data.driverCores + taskParams.driverMemory = data.driverMemory + taskParams.numExecutors = data.numExecutors + taskParams.executorMemory = data.executorMemory + taskParams.executorCores = data.executorCores + taskParams.sqlExecutionType = data.sqlExecutionType + } + + if (data.taskType === 'FLINK' || data.taskType === 'FLINK_STREAM') { + taskParams.flinkVersion = data.flinkVersion + taskParams.jobManagerMemory = data.jobManagerMemory + taskParams.taskManagerMemory = data.taskManagerMemory + taskParams.slot = data.slot + taskParams.taskManager = data.taskManager + taskParams.parallelism = data.parallelism + } + if (data.taskType === 'HTTP') { + taskParams.httpMethod = data.httpMethod + taskParams.httpBody = data.httpBody + taskParams.httpCheckCondition = data.httpCheckCondition + taskParams.httpParams = data.httpParams + taskParams.url = data.url + taskParams.condition = data.condition + taskParams.connectTimeout = data.connectTimeout + taskParams.socketTimeout = data.socketTimeout + } + + if (data.taskType === 'SQOOP') { + taskParams.jobType = data.isCustomTask ? 'CUSTOM' : 'TEMPLATE' + taskParams.localParams = data.localParams + if (data.isCustomTask) { + taskParams.customShell = data.customShell + } else { + taskParams.jobName = data.jobName + taskParams.hadoopCustomParams = data.hadoopCustomParams + taskParams.sqoopAdvancedParams = data.sqoopAdvancedParams + taskParams.concurrency = data.concurrency + taskParams.splitBy = data.splitBy + taskParams.modelType = data.modelType + taskParams.sourceType = data.sourceType + taskParams.targetType = data.targetType + let targetParams: ISqoopTargetParams = {} + let sourceParams: ISqoopSourceParams = {} + if (data.targetType === 'HIVE') { + targetParams = { + hiveDatabase: data.targetHiveDatabase, + hiveTable: data.targetHiveTable, + createHiveTable: data.targetHiveCreateTable, + dropDelimiter: data.targetHiveDropDelimiter, + hiveOverWrite: data.targetHiveOverWrite, + hiveTargetDir: data.targetHiveTargetDir, + replaceDelimiter: data.targetHiveReplaceDelimiter, + hivePartitionKey: data.targetHivePartitionKey, + hivePartitionValue: data.targetHivePartitionValue + } + } else if (data.targetType === 'HDFS') { + targetParams = { + targetPath: data.targetHdfsTargetPath, + deleteTargetDir: data.targetHdfsDeleteTargetDir, + compressionCodec: data.targetHdfsCompressionCodec, + fileType: data.targetHdfsFileType, + fieldsTerminated: data.targetHdfsFieldsTerminated, + linesTerminated: data.targetHdfsLinesTerminated + } + } else if ( + rdbmsSourceTypes.value.some((target) => target === data.targetType) + ) { + targetParams = { + targetType: data.targetMysqlType, + targetDatasource: data.targetMysqlDatasource, + targetTable: data.targetMysqlTable, + targetColumns: data.targetMysqlColumns, + fieldsTerminated: data.targetMysqlFieldsTerminated, + linesTerminated: data.targetMysqlLinesTerminated, + isUpdate: data.targetMysqlIsUpdate, + targetUpdateKey: data.targetMysqlTargetUpdateKey, + targetUpdateMode: data.targetMysqlUpdateMode + } + } + if (rdbmsSourceTypes.value.some((target) => target === data.sourceType)) { + sourceParams = { + srcTable: data.srcQueryType === '1' ? '' : data.srcTable, + srcColumnType: data.srcQueryType === '1' ? '0' : data.srcColumnType, + srcColumns: + data.srcQueryType === '1' || data.srcColumnType === '0' + ? '' + : data.srcColumns, + srcQuerySql: + data.srcQueryType === '0' ? '' : data.sourceMysqlSrcQuerySql, + srcQueryType: data.srcQueryType, + srcType: data.sourceMysqlType, + srcDatasource: data.sourceMysqlDatasource, + mapColumnHive: data.mapColumnHive, + mapColumnJava: data.mapColumnJava + } + } else if (data.sourceType === 'HDFS') { + sourceParams = { + exportDir: data.sourceHdfsExportDir + } + } else if (data.sourceType === 'HIVE') { + sourceParams = { + hiveDatabase: data.sourceHiveDatabase, + hiveTable: data.sourceHiveTable, + hivePartitionKey: data.sourceHivePartitionKey, + hivePartitionValue: data.sourceHivePartitionValue + } + } + taskParams.targetParams = JSON.stringify(targetParams) + taskParams.sourceParams = JSON.stringify(sourceParams) + } + } + + if (data.taskType === 'SQL') { + taskParams.type = data.type + taskParams.datasource = data.datasource + taskParams.sql = data.sql + taskParams.sqlType = data.sqlType + taskParams.preStatements = data.preStatements + taskParams.postStatements = data.postStatements + taskParams.sendEmail = data.sendEmail + taskParams.displayRows = data.displayRows + if (data.sqlType === '0' && data.sendEmail) { + taskParams.title = data.title + taskParams.groupId = data.groupId + } + if (data.type === 'HIVE') { + if (data.udfs) taskParams.udfs = data.udfs.join(',') + taskParams.connParams = data.connParams + } + + if (data.type === 'KYUUBI') { + if (data.udfs) taskParams.udfs = data.udfs.join(',') + } + } + + if (data.taskType === 'PROCEDURE') { + taskParams.type = data.type + taskParams.datasource = data.datasource + taskParams.method = data.method + } + + if (data.taskType === 'SEATUNNEL') { + taskParams.startupScript = data.startupScript + taskParams.useCustom = data.useCustom + taskParams.rawScript = data.rawScript + if (data.startupScript?.includes('flink')) { + taskParams.runMode = data.runMode + taskParams.others = data.others + } + if (data.startupScript?.includes('spark')) { + taskParams.deployMode = data.deployMode + taskParams.master = data.master + taskParams.masterUrl = data.masterUrl + } + if (data.startupScript === 'seatunnel.sh') { + taskParams.deployMode = data.deployMode + taskParams.others = data.others + } + } + + if (data.taskType === 'SWITCH') { + taskParams.switchResult = {} + taskParams.switchResult.dependTaskList = data.dependTaskList + taskParams.switchResult.nextNode = data.nextNode + } + + if (data.taskType === 'CONDITIONS') { + taskParams.dependence = { + relation: data.relation, + dependTaskList: data.dependTaskList + } + taskParams.conditionResult = {} + if (data.successBranch) { + taskParams.conditionResult.successNode = [data.successBranch] + } + if (data.failedBranch) { + taskParams.conditionResult.failedNode = [data.failedBranch] + } + } + + if (data.taskType === 'DATAX') { + taskParams.customConfig = data.customConfig ? 1 : 0 + if (taskParams.customConfig === 0) { + taskParams.dsType = data.dsType + taskParams.dataSource = data.dataSource + taskParams.dtType = data.dtType + taskParams.dataTarget = data.dataTarget + taskParams.sql = data.sql + taskParams.targetTable = data.targetTable + taskParams.jobSpeedByte = data.jobSpeedByte + taskParams.jobSpeedRecord = data.jobSpeedRecord + taskParams.preStatements = data.preStatements + taskParams.postStatements = data.postStatements + } else { + taskParams.json = data.json + data?.localParams?.map((param: ILocalParam) => { + param.direct = 'IN' + param.type = 'VARCHAR' + }) + } + taskParams.xms = data.xms + taskParams.xmx = data.xmx + } + if (data.taskType === 'DEPENDENT') { + taskParams.dependence = { + checkInterval: data.checkInterval, + failurePolicy: data.failurePolicy, + failureWaitingTime: data.failureWaitingTime, + relation: data.relation, + dependTaskList: data.dependTaskList + } + } + if (data.taskType === 'DATA_QUALITY') { + taskParams.ruleId = data.ruleId + taskParams.ruleInputParameter = { + check_type: data.check_type, + comparison_execute_sql: data.comparison_execute_sql, + comparison_type: data.comparison_type, + comparison_name: data.comparison_name, + failure_strategy: data.failure_strategy, + operator: data.operator, + src_connector_type: data.src_connector_type, + src_datasource_id: data.src_datasource_id, + src_database: data.src_database, + field_length: data.field_length, + begin_time: data.begin_time, + deadline: data.deadline, + datetime_format: data.datetime_format, + enum_list: data.enum_list, + regexp_pattern: data.regexp_pattern, + target_filter: data.target_filter, + src_filter: data.src_filter, + src_field: data.src_field, + src_table: data.src_table, + statistics_execute_sql: data.statistics_execute_sql, + statistics_name: data.statistics_name, + target_connector_type: data.target_connector_type, + target_datasource_id: data.target_datasource_id, + target_database: data.target_database, + target_table: data.target_table, + threshold: data.threshold, + mapping_columns: JSON.stringify(data.mapping_columns) + } + taskParams.sparkParameters = { + deployMode: data.deployMode, + driverCores: data.driverCores, + driverMemory: data.driverMemory, + executorCores: data.executorCores, + executorMemory: data.executorMemory, + numExecutors: data.numExecutors, + others: data.others, + yarnQueue: data.yarnQueue, + sqlExecutionType: data.sqlExecutionType + } + } + + if (data.taskType === 'EMR') { + taskParams.type = data.type + taskParams.programType = data.programType + taskParams.jobFlowDefineJson = data.jobFlowDefineJson + taskParams.stepsDefineJson = data.stepsDefineJson + } + + if (data.taskType === 'ZEPPELIN') { + taskParams.noteId = data.noteId + taskParams.paragraphId = data.paragraphId + taskParams.restEndpoint = data.restEndpoint + taskParams.username = data.username + taskParams.password = data.password + taskParams.productionNoteDirectory = data.productionNoteDirectory + taskParams.parameters = data.parameters + taskParams.datasource = data.datasource + taskParams.type = data.type + } + + if (data.taskType === 'K8S') { + taskParams.namespace = data.namespace + taskParams.minCpuCores = data.minCpuCores + taskParams.minMemorySpace = data.minMemorySpace + taskParams.image = data.image + taskParams.imagePullPolicy = data.imagePullPolicy + taskParams.command = data.command + taskParams.args = data.args + taskParams.customizedLabels = data.customizedLabels + taskParams.nodeSelectors = data.nodeSelectors + taskParams.datasource = data.datasource + taskParams.type = data.type + taskParams.kubeConfig = data.kubeConfig + taskParams.pullSecret = data.pullSecret + } + + if (data.taskType === 'JUPYTER') { + taskParams.condaEnvName = data.condaEnvName + taskParams.inputNotePath = data.inputNotePath + taskParams.outputNotePath = data.outputNotePath + taskParams.parameters = data.parameters + taskParams.kernel = data.kernel + taskParams.engine = data.engine + taskParams.executionTimeout = data.executionTimeout + taskParams.startTimeout = data.startTimeout + taskParams.others = data.others + } + + if (data.taskType === 'MLFLOW') { + taskParams.algorithm = data.algorithm + taskParams.params = data.params + taskParams.searchParams = data.searchParams + taskParams.dataPath = data.dataPath + taskParams.experimentName = data.experimentName + taskParams.modelName = data.modelName + taskParams.mlflowTrackingUri = data.mlflowTrackingUri + taskParams.mlflowJobType = data.mlflowJobType + taskParams.automlTool = data.automlTool + taskParams.registerModel = data.registerModel + taskParams.mlflowTaskType = data.mlflowTaskType + taskParams.deployType = data.deployType + taskParams.deployPort = data.deployPort + taskParams.deployModelKey = data.deployModelKey + taskParams.mlflowProjectRepository = data.mlflowProjectRepository + taskParams.mlflowProjectVersion = data.mlflowProjectVersion + } + + if (data.taskType === 'DVC') { + taskParams.dvcTaskType = data.dvcTaskType + taskParams.dvcRepository = data.dvcRepository + taskParams.dvcVersion = data.dvcVersion + taskParams.dvcDataLocation = data.dvcDataLocation + taskParams.dvcMessage = data.dvcMessage + taskParams.dvcLoadSaveDataPath = data.dvcLoadSaveDataPath + taskParams.dvcStoreUrl = data.dvcStoreUrl + } + + if (data.taskType === 'SAGEMAKER') { + taskParams.sagemakerRequestJson = data.sagemakerRequestJson + taskParams.username = data.username + taskParams.password = data.password + taskParams.datasource = data.datasource + taskParams.type = data.type + taskParams.awsRegion = data.awsRegion + } + if (data.taskType === 'PYTORCH') { + taskParams.script = data.script + taskParams.scriptParams = data.scriptParams + taskParams.pythonPath = data.pythonPath + taskParams.isCreateEnvironment = data.isCreateEnvironment + taskParams.pythonCommand = data.pythonCommand + taskParams.pythonEnvTool = data.pythonEnvTool + taskParams.requirements = data.requirements + taskParams.condaPythonVersion = data.condaPythonVersion + } + + if (data.taskType === 'DINKY') { + taskParams.address = data.address + taskParams.taskId = data.taskId + taskParams.online = data.online + } + + if (data.taskType === 'OPENMLDB') { + taskParams.zk = data.zk + taskParams.zkPath = data.zkPath + taskParams.executeMode = data.executeMode + taskParams.sql = data.sql + } + + if (data.taskType === 'CHUNJUN') { + taskParams.customConfig = data.customConfig ? 1 : 0 + taskParams.json = data.json + taskParams.deployMode = data.deployMode + taskParams.others = data.others + } + + if (data.taskType === 'PIGEON') { + taskParams.targetJobName = data.targetJobName + } + + if (data.taskType === 'HIVECLI') { + taskParams.hiveCliTaskExecutionType = data.hiveCliTaskExecutionType + taskParams.hiveSqlScript = data.hiveSqlScript + taskParams.hiveCliOptions = data.hiveCliOptions + } + if (data.taskType === 'DMS') { + taskParams.isRestartTask = data.isRestartTask + taskParams.isJsonFormat = data.isJsonFormat + taskParams.jsonData = data.jsonData + taskParams.migrationType = data.migrationType + taskParams.replicationTaskIdentifier = data.replicationTaskIdentifier + taskParams.sourceEndpointArn = data.sourceEndpointArn + taskParams.targetEndpointArn = data.targetEndpointArn + taskParams.replicationInstanceArn = data.replicationInstanceArn + taskParams.tableMappings = data.tableMappings + taskParams.replicationTaskArn = data.replicationTaskArn + } + + if (data.taskType === 'DATASYNC') { + taskParams.jsonFormat = data.jsonFormat + taskParams.json = data.json + taskParams.destinationLocationArn = data.destinationLocationArn + taskParams.sourceLocationArn = data.sourceLocationArn + taskParams.name = data.name + taskParams.cloudWatchLogGroupArn = data.cloudWatchLogGroupArn + } + + if (data.taskType === 'KUBEFLOW') { + taskParams.yamlContent = data.yamlContent + taskParams.namespace = data.namespace + } + + if (data.taskType === 'LINKIS') { + taskParams.useCustom = data.useCustom + taskParams.paramScript = data.paramScript + taskParams.rawScript = data.rawScript + } + + if (data.taskType === 'DATA_FACTORY') { + taskParams.factoryName = data.factoryName + taskParams.resourceGroupName = data.resourceGroupName + taskParams.pipelineName = data.pipelineName + } + + if (data.taskType === 'REMOTESHELL') { + taskParams.type = data.type + taskParams.datasource = data.datasource + } + + if (data.taskType === 'DYNAMIC') { + taskParams.processDefinitionCode = data.processDefinitionCode + taskParams.maxNumOfSubWorkflowInstances = data.maxNumOfSubWorkflowInstances + taskParams.degreeOfParallelism = data.degreeOfParallelism + taskParams.filterCondition = data.filterCondition + taskParams.listParameters = data.listParameters + } + + let timeoutNotifyStrategy = '' + if (data.timeoutNotifyStrategy) { + if (data.timeoutNotifyStrategy.length === 1) { + timeoutNotifyStrategy = data.timeoutNotifyStrategy[0] + } + if (data.timeoutNotifyStrategy.length === 2) { + timeoutNotifyStrategy = 'WARNFAILED' + } + } + const params = { + processDefinitionCode: data.processName ? String(data.processName) : '', + upstreamCodes: data?.preTasks?.join(','), + taskDefinitionJsonObj: { + code: data.code, + delayTime: data.delayTime ? String(data.delayTime) : '0', + description: data.description, + environmentCode: data.environmentCode || -1, + failRetryInterval: data.failRetryInterval + ? String(data.failRetryInterval) + : '0', + failRetryTimes: data.failRetryTimes ? String(data.failRetryTimes) : '0', + flag: data.flag, + isCache: data.isCache ? 'YES' : 'NO', + name: data.name, + taskGroupId: data.taskGroupId, + taskGroupPriority: data.taskGroupPriority, + taskParams: { + localParams: data.localParams?.map((item: any) => { + item.value = item.value || '' + return item + }), + initScript: data.initScript, + rawScript: data.rawScript, + resourceList: data.resourceList?.length + ? data.resourceList.map((fullName: string) => ({ + resourceName: `${fullName}` + })) + : [], + ...taskParams + }, + taskPriority: data.taskPriority, + taskType: data.taskType, + timeout: data.timeoutFlag ? data.timeout : 0, + timeoutFlag: data.timeoutFlag ? 'OPEN' : 'CLOSE', + timeoutNotifyStrategy: data.timeoutFlag ? timeoutNotifyStrategy : '', + workerGroup: data.workerGroup, + cpuQuota: data.cpuQuota || -1, + memoryMax: data.memoryMax || -1, + taskExecuteType: data.taskExecuteType + } + } as { + processDefinitionCode: string + upstreamCodes: string + taskDefinitionJsonObj: { timeout: number; timeoutNotifyStrategy: string } + } + if (!data.timeoutFlag) { + params.taskDefinitionJsonObj.timeout = 0 + params.taskDefinitionJsonObj.timeoutNotifyStrategy = '' + } + return params +} + +export function formatModel(data: ITaskData) { + const params = { + ...omit(data, [ + 'environmentCode', + 'timeoutFlag', + 'timeoutNotifyStrategy', + 'taskParams' + ]), + ...omit(data.taskParams, ['resourceList', 'mainJar', 'localParams']), + environmentCode: data.environmentCode === -1 ? null : data.environmentCode, + timeoutFlag: data.timeoutFlag === 'OPEN', + isCache: data.isCache === 'YES', + timeoutNotifyStrategy: data.timeoutNotifyStrategy + ? [data.timeoutNotifyStrategy] + : [], + localParams: data.taskParams?.localParams || [] + } as INodeData + + if (data.timeoutNotifyStrategy === 'WARNFAILED') { + params.timeoutNotifyStrategy = ['WARN', 'FAILED'] + } + if (data.taskParams?.resourceList) { + params.resourceList = data.taskParams.resourceList.map( + (item: { resourceName: string }) => `${item.resourceName}` + ) + } + if (data.taskParams?.mainJar) { + params.mainJar = data.taskParams?.mainJar.resourceName + } + + if (data.taskParams?.method) { + params.method = data.taskParams?.method + } + + if (data.taskParams?.targetParams) { + const targetParams: ISqoopTargetParams = JSON.parse( + data.taskParams.targetParams + ) + params.targetType = data.taskParams.targetType + params.targetHiveDatabase = targetParams.hiveDatabase + params.targetHiveTable = targetParams.hiveTable + params.targetHiveCreateTable = targetParams.createHiveTable + params.targetHiveDropDelimiter = targetParams.dropDelimiter + params.targetHiveOverWrite = + targetParams.hiveOverWrite === void 0 ? true : targetParams.hiveOverWrite + params.targetHiveTargetDir = targetParams.hiveTargetDir + params.targetHiveReplaceDelimiter = targetParams.replaceDelimiter + params.targetHivePartitionKey = targetParams.hivePartitionKey + params.targetHivePartitionValue = targetParams.hivePartitionValue + params.targetHdfsTargetPath = targetParams.targetPath + params.targetHdfsDeleteTargetDir = + targetParams.deleteTargetDir === void 0 + ? true + : targetParams.deleteTargetDir + params.targetHdfsCompressionCodec = + targetParams.compressionCodec === void 0 + ? 'snappy' + : targetParams.compressionCodec + params.targetHdfsFileType = + targetParams.fileType === void 0 + ? '--as-avrodatafile' + : targetParams.fileType + params.targetHdfsFieldsTerminated = targetParams.fieldsTerminated + params.targetHdfsLinesTerminated = targetParams.linesTerminated + params.targetMysqlType = targetParams.targetType + params.targetMysqlDatasource = targetParams.targetDatasource + params.targetMysqlTable = targetParams.targetTable + params.targetMysqlColumns = targetParams.targetColumns + params.targetMysqlFieldsTerminated = targetParams.fieldsTerminated + params.targetMysqlLinesTerminated = targetParams.linesTerminated + params.targetMysqlIsUpdate = targetParams.isUpdate + params.targetMysqlTargetUpdateKey = targetParams.targetUpdateKey + params.targetMysqlUpdateMode = + targetParams.targetUpdateMode === void 0 + ? 'allowinsert' + : targetParams.targetUpdateMode + } + if (data.taskParams?.sourceParams) { + const sourceParams: ISqoopSourceParams = JSON.parse( + data.taskParams.sourceParams + ) + params.srcTable = sourceParams.srcTable + params.srcColumnType = sourceParams.srcColumnType + params.srcColumns = sourceParams.srcColumns + params.sourceMysqlSrcQuerySql = sourceParams.srcQuerySql + params.srcQueryType = sourceParams.srcQueryType + params.sourceMysqlType = sourceParams.srcType + params.sourceMysqlDatasource = sourceParams.srcDatasource + params.mapColumnHive = sourceParams.mapColumnHive || [] + params.mapColumnJava = sourceParams.mapColumnJava || [] + params.sourceHdfsExportDir = sourceParams.exportDir + params.sourceHiveDatabase = sourceParams.hiveDatabase + params.sourceHiveTable = sourceParams.hiveTable + params.sourceHivePartitionKey = sourceParams.hivePartitionKey + params.sourceHivePartitionValue = sourceParams.hivePartitionValue + } + + if (data.taskParams?.rawScript) { + params.rawScript = data.taskParams?.rawScript + } + + if (data.taskParams?.initScript) { + params.initScript = data.taskParams?.initScript + } + + if (data.taskParams?.switchResult) { + params.switchResult = data.taskParams.switchResult + params.dependTaskList = data.taskParams.switchResult?.dependTaskList + ? data.taskParams.switchResult?.dependTaskList + : [] + params.nextNode = data.taskParams.switchResult?.nextNode + } + + if (data.taskParams?.dependence) { + const dependence: IDependentParameters = JSON.parse( + JSON.stringify(data.taskParams.dependence) + ) + params.checkInterval = dependence.checkInterval + params.failurePolicy = dependence.failurePolicy + params.failureWaitingTime = dependence.failureWaitingTime + params.dependTaskList = dependence.dependTaskList || [] + params.relation = dependence.relation + } + + if (data.taskParams?.ruleInputParameter) { + params.check_type = data.taskParams.ruleInputParameter.check_type + params.comparison_execute_sql = + data.taskParams.ruleInputParameter.comparison_execute_sql + params.comparison_type = data.taskParams.ruleInputParameter.comparison_type + params.comparison_name = data.taskParams.ruleInputParameter.comparison_name + params.failure_strategy = + data.taskParams.ruleInputParameter.failure_strategy + params.operator = data.taskParams.ruleInputParameter.operator + params.src_connector_type = + data.taskParams.ruleInputParameter.src_connector_type + params.src_datasource_id = + data.taskParams.ruleInputParameter.src_datasource_id + params.src_database = data.taskParams.ruleInputParameter.src_database + params.src_table = data.taskParams.ruleInputParameter.src_table + params.field_length = data.taskParams.ruleInputParameter.field_length + params.begin_time = data.taskParams.ruleInputParameter.begin_time + params.deadline = data.taskParams.ruleInputParameter.deadline + params.datetime_format = data.taskParams.ruleInputParameter.datetime_format + params.target_filter = data.taskParams.ruleInputParameter.target_filter + params.regexp_pattern = data.taskParams.ruleInputParameter.regexp_pattern + params.enum_list = data.taskParams.ruleInputParameter.enum_list + params.src_filter = data.taskParams.ruleInputParameter.src_filter + params.src_field = data.taskParams.ruleInputParameter.src_field + params.statistics_execute_sql = + data.taskParams.ruleInputParameter.statistics_execute_sql + params.statistics_name = data.taskParams.ruleInputParameter.statistics_name + params.target_connector_type = + data.taskParams.ruleInputParameter.target_connector_type + params.target_datasource_id = + data.taskParams.ruleInputParameter.target_datasource_id + params.target_database = data.taskParams.ruleInputParameter.target_database + params.target_table = data.taskParams.ruleInputParameter.target_table + params.threshold = data.taskParams.ruleInputParameter.threshold + if (data.taskParams.ruleInputParameter.mapping_columns) + params.mapping_columns = JSON.parse( + data.taskParams.ruleInputParameter.mapping_columns + ) + } + if (data.taskParams?.sparkParameters) { + params.deployMode = data.taskParams.sparkParameters.deployMode + params.driverCores = data.taskParams.sparkParameters.driverCores + params.driverMemory = data.taskParams.sparkParameters.driverMemory + params.executorCores = data.taskParams.sparkParameters.executorCores + params.executorMemory = data.taskParams.sparkParameters.executorMemory + params.numExecutors = data.taskParams.sparkParameters.numExecutors + params.others = data.taskParams.sparkParameters.others + params.sqlExecutionType = data.taskParams.sparkParameters.sqlExecutionType + } + + if (data.taskParams?.conditionResult?.successNode?.length) { + params.successBranch = data.taskParams.conditionResult.successNode[0] + } + if (data.taskParams?.conditionResult?.failedNode?.length) { + params.failedBranch = data.taskParams.conditionResult.failedNode[0] + } + if (data.taskParams?.udfs) { + params.udfs = data.taskParams.udfs?.split(',') + } + if (data.taskParams?.customConfig !== void 0) { + params.customConfig = data.taskParams.customConfig === 1 ? true : false + } + if (data.taskParams?.jobType) { + params.isCustomTask = data.taskParams.jobType === 'CUSTOM' + } + + return params +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/index.module.scss b/dolphinscheduler-ui/src/views/projects/trigger/components/node/index.module.scss new file mode 100644 index 0000000000..6d9f1c9432 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/index.module.scss @@ -0,0 +1,56 @@ +/* + * 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. + */ + +.field-title { + font-weight: bold; + width: 100%; + + &::before { + content: ''; + display: inline-block; + vertical-align: -2px; + width: 4px; + height: 1em; + background-color: var(--n-color); + border-radius: 4px; + margin-right: 8px; + } +} +.relaction-label { + height: 30px; + overflow: hidden; +} +.relaction-switch { + position: relative; + cursor: pointer; + display: flex; + align-items: center; + &::before { + content: ''; + display: block; + width: 4px; + height: 100%; + background-color: var(--n-color); + border-radius: 4px; + position: absolute; + top: 0px; + left: 20px; + } +} +.display-rows-tips { + margin-top: 32px; +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/index.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/index.ts new file mode 100644 index 0000000000..41f877d80c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/index.ts @@ -0,0 +1,96 @@ +/* + * 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 { useFlink } from './use-flink' +import { useFlinkStream } from './use-flink-stream' +import { useShell } from './use-shell' +import { useSubProcess } from './use-sub-process' +import { usePigeon } from './use-pigeon' +import { usePython } from './use-python' +import { useSpark } from './use-spark' +import { useMr } from './use-mr' +import { useHttp } from './use-http' +import { useSql } from './use-sql' +import { useProcedure } from './use-procedure' +import { useSqoop } from './use-sqoop' +import { useSeaTunnel } from './use-sea-tunnel' +import { useSwitch } from './use-switch' +import { useConditions } from './use-conditions' +import { useDataX } from './use-datax' +import { useDependent } from './use-dependent' +import { useDataQuality } from './use-data-quality' +import { useEmr } from './use-emr' +import { useZeppelin } from './use-zeppelin' +import { useK8s } from './use-k8s' +import { useJupyter } from './use-jupyter' +import { useMlflow } from './use-mlflow' +import { useOpenmldb } from './use-openmldb' +import { useDvc } from './use-dvc' +import { useJava } from './use-java' +import { useDinky } from './use-dinky' +import { userSagemaker } from './use-sagemaker' +import { useChunjun } from './use-chunjun' +import { usePytorch } from './use-pytorch' +import { useHiveCli } from './use-hive-cli' +import { useDms } from './use-dms' +import { useDatasync } from './use-datasync' +import { useKubeflow } from './use-kubeflow' +import { useLinkis } from './use-linkis' +import { useDataFactory } from './use-data-factory' +import { useRemoteShell } from './use-remote-shell' +import { useDynamic } from './use-dynamic' + +export default { + SHELL: useShell, + SUB_PROCESS: useSubProcess, + DYNAMIC: useDynamic, + PYTHON: usePython, + SPARK: useSpark, + MR: useMr, + FLINK: useFlink, + HTTP: useHttp, + PIGEON: usePigeon, + SQL: useSql, + PROCEDURE: useProcedure, + SQOOP: useSqoop, + SEATUNNEL: useSeaTunnel, + SWITCH: useSwitch, + CONDITIONS: useConditions, + DATAX: useDataX, + DEPENDENT: useDependent, + DATA_QUALITY: useDataQuality, + EMR: useEmr, + ZEPPELIN: useZeppelin, + K8S: useK8s, + JUPYTER: useJupyter, + MLFLOW: useMlflow, + OPENMLDB: useOpenmldb, + DVC: useDvc, + DINKY: useDinky, + SAGEMAKER: userSagemaker, + CHUNJUN: useChunjun, + FLINK_STREAM: useFlinkStream, + JAVA: useJava, + PYTORCH: usePytorch, + HIVECLI: useHiveCli, + DMS: useDms, + DATASYNC: useDatasync, + KUBEFLOW: useKubeflow, + LINKIS: useLinkis, + DATA_FACTORY: useDataFactory, + REMOTESHELL: useRemoteShell +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-chunjun.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-chunjun.ts new file mode 100644 index 0000000000..fc24e1a7a8 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-chunjun.ts @@ -0,0 +1,73 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useChunjun({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'CHUNJUN', + flag: 'YES', + description: '', + deployMode: 'local', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + customConfig: true, + preStatements: [], + postStatements: [], + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useChunjun(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-conditions.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-conditions.ts new file mode 100644 index 0000000000..08e325099f --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-conditions.ts @@ -0,0 +1,69 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useConditions({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'CONDITIONS', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + timeout: 30, + relation: 'AND', + dependTaskList: [], + preTasks: [], + successNode: 'success', + failedNode: 'failed', + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useConditions(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-data-factory.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-data-factory.ts new file mode 100644 index 0000000000..91fe1ff2f7 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-data-factory.ts @@ -0,0 +1,72 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useDataFactory({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'DATA_FACTORY', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'], + factoryName: '', + resourceGroupName: '', + pipelineName: '' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDataFactory(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-data-quality.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-data-quality.ts new file mode 100644 index 0000000000..c45dfa7044 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-data-quality.ts @@ -0,0 +1,107 @@ +/* + * 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, reactive } from 'vue' +import { useI18n } from 'vue-i18n' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useDataQuality({ + projectCode, + from = 0, + readonly, + data, + jsonRef, + updateElements +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData + jsonRef: Ref + updateElements: () => void +}) { + const { t } = useI18n() + const model = reactive({ + taskType: 'DATA_QUALITY', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + timeoutNotifyStrategy: ['WARN'], + timeout: 30, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + ruleId: 1, + deployMode: 'cluster', + driverCores: 1, + driverMemory: '512M', + numExecutors: 2, + executorMemory: '2G', + executorCores: 2, + others: '--conf spark.yarn.maxAppAttempts=1', + yarnQueue: '' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useRules(model, (items: IJsonItem[], len: number) => { + jsonRef.value.splice(15, len, ...items) + updateElements() + }), + Fields.useDeployMode(), + Fields.useDriverCores(), + Fields.useDriverMemory(), + Fields.useExecutorNumber(), + Fields.useExecutorMemory(), + Fields.useExecutorCores(), + Fields.useYarnQueue(), + { + type: 'input', + field: 'others', + name: t('project.node.option_parameters'), + props: { + type: 'textarea', + placeholder: t('project.node.option_parameters_tips') + } + }, + ...Fields.useCustomParams({ + model, + field: 'localParams', + isSimple: true + }), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-datasync.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-datasync.ts new file mode 100644 index 0000000000..843f90f349 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-datasync.ts @@ -0,0 +1,83 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useDatasync({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'DATASYNC', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + let extra: IJsonItem[] = [] + if (from === 1) { + extra = [ + Fields.useTaskType(model, readonly), + Fields.useProcessName({ + model, + projectCode, + isCreate: !data?.id, + from, + processName: data?.processName + }) + ] + } + + return { + json: [ + Fields.useName(from), + ...extra, + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDatasync(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-datax.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-datax.ts new file mode 100644 index 0000000000..b1344fbf35 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-datax.ts @@ -0,0 +1,77 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useDataX({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'DATAX', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + cpuQuota: -1, + memoryMax: -1, + delayTime: 0, + timeout: 30, + customConfig: false, + dsType: 'MYSQL', + dtType: 'MYSQL', + preStatements: [], + postStatements: [], + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDataX(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dependent.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dependent.ts new file mode 100644 index 0000000000..b140eea7f3 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dependent.ts @@ -0,0 +1,72 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useDependent({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'DEPENDENT', + name: '', + flag: 'YES', + description: '', + timeoutShowFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + relation: 'AND', + dependTaskList: [], + preTasks: [], + timeoutNotifyStrategy: [], + timeout: 30, + timeoutFlag: false, + failurePolicy: 'DEPENDENT_FAILURE_FAILURE', + checkInterval: 10, + ...data + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useDependent(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dinky.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dinky.ts new file mode 100644 index 0000000000..846a6d7872 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dinky.ts @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useDinky({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'DINKY', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDinky(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dms.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dms.ts new file mode 100644 index 0000000000..7fe0922a73 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dms.ts @@ -0,0 +1,84 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useDms({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'DMS', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'], + isRestartTask: false + } as INodeData) + + let extra: IJsonItem[] = [] + if (from === 1) { + extra = [ + Fields.useTaskType(model, readonly), + Fields.useProcessName({ + model, + projectCode, + isCreate: !data?.id, + from, + processName: data?.processName + }) + ] + } + + return { + json: [ + Fields.useName(from), + ...extra, + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDms(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dvc.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dvc.ts new file mode 100644 index 0000000000..d8376a5c9c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dvc.ts @@ -0,0 +1,69 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useDvc({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'MLFLOW', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'], + dvcTaskType: 'Upload' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDvc(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dynamic.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dynamic.ts new file mode 100644 index 0000000000..8f498fbfe9 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-dynamic.ts @@ -0,0 +1,83 @@ +/* + * 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 { reactive } from 'vue' +import { useRouter } from 'vue-router' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useDynamic({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const router = useRouter() + const workflowCode = router.currentRoute.value.params.code + const model = reactive({ + taskType: 'DYNAMIC', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + maxNumOfSubWorkflowInstances: 1024, + degreeOfParallelism: 1, + filterCondition: '', + listParameters: [{ name: null, value: null, separator: ',' }] + } as INodeData) + + if (model.listParameters?.length) { + model.listParameters[0].disabled = true + } + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useTimeoutAlarm(model), + Fields.useChildNode({ + model, + projectCode, + from, + processName: data?.processName, + code: from === 1 ? 0 : Number(workflowCode) + }), + ...Fields.useDynamic(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-emr.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-emr.ts new file mode 100644 index 0000000000..7af5aa3e3a --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-emr.ts @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useEmr({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'EMR', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + programType: 'ADD_JOB_FLOW_STEPS', + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useEmr(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-flink-stream.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-flink-stream.ts new file mode 100644 index 0000000000..0b35f9f275 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-flink-stream.ts @@ -0,0 +1,76 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useFlinkStream({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'FLINK_STREAM', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + programType: 'SCALA', + deployMode: 'cluster', + initScript: '', + rawScript: '', + flinkVersion: '<1.10', + jobManagerMemory: '1G', + taskManagerMemory: '2G', + slot: 1, + taskManager: 2, + parallelism: 1, + timeoutNotifyStrategy: ['WARN'], + yarnQueue: '' + }) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + Fields.useDelayTime(model), + ...Fields.useFlink(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-flink.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-flink.ts new file mode 100644 index 0000000000..204bfc7141 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-flink.ts @@ -0,0 +1,79 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useFlink({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'FLINK', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + programType: 'SCALA', + deployMode: 'cluster', + initScript: '', + rawScript: '', + flinkVersion: '<1.10', + jobManagerMemory: '1G', + taskManagerMemory: '2G', + slot: 1, + taskManager: 2, + parallelism: 1, + timeoutNotifyStrategy: ['WARN'], + yarnQueue: '' + }) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useFlink(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-hive-cli.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-hive-cli.ts new file mode 100644 index 0000000000..e9e485a9b7 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-hive-cli.ts @@ -0,0 +1,82 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useHiveCli({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'HIVECLI', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + hiveCliTaskExecutionType: 'SCRIPT' + } as INodeData) + + let extra: IJsonItem[] = [] + if (from === 1) { + extra = [ + Fields.useTaskType(model, readonly), + Fields.useProcessName({ + model, + projectCode, + isCreate: !data?.id, + from, + processName: data?.processName + }) + ] + } + + return { + json: [ + Fields.useName(from), + ...extra, + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useHiveCli(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-http.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-http.ts new file mode 100644 index 0000000000..0e5d5fe5ca --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-http.ts @@ -0,0 +1,76 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useHttp({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'HTTP', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + httpMethod: 'GET', + httpBody: '', + httpCheckCondition: 'STATUS_CODE_DEFAULT', + httpParams: [], + url: '', + condition: '', + connectTimeout: 60000, + socketTimeout: 60000, + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useHttp(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-java.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-java.ts new file mode 100644 index 0000000000..1eb99de965 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-java.ts @@ -0,0 +1,90 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useJava({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'JAVA', + flag: 'YES', + description: '', + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + isModulePath: false, + rawScript: '', + timeoutFlag: false, + timeoutNotifyStrategy: ['WARN'], + timeout: 30, + mainJar: undefined, + runType: 'JAVA', + mainArgs: '', + jvmArgs: '', + programType: 'JAVA' + } as unknown as INodeData) + + let extra: IJsonItem[] = [] + if (from === 1) { + extra = [ + Fields.useTaskType(model, readonly), + Fields.useProcessName({ + model, + projectCode, + isCreate: !data?.id, + from, + processName: data?.processName + }) + ] + } + + return { + json: [ + Fields.useName(from), + ...extra, + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useJava(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-jupyter.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-jupyter.ts new file mode 100644 index 0000000000..1901209e73 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-jupyter.ts @@ -0,0 +1,71 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useJupyter({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'JUPYTER', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + cpuQuota: -1, + memoryMax: -1, + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useJupyter(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-k8s.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-k8s.ts new file mode 100644 index 0000000000..e20a506df6 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-k8s.ts @@ -0,0 +1,76 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useK8s({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'K8S', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + customizedLabels: [], + nodeSelectors: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + type: 'K8S', + displayRows: 10, + timeoutNotifyStrategy: ['WARN'], + kubeConfig: '', + namespace: '' + } as INodeData) + + return { + json: [ + Fields.useName(), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDatasource(model), + ...Fields.useK8s(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-kubeflow.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-kubeflow.ts new file mode 100644 index 0000000000..1c721a6dcd --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-kubeflow.ts @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useKubeflow({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'KUBEFLOW', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useKubeflow(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-linkis.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-linkis.ts new file mode 100644 index 0000000000..5507f79bf6 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-linkis.ts @@ -0,0 +1,80 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useLinkis({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'LINKIS', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + cpuQuota: -1, + memoryMax: -1, + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'], + useCustom: false, + paramScript: [ + { + prop: '', + value: '' + } + ], + rawScript: '' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useLinkis(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-mlflow.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-mlflow.ts new file mode 100644 index 0000000000..b25fdae436 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-mlflow.ts @@ -0,0 +1,76 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useMlflow({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'MLFLOW', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + algorithm: 'svm', + mlflowTrackingUri: 'http://127.0.0.1:5000', + mlflowTaskType: 'MLflow Projects', + deployType: 'MLFLOW', + deployPort: '7000', + mlflowJobType: 'CustomProject', + automlTool: 'flaml', + mlflowCustomProjectParameters: [], + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useMlflow(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-mr.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-mr.ts new file mode 100644 index 0000000000..4552133a20 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-mr.ts @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useMr({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'MR', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + programType: 'SCALA', + timeoutNotifyStrategy: ['WARN'], + yarnQueue: '' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useMr(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-openmldb.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-openmldb.ts new file mode 100644 index 0000000000..18bd0deadc --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-openmldb.ts @@ -0,0 +1,72 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useOpenmldb({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'OPENMLDB', + flag: 'YES', + description: '', + timeoutFlag: false, + timeoutNotifyStrategy: ['WARN'], + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + zk: '', + zkPath: '', + executeMode: 'offline' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useOpenmldb(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-pigeon.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-pigeon.ts new file mode 100644 index 0000000000..22b879919b --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-pigeon.ts @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function usePigeon({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'PIGEON', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + targetJobName: '', + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + Fields.useTargetTaskName(), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-procedure.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-procedure.ts new file mode 100644 index 0000000000..90f2491613 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-procedure.ts @@ -0,0 +1,73 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useProcedure({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'PROCEDURE', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + type: data?.taskParams?.type ? data?.taskParams?.type : 'MYSQL', + datasource: data?.taskParams?.datasource, + method: data?.taskParams?.method, + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDatasource(model), + ...Fields.useProcedure(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-python.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-python.ts new file mode 100644 index 0000000000..09f598e1d4 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-python.ts @@ -0,0 +1,73 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function usePython({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'PYTHON', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + cpuQuota: -1, + memoryMax: -1, + delayTime: 0, + timeout: 30, + rawScript: '', + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useShell(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-pytorch.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-pytorch.ts new file mode 100644 index 0000000000..ca0776aa38 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-pytorch.ts @@ -0,0 +1,88 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function usePytorch({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'PYTORCH', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'], + pythonEnvTool: 'conda', + pythonCommand: '${PYTHON_LAUNCHER}', + condaPythonVersion: '3.7', + requirements: 'requirements.txt', + pythonPath: '.' + } as INodeData) + + let extra: IJsonItem[] = [] + if (from === 1) { + extra = [ + Fields.useTaskType(model, readonly), + Fields.useProcessName({ + model, + projectCode, + isCreate: !data?.id, + from, + processName: data?.processName + }) + ] + } + + return { + json: [ + Fields.useName(from), + ...extra, + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.usePytorch(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-remote-shell.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-remote-shell.ts new file mode 100644 index 0000000000..977776510d --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-remote-shell.ts @@ -0,0 +1,74 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useRemoteShell({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'REMOTESHELL', + flag: 'YES', + description: '', + timeoutFlag: false, + timeoutNotifyStrategy: ['WARN'], + timeout: 30, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + type: 'SSH', + rawScript: '' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDatasource(model, { + supportedDatasourceType: ['SSH'] + }), + ...Fields.useRemoteShell(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sagemaker.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sagemaker.ts new file mode 100644 index 0000000000..88a38d8ea7 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sagemaker.ts @@ -0,0 +1,74 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function userSagemaker({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'MLFLOW', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + type: 'SAGEMAKER', + displayRows: 10, + timeoutNotifyStrategy: ['WARN'], + username: '', + password: '', + awsRegion: '' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDatasource(model), + ...Fields.useSagemaker(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sea-tunnel.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sea-tunnel.ts new file mode 100644 index 0000000000..1cf03008b9 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sea-tunnel.ts @@ -0,0 +1,104 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useSeaTunnel({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'SEATUNNEL', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + cpuQuota: -1, + memoryMax: -1, + delayTime: 0, + timeout: 30, + startupScript: 'seatunnel.sh', + runMode: 'RUN', + useCustom: true, + deployMode: 'client', + master: 'YARN', + masterUrl: '', + resourceFiles: [], + timeoutNotifyStrategy: ['WARN'], + rawScript: + 'env {\n' + + ' execution.parallelism = 2\n' + + ' job.mode = "BATCH"\n' + + ' checkpoint.interval = 10000\n' + + '}\n' + + '\n' + + 'source {\n' + + ' FakeSource {\n' + + ' parallelism = 2\n' + + ' result_table_name = "fake"\n' + + ' row.num = 16\n' + + ' schema = {\n' + + ' fields {\n' + + ' name = "string"\n' + + ' age = "int"\n' + + ' }\n' + + ' }\n' + + ' }\n' + + '}\n' + + '\n' + + 'sink {\n' + + ' Console {\n' + + ' }\n' + + '}' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useSeaTunnel(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-shell.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-shell.ts new file mode 100644 index 0000000000..96b1c9ce6c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-shell.ts @@ -0,0 +1,72 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useShell({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'SHELL', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + timeoutNotifyStrategy: ['WARN'], + timeout: 30, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + cpuQuota: -1, + memoryMax: -1, + delayTime: 0, + rawScript: '' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useShell(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-spark.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-spark.ts new file mode 100644 index 0000000000..1e5c929b0f --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-spark.ts @@ -0,0 +1,79 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useSpark({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'SPARK', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + programType: 'SCALA', + rawScript: '', + master: '', + deployMode: '', + driverCores: 1, + driverMemory: '512M', + numExecutors: 2, + executorMemory: '2G', + executorCores: 2, + yarnQueue: '', + timeoutNotifyStrategy: ['WARN'], + sqlExecutionType: 'SCRIPT' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useSpark(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sql.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sql.ts new file mode 100644 index 0000000000..e733387c1d --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sql.ts @@ -0,0 +1,78 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useSql({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'SQL', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + type: 'MYSQL', + displayRows: 10, + sql: '', + sqlType: '0', + preStatements: [], + postStatements: [], + udfs: [], + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDatasource(model), + ...Fields.useSqlType(model), + ...Fields.useSql(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sqoop.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sqoop.ts new file mode 100644 index 0000000000..f401fb6d2c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sqoop.ts @@ -0,0 +1,92 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useSqoop({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'SQOOP', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + cpuQuota: -1, + memoryMax: -1, + delayTime: 0, + timeout: 30, + isCustomTask: false, + hadoopCustomParams: [], + sqoopAdvancedParams: [], + mapColumnHive: [], + mapColumnJava: [], + modelType: 'import', + sourceType: 'MYSQL', + srcQueryType: '1', + srcColumnType: '0', + targetType: 'HIVE', + sourceMysqlType: 'MYSQL', + targetHdfsDeleteTargetDir: true, + targetHdfsCompressionCodec: 'snappy', + targetHdfsFileType: '--as-avrodatafile', + targetMysqlType: 'MYSQL', + targetMysqlUpdateMode: 'allowinsert', + targetHiveCreateTable: false, + targetHiveDropDelimiter: false, + targetHiveOverWrite: true, + concurrency: 1, + splitBy: '', + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + ...Fields.useResourceLimit(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useSqoop(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sub-process.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sub-process.ts new file mode 100644 index 0000000000..8c855666bc --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-sub-process.ts @@ -0,0 +1,74 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import { useRouter } from 'vue-router' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useSubProcess({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const router = useRouter() + const workflowCode = router.currentRoute.value.params.code + const model = reactive({ + taskType: 'SUB_PROCESS', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useTimeoutAlarm(model), + Fields.useChildNode({ + model, + projectCode, + from, + processName: data?.processName, + code: from === 1 ? 0 : Number(workflowCode) + }), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-switch.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-switch.ts new file mode 100644 index 0000000000..1e6d3f80cc --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-switch.ts @@ -0,0 +1,71 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useSwitch({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + taskType: 'SWITCH', + name: '', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + rawScript: '', + switchResult: {}, + dependTaskList: [], + nextNode: undefined, + timeoutNotifyStrategy: ['WARN'] + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useSwitch(model, projectCode), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-zeppelin.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-zeppelin.ts new file mode 100644 index 0000000000..c8ac1260e4 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/tasks/use-zeppelin.ts @@ -0,0 +1,74 @@ +/* + * 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 { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData, ITaskData } from '../types' + +export function useZeppelin({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'ZEPPELIN', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + type: 'ZEPPELIN', + displayRows: 10, + timeoutNotifyStrategy: ['WARN'], + restEndpoint: '', + username: '', + password: '' + } as INodeData) + + return { + json: [ + Fields.useName(from), + ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }), + Fields.useRunFlag(), + Fields.useCache(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(projectCode), + Fields.useEnvironmentName(model, !data?.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDatasource(model), + ...Fields.useZeppelin(model), + Fields.usePreTasks() + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/types.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/types.ts new file mode 100644 index 0000000000..0f6e1cd0c7 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/types.ts @@ -0,0 +1,555 @@ +/* + * 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 { VNode } from 'vue' +import type { SelectOption } from 'naive-ui' +import type { TaskExecuteType, TriggerType } from '@/store/project/types' +import type { IDataBase } from '@/service/modules/data-source/types' +import type { + IFormItem, + IJsonItem, + FormRules, + IJsonItemParams +} from '@/components/form/types' +export type { EditWorkflowDefinition } from '@/views/projects/workflow/components/dag/types' +export type { + IWorkflowTaskInstance, + WorkflowInstance +} from '@/views/projects/workflow/components/dag/types' +export type { IResource, ProgramType, IMainJar } from '@/store/project/types' +export type { ITaskState } from '@/common/types' + +export type RelationType = 'AND' | 'OR' + +type SourceType = 'MYSQL' | 'HDFS' | 'HIVE' +type ModelType = 'import' | 'export' +type ITriggerType = TriggerType +type IDateType = 'hour' | 'day' | 'week' | 'month' + +interface IOption { + label: string + value: string | number +} + +interface IRenderOption extends IOption { + filterLabel: string +} + +interface ITaskPriorityOption extends SelectOption { + icon: VNode + color: string +} +interface IEnvironmentNameOption { + label: string + value: string + workerGroups?: string[] +} + +interface ILocalParam { + prop: string + direct?: string + type?: string + value?: string +} + +interface ILabel { + label: string + value: string +} + +interface IMatchExpression { + key: string + operator: string + values: string +} + +interface IResponseJsonItem extends Omit { + type: 'input' | 'select' | 'radio' | 'group' + emit: 'change'[] +} + +interface IDependentItemOptions { + dependentTypeOptions?: IOption[] + definitionCodeOptions?: IOption[] + depTaskCodeOptions?: IOption[] + dateOptions?: IOption[] +} + +interface IDependTaskOptions { + dependItemList: IDependentItemOptions[] +} + +interface IDependentItem { + depTaskCode?: number + status?: 'SUCCESS' | 'FAILURE' + projectCode?: number + definitionCode?: number + cycle?: 'month' | 'week' | 'day' | 'hour' + dateValue?: string + dependentType?: 'DEPENDENT_ON_WORKFLOW' | 'DEPENDENT_ON_TASK' + parameterPassing?: boolean +} + +interface IDependTask { + condition?: string + nextNode?: number + relation?: RelationType + dependItemList?: IDependentItem[] +} + +interface ISwitchResult { + dependTaskList?: IDependTask[] + nextNode?: number +} + +interface IDependentParameters { + checkInterval?: number + failurePolicy?: 'DEPENDENT_FAILURE_FAILURE' | 'DEPENDENT_FAILURE_WAITING' + failureWaitingTime?: number + relation?: RelationType + dependTaskList?: IDependTask[] +} + +/* + * resourceName: resource full name + * res: resource file name + */ +interface ISourceItem { + id?: number + resourceName: string + res?: string +} + +interface ISqoopTargetData { + targetHiveDatabase?: string + targetHiveTable?: string + targetHiveCreateTable?: boolean + targetHiveDropDelimiter?: boolean + targetHiveOverWrite?: boolean + targetHiveTargetDir?: string + targetHiveReplaceDelimiter?: string + targetHivePartitionKey?: string + targetHivePartitionValue?: string + targetHdfsTargetPath?: string + targetHdfsDeleteTargetDir?: boolean + targetHdfsCompressionCodec?: string + targetHdfsFileType?: string + targetHdfsFieldsTerminated?: string + targetHdfsLinesTerminated?: string + targetMysqlType?: string + targetMysqlDatasource?: string + targetMysqlTable?: string + targetMysqlColumns?: string + targetMysqlFieldsTerminated?: string + targetMysqlLinesTerminated?: string + targetMysqlIsUpdate?: string + targetMysqlTargetUpdateKey?: string + targetMysqlUpdateMode?: string +} + +interface ISqoopSourceData { + srcQueryType?: '1' | '0' + srcTable?: string + srcColumnType?: '1' | '0' + srcColumns?: string + sourceMysqlSrcQuerySql?: string + sourceMysqlType?: string + sourceMysqlDatasource?: string + mapColumnHive?: ILocalParam[] + mapColumnJava?: ILocalParam[] + sourceHdfsExportDir?: string + sourceHiveDatabase?: string + sourceHiveTable?: string + sourceHivePartitionKey?: string + sourceHivePartitionValue?: string +} + +interface ISqoopTargetParams { + hiveDatabase?: string + hiveTable?: string + createHiveTable?: boolean + dropDelimiter?: boolean + hiveOverWrite?: boolean + hiveTargetDir?: string + replaceDelimiter?: string + hivePartitionKey?: string + hivePartitionValue?: string + targetPath?: string + deleteTargetDir?: boolean + compressionCodec?: string + fileType?: string + fieldsTerminated?: string + linesTerminated?: string + targetType?: string + targetDatasource?: string + targetTable?: string + targetColumns?: string + isUpdate?: string + targetUpdateKey?: string + targetUpdateMode?: string +} +interface ISqoopSourceParams { + srcTable?: string + srcColumnType?: '1' | '0' + srcColumns?: string + srcQuerySql?: string + srcQueryType?: '1' | '0' + srcType?: string + srcDatasource?: string + mapColumnHive?: ILocalParam[] + mapColumnJava?: ILocalParam[] + exportDir?: string + hiveDatabase?: string + hiveTable?: string + hivePartitionKey?: string + hivePartitionValue?: string +} +interface ISparkParameters { + deployMode?: string + driverCores?: number + driverMemory?: string + executorCores?: number + executorMemory?: string + numExecutors?: number + others?: string + yarnQueue?: string + sqlExecutionType?: string +} + +interface IRuleParameters { + check_type?: string + comparison_execute_sql?: string + comparison_name?: string + comparison_type?: number + failure_strategy?: string + operator?: string + src_connector_type?: number + src_datasource_id?: number + src_database?: string + src_table?: string + field_length?: number + begin_time?: string + deadline?: string + datetime_format?: string + target_filter?: string + regexp_pattern?: string + enum_list?: string + src_filter?: string + src_field?: string + statistics_execute_sql?: string + statistics_name?: string + target_connector_type?: number + target_datasource_id?: number + target_database?: string + target_table?: string + threshold?: string + mapping_columns?: string +} + +interface ITriggerParams { + resourceList?: ISourceItem[] + mainJar?: ISourceItem + localParams?: ILocalParam[] + runType?: string + jvmArgs?: string + isModulePath?: boolean + rawScript?: string + initScript?: string + programType?: string + flinkVersion?: string + jobManagerMemory?: string + taskManagerMemory?: string + slot?: number + taskManager?: number + parallelism?: number + mainClass?: string + deployMode?: string + appName?: string + driverCores?: number + driverMemory?: string + numExecutors?: number + executorMemory?: string + executorCores?: number + mainArgs?: string + others?: string + httpMethod?: string + httpBody?: string + httpCheckCondition?: string + httpParams?: [] + url?: string + condition?: string + connectTimeout?: number + socketTimeout?: number + type?: string + datasource?: string + sql?: string + sqlType?: string + sendEmail?: boolean + displayRows?: number + title?: string + groupId?: string + preStatements?: string[] + postStatements?: string[] + method?: string + jobType?: 'CUSTOM' | 'TEMPLATE' + customShell?: string + jobName?: string + hadoopCustomParams?: ILocalParam[] + sqoopAdvancedParams?: ILocalParam[] + concurrency?: number + splitBy?: string + modelType?: ModelType + sourceType?: SourceType + targetType?: SourceType + targetParams?: string + sourceParams?: string + queue?: string + master?: string + masterUrl?: string + switchResult?: ISwitchResult + dependTaskList?: IDependTask[] + nextNode?: number + dependence?: IDependentParameters + customConfig?: number + json?: string + dsType?: string + dataSource?: number + dtType?: string + dataTarget?: number + targetTable?: string + jobSpeedByte?: number + jobSpeedRecord?: number + xms?: number + xmx?: number + sparkParameters?: ISparkParameters + ruleId?: number + ruleInputParameter?: IRuleParameters + jobFlowDefineJson?: string + stepsDefineJson?: string + zeppelinNoteId?: string + zeppelinParagraphId?: string + zeppelinRestEndpoint?: string + restEndpoint?: string + zeppelinUsername?: string + username?: string + zeppelinPassword?: string + password?: string + zeppelinProductionNoteDirectory?: string + productionNoteDirectory?: string + hiveCliOptions?: string + hiveSqlScript?: string + hiveCliTaskExecutionType?: string + sqlExecutionType?: string + noteId?: string + paragraphId?: string + condaEnvName?: string + inputNotePath?: string + outputNotePath?: string + parameters?: string + kernel?: string + engine?: string + startupScript?: string + executionTimeout?: string + startTimeout?: string + processDefinitionCode?: number + conditionResult?: { + successNode?: number[] + failedNode?: number[] + } + udfs?: string + connParams?: string + targetJobName?: string + cluster?: string + namespace?: string + clusterNamespace?: string + minCpuCores?: string + minMemorySpace?: string + image?: string + imagePullPolicy?: string + pullSecret?: string + command?: string + args?: string + customizedLabels?: ILabel[] + nodeSelectors?: IMatchExpression[] + algorithm?: string + params?: string + searchParams?: string + dataPath?: string + experimentName?: string + modelName?: string + mlflowTrackingUri?: string + mlflowJobType?: string + automlTool?: string + registerModel?: boolean + mlflowTaskType?: string + mlflowProjectRepository?: string + mlflowProjectVersion?: string + deployType?: string + deployPort?: string + deployModelKey?: string + cpuLimit?: string + memoryLimit?: string + zk?: string + zkPath?: string + executeMode?: string + useCustom?: boolean + runMode?: string + dvcTaskType?: string + dvcRepository?: string + dvcVersion?: string + dvcDataLocation?: string + dvcMessage?: string + dvcLoadSaveDataPath?: string + dvcStoreUrl?: string + address?: string + taskId?: string + online?: boolean + sagemakerRequestJson?: string + script?: string + scriptParams?: string + pythonPath?: string + isCreateEnvironment?: string + pythonCommand?: string + pythonEnvTool?: string + requirements?: string + condaPythonVersion?: string + isRestartTask?: boolean + isJsonFormat?: boolean + jsonData?: string + migrationType?: string + replicationTaskIdentifier?: string + sourceEndpointArn?: string + targetEndpointArn?: string + replicationInstanceArn?: string + tableMappings?: string + replicationTaskArn?: string + jsonFormat?: boolean + destinationLocationArn?: string + sourceLocationArn?: string + name?: string + cloudWatchLogGroupArn?: string + yamlContent?: string + paramScript?: ILocalParam[] + factoryName?: string + resourceGroupName?: string + pipelineName?: string + maxNumOfSubWorkflowInstances?: number + degreeOfParallelism?: number + filterCondition?: string + listParameters?: Array + yarnQueue?: string + awsRegion?: string + kubeConfig?: string +} + +interface INodeData + extends Omit< + ITriggerParams, + | 'resourceList' + | 'mainJar' + | 'targetParams' + | 'sourceParams' + | 'dependence' + | 'sparkParameters' + | 'conditionResult' + | 'udfs' + | 'customConfig' + >, + ISqoopTargetData, + ISqoopSourceData, + IDependentParameters, + Omit { + id?: string + triggerType?: ITriggerType + processName?: number + delayTime?: number + description?: string + environmentCode?: number | null + failRetryInterval?: number + failRetryTimes?: number + cpuQuota?: number + memoryMax?: number + flag?: 'YES' | 'NO' + isCache?: boolean + taskGroupId?: number + taskGroupPriority?: number + taskPriority?: string + timeout?: number + timeoutFlag?: boolean + timeoutNotifyStrategy?: string[] + workerGroup?: string + code?: number + name?: string + preTasks?: number[] + preTaskOptions?: [] + postTaskOptions?: [] + resourceList?: string[] + mainJar?: string + timeoutSetting?: boolean + isCustomTask?: boolean + method?: string + resourceFiles?: { id: number; fullName: string }[] | null + relation?: RelationType + definition?: object + successBranch?: number + failedBranch?: number + udfs?: string[] + customConfig?: boolean + mapping_columns?: object[] + taskExecuteType?: TaskExecuteType +} + +interface ITriggerData + extends Omit< + INodeData, + 'isCache' | 'timeoutFlag' | 'taskPriority' | 'timeoutNotifyStrategy' + > { + name?: string + taskPriority?: string + isCache?: 'YES' | 'NO' + timeoutFlag?: 'OPEN' | 'CLOSE' + timeoutNotifyStrategy?: string | [] + triggerParams?: ITriggerParams +} + +export { + ITaskPriorityOption, + IEnvironmentNameOption, + ILocalParam, + ITriggerType, + ITriggerData, + INodeData, + ITriggerParams, + IOption, + IRenderOption, + IDataBase, + ModelType, + SourceType, + ISqoopSourceParams, + ISqoopTargetParams, + IDependTask, + IDependentItem, + IDependentItemOptions, + IDependTaskOptions, + IFormItem, + IJsonItem, + FormRules, + IJsonItemParams, + IResponseJsonItem, + IDateType, + IDependentParameters +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/components/node/use-task.ts b/dolphinscheduler-ui/src/views/projects/trigger/components/node/use-task.ts new file mode 100644 index 0000000000..c9c804188c --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/components/node/use-task.ts @@ -0,0 +1,82 @@ +/* + * 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, unref } from 'vue' +import nodes from './tasks' +import getElementByJson from '@/components/form/get-elements-by-json' +import { useTaskNodeStore } from '@/store/project/task-node' +import { TASK_TYPES_MAP } from '@/store/project/task-type' +import type { + EditWorkflowDefinition, + FormRules, + IFormItem, + IJsonItem, + INodeData, + ITaskData +} from './types' + +export function useTask({ + data, + projectCode, + from, + readonly, + definition +}: { + data: ITaskData + projectCode: number + from?: number + readonly?: boolean + definition?: EditWorkflowDefinition +}): { + elementsRef: Ref + rulesRef: Ref + model: INodeData +} { + const taskStore = useTaskNodeStore() + taskStore.updateDefinition(unref(definition), data?.code) + + const jsonRef = ref([]) as Ref + const elementsRef = ref([]) as Ref + const rulesRef = ref({}) + + const params = { + projectCode, + from, + readonly, + data, + jsonRef, + updateElements: () => { + getElements() + } + } + + const { model, json } = nodes[data.taskType || 'SHELL'](params) + jsonRef.value = json + model.preTasks = taskStore.getPreTasks + model.name = taskStore.getName + model.taskExecuteType = + TASK_TYPES_MAP[data.taskType || 'SHELL'].taskExecuteType || 'BATCH' + + const getElements = () => { + const { rules, elements } = getElementByJson(jsonRef.value, model) + elementsRef.value = elements + rulesRef.value = rules + } + + getElements() + + return { elementsRef, rulesRef, model } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/definition/components/start-modal.tsx b/dolphinscheduler-ui/src/views/projects/trigger/definition/components/start-modal.tsx new file mode 100644 index 0000000000..10b2098058 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/definition/components/start-modal.tsx @@ -0,0 +1,272 @@ +/* + * 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, + toRefs, + onMounted, + watch, + getCurrentInstance +} from 'vue' +import { useI18n } from 'vue-i18n' +import Modal from '@/components/modal' +import { useStart } from './use-start' +import { + NForm, + NFormItem, + NButton, + NIcon, + NInput, + NSpace, + NSelect, + NSwitch +} from 'naive-ui' +import { DeleteOutlined, PlusCircleOutlined } from '@vicons/antd' + +const props = { + row: { + type: Object, + default: {} + }, + show: { + type: Boolean as PropType, + default: false + }, + taskCode: { + type: String + } +} + +export default defineComponent({ + name: 'task-definition-start', + props, + emits: ['update:show', 'update:row', 'updateList'], + setup(props, ctx) { + const { t } = useI18n() + const { + variables, + handleStartDefinition, + getWorkerGroups, + getTenantList, + getAlertGroups, + getEnvironmentList, + getStartParamsList + } = useStart(ctx) + + const generalWarningTypeListOptions = () => [ + { + value: 'NONE', + label: t('project.task.none_send') + }, + { + value: 'SUCCESS', + label: t('project.task.success_send') + }, + { + value: 'FAILURE', + label: t('project.task.failure_send') + }, + { + value: 'ALL', + label: t('project.task.all_send') + } + ] + + const hideModal = () => { + ctx.emit('update:show') + } + + const handleStart = () => { + handleStartDefinition(props.row.taskCode) + } + + const updateWorkerGroup = () => { + variables.startForm.environmentCode = null + } + + const addStartParams = () => { + variables.startState.startParamsList.push({ + prop: '', + value: '' + }) + } + + const updateParamsList = (index: number, param: Array) => { + variables.startState.startParamsList[index].prop = param[0] + variables.startState.startParamsList[index].value = param[1] + } + + const removeStartParams = (index: number) => { + variables.startState.startParamsList.splice(index, 1) + } + + const trim = getCurrentInstance()?.appContext.config.globalProperties.trim + + onMounted(() => { + getWorkerGroups() + getTenantList() + getAlertGroups() + getEnvironmentList() + }) + + watch( + () => props.show, + () => { + if (props.show) { + getStartParamsList(props.row.processDefinitionCode) + } + } + ) + + return { + t, + hideModal, + handleStart, + updateWorkerGroup, + removeStartParams, + addStartParams, + updateParamsList, + generalWarningTypeListOptions, + ...toRefs(variables), + ...toRefs(variables.startState), + ...toRefs(props), + trim + } + }, + + render() { + const { t } = this + + return ( + + + +
{this.row.taskName}
+
+ + + + + + + + + + + + item.workerGroups?.includes(this.startForm.workerGroup) + )} + v-model:value={this.startForm.environmentCode} + clearable + /> + + + + + + {this.startParamsList.length === 0 ? ( + + + + + + ) : ( + + {this.startParamsList.map((item, index) => ( + + + this.updateParamsList(index, param) + } + /> + this.removeStartParams(index)} + class='btn-delete-custom-parameter' + > + + + + + + + + + + + ))} + + )} + + + + +
+
+ ) + } +}) diff --git a/dolphinscheduler-ui/src/views/projects/trigger/definition/components/use-start.tsx b/dolphinscheduler-ui/src/views/projects/trigger/definition/components/use-start.tsx new file mode 100644 index 0000000000..f824a4dba8 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/definition/components/use-start.tsx @@ -0,0 +1,156 @@ +/* + * 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 { startTaskDefinition } from '@/service/modules/task-definition' +import _ from 'lodash' +import { reactive, ref, SetupContext } from 'vue' +import { useI18n } from 'vue-i18n' +import { useRoute } from 'vue-router' +import { queryProcessDefinitionByCode } from '@/service/modules/process-definition' +import { queryAllWorkerGroups } from '@/service/modules/worker-groups' +import { queryTenantList } from '@/service/modules/tenants' +import { queryAllEnvironmentList } from '@/service/modules/environment' +import { listNormalAlertGroupById } from '@/service/modules/alert-group' +import type { EnvironmentItem } from '@/service/modules/environment/types' +import type { IStartState } from '../types' + +export const useStart = ( + ctx: SetupContext<('update:show' | 'update:row' | 'updateList')[]> +) => { + const { t } = useI18n() + const route = useRoute() + + const variables = reactive({ + startFormRef: ref(), + startForm: { + version: 1, + warningType: 'NONE', + warningGroupId: null, + workerGroup: 'default', + tenantCode: 'default', + environmentCode: null, + startParams: null as null | string, + dryRun: 0 + }, + startState: { + projectCode: Number(route.params.projectCode), + workerGroups: [], + tenantList: [], + alertGroups: [], + environmentList: [], + startParamsList: [] + } as IStartState, + saving: false + }) + + const cachedStartParams = {} as { + [key: string]: { prop: string; value: string }[] + } + + const getWorkerGroups = () => { + queryAllWorkerGroups().then((res: any) => { + variables.startState.workerGroups = res.map((item: string) => ({ + label: item, + value: item + })) + }) + } + + const getTenantList = () => { + queryTenantList().then((res: any) => { + variables.startState.tenantList = res.map((item: any) => ({ + label: item.tenantCode, + value: item.tenantCode + })) + }) + } + + const getEnvironmentList = () => { + queryAllEnvironmentList().then((res: Array) => { + variables.startState.environmentList = res.map((item) => ({ + label: item.name, + value: item.code, + workerGroups: item.workerGroups + })) + }) + } + + const getAlertGroups = () => { + listNormalAlertGroupById().then((res: any) => { + variables.startState.alertGroups = res.map((item: any) => ({ + label: item.groupName, + value: item.id + })) + }) + } + + const getStartParamsList = (code: number) => { + if (cachedStartParams[code]) { + variables.startState.startParamsList = _.cloneDeep( + cachedStartParams[code] + ) + return + } + queryProcessDefinitionByCode(code, variables.startState.projectCode).then( + (res: any) => { + variables.startState.startParamsList = + res.processDefinition.globalParamList + cachedStartParams[code] = _.cloneDeep( + variables.startState.startParamsList + ) + } + ) + } + + const handleStartDefinition = async (code: number) => { + await variables.startFormRef.validate() + + if (variables.saving) return + variables.saving = true + try { + const startParams = {} as any + for (const item of variables.startState.startParamsList) { + if (item.value !== '') { + startParams[item.prop] = item.value + } + } + variables.startForm.startParams = !_.isEmpty(startParams) + ? JSON.stringify(startParams) + : '' + + await startTaskDefinition(variables.startState.projectCode, code, { + ...variables.startForm + } as any) + window.$message.success(t('project.task.success')) + variables.saving = false + ctx.emit('updateList') + ctx.emit('update:show') + } catch (err) { + variables.saving = false + } + } + + return { + variables, + getWorkerGroups, + getTenantList, + getEnvironmentList, + getAlertGroups, + getStartParamsList, + handleStartDefinition + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/definition/components/use-version.ts b/dolphinscheduler-ui/src/views/projects/trigger/definition/components/use-version.ts new file mode 100644 index 0000000000..924dca6864 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/definition/components/use-version.ts @@ -0,0 +1,213 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { h, reactive, ref } from 'vue' +import { NButton, NPopconfirm, NSpace, NTag, NTooltip } from 'naive-ui' +import { DeleteOutlined, CheckOutlined } from '@vicons/antd' +import { useAsyncState } from '@vueuse/core' +import { + queryTaskVersions, + switchVersion, + deleteVersion +} from '@/service/modules/task-definition' +import { useRoute } from 'vue-router' +import type { + TaskDefinitionVersionRes, + TaskDefinitionVersionItem +} from '@/service/modules/task-definition/types' + +export function useVersion() { + const { t } = useI18n() + const route = useRoute() + const projectCode = Number(route.params.projectCode) + + const createColumns = (variables: any) => { + variables.columns = [ + { + title: '#', + key: 'index', + render: (row: any, index: number) => index + 1 + }, + { + title: t('project.task.version'), + key: 'version', + render: (row: TaskDefinitionVersionItem) => + h( + 'span', + null, + row.version !== variables.taskVersion + ? 'v' + row.version + : h( + NTag, + { type: 'success', size: 'small' }, + { + default: () => + `v${row.version} ${t('project.task.current_version')}` + } + ) + ) + }, + { + title: t('project.task.description'), + key: 'description', + render: (row: TaskDefinitionVersionItem) => + h('span', null, row.description ? row.description : '-') + }, + { + title: t('project.task.create_time'), + key: 'createTime' + }, + { + title: t('project.task.operation'), + key: 'operation', + render(row: TaskDefinitionVersionItem) { + return h(NSpace, null, { + default: () => [ + h( + NPopconfirm, + { + onPositiveClick: () => { + handleSwitchVersion(row) + } + }, + { + trigger: () => + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'info', + size: 'small', + disabled: row.version === variables.taskVersion + }, + { + icon: () => h(CheckOutlined) + } + ), + default: () => t('project.task.switch_version') + } + ), + default: () => t('project.task.confirm_switch_version') + } + ), + h( + NPopconfirm, + { + onPositiveClick: () => { + handleDelete(row) + } + }, + { + trigger: () => + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'error', + size: 'small', + disabled: row.version === variables.taskVersion + }, + { + icon: () => h(DeleteOutlined) + } + ), + default: () => t('project.task.delete') + } + ), + default: () => t('project.task.delete_confirm') + } + ) + ] + }) + } + } + ] + } + + const variables = reactive({ + columns: [], + tableData: [], + page: ref(1), + pageSize: ref(10), + totalPage: ref(1), + taskVersion: ref(null), + taskCode: ref(null), + refreshTaskDefinition: ref(false), + row: {}, + loadingRef: ref(false) + }) + + const handleSwitchVersion = (row: TaskDefinitionVersionItem) => { + switchVersion( + { version: row.version }, + { code: variables.taskCode }, + { projectCode } + ).then(() => { + variables.refreshTaskDefinition = true + }) + } + + const handleDelete = (row: TaskDefinitionVersionItem) => { + deleteVersion( + { version: row.version }, + { code: variables.taskCode }, + { projectCode } + ).then(() => { + variables.refreshTaskDefinition = true + }) + } + + const getTableData = (params: any) => { + if (variables.loadingRef) return + variables.loadingRef = true + const { state } = useAsyncState( + queryTaskVersions( + { ...params }, + { code: variables.taskCode }, + { projectCode } + ).then((res: TaskDefinitionVersionRes) => { + variables.tableData = res.totalList.map((item, unused) => { + return { + ...item + } + }) as any + variables.totalPage = res.totalPage + variables.loadingRef = false + }), + {} + ) + + return state + } + + return { + variables, + getTableData, + createColumns + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/definition/index.tsx b/dolphinscheduler-ui/src/views/projects/trigger/definition/index.tsx new file mode 100644 index 0000000000..05f5e9a72f --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/definition/index.tsx @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineComponent } from 'vue' +import { useI18n } from 'vue-i18n' +import { NTabPane, NTabs } from 'naive-ui' +import BatchTriggerDefinition from './trigger' + +const TriggerDefinition = defineComponent({ + name: 'trigger-definition', + setup() { + const { t } = useI18n() + return () => ( + + + + + + ) + } +}) + +export default TriggerDefinition diff --git a/dolphinscheduler-ui/src/views/projects/trigger/definition/trigger.tsx b/dolphinscheduler-ui/src/views/projects/trigger/definition/trigger.tsx new file mode 100644 index 0000000000..b059f4ece2 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/definition/trigger.tsx @@ -0,0 +1,226 @@ +/* + * 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, + getCurrentInstance, + onMounted, + toRefs, + watch +} from 'vue' +import { useRoute } from 'vue-router' +import { + NButton, + NDataTable, + NIcon, + NInput, + NPagination, + NSelect, + NSpace +} from 'naive-ui' +import { SearchOutlined } from '@vicons/antd' +import { useI18n } from 'vue-i18n' +import { useTable } from './use-table' +import { useTrigger } from './use-trigger' +import { TASK_TYPES_MAP } from '@/store/project/task-type' +import Card from '@/components/card' +import TaskModal from '@/views/projects/trigger/components/node/detail-modal' +import type { INodeData } from './types' +import DependenciesModal from '@/views/projects/components/dependencies/dependencies-modal' + +const BatchTriggerDefinition = defineComponent({ + name: 'trigger-definition', + setup() { + const route = useRoute() + const projectCode = Number(route.params.projectCode) + const { t } = useI18n() + + const { + trigger, + onToggleShow, + onTriggerSave, + onEditTrigger, + onInitTrigger + } = useTrigger(projectCode) + + const { variables, getTableData, createColumns } = useTable(onEditTrigger) + + const requestData = () => { + getTableData({ + pageSize: variables.pageSize, + pageNo: variables.page, + searchTaskName: variables.searchTaskName, + taskType: variables.taskType + }) + } + + const onUpdatePageSize = () => { + variables.page = 1 + requestData() + } + + const onSearch = () => { + variables.page = 1 + requestData() + } + + const onClearSearchTaskName = () => { + variables.searchTaskName = null + onSearch() + } + + const onClearSearchTaskType = () => { + variables.taskType = null + onSearch() + } + + const onRefresh = () => { + variables.showVersionModalRef = false + requestData() + } + const onCreate = () => { + onToggleShow(true) + } + const onTaskCancel = () => { + onToggleShow(false) + onInitTrigger() + } + const onTaskSubmit = async (params: { data: INodeData }) => { + const result = await onTriggerSave(params.data) + if (result) { + onTaskCancel() + onRefresh() + } + } + + const trim = getCurrentInstance()?.appContext.config.globalProperties.trim + onMounted(() => { + createColumns(variables) + requestData() + }) + + watch(useI18n().locale, () => { + createColumns(variables) + }) + + return { + t, + ...toRefs(variables), + ...toRefs(trigger), + onSearch, + onClearSearchTaskName, + onClearSearchTaskType, + requestData, + onUpdatePageSize, + onRefresh, + onCreate, + onTaskSubmit, + onTaskCancel, + projectCode, + trim + } + }, + render() { + const { + t, + onSearch, + requestData, + onUpdatePageSize, + onCreate, + loadingRef + } = this + + return ( + + + + + {t('project.trigger.create_trigger')} + + + + { + return { value: item, label: item } + })} + placeholder={t('project.task.task_type')} + style={{ width: '180px' }} + clearable + onClear={this.onClearSearchTaskType} + /> + + + + + + + + + + + + + + + + + + + + ) + } +}) + +export default BatchTriggerDefinition diff --git a/dolphinscheduler-ui/src/views/projects/trigger/definition/types.ts b/dolphinscheduler-ui/src/views/projects/trigger/definition/types.ts new file mode 100644 index 0000000000..a21876b0a4 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/definition/types.ts @@ -0,0 +1,39 @@ +/* + * 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 { IOption } from '@/components/form/types' +import { IParam } from '../../workflow/definition/components/types' +import { IEnvironmentNameOption } from '../components/node/types' +export type { ITriggerData, INodeData } from '../components/node/types' +export type { ISingleSaveReq } from '@/service/modules/task-definition/types' + +interface IRecord { + processDefinitionCode: number + triggerCode: number + triggerName: string +} + +interface IStartState { + projectCode: number + workerGroups: Array + tenantList: Array + alertGroups: Array + environmentList: Array + startParamsList: Array +} + +export { IRecord, IStartState } diff --git a/dolphinscheduler-ui/src/views/projects/trigger/definition/use-table.ts b/dolphinscheduler-ui/src/views/projects/trigger/definition/use-table.ts new file mode 100644 index 0000000000..9ebf3347ae --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/definition/use-table.ts @@ -0,0 +1,348 @@ +/* + * 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 { useAsyncState } from '@vueuse/core' +import { reactive, h, ref } from 'vue' +import { + NButton, + NIcon, + NPopconfirm, + NSpace, + NTag, + NTooltip, + NEllipsis +} from 'naive-ui' +import ButtonLink from '@/components/button-link' +import { useI18n } from 'vue-i18n' +import { + DeleteOutlined, + EditOutlined, + ExclamationCircleOutlined +} from '@vicons/antd' +import { + queryTriggerDefinitionListPaging, + deleteTriggerDefinition +} from '@/service/modules/trigger-definition' +import { useRoute } from 'vue-router' +import { + COLUMN_WIDTH_CONFIG, + calculateTableWidth, + DefaultTableWidth +} from '@/common/column-width-config' +import type { + TaskDefinitionItem, + TaskDefinitionRes +} 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 = [ + { + title: '#', + key: 'index', + render: (row: any, index: number) => index + 1, + ...COLUMN_WIDTH_CONFIG['index'] + }, + { + title: t('project.trigger.trigger_name'), + key: 'triggerName', + ...COLUMN_WIDTH_CONFIG['linkName'], + resizable: true, + minWidth: 200, + maxWidth: 600, + render: (row: IRecord) => + h( + ButtonLink, + { + onClick: () => void onEdit(row, true) + }, + { + default: () => + h( + NEllipsis, + { + style: 'max-width: 580px;line-height: 1.5' + }, + () => row.triggerName + ) + } + ) + }, + { + title: t('project.task.workflow_name'), + key: 'processDefinitionName', + ...COLUMN_WIDTH_CONFIG['name'], + resizable: true, + minWidth: 200, + maxWidth: 600 + }, + { + title: t('project.task.workflow_state'), + key: 'processReleaseState', + render: (row: any) => { + if (row.processReleaseState === 'OFFLINE') { + return h(NTag, { type: 'error', size: 'small' }, () => + t('project.task.offline') + ) + } else if (row.processReleaseState === 'ONLINE') { + return h(NTag, { type: 'info', size: 'small' }, () => + t('project.task.online') + ) + } + }, + width: 130 + }, + { + title: t('project.task.task_type'), + key: 'taskType', + ...COLUMN_WIDTH_CONFIG['type'] + }, + { + title: t('project.task.version'), + key: 'taskVersion', + render: (row: TaskDefinitionItem) => + h('span', null, 'v' + row.taskVersion), + ...COLUMN_WIDTH_CONFIG['version'] + }, + { + title: t('project.task.upstream_tasks'), + key: 'upstreamTaskMap', + render: (row: TaskDefinitionItem) => + row.upstreamTaskMap.map((item: string, index: number) => { + return h('p', null, { default: () => `[${index + 1}] ${item}` }) + }), + ...COLUMN_WIDTH_CONFIG['name'] + }, + { + title: t('project.task.create_time'), + key: 'taskCreateTime', + ...COLUMN_WIDTH_CONFIG['time'] + }, + { + title: t('project.task.update_time'), + key: 'taskUpdateTime', + ...COLUMN_WIDTH_CONFIG['time'] + }, + { + title: t('project.task.operation'), + key: 'operation', + ...COLUMN_WIDTH_CONFIG['operation'](3), + render(row: any) { + return h(NSpace, null, { + default: () => [ + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'info', + size: 'small', + disabled: + ['CONDITIONS', 'SWITCH'].includes(row.taskType) || + (!!row.processDefinitionCode && + row.processReleaseState === 'ONLINE'), + onClick: () => { + onEdit(row, false) + } + }, + { + icon: () => + h(NIcon, null, { default: () => h(EditOutlined) }) + } + ), + default: () => t('project.task.edit') + } + ), + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'info', + size: 'small', + onClick: () => { + variables.showVersionModalRef = true + variables.row = row + } + }, + { + icon: () => + h(NIcon, null, { + default: () => h(ExclamationCircleOutlined) + }) + } + ), + default: () => t('project.task.version') + } + ), + h( + NPopconfirm, + { + onPositiveClick: () => { + handleDelete(row) + } + }, + { + trigger: () => + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'error', + size: 'small', + disabled: + !!row.processDefinitionCode && + row.processReleaseState === 'ONLINE' + }, + { + icon: () => + h(NIcon, null, { + default: () => h(DeleteOutlined) + }) + } + ), + default: () => t('project.task.delete') + } + ), + default: () => t('project.task.delete_confirm') + } + ) + ] + }) + } + } + ] + if (variables.tableWidth) { + variables.tableWidth = calculateTableWidth(variables.columns) + } + } + + const variables = reactive({ + columns: [], + tableWidth: DefaultTableWidth, + tableData: [], + page: ref(1), + pageSize: ref(10), + searchTaskName: ref(null), + searchWorkflowName: ref(null), + totalPage: ref(1), + taskType: ref(null), + showVersionModalRef: ref(false), + dependentTasksShowRef: ref(false), + dependentTaskLinksRef: ref([]), + row: {}, + loadingRef: ref(false), + dependenciesData: ref({ + showRef: ref(false), + taskLinks: ref([]), + required: ref(false), + tip: ref(''), + action: () => {} + }) + }) + + const handleDelete = (row: any) => { + 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 { + deleteTriggerDefinition({ 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 + }) + } + ) + } + }) + } + + const getTableData = (params: any) => { + if (variables.loadingRef) return + variables.loadingRef = true + const { state } = useAsyncState( + queryTriggerDefinitionListPaging({ ...params }, { projectCode }).then( + (res: TaskDefinitionRes) => { + variables.tableData = res.totalList.map((item, unused) => { + if (Object.keys(item.upstreamTaskMap).length > 0) { + item.upstreamTaskMap = Object.keys(item.upstreamTaskMap).map( + (code) => item.upstreamTaskMap[code] + ) + } else { + item.upstreamTaskMap = [] + } + + return { + ...item + } + }) as any + variables.totalPage = res.totalPage + variables.loadingRef = false + } + ), + {} + ) + + return state + } + + return { + variables, + getTableData, + createColumns + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/definition/use-trigger.ts b/dolphinscheduler-ui/src/views/projects/trigger/definition/use-trigger.ts new file mode 100644 index 0000000000..34d344c227 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/definition/use-trigger.ts @@ -0,0 +1,142 @@ +/* + * 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 { reactive } from 'vue' +import { + updateTrigger, + genTaskCodeList, + saveSingle, + queryTriggerDefinitionByCode, + updateWithUpstream +} from '@/service/modules/trigger-definition' +import { formatParams as formatData } from '../components/node/format-data' +import type { ITriggerData, INodeData, ISingleSaveReq, IRecord } from './types' +import { Connect } from '../../workflow/components/dag/types' + +export function useTrigger(projectCode: number) { + const initialTrigger = { + taskType: 'SIMPLE' + } as ITriggerData + const trigger = reactive({ + triggerShow: false, + triggerData: { ...initialTrigger }, + triggerSaving: false, + triggerReadonly: false + } as { triggerShow: boolean; triggerData: ITriggerData; triggerSaving: boolean; triggerReadonly: boolean }) + + const formatParams = (data: INodeData, isCreate: boolean): ISingleSaveReq => { + const params = formatData(data) + if (isCreate) { + return { + processDefinitionCode: params.processDefinitionCode, + upstreamCodes: params.upstreamCodes, + taskDefinitionJsonObj: JSON.stringify(params.taskDefinitionJsonObj) + } + } + return { + upstreamCodes: params.upstreamCodes, + taskDefinitionJsonObj: JSON.stringify(params.taskDefinitionJsonObj) + } + } + + const getTaskCode = async () => { + const result = await genTaskCodeList(1, projectCode) + return result[0] + } + + const onToggleShow = (show: boolean) => { + trigger.triggerShow = show + } + const onTriggerSave = async (data: INodeData) => { + if (trigger.triggerSaving) return + trigger.triggerSaving = true + try { + if (data.id) { + data.code && + (await updateWithUpstream( + projectCode, + data.code, + formatParams({ ...data, code: data.code }, false) + )) + } else { + const taskCode = await getTaskCode() + await saveSingle( + projectCode, + formatParams({ ...data, code: taskCode }, true) + ) + } + + trigger.triggerSaving = false + return true + } catch (err) { + trigger.triggerSaving = false + return false + } + } + + const onEditTrigger = async (row: IRecord, readonly: boolean) => { + const result = await queryTriggerDefinitionByCode( + row.triggerCode, + projectCode + ) + trigger.triggerData = { + ...result, + processName: row.processDefinitionCode, + preTasks: + result?.processTaskRelationList?.map( + (item: Connect) => item.preTaskCode + ) || [] + } + trigger.triggerShow = true + trigger.triggerReadonly = readonly + } + + const onInitTrigger = () => { + trigger.triggerData = { ...initialTrigger } + trigger.triggerReadonly = false + } + + const onUpdateTrigger = async (data: INodeData) => { + if (trigger.triggerSaving || !data.code) return + trigger.triggerSaving = true + + const params = { + taskExecuteType: 'STREAM', + taskDefinitionJsonObj: JSON.stringify( + formatData(data).taskDefinitionJsonObj + ) + } + + try { + await updateTrigger(projectCode, data.code, params) + trigger.triggerSaving = false + return true + } catch (err) { + trigger.triggerSaving = false + return false + } + } + + return { + trigger: trigger, + onToggleShow, + onTriggerSave, + onEditTrigger, + onInitTrigger, + onUpdateTrigger + } +} diff --git a/dolphinscheduler-ui/src/views/projects/trigger/instance/index.tsx b/dolphinscheduler-ui/src/views/projects/trigger/instance/index.tsx new file mode 100644 index 0000000000..12774262b2 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/instance/index.tsx @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineComponent } from 'vue' +import { useI18n } from 'vue-i18n' +import { NTabPane, NTabs } from 'naive-ui' +import BatchTriggerInstance from './trigger' + +const TriggerDefinition = defineComponent({ + name: 'trigger-instance', + setup() { + const { t } = useI18n() + return () => ( + + + + + + ) + } +}) + +export default TriggerDefinition diff --git a/dolphinscheduler-ui/src/views/projects/trigger/instance/trigger.tsx b/dolphinscheduler-ui/src/views/projects/trigger/instance/trigger.tsx new file mode 100644 index 0000000000..57d137fcd1 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/instance/trigger.tsx @@ -0,0 +1,318 @@ +/* + * 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, + getCurrentInstance, + onMounted, + toRefs, + watch +} from 'vue' +import { + NSpace, + NInput, + NSelect, + NDatePicker, + NButton, + NIcon, + NDataTable, + NPagination +} from 'naive-ui' +import { SearchOutlined } from '@vicons/antd' +import { useTable } from './use-table' +import { useI18n } from 'vue-i18n' +import { useAsyncState } from '@vueuse/core' +import { queryLog } from '@/service/modules/log' +import { stateType } from '@/common/common' +import { useUISettingStore } from '@/store/ui-setting/ui-setting' +import Card from '@/components/card' +import LogModal from '@/components/log-modal' + +const BatchTriggerInstance = defineComponent({ + name: 'trigger-instance', + setup() { + const uiSettingStore = useUISettingStore() + const logTimer = uiSettingStore.getLogTimer + const { t, variables, getTableData, createColumns } = useTable() + + const requestTableData = () => { + getTableData({ + pageSize: variables.pageSize, + pageNo: variables.page, + searchVal: variables.searchVal, + taskCode: variables.taskCode, + processInstanceId: variables.processInstanceId, + host: variables.host, + stateType: variables.stateType, + datePickerRange: variables.datePickerRange, + executorName: variables.executorName, + processInstanceName: variables.processInstanceName + }) + } + + const onUpdatePageSize = () => { + variables.page = 1 + requestTableData() + } + + const onSearch = () => { + variables.page = 1 + requestTableData() + } + + const onClearSearchTaskCode = () => { + variables.taskCode = null + onSearch() + } + + const onClearSearchTaskName = () => { + variables.searchVal = '' + onSearch() + } + + const onClearSearchProcessInstanceName = () => { + variables.processInstanceName = null + onSearch() + } + + const onClearSearchExecutorName = () => { + variables.executorName = null + onSearch() + } + + const onClearSearchHost = () => { + variables.host = null + onSearch() + } + + const onClearSearchStateType = () => { + variables.stateType = null + onSearch() + } + + const onClearSearchTime = () => { + variables.datePickerRange = null + onSearch() + } + + const onConfirmModal = () => { + variables.showModalRef = false + } + + let getLogsID: number + + const getLogs = (row: any, logTimer: number) => { + const { state } = useAsyncState( + queryLog({ + taskInstanceId: Number(row.id), + limit: variables.limit, + skipLineNum: variables.skipLineNum + }).then((res: any) => { + variables.logRef += res.message || '' + if (res && res.message !== '') { + variables.limit += 1000 + variables.skipLineNum += res.lineNum + getLogs(row, logTimer) + } else { + variables.logLoadingRef = false + if (logTimer !== 0) { + if (typeof getLogsID === 'number') { + clearTimeout(getLogsID) + } + getLogsID = setTimeout(() => { + variables.logRef = '' + variables.limit = 1000 + variables.skipLineNum = 0 + variables.logLoadingRef = true + getLogs(row, logTimer) + }, logTimer * 1000) + } + } + }), + {} + ) + + return state + } + + const refreshLogs = (row: any) => { + variables.logRef = '' + variables.limit = 1000 + variables.skipLineNum = 0 + getLogs(row, logTimer) + } + + const trim = getCurrentInstance()?.appContext.config.globalProperties.trim + + onMounted(() => { + createColumns(variables) + requestTableData() + }) + + watch(useI18n().locale, () => { + createColumns(variables) + }) + + watch( + () => variables.showModalRef, + () => { + if (variables.showModalRef) { + getLogs(variables.row, logTimer) + } else { + variables.row = {} + variables.logRef = '' + variables.logLoadingRef = true + variables.skipLineNum = 0 + variables.limit = 1000 + } + } + ) + + return { + t, + ...toRefs(variables), + requestTableData, + onUpdatePageSize, + onSearch, + onClearSearchTaskCode, + onClearSearchTaskName, + onClearSearchProcessInstanceName, + onClearSearchExecutorName, + onClearSearchHost, + onClearSearchStateType, + onClearSearchTime, + onConfirmModal, + refreshLogs, + trim + } + }, + render() { + const { + t, + requestTableData, + onUpdatePageSize, + onSearch, + onConfirmModal, + loadingRef, + refreshLogs + } = this + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + } +}) + +export default BatchTriggerInstance diff --git a/dolphinscheduler-ui/src/views/projects/trigger/instance/types.ts b/dolphinscheduler-ui/src/views/projects/trigger/instance/types.ts new file mode 100644 index 0000000000..af4dfa8061 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/instance/types.ts @@ -0,0 +1,39 @@ +/* + * 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 { ITaskState } from '@/common/types' + +export type { Router } from 'vue-router' +export type { TaskInstancesRes } from '@/service/modules/task-instances/types' + +interface IRecord { + name: string + processInstanceName: string + executorName: string + taskType: string + state: ITaskState + submitTime: string + startTime: string + endTime: string + duration?: string + retryTimes: number + dryRun: number + host: string + appLink: string + testFlag?: number +} + +export { ITaskState, IRecord } diff --git a/dolphinscheduler-ui/src/views/projects/trigger/instance/use-table.ts b/dolphinscheduler-ui/src/views/projects/trigger/instance/use-table.ts new file mode 100644 index 0000000000..dd8c944af0 --- /dev/null +++ b/dolphinscheduler-ui/src/views/projects/trigger/instance/use-table.ts @@ -0,0 +1,377 @@ +/* + * 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 { useI18n } from 'vue-i18n' +import { h, reactive, ref } from 'vue' +import { useAsyncState } from '@vueuse/core' +import { + queryTaskListPaging, + forceSuccess, + downloadLog +} from '@/service/modules/task-instances' +import { NButton, NIcon, NSpace, NTooltip, NSpin, NEllipsis } from 'naive-ui' +import ButtonLink from '@/components/button-link' +import { + AlignLeftOutlined, + CheckCircleOutlined, + DownloadOutlined +} from '@vicons/antd' +import { format } from 'date-fns' +import { useRoute, useRouter } from 'vue-router' +import { parseTime, renderTableTime, tasksState } from '@/common/common' +import { + COLUMN_WIDTH_CONFIG, + calculateTableWidth, + DefaultTableWidth +} from '@/common/column-width-config' +import type { Router, TaskInstancesRes, IRecord, ITaskState } from './types' + +export function useTable() { + const { t } = useI18n() + const route = useRoute() + const router: Router = useRouter() + + const projectCode = Number(route.params.projectCode) + const processInstanceId = Number(route.query.processInstanceId) + const taskName = route.query.taskName + const taskCode = route.query.taskCode + + const variables = reactive({ + columns: [], + tableWidth: DefaultTableWidth, + tableData: [] as IRecord[], + page: ref(1), + pageSize: ref(10), + searchVal: ref(taskName || null), + taskCode: ref(taskCode || null), + processInstanceId: ref(processInstanceId ? processInstanceId : null), + host: ref(null), + stateType: ref(null), + datePickerRange: ref(null), + executorName: ref(null), + processInstanceName: ref(null), + totalPage: ref(1), + showModalRef: ref(false), + row: {}, + loadingRef: ref(false), + logRef: '', + logLoadingRef: ref(true), + skipLineNum: ref(0), + limit: ref(1000) + }) + + const createColumns = (variables: any) => { + variables.columns = [ + { + title: '#', + key: 'index', + render: (row: any, index: number) => index + 1, + ...COLUMN_WIDTH_CONFIG['index'] + }, + { + title: t('project.task.task_name'), + key: 'name', + ...COLUMN_WIDTH_CONFIG['name'], + resizable: true, + minWidth: 200, + maxWidth: 600 + }, + { + title: t('project.task.workflow_instance'), + key: 'processInstanceName', + ...COLUMN_WIDTH_CONFIG['linkName'], + resizable: true, + minWidth: 300, + maxWidth: 600, + render: (row: { + processInstanceId: number + processInstanceName: string + }) => + h( + ButtonLink, + { + onClick: () => { + const routeUrl = router.resolve({ + name: 'workflow-instance-detail', + params: { id: row.processInstanceId }, + query: { code: projectCode } + }) + window.open(routeUrl.href, '_blank') + } + }, + { + default: () => + h( + NEllipsis, + { + style: 'max-width: 580px;line-height: 1.5' + }, + () => row.processInstanceName + ) + } + ) + }, + { + title: t('project.task.executor'), + key: 'executorName', + ...COLUMN_WIDTH_CONFIG['name'] + }, + { + title: t('project.task.node_type'), + key: 'taskType', + ...COLUMN_WIDTH_CONFIG['type'] + }, + { + title: t('project.task.state'), + key: 'state', + ...COLUMN_WIDTH_CONFIG['state'], + render: (row: IRecord) => renderStateCell(row.state, t) + }, + { + title: t('project.task.submit_time'), + ...COLUMN_WIDTH_CONFIG['time'], + key: 'submitTime', + render: (row: IRecord) => renderTableTime(row.submitTime) + }, + { + title: t('project.task.start_time'), + ...COLUMN_WIDTH_CONFIG['time'], + key: 'startTime', + render: (row: IRecord) => renderTableTime(row.startTime) + }, + { + title: t('project.task.end_time'), + ...COLUMN_WIDTH_CONFIG['time'], + key: 'endTime', + render: (row: IRecord) => renderTableTime(row.endTime) + }, + { + title: t('project.task.duration'), + key: 'duration', + ...COLUMN_WIDTH_CONFIG['duration'], + render: (row: any) => h('span', null, row.duration ? row.duration : '-') + }, + { + title: t('project.task.retry_count'), + key: 'retryTimes', + ...COLUMN_WIDTH_CONFIG['times'] + }, + { + title: t('project.task.dry_run_flag'), + key: 'dryRun', + ...COLUMN_WIDTH_CONFIG['dryRun'], + render: (row: IRecord) => (row.dryRun === 1 ? 'YES' : 'NO') + }, + { + title: t('project.task.host'), + key: 'host', + ...COLUMN_WIDTH_CONFIG['name'], + render: (row: IRecord) => row.host || '-' + }, + { + title: t('project.task.app_link'), + key: 'appLink', + ...COLUMN_WIDTH_CONFIG['name'], + render: (row: IRecord) => row.appLink || '-' + }, + { + title: t('project.task.operation'), + key: 'operation', + ...COLUMN_WIDTH_CONFIG['operation'](3), + render(row: any) { + return h(NSpace, null, { + default: () => [ + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + tag: 'div', + circle: true, + type: 'info', + size: 'small', + disabled: !( + row.state === 'FAILURE' || + row.state === 'NEED_FAULT_TOLERANCE' || + row.state === 'KILL' + ), + onClick: () => { + handleForcedSuccess(row) + } + }, + { + icon: () => + h(NIcon, null, { + default: () => h(CheckCircleOutlined) + }) + } + ), + default: () => t('project.task.forced_success') + } + ), + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'info', + size: 'small', + disabled: !row.host, + onClick: () => handleLog(row) + }, + { + icon: () => + h(NIcon, null, { + default: () => h(AlignLeftOutlined) + }) + } + ), + default: () => t('project.task.view_log') + } + ), + h( + NTooltip, + {}, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'info', + size: 'small', + disabled: !row.host, + onClick: () => downloadLog(row.id) + }, + { + icon: () => + h(NIcon, null, { default: () => h(DownloadOutlined) }) + } + ), + default: () => t('project.task.download_log') + } + ) + ] + }) + } + } + ] + if (variables.tableWidth) { + variables.tableWidth = calculateTableWidth(variables.columns) + } + } + + const handleLog = (row: any) => { + variables.showModalRef = true + variables.row = row + } + + const handleForcedSuccess = (row: any) => { + forceSuccess({ id: row.id }, { projectCode }).then(() => { + getTableData({ + pageSize: variables.pageSize, + pageNo: + variables.tableData.length === 1 && variables.page > 1 + ? variables.page - 1 + : variables.page, + searchVal: variables.searchVal, + taskCode: variables.taskCode, + processInstanceId: variables.processInstanceId, + host: variables.host, + stateType: variables.stateType, + datePickerRange: variables.datePickerRange, + executorName: variables.executorName, + processInstanceName: variables.processInstanceName + }) + }) + } + + const getTableData = (params: any) => { + if (variables.loadingRef) return + variables.loadingRef = true + const data = { + pageSize: params.pageSize, + pageNo: params.pageNo, + searchVal: params.searchVal, + taskCode: params.taskCode, + processInstanceId: params.processInstanceId, + host: params.host, + stateType: params.stateType, + startDate: params.datePickerRange + ? format(parseTime(params.datePickerRange[0]), 'yyyy-MM-dd HH:mm:ss') + : '', + endDate: params.datePickerRange + ? format(parseTime(params.datePickerRange[1]), 'yyyy-MM-dd HH:mm:ss') + : '', + executorName: params.executorName, + processInstanceName: params.processInstanceName + } + + const { state } = useAsyncState( + queryTaskListPaging(data, { projectCode }).then( + (res: TaskInstancesRes) => { + variables.tableData = res.totalList as IRecord[] + variables.totalPage = res.totalPage + variables.loadingRef = false + } + ), + {} + ) + + return state + } + + return { + t, + variables, + getTableData, + createColumns + } +} + +export function renderStateCell(state: ITaskState, t: Function) { + if (!state) return '' + + const stateOption = tasksState(t)[state] + + const Icon = h( + NIcon, + { + color: stateOption.color, + class: stateOption.classNames, + style: { + display: 'flex' + }, + size: 20 + }, + () => h(stateOption.icon) + ) + return h(NTooltip, null, { + trigger: () => { + if (!stateOption.isSpin) return Icon + return h(NSpin, { size: 20 }, { icon: () => Icon }) + }, + default: () => stateOption.desc + }) +} 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 61499a898c..4092d3df05 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 @@ -160,6 +160,27 @@ export default defineComponent({ ) }} + + {{ + default: () => t('project.workflow.trigger'), + trigger: () => ( + + + + + + ) + }} + {{ default: () => diff --git a/dolphinscheduler-worker/pom.xml b/dolphinscheduler-worker/pom.xml index a6f39ca15e..87d7ca2432 100644 --- a/dolphinscheduler-worker/pom.xml +++ b/dolphinscheduler-worker/pom.xml @@ -61,6 +61,11 @@ dolphinscheduler-task-all + + org.apache.dolphinscheduler + dolphinscheduler-trigger-all + + org.apache.dolphinscheduler dolphinscheduler-storage-all diff --git a/dolphinscheduler-worker/src/main/java/org/apache/dolphinscheduler/server/worker/WorkerServer.java b/dolphinscheduler-worker/src/main/java/org/apache/dolphinscheduler/server/worker/WorkerServer.java index 797d8f78a3..c8e8d9ab04 100644 --- a/dolphinscheduler-worker/src/main/java/org/apache/dolphinscheduler/server/worker/WorkerServer.java +++ b/dolphinscheduler-worker/src/main/java/org/apache/dolphinscheduler/server/worker/WorkerServer.java @@ -31,6 +31,7 @@ import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; import org.apache.dolphinscheduler.plugin.task.api.TaskPluginManager; import org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils; import org.apache.dolphinscheduler.plugin.task.api.utils.ProcessUtils; +import org.apache.dolphinscheduler.plugin.trigger.api.TriggerPluginManager; import org.apache.dolphinscheduler.registry.api.RegistryConfiguration; import org.apache.dolphinscheduler.server.worker.message.MessageRetryRunner; import org.apache.dolphinscheduler.server.worker.metrics.WorkerServerMetrics; @@ -87,6 +88,7 @@ public class WorkerServer implements IStoppable { public void run() { this.workerRpcServer.start(); TaskPluginManager.loadPlugin(); + TriggerPluginManager.loadPlugin(); DataSourceProcessorProvider.initialize(); this.workerRegistryClient.setRegistryStoppable(this); diff --git a/pom.xml b/pom.xml index aeadd3adc0..a452ecfc6e 100755 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,7 @@ dolphinscheduler-extract dolphinscheduler-dao-plugin dolphinscheduler-authentication + dolphinscheduler-trigger-plugin @@ -234,6 +235,17 @@ ${project.version} + + org.apache.dolphinscheduler + dolphinscheduler-trigger-api + ${project.version} + + + org.apache.dolphinscheduler + dolphinscheduler-trigger-all + ${project.version} + + org.apache.dolphinscheduler dolphinscheduler-storage-api