From 1efe5b0c2df147b44c135f78516a12468539ec89 Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Mon, 14 Dec 2020 14:35:32 +0800 Subject: [PATCH 01/15] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E9=83=A8=E5=88=86=E7=BC=BA=E9=99=B7=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ApiAutomationController.java | 5 ++++ .../controller/ApiDefinitionController.java | 5 ++++ .../api/dto/automation/ApiScenarioDTO.java | 4 ++- .../api/service/ApiAutomationService.java | 28 ++++++++++++------- .../api/service/ApiDefinitionService.java | 4 +++ .../mapper/ext/ExtApiDefinitionMapper.java | 2 ++ .../mapper/ext/ExtApiDefinitionMapper.xml | 11 ++++++++ .../base/mapper/ext/ExtApiScenarioMapper.java | 3 ++ .../base/mapper/ext/ExtApiScenarioMapper.xml | 20 +++++++++++++ backend/src/main/java/io/metersphere/xpack | 2 +- .../api/automation/scenario/AddTag.vue | 4 +-- .../automation/scenario/ApiScenarioList.vue | 12 ++++---- .../automation/scenario/EditApiScenario.vue | 9 +++--- .../automation/scenario/ImportApiScenario.vue | 2 +- .../api/definition/components/ApiList.vue | 6 ++-- .../api/definition/components/ApiModule.vue | 1 + 16 files changed, 89 insertions(+), 29 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java index f4452ed120..710f2d3aa3 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java @@ -58,6 +58,11 @@ public class ApiAutomationController { apiAutomationService.removeToGc(ids); } + @PostMapping("/reduction") + public void reduction(@RequestBody List ids) { + apiAutomationService.reduction(ids); + } + @GetMapping("/getApiScenario/{id}") public ApiScenario getScenarioDefinition(@PathVariable String id) { return apiAutomationService.getApiScenario(id); diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java index b27b4737b6..354f37d5e8 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java @@ -64,6 +64,11 @@ public class ApiDefinitionController { apiDefinitionService.removeToGc(ids); } + @PostMapping("/reduction") + public void reduction(@RequestBody List ids) { + apiDefinitionService.reduction(ids); + } + @GetMapping("/get/{id}") public ApiDefinition get(@PathVariable String id) { return apiDefinitionService.get(id); diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioDTO.java b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioDTO.java index 173f7897da..efecbd4e2b 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioDTO.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioDTO.java @@ -4,11 +4,13 @@ import io.metersphere.base.domain.ApiScenario; import lombok.Getter; import lombok.Setter; +import java.util.List; + @Getter @Setter public class ApiScenarioDTO extends ApiScenario { private String projectName; private String userName; - private String tagName; + private List tagNames; } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 70145ccad2..9d652d367f 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -22,6 +22,7 @@ import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.i18n.Translator; import io.metersphere.track.dto.TestPlanDTO; @@ -67,11 +68,12 @@ public class ApiAutomationService { private static final String BODY_FILE_DIR = "/opt/metersphere/data/body"; public List list(ApiScenarioRequest request) { + request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); + List list = extApiScenarioMapper.list(request); ApiTagExample example = new ApiTagExample(); example.createCriteria().andProjectIdEqualTo(request.getProjectId()); List tags = apiTagMapper.selectByExample(example); Map tagMap = tags.stream().collect(Collectors.toMap(ApiTag::getId, ApiTag::getName)); - List list = extApiScenarioMapper.list(request); Gson gs = new Gson(); list.forEach(item -> { if (item.getTagId() != null) { @@ -81,7 +83,11 @@ public class ApiAutomationService { buf.append(","); }); if (buf != null && buf.length() > 0) { - item.setTagName(buf.toString().substring(0, buf.toString().length() - 1)); + String tagNames = buf.toString().substring(0, buf.toString().length() - 1); + List tagList = Arrays.asList(tagNames.split(",")); + item.setTagNames(tagList); + } else { + item.setTagNames(new ArrayList<>()); } } }); @@ -166,12 +172,12 @@ public class ApiAutomationService { apiScenarioMapper.deleteByExample(example); } - public void removeToGc(List ids) { - ApiScenario record = new ApiScenario(); - record.setStatus(ScenarioStatus.Trash.name()); - ApiScenarioExample example = new ApiScenarioExample(); - example.createCriteria().andIdIn(ids); - apiScenarioMapper.updateByExampleSelective(record, example); + public void removeToGc(List apiIds) { + extApiScenarioMapper.removeToGc(apiIds); + } + + public void reduction(List apiIds) { + extApiScenarioMapper.reduction(apiIds); } private void checkNameExist(SaveApiScenarioRequest request) { @@ -244,12 +250,14 @@ public class ApiAutomationService { // 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取 if (StringUtils.isNotEmpty(element.getString("hashTree"))) { LinkedList elements = mapper.readValue(element.getString("hashTree"), - new TypeReference>() {}); + new TypeReference>() { + }); scenario.setHashTree(elements); } if (StringUtils.isNotEmpty(element.getString("variables"))) { LinkedList variables = mapper.readValue(element.getString("variables"), - new TypeReference>() {}); + new TypeReference>() { + }); scenario.setVariables(variables); } LinkedList scenarios = new LinkedList<>(); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index 5851ca24ec..a1c60272fa 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -163,6 +163,10 @@ public class ApiDefinitionService { extApiDefinitionMapper.removeToGc(apiIds); } + public void reduction(List apiIds) { + extApiDefinitionMapper.reduction(apiIds); + } + public void deleteBodyFiles(String apiId) { File file = new File(BODY_FILE_DIR + "/" + apiId); FileUtil.deleteContents(file); diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java index 320d5b4664..ba560aeebe 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java @@ -15,4 +15,6 @@ public interface ExtApiDefinitionMapper { int removeToGc(@Param("ids") List ids); + int reduction(@Param("ids") List ids); + } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml index ab5b4dac15..545bc9b71a 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml @@ -255,4 +255,15 @@ #{v} + + + update api_definition + set + status = 'Underway' + where id in + + #{v} + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java index bec0fbde89..fce72e2e7b 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java @@ -16,4 +16,7 @@ public interface ExtApiScenarioMapper { List selectReference(@Param("request") ApiScenarioRequest request); + int removeToGc(@Param("ids") List ids); + + int reduction(@Param("ids") List ids); } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml index da36ff4df5..e7c638e10c 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml @@ -88,5 +88,25 @@ + + update api_scenario + set + status = 'Trash' + where id in + + #{v} + + + + + update api_scenario + set + status = 'Underway' + where id in + + #{v} + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index 2ba1351aa0..905ca8af61 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit 2ba1351aa0135cdf3e5de740fa2d9c185b60ce9d +Subproject commit 905ca8af61ce966d26109e9c5c8c0aee3ca1324e diff --git a/frontend/src/business/components/api/automation/scenario/AddTag.vue b/frontend/src/business/components/api/automation/scenario/AddTag.vue index 4c78077330..4bb4dd12dd 100644 --- a/frontend/src/business/components/api/automation/scenario/AddTag.vue +++ b/frontend/src/business/components/api/automation/scenario/AddTag.vue @@ -9,7 +9,7 @@ - {{$t('commons.save')}} + {{$t('commons.save')}} @@ -72,7 +72,7 @@ }, methods: { saveTag() { - if (this.tagData.id != undefined && this.tagForm.id != null) { + if (this.tagForm.id != undefined && this.tagForm.id != null) { this.path = "/api/tag/update"; } else { this.path = "/api/tag/create"; diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue index 7214df3c1c..16c40b99d9 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue @@ -25,9 +25,11 @@ - + @@ -210,8 +212,8 @@ this.$emit('edit', row); }, reductionApi(row) { - let obj = {id: row.id, projectId: row.projectId, name: row.name, status: 'Underway'} - this.$fileUpload("/api/automation/update", null, [], obj, () => { + let obj = [row.id]; + this.$post("/api/automation/reduction", obj, response => { this.$success(this.$t('commons.save_success')); this.search(); }) @@ -265,7 +267,7 @@ diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index ab484774bd..ea19ba2c39 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -352,6 +352,9 @@ } }, created() { + if (!this.currentScenario.apiScenarioModuleId) { + this.currentScenario.apiScenarioModuleId = ""; + } this.projectId = getCurrentProjectID(); this.operatingElements = ELEMENTS.get("ALL"); this.getMaintainerOptions(); @@ -450,7 +453,7 @@ this.reload(); }, addScenario(arr) { - if (arr.length > 0) { + if (arr && arr.length > 0) { arr.forEach(item => { item.enable === undefined ? item.enable = true : item.enable; this.scenarioDefinition.push(item); @@ -710,10 +713,6 @@ } }, setParameter() { - this.currentScenario.projectId = this.projectId; - if (!this.currentScenario.id) { - this.currentScenario.id = getUUID(); - } this.currentScenario.stepTotal = this.scenarioDefinition.length; this.currentScenario.modulePath = this.getPath(this.currentScenario.apiScenarioModuleId); // 构建一个场景对象 方便引用处理 diff --git a/frontend/src/business/components/api/automation/scenario/ImportApiScenario.vue b/frontend/src/business/components/api/automation/scenario/ImportApiScenario.vue index 01c1ab5daa..6ef476bc3a 100644 --- a/frontend/src/business/components/api/automation/scenario/ImportApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/ImportApiScenario.vue @@ -68,7 +68,7 @@ if (response.data) { response.data.forEach(item => { let scenarioDefinition = JSON.parse(item.scenarioDefinition); - let obj = {id: item.id, name: item.name, type: "scenario", referenced: 'Copy', resourceId: getUUID(), hashTree: scenarioDefinition}; + let obj = {id: item.id, name: item.name, type: "scenario", referenced: 'Copy', resourceId: getUUID(), hashTree: scenarioDefinition.hashTree}; scenarios.push(obj); }) this.$emit('addScenario', scenarios); diff --git a/frontend/src/business/components/api/definition/components/ApiList.vue b/frontend/src/business/components/api/definition/components/ApiList.vue index 498fb5c9e9..16bc90da52 100644 --- a/frontend/src/business/components/api/definition/components/ApiList.vue +++ b/frontend/src/business/components/api/definition/components/ApiList.vue @@ -230,10 +230,8 @@ this.$emit('editApi', row); }, reductionApi(row) { - row.status = 'Underway'; - row.request = null; - row.response = null; - this.$fileUpload("/api/definition/update", null, [], row, () => { + let ids = [row.id]; + this.$post('/api/definition/reduction/', ids, () => { this.$success(this.$t('commons.save_success')); this.search(); }); diff --git a/frontend/src/business/components/api/definition/components/ApiModule.vue b/frontend/src/business/components/api/definition/components/ApiModule.vue index 812732eab1..aea697aa4a 100644 --- a/frontend/src/business/components/api/definition/components/ApiModule.vue +++ b/frontend/src/business/components/api/definition/components/ApiModule.vue @@ -138,6 +138,7 @@ if (this.expandedNode.length === 0) { this.expandedNode.push("root"); } + this.nextFlag = true; this.result = this.$get("/api/module/list/" + this.projectId + "/" + this.protocol, response => { if (response.data != undefined && response.data != null) { this.data[1].children = response.data; From 60fc50cf07839ccbed1c408e7b7219ac7651b015 Mon Sep 17 00:00:00 2001 From: BugKing Date: Mon, 14 Dec 2020 15:02:45 +0800 Subject: [PATCH 02/15] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20roadmap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ROADMAP.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index a6d51bbbb4..440f6fdbc5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -55,11 +55,17 @@ - [x] 测试跟踪:支持对接禅道同步缺陷 - [x] 其他:Jenkins 插件支持 pipeline 方式调用 +## v1.6 (开发中) +- [ ] 新增接口管理功能 +- [ ] 全新接口自动化使用方式 +- [ ] 测试跟踪测试计划分类型展示 +- [ ] 优化消息通知配置及实现方式 + ## 规划中 - [ ] 接口测试支持添加 WebSocket 协议请求 -- [ ] 接口管理功能 - [ ] 集成云平台动态管理测试资源池 -- [ ] 支持 K8s 集群作为测试资源池 +- [ ] 测试跟踪测试用例及接口测试增加版本管理 +- [ ] 测试跟踪测试用例增加思维导图展示形式 - [ ] 移动端测试支持 - [ ] UI 功能测试支持 From 723d5aa4623d2809a8cc551c153a6ab0c0255a9e Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Mon, 14 Dec 2020 15:38:38 +0800 Subject: [PATCH 03/15] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BC=80?= =?UTF-8?q?=E6=BA=90=E7=89=88=E6=98=BE=E7=A4=BA=E5=9B=BE=E7=89=87=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LoginController.java | 10 +++ .../service/BaseDisplayService.java | 72 +++++++++++++++++++ backend/src/main/java/io/metersphere/xpack | 2 +- 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/io/metersphere/service/BaseDisplayService.java diff --git a/backend/src/main/java/io/metersphere/controller/LoginController.java b/backend/src/main/java/io/metersphere/controller/LoginController.java index f1473d15fc..a3a73e2577 100644 --- a/backend/src/main/java/io/metersphere/controller/LoginController.java +++ b/backend/src/main/java/io/metersphere/controller/LoginController.java @@ -5,14 +5,17 @@ import io.metersphere.commons.constants.UserSource; import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.LoginRequest; +import io.metersphere.service.BaseDisplayService; import io.metersphere.service.UserService; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.SecurityUtils; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.core.env.Environment; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.io.IOException; @RestController @RequestMapping @@ -22,6 +25,8 @@ public class LoginController { private UserService userService; @Resource private Environment env; + @Resource + private BaseDisplayService baseDisplayService; @GetMapping(value = "/isLogin") public ResultHolder isLogin() { @@ -66,4 +71,9 @@ public class LoginController { public String getDefaultLanguage() { return userService.getDefaultLanguage(); } + + @GetMapping("display/file/{imageName}") + public ResponseEntity image(@PathVariable("imageName") String imageName) throws IOException { + return baseDisplayService.getImage(imageName); + } } diff --git a/backend/src/main/java/io/metersphere/service/BaseDisplayService.java b/backend/src/main/java/io/metersphere/service/BaseDisplayService.java new file mode 100644 index 0000000000..6373548114 --- /dev/null +++ b/backend/src/main/java/io/metersphere/service/BaseDisplayService.java @@ -0,0 +1,72 @@ +package io.metersphere.service; + +import io.metersphere.base.domain.SystemParameter; +import io.metersphere.base.domain.SystemParameterExample; +import io.metersphere.base.mapper.SystemParameterMapper; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.List; + +@Service +public class BaseDisplayService { + @Resource + private SystemParameterMapper systemParameterMapper; + @Resource + private FileService fileService; + + public List getParamList(String type) { + SystemParameterExample example = new SystemParameterExample(); + example.createCriteria().andParamKeyLike(type + "%"); + return systemParameterMapper.selectByExample(example); + } + + public byte[] loadFileAsBytes(String fileId) { + return fileService.loadFileAsBytes(fileId); + } + + public ResponseEntity getImage(String imageName) throws IOException { + byte[] bytes = null; + List paramList = getParamList("ui." + imageName); + if (!CollectionUtils.isEmpty(paramList)) { + SystemParameter sp = paramList.get(0); + String paramValue = sp.getParamValue(); + if (StringUtils.isNotBlank(paramValue)) { + bytes = loadFileAsBytes(paramValue); + } + } + + MediaType contentType = MediaType.parseMediaType("application/octet-stream"); + if (bytes == null) { + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(getClass().getClassLoader()); + switch (imageName) { + case "logo": + bytes = IOUtils.toByteArray(resolver.getResources("/static/img/logo-light-MeterSphere.*.svg")[0].getInputStream()); + contentType = MediaType.valueOf("image/svg+xml"); + break; + case "loginImage": + bytes = IOUtils.toByteArray(resolver.getResources("/static/img/info.*.png")[0].getInputStream()); + break; + case "loginLogo": + bytes = IOUtils.toByteArray(resolver.getResources("/static/img/logo-dark-MeterSphere.*.svg")[0].getInputStream()); + contentType = MediaType.valueOf("image/svg+xml"); + break; + default: + break; + } + } + + return ResponseEntity.ok() + .contentType(contentType) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + imageName + "\"") + .body(bytes); + } +} diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index 2ba1351aa0..f514243111 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit 2ba1351aa0135cdf3e5de740fa2d9c185b60ce9d +Subproject commit f514243111c3acb317e80da23857143857a53566 From 2f99251debeff346995f04d6c6e967246076a505 Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Mon, 14 Dec 2020 15:57:56 +0800 Subject: [PATCH 04/15] =?UTF-8?q?fix:=20=E9=81=BF=E5=85=8D=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E6=89=93=E5=8C=85=E7=BC=BA=E5=B0=91=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/login/Login.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/login/Login.vue b/frontend/src/login/Login.vue index 1a802e9d2c..cae9162e76 100644 --- a/frontend/src/login/Login.vue +++ b/frontend/src/login/Login.vue @@ -264,6 +264,10 @@ export default { .login-logo { background: url(../assets/logo-dark-MeterSphere.svg); } + +.logo-header { + background: url(../assets/logo-light-MeterSphere.svg); +} diff --git a/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue b/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue index 1b2ba625bb..3d307e5a0e 100644 --- a/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue +++ b/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue @@ -236,7 +236,7 @@ let hasEnvironment = false; for (let i in this.environments) { if (this.environments[i].id === this.api.environmentId) { - this.api.environmentId = this.environments[i]; + this.api.environmentId = this.environments[i].id; hasEnvironment = true; break; } From f10b154a8ab96da0c49fec27674879b4a70a2027 Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Mon, 14 Dec 2020 16:14:45 +0800 Subject: [PATCH 06/15] =?UTF-8?q?fix:=20=E6=8C=87=E5=AE=9A=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E7=9A=84=20rest=20template?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/metersphere/service/NodeResourcePoolService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java b/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java index 5ac02b5367..b22c00f9c2 100644 --- a/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java +++ b/backend/src/main/java/io/metersphere/service/NodeResourcePoolService.java @@ -28,7 +28,7 @@ import static io.metersphere.commons.constants.ResourceStatusEnum.VALID; public class NodeResourcePoolService { private final static String nodeControllerUrl = "http://%s:%s/status"; - @Resource + @Resource(name = "restTemplateWithTimeOut") private RestTemplate restTemplateWithTimeOut; @Resource private TestResourceMapper testResourceMapper; From 3af1825a26c5d0b1799051d4b2c9301b2195a6c7 Mon Sep 17 00:00:00 2001 From: shiziyuan9527 Date: Mon, 14 Dec 2020 16:17:45 +0800 Subject: [PATCH 07/15] =?UTF-8?q?feat:=20=E5=88=87=E6=8D=A2=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=90=8E=E6=98=BE=E7=A4=BA=E9=A1=B9=E7=9B=AE=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/api/head/ApiHeaderMenus.vue | 9 ++- .../components/common/head/SearchList.vue | 55 ++++++++++++++----- .../head/PerformanceHeaderMenus.vue | 16 ++++-- .../track/head/TrackHeaderMenus.vue | 13 +++-- 4 files changed, 66 insertions(+), 27 deletions(-) diff --git a/frontend/src/business/components/api/head/ApiHeaderMenus.vue b/frontend/src/business/components/api/head/ApiHeaderMenus.vue index b4dcf3f51b..409e7409d4 100644 --- a/frontend/src/business/components/api/head/ApiHeaderMenus.vue +++ b/frontend/src/business/components/api/head/ApiHeaderMenus.vue @@ -6,8 +6,12 @@ - - + + @@ -108,6 +112,7 @@ export default { isProjectActivation: true, isRouterAlive: true, apiTestProjectPath: '', + currentProject: '' } }, // watch: { diff --git a/frontend/src/business/components/common/head/SearchList.vue b/frontend/src/business/components/common/head/SearchList.vue index b6f3c3ba2c..e4effd6cbe 100644 --- a/frontend/src/business/components/common/head/SearchList.vue +++ b/frontend/src/business/components/common/head/SearchList.vue @@ -2,7 +2,7 @@
@@ -16,8 +16,8 @@
@@ -32,7 +32,8 @@ import {PROJECT_ID, ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "@ export default { name: "SearchList", props: { - options: Object + options: Object, + currentProject: String }, mounted() { this.init(); @@ -41,44 +42,68 @@ export default { return { result: {}, items: [], - search_text: '', + searchArray: [], + searchString: '', userId: getCurrentUser().id, currentProjectId: localStorage.getItem(PROJECT_ID) } }, watch: { - search_text(val) { - if (!val) { - this.init(); - } else { - this.search(); - } + searchString(val) { + this.query(val) } }, methods: { init: function () { if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) { - this.result = this.$get(this.options.url, (response) => { + this.result = this.$get("/project/listAll", response => { this.items = response.data; - this.items = this.items.splice(0, 3); + this.searchArray = response.data; if (!getCurrentProjectID() && this.items.length > 0) { this.change(this.items[0].id); } - }); + let projectId = getCurrentProjectID(); + this.changeProjectName(projectId); + }) } }, search() { if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) { - this.result = this.$post("/project/search", {name: this.search_text},response => { + this.result = this.$post("/project/search", {name: this.searchString},response => { this.items = response.data; }) } }, + query(queryString) { + this.items = queryString ? this.searchArray.filter(this.createFilter(queryString)) : this.searchArray; + }, + createFilter(queryString) { + return item => { + return (item.name.toLowerCase().indexOf(queryString.toLowerCase()) !== -1); + }; + }, change(projectId) { this.$post("/user/update/current", {id: this.userId, lastProjectId: projectId}, () => { localStorage.setItem(PROJECT_ID, projectId); - window.location.reload(); + if (this.$route.path.indexOf('/track/review/view/') >= 0) { + this.$router.replace('/track/review/all'); + } else if (this.$route.path.indexOf('/track/plan/view/') >= 0) { + this.$router.replace('/track/plan/all'); + } else { + window.location.reload(); + } + this.changeProjectName(projectId); }); + }, + changeProjectName(projectId) { + if (projectId) { + let project = this.searchArray.filter(p => p.id === projectId); + if (project.length > 0) { + this.$emit("update:currentProject", project[0].name); + } + } else { + this.$emit("update:currentProject", '选择项目'); + } } } } diff --git a/frontend/src/business/components/performance/head/PerformanceHeaderMenus.vue b/frontend/src/business/components/performance/head/PerformanceHeaderMenus.vue index 79324356fb..e63010aaec 100644 --- a/frontend/src/business/components/performance/head/PerformanceHeaderMenus.vue +++ b/frontend/src/business/components/performance/head/PerformanceHeaderMenus.vue @@ -1,13 +1,17 @@ @@ -98,7 +102,7 @@ export default { router(item) { } }, - input2: '' + currentProject: '' } }, methods: { diff --git a/frontend/src/business/components/track/head/TrackHeaderMenus.vue b/frontend/src/business/components/track/head/TrackHeaderMenus.vue index 3ac4dc779d..7f01d57323 100644 --- a/frontend/src/business/components/track/head/TrackHeaderMenus.vue +++ b/frontend/src/business/components/track/head/TrackHeaderMenus.vue @@ -2,13 +2,17 @@ @@ -78,6 +82,7 @@ export default { testCaseReviewEditPath: '', testCaseProjectPath: '', isProjectActivation: true, + currentProject: '', projectRecent: { title: this.$t('project.recent'), url: "/project/recent/5", From 82248b22daea8fc3900f2cfb8cacb79d508d0e7e Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Mon, 14 Dec 2020 16:57:42 +0800 Subject: [PATCH 08/15] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E4=BF=AE=E6=94=B9Tree=20=E6=A0=B7=E5=BC=8F=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/service/ApiScenarioModuleService.java | 9 +-- .../automation/scenario/ApiScenarioModule.vue | 11 ++-- .../api/definition/components/ApiModule.vue | 58 +++++++++---------- 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java index 24d2c3412b..374f6a8c58 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java @@ -123,16 +123,17 @@ public class ApiScenarioModuleService { } } - private List queryByModuleIds(List nodeIds) { + private List queryByModuleIds(DragApiScenarioModuleRequest request) { ApiScenarioRequest apiScenarioRequest = new ApiScenarioRequest(); - apiScenarioRequest.setModuleIds(nodeIds); + apiScenarioRequest.setProjectId(request.getProjectId()); + apiScenarioRequest.setModuleIds(request.getNodeIds()); return apiAutomationService.list(apiScenarioRequest); } public int editNode(DragApiScenarioModuleRequest request) { request.setUpdateTime(System.currentTimeMillis()); checkApiScenarioModuleExist(request); - List apiScenarios = queryByModuleIds(request.getNodeIds()); + List apiScenarios = queryByModuleIds(request); apiScenarios.forEach(apiScenario -> { StringBuilder path = new StringBuilder(apiScenario.getModulePath()); @@ -171,7 +172,7 @@ public class ApiScenarioModuleService { List nodeIds = request.getNodeIds(); - List apiScenarios = queryByModuleIds(nodeIds); + List apiScenarios = queryByModuleIds(request); ApiScenarioModuleDTO nodeTree = request.getNodeTree(); diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue index 1f728d338d..edbd91f712 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioModule.vue @@ -30,11 +30,9 @@ class="ms-el-input" size="mini">
- - - - - + + + - + -
- - - -
- + + + i { - color: #409eff; - margin: 0px 5px; - } - /deep/ .el-tree-node__content { height: 33px; } @@ -503,4 +477,26 @@ width: 90px; } + .father .child { + display: none; + } + + .father:hover .child { + display: block; + } + + .node-title { + width: 0px; + text-overflow: ellipsis; + white-space: nowrap; + flex: 1 1 auto; + padding: 0px 5px; + overflow: hidden; + } + + .node-operate > i { + color: #409eff; + margin: 0px 5px; + } + From a5a8f94cbede7ad8296af36863babce1b741230a Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Mon, 14 Dec 2020 17:00:51 +0800 Subject: [PATCH 09/15] =?UTF-8?q?fix:=20=E6=8C=87=E5=AE=9A=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E7=9A=84=20rest=20template?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/java/io/metersphere/xpack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index f514243111..1fe20ba15a 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit f514243111c3acb317e80da23857143857a53566 +Subproject commit 1fe20ba15a7ca3fe9f77ddf866021e7c7dfe5969 From 36acba4121a766948a517a34b707cccddb6efb5c Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Mon, 14 Dec 2020 17:16:56 +0800 Subject: [PATCH 10/15] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E4=BF=AE=E5=A4=8D=E6=89=A7=E8=A1=8C=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E7=BC=BA=E5=A4=B1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/java/io/metersphere/xpack | 2 +- .../components/api/definition/components/Run.vue | 6 +++++- .../api/definition/components/case/ApiCaseHeader.vue | 11 +---------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index f514243111..905ca8af61 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit f514243111c3acb317e80da23857143857a53566 +Subproject commit 905ca8af61ce966d26109e9c5c8c0aee3ca1324e diff --git a/frontend/src/business/components/api/definition/components/Run.vue b/frontend/src/business/components/api/definition/components/Run.vue index 887ebe2631..b44e83bfd3 100644 --- a/frontend/src/business/components/api/definition/components/Run.vue +++ b/frontend/src/business/components/api/definition/components/Run.vue @@ -104,10 +104,14 @@ threadGroup.hashTree = []; testPlan.hashTree = [threadGroup]; this.runData.forEach(item => { + if (!item.useEnvironment) { + this.$error(this.$t("api_test.environment.select_environment")); + this.$emit('runRefresh', {}); + return; + } threadGroup.hashTree.push(item); }) let reqObj = {id: this.reportId, testElement: testPlan}; - let bodyFiles = this.getBodyUploadFiles(reqObj); let url = ""; if (this.debug) { diff --git a/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue b/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue index 8fe0bef3d9..7967a0ce89 100644 --- a/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue +++ b/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue @@ -103,6 +103,7 @@ } }, created() { + this.environment = undefined; this.getEnvironments(); }, watch: { @@ -118,16 +119,6 @@ this.environments.forEach(environment => { parseEnvironment(environment); }); - let hasEnvironment = false; - for (let i in this.environments) { - if (this.environments[i].id === this.api.environmentId) { - hasEnvironment = true; - break; - } - } - if (!hasEnvironment) { - this.environment = undefined; - } }); } else { this.environment = undefined; From fd3c8052fc2e5745f6a14758452990c14a1b2503 Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Mon, 14 Dec 2020 17:35:16 +0800 Subject: [PATCH 11/15] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89)?= =?UTF-8?q?:=20=E4=BF=AE=E5=A4=8D=E6=89=A7=E8=A1=8C=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/metersphere/api/service/ApiAutomationService.java | 2 +- .../components/api/automation/scenario/EditApiScenario.vue | 4 ++++ .../components/api/definition/components/ApiList.vue | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 9d652d367f..90c436f519 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -248,7 +248,7 @@ public class ApiAutomationService { JSONObject element = JSON.parseObject(item.getScenarioDefinition()); MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class); // 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取 - if (StringUtils.isNotEmpty(element.getString("hashTree"))) { + if (element!= null && StringUtils.isNotEmpty(element.getString("hashTree"))) { LinkedList elements = mapper.readValue(element.getString("hashTree"), new TypeReference>() { }); diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index ea19ba2c39..79d369b596 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -455,6 +455,10 @@ addScenario(arr) { if (arr && arr.length > 0) { arr.forEach(item => { + if (item.id === this.currentScenario.id) { + this.$error("不能引用或复制自身!"); + return; + } item.enable === undefined ? item.enable = true : item.enable; this.scenarioDefinition.push(item); }) diff --git a/frontend/src/business/components/api/definition/components/ApiList.vue b/frontend/src/business/components/api/definition/components/ApiList.vue index 4862905580..4c831ab263 100644 --- a/frontend/src/business/components/api/definition/components/ApiList.vue +++ b/frontend/src/business/components/api/definition/components/ApiList.vue @@ -306,7 +306,12 @@ }, handleTestCase(api) { this.selectApi = api; - let request = JSON.parse(api.request); + let request = {}; + if (Object.prototype.toString.call(api.request).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object') { + request = api.request; + } else { + request = JSON.parse(api.request); + } if (!request.hashTree) { request.hashTree = []; } From 80a652813f71e30e1a665a0850e47d168f1abfac Mon Sep 17 00:00:00 2001 From: shiziyuan9527 Date: Mon, 14 Dec 2020 17:43:57 +0800 Subject: [PATCH 12/15] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E9=A1=B9=E7=9B=AE=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/head/HeaderOrgWs.vue | 17 ++++++++++------- .../components/common/head/SearchList.vue | 17 +++++++++++++++-- .../components/settings/SettingMenu.vue | 2 +- frontend/src/common/js/utils.js | 1 - 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/frontend/src/business/components/common/head/HeaderOrgWs.vue b/frontend/src/business/components/common/head/HeaderOrgWs.vue index d91a800ecc..5b8a565245 100644 --- a/frontend/src/business/components/common/head/HeaderOrgWs.vue +++ b/frontend/src/business/components/common/head/HeaderOrgWs.vue @@ -26,13 +26,14 @@