feat(项目设置): 项目设置缺陷平台插件化
This commit is contained in:
parent
debc072829
commit
6c6fd3e2b3
|
@ -188,6 +188,7 @@ export default {
|
|||
if (this.form) {
|
||||
this.$set(this.form, this.data.name, this.data[this.prop]);
|
||||
}
|
||||
this.$emit('change', this.data.name);
|
||||
this.$forceUpdate();
|
||||
},
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@ export const ZH_TW = 'zh_TW';
|
|||
export const EN_US = 'en_US';
|
||||
|
||||
export const TAPD = 'Tapd';
|
||||
export const JIRA = 'Jira';
|
||||
export const ZEN_TAO = 'Zentao';
|
||||
export const LOCAL = 'Local';
|
||||
export const AZURE_DEVOPS = 'AzureDevops';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 模板
|
||||
import i18n from "../i18n";
|
||||
import {AZURE_DEVOPS, JIRA, LOCAL, TAPD, ZEN_TAO} from "./constants";
|
||||
import {AZURE_DEVOPS, LOCAL, TAPD, ZEN_TAO} from "./constants";
|
||||
|
||||
export const CUSTOM_FIELD_TYPE_OPTION = [
|
||||
{value: 'input', text: 'workspace.custom_filed.input'},
|
||||
|
@ -68,7 +68,6 @@ export function CASE_TYPE_OPTION(){
|
|||
export const ISSUE_PLATFORM_OPTION = [
|
||||
{value: LOCAL, text: 'Local'},
|
||||
{value: TAPD, text: 'Tapd'},
|
||||
{value: JIRA, text: 'JIRA'},
|
||||
{value: ZEN_TAO, text: 'Zentao'},
|
||||
{value: AZURE_DEVOPS, text: 'Azure Devops'},
|
||||
];
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
|
@ -37,4 +38,23 @@ public class RemoteService {
|
|||
public Object post(String url, Object param) {
|
||||
return Optional.ofNullable(microService.postForData(serviceName, url, param)).orElse(StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
public Object get(HttpServletRequest request) {
|
||||
// 返回null,前端会报错
|
||||
return Optional.ofNullable(microService.getForData(serviceName, wrapperQuery(request))).orElse(StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
|
||||
public Object post(HttpServletRequest request, Object param) {
|
||||
// 返回null,前端会报错
|
||||
return Optional.ofNullable(microService.postForData(serviceName, wrapperQuery(request), param)).orElse(StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
private String wrapperQuery(HttpServletRequest request) {
|
||||
String url = request.getRequestURI();
|
||||
if (StringUtils.isNotBlank(request.getQueryString())) {
|
||||
url += "?" + request.getQueryString();
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ import io.metersphere.dto.WorkspaceMemberDTO;
|
|||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.log.annotation.MsAuditLog;
|
||||
import io.metersphere.request.AddProjectRequest;
|
||||
import io.metersphere.request.JiraIssueType;
|
||||
import io.metersphere.request.JiraIssueTypeRequest;
|
||||
import io.metersphere.request.ProjectRequest;
|
||||
import io.metersphere.request.member.AddMemberRequest;
|
||||
import io.metersphere.request.member.QueryMemberRequest;
|
||||
|
@ -139,11 +137,6 @@ public class ProjectController {
|
|||
return projectService.getAllServiceIntegration();
|
||||
}
|
||||
|
||||
@PostMapping("/issues/jira/issuetype")
|
||||
public List<JiraIssueType> getJiraIssueType(@RequestBody JiraIssueTypeRequest request) {
|
||||
return projectService.getJiraIssueType(request);
|
||||
}
|
||||
|
||||
@PostMapping("/member/add")
|
||||
public void addProjectMember(@RequestBody AddMemberRequest request) {
|
||||
projectService.addProjectMember(request);
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package io.metersphere.controller.remote;
|
||||
|
||||
import io.metersphere.remote.service.PlatformPluginService;
|
||||
import io.metersphere.remote.service.SystemSettingService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = {
|
||||
"/platform/plugin",
|
||||
})
|
||||
public class SystemSettingController {
|
||||
@Resource
|
||||
SystemSettingService systemSettingService;
|
||||
@Resource
|
||||
PlatformPluginService platformPluginService;
|
||||
|
||||
@PostMapping("/**")
|
||||
public Object list(HttpServletRequest request, @RequestBody Object param) {
|
||||
return systemSettingService.post(request, param);
|
||||
}
|
||||
|
||||
@GetMapping("/**")
|
||||
public Object get(HttpServletRequest request) {
|
||||
return systemSettingService.get(request);
|
||||
}
|
||||
|
||||
@GetMapping("/resource/{pluginId}")
|
||||
public void getPluginResource(@PathVariable("pluginId") String pluginId, @RequestParam("fileName") String fileName, HttpServletResponse response) {
|
||||
platformPluginService.getPluginResource(pluginId, fileName, response);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package io.metersphere.remote.service;
|
||||
|
||||
import io.metersphere.commons.constants.StorageConstants;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.metadata.service.FileManagerService;
|
||||
import io.metersphere.metadata.vo.FileRequest;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
@Service
|
||||
public class PlatformPluginService {
|
||||
|
||||
@Resource
|
||||
FileManagerService fileManagerService;
|
||||
|
||||
public static final String DIR_PATH = "system/plugin";
|
||||
|
||||
public void getPluginResource(String pluginId, String name, HttpServletResponse response) {
|
||||
FileRequest request = new FileRequest();
|
||||
request.setProjectId(DIR_PATH + "/" + pluginId);
|
||||
request.setFileName(name);
|
||||
request.setStorage(StorageConstants.MINIO.name());
|
||||
InputStream inputStream = fileManagerService.downloadFileAsStream(request);
|
||||
getImage(inputStream, response);
|
||||
}
|
||||
|
||||
public void getImage(InputStream in, HttpServletResponse response) {
|
||||
response.setContentType("image/png");
|
||||
try (OutputStream out = response.getOutputStream()) {
|
||||
out.write(in.readAllBytes());
|
||||
out.flush();
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
} finally {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package io.metersphere.remote.service;
|
||||
|
||||
import io.metersphere.commons.constants.MicroServiceName;
|
||||
import io.metersphere.service.RemoteService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SystemSettingService extends RemoteService {
|
||||
public SystemSettingService() {
|
||||
super(MicroServiceName.SYSTEM_SETTING);
|
||||
}
|
||||
}
|
|
@ -428,10 +428,6 @@ public class ProjectService {
|
|||
microService.postForData(MicroServiceName.TEST_TRACK, "/issues/check/third/project", project);
|
||||
}
|
||||
|
||||
public List<JiraIssueType> getJiraIssueType(JiraIssueTypeRequest request) {
|
||||
return microService.postForDataArray(MicroServiceName.TEST_TRACK, "/issues/jira/issuetype", request, JiraIssueType.class);
|
||||
}
|
||||
|
||||
public void addOrUpdateCleanUpSchedule(AddProjectRequest project) {
|
||||
Boolean cleanTrackReport = project.getCleanTrackReport();
|
||||
Boolean cleanApiReport = project.getCleanApiReport();
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import {post, get} from "metersphere-frontend/src/plugins/request";
|
||||
const BASE_URL = "/platform/plugin/";
|
||||
|
||||
export function getPlatformProjectInfo(key) {
|
||||
return key ? get(BASE_URL + `project/info/${key}`) : new Promise(r => r({}));
|
||||
}
|
||||
|
||||
export function validateProjectConfig(pluginId, config) {
|
||||
return post(BASE_URL + `project/validate/${pluginId}`, config);
|
||||
}
|
||||
|
||||
export function getPlatformProjectOption(pluginId, request) {
|
||||
return post(BASE_URL + 'project/option', request);
|
||||
}
|
||||
|
||||
export function getPlatformOption() {
|
||||
return get(BASE_URL + 'platform/option');
|
||||
}
|
||||
|
||||
export function getThirdPartTemplateSupportPlatform() {
|
||||
return get(BASE_URL + 'template/support/list');
|
||||
}
|
|
@ -26,10 +26,10 @@
|
|||
:label="$t('workspace.issue_template_manage')" prop="issueTemplateId">
|
||||
<template-select :platform="form.platform" :data="form" scene="ISSUE" prop="issueTemplateId"
|
||||
:disabled="form.platform === 'Jira' && form.thirdPartTemplate"
|
||||
:platformOptions="issueOptions" :project-id="form.id"
|
||||
:platformOptions="platformOptions" :project-id="form.id"
|
||||
ref="issueTemplate"/>
|
||||
|
||||
<el-checkbox @change="thirdPartTemplateChange" v-if="form.platform === 'Jira'"
|
||||
<el-checkbox @change="thirdPartTemplateChange" v-if="form.platform === 'Jira' && thirdPartTemplateSupport"
|
||||
v-model="form.thirdPartTemplate" style="margin-left: 10px">
|
||||
{{ $t('test_track.issue.use_third_party') }}
|
||||
</el-checkbox>
|
||||
|
@ -51,13 +51,15 @@
|
|||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<project-jira-config :result="jiraResult" v-if="jira" :label-width="labelWidth" :form="form" ref="jiraConfig">
|
||||
<template #checkBtn>
|
||||
<el-button @click="check" type="primary" class="checkButton">
|
||||
{{ $t('test_track.issue.check_id_exist') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</project-jira-config>
|
||||
<project-platform-config
|
||||
v-if="form.platform === 'Jira'"
|
||||
:result="jiraResult"
|
||||
:platform-key="form.platform"
|
||||
:label-width="labelWidth"
|
||||
:project-config="platformConfig"
|
||||
ref="platformConfig"
|
||||
/>
|
||||
|
||||
<el-form-item :label-width="labelWidth" :label="$t('project.zentao_id')" v-if="zentao">
|
||||
<el-input v-model="form.zentaoId" autocomplete="off"></el-input>
|
||||
<el-button @click="check" type="primary" class="checkButton">
|
||||
|
@ -103,7 +105,7 @@ import {
|
|||
getCurrentUserId,
|
||||
getCurrentWorkspaceId
|
||||
} from "metersphere-frontend/src/utils/token";
|
||||
import {AZURE_DEVOPS, JIRA, PROJECT_ID, TAPD, ZEN_TAO} from "metersphere-frontend/src/utils/constants";
|
||||
import {AZURE_DEVOPS, PROJECT_ID, TAPD, ZEN_TAO} from "metersphere-frontend/src/utils/constants";
|
||||
import {PROJECT_CONFIGS} from "metersphere-frontend/src/components/search/search-components";
|
||||
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
|
||||
import TemplateSelect from "../menu/template/TemplateSelect";
|
||||
|
@ -117,7 +119,6 @@ import MsTablePagination from "metersphere-frontend/src/components/pagination/Ta
|
|||
import MsTableHeader from "metersphere-frontend/src/components/MsTableHeader";
|
||||
import MsDialogFooter from "metersphere-frontend/src/components/MsDialogFooter";
|
||||
import {ISSUE_PLATFORM_OPTION} from "metersphere-frontend/src/utils/table-constants";
|
||||
import ProjectJiraConfig from "./ProjectJiraConfig";
|
||||
import {getAllServiceIntegration} from "../../api/project";
|
||||
import {
|
||||
checkThirdPlatformProject,
|
||||
|
@ -126,11 +127,13 @@ import {
|
|||
saveProject
|
||||
} from "../../api/project";
|
||||
import {updateInfo} from "metersphere-frontend/src/api/user";
|
||||
import ProjectPlatformConfig from "@/business/home/ProjectPlatformConfig";
|
||||
import {getPlatformOption, getThirdPartTemplateSupportPlatform} from "@/api/platform-plugin";
|
||||
|
||||
export default {
|
||||
name: "EditProject",
|
||||
components: {
|
||||
ProjectJiraConfig,
|
||||
ProjectPlatformConfig,
|
||||
MsInstructionsIcon,
|
||||
TemplateSelect,
|
||||
MsTableButton,
|
||||
|
@ -152,6 +155,9 @@ export default {
|
|||
jiraResult: {
|
||||
loading: false
|
||||
},
|
||||
platformProjectConfigs: [],
|
||||
platformConfig: {},
|
||||
thirdPartTemplateSupportPlatforms: [],
|
||||
btnTips: this.$t('project.create'),
|
||||
title: this.$t('project.create'),
|
||||
condition: {components: PROJECT_CONFIGS},
|
||||
|
@ -171,7 +177,6 @@ export default {
|
|||
],
|
||||
},
|
||||
platformOptions: [],
|
||||
issueOptions: [],
|
||||
issueTemplateId: "",
|
||||
ableEdit: true,
|
||||
};
|
||||
|
@ -192,15 +197,15 @@ export default {
|
|||
tapd() {
|
||||
return this.showPlatform(TAPD);
|
||||
},
|
||||
jira() {
|
||||
return this.showPlatform(JIRA);
|
||||
},
|
||||
zentao() {
|
||||
return this.showPlatform(ZEN_TAO);
|
||||
},
|
||||
azuredevops() {
|
||||
return this.showPlatform(AZURE_DEVOPS);
|
||||
},
|
||||
thirdPartTemplateSupport() {
|
||||
return this.thirdPartTemplateSupportPlatforms.indexOf(this.form.platform) > -1;
|
||||
}
|
||||
},
|
||||
inject: ['reload'],
|
||||
destroyed() {
|
||||
|
@ -230,6 +235,10 @@ export default {
|
|||
if (this.$refs.apiTemplate) {
|
||||
this.$refs.apiTemplate.getTemplateOptions();
|
||||
}
|
||||
getThirdPartTemplateSupportPlatform()
|
||||
.then((r) => {
|
||||
this.thirdPartTemplateSupportPlatforms = r.data;
|
||||
});
|
||||
},
|
||||
thirdPartTemplateChange(val) {
|
||||
if (val)
|
||||
|
@ -241,38 +250,26 @@ export default {
|
|||
listenGoBack(this.handleClose);
|
||||
if (row) {
|
||||
this.title = this.$t('project.edit');
|
||||
row.issueConfigObj = row.issueConfig ? JSON.parse(row.issueConfig) : {
|
||||
jiraIssueTypeId: null,
|
||||
jiraStoryTypeId: null
|
||||
};
|
||||
// 兼容性处理
|
||||
if (!row.issueConfigObj.jiraIssueTypeId) {
|
||||
row.issueConfigObj.jiraIssueTypeId = null;
|
||||
}
|
||||
if (!row.issueConfigObj.jiraStoryTypeId) {
|
||||
row.issueConfigObj.jiraStoryTypeId = null;
|
||||
}
|
||||
this.platformConfig = row.issueConfig ? JSON.parse(row.issueConfig) : {};
|
||||
this.form = Object.assign({}, row);
|
||||
this.issueTemplateId = row.issueTemplateId;
|
||||
} else {
|
||||
this.form = {issueConfigObj: {jiraIssueTypeId: null, jiraStoryTypeId: null}};
|
||||
}
|
||||
if (this.$refs.jiraConfig) {
|
||||
this.$refs.jiraConfig.getIssueTypeOption(this.form);
|
||||
}
|
||||
this.platformOptions = [];
|
||||
this.platformOptions.push(...ISSUE_PLATFORM_OPTION);
|
||||
this.loading = getAllServiceIntegration().then(res => {
|
||||
let data = res.data;
|
||||
let platforms = data.map(d => d.platform);
|
||||
this.filterPlatformOptions(platforms, TAPD);
|
||||
this.filterPlatformOptions(platforms, JIRA);
|
||||
this.filterPlatformOptions(platforms, ZEN_TAO);
|
||||
this.filterPlatformOptions(platforms, AZURE_DEVOPS);
|
||||
this.issueOptions = this.platformOptions;
|
||||
}).catch(() => {
|
||||
this.ableEdit = false;
|
||||
})
|
||||
|
||||
getPlatformOption()
|
||||
.then((r) => {
|
||||
this.platformOptions = [];
|
||||
this.platformOptions.push(...r.data);
|
||||
this.platformOptions.push(...ISSUE_PLATFORM_OPTION);
|
||||
this.loading = getAllServiceIntegration().then(res => {
|
||||
let data = res.data;
|
||||
let platforms = data.map(d => d.platform);
|
||||
this.filterPlatformOptions(platforms, TAPD);
|
||||
this.filterPlatformOptions(platforms, ZEN_TAO);
|
||||
this.filterPlatformOptions(platforms, AZURE_DEVOPS);
|
||||
}).catch(() => {
|
||||
this.ableEdit = false;
|
||||
})
|
||||
});
|
||||
},
|
||||
filterPlatformOptions(platforms, platform) {
|
||||
if (platforms.indexOf(platform) === -1) {
|
||||
|
@ -289,24 +286,34 @@ export default {
|
|||
if (!valid || !this.ableEdit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let protocol = document.location.protocol;
|
||||
protocol = protocol.substring(0, protocol.indexOf(":"));
|
||||
this.form.protocal = protocol;
|
||||
this.form.workspaceId = getCurrentWorkspaceId();
|
||||
this.form.createUser = getCurrentUserId();
|
||||
this.form.issueConfig = JSON.stringify(this.form.issueConfigObj);
|
||||
if (this.issueTemplateId !== this.form.issueTemplateId) {
|
||||
// 更换缺陷模版移除字段
|
||||
localStorage.removeItem("ISSUE_LIST");
|
||||
let projectConfig = this.$refs.platformConfig;
|
||||
if (projectConfig) {
|
||||
projectConfig.validate()
|
||||
.then(() => {
|
||||
this.form.issueConfig = JSON.stringify(projectConfig.form);
|
||||
this.handleSave()
|
||||
});
|
||||
} else {
|
||||
this.handleSave();
|
||||
}
|
||||
});
|
||||
},
|
||||
handleSave() {
|
||||
let protocol = document.location.protocol;
|
||||
protocol = protocol.substring(0, protocol.indexOf(":"));
|
||||
this.form.protocal = protocol;
|
||||
this.form.workspaceId = getCurrentWorkspaceId();
|
||||
this.form.createUser = getCurrentUserId();
|
||||
if (this.issueTemplateId !== this.form.issueTemplateId) {
|
||||
// 更换缺陷模版移除字段
|
||||
localStorage.removeItem("ISSUE_LIST");
|
||||
}
|
||||
|
||||
let promise = this.form.id ? modifyProject(this.form) : saveProject(this.form);
|
||||
this.loading = promise.then(() => {
|
||||
this.createVisible = false;
|
||||
this.reload();
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
});
|
||||
let promise = this.form.id ? modifyProject(this.form) : saveProject(this.form);
|
||||
this.loading = promise.then(() => {
|
||||
this.createVisible = false;
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.reload();
|
||||
});
|
||||
},
|
||||
handleDelete(project) {
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-form :model="form" ref="form" label-width="100px" size="small" :rules="rules">
|
||||
<el-form-item
|
||||
:label-width="labelWidth"
|
||||
v-for="item in config.formItems"
|
||||
:key="item.name"
|
||||
:label="item.i18n ? $t(item.label) : item.label"
|
||||
:prop="item.name">
|
||||
<custom-filed-component :form="form"
|
||||
:data="item"
|
||||
class="custom-filed"
|
||||
prop="defaultValue"
|
||||
@change="handleChange"/>
|
||||
<el-button v-if="item.withProjectCheck"
|
||||
:disabled="!form[item.name]"
|
||||
@click="check"
|
||||
type="primary"
|
||||
class="checkButton">
|
||||
{{ $t('test_track.issue.check_id_exist') }}
|
||||
</el-button>
|
||||
<ms-instructions-icon v-if="item.instructionsIcon" effect="light">
|
||||
<template>
|
||||
<img class="jira-image"
|
||||
:src="'/platform/plugin/resource/' + config.id + '?fileName=' + item.instructionsIcon"/>
|
||||
</template>
|
||||
</ms-instructions-icon>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
|
||||
import {getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
|
||||
import {
|
||||
getPlatformProjectInfo,
|
||||
getPlatformProjectOption,
|
||||
validateProjectConfig,
|
||||
} from "@/api/platform-plugin";
|
||||
import CustomFiledComponent from "metersphere-frontend/src/components/template/CustomFiledComponent";
|
||||
import {getPlatformFormRules} from "@/business/home/platform";
|
||||
|
||||
export default {
|
||||
name: "ProjectPlatformConfig",
|
||||
components: {MsInstructionsIcon, CustomFiledComponent},
|
||||
props: {
|
||||
labelWidth: String,
|
||||
result: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
platformKey: String,
|
||||
projectConfig: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
issueTypes: [],
|
||||
form: {},
|
||||
rules: {},
|
||||
config: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
platformKey() {
|
||||
this.getPlatformProjectInfo();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getPlatformProjectInfo();
|
||||
},
|
||||
methods: {
|
||||
getPlatformProjectInfo() {
|
||||
getPlatformProjectInfo(this.platformKey)
|
||||
.then(r => {
|
||||
if (r.data) {
|
||||
Object.assign(this.form, this.projectConfig);
|
||||
r.data.formItems.forEach(item => {
|
||||
if (!item.options) {
|
||||
item.options = [];
|
||||
}
|
||||
// 设置默认值
|
||||
if (this.form[item.name]) {
|
||||
this.$set(item, 'defaultValue', this.form[item.name]);
|
||||
}
|
||||
// 获取级联选项值
|
||||
if (item.cascade && this.form[item.name]) {
|
||||
this.getCascadeOptions(item, () => {
|
||||
// 没有选项值会被组件自动清空,获取下拉框选项之后,重新设置默认值
|
||||
if (this.form[item.name]) {
|
||||
this.$set(item, 'defaultValue', this.form[item.name]);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
this.config = r.data;
|
||||
this.rules = getPlatformFormRules(this.config);
|
||||
}
|
||||
});
|
||||
},
|
||||
check() {
|
||||
validateProjectConfig(this.config.id, this.form)
|
||||
.then(() => {
|
||||
this.$success(this.$t("system.check_third_project_success"));
|
||||
});
|
||||
},
|
||||
validate() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$refs['form'].validate((valid) => {
|
||||
if (!valid) {
|
||||
reject();
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
handleChange(name) {
|
||||
this.config.formItems.forEach(item => {
|
||||
if (item.cascade === name) {
|
||||
this.$set(item, 'options', []);
|
||||
this.getCascadeOptions(item);
|
||||
}
|
||||
});
|
||||
},
|
||||
getCascadeOptions(item, callback) {
|
||||
getPlatformProjectOption(this.config.id, {
|
||||
platform: this.platformKey,
|
||||
optionMethod: item.optionMethod,
|
||||
workspaceId: getCurrentWorkspaceId(),
|
||||
projectConfig: JSON.stringify(this.form)
|
||||
}).then((r) => {
|
||||
this.$set(item, 'options', r.data);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.custom-filed :deep(.el-select) {
|
||||
width: 260px !important;
|
||||
}
|
||||
|
||||
.custom-filed :deep(.el-input, .el-textarea) {
|
||||
width: 80% !important;
|
||||
}
|
||||
|
||||
.checkButton {
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,15 @@
|
|||
import i18n from "@/i18n";
|
||||
|
||||
export function getPlatformFormRules(config) {
|
||||
let rules = {};
|
||||
if (config && config.formItems) {
|
||||
config.formItems.forEach(item => {
|
||||
rules[item.name] = {
|
||||
required: item.required,
|
||||
message: item.i18n ? i18n.t(item.message) : item.message,
|
||||
trigger: ['change', 'blur']
|
||||
}
|
||||
});
|
||||
}
|
||||
return rules;
|
||||
}
|
|
@ -1,12 +1,14 @@
|
|||
package io.metersphere.controller;
|
||||
|
||||
import io.metersphere.domain.SelectOption;
|
||||
import io.metersphere.dto.PlatformProjectOptionRequest;
|
||||
import io.metersphere.service.PlatformPluginService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@RestController
|
||||
|
@ -21,8 +23,37 @@ public class PlatformPluginController {
|
|||
return platformPluginService.getIntegrationInfo();
|
||||
}
|
||||
|
||||
@GetMapping("/project/info/{key}")
|
||||
public Object getProjectInfo(@PathVariable("key") String key) {
|
||||
return platformPluginService.getProjectInfo(key);
|
||||
}
|
||||
|
||||
@GetMapping("/resource/{pluginId}")
|
||||
public void getPluginResource(@PathVariable("pluginId") String pluginId, @RequestParam("fileName") String fileName, HttpServletResponse response) {
|
||||
platformPluginService.getPluginResource(pluginId, fileName, response);
|
||||
}
|
||||
|
||||
@PostMapping("/integration/validate/{pluginId}")
|
||||
public void validateIntegration(@PathVariable("pluginId") String pluginId, @RequestBody Map config) {
|
||||
platformPluginService.validateIntegration(pluginId, config);
|
||||
}
|
||||
@PostMapping("/project/validate/{pluginId}")
|
||||
public void validateProjectConfig(@PathVariable("pluginId") String pluginId, @RequestBody Map config) {
|
||||
platformPluginService.validateProjectConfig(pluginId, config);
|
||||
}
|
||||
|
||||
@PostMapping("/project/option")
|
||||
public List<SelectOption> getProjectOption(@RequestBody PlatformProjectOptionRequest request) {
|
||||
return platformPluginService.getProjectOption(request);
|
||||
}
|
||||
|
||||
@GetMapping("/platform/option")
|
||||
public List<SelectOption> getPlatformOptions() {
|
||||
return platformPluginService.getPlatformOptions();
|
||||
}
|
||||
|
||||
@GetMapping("/template/support/list")
|
||||
public List<String> getThirdPartTemplateSupportPlatform() {
|
||||
return platformPluginService.getThirdPartTemplateSupportPlatform();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package io.metersphere.controller;
|
|||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.base.domain.FileMetadata;
|
||||
import io.metersphere.base.domain.Project;
|
||||
import io.metersphere.commons.constants.MicroServiceName;
|
||||
import io.metersphere.commons.constants.OperLogConstants;
|
||||
|
@ -17,14 +16,13 @@ import io.metersphere.dto.WorkspaceMemberDTO;
|
|||
import io.metersphere.log.annotation.MsAuditLog;
|
||||
import io.metersphere.request.AddProjectRequest;
|
||||
import io.metersphere.request.ProjectRequest;
|
||||
import io.metersphere.service.BaseProjectService;
|
||||
import io.metersphere.service.BaseCheckPermissionService;
|
||||
import io.metersphere.service.BaseProjectService;
|
||||
import io.metersphere.service.MicroService;
|
||||
import io.metersphere.service.SystemProjectService;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -131,9 +129,4 @@ public class SystemProjectController {
|
|||
public void checkThirdProjectExist(@RequestBody Project project) {
|
||||
microService.postForData(MicroServiceName.TEST_TRACK, "/issues/check/third/project", project);
|
||||
}
|
||||
|
||||
@PostMapping("/issues/jira/issuetype")
|
||||
public Object getJiraIssueType(@RequestBody Object request) {
|
||||
return microService.postForData(MicroServiceName.TEST_TRACK, "/issues/jira/issuetype", request);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package io.metersphere.dto;
|
||||
|
||||
import io.metersphere.request.IntegrationRequest;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PlatformProjectOptionRequest extends IntegrationRequest {
|
||||
private String optionMethod;
|
||||
private String projectConfig;
|
||||
}
|
|
@ -1,14 +1,23 @@
|
|||
package io.metersphere.service;
|
||||
|
||||
import im.metersphere.loader.PluginManager;
|
||||
import io.metersphere.api.Platform;
|
||||
import io.metersphere.api.PluginMetaInfo;
|
||||
import io.metersphere.base.domain.PluginWithBLOBs;
|
||||
import io.metersphere.base.domain.ServiceIntegration;
|
||||
import io.metersphere.base.mapper.PluginMapper;
|
||||
import io.metersphere.commons.constants.PluginScenario;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.commons.utils.JSON;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.domain.GetOptionRequest;
|
||||
import io.metersphere.domain.PlatformRequest;
|
||||
import io.metersphere.domain.SelectOption;
|
||||
import io.metersphere.dto.PlatformProjectOptionRequest;
|
||||
import io.metersphere.loader.PlatformPluginManager;
|
||||
import io.metersphere.request.IntegrationRequest;
|
||||
import io.metersphere.utils.PluginManagerUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
@ -22,6 +31,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
@ -31,12 +41,14 @@ public class PlatformPluginService {
|
|||
private BasePluginService basePluginService;
|
||||
@Resource
|
||||
private PluginMapper pluginMapper;
|
||||
@Resource
|
||||
private BaseIntegrationService baseIntegrationService;
|
||||
|
||||
private PluginManager pluginManager;
|
||||
private PlatformPluginManager pluginManager;
|
||||
|
||||
public PluginWithBLOBs addPlatformPlugin(MultipartFile file) {
|
||||
if (pluginManager != null) {
|
||||
pluginManager = new PluginManager();
|
||||
pluginManager = new PlatformPluginManager();
|
||||
}
|
||||
String id = UUID.randomUUID().toString();
|
||||
|
||||
|
@ -51,7 +63,7 @@ public class PlatformPluginService {
|
|||
plugin.setId(id);
|
||||
plugin.setName(file.getOriginalFilename());
|
||||
plugin.setPluginId(pluginMetaInfo.getKey() + "-" + pluginMetaInfo.getVersion());
|
||||
plugin.setScriptId(plugin.getPluginId());
|
||||
plugin.setScriptId(pluginMetaInfo.getKey());
|
||||
plugin.setSourcePath("");
|
||||
// plugin.setFormOption(item.getFormOption());
|
||||
plugin.setFormScript(JSON.toJSONString(map));
|
||||
|
@ -69,7 +81,7 @@ public class PlatformPluginService {
|
|||
* 查询所有平台插件并加载
|
||||
*/
|
||||
public void loadPlatFormPlugins() {
|
||||
pluginManager = new PluginManager();
|
||||
pluginManager = new PlatformPluginManager();
|
||||
List<PluginWithBLOBs> plugins = basePluginService.getPlugins(PluginScenario.platform.name());
|
||||
PluginManagerUtil.loadPlugins(pluginManager, plugins);
|
||||
}
|
||||
|
@ -83,19 +95,51 @@ public class PlatformPluginService {
|
|||
public Object getIntegrationInfo() {
|
||||
List<PluginWithBLOBs> plugins = basePluginService.getPlugins(PluginScenario.platform.name());
|
||||
List<Map> configs = new ArrayList<>();
|
||||
plugins.forEach(item ->{
|
||||
Map metaData = JSON.parseMap(item.getFormScript());
|
||||
Map serviceIntegration = (Map) metaData.get("serviceIntegration");
|
||||
serviceIntegration.put("id", metaData.get("id"));
|
||||
serviceIntegration.put("key", metaData.get("key"));
|
||||
configs.add(serviceIntegration);
|
||||
});
|
||||
plugins.forEach(item -> configs.add(getFrontendMetaDataConfig(item, "serviceIntegration")));
|
||||
return configs;
|
||||
}
|
||||
|
||||
public Map getProjectInfo(String key) {
|
||||
List<PluginWithBLOBs> plugins = basePluginService.getPlugins(PluginScenario.platform.name());
|
||||
for (PluginWithBLOBs plugin : plugins) {
|
||||
if (StringUtils.equals(plugin.getScriptId(), key)) {
|
||||
return getFrontendMetaDataConfig(plugin, "projectConfig");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<SelectOption> getProjectOption(PlatformProjectOptionRequest request) {
|
||||
IntegrationRequest integrationRequest = new IntegrationRequest();
|
||||
BeanUtils.copyBean(integrationRequest, request);
|
||||
ServiceIntegration serviceIntegration = baseIntegrationService.get(integrationRequest);
|
||||
|
||||
PlatformRequest platformRequest = new PlatformRequest();
|
||||
platformRequest.setIntegrationConfig(serviceIntegration.getConfiguration());
|
||||
|
||||
Platform platform = pluginManager.getPlatformByKey(request.getPlatform(), platformRequest);
|
||||
GetOptionRequest getOptionRequest = new GetOptionRequest();
|
||||
getOptionRequest.setOptionMethod(request.getOptionMethod());
|
||||
getOptionRequest.setProjectConfig(request.getProjectConfig());
|
||||
try {
|
||||
return platform.getProjectOptions(getOptionRequest);
|
||||
} catch (Exception e) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Map getFrontendMetaDataConfig(PluginWithBLOBs plugin, String configName) {
|
||||
Map metaData = JSON.parseMap(plugin.getFormScript());
|
||||
Map serviceIntegration = (Map) metaData.get(configName);
|
||||
serviceIntegration.put("id", metaData.get("id"));
|
||||
serviceIntegration.put("key", metaData.get("key"));
|
||||
return serviceIntegration;
|
||||
}
|
||||
|
||||
public void getImage(InputStream in, HttpServletResponse response) {
|
||||
response.setContentType("image/png");
|
||||
try(OutputStream out = response.getOutputStream()) {
|
||||
try (OutputStream out = response.getOutputStream()) {
|
||||
out.write(in.readAllBytes());
|
||||
out.flush();
|
||||
} catch (Exception e) {
|
||||
|
@ -118,4 +162,54 @@ public class PlatformPluginService {
|
|||
LogUtil.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Platform getPlatFormInstance(String pluginId, Map IntegrationConfig) {
|
||||
PlatformRequest request = new PlatformRequest();
|
||||
request.setIntegrationConfig(JSON.toJSONString(IntegrationConfig));
|
||||
return pluginManager.getPlatform(pluginId, request);
|
||||
}
|
||||
|
||||
public Platform getPlatFormInstance(String pluginId, String integrationConfig) {
|
||||
PlatformRequest request = new PlatformRequest();
|
||||
request.setIntegrationConfig(integrationConfig);
|
||||
return pluginManager.getPlatform(pluginId, request);
|
||||
}
|
||||
|
||||
public void validateIntegration(String pluginId, Map integrationConfig) {
|
||||
Platform platform = getPlatFormInstance(pluginId, integrationConfig);
|
||||
platform.validateIntegrationConfig();
|
||||
}
|
||||
|
||||
public void validateProjectConfig(String pluginId, Map projectConfig) {
|
||||
PluginMetaInfo pluginMetaInfo = pluginManager.getPluginMetaInfo(pluginId);
|
||||
IntegrationRequest integrationRequest = new IntegrationRequest();
|
||||
integrationRequest.setPlatform(pluginMetaInfo.getKey());
|
||||
integrationRequest.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
||||
ServiceIntegration serviceIntegration = baseIntegrationService.get(integrationRequest);
|
||||
Platform platform = getPlatFormInstance(pluginId, serviceIntegration.getConfiguration());
|
||||
platform.validateProjectConfig(JSON.toJSONString(projectConfig));
|
||||
}
|
||||
|
||||
public List<SelectOption> getPlatformOptions() {
|
||||
List<SelectOption> options = pluginManager.getPluginMetaInfoList()
|
||||
.stream()
|
||||
.map(pluginMetaInfo -> new SelectOption(pluginMetaInfo.getLabel(), pluginMetaInfo.getKey()))
|
||||
.collect(Collectors.toList());
|
||||
List<ServiceIntegration> integrations = baseIntegrationService.getAll(SessionUtils.getCurrentWorkspaceId());
|
||||
// 过滤掉服务集成中没有的选项
|
||||
return options.stream()
|
||||
.filter(option ->
|
||||
integrations.stream()
|
||||
.filter(integration -> StringUtils.equals(integration.getPlatform(), option.getValue()))
|
||||
.collect(Collectors.toList()).size() > 0
|
||||
).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<String> getThirdPartTemplateSupportPlatform() {
|
||||
List<PluginMetaInfo> pluginMetaInfoList = pluginManager.getPluginMetaInfoList();
|
||||
return pluginMetaInfoList.stream()
|
||||
.filter(PluginMetaInfo::isThirdPartTemplateSupport)
|
||||
.map(PluginMetaInfo::getKey)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,3 +4,27 @@ const BASE_URL = "/platform/plugin/";
|
|||
export function getIntegrationInfo() {
|
||||
return get(BASE_URL + 'integration/info');
|
||||
}
|
||||
|
||||
export function getPlatformProjectInfo(key) {
|
||||
return key ? get(BASE_URL + `project/info/${key}`) : new Promise(r => r({}));
|
||||
}
|
||||
|
||||
export function validateServiceIntegration(pluginId, config) {
|
||||
return post(BASE_URL + `integration/validate/${pluginId}`, config);
|
||||
}
|
||||
|
||||
export function validateProjectConfig(pluginId, config) {
|
||||
return post(BASE_URL + `project/validate/${pluginId}`, config);
|
||||
}
|
||||
|
||||
export function getPlatformProjectOption(pluginId, request) {
|
||||
return post(BASE_URL + 'project/option', request);
|
||||
}
|
||||
|
||||
export function getPlatformOption() {
|
||||
return get(BASE_URL + 'platform/option');
|
||||
}
|
||||
|
||||
export function getThirdPartTemplateSupportPlatform() {
|
||||
return get(BASE_URL + 'template/support/list');
|
||||
}
|
||||
|
|
|
@ -46,11 +46,6 @@ export function getAllServiceIntegration() {
|
|||
return get('/service/integration/all');
|
||||
}
|
||||
|
||||
|
||||
export function getJiraIssueType(param) {
|
||||
return post('/project/issues/jira/issuetype', param);
|
||||
}
|
||||
|
||||
export function getFieldTemplateCaseOption(projectId) {
|
||||
return get(`/project/field/template/case/option/${projectId}`);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ export default {
|
|||
platform: TAPD,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
activated() {
|
||||
this.platformConfigs = [];
|
||||
|
||||
getIntegrationInfo()
|
||||
|
@ -62,7 +62,6 @@ export default {
|
|||
});
|
||||
|
||||
this.platform = TAPD;
|
||||
this.platformConfigs[0].key;
|
||||
},
|
||||
computed: {
|
||||
tapdEnable() {
|
||||
|
|
|
@ -56,17 +56,17 @@
|
|||
|
||||
<script>
|
||||
import BugManageBtn from "./BugManageBtn";
|
||||
import {getCurrentUser, getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
|
||||
import {JIRA} from "metersphere-frontend/src/utils/constants";
|
||||
import {getCurrentUser} from "metersphere-frontend/src/utils/token";
|
||||
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
|
||||
import MsPersonRouter from "metersphere-frontend/src/components/personal/PersonRouter";
|
||||
import CustomFiledComponent from "metersphere-frontend/src/components/template/CustomFiledComponent";
|
||||
import {
|
||||
authServiceIntegration,
|
||||
delServiceIntegration,
|
||||
getServiceIntegration,
|
||||
saveServiceIntegration
|
||||
} from "../../../api/workspace";
|
||||
import {validateServiceIntegration} from "@/api/platform-plugin";
|
||||
import {getPlatformFormRules} from "@/business/workspace/integration/platform";
|
||||
|
||||
export default {
|
||||
name: "PlatformConfig",
|
||||
|
@ -93,19 +93,11 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
init() {
|
||||
let rules = {};
|
||||
this.config.formItems.forEach(item => {
|
||||
rules[item.name] = {
|
||||
required: item.required,
|
||||
message: item.i18n ? this.$t(item.message) : item.message,
|
||||
trigger: ['change', 'blur']
|
||||
}
|
||||
});
|
||||
this.rules = rules;
|
||||
this.rules = getPlatformFormRules(this.config);
|
||||
|
||||
const {lastWorkspaceId} = getCurrentUser();
|
||||
let param = {};
|
||||
param.platform = JIRA;
|
||||
param.platform = this.config.key;
|
||||
param.workspaceId = lastWorkspaceId;
|
||||
this.$parent.loading = getServiceIntegration(param).then(res => {
|
||||
let data = res.data;
|
||||
|
@ -116,7 +108,7 @@ export default {
|
|||
this.form = form;
|
||||
// 设置默认值
|
||||
this.config.formItems.forEach(item => {
|
||||
item.defaultValue = this.form[item.name];
|
||||
this.$set(item, 'defaultValue', this.form[item.name]);
|
||||
});
|
||||
} else {
|
||||
this.clear();
|
||||
|
@ -156,36 +148,30 @@ export default {
|
|||
});
|
||||
},
|
||||
testConnection() {
|
||||
if (this.form.account && this.form.password) {
|
||||
// todo 插件改造
|
||||
this.$parent.loading = authServiceIntegration(getCurrentWorkspaceId(), JIRA).then(() => {
|
||||
this.$success(this.$t('organization.integration.verified'));
|
||||
});
|
||||
} else {
|
||||
this.$warning(this.$t('organization.integration.not_integrated'));
|
||||
return false;
|
||||
}
|
||||
this.$refs['form'].validate(valid => {
|
||||
if (valid) {
|
||||
this.$parent.loading = validateServiceIntegration(this.config.id, this.form).then(() => {
|
||||
this.$success(this.$t('organization.integration.verified'));
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
cancelIntegration() {
|
||||
if (this.form.account && this.form.password) {
|
||||
this.$alert(this.$t('organization.integration.cancel_confirm') + JIRA + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
const {lastWorkspaceId} = getCurrentUser();
|
||||
let param = {};
|
||||
param.workspaceId = lastWorkspaceId;
|
||||
param.platform = this.config.key;
|
||||
this.$parent.loading = delServiceIntegration(param).then(() => {
|
||||
this.$success(this.$t('organization.integration.successful_operation'));
|
||||
this.init('');
|
||||
});
|
||||
}
|
||||
this.$alert(this.$t('organization.integration.cancel_confirm') + this.config.key + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
const {lastWorkspaceId} = getCurrentUser();
|
||||
let param = {};
|
||||
param.workspaceId = lastWorkspaceId;
|
||||
param.platform = this.config.key;
|
||||
this.$parent.loading = delServiceIntegration(param).then(() => {
|
||||
this.$success(this.$t('organization.integration.successful_operation'));
|
||||
this.init('');
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$warning(this.$t('organization.integration.not_integrated'));
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
reloadPassInput() {
|
||||
this.showInput = false;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import i18n from "@/i18n";
|
||||
|
||||
export function getPlatformFormRules(config) {
|
||||
let rules = {};
|
||||
if (config && config.formItems) {
|
||||
config.formItems.forEach(item => {
|
||||
rules[item.name] = {
|
||||
required: item.required,
|
||||
message: item.i18n ? i18n.t(item.message) : item.message,
|
||||
trigger: ['change', 'blur']
|
||||
}
|
||||
});
|
||||
}
|
||||
return rules;
|
||||
}
|
|
@ -26,10 +26,10 @@
|
|||
:label="$t('workspace.issue_template_manage')" prop="issueTemplateId">
|
||||
<template-select :platform="form.platform" :data="form" scene="ISSUE" prop="issueTemplateId"
|
||||
:disabled="form.platform === 'Jira' && form.thirdPartTemplate"
|
||||
:platformOptions="issueOptions" :project-id="form.id"
|
||||
:platformOptions="platformOptions" :project-id="form.id"
|
||||
ref="issueTemplate"/>
|
||||
|
||||
<el-checkbox @change="thirdPartTemplateChange" v-if="form.platform === 'Jira'"
|
||||
<el-checkbox @change="thirdPartTemplateChange" v-if="form.platform === 'Jira' && thirdPartTemplateSupport"
|
||||
v-model="form.thirdPartTemplate" style="margin-left: 10px">
|
||||
{{ $t('test_track.issue.use_third_party') }}
|
||||
</el-checkbox>
|
||||
|
@ -51,13 +51,15 @@
|
|||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<project-jira-config :result="jiraResult" v-if="jira" :label-width="labelWidth" :form="form" ref="jiraConfig">
|
||||
<template #checkBtn>
|
||||
<el-button @click="check" type="primary" class="checkButton">
|
||||
{{ $t('test_track.issue.check_id_exist') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</project-jira-config>
|
||||
<project-platform-config
|
||||
v-if="form.platform === 'Jira'"
|
||||
:result="jiraResult"
|
||||
:platform-key="form.platform"
|
||||
:label-width="labelWidth"
|
||||
:project-config="platformConfig"
|
||||
ref="platformConfig"
|
||||
/>
|
||||
|
||||
<el-form-item :label-width="labelWidth" :label="$t('project.zentao_id')" v-if="zentao">
|
||||
<el-input v-model="form.zentaoId" autocomplete="off"></el-input>
|
||||
<el-button @click="check" type="primary" class="checkButton">
|
||||
|
@ -103,7 +105,7 @@ import {
|
|||
getCurrentUserId,
|
||||
getCurrentWorkspaceId
|
||||
} from "metersphere-frontend/src/utils/token";
|
||||
import {AZURE_DEVOPS, JIRA, PROJECT_ID, TAPD, ZEN_TAO} from "metersphere-frontend/src/utils/constants";
|
||||
import {AZURE_DEVOPS, PROJECT_ID, TAPD, ZEN_TAO} from "metersphere-frontend/src/utils/constants";
|
||||
import {PROJECT_CONFIGS} from "metersphere-frontend/src/components/search/search-components";
|
||||
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
|
||||
import TemplateSelect from "./TemplateSelect";
|
||||
|
@ -115,7 +117,6 @@ import MsTablePagination from "metersphere-frontend/src/components/pagination/Ta
|
|||
import MsTableHeader from "metersphere-frontend/src/components/MsTableHeader";
|
||||
import MsDialogFooter from "metersphere-frontend/src/components/MsDialogFooter";
|
||||
import {ISSUE_PLATFORM_OPTION} from "metersphere-frontend/src/utils/table-constants";
|
||||
import ProjectJiraConfig from "./ProjectJiraConfig";
|
||||
import {
|
||||
getAllServiceIntegration,
|
||||
checkThirdPlatformProject,
|
||||
|
@ -124,11 +125,13 @@ import {
|
|||
saveProject
|
||||
} from "../../../api/project";
|
||||
import {updateInfo} from "metersphere-frontend/src/api/user";
|
||||
import {getPlatformOption, getPlatformProjectInfo, getThirdPartTemplateSupportPlatform} from "@/api/platform-plugin";
|
||||
import ProjectPlatformConfig from "@/business/workspace/project/ProjectPlatformConfig";
|
||||
|
||||
export default {
|
||||
name: "EditProject",
|
||||
components: {
|
||||
ProjectJiraConfig,
|
||||
ProjectPlatformConfig,
|
||||
MsInstructionsIcon,
|
||||
TemplateSelect,
|
||||
MsTableButton,
|
||||
|
@ -148,6 +151,7 @@ export default {
|
|||
jiraResult: {
|
||||
loading: false
|
||||
},
|
||||
platformProjectConfigs: [],
|
||||
btnTips: this.$t('project.create'),
|
||||
title: this.$t('project.create'),
|
||||
condition: {components: PROJECT_CONFIGS},
|
||||
|
@ -167,9 +171,10 @@ export default {
|
|||
],
|
||||
},
|
||||
platformOptions: [],
|
||||
issueOptions: [],
|
||||
issueTemplateId: "",
|
||||
ableEdit: true,
|
||||
platformConfig: {},
|
||||
thirdPartTemplateSupportPlatforms: []
|
||||
};
|
||||
},
|
||||
props: {
|
||||
|
@ -188,15 +193,15 @@ export default {
|
|||
tapd() {
|
||||
return this.showPlatform(TAPD);
|
||||
},
|
||||
jira() {
|
||||
return this.showPlatform(JIRA);
|
||||
},
|
||||
zentao() {
|
||||
return this.showPlatform(ZEN_TAO);
|
||||
},
|
||||
azuredevops() {
|
||||
return this.showPlatform(AZURE_DEVOPS);
|
||||
},
|
||||
thirdPartTemplateSupport() {
|
||||
return this.thirdPartTemplateSupportPlatforms.indexOf(this.form.platform) > -1;
|
||||
}
|
||||
},
|
||||
inject: ['reload'],
|
||||
destroyed() {
|
||||
|
@ -226,6 +231,10 @@ export default {
|
|||
if (this.$refs.apiTemplate) {
|
||||
this.$refs.apiTemplate.getTemplateOptions();
|
||||
}
|
||||
getThirdPartTemplateSupportPlatform()
|
||||
.then((r) => {
|
||||
this.thirdPartTemplateSupportPlatforms = r.data;
|
||||
});
|
||||
},
|
||||
thirdPartTemplateChange(val) {
|
||||
if (val)
|
||||
|
@ -237,38 +246,32 @@ export default {
|
|||
listenGoBack(this.handleClose);
|
||||
if (row) {
|
||||
this.title = this.$t('project.edit');
|
||||
row.issueConfigObj = row.issueConfig ? JSON.parse(row.issueConfig) : {
|
||||
jiraIssueTypeId: null,
|
||||
jiraStoryTypeId: null
|
||||
};
|
||||
// 兼容性处理
|
||||
if (!row.issueConfigObj.jiraIssueTypeId) {
|
||||
row.issueConfigObj.jiraIssueTypeId = null;
|
||||
}
|
||||
if (!row.issueConfigObj.jiraStoryTypeId) {
|
||||
row.issueConfigObj.jiraStoryTypeId = null;
|
||||
}
|
||||
this.platformConfig = row.issueConfig ? JSON.parse(row.issueConfig) : {};
|
||||
this.form = Object.assign({}, row);
|
||||
this.issueTemplateId = row.issueTemplateId;
|
||||
} else {
|
||||
this.form = {issueConfigObj: {jiraIssueTypeId: null, jiraStoryTypeId: null}};
|
||||
}
|
||||
if (this.$refs.jiraConfig) {
|
||||
this.$refs.jiraConfig.getIssueTypeOption(this.form);
|
||||
}
|
||||
this.platformOptions = [];
|
||||
this.platformOptions.push(...ISSUE_PLATFORM_OPTION);
|
||||
this.loading = getAllServiceIntegration().then(res => {
|
||||
let data = res.data;
|
||||
let platforms = data.map(d => d.platform);
|
||||
this.filterPlatformOptions(platforms, TAPD);
|
||||
this.filterPlatformOptions(platforms, JIRA);
|
||||
this.filterPlatformOptions(platforms, ZEN_TAO);
|
||||
this.filterPlatformOptions(platforms, AZURE_DEVOPS);
|
||||
this.issueOptions = this.platformOptions;
|
||||
}).catch(() => {
|
||||
this.ableEdit = false;
|
||||
})
|
||||
|
||||
getPlatformOption()
|
||||
.then((r) => {
|
||||
this.platformOptions = [];
|
||||
this.platformOptions.push(...r.data);
|
||||
this.platformOptions.push(...ISSUE_PLATFORM_OPTION);
|
||||
this.loading = getAllServiceIntegration().then(res => {
|
||||
let data = res.data;
|
||||
let platforms = data.map(d => d.platform);
|
||||
this.filterPlatformOptions(platforms, TAPD);
|
||||
this.filterPlatformOptions(platforms, ZEN_TAO);
|
||||
this.filterPlatformOptions(platforms, AZURE_DEVOPS);
|
||||
}).catch(() => {
|
||||
this.ableEdit = false;
|
||||
})
|
||||
});
|
||||
},
|
||||
getPlatformProjectInfo() {
|
||||
getPlatformProjectInfo()
|
||||
.then((r) => {
|
||||
this.platformProjectConfigs = r.data;
|
||||
});
|
||||
},
|
||||
filterPlatformOptions(platforms, platform) {
|
||||
if (platforms.indexOf(platform) === -1) {
|
||||
|
@ -285,24 +288,34 @@ export default {
|
|||
if (!valid || !this.ableEdit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let protocol = document.location.protocol;
|
||||
protocol = protocol.substring(0, protocol.indexOf(":"));
|
||||
this.form.protocal = protocol;
|
||||
this.form.workspaceId = getCurrentWorkspaceId();
|
||||
this.form.createUser = getCurrentUserId();
|
||||
this.form.issueConfig = JSON.stringify(this.form.issueConfigObj);
|
||||
if (this.issueTemplateId !== this.form.issueTemplateId) {
|
||||
// 更换缺陷模版移除字段
|
||||
localStorage.removeItem("ISSUE_LIST");
|
||||
let projectConfig = this.$refs.platformConfig;
|
||||
if (projectConfig) {
|
||||
projectConfig.validate()
|
||||
.then(() => {
|
||||
this.form.issueConfig = JSON.stringify(projectConfig.form);
|
||||
this.handleSave()
|
||||
});
|
||||
} else {
|
||||
this.handleSave();
|
||||
}
|
||||
});
|
||||
},
|
||||
handleSave() {
|
||||
let protocol = document.location.protocol;
|
||||
protocol = protocol.substring(0, protocol.indexOf(":"));
|
||||
this.form.protocal = protocol;
|
||||
this.form.workspaceId = getCurrentWorkspaceId();
|
||||
this.form.createUser = getCurrentUserId();
|
||||
if (this.issueTemplateId !== this.form.issueTemplateId) {
|
||||
// 更换缺陷模版移除字段
|
||||
localStorage.removeItem("ISSUE_LIST");
|
||||
}
|
||||
|
||||
let promise = this.form.id ? modifyProject(this.form) : saveProject(this.form);
|
||||
this.loading = promise.then(() => {
|
||||
this.createVisible = false;
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.reload();
|
||||
});
|
||||
let promise = this.form.id ? modifyProject(this.form) : saveProject(this.form);
|
||||
this.loading = promise.then(() => {
|
||||
this.createVisible = false;
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.reload();
|
||||
});
|
||||
},
|
||||
handleDelete(project) {
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-form :model="form" ref="form" label-width="100px" size="small" :rules="rules">
|
||||
<el-form-item
|
||||
:label-width="labelWidth"
|
||||
v-for="item in config.formItems"
|
||||
:key="item.name"
|
||||
:label="item.i18n ? $t(item.label) : item.label"
|
||||
:prop="item.name">
|
||||
<custom-filed-component :form="form"
|
||||
:data="item"
|
||||
class="custom-filed"
|
||||
prop="defaultValue"
|
||||
@change="handleChange"/>
|
||||
<el-button v-if="item.withProjectCheck"
|
||||
:disabled="!form[item.name]"
|
||||
@click="check"
|
||||
type="primary"
|
||||
class="checkButton">
|
||||
{{ $t('test_track.issue.check_id_exist') }}
|
||||
</el-button>
|
||||
<ms-instructions-icon v-if="item.instructionsIcon" effect="light">
|
||||
<template>
|
||||
<img class="jira-image"
|
||||
:src="'/platform/plugin/resource/' + config.id + '?fileName=' + item.instructionsIcon"/>
|
||||
</template>
|
||||
</ms-instructions-icon>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
|
||||
import {getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
|
||||
import {
|
||||
getPlatformProjectInfo,
|
||||
getPlatformProjectOption,
|
||||
validateProjectConfig,
|
||||
} from "@/api/platform-plugin";
|
||||
import {getPlatformFormRules} from "@/business/workspace/integration/platform";
|
||||
import CustomFiledComponent from "metersphere-frontend/src/components/template/CustomFiledComponent";
|
||||
|
||||
export default {
|
||||
name: "ProjectPlatformConfig",
|
||||
components: {MsInstructionsIcon, CustomFiledComponent},
|
||||
props: {
|
||||
labelWidth: String,
|
||||
result: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
platformKey: String,
|
||||
projectConfig: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
issueTypes: [],
|
||||
form: {},
|
||||
rules: {},
|
||||
config: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
platformKey() {
|
||||
this.getPlatformProjectInfo();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getPlatformProjectInfo();
|
||||
},
|
||||
methods: {
|
||||
getPlatformProjectInfo() {
|
||||
getPlatformProjectInfo(this.platformKey)
|
||||
.then(r => {
|
||||
if (r.data) {
|
||||
Object.assign(this.form, this.projectConfig);
|
||||
r.data.formItems.forEach(item => {
|
||||
if (!item.options) {
|
||||
item.options = [];
|
||||
}
|
||||
// 设置默认值
|
||||
if (this.form[item.name]) {
|
||||
this.$set(item, 'defaultValue', this.form[item.name]);
|
||||
}
|
||||
// 获取级联选项值
|
||||
if (item.cascade && this.form[item.name]) {
|
||||
this.getCascadeOptions(item, () => {
|
||||
// 没有选项值会被组件自动清空,获取下拉框选项之后,重新设置默认值
|
||||
if (this.form[item.name]) {
|
||||
this.$set(item, 'defaultValue', this.form[item.name]);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
this.config = r.data;
|
||||
this.rules = getPlatformFormRules(this.config);
|
||||
}
|
||||
});
|
||||
},
|
||||
check() {
|
||||
validateProjectConfig(this.config.id, this.form)
|
||||
.then(() => {
|
||||
this.$success(this.$t("system.check_third_project_success"));
|
||||
});
|
||||
},
|
||||
validate() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$refs['form'].validate((valid) => {
|
||||
if (!valid) {
|
||||
reject();
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
handleChange(name) {
|
||||
this.config.formItems.forEach(item => {
|
||||
if (item.cascade === name) {
|
||||
this.$set(item, 'options', []);
|
||||
this.getCascadeOptions(item);
|
||||
}
|
||||
});
|
||||
},
|
||||
getCascadeOptions(item, callback) {
|
||||
getPlatformProjectOption(this.config.id, {
|
||||
platform: this.platformKey,
|
||||
optionMethod: item.optionMethod,
|
||||
workspaceId: getCurrentWorkspaceId(),
|
||||
projectConfig: JSON.stringify(this.form)
|
||||
}).then((r) => {
|
||||
this.$set(item, 'options', r.data);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.custom-filed :deep(.el-select) {
|
||||
width: 260px !important;
|
||||
}
|
||||
|
||||
.custom-filed :deep(.el-input, .el-textarea) {
|
||||
width: 80% !important;
|
||||
}
|
||||
|
||||
.checkButton {
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue