Browse Source

[Feature-14505][UI] Support to set project-level preferences (#14573)

* add a few codes about the project preferences
3.2.1-prepare
calvin 12 months ago committed by GitHub
parent
commit
20cf4ad4e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 82
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectPreferenceController.java
  2. 5
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
  3. 28
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProjectPreferenceService.java
  4. 126
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectPreferenceServiceImpl.java
  5. 7
      dolphinscheduler-api/src/main/resources/i18n/messages.properties
  6. 82
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/ProjectPreferenceControllerTest.java
  7. 118
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProjectPreferenceServiceTest.java
  8. 56
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/ProjectPreference.java
  9. 26
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ProjectPreferenceMapper.java
  10. 22
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
  11. 21
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
  12. 25
      dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
  13. 68
      dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/ProjectPreferenceMapperTest.java
  14. 1
      dolphinscheduler-ui/src/components/form/use-form.ts
  15. 5
      dolphinscheduler-ui/src/layouts/content/use-dataList.ts
  16. 1
      dolphinscheduler-ui/src/locales/en_US/menu.ts
  17. 7
      dolphinscheduler-ui/src/locales/en_US/project.ts
  18. 1
      dolphinscheduler-ui/src/locales/zh_CN/menu.ts
  19. 7
      dolphinscheduler-ui/src/locales/zh_CN/project.ts
  20. 11
      dolphinscheduler-ui/src/router/modules/projects.ts
  21. 42
      dolphinscheduler-ui/src/service/modules/projects-preference/index.ts
  22. 40
      dolphinscheduler-ui/src/service/modules/projects-preference/types.ts
  23. 48
      dolphinscheduler-ui/src/views/projects/preference/components/use-alert-group.ts
  24. 48
      dolphinscheduler-ui/src/views/projects/preference/components/use-tenant.ts
  25. 46
      dolphinscheduler-ui/src/views/projects/preference/components/use-warning-type.ts
  26. 66
      dolphinscheduler-ui/src/views/projects/preference/detail.tsx
  27. 47
      dolphinscheduler-ui/src/views/projects/preference/index.tsx
  28. 136
      dolphinscheduler-ui/src/views/projects/preference/use-form.ts
  29. 32
      dolphinscheduler-ui/src/views/projects/task/components/node/detail-modal.tsx
  30. 1
      dolphinscheduler-ui/src/views/projects/task/components/node/format-data.ts
  31. 116
      dolphinscheduler-ui/src/views/projects/workflow/definition/components/timing-modal.tsx

82
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectPreferenceController.java

@ -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.
*/
package org.apache.dolphinscheduler.api.controller;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_PROJECT_PREFERENCE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.UPDATE_PROJECT_PREFERENCE_ERROR;
import org.apache.dolphinscheduler.api.aspect.AccessLogAnnotation;
import org.apache.dolphinscheduler.api.exceptions.ApiException;
import org.apache.dolphinscheduler.api.service.ProjectPreferenceService;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.dao.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
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;
@Tag(name = "PROJECT_PREFERENCE_TAG")
@RestController
@RequestMapping("projects/{projectCode}/project-preference")
@Slf4j
public class ProjectPreferenceController extends BaseController {
@Autowired
private ProjectPreferenceService projectPreferenceService;
@Operation(summary = "updateProjectPreference", description = "UPDATE_PROJECT_PREFERENCE_NOTES")
@Parameters({
@Parameter(name = "projectPreferences", description = "PROJECT_PREFERENCES", schema = @Schema(implementation = String.class)),
})
@PutMapping
@ResponseStatus(HttpStatus.CREATED)
@ApiException(UPDATE_PROJECT_PREFERENCE_ERROR)
@AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result updateProjectPreference(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@Parameter(name = "projectCode", description = "PROJECT_CODE", required = true) @PathVariable long projectCode,
@RequestParam(value = "projectPreferences", required = true) String projectPreferences) {
return projectPreferenceService.updateProjectPreference(loginUser, projectCode, projectPreferences);
}
@Operation(summary = "queryProjectPreferenceByProjectCode", description = "QUERY_PROJECT_PREFERENCE_NOTES")
@GetMapping()
@ResponseStatus(HttpStatus.OK)
@ApiException(QUERY_PROJECT_PREFERENCE_ERROR)
@AccessLogAnnotation(ignoreRequestArgs = "loginUser")
public Result queryProjectPreferenceByProjectCode(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@Parameter(name = "projectCode", description = "PROJECT_CODE", required = true) @PathVariable long projectCode) {
return projectPreferenceService.queryProjectPreferenceByProjectCode(loginUser, projectCode);
}
}

5
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java

@ -287,6 +287,11 @@ public enum Status {
PROJECT_PARAMETER_CODE_EMPTY(10220, "project parameter code empty", "项目参数code为空"),
CREATE_PROJECT_PREFERENCE_ERROR(10300, "create project preference error", "创建项目偏好设置错误"),
UPDATE_PROJECT_PREFERENCE_ERROR(10301, "update project preference error", "更新项目偏好设置错误"),
QUERY_PROJECT_PREFERENCE_ERROR(10302, "query project preference error", "查询项目偏好设置错误"),
UDF_FUNCTION_NOT_EXIST(20001, "UDF function not found", "UDF函数不存在"),
UDF_FUNCTION_EXISTS(20002, "UDF function already exists", "UDF函数已存在"),
RESOURCE_NOT_EXIST(20004, "resource not exist", "资源不存在"),

28
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProjectPreferenceService.java

@ -0,0 +1,28 @@
/*
* 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;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.dao.entity.User;
public interface ProjectPreferenceService {
Result updateProjectPreference(User loginUser, long projectCode, String preferences);
Result queryProjectPreferenceByProjectCode(User loginUser, long projectCode);
}

126
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectPreferenceServiceImpl.java

@ -0,0 +1,126 @@
/*
* 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 static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.PROJECT;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.ProjectPreferenceService;
import org.apache.dolphinscheduler.api.service.ProjectService;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.utils.CodeGenerateUtils;
import org.apache.dolphinscheduler.dao.entity.Project;
import org.apache.dolphinscheduler.dao.entity.ProjectPreference;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectPreferenceMapper;
import java.util.Date;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@Service
@Slf4j
public class ProjectPreferenceServiceImpl extends BaseServiceImpl
implements
ProjectPreferenceService {
@Autowired
private ProjectPreferenceMapper projectPreferenceMapper;
@Autowired
private ProjectService projectService;
@Autowired
private ProjectMapper projectMapper;
@Override
public Result updateProjectPreference(User loginUser, long projectCode, String preferences) {
Result result = new Result();
// check if the user has the writing permission for project
Project project = projectMapper.queryByCode(projectCode);
boolean hasProjectAndWritePerm = projectService.hasProjectAndWritePerm(loginUser, project, result);
if (!hasProjectAndWritePerm) {
return result;
}
ProjectPreference projectPreference = projectPreferenceMapper
.selectOne(new QueryWrapper<ProjectPreference>().lambda().eq(ProjectPreference::getProjectCode,
projectCode));
Date now = new Date();
if (Objects.isNull(projectPreference)) {
projectPreference = new ProjectPreference();
projectPreference.setProjectCode(projectCode);
projectPreference.setPreferences(preferences);
projectPreference.setUserId(loginUser.getId());
projectPreference.setCode(CodeGenerateUtils.getInstance().genCode());
projectPreference.setCreateTime(now);
projectPreference.setUpdateTime(now);
if (projectPreferenceMapper.insert(projectPreference) > 0) {
log.info("Project preference is created and id is :{}", projectPreference.getId());
result.setData(projectPreference);
putMsg(result, Status.SUCCESS);
} else {
log.error("Project preference create error, projectCode:{}.", projectPreference.getProjectCode());
putMsg(result, Status.CREATE_PROJECT_PREFERENCE_ERROR);
}
} else {
projectPreference.setPreferences(preferences);
projectPreference.setUserId(loginUser.getId());
projectPreference.setUpdateTime(now);
if (projectPreferenceMapper.updateById(projectPreference) > 0) {
log.info("Project preference is updated and id is :{}", projectPreference.getId());
result.setData(projectPreference);
putMsg(result, Status.SUCCESS);
} else {
log.error("Project preference update error, projectCode:{}.", projectPreference.getProjectCode());
putMsg(result, Status.UPDATE_PROJECT_PREFERENCE_ERROR);
}
}
return result;
}
@Override
public Result queryProjectPreferenceByProjectCode(User loginUser, long projectCode) {
Result result = new Result();
Project project = projectMapper.queryByCode(projectCode);
boolean hasProjectAndPerm = projectService.hasProjectAndPerm(loginUser, project, result, PROJECT);
if (!hasProjectAndPerm) {
return result;
}
ProjectPreference projectPreference = projectPreferenceMapper
.selectOne(new QueryWrapper<ProjectPreference>().lambda().eq(ProjectPreference::getProjectCode,
projectCode));
result.setData(projectPreference);
putMsg(result, Status.SUCCESS);
return result;
}
}

7
dolphinscheduler-api/src/main/resources/i18n/messages.properties

@ -447,4 +447,9 @@ UPDATE_PROJECT_PARAMETER_NOTES=update project parameter
PROJECT_PARAMETER_CODE=project parameter code
DELETE_PROJECT_PARAMETER_NOTES=delete project parameter
QUERY_PROJECT_PARAMETER_LIST_PAGING_NOTES=query project parameter list paging
QUERY_PROJECT_PARAMETER_NOTES=query project parameter
QUERY_PROJECT_PARAMETER_NOTES=query project parameter
PROJECT_PREFERENCE_TAG=project preference related operation
UPDATE_PROJECT_PREFERENCE_NOTES=update project preference
PROJECT_PREFERENCES=project preferences
QUERY_PROJECT_PREFERENCE_NOTES=query project preference

82
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/ProjectPreferenceControllerTest.java

@ -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.
*/
package org.apache.dolphinscheduler.api.controller;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.impl.ProjectPreferenceServiceImpl;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.enums.UserType;
import org.apache.dolphinscheduler.dao.entity.User;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class ProjectPreferenceControllerTest {
@InjectMocks
private ProjectPreferenceController projectPreferenceController;
@Mock
private ProjectPreferenceServiceImpl projectPreferenceService;
@Test
public void testUpdateProjectPreference() {
User loginUser = getGeneralUser();
Mockito.when(projectPreferenceService.updateProjectPreference(Mockito.any(), Mockito.anyLong(),
Mockito.anyString())).thenReturn(getSuccessResult());
Result result = projectPreferenceController.updateProjectPreference(loginUser, 1, "value");
Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode());
}
@Test
public void testQueryProjectPreferenceByProjectCode() {
User loginUser = getGeneralUser();
Mockito.when(projectPreferenceService.queryProjectPreferenceByProjectCode(Mockito.any(), Mockito.anyLong()))
.thenReturn(getSuccessResult());
Result result = projectPreferenceController.queryProjectPreferenceByProjectCode(loginUser, 1);
Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode());
}
private User getGeneralUser() {
User loginUser = new User();
loginUser.setUserType(UserType.GENERAL_USER);
loginUser.setUserName("userName");
loginUser.setId(1);
return loginUser;
}
private Result getSuccessResult() {
Result result = new Result();
result.setCode(Status.SUCCESS.getCode());
result.setMsg(Status.SUCCESS.getMsg());
return result;
}
}

118
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProjectPreferenceServiceTest.java

@ -0,0 +1,118 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dolphinscheduler.api.service;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.impl.ProjectPreferenceServiceImpl;
import org.apache.dolphinscheduler.api.service.impl.ProjectServiceImpl;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.enums.UserType;
import org.apache.dolphinscheduler.dao.entity.Project;
import org.apache.dolphinscheduler.dao.entity.ProjectPreference;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectPreferenceMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class ProjectPreferenceServiceTest {
@InjectMocks
private ProjectPreferenceServiceImpl projectPreferenceService;
@Mock
private ProjectMapper projectMapper;
@Mock
private ProjectPreferenceMapper projectPreferenceMapper;
@Mock
private ProjectServiceImpl projectService;
protected final static long projectCode = 1L;
@Test
public void testUpdateProjectPreference() {
User loginUser = getGeneralUser();
Mockito.when(projectMapper.queryByCode(projectCode)).thenReturn(getProject(projectCode));
Mockito.when(projectService.hasProjectAndWritePerm(Mockito.any(), Mockito.any(), Mockito.any(Result.class)))
.thenReturn(true);
Mockito.when(projectPreferenceMapper.selectOne(Mockito.any())).thenReturn(null);
Mockito.when(projectPreferenceMapper.insert(Mockito.any())).thenReturn(1);
Result result = projectPreferenceService.updateProjectPreference(loginUser, projectCode, "value");
Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode());
}
@Test
public void testQueryProjectPreferenceByProjectCode() {
User loginUser = getGeneralUser();
// PROJECT_PARAMETER_NOT_EXISTS
Mockito.when(projectMapper.queryByCode(projectCode)).thenReturn(getProject(projectCode));
Mockito.when(projectService.hasProjectAndPerm(Mockito.any(), Mockito.any(), Mockito.any(Result.class),
Mockito.any())).thenReturn(true);
Mockito.when(projectPreferenceMapper.selectOne(Mockito.any())).thenReturn(null);
Result result = projectPreferenceService.queryProjectPreferenceByProjectCode(loginUser, projectCode);
Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode());
// SUCCESS
Mockito.when(projectPreferenceMapper.selectOne(Mockito.any())).thenReturn(getProjectPreference());
result = projectPreferenceService.queryProjectPreferenceByProjectCode(loginUser, projectCode);
Assertions.assertEquals(Status.SUCCESS.getCode(), result.getCode());
}
private User getGeneralUser() {
User loginUser = new User();
loginUser.setUserType(UserType.GENERAL_USER);
loginUser.setUserName("userName");
loginUser.setId(1);
return loginUser;
}
private Project getProject(long projectCode) {
Project project = new Project();
project.setCode(projectCode);
project.setId(1);
project.setName("test");
project.setUserId(1);
return project;
}
private ProjectPreference getProjectPreference() {
ProjectPreference projectPreference = new ProjectPreference();
projectPreference.setId(1);
projectPreference.setCode(1);
projectPreference.setProjectCode(projectCode);
projectPreference.setPreferences("value");
return projectPreference;
}
}

56
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/ProjectPreference.java

@ -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.
*/
package org.apache.dolphinscheduler.dao.entity;
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("t_ds_project_preference")
public class ProjectPreference {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private long code;
@TableField("project_code")
private long projectCode;
@TableField("preferences")
private String preferences;
@TableField("user_id")
private Integer userId;
private Date createTime;
private Date updateTime;
}

26
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ProjectPreferenceMapper.java

@ -0,0 +1,26 @@
/*
* 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.dao.entity.ProjectPreference;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface ProjectPreferenceMapper extends BaseMapper<ProjectPreference> {
}

22
dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql

@ -681,6 +681,28 @@ CREATE TABLE t_ds_project_parameter
-- Records of t_ds_project_parameter
-- ----------------------------
-- ----------------------------
-- Table structure for t_ds_project_preference
-- ----------------------------
DROP TABLE IF EXISTS t_ds_project_preference CASCADE;
CREATE TABLE t_ds_project_preference
(
id int(11) NOT NULL AUTO_INCREMENT,
code bigint(20) NOT NULL,
project_code bigint(20) NOT NULL,
preferences varchar(512) NOT NULL,
user_id int(11) DEFAULT NULL,
create_time datetime NOT NULL,
update_time datetime DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY unique_project_preference_project_code (project_code),
UNIQUE KEY unique_project_preference_code (code)
);
-- ----------------------------
-- Records of t_ds_project_preference
-- ----------------------------
-- ----------------------------
-- Table structure for t_ds_queue
-- ----------------------------

21
dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql

@ -684,6 +684,27 @@ CREATE TABLE `t_ds_project_parameter` (
-- Records of t_ds_project_parameter
-- ----------------------------
-- ----------------------------
-- Table structure for t_ds_project_preference
-- ----------------------------
DROP TABLE IF EXISTS `t_ds_project_preference`;
CREATE TABLE `t_ds_project_preference` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'key',
`code` bigint(20) NOT NULL COMMENT 'encoding',
`project_code` bigint(20) NOT NULL COMMENT 'project code',
`preferences` varchar(512) NOT NULL COMMENT 'project preferences',
`user_id` int(11) DEFAULT NULL COMMENT 'creator id',
`create_time` datetime NOT NULL COMMENT 'create time',
`update_time` datetime DEFAULT NULL COMMENT 'update time',
PRIMARY KEY (`id`),
UNIQUE KEY `unique_project_preference_project_code`(`project_code`),
UNIQUE KEY `unique_project_preference_code`(`code`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE = utf8_bin;
-- ----------------------------
-- Records of t_ds_project_preference
-- ----------------------------
-- ----------------------------
-- Table structure for t_ds_queue
-- ----------------------------

25
dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql

@ -606,6 +606,27 @@ CREATE TABLE t_ds_project_parameter (
CREATE UNIQUE INDEX unique_project_parameter_name on t_ds_project_parameter (project_code, param_name);
CREATE UNIQUE INDEX unique_project_parameter_code on t_ds_project_parameter (code);
--
-- Table structure for table t_ds_project_preference
--
DROP TABLE IF EXISTS t_ds_project_preference;
CREATE TABLE t_ds_project_preference
(
id int NOT NULL ,
code bigint NOT NULL,
project_code bigint NOT NULL,
preferences varchar(512) NOT NULL,
user_id int DEFAULT NULL ,
create_time timestamp DEFAULT CURRENT_TIMESTAMP ,
update_time timestamp DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY (id)
);
CREATE UNIQUE INDEX unique_project_preference_project_code on t_ds_project_preference (project_code);
CREATE UNIQUE INDEX unique_project_preference_code on t_ds_project_preference (code);
--
-- Table structure for table t_ds_queue
--
@ -998,6 +1019,10 @@ DROP SEQUENCE IF EXISTS t_ds_project_parameter_id_sequence;
CREATE SEQUENCE t_ds_project_parameter_id_sequence;
ALTER TABLE t_ds_project_parameter ALTER COLUMN id SET DEFAULT NEXTVAL('t_ds_project_parameter_id_sequence');
DROP SEQUENCE IF EXISTS t_ds_project_preference_id_sequence;
CREATE SEQUENCE t_ds_project_preference_id_sequence;
ALTER TABLE t_ds_project_preference ALTER COLUMN id SET DEFAULT NEXTVAL('t_ds_project_preference_id_sequence');
-- Records of t_ds_user?user : admin , password : dolphinscheduler123
INSERT INTO t_ds_user(user_name, user_password, user_type, email, phone, tenant_id, state, create_time, update_time, time_zone)
VALUES ('admin', '7ad2410b2f4c074479a8937a28a22b8f', '0', 'xxx@qq.com', '', '-1', 1, '2018-03-27 15:48:50', '2018-10-24 17:40:22', null);

68
dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/ProjectPreferenceMapperTest.java

@ -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.
*/
package org.apache.dolphinscheduler.dao.mapper;
import org.apache.dolphinscheduler.dao.BaseDaoTest;
import org.apache.dolphinscheduler.dao.entity.ProjectPreference;
import java.util.Date;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
public class ProjectPreferenceMapperTest extends BaseDaoTest {
@Autowired
private ProjectPreferenceMapper projectPreferenceMapper;
private ProjectPreference insertOne(long code, long projectCode) {
ProjectPreference projectPreference = new ProjectPreference();
projectPreference.setCode(code);
projectPreference.setProjectCode(projectCode);
projectPreference.setPreferences("{workerGroup:{availableOptions:[],default:1}}");
projectPreference.setCreateTime(new Date());
projectPreference.setUpdateTime(new Date());
projectPreference.setUserId(1);
projectPreferenceMapper.insert(projectPreference);
return projectPreference;
}
@Test
public void testUpdate() {
ProjectPreference projectPreference = insertOne(1, 1);
projectPreference.setUpdateTime(new Date());
int update = projectPreferenceMapper.updateById(projectPreference);
Assertions.assertEquals(1, update);
}
@Test
public void testQueryByProjectCode() {
long projectCode = 2;
ProjectPreference expectedProjectPreference = insertOne(2, projectCode);
ProjectPreference projectPreference = projectPreferenceMapper
.selectOne(new QueryWrapper<ProjectPreference>().lambda().eq(ProjectPreference::getProjectCode,
projectCode));
Assertions.assertEquals(expectedProjectPreference, projectPreference);
}
}

1
dolphinscheduler-ui/src/components/form/use-form.ts

@ -33,7 +33,6 @@ export function useForm() {
delete state.formRef.model[key]
}
}
setValues(initialValues)
}

5
dolphinscheduler-ui/src/layouts/content/use-dataList.ts

@ -117,6 +117,11 @@ export function useDataList() {
key: `/projects/${projectCode}/parameter`,
payload: { projectName: projectName },
},
{
label: t('menu.project_preferences'),
key: `/projects/${projectCode}/preferences`,
payload: { projectName: projectName },
},
]
},
{

1
dolphinscheduler-ui/src/locales/en_US/menu.ts

@ -24,6 +24,7 @@ export default {
security: 'Security',
project_overview: 'Project Overview',
project_parameter: 'Project Parameter',
project_preferences: 'Project Preferences',
workflow_relation: 'Workflow Relation',
workflow: 'Workflow',
workflow_definition: 'Workflow Definition',

7
dolphinscheduler-ui/src/locales/en_US/project.ts

@ -904,4 +904,11 @@ export default {
delete_confirm: 'Delete?',
success: 'Success',
},
preference: {
edit_preference: 'Edit Preference',
preference_manage: 'Project Preference Management',
instruction_tips: 'The settings below will affect all workflows and tasks under this project.When creating the workflow or task, these preferences will be the default value of their components.',
success: 'Success',
submit: 'Submit'
},
}

1
dolphinscheduler-ui/src/locales/zh_CN/menu.ts

@ -25,6 +25,7 @@ export default {
ui_setting: '界面设置',
project_overview: '项目概览',
project_parameter: '项目级别参数',
project_preferences: '项目偏好设置',
workflow_relation: '工作流关系',
workflow: '工作流',
workflow_definition: '工作流定义',

7
dolphinscheduler-ui/src/locales/zh_CN/project.ts

@ -878,4 +878,11 @@ export default {
delete_confirm: '确定删除吗?',
success: '成功',
},
preference: {
edit_preference: '修改项目偏好设置',
preference_manage: '项目偏好管理',
instruction_tips: '下面这些项目偏好配置将影响这个项目下的所有工作流和任务。当创建工作流和任务时,这些配置将影响组件中的默认选项',
success: '成功',
submit: '提交'
},
}

11
dolphinscheduler-ui/src/router/modules/projects.ts

@ -64,6 +64,17 @@ export default {
auth: []
}
},
{
path: '/projects/:projectCode/preferences',
name: 'projects-preference',
component: components['projects-preference'],
meta: {
title: '项目偏好设置',
activeMenu: 'projects',
showSide: true,
auth: []
}
},
{
path: '/projects/:projectCode/workflow/relation',
name: 'workflow-relation',

42
dolphinscheduler-ui/src/service/modules/projects-preference/index.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 { axios } from '@/service/service'
import {
UpdateProjectPreferenceReq
} from './types'
export function queryProjectPreferenceByProjectCode(
projectCode: number
): any {
return axios({
url: `/projects/${projectCode}/project-preference`,
method: 'get'
})
}
export function updateProjectPreference(
data: UpdateProjectPreferenceReq,
projectCode: number
): any {
return axios({
url: `/projects/${projectCode}/project-preference`,
method: 'put',
data
})
}

40
dolphinscheduler-ui/src/service/modules/projects-preference/types.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.
*/
interface ProjectPreferenceReq {
projectPreferences: string
}
interface UpdateProjectPreferenceReq extends ProjectPreferenceReq {
code: number
}
interface ProjectPreferenceRes {
id: number
code: number
projectCode: number
preferences: string
createTime: string
updateTime: string
}
export {
ProjectPreferenceRes,
ProjectPreferenceReq,
UpdateProjectPreferenceReq
}

48
dolphinscheduler-ui/src/views/projects/preference/components/use-alert-group.ts

@ -0,0 +1,48 @@
/*
* 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 '../../task/components/node/types'
import { listAlertGroupById } from '@/service/modules/alert-group'
export function useAlertGroup(): IJsonItem {
const { t } = useI18n()
const options = ref([] as { label: string; value: string }[])
const getAlertGroups = async () => {
const res = await listAlertGroupById()
options.value = res.map((item: any) => ({
label: item.groupName,
value: item.id
}))
}
onMounted(() => {
getAlertGroups()
})
return {
type: 'select',
field: 'alertGroups',
span: 12,
name: t('project.workflow.alarm_group'),
options: options,
value: 'default'
}
}

48
dolphinscheduler-ui/src/views/projects/preference/components/use-tenant.ts

@ -0,0 +1,48 @@
/*
* 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 '../../task/components/node/types'
import { queryTenantList } from '@/service/modules/tenants'
export function useTenant(): IJsonItem {
const { t } = useI18n()
const options = ref([] as { label: string; value: string }[])
const getTenantList = async () => {
const res = await queryTenantList()
options.value = res.map((item: any) => ({
label: item.tenantCode,
value: item.tenantCode
}))
}
onMounted(() => {
getTenantList()
})
return {
type: 'select',
field: 'tenant',
span: 12,
name: t('project.workflow.tenant_code'),
options: options,
value: 'default'
}
}

46
dolphinscheduler-ui/src/views/projects/preference/components/use-warning-type.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 { useI18n } from 'vue-i18n'
import type { IJsonItem } from '../../task/components/node/types'
import { warningTypeList } from '@/common/common'
export function useWarningType(): IJsonItem {
const { t } = useI18n()
const options = [] as any
const initOptions = () => {
warningTypeList.forEach((item) => {
options.push({ label: t(item.code), value: item.id })
})
}
initOptions()
return {
type: 'select',
field: 'warningType',
name: t('project.workflow.notification_strategy'),
span: 12,
options,
validate: {
required: true
},
value: 'NONE'
}
}

66
dolphinscheduler-ui/src/views/projects/preference/detail.tsx

@ -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 { defineComponent } from 'vue'
import Form from '@/components/form'
import { useForm } from './use-form'
import { NButton, NDivider, NSpace } from 'naive-ui'
const PreferenceForm = defineComponent({
name: 'PreferenceForm',
setup() {
const {
formRef,
elementsRef,
rulesRef,
model,
formProps,
t,
handleUpdate
} = useForm()
return () => (
<div>
<div style={{ margin: '30px' }}>
{t('project.preference.instruction_tips')}
</div>
<NDivider />
<Form
ref={formRef}
meta={{
model,
rules: rulesRef.value,
elements: elementsRef.value,
...formProps.value
}}
layout={{
xGap: 10
}}
style={{ marginLeft: '150px' }}
/>
<NDivider />
<NSpace justify='end'>
<NButton type='info' onClick={handleUpdate}>
{t('project.preference.submit')}
</NButton>
</NSpace>
</div>
)
}
})
export default PreferenceForm

47
dolphinscheduler-ui/src/views/projects/preference/index.tsx

@ -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 { NSpace } from 'naive-ui'
import { defineComponent, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import Card from '@/components/card'
import PreferenceForm from '@/views/projects/preference/detail'
export default defineComponent({
name: 'ProjectPreference',
setup() {
const detailRef = ref()
return {
detailRef
}
},
render() {
const { t } = useI18n()
const { detailRef } = this
return (
<NSpace vertical>
<Card title={t('project.preference.preference_manage')}>
<NSpace vertical>
<PreferenceForm ref={detailRef} />
</NSpace>
</Card>
</NSpace>
)
}
})

136
dolphinscheduler-ui/src/views/projects/preference/use-form.ts

@ -0,0 +1,136 @@
/*
* 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, reactive, ref, Ref } from 'vue'
import getElementByJson from '@/components/form/get-elements-by-json'
import type {
IFormItem,
IJsonItem,
INodeData
} from '../task/components/node/types'
import * as Fields from '@/views/projects/task/components/node/fields'
import { Router, useRouter } from 'vue-router'
import {
queryProjectPreferenceByProjectCode,
updateProjectPreference
} from '@/service/modules/projects-preference'
import { useI18n } from 'vue-i18n'
import { UpdateProjectPreferenceReq } from '@/service/modules/projects-preference/types'
import { useWarningType } from '@/views/projects/preference/components/use-warning-type'
import { useTenant } from '@/views/projects/preference/components/use-tenant'
import { useAlertGroup } from '@/views/projects/preference/components/use-alert-group'
export function useForm() {
const router: Router = useRouter()
const { t } = useI18n()
const projectCode = Number(router.currentRoute.value.params.projectCode)
const formRef = ref()
const jsonRef = ref([]) as Ref<IJsonItem[]>
const elementsRef = ref([]) as Ref<IFormItem[]>
const rulesRef = ref({})
const formProps = ref({})
formProps.value = {
labelPlacement: 'left',
labelWidth: 'auto',
size: 'large'
}
const data = reactive({
model: {
taskPriority: 'MEDIUM',
workerGroup: 'default',
environmentCode: null,
failRetryTimes: 0,
failRetryInterval: 1,
cpuQuota: -1,
memoryMax: -1,
timeoutFlag: false,
timeoutNotifyStrategy: ['WARN'],
timeout: 30
} as INodeData
})
const setValues = (initialValues: { [field: string]: any }) => {
Object.assign(data.model, initialValues)
}
const initProjectPreference = async () => {
if (projectCode) {
const result = await queryProjectPreferenceByProjectCode(projectCode)
if (result?.preferences) {
setValues(JSON.parse(result.preferences))
}
}
}
onMounted(() => {
initProjectPreference()
})
const handleUpdate = () => {
const requestData = {
projectPreferences: JSON.stringify(data.model)
} as UpdateProjectPreferenceReq
updateProjectPreference(requestData, projectCode).then(() => {
window.$message.success(t('project.preference.success'))
})
}
const preferencesItems: IJsonItem[] = [
Fields.useTaskPriority(),
useTenant(),
Fields.useWorkerGroup(),
Fields.useEnvironmentName(data.model, true),
...Fields.useFailed(),
useWarningType(),
useAlertGroup(),
...Fields.useResourceLimit()
]
const restructurePreferencesItems = (preferencesItems: any) => {
for (let item of preferencesItems) {
if (item.validate?.required) {
item.validate.required = false
item.span = 12
}
Object.assign(item, { props: { style: 'width: 250px' } })
}
return preferencesItems
}
jsonRef.value = restructurePreferencesItems(preferencesItems)
const getElements = () => {
const { rules, elements } = getElementByJson(jsonRef.value, data.model)
elementsRef.value = elements
rulesRef.value = rules
}
getElements()
return {
formRef,
elementsRef,
rulesRef,
model: data.model,
formProps,
t,
handleUpdate
}
}

32
dolphinscheduler-ui/src/views/projects/task/components/node/detail-modal.tsx

@ -24,7 +24,8 @@ import {
provide,
computed,
h,
Ref
Ref,
onMounted
} from 'vue'
import { useI18n } from 'vue-i18n'
import Modal from '@/components/modal'
@ -48,6 +49,8 @@ import type {
IWorkflowTaskInstance,
WorkflowInstance
} from './types'
import { queryProjectPreferenceByProjectCode } from '@/service/modules/projects-preference'
import { INodeData } from './types'
const props = {
show: {
@ -109,6 +112,7 @@ const NodeDetailModal = defineComponent({
}
const headerLinks = ref([] as any)
const projectPreferences = ref({} as any)
const handleViewLog = () => {
if (props.taskInstance) {
@ -116,6 +120,20 @@ const NodeDetailModal = defineComponent({
}
}
const initProjectPreferences = (projectCode: number) => {
queryProjectPreferenceByProjectCode(projectCode).then((result: any) => {
if (result?.preferences) {
projectPreferences.value = JSON.parse(result.preferences)
}
})
}
const restructureNodeData = (data: INodeData) => {
if (!data?.id) {
Object.assign(data, projectPreferences.value)
}
}
const initHeaderLinks = (processInstance: any, taskType?: ITaskType) => {
headerLinks.value = [
{
@ -158,7 +176,9 @@ const NodeDetailModal = defineComponent({
},
{
text: t('project.node.enter_this_child_node'),
show: props.data.taskType === 'SUB_PROCESS' || props.data.taskType === 'DYNAMIC',
show:
props.data.taskType === 'SUB_PROCESS' ||
props.data.taskType === 'DYNAMIC',
disabled:
!props.data.id ||
(router.currentRoute.value.name === 'workflow-instance-detail' &&
@ -204,14 +224,20 @@ const NodeDetailModal = defineComponent({
}))
)
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()
detailRef.value.value.setValues(formatModel(props.data))
restructureNodeData(nodeData)
detailRef.value.value.setValues(nodeData)
}
)

1
dolphinscheduler-ui/src/views/projects/task/components/node/format-data.ts

@ -31,6 +31,7 @@ export function formatParams(data: INodeData): {
upstreamCodes: string
taskDefinitionJsonObj: object
} {
const taskParams: ITaskParams = {}
if (data.taskType === 'SUB_PROCESS' || data.taskType === 'DYNAMIC') {
taskParams.processDefinitionCode = data.processDefinitionCode

116
dolphinscheduler-ui/src/views/projects/workflow/definition/components/timing-modal.tsx

@ -47,9 +47,11 @@ import {
NThing,
NPopover
} from 'naive-ui'
import { Router, useRouter } from 'vue-router'
import { ArrowDownOutlined, ArrowUpOutlined } from '@vicons/antd'
import { timezoneList } from '@/common/timezone'
import Crontab from '@/components/crontab'
import { queryProjectPreferenceByProjectCode } from '@/service/modules/projects-preference'
const props = {
row: {
@ -74,6 +76,8 @@ export default defineComponent({
const crontabRef = ref()
const parallelismRef = ref(false)
const { t } = useI18n()
const router: Router = useRouter()
const { timingState } = useForm()
const {
variables,
@ -86,12 +90,24 @@ export default defineComponent({
getPreviewSchedule
} = useModal(timingState, ctx)
const projectCode = Number(router.currentRoute.value.params.projectCode)
const environmentOptions = computed(() =>
variables.environmentList.filter((item: any) =>
item.workerGroups?.includes(timingState.timingForm.workerGroup)
)
)
const projectPreferences = ref({} as any)
const initProjectPreferences = (projectCode: number) => {
queryProjectPreferenceByProjectCode(projectCode).then((result: any) => {
if (result?.preferences) {
projectPreferences.value = JSON.parse(result.preferences)
}
})
}
const hideModal = () => {
ctx.emit('update:show')
}
@ -186,6 +202,71 @@ export default defineComponent({
})
}
const containValueInOptions = (
options: Array<any>,
findingValue: string
): boolean => {
for (let { value } of options) {
if (findingValue === value) {
return true
}
}
return false
}
const restructureTimingForm = (timingForm: any) => {
if (projectPreferences.value?.taskPriority) {
timingForm.processInstancePriority =
projectPreferences.value.taskPriority
}
if (projectPreferences.value?.warningType) {
timingForm.warningType = projectPreferences.value.warningType
}
if (projectPreferences.value?.workerGroup) {
if (
containValueInOptions(
variables.workerGroups,
projectPreferences.value.workerGroup
)
) {
timingForm.workerGroup = projectPreferences.value.workerGroup
}
}
if (projectPreferences.value?.tenant) {
if (
containValueInOptions(
variables.tenantList,
projectPreferences.value.tenant
)
) {
timingForm.tenantCode = projectPreferences.value.tenant
}
}
if (
projectPreferences.value?.environmentCode &&
variables?.environmentList
) {
if (
containValueInOptions(
variables.environmentList,
projectPreferences.value.environmentCode
)
) {
timingForm.environmentCode = projectPreferences.value.environmentCode
}
}
if (projectPreferences.value?.alertGroup && variables?.alertGroups) {
if (
containValueInOptions(
variables.alertGroups,
projectPreferences.value.alertGroup
)
) {
timingForm.warningGroupId = projectPreferences.value.alertGroup
}
}
}
const trim = getCurrentInstance()?.appContext.config.globalProperties.trim
onMounted(() => {
@ -193,12 +274,16 @@ export default defineComponent({
getTenantList()
getAlertGroups()
getEnvironmentList()
initProjectPreferences(projectCode)
})
watch(
() => props.row,
() => {
if (!props.row.crontab) return
if (!props.row.crontab) {
restructureTimingForm(timingState.timingForm)
return
}
timingState.timingForm.startEndTime = [
new Date(props.row.startTime),
@ -298,19 +383,22 @@ export default defineComponent({
</NFormItem>
<NFormItem label=' ' showFeedback={false}>
<NList>
{this.schedulePreviewList.length > 0 ?
<NListItem>
<NThing
description={t('project.workflow.next_five_execution_times')}
>
{this.schedulePreviewList.map((item: string) => (
<NSpace>
{item}
<br/>
</NSpace>
))}
</NThing>
</NListItem> : null}
{this.schedulePreviewList.length > 0 ? (
<NListItem>
<NThing
description={t(
'project.workflow.next_five_execution_times'
)}
>
{this.schedulePreviewList.map((item: string) => (
<NSpace>
{item}
<br />
</NSpace>
))}
</NThing>
</NListItem>
) : null}
</NList>
</NFormItem>
<NFormItem

Loading…
Cancel
Save