From 4dd976cd2ebf701a01fa211b59ece3e5853aca78 Mon Sep 17 00:00:00 2001 From: shenkaibo Date: Wed, 4 Aug 2021 09:53:59 +0800 Subject: [PATCH] Pr@v1.10@tfs (#5244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:azuredevops add issue * feat:azuredevops add issue * feat:azuredevops取消集成 * feat:azuredevops支持自定义字段 * feat:azuredevops add issue feat:azuredevops add issue feat:azuredevops取消集成 feat:azuredevops支持自定义字段 feat:azuredevops add issue feat:azuredevops add issue feat:azuredevops取消集成 feat:azuredevops支持自定义字段 fix:fix flyway version --- .gitmodules | 4 - .../io/metersphere/base/domain/Project.java | 2 + .../base/domain/ProjectExample.java | 70 ++++++ .../metersphere/base/mapper/ProjectMapper.xml | 31 ++- .../base/mapper/ext/ExtProjectMapper.xml | 5 +- .../constants/IssuesManagePlatform.java | 2 +- .../main/java/io/metersphere/dto/UserDTO.java | 1 + .../track/issue/AbstractIssuePlatform.java | 2 +- .../metersphere/track/issue/IssueFactory.java | 25 +- .../metersphere/track/issue/JiraPlatform.java | 2 +- .../track/issue/LocalAbstractPlatform.java | 2 +- .../metersphere/track/issue/TapdPlatform.java | 2 +- .../track/issue/ZentaoPlatform.java | 2 +- .../track/service/DemandService.java | 8 + .../track/service/IssuesService.java | 26 ++ backend/src/main/java/io/metersphere/xpack | 1 - ...V94__v1.11_project_add_azure_devops_id.sql | 2 + .../src/main/resources/generatorConfig.xml | 11 +- frontend/src/assets/AzureDevops.png | Bin 0 -> 4598 bytes frontend/src/assets/azureDevops-type.png | Bin 0 -> 29657 bytes .../settings/organization/BugManagement.vue | 19 +- .../components/AzureDevopsSetting.vue | 230 ++++++++++++++++++ .../settings/personal/AzureDevopsUserInfo.vue | 30 +++ .../settings/personal/PersonSetting.vue | 11 +- .../settings/project/ProjectList.vue | 8 + .../settings/workspace/MsProject.vue | 8 + .../workspace/template/IssuesTemplateList.vue | 1 + frontend/src/common/js/constants.js | 1 + frontend/src/common/js/table-constants.js | 1 + frontend/src/i18n/en-US.js | 13 +- frontend/src/i18n/zh-CN.js | 14 +- frontend/src/i18n/zh-TW.js | 15 +- 32 files changed, 514 insertions(+), 35 deletions(-) delete mode 160000 backend/src/main/java/io/metersphere/xpack create mode 100644 backend/src/main/resources/db/migration/V94__v1.11_project_add_azure_devops_id.sql create mode 100644 frontend/src/assets/AzureDevops.png create mode 100644 frontend/src/assets/azureDevops-type.png create mode 100644 frontend/src/business/components/settings/organization/components/AzureDevopsSetting.vue create mode 100644 frontend/src/business/components/settings/personal/AzureDevopsUserInfo.vue diff --git a/.gitmodules b/.gitmodules index c6324db453..e85986733a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ -[submodule "backend/src/main/java/io/metersphere/xpack"] - path = backend/src/main/java/io/metersphere/xpack - url = git@github.com:metersphere/xpack-backend.git - branch = master [submodule "frontend/src/business/components/xpack"] path = frontend/src/business/components/xpack url = git@github.com:metersphere/xpack-frontend.git diff --git a/backend/src/main/java/io/metersphere/base/domain/Project.java b/backend/src/main/java/io/metersphere/base/domain/Project.java index b167839386..2e1470180b 100644 --- a/backend/src/main/java/io/metersphere/base/domain/Project.java +++ b/backend/src/main/java/io/metersphere/base/domain/Project.java @@ -23,6 +23,8 @@ public class Project implements Serializable { private String zentaoId; + private String azureDevopsId; + private Boolean repeatable; private String caseTemplateId; diff --git a/backend/src/main/java/io/metersphere/base/domain/ProjectExample.java b/backend/src/main/java/io/metersphere/base/domain/ProjectExample.java index 06ce2efdc0..abf3cc1b01 100644 --- a/backend/src/main/java/io/metersphere/base/domain/ProjectExample.java +++ b/backend/src/main/java/io/metersphere/base/domain/ProjectExample.java @@ -714,6 +714,76 @@ public class ProjectExample { return (Criteria) this; } + public Criteria andAzureDevopsIdIsNull() { + addCriterion("azure_devops_id is null"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdIsNotNull() { + addCriterion("azure_devops_id is not null"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdEqualTo(String value) { + addCriterion("azure_devops_id =", value, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdNotEqualTo(String value) { + addCriterion("azure_devops_id <>", value, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdGreaterThan(String value) { + addCriterion("azure_devops_id >", value, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdGreaterThanOrEqualTo(String value) { + addCriterion("azure_devops_id >=", value, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdLessThan(String value) { + addCriterion("azure_devops_id <", value, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdLessThanOrEqualTo(String value) { + addCriterion("azure_devops_id <=", value, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdLike(String value) { + addCriterion("azure_devops_id like", value, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdNotLike(String value) { + addCriterion("azure_devops_id not like", value, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdIn(List values) { + addCriterion("azure_devops_id in", values, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdNotIn(List values) { + addCriterion("azure_devops_id not in", values, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdBetween(String value1, String value2) { + addCriterion("azure_devops_id between", value1, value2, "azureDevopsId"); + return (Criteria) this; + } + + public Criteria andAzureDevopsIdNotBetween(String value1, String value2) { + addCriterion("azure_devops_id not between", value1, value2, "azureDevopsId"); + return (Criteria) this; + } + public Criteria andRepeatableIsNull() { addCriterion("`repeatable` is null"); return (Criteria) this; diff --git a/backend/src/main/java/io/metersphere/base/mapper/ProjectMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ProjectMapper.xml index f92e0c014e..f99aa860a8 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ProjectMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ProjectMapper.xml @@ -11,6 +11,7 @@ + @@ -79,8 +80,8 @@ id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key, - zentao_id, `repeatable`, case_template_id, issue_template_id, custom_num, scenario_custom_num, - create_user, system_id + zentao_id, azure_devops_id, `repeatable`, case_template_id, issue_template_id, custom_num, + scenario_custom_num, create_user, system_id select p.id, p.workspace_id, p.name, p.description, p.update_time, p.issue_template_id, p.case_template_id, - p.create_time, w.id as workspaceId, w.name as workspaceName, p.tapd_id, p.jira_key, p.zentao_id,p.repeatable, p.custom_num, + p.create_time, w.id as workspaceId, w.name as workspaceName, p.tapd_id, p.jira_key, p.zentao_id,p.azure_devops_id,p.repeatable, p.custom_num, user.name as createUserName, p.scenario_custom_num from project p @@ -131,6 +131,9 @@ zentao_id = null + + azure_devops_id = null + where project.id in (select id from (select id from project diff --git a/backend/src/main/java/io/metersphere/commons/constants/IssuesManagePlatform.java b/backend/src/main/java/io/metersphere/commons/constants/IssuesManagePlatform.java index 0e6540740d..32e0ce8cad 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/IssuesManagePlatform.java +++ b/backend/src/main/java/io/metersphere/commons/constants/IssuesManagePlatform.java @@ -1,5 +1,5 @@ package io.metersphere.commons.constants; public enum IssuesManagePlatform { - Tapd, Jira, Local, Zentao + Tapd, Jira, Local, Zentao, AzureDevops } diff --git a/backend/src/main/java/io/metersphere/dto/UserDTO.java b/backend/src/main/java/io/metersphere/dto/UserDTO.java index 2d41f6c8c2..771aaf2eec 100644 --- a/backend/src/main/java/io/metersphere/dto/UserDTO.java +++ b/backend/src/main/java/io/metersphere/dto/UserDTO.java @@ -29,6 +29,7 @@ public class UserDTO extends User { private String tapdUserName; private String zentaoUserName; private String zentaoPassword; + private String azureDevopsPat; } } diff --git a/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java b/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java index 5adb29fc41..11c31f4ade 100644 --- a/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/AbstractIssuePlatform.java @@ -130,7 +130,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform { * * @return 其他平台和本地项目绑定的属性值 */ - abstract String getProjectId(String projectId); + public abstract String getProjectId(String projectId); protected boolean isIntegratedPlatform(String orgId, String platform) { IntegrationRequest request = new IntegrationRequest(); diff --git a/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java b/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java index 3960a34ce2..87b2e43952 100644 --- a/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java +++ b/backend/src/main/java/io/metersphere/track/issue/IssueFactory.java @@ -4,10 +4,9 @@ import io.metersphere.commons.constants.IssuesManagePlatform; import io.metersphere.track.request.testcase.IssuesRequest; import org.apache.commons.lang3.StringUtils; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.*; public class IssueFactory { public static AbstractIssuePlatform createPlatform(String platform, IssuesRequest addIssueRequest) { @@ -17,6 +16,24 @@ public class IssueFactory { return new JiraPlatform(addIssueRequest); } else if (StringUtils.equals(IssuesManagePlatform.Zentao.toString(), platform)) { return new ZentaoPlatform(addIssueRequest); + } else if (StringUtils.equals(IssuesManagePlatform.AzureDevops.toString(), platform)) { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + try { + Class clazz = loader.loadClass("io.metersphere.xpack.issue.azureDevops.AzureDevopsPlatform"); + Constructor cons = clazz.getDeclaredConstructor(new Class[] { IssuesRequest.class }); + AbstractIssuePlatform azureDevopsPlatform = (AbstractIssuePlatform) cons.newInstance(addIssueRequest); + return azureDevopsPlatform; + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } } else if (StringUtils.equalsIgnoreCase(IssuesManagePlatform.Local.toString(), platform)) { return new LocalPlatform(addIssueRequest); } diff --git a/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java b/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java index 731c3bb630..303558ccb2 100644 --- a/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/JiraPlatform.java @@ -298,7 +298,7 @@ public class JiraPlatform extends AbstractIssuePlatform { } @Override - String getProjectId(String projectId) { + public String getProjectId(String projectId) { if (StringUtils.isNotBlank(projectId)) { return projectService.getProjectById(projectId).getJiraKey(); } diff --git a/backend/src/main/java/io/metersphere/track/issue/LocalAbstractPlatform.java b/backend/src/main/java/io/metersphere/track/issue/LocalAbstractPlatform.java index f105d2b669..2e9bd550c6 100644 --- a/backend/src/main/java/io/metersphere/track/issue/LocalAbstractPlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/LocalAbstractPlatform.java @@ -25,5 +25,5 @@ public abstract class LocalAbstractPlatform extends AbstractIssuePlatform { public void syncIssues(Project project, List tapdIssues) {} @Override - String getProjectId(String projectId) { return null; } + public String getProjectId(String projectId) { return null; } } diff --git a/backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java b/backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java index 153afc1249..2c5e9fa4c6 100644 --- a/backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/TapdPlatform.java @@ -236,7 +236,7 @@ public class TapdPlatform extends AbstractIssuePlatform { } @Override - String getProjectId(String projectId) { + public String getProjectId(String projectId) { if (StringUtils.isNotBlank(projectId)) { return projectService.getProjectById(projectId).getTapdId(); } diff --git a/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java b/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java index 794396d2d7..6667f12e2e 100644 --- a/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java +++ b/backend/src/main/java/io/metersphere/track/issue/ZentaoPlatform.java @@ -70,7 +70,7 @@ public class ZentaoPlatform extends AbstractIssuePlatform { } @Override - String getProjectId(String projectId) { + public String getProjectId(String projectId) { if (StringUtils.isNotBlank(projectId)) { return projectService.getProjectById(projectId).getZentaoId(); } diff --git a/backend/src/main/java/io/metersphere/track/service/DemandService.java b/backend/src/main/java/io/metersphere/track/service/DemandService.java index 701c412d37..221980ac06 100644 --- a/backend/src/main/java/io/metersphere/track/service/DemandService.java +++ b/backend/src/main/java/io/metersphere/track/service/DemandService.java @@ -34,6 +34,7 @@ public class DemandService { boolean tapd = issuesService.isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString()); boolean jira = issuesService.isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString()); boolean zentao = issuesService.isIntegratedPlatform(orgId, IssuesManagePlatform.Zentao.toString()); + boolean azureDevops = issuesService.isIntegratedPlatform(orgId, IssuesManagePlatform.AzureDevops.toString()); List list = new ArrayList<>(); List platforms = new ArrayList<>(); IssuesRequest issueRequest = new IssuesRequest(); @@ -59,6 +60,13 @@ public class DemandService { } } + if (azureDevops) { + String azureDevopsId = project.getAzureDevopsId(); + if (StringUtils.isNotBlank(azureDevopsId)) { + platforms.add(IssuesManagePlatform.AzureDevops.name()); + } + } + issueRequest.setOrganizationId(orgId); List platformList = IssueFactory.createPlatforms(platforms, issueRequest); platformList.forEach(platform -> { diff --git a/backend/src/main/java/io/metersphere/track/service/IssuesService.java b/backend/src/main/java/io/metersphere/track/service/IssuesService.java index 9630e4441b..14ab77c929 100644 --- a/backend/src/main/java/io/metersphere/track/service/IssuesService.java +++ b/backend/src/main/java/io/metersphere/track/service/IssuesService.java @@ -40,6 +40,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -88,6 +90,8 @@ public class IssuesService { abstractPlatform.testAuth(); } + + public void addIssues(IssuesUpdateRequest issuesRequest) { List platformList = getUpdatePlatforms(issuesRequest); platformList.forEach(platform -> { @@ -453,6 +457,9 @@ public class IssuesService { List zentaoIssues = issues.stream() .filter(item -> item.getPlatform().equals(IssuesManagePlatform.Zentao.name())) .collect(Collectors.toList()); + List azureDevopsIssues = issues.stream() + .filter(item -> item.getPlatform().equals(IssuesManagePlatform.AzureDevops.name())) + .collect(Collectors.toList()); IssuesRequest issuesRequest = new IssuesRequest(); issuesRequest.setProjectId(projectId); @@ -469,6 +476,25 @@ public class IssuesService { ZentaoPlatform zentaoPlatform = new ZentaoPlatform(issuesRequest); syncThirdPartyIssues(zentaoPlatform::syncIssues, project, zentaoIssues); } + if (CollectionUtils.isNotEmpty(azureDevopsIssues)) { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + try { + Class clazz = loader.loadClass("io.metersphere.xpack.issue.azureDevops.AzureDevopsPlatform"); + Constructor cons = clazz.getDeclaredConstructor(new Class[] { IssuesRequest.class }); + AbstractIssuePlatform azureDevopsPlatform = (AbstractIssuePlatform) cons.newInstance(issuesRequest); + syncThirdPartyIssues(azureDevopsPlatform::syncIssues, project, azureDevopsIssues); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } } } diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack deleted file mode 160000 index 52e757ba12..0000000000 --- a/backend/src/main/java/io/metersphere/xpack +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 52e757ba127c9b33e2715c02bc618aa315192ceb diff --git a/backend/src/main/resources/db/migration/V94__v1.11_project_add_azure_devops_id.sql b/backend/src/main/resources/db/migration/V94__v1.11_project_add_azure_devops_id.sql new file mode 100644 index 0000000000..84b0b5372d --- /dev/null +++ b/backend/src/main/resources/db/migration/V94__v1.11_project_add_azure_devops_id.sql @@ -0,0 +1,2 @@ +alter table project add azure_devops_id varchar(50) null after zentao_id; +alter table custom_field_template modify default_value varchar(100) null ; \ No newline at end of file diff --git a/backend/src/main/resources/generatorConfig.xml b/backend/src/main/resources/generatorConfig.xml index 72de9d40b4..6e1f8c396f 100644 --- a/backend/src/main/resources/generatorConfig.xml +++ b/backend/src/main/resources/generatorConfig.xml @@ -64,7 +64,7 @@ - + @@ -78,16 +78,21 @@
--> - +<<<<<<< HEAD
+======= + +>>>>>>> feat:azuredevops add issue diff --git a/frontend/src/assets/AzureDevops.png b/frontend/src/assets/AzureDevops.png new file mode 100644 index 0000000000000000000000000000000000000000..2e3b3323fefe4aaa270426d86d10b1232be0d549 GIT binary patch literal 4598 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 literal 0 HcmV?d00001 diff --git a/frontend/src/business/components/settings/organization/BugManagement.vue b/frontend/src/business/components/settings/organization/BugManagement.vue index 0c5a2c3bb7..0efd34f7e5 100644 --- a/frontend/src/business/components/settings/organization/BugManagement.vue +++ b/frontend/src/business/components/settings/organization/BugManagement.vue @@ -12,13 +12,16 @@ Zentao + + AzureDevops + - + @@ -26,16 +29,18 @@ import TapdSetting from "@/business/components/settings/organization/components/TapdSetting"; import JiraSetting from "@/business/components/settings/organization/components/JiraSetting"; import ZentaoSetting from "@/business/components/settings/organization/components/ZentaoSetting"; -import {JIRA, TAPD, ZEN_TAO} from "@/common/js/constants"; +import AzuredevopsSetting from "@/business/components/settings/organization/components/AzureDevopsSetting"; +import {JIRA, TAPD, ZEN_TAO, AZURE_DEVOPS} from "@/common/js/constants"; export default { name: "BugManagement", - components: {TapdSetting, JiraSetting, ZentaoSetting}, + components: {TapdSetting, JiraSetting, ZentaoSetting, AzuredevopsSetting}, data() { return { tapdEnable: true, jiraEnable: false, zentaoEnable: false, + azuredevopsEnable:false, result: {}, platform: TAPD } @@ -46,14 +51,22 @@ export default { this.tapdEnable = true; this.jiraEnable = false; this.zentaoEnable = false; + this.azuredevopsEnable = false; } else if (platform === JIRA) { this.tapdEnable = false; this.jiraEnable = true; this.zentaoEnable = false; + this.azuredevopsEnable = false; } else if (platform === ZEN_TAO) { this.tapdEnable = false; this.jiraEnable = false; this.zentaoEnable = true; + this.azuredevopsEnable = false; + } else if (platform === AZURE_DEVOPS) { + this.tapdEnable = false; + this.jiraEnable = false; + this.zentaoEnable = false; + this.azuredevopsEnable = true; } } } diff --git a/frontend/src/business/components/settings/organization/components/AzureDevopsSetting.vue b/frontend/src/business/components/settings/organization/components/AzureDevopsSetting.vue new file mode 100644 index 0000000000..608205e009 --- /dev/null +++ b/frontend/src/business/components/settings/organization/components/AzureDevopsSetting.vue @@ -0,0 +1,230 @@ + + + + + diff --git a/frontend/src/business/components/settings/personal/AzureDevopsUserInfo.vue b/frontend/src/business/components/settings/personal/AzureDevopsUserInfo.vue new file mode 100644 index 0000000000..8736367560 --- /dev/null +++ b/frontend/src/business/components/settings/personal/AzureDevopsUserInfo.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/frontend/src/business/components/settings/personal/PersonSetting.vue b/frontend/src/business/components/settings/personal/PersonSetting.vue index 3215e65aa8..f325c0f0ce 100644 --- a/frontend/src/business/components/settings/personal/PersonSetting.vue +++ b/frontend/src/business/components/settings/personal/PersonSetting.vue @@ -54,6 +54,7 @@ + + + + @@ -300,6 +303,7 @@ export default { tapd: false, jira: false, zentao: false, + azuredevops: false, form: {}, currentPage: 1, pageSize: 10, @@ -430,6 +434,9 @@ export default { if (platforms.indexOf("Zentao") !== -1) { this.zentao = true; } + if (platforms.indexOf("AzureDevops") !== -1) { + this.azuredevops = true; + } }); }, submit(formName) { @@ -494,6 +501,7 @@ export default { this.tapd = false; this.jira = false; this.zentao = false; + this.azuredevops = false; }, search() { this.list(); diff --git a/frontend/src/business/components/settings/workspace/template/IssuesTemplateList.vue b/frontend/src/business/components/settings/workspace/template/IssuesTemplateList.vue index 7b10660715..f55a1d5ac6 100644 --- a/frontend/src/business/components/settings/workspace/template/IssuesTemplateList.vue +++ b/frontend/src/business/components/settings/workspace/template/IssuesTemplateList.vue @@ -109,6 +109,7 @@ export default { Jira: 'JIRA', Tapd: 'Tapd', Zentao: '禅道', + AzureDevops: 'Azure Devops', }, operators: [ { diff --git a/frontend/src/common/js/constants.js b/frontend/src/common/js/constants.js index 36780550b4..b9cc173876 100644 --- a/frontend/src/common/js/constants.js +++ b/frontend/src/common/js/constants.js @@ -38,6 +38,7 @@ export const EN_US = 'en_US'; export const TAPD = 'Tapd'; export const JIRA = 'Jira'; export const ZEN_TAO = 'Zentao'; +export const AZURE_DEVOPS = 'AzureDevops'; export const GROUP_SYSTEM = 'SYSTEM'; export const GROUP_ORGANIZATION = 'ORGANIZATION'; diff --git a/frontend/src/common/js/table-constants.js b/frontend/src/common/js/table-constants.js index 743fe71969..f21d51006c 100644 --- a/frontend/src/common/js/table-constants.js +++ b/frontend/src/common/js/table-constants.js @@ -29,6 +29,7 @@ export const ISSUE_PLATFORM_OPTION = [ {value: 'Jira',text: 'JIRA'}, {value: 'Tapd',text: 'Tapd'}, {value: 'Zentao',text: '禅道'}, + {value: 'AzureDevops',text: 'Azure Devops'}, ]; export const FIELD_TYPE_MAP = { diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index 215a877cd5..0281212bf5 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -424,7 +424,17 @@ export default { successful_operation: 'Successful operation', not_integrated: 'The platform is not integrated', choose_platform: 'Please choose an integrated platform', - verified: 'Verified' + azure_issuetype: 'Azure issue type', + azure_storytype: 'Azure story type', + input_azure_issuetype: 'Please enter the issue type', + input_azure_storytype: 'Please enter the story type', + azure_pat:'PersonalAccessTokens', + azure_devops_url:'Azure Devops url', + azure_organization_id:'Azure Organization ID', + input_azure_pat:'Please enter Personal Access Token', + input_azure_url:'Please enter Azure Devops Url', + input_azure_id:'Please enter Azure Organization ID', + use_tip_azure: 'Azure Devops URL+PersonalAccessTokens(User Settings-Personal Access Tokens-New Token)', } }, project: { @@ -445,6 +455,7 @@ export default { tapd_id: 'TAPD Project ID', jira_key: 'JIRA Project key', zentao_id: 'Zentao Project ID', + azureDevops_id: 'AzureDevops Project ID', manager: 'Manager', no_data: 'No Data', select: 'Select', diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index e118dad63b..cb435cadd7 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -423,7 +423,18 @@ export default { successful_operation: '操作成功', not_integrated: '未集成该平台', choose_platform: '请选择集成的平台', - verified: '验证通过' + verified: '验证通过', + azure_issuetype: '问题类型', + azure_storytype: '需求类型', + input_azure_issuetype: '请输入问题类型', + input_azure_storytype: '请输入需求类型', + azure_pat:'PersonalAccessTokens', + azure_devops_url:'Azure Devops 地址', + azure_organization_id:'Azure 组织ID', + input_azure_pat:'请输入 Personal Access Token', + input_azure_url:'请输入 Azure Devops 地址', + input_azure_organization_id:'请输入 Azure 组织ID', + use_tip_azure: 'Azure Devops 地址+令牌(账户设置-个人访问令牌-创建令牌)', } }, project: { @@ -444,6 +455,7 @@ export default { tapd_id: 'TAPD项目ID', jira_key: 'JIRA项目key', zentao_id: 'Zentao项目ID', + azureDevops_id: 'AzureDevops项目ID', manager: '项目管理', no_data: '无数据', select: '选择项目', diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index 75ae90511a..ae568ddfd7 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -402,6 +402,7 @@ export default { jira_storytype: '需求類型', input_api_account: '請輸入賬號', input_api_password: '請輸入密碼', + input_api_pat:'請输入 Personal Access Token', input_jira_url: '請輸入Jira地址,例:https://metersphere.atlassian.net/', input_jira_issuetype: '請輸入問題類型', input_jira_storytype: '請輸入需求類型', @@ -423,7 +424,18 @@ export default { successful_operation: '操作成功', not_integrated: '未集成該平臺', choose_platform: '請選擇集成的平臺', - verified: '驗證通過' + verified: '驗證通過', + azure_issuetype: '問題類型', + azure_storytype: '需求類型', + input_azure_issuetype: '請輸入問題類型', + input_azure_storytype: '請輸入需求類型', + azure_pat:'PersonalAccessTokens', + azure_devops_url:'Azure Devops 地址', + azure_organization_id:'Azure 組織ID', + input_azure_pat:'請輸入 Personal Access Token', + input_azure_url:'請輸入 Azure Devops 地址', + input_azure_id:'請輸入 Azure 組織ID', + use_tip_azure: 'Azure Devops 地址+令牌(賬戶設置-個人訪問令牌-創建令牌)', } }, project: { @@ -444,6 +456,7 @@ export default { tapd_id: 'TAPD項目ID', jira_key: 'JIRA項目key', zentao_id: 'Zentao項目ID', + azureDevops_id: 'AzureDevops項目ID', manager: '項目管理', no_data: '無數據', select: '選擇項目',