Merge branch 'main' of https://github.com/metersphere/metersphere
This commit is contained in:
commit
981088f066
|
@ -158,7 +158,7 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu
|
|||
|
||||
## License & Copyright
|
||||
|
||||
Copyright (c) 2014-2022 飞致云 FIT2CLOUD, All rights reserved.
|
||||
Copyright (c) 2014-2023 飞致云 FIT2CLOUD, All rights reserved.
|
||||
|
||||
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ MeterSphere 的最新 LTS 版本为 v1.20 LTS。MeterSphere 下一个 LTS 版本
|
|||
|
||||
### License & Copyright
|
||||
|
||||
Copyright (c) 2014-2022 飞致云 FIT2CLOUD, All rights reserved.
|
||||
Copyright (c) 2014-2023 飞致云 FIT2CLOUD, All rights reserved.
|
||||
|
||||
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
|
|
|
@ -555,8 +555,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
|||
String value = keyValue.getValue() != null && keyValue.getValue().startsWith("@") ?
|
||||
ScriptEngineUtils.buildFunctionCallString(keyValue.getValue()) : keyValue.getValue();
|
||||
value = keyValue.isUrlEncode() ? StringUtils.join(StringUtils.join("${__urlencode(", value), ")}") : value;
|
||||
String key = keyValue.isUrlEncode() ? StringUtils.join(StringUtils.join("${__urlencode(", keyValue.getName()), ")}") : keyValue.getName();
|
||||
keyValueMap.put(key, value);
|
||||
keyValueMap.put(keyValue.getName(), value);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
|
|
|
@ -330,7 +330,7 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
|||
Set<String> refSet = new HashSet<>();
|
||||
Map<String, Schema> infoMap = new HashMap();
|
||||
Schema schema = getSchema(mediaType.getSchema());
|
||||
if (content.get(contentType).getExample() != null && schema.getExample() == null) {
|
||||
if (content.get(contentType) != null && content.get(contentType).getExample() != null && schema.getExample() == null) {
|
||||
schema.setExample(content.get(contentType).getExample());
|
||||
}
|
||||
Object bodyData = null;
|
||||
|
@ -979,7 +979,7 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
|||
return new JSONObject();
|
||||
}
|
||||
JSONObject responseBody = new JSONObject();
|
||||
JSONObject statusCodeInfo = new JSONObject();
|
||||
|
||||
// build 请求头
|
||||
JSONObject headers = new JSONObject();
|
||||
JSONArray headValueList = response.optJSONArray("headers");
|
||||
|
@ -995,17 +995,21 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
|||
}
|
||||
}
|
||||
}
|
||||
statusCodeInfo.put("headers", headers);
|
||||
|
||||
statusCodeInfo.put("content", buildContent(response));
|
||||
statusCodeInfo.put("description", StringUtils.EMPTY);
|
||||
// 返回code
|
||||
JSONArray statusCode = response.optJSONArray("statusCode");
|
||||
for (int i = 0; i < statusCode.length(); i++) {
|
||||
JSONObject statusCodeInfo = new JSONObject();
|
||||
statusCodeInfo.put("headers", headers);
|
||||
statusCodeInfo.put("content", buildContent(response));
|
||||
statusCodeInfo.put("description", StringUtils.EMPTY);
|
||||
JSONObject jsonObject = statusCode.getJSONObject(i);
|
||||
jsonObject.get("name");
|
||||
statusCodeInfo.put("description", jsonObject.get("value"));
|
||||
responseBody.put(jsonObject.get("name").toString(), statusCodeInfo);
|
||||
if (jsonObject.optString("value") != null) {
|
||||
statusCodeInfo.put("description", jsonObject.optString("value"));
|
||||
}
|
||||
if (jsonObject.optString("name") != null) {
|
||||
responseBody.put(jsonObject.optString("name"), statusCodeInfo);
|
||||
}
|
||||
}
|
||||
return responseBody;
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ import org.apache.jorphan.collections.HashTree;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
@ -823,6 +824,14 @@ public class JMeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
|||
elementNode.setName(transactionController.getName());
|
||||
((MsTransactionController) elementNode).setGenerateParentSample(transactionController.isGenerateParentSample());
|
||||
((MsTransactionController) elementNode).setIncludeTimers(transactionController.isIncludeTimers());
|
||||
} else if (StringUtils.equals(key.getClass().getName(), "net.xmeter.samplers.ConnectSampler")) {
|
||||
elementNode = getMqttElement(key, "io.metersphere.plugin.mqtt.sampler.MqttConnectSampler");
|
||||
} else if (StringUtils.equals(key.getClass().getName(), "net.xmeter.samplers.DisConnectSampler")) {
|
||||
elementNode = getMqttElement(key, "io.metersphere.plugin.mqtt.sampler.MqttDisConnectSampler");
|
||||
} else if (StringUtils.equals(key.getClass().getName(), "net.xmeter.samplers.PubSampler")) {
|
||||
elementNode = getMqttElement(key, "io.metersphere.plugin.mqtt.sampler.MqttPubSampler");
|
||||
} else if (StringUtils.equals(key.getClass().getName(), "net.xmeter.samplers.SubSampler")) {
|
||||
elementNode = getMqttElement(key, "io.metersphere.plugin.mqtt.sampler.MqttSubSampler");
|
||||
}
|
||||
// 平台不能识别的Jmeter步骤
|
||||
else {
|
||||
|
@ -866,6 +875,21 @@ public class JMeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
|||
}
|
||||
}
|
||||
|
||||
private static MsTestElement getMqttElement(Object key, String className) {
|
||||
MsTestElement elementNode;
|
||||
try {
|
||||
Class<?> clazz = null;
|
||||
clazz = Class.forName(className);
|
||||
Object instance = clazz.getConstructor().newInstance();
|
||||
Method methods2 = clazz.getMethod("importJmx", Object.class);
|
||||
Object invoke = methods2.invoke(instance, key);
|
||||
elementNode = (MsTestElement) invoke;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return elementNode;
|
||||
}
|
||||
|
||||
public static MsTestElement getMsTestElement(BeanShellPreProcessor key) {
|
||||
MsTestElement elementNode;
|
||||
BeanShellPreProcessor beanShellPreProcessor = key;
|
||||
|
|
|
@ -94,10 +94,11 @@ public class GenerateHashTreeUtil {
|
|||
String environmentType = apiScenarioWithBLOBs.getEnvironmentType();
|
||||
String environmentJson = apiScenarioWithBLOBs.getEnvironmentJson();
|
||||
String environmentGroupId = apiScenarioWithBLOBs.getEnvironmentGroupId();
|
||||
|
||||
if (StringUtils.isBlank(environmentType)) {
|
||||
environmentType = EnvironmentType.JSON.toString();
|
||||
}
|
||||
if (StringUtils.equals(environmentType, EnvironmentType.JSON.toString())) {
|
||||
if (StringUtils.equals(environmentType, EnvironmentType.JSON.toString()) && StringUtils.isNotBlank(environmentJson)) {
|
||||
scenario.setEnvironmentMap(JSON.parseObject(environmentJson, Map.class));
|
||||
} else if (StringUtils.equals(environmentType, EnvironmentType.GROUP.toString())) {
|
||||
Map<String, String> map = CommonBeanFactory.getBean(BaseEnvGroupProjectService.class).getEnvMap(environmentGroupId);
|
||||
|
@ -133,7 +134,7 @@ public class GenerateHashTreeUtil {
|
|||
String definition = element.toString();
|
||||
MsScenario scenario = JSON.parseObject(definition, MsScenario.class);
|
||||
group.setOnSampleError(scenario.getOnSampleError());
|
||||
if (planEnvMap != null && planEnvMap.size() > 0) {
|
||||
if (MapUtils.isNotEmpty(planEnvMap)) {
|
||||
scenario.setEnvironmentMap(planEnvMap);
|
||||
} else {
|
||||
setScenarioEnv(scenario, item);
|
||||
|
|
|
@ -3,15 +3,13 @@ package io.metersphere.listener;
|
|||
import com.mchange.lang.IntegerUtils;
|
||||
import io.metersphere.api.exec.queue.ExecThreadPoolExecutor;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.service.ApiExecutionQueueService;
|
||||
import io.metersphere.service.MockConfigService;
|
||||
import io.metersphere.service.PluginService;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.dto.BaseSystemConfigDTO;
|
||||
import io.metersphere.service.BaseScheduleService;
|
||||
import io.metersphere.service.SystemParameterService;
|
||||
import io.metersphere.service.*;
|
||||
import io.metersphere.service.definition.ApiModuleService;
|
||||
import io.metersphere.service.scenario.ApiScenarioModuleService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.python.core.Options;
|
||||
import org.python.util.PythonInterpreter;
|
||||
|
@ -36,6 +34,10 @@ public class ApiAppStartListener implements ApplicationRunner {
|
|||
private PluginService pluginService;
|
||||
@Resource
|
||||
private ApiExecutionQueueService apiExecutionQueueService;
|
||||
@Resource
|
||||
private ApiModuleService apiModuleService;
|
||||
@Resource
|
||||
private ApiScenarioModuleService apiScenarioModuleService;
|
||||
|
||||
@Value("${jmeter.home}")
|
||||
private String jmeterHome;
|
||||
|
@ -59,6 +61,12 @@ public class ApiAppStartListener implements ApplicationRunner {
|
|||
LogUtil.info("处理重启导致未执行完成的报告");
|
||||
apiExecutionQueueService.exceptionHandling();
|
||||
|
||||
LogUtil.info("初始化默认项目接口模块");
|
||||
apiModuleService.initDefaultNode();
|
||||
|
||||
LogUtil.info("初始化默认项目场景模块");
|
||||
apiScenarioModuleService.initDefaultModule();
|
||||
|
||||
BaseSystemConfigDTO dto = systemParameterService.getBaseInfo();
|
||||
LogUtil.info("设置并发队列核心数", dto.getConcurrency());
|
||||
if (StringUtils.isNotEmpty(dto.getConcurrency())) {
|
||||
|
|
|
@ -6,11 +6,13 @@ import io.metersphere.api.parse.api.ApiDefinitionImport;
|
|||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ApiDefinitionMapper;
|
||||
import io.metersphere.base.mapper.ApiModuleMapper;
|
||||
import io.metersphere.base.mapper.ProjectMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtApiDefinitionMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtApiModuleMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtApiTestCaseMapper;
|
||||
import io.metersphere.commons.constants.ProjectModuleDefaultNodeEnum;
|
||||
import io.metersphere.commons.constants.PropertyConstant;
|
||||
import io.metersphere.commons.constants.RequestTypeConstants;
|
||||
import io.metersphere.commons.constants.TestCaseConstants;
|
||||
import io.metersphere.commons.enums.ApiTestDataStatus;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
|
@ -31,7 +33,6 @@ import org.apache.ibatis.session.SqlSession;
|
|||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.mybatis.spring.SqlSessionUtils;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -54,6 +55,8 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
|
|||
private ApiDefinitionService apiDefinitionService;
|
||||
@Resource
|
||||
private ExtApiTestCaseMapper extApiTestCaseMapper;
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
|
||||
@Resource
|
||||
SqlSessionFactory sqlSessionFactory;
|
||||
|
@ -141,8 +144,6 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
|
|||
}
|
||||
|
||||
public List<ApiModuleDTO> getNodeTreeByProjectId(String projectId, String protocol, String versionId) {
|
||||
// 判断当前项目下是否有默认模块,没有添加默认模块
|
||||
this.getDefaultNode(projectId, protocol);
|
||||
ApiDefinitionRequest request = new ApiDefinitionRequest();
|
||||
List<ApiModuleDTO> apiModules = getApiModulesByProjectAndPro(projectId, protocol);
|
||||
request.setProjectId(projectId);
|
||||
|
@ -189,8 +190,6 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
|
|||
}
|
||||
|
||||
public List<ApiModuleDTO> getNodeTreeByCondition(String projectId, String protocol, String versionId, ApiDefinitionRequest request) {
|
||||
// 判断当前项目下是否有默认模块,没有添加默认模块
|
||||
this.getDefaultNode(projectId, protocol);
|
||||
List<ApiModuleDTO> apiModules = getApiModulesByProjectAndPro(projectId, protocol);
|
||||
request.setProjectId(projectId);
|
||||
request.setProtocol(protocol);
|
||||
|
@ -570,19 +569,29 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
|
|||
return apiModuleMapper.countByExample(example);
|
||||
}
|
||||
|
||||
public void initDefaultNode() {
|
||||
ProjectExample projectExample = new ProjectExample();
|
||||
projectExample.createCriteria().andNameEqualTo("默认项目");
|
||||
List<Project> projects = projectMapper.selectByExample(projectExample);
|
||||
if (CollectionUtils.isNotEmpty(projects)) {
|
||||
String[] protocols = {RequestTypeConstants.HTTP, RequestTypeConstants.DUBBO, RequestTypeConstants.SQL, RequestTypeConstants.TCP};
|
||||
for (String protocol : protocols) {
|
||||
saveDefault(projects.get(0).getId(), protocol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ApiModule getDefaultNode(String projectId, String protocol) {
|
||||
ApiModuleExample example = new ApiModuleExample();
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andProtocolEqualTo(protocol).andNameEqualTo(ProjectModuleDefaultNodeEnum.API_MODULE_DEFAULT_NODE.getNodeName()).andParentIdIsNull();
|
||||
List<ApiModule> list = apiModuleMapper.selectByExample(example);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return saveDefault(projectId, protocol);
|
||||
} else {
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
return list.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Async
|
||||
public synchronized ApiModule saveDefault(String projectId, String protocol) {
|
||||
public ApiModule saveDefault(String projectId, String protocol) {
|
||||
ApiModuleExample example = new ApiModuleExample();
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andProtocolEqualTo(protocol).andNameEqualTo(ProjectModuleDefaultNodeEnum.API_MODULE_DEFAULT_NODE.getNodeName()).andParentIdIsNull();
|
||||
List<ApiModule> list = apiModuleMapper.selectByExample(example);
|
||||
|
|
|
@ -3,12 +3,10 @@ package io.metersphere.service.scenario;
|
|||
|
||||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
import io.metersphere.api.dto.automation.*;
|
||||
import io.metersphere.base.domain.ApiScenario;
|
||||
import io.metersphere.base.domain.ApiScenarioModule;
|
||||
import io.metersphere.base.domain.ApiScenarioModuleExample;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ApiScenarioMapper;
|
||||
import io.metersphere.base.mapper.ApiScenarioModuleMapper;
|
||||
import io.metersphere.base.mapper.ProjectMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtApiScenarioModuleMapper;
|
||||
import io.metersphere.commons.constants.ProjectModuleDefaultNodeEnum;
|
||||
|
@ -30,10 +28,9 @@ import org.apache.ibatis.session.ExecutorType;
|
|||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionUtils;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
|
@ -55,14 +52,14 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
|
|||
SqlSessionFactory sqlSessionFactory;
|
||||
@Resource
|
||||
private ExtApiScenarioMapper extApiScenarioMapper;
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
|
||||
public ApiScenarioModuleService() {
|
||||
super(ApiScenarioModuleDTO.class);
|
||||
}
|
||||
|
||||
public List<ApiScenarioModuleDTO> getNodeTreeByProjectId(String projectId) {
|
||||
// 判断当前项目下是否有默认模块,没有添加默认模块
|
||||
this.getDefaultNode(projectId);
|
||||
List<ApiScenarioModuleDTO> nodes = extApiScenarioModuleMapper.getNodeTreeByProjectId(projectId);
|
||||
ApiScenarioRequest request = new ApiScenarioRequest();
|
||||
request.setProjectId(projectId);
|
||||
|
@ -103,8 +100,6 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
|
|||
}
|
||||
|
||||
public List<ApiScenarioModuleDTO> getNodeTreeByProjectId(String projectId, ApiScenarioRequest request) {
|
||||
// 判断当前项目下是否有默认模块,没有添加默认模块
|
||||
this.getDefaultNode(projectId);
|
||||
List<ApiScenarioModuleDTO> nodes = extApiScenarioModuleMapper.getNodeTreeByProjectId(projectId);
|
||||
request.setProjectId(projectId);
|
||||
List<String> list = new ArrayList<>();
|
||||
|
@ -174,7 +169,7 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
|
|||
}
|
||||
|
||||
private void initApiCount(List<ApiScenarioModuleDTO> moduleDTOList, Map<String, List<ApiScenario>> scenarioMap) {
|
||||
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(moduleDTOList) && MapUtils.isNotEmpty(scenarioMap)) {
|
||||
if (CollectionUtils.isNotEmpty(moduleDTOList) && MapUtils.isNotEmpty(scenarioMap)) {
|
||||
moduleDTOList.forEach(node -> {
|
||||
List<String> moduleIds = new ArrayList<>();
|
||||
moduleIds = this.nodeList(moduleDTOList, node.getId(), moduleIds);
|
||||
|
@ -191,7 +186,7 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
|
|||
}
|
||||
|
||||
private List<ApiScenarioModuleDTO> selectTreeStructModuleById(Collection<String> ids) {
|
||||
if (org.apache.commons.collections.CollectionUtils.isEmpty(ids)) {
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return new ArrayList<>(0);
|
||||
} else {
|
||||
List<String> parentIdList = new ArrayList<>();
|
||||
|
@ -246,7 +241,7 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
|
|||
|
||||
public double getNextLevelPos(String projectId, int level, String parentId) {
|
||||
List<ApiScenarioModule> list = getPos(projectId, level, parentId, "pos desc");
|
||||
if (!CollectionUtils.isEmpty(list) && list.get(0) != null && list.get(0).getPos() != null) {
|
||||
if (CollectionUtils.isNotEmpty(list) && list.get(0) != null && list.get(0).getPos() != null) {
|
||||
return list.get(0).getPos() + DEFAULT_POS;
|
||||
} else {
|
||||
return DEFAULT_POS;
|
||||
|
@ -463,7 +458,7 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
|
|||
ApiScenarioModuleExample example = new ApiScenarioModuleExample();
|
||||
example.createCriteria().andIdIn(ids);
|
||||
List<ApiScenarioModule> nodes = apiScenarioModuleMapper.selectByExample(example);
|
||||
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(nodes)) {
|
||||
if (CollectionUtils.isNotEmpty(nodes)) {
|
||||
List<String> names = nodes.stream().map(ApiScenarioModule::getName).collect(Collectors.toList());
|
||||
OperatingLogDetails details = new OperatingLogDetails(JSON.toJSONString(ids), nodes.get(0).getProjectId(), String.join(",", names), nodes.get(0).getCreateUser(), new LinkedList<>());
|
||||
return JSON.toJSONString(details);
|
||||
|
@ -489,7 +484,7 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
|
|||
criteria.andIdNotEqualTo(node.getId());
|
||||
}
|
||||
List<ApiScenarioModule> list = apiScenarioModuleMapper.selectByExample(example);
|
||||
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(list)) {
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
module = list.get(0);
|
||||
}
|
||||
}
|
||||
|
@ -509,19 +504,27 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
|
|||
|
||||
public ApiScenarioModule getDefaultNode(String projectId) {
|
||||
ApiScenarioModuleExample example = new ApiScenarioModuleExample();
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andNameEqualTo(ProjectModuleDefaultNodeEnum.API_SCENARIO_DEFAULT_NODE.getNodeName()).andParentIdIsNull();
|
||||
example.createCriteria()
|
||||
.andProjectIdEqualTo(projectId)
|
||||
.andNameEqualTo(ProjectModuleDefaultNodeEnum.API_SCENARIO_DEFAULT_NODE.getNodeName())
|
||||
.andParentIdIsNull();
|
||||
List<ApiScenarioModule> list = apiScenarioModuleMapper.selectByExample(example);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return saveDefault(projectId);
|
||||
} else {
|
||||
if (!CollectionUtils.isEmpty(list)) {
|
||||
return list.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Async
|
||||
public synchronized ApiScenarioModule saveDefault(String projectId) {
|
||||
public void initDefaultModule() {
|
||||
ProjectExample projectExample = new ProjectExample();
|
||||
projectExample.createCriteria().andNameEqualTo("默认项目");
|
||||
List<Project> projects = projectMapper.selectByExample(projectExample);
|
||||
if (!CollectionUtils.isEmpty(projects)) {
|
||||
ApiScenarioModuleExample example = new ApiScenarioModuleExample();
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andNameEqualTo(ProjectModuleDefaultNodeEnum.API_SCENARIO_DEFAULT_NODE.getNodeName()).andParentIdIsNull();
|
||||
example.createCriteria()
|
||||
.andProjectIdEqualTo(projects.get(0).getId())
|
||||
.andNameEqualTo(ProjectModuleDefaultNodeEnum.API_SCENARIO_DEFAULT_NODE.getNodeName())
|
||||
.andParentIdIsNull();
|
||||
List<ApiScenarioModule> list = apiScenarioModuleMapper.selectByExample(example);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
ApiScenarioModule module = new ApiScenarioModule();
|
||||
|
@ -531,12 +534,10 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
|
|||
module.setLevel(1);
|
||||
module.setCreateTime(System.currentTimeMillis());
|
||||
module.setUpdateTime(System.currentTimeMillis());
|
||||
module.setProjectId(projectId);
|
||||
module.setProjectId(projects.get(0).getId());
|
||||
module.setCreateUser(SessionUtils.getUserId());
|
||||
apiScenarioModuleMapper.insert(module);
|
||||
return module;
|
||||
} else {
|
||||
return list.get(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -327,7 +327,7 @@ export default {
|
|||
this.activeName = name;
|
||||
let currentScenario = {
|
||||
status: 'Underway',
|
||||
principal: getCurrentUser().id,
|
||||
principal: this._getCurrentUserId(),
|
||||
apiScenarioModuleId: 'default-module',
|
||||
id: getUUID(),
|
||||
modulePath: '/' + this.$t('commons.module_title'),
|
||||
|
@ -371,6 +371,17 @@ export default {
|
|||
this.addListener();
|
||||
}
|
||||
},
|
||||
_getCurrentUserId() {
|
||||
const {id, userGroups} = getCurrentUser();
|
||||
if (userGroups) {
|
||||
// 是否是当前项目下的成员
|
||||
let index = userGroups.findIndex(ug => ug.sourceId === getCurrentProjectID());
|
||||
if (index !== -1) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
addListener() {
|
||||
let index = this.tabs.findIndex((item) => item.name === this.activeName); // 找到当前选中tab的index
|
||||
if (index != -1) {
|
||||
|
|
|
@ -14,7 +14,14 @@
|
|||
:closable="!readOnly"
|
||||
:disable-transitions="false"
|
||||
@close="remove(idx)">
|
||||
{{ tag && tag.length > 10 ? tag.substring(0, 10) + '...' : tag }}
|
||||
<span v-if="tag && tag.length > 10">
|
||||
<el-tooltip class="item" effect="light" :content="tag" placement="top" :enterable="false">
|
||||
<span>{{ tag && tag.length > 10 ? tag.substring(0, 10) + "..." : tag }}</span>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ tag }}
|
||||
</span>
|
||||
</el-tag>
|
||||
<input
|
||||
:disabled="readOnly"
|
||||
|
|
|
@ -267,14 +267,14 @@ export default {
|
|||
return (
|
||||
!this.innerStep ||
|
||||
(this.showBtn &&
|
||||
(!this.data.disabled || this.data.root || this.data.isCopy) &&
|
||||
(!this.data.disabled || this.data.root || this.data.isCopy || this.data.showExtend) &&
|
||||
this.showVersion &&
|
||||
this.stepFilter.get('ALlSamplerStep').indexOf(this.data.type) === -1)
|
||||
);
|
||||
}
|
||||
return (
|
||||
this.showBtn &&
|
||||
(!this.data.disabled || this.data.root || this.isDeleted || this.data.isCopy) &&
|
||||
(!this.data.disabled || this.data.root || this.isDeleted || this.data.isCopy || this.data.showExtend) &&
|
||||
this.showVersion &&
|
||||
this.stepFilter.get('ALlSamplerStep').indexOf(this.data.type) === -1
|
||||
);
|
||||
|
|
|
@ -281,6 +281,8 @@ export default {
|
|||
if (this.request.id && this.request.referenced === 'REF') {
|
||||
this.request.disabled = true;
|
||||
this.request.root = this.node.parent.parent ? false : true;
|
||||
this.request.showExtend =
|
||||
this.node.parent && this.node.parent.data && this.node.parent.data.disabled ? false : true;
|
||||
}
|
||||
this.isShowNum = this.request.num ? true : false;
|
||||
if (this.request.protocol === 'HTTP') {
|
||||
|
@ -332,15 +334,7 @@ export default {
|
|||
return {};
|
||||
},
|
||||
isCompReadOnly() {
|
||||
if (this.request) {
|
||||
if (this.request.disabled) {
|
||||
return this.request.disabled;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
displayTitle() {
|
||||
if (this.isApiImport) {
|
||||
|
|
|
@ -156,6 +156,8 @@ export default {
|
|||
if (this.scenario.id && this.scenario.referenced === 'REF' && !this.scenario.loaded && this.scenario.hashTree) {
|
||||
this.scenario.root = this.node.parent.parent ? false : true;
|
||||
this.scenario.disabled = true;
|
||||
this.scenario.showExtend =
|
||||
this.node.parent && this.node.parent.data && this.node.parent.data.disabled ? false : true;
|
||||
this.recursive(this.scenario.hashTree, this.scenario.projectId, true);
|
||||
}
|
||||
if (this.scenario.id && this.scenario.referenced === 'Copy' && !this.scenario.isCopy && !this.scenario.disabled) {
|
||||
|
|
|
@ -178,7 +178,7 @@
|
|||
</span>
|
||||
<span
|
||||
class="ms-step-debug-code"
|
||||
:class="node.data.code === 'ERROR' ? 'ms-req-error' : 'ms-req-success'"
|
||||
:class="node.data.code && node.data.code.toUpperCase() === 'ERROR' ? 'ms-req-error' : 'ms-req-success'"
|
||||
v-if="!loading && !node.data.testing && node.data.debug">
|
||||
{{ getCode() }}
|
||||
</span>
|
||||
|
|
|
@ -659,7 +659,7 @@ export default {
|
|||
name: '',
|
||||
status: 'Underway',
|
||||
method: 'GET',
|
||||
userId: getCurrentUser().id,
|
||||
userId: this._getCurrentUserId(),
|
||||
url: '',
|
||||
protocol: this.currentProtocol,
|
||||
environmentId: '',
|
||||
|
@ -681,6 +681,17 @@ export default {
|
|||
}
|
||||
this.handleTabsEdit(this.$t('api_test.definition.request.title'), e, api);
|
||||
},
|
||||
_getCurrentUserId() {
|
||||
const {id, userGroups} = getCurrentUser();
|
||||
if (userGroups) {
|
||||
// 是否是当前项目下的成员
|
||||
let index = userGroups.findIndex(ug => ug.sourceId === getCurrentProjectID());
|
||||
if (index !== -1) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
handleTabClose() {
|
||||
let tabs = this.apiTabs[0];
|
||||
let message = '';
|
||||
|
|
|
@ -240,7 +240,19 @@ export default {
|
|||
}
|
||||
});
|
||||
if (isNeedCreate) {
|
||||
this.items.push(new KeyValue({ enable: true }));
|
||||
this.items.push(new KeyValue({
|
||||
enable: true,
|
||||
contentType: null,
|
||||
description: null,
|
||||
file: false,
|
||||
files: null,
|
||||
max: null,
|
||||
min: null,
|
||||
required: true,
|
||||
type: null,
|
||||
urlEncode: false,
|
||||
value: null
|
||||
}));
|
||||
}
|
||||
this.$emit('change', this.items);
|
||||
// TODO 检查key重复
|
||||
|
|
|
@ -424,13 +424,20 @@ export default {
|
|||
if (isNeedCreate) {
|
||||
this.parameters.push(
|
||||
new KeyValue({
|
||||
type: 'text',
|
||||
contentType: 'text/plain',
|
||||
description: null,
|
||||
enable: true,
|
||||
file: false,
|
||||
files: null,
|
||||
isEdit: false,
|
||||
max: null,
|
||||
min: null,
|
||||
required: false,
|
||||
type: 'text',
|
||||
urlEncode: this.urlEncode,
|
||||
uuid: this.uuid(),
|
||||
required: false,
|
||||
isEdit: false,
|
||||
contentType: 'text/plain',
|
||||
valid: false,
|
||||
value: null
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -520,13 +527,20 @@ export default {
|
|||
if (this.parameters.length === 0 || this.parameters[this.parameters.length - 1].name) {
|
||||
this.parameters.push(
|
||||
new KeyValue({
|
||||
type: 'text',
|
||||
contentType: 'text/plain',
|
||||
description: null,
|
||||
enable: true,
|
||||
file: false,
|
||||
files: null,
|
||||
isEdit: false,
|
||||
max: null,
|
||||
min: null,
|
||||
required: false,
|
||||
type: 'text',
|
||||
urlEncode: this.urlEncode,
|
||||
uuid: this.uuid(),
|
||||
isEdit: false,
|
||||
contentType: 'text/plain',
|
||||
valid: false,
|
||||
value: null
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
:api-template="apiTemplate"
|
||||
@validateBasic="validateBasic" />
|
||||
</div>
|
||||
<div v-else-if="showTest">
|
||||
<div v-show="showTest">
|
||||
<ms-run-test-http-page
|
||||
:syncTabs="syncTabs"
|
||||
:currentProtocol="currentProtocol"
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
:placeholder="$t('api_test.definition.request.run_env')"
|
||||
clearable
|
||||
filterable
|
||||
@click.native="refreshEnv"
|
||||
@clear="clear">
|
||||
<el-option
|
||||
v-for="(environment, key) in environments"
|
||||
|
@ -66,6 +67,9 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
refreshEnv() {
|
||||
this.getEnvironments();
|
||||
},
|
||||
refreshEnvironment() {
|
||||
this.$emit('setEnvironment', this.environment);
|
||||
},
|
||||
|
|
|
@ -149,91 +149,15 @@
|
|||
</ms-dialog-footer>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
:visible.sync="batchSyncApiVisible"
|
||||
:title="$t('commons.save') + '&' + $t('workstation.sync') + $t('commons.setting')"
|
||||
v-if="isXpack">
|
||||
<el-row style="margin-bottom: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)">
|
||||
<div class="timeClass">
|
||||
<span style="font-size: 16px; font-weight: bold; padding-left: 10px">{{
|
||||
$t('api_test.definition.one_click_sync') + 'case'
|
||||
}}</span>
|
||||
<el-switch v-model="apiSyncRuleRelation.syncCase" style="padding-right: 10px"></el-switch>
|
||||
</div>
|
||||
<br />
|
||||
<span style="font-size: 12px; padding-left: 10px">{{ $t('workstation.batch_sync_api_tips') }}</span
|
||||
><br /><br />
|
||||
<span v-if="apiSyncRuleRelation.syncCase" style="font-size: 16px; font-weight: bold; padding-left: 10px">
|
||||
{{ $t('workstation.sync') + $t('commons.setting') }}
|
||||
<i class="el-icon-arrow-down" v-if="showApiSyncConfig" @click="showApiSyncConfig = false" />
|
||||
<i class="el-icon-arrow-right" v-if="!showApiSyncConfig" @click="showApiSyncConfig = true" /> </span
|
||||
><br /><br />
|
||||
<div v-if="showApiSyncConfig">
|
||||
<sync-setting
|
||||
style="padding-left: 20px"
|
||||
v-if="apiSyncRuleRelation.syncCase"
|
||||
v-bind:sync-data="apiSyncRuleRelation.apiSyncConfig"
|
||||
ref="synSetting"
|
||||
@updateSyncData="updateSyncData"></sync-setting>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row style="margin-bottom: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)">
|
||||
<div class="timeClass">
|
||||
<span style="font-size: 16px; font-weight: bold; padding-left: 10px">
|
||||
{{ $t('api_test.definition.change_notification') }}
|
||||
<el-tooltip
|
||||
class="ms-num"
|
||||
effect="dark"
|
||||
:content="$t('project_application.workstation.api_receiver_tip')"
|
||||
placement="top">
|
||||
<i class="el-icon-warning" />
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<el-switch v-model="apiSyncRuleRelation.sendNotice" style="padding-right: 10px"></el-switch>
|
||||
</div>
|
||||
<span style="font-size: 12px; padding-left: 10px"> {{ $t('api_test.definition.recipient_tips') }} </span><br />
|
||||
<p
|
||||
style="
|
||||
font-size: 12px;
|
||||
color: var(--primary_color);
|
||||
margin-bottom: 20px;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
padding-left: 10px;
|
||||
"
|
||||
@click="gotoApiMessage">
|
||||
{{ $t('project_application.workstation.go_to_api_message') }}
|
||||
</p>
|
||||
<el-row v-if="apiSyncRuleRelation.sendNotice" style="margin-bottom: 5px; margin-top: 5px">
|
||||
<el-col :span="4"
|
||||
><span style="font-weight: bold; padding-left: 10px">{{ $t('api_test.definition.recipient') + ':' }}</span>
|
||||
</el-col>
|
||||
<el-col :span="20" style="color: var(--primary_color)">
|
||||
<el-checkbox v-model="apiSyncRuleRelation.caseCreator">{{ 'CASE' + $t('api_test.creator') }}</el-checkbox>
|
||||
<el-checkbox v-model="apiSyncRuleRelation.scenarioCreator">
|
||||
{{ $t('commons.scenario') + $t('api_test.creator') }}
|
||||
</el-checkbox>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-checkbox v-model="apiSyncRuleRelation.showUpdateRule" style="padding-left: 10px"
|
||||
>{{ $t('project_application.workstation.no_show_setting') }}
|
||||
</el-checkbox>
|
||||
<el-tooltip
|
||||
class="ms-num"
|
||||
effect="dark"
|
||||
:content="$t('project_application.workstation.no_show_setting_tip')"
|
||||
placement="top">
|
||||
<i class="el-icon-warning" />
|
||||
</el-tooltip>
|
||||
</el-row>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="batchSyncApiVisible = false">{{ $t('commons.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="batchSync()">{{ $t('commons.confirm') }}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<api-sync-case-config
|
||||
:is-xpack="isXpack"
|
||||
:api-sync-rule-relation="apiSyncRuleRelation"
|
||||
:batch-sync-api-visible="batchSyncApiVisible"
|
||||
:show-api-sync-config="true"
|
||||
@batchSync="batchSync"
|
||||
ref="syncCaseConfig"
|
||||
>
|
||||
</api-sync-case-config>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -269,11 +193,10 @@ import {createComponent} from '.././jmeter/components';
|
|||
import {TYPE_TO_C} from '@/business/automation/scenario/Setting';
|
||||
import MsDialogFooter from 'metersphere-frontend/src/components/MsDialogFooter';
|
||||
import {getProjectMemberOption} from '@/api/project';
|
||||
import {deepClone} from 'metersphere-frontend/src/utils/tableUtils';
|
||||
import {getDefaultVersion, setLatestVersionById} from 'metersphere-frontend/src/api/version';
|
||||
|
||||
import SyncSetting from '@/business/definition/util/SyncSetting';
|
||||
import {useApiStore} from '@/store';
|
||||
import ApiSyncCaseConfig from "@/business/definition/components/sync/ApiSyncCaseConfig";
|
||||
|
||||
const {Body} = require('@/business/definition/model/ApiTestModel');
|
||||
const Sampler = require('@/business/definition/components/jmeter/components/sampler/sampler');
|
||||
|
@ -294,7 +217,7 @@ export default {
|
|||
MsSelectTree,
|
||||
MsChangeHistory,
|
||||
HttpApiVersionDiff,
|
||||
SyncSetting,
|
||||
ApiSyncCaseConfig
|
||||
},
|
||||
data() {
|
||||
let validateURL = (rule, value, callback) => {
|
||||
|
@ -377,7 +300,6 @@ export default {
|
|||
createNewVersionVisible: false,
|
||||
batchSyncApiVisible: false,
|
||||
isXpack: false,
|
||||
showApiSyncConfig: true,
|
||||
apiSyncRuleRelation: {
|
||||
caseCreator: true,
|
||||
scenarioCreator: true,
|
||||
|
@ -555,7 +477,6 @@ export default {
|
|||
this.$refs['httpForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.setParameter();
|
||||
|
||||
if (!this.httpForm.versionId) {
|
||||
if (this.$refs.versionHistory && this.$refs.versionHistory.currentVersion) {
|
||||
this.httpForm.versionId = this.$refs.versionHistory.currentVersion.id;
|
||||
|
@ -564,76 +485,214 @@ export default {
|
|||
if (hasLicense() && (this.httpForm.caseTotal > 0 || this.citedScenarioCount > 0) && !this.httpForm.isCopy) {
|
||||
if (this.httpForm.method !== this.beforeHttpForm.method && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
if (this.httpForm.path !== this.beforeHttpForm.path && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
if (this.httpForm.request.headers && this.beforeRequest.headers) {
|
||||
for (let i = 0; i < this.httpForm.request.headers.length; i++) {
|
||||
if (this.httpForm.request.headers[i].isEdit !== undefined) {
|
||||
this.beforeRequest.headers[i].isEdit = this.httpForm.request.headers[i].isEdit
|
||||
if (this.request.headers && this.beforeRequest.headers) {
|
||||
if (this.request.headers.length === this.beforeRequest.headers.length) {
|
||||
let requestHeaders = [];
|
||||
let beforeHeaders = [];
|
||||
for (let i = 0; i < this.request.headers.length; i++) {
|
||||
this.beforeRequest.headers[i].valid = this.request.headers[i].valid
|
||||
if (this.request.headers[i].isEdit !== undefined) {
|
||||
this.beforeRequest.headers[i].isEdit = this.request.headers[i].isEdit
|
||||
}
|
||||
if (this.request.headers[i].uuid) {
|
||||
this.beforeRequest.headers[i].uuid = this.request.headers[i].uuid
|
||||
}
|
||||
let submitRequestHeaders = JSON.stringify(this.httpForm.request.headers);
|
||||
if (this.request.headers[i].time) {
|
||||
this.beforeRequest.headers[i].time = this.request.headers[i].time
|
||||
}
|
||||
if (this.request.headers[i].name === undefined) {
|
||||
this.beforeRequest.headers[i].name = undefined
|
||||
}
|
||||
let newRequest = this.request.headers[i];
|
||||
const ordered = {};
|
||||
Object.keys(newRequest).sort().forEach(function (key) {
|
||||
ordered[key] = newRequest[key];
|
||||
});
|
||||
requestHeaders.push(ordered);
|
||||
let beforeRequest = this.beforeRequest.headers[i];
|
||||
const beforeOrdered = {};
|
||||
Object.keys(beforeRequest).sort().forEach(function (key) {
|
||||
beforeOrdered[key] = beforeRequest[key];
|
||||
});
|
||||
beforeHeaders.push(beforeOrdered)
|
||||
}
|
||||
|
||||
let submitRequestHeaders = JSON.stringify(requestHeaders);
|
||||
let beforeRequestHeaders = JSON.stringify(beforeHeaders);
|
||||
if (submitRequestHeaders !== beforeRequestHeaders && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
} else {
|
||||
let submitRequestHeaders = JSON.stringify(this.request.headers);
|
||||
let beforeRequestHeaders = JSON.stringify(this.beforeRequest.headers);
|
||||
if (submitRequestHeaders !== beforeRequestHeaders && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
if (this.httpForm.request.arguments && this.beforeRequest.arguments) {
|
||||
for (let i = 0; i < this.httpForm.request.arguments.length; i++) {
|
||||
if (this.httpForm.request.arguments[i].isEdit !== undefined) {
|
||||
this.beforeRequest.arguments[i].isEdit = this.httpForm.request.arguments[i].isEdit
|
||||
}
|
||||
if (this.request.arguments && this.beforeRequest.arguments) {
|
||||
if (this.request.arguments.length === this.beforeRequest.arguments.length) {
|
||||
let requestArguments = [];
|
||||
let beforeArguments = [];
|
||||
for (let i = 0; i < this.request.arguments.length; i++) {
|
||||
if (this.request.arguments[i].isEdit !== undefined) {
|
||||
this.beforeRequest.arguments[i].isEdit = this.request.arguments[i].isEdit
|
||||
}
|
||||
let submitRequestQuery = JSON.stringify(this.httpForm.request.arguments);
|
||||
if (this.request.arguments[i].uuid) {
|
||||
this.beforeRequest.arguments[i].uuid = this.request.arguments[i].uuid
|
||||
}
|
||||
if (this.request.arguments[i].time) {
|
||||
this.beforeRequest.arguments[i].time = this.request.arguments[i].time
|
||||
}
|
||||
if (this.request.arguments[i].name === undefined) {
|
||||
this.beforeRequest.arguments[i].name = undefined
|
||||
}
|
||||
this.beforeRequest.arguments[i].valid = this.request.arguments[i].valid
|
||||
let newRequest = this.request.arguments[i];
|
||||
const ordered = {};
|
||||
Object.keys(newRequest).sort().forEach(function (key) {
|
||||
ordered[key] = newRequest[key];
|
||||
});
|
||||
requestArguments.push(ordered);
|
||||
let beforeRequest = this.beforeRequest.arguments[i];
|
||||
const beforeOrdered = {};
|
||||
Object.keys(beforeRequest).sort().forEach(function (key) {
|
||||
beforeOrdered[key] = beforeRequest[key];
|
||||
});
|
||||
beforeArguments.push(beforeOrdered)
|
||||
}
|
||||
let submitRequestQuery = JSON.stringify(requestArguments);
|
||||
let beforeRequestQuery = JSON.stringify(beforeArguments);
|
||||
if (submitRequestQuery !== beforeRequestQuery && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
} else {
|
||||
let submitRequestQuery = JSON.stringify(this.request.arguments);
|
||||
let beforeRequestQuery = JSON.stringify(this.beforeRequest.arguments);
|
||||
if (submitRequestQuery !== beforeRequestQuery && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
if (this.httpForm.request.rest && this.beforeRequest.rest) {
|
||||
for (let i = 0; i < this.httpForm.request.rest.length; i++) {
|
||||
if (this.httpForm.request.rest[i].isEdit !== undefined) {
|
||||
this.beforeRequest.rest[i].isEdit = this.httpForm.request.rest[i].isEdit
|
||||
}
|
||||
if (this.request.rest && this.beforeRequest.rest) {
|
||||
if (this.request.rest.length === this.beforeRequest.rest.length) {
|
||||
let requestRest = [];
|
||||
let beforeRest = [];
|
||||
for (let i = 0; i < this.request.rest.length; i++) {
|
||||
if (this.request.rest[i].isEdit !== undefined) {
|
||||
this.beforeRequest.rest[i].isEdit = this.request.rest[i].isEdit
|
||||
}
|
||||
let submitRequestRest = JSON.stringify(this.httpForm.request.rest);
|
||||
if (this.request.rest[i].uuid) {
|
||||
this.beforeRequest.rest[i].uuid = this.request.rest[i].uuid
|
||||
}
|
||||
if (this.request.rest[i].time) {
|
||||
this.beforeRequest.rest[i].time = this.request.rest[i].time
|
||||
}
|
||||
if (this.request.rest[i].name === undefined) {
|
||||
this.beforeRequest.rest[i].name = undefined
|
||||
}
|
||||
this.beforeRequest.rest[i].valid = this.request.rest[i].valid
|
||||
|
||||
let newRequest = this.request.rest[i];
|
||||
const ordered = {};
|
||||
Object.keys(newRequest).sort().forEach(function (key) {
|
||||
ordered[key] = newRequest[key];
|
||||
});
|
||||
requestRest.push(ordered);
|
||||
let beforeRequest = this.beforeRequest.rest[i];
|
||||
const beforeOrdered = {};
|
||||
Object.keys(beforeRequest).sort().forEach(function (key) {
|
||||
beforeOrdered[key] = beforeRequest[key];
|
||||
});
|
||||
beforeRest.push(beforeOrdered)
|
||||
}
|
||||
let submitRequestRest = JSON.stringify(requestRest);
|
||||
let beforeRequestRest = JSON.stringify(beforeRest);
|
||||
if (submitRequestRest !== beforeRequestRest && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
} else {
|
||||
let submitRequestRest = JSON.stringify(this.request.rest);
|
||||
let beforeRequestRest = JSON.stringify(this.beforeRequest.rest);
|
||||
if (submitRequestRest !== beforeRequestRest && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
if (this.httpForm.request.body && this.beforeRequest.body) {
|
||||
let submitRequestBody = JSON.stringify(this.httpForm.request.body);
|
||||
}
|
||||
if (this.request.body && this.beforeRequest.body) {
|
||||
if (this.request.body.valid) {
|
||||
this.beforeRequest.body.valid = this.request.body.valid
|
||||
}
|
||||
if (this.request.body.kvs.length === this.beforeRequest.body.kvs.length) {
|
||||
let requestKvs = [];
|
||||
let beforeKvs = [];
|
||||
for (let i = 0; i < this.request.body.kvs.length; i++) {
|
||||
if (this.request.body.kvs[i].isEdit !== undefined) {
|
||||
this.beforeRequest.body.kvs[i].isEdit = this.request.body.kvs[i].isEdit
|
||||
}
|
||||
if (this.request.body.kvs[i].files !== null && this.request.body.kvs[i].files.length === 0) {
|
||||
this.beforeRequest.body.kvs[i].files = this.request.body.kvs[i].files
|
||||
}
|
||||
if (this.request.body.kvs[i].uuid) {
|
||||
this.beforeRequest.body.kvs[i].uuid = this.request.body.kvs[i].uuid
|
||||
}
|
||||
if (this.request.body.kvs[i].time) {
|
||||
this.beforeRequest.body.kvs[i].time = this.request.body.kvs[i].time
|
||||
}
|
||||
if (this.request.body.kvs[i].name === undefined) {
|
||||
this.beforeRequest.body.kvs[i].name = undefined
|
||||
}
|
||||
this.beforeRequest.body.kvs[i].valid = this.request.body.kvs[i].valid
|
||||
|
||||
let newRequest = this.request.body.kvs[i];
|
||||
const ordered = {};
|
||||
Object.keys(newRequest).sort().forEach(function (key) {
|
||||
ordered[key] = newRequest[key];
|
||||
});
|
||||
requestKvs.push(ordered);
|
||||
let beforeRequest = this.request.body.kvs[i];
|
||||
const beforeOrdered = {};
|
||||
Object.keys(beforeRequest).sort().forEach(function (key) {
|
||||
beforeOrdered[key] = beforeRequest[key];
|
||||
});
|
||||
beforeKvs.push(beforeOrdered)
|
||||
}
|
||||
this.request.body.kvs = requestKvs;
|
||||
this.beforeRequest.body.kvs = beforeKvs
|
||||
}
|
||||
let submitRequestBody = JSON.stringify(this.request.body);
|
||||
let beforeRequestBody = JSON.stringify(this.beforeRequest.body);
|
||||
for (let i = 0; i < this.httpForm.request.body.kvs.length; i++) {
|
||||
if (this.httpForm.request.body.kvs[i].isEdit !== undefined) {
|
||||
this.beforeRequest.body.kvs[i].isEdit = this.httpForm.request.body.kvs[i].isEdit
|
||||
}
|
||||
if (this.httpForm.request.body.kvs[i].files !== null && this.httpForm.request.body.kvs[i].files.length === 0) {
|
||||
this.beforeRequest.body.kvs[i].files = this.httpForm.request.body.kvs[i].files
|
||||
}
|
||||
if (this.httpForm.request.body.kvs[i].uuid) {
|
||||
this.beforeRequest.body.kvs[i].uuid = this.httpForm.request.body.kvs[i].uuid
|
||||
}
|
||||
}
|
||||
if (submitRequestBody !== beforeRequestBody && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
if (this.httpForm.request.authManager && this.beforeRequest.authManager) {
|
||||
let submitRequestAuthManager = JSON.stringify(this.httpForm.request.authManager);
|
||||
if (this.request.authManager && this.beforeRequest.authManager) {
|
||||
let submitRequestAuthManager = JSON.stringify(this.request.authManager);
|
||||
let beforeRequestAuthManager = JSON.stringify(this.beforeRequest.authManager);
|
||||
if (submitRequestAuthManager !== beforeRequestAuthManager && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
if (this.httpForm.request.hashTree && this.beforeRequest.hashTree) {
|
||||
let submitRequestHashTree = JSON.stringify(this.httpForm.request.hashTree);
|
||||
if (this.request.hashTree && this.beforeRequest.hashTree) {
|
||||
let submitRequestHashTree = JSON.stringify(this.request.hashTree);
|
||||
let beforeRequestHashTree = JSON.stringify(this.beforeRequest.hashTree);
|
||||
if (submitRequestHashTree !== beforeRequestHashTree && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
if (
|
||||
|
@ -645,10 +704,12 @@ export default {
|
|||
!this.noShowSyncRuleRelation
|
||||
) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
if (this.batchSyncApiVisible !== true) {
|
||||
this.$emit('saveApi', this.httpForm);
|
||||
}
|
||||
|
||||
} else {
|
||||
this.$emit('saveApi', this.httpForm);
|
||||
}
|
||||
|
@ -660,16 +721,10 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
batchSync() {
|
||||
batchSync(fromData) {
|
||||
if (hasLicense() && (this.httpForm.caseTotal > 0 || this.citedScenarioCount > 0) && !this.httpForm.isCopy) {
|
||||
if (this.$refs.synSetting && this.$refs.synSetting.fromData) {
|
||||
let fromData = this.$refs.synSetting.fromData;
|
||||
fromData.method = true;
|
||||
fromData.path = true;
|
||||
fromData.protocol = true;
|
||||
this.httpForm.triggerUpdate = JSON.stringify(fromData);
|
||||
this.apiSyncRuleRelation.apiSyncCaseRequest = JSON.stringify(fromData);
|
||||
}
|
||||
if (this.apiSyncRuleRelation.sendNotice && this.apiSyncRuleRelation.sendNotice === true) {
|
||||
this.httpForm.sendSpecialMessage = this.apiSyncRuleRelation.sendNotice;
|
||||
} else {
|
||||
|
@ -694,7 +749,7 @@ export default {
|
|||
saveApiSyncRuleRelation(apiSyncRuleRelation) {
|
||||
updateRuleRelation(apiSyncRuleRelation.resourceId, apiSyncRuleRelation).then(() => {
|
||||
this.$emit('saveApi', this.httpForm);
|
||||
this.batchSyncApiVisible = false;
|
||||
this.$refs.syncCaseConfig.close();
|
||||
});
|
||||
},
|
||||
createModules() {
|
||||
|
@ -1019,12 +1074,6 @@ export default {
|
|||
this.checkout(row);
|
||||
});
|
||||
},
|
||||
gotoApiMessage() {
|
||||
let apiResolve = this.$router.resolve({
|
||||
path: '/project/messagesettings',
|
||||
});
|
||||
window.open(apiResolve.href, '_blank');
|
||||
},
|
||||
getSyncRule() {
|
||||
relationGet(this.httpForm.id, 'API').then((response) => {
|
||||
if (response.data) {
|
||||
|
@ -1051,9 +1100,6 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
updateSyncData(value) {
|
||||
this.apiSyncRuleRelation.apiSyncConfig = value;
|
||||
},
|
||||
handleCommand(command) {
|
||||
if (command === 'openSyncRule') {
|
||||
this.noShowSyncRuleRelation = false;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
:destroy-on-close="true">
|
||||
<div class="header-bar">
|
||||
<div>{{ $t('api_test.api_import.data_format') }}</div>
|
||||
<el-radio-group v-model="selectedPlatformValue">
|
||||
<el-radio-group v-model="selectedPlatformValue" @input="clearUrParameter">
|
||||
<span v-for="(item, index) in platforms" :key="index">
|
||||
<el-radio v-if="!isScenarioModel || item.name != 'Swagger'" :label="item.value">{{ item.name }}</el-radio>
|
||||
</span>
|
||||
|
@ -476,6 +476,12 @@ export default {
|
|||
this.clearAuthInfo();
|
||||
}
|
||||
},
|
||||
clearUrParameter(value) {
|
||||
if (value !== 'Swagger2') {
|
||||
this.clearAuthInfo();
|
||||
this.authEnable = false;
|
||||
}
|
||||
},
|
||||
buildParam() {
|
||||
let param = {};
|
||||
Object.assign(param, this.formData);
|
||||
|
|
|
@ -513,6 +513,7 @@ export default {
|
|||
if (item) {
|
||||
let line = item.split(/:|:/);
|
||||
let values = item.split(line[0] + ':');
|
||||
|
||||
let required = false;
|
||||
keyValues.push(
|
||||
new KeyValue({
|
||||
|
@ -525,6 +526,7 @@ export default {
|
|||
encode: true,
|
||||
enable: true,
|
||||
contentType: 'text/plain',
|
||||
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -335,7 +335,7 @@ export default {
|
|||
this.currentRequest = this.api.request;
|
||||
this.runLoading = false;
|
||||
this.getEnvironments();
|
||||
getLastResultDetail(this.api.id, this);
|
||||
//getLastResultDetail(this.api.id, this);
|
||||
this.checkVersionEnable();
|
||||
},
|
||||
};
|
||||
|
|
|
@ -81,7 +81,14 @@
|
|||
<ms-request-result-tail :response="responseData" ref="runResult" />
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<api-sync-case-config
|
||||
:is-xpack="isXpack"
|
||||
:api-sync-rule-relation="apiSyncRuleRelation"
|
||||
:batch-sync-api-visible="batchSyncApiVisible"
|
||||
:show-api-sync-config="true"
|
||||
@batchSync="batchSync"
|
||||
ref="syncCaseConfig">
|
||||
</api-sync-case-config>
|
||||
<!-- 加载用例 -->
|
||||
<ms-api-case-list
|
||||
@selectTestCase="selectTestCase"
|
||||
|
@ -106,9 +113,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { getMockEnvironment, updateDefinition } from '@/api/definition';
|
||||
import { citedApiScenarioCount, getDefinitionVersions, getMockEnvironment, updateDefinition } from '@/api/definition';
|
||||
import { getLastResultDetail } from '@/api/definition-report';
|
||||
import { versionEnableByProjectId } from '@/api/xpack';
|
||||
import { relationGet, updateRuleRelation, versionEnableByProjectId } from '@/api/xpack';
|
||||
import MsApiRequestForm from '../request/http/ApiHttpRequestForm';
|
||||
import { hasLicense, hasPermission } from 'metersphere-frontend/src/utils/permission';
|
||||
import { getUUID } from 'metersphere-frontend/src/utils';
|
||||
|
@ -122,6 +129,9 @@ import { TYPE_TO_C } from '@/business/automation/scenario/Setting';
|
|||
import { mergeRequestDocumentData } from '@/business/definition/api-definition';
|
||||
import { execStop } from '@/api/scenario';
|
||||
import { useApiStore } from '@/store';
|
||||
import { apiTestCaseCount } from '@/api/api-test-case';
|
||||
import ApiSyncCaseConfig from '@/business/definition/components/sync/ApiSyncCaseConfig';
|
||||
import { deepClone } from 'metersphere-frontend/src/utils/tableUtils';
|
||||
|
||||
const store = useApiStore();
|
||||
export default {
|
||||
|
@ -133,6 +143,7 @@ export default {
|
|||
MsContainer,
|
||||
MsRequestResultTail,
|
||||
MsRun,
|
||||
ApiSyncCaseConfig,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -168,6 +179,22 @@ export default {
|
|||
envMap: new Map(),
|
||||
runLoading: false,
|
||||
versionEnable: false,
|
||||
beforeHttpForm: { environmentId: '', path: '', tags: [] },
|
||||
beforeRequest: { arguments: [] },
|
||||
beforeResponse: {},
|
||||
citedScenarioCount: 0,
|
||||
apiSyncRuleRelation: {
|
||||
caseCreator: true,
|
||||
scenarioCreator: true,
|
||||
showUpdateRule: false,
|
||||
apiSyncCaseRequest: '',
|
||||
apiSyncConfig: {},
|
||||
syncCase: true,
|
||||
sendNotice: true,
|
||||
},
|
||||
noShowSyncRuleRelation: false,
|
||||
batchSyncApiVisible: false,
|
||||
isXpack: false,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
|
@ -188,6 +215,11 @@ export default {
|
|||
storeUseEnvironment: function () {
|
||||
this.api.environmentId = store.useEnvironment;
|
||||
},
|
||||
batchSyncApiVisible() {
|
||||
if (!this.batchSyncApiVisible && this.apiSyncRuleRelation.showUpdateRule) {
|
||||
this.noShowSyncRuleRelation = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
hasPermission,
|
||||
|
@ -390,11 +422,257 @@ export default {
|
|||
if (this.api.tags instanceof Array) {
|
||||
this.api.tags = JSON.stringify(this.api.tags);
|
||||
}
|
||||
if (this.beforeHttpForm) {
|
||||
if (this.beforeHttpForm.tags instanceof Array) {
|
||||
this.beforeHttpForm.tags = JSON.stringify(this.beforeHttpForm.tags);
|
||||
}
|
||||
}
|
||||
// 历史数据兼容处理
|
||||
if (this.api.request) {
|
||||
this.api.request.clazzName = TYPE_TO_C.get(this.api.request.type);
|
||||
this.compatibleHistory(this.api.request.hashTree);
|
||||
}
|
||||
if (hasLicense() && (this.api.caseTotal > 0 || this.citedScenarioCount > 0)) {
|
||||
if (this.api.method !== this.beforeHttpForm.method && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
if (this.api.path !== this.beforeHttpForm.path && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
if (this.api.request.headers && this.beforeRequest.headers) {
|
||||
if (this.api.request.headers.length === this.beforeRequest.headers.length) {
|
||||
let requestHeaders = [];
|
||||
let beforeHeaders = [];
|
||||
for (let i = 0; i < this.api.request.headers.length; i++) {
|
||||
this.beforeRequest.headers[i].valid = this.api.request.headers[i].valid;
|
||||
if (this.api.request.headers[i].isEdit !== undefined) {
|
||||
this.beforeRequest.headers[i].isEdit = this.api.request.headers[i].isEdit;
|
||||
}
|
||||
if (this.api.request.headers[i].uuid) {
|
||||
this.beforeRequest.headers[i].uuid = this.api.request.headers[i].uuid;
|
||||
}
|
||||
if (this.api.request.headers[i].time) {
|
||||
this.beforeRequest.headers[i].time = this.api.request.headers[i].time;
|
||||
}
|
||||
if (this.api.request.headers[i].name === undefined) {
|
||||
this.beforeRequest.headers[i].name = undefined;
|
||||
}
|
||||
let newRequest = this.api.request.headers[i];
|
||||
const ordered = {};
|
||||
Object.keys(newRequest)
|
||||
.sort()
|
||||
.forEach(function (key) {
|
||||
ordered[key] = newRequest[key];
|
||||
});
|
||||
requestHeaders.push(ordered);
|
||||
let beforeRequest = this.beforeRequest.headers[i];
|
||||
const beforeOrdered = {};
|
||||
Object.keys(beforeRequest)
|
||||
.sort()
|
||||
.forEach(function (key) {
|
||||
beforeOrdered[key] = beforeRequest[key];
|
||||
});
|
||||
beforeHeaders.push(beforeOrdered);
|
||||
}
|
||||
|
||||
let submitRequestHeaders = JSON.stringify(requestHeaders);
|
||||
let beforeRequestHeaders = JSON.stringify(beforeHeaders);
|
||||
if (submitRequestHeaders !== beforeRequestHeaders && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
} else {
|
||||
let submitRequestHeaders = JSON.stringify(this.api.request.headers);
|
||||
let beforeRequestHeaders = JSON.stringify(this.beforeRequest.headers);
|
||||
if (submitRequestHeaders !== beforeRequestHeaders && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.api.request.arguments && this.beforeRequest.arguments) {
|
||||
if (this.api.request.arguments.length === this.beforeRequest.arguments.length) {
|
||||
let requestArguments = [];
|
||||
let beforeArguments = [];
|
||||
for (let i = 0; i < this.api.request.arguments.length; i++) {
|
||||
if (this.api.request.arguments[i].isEdit !== undefined) {
|
||||
this.beforeRequest.arguments[i].isEdit = this.api.request.arguments[i].isEdit;
|
||||
}
|
||||
if (this.api.request.arguments[i].uuid) {
|
||||
this.beforeRequest.arguments[i].uuid = this.api.request.arguments[i].uuid;
|
||||
}
|
||||
if (this.api.request.arguments[i].time) {
|
||||
this.beforeRequest.arguments[i].time = this.api.request.arguments[i].time;
|
||||
}
|
||||
if (this.api.request.arguments[i].name === undefined) {
|
||||
this.beforeRequest.arguments[i].name = undefined;
|
||||
}
|
||||
this.beforeRequest.arguments[i].valid = this.api.request.arguments[i].valid;
|
||||
let newRequest = this.api.request.arguments[i];
|
||||
const ordered = {};
|
||||
Object.keys(newRequest)
|
||||
.sort()
|
||||
.forEach(function (key) {
|
||||
ordered[key] = newRequest[key];
|
||||
});
|
||||
requestArguments.push(ordered);
|
||||
let beforeRequest = this.beforeRequest.arguments[i];
|
||||
const beforeOrdered = {};
|
||||
Object.keys(beforeRequest)
|
||||
.sort()
|
||||
.forEach(function (key) {
|
||||
beforeOrdered[key] = beforeRequest[key];
|
||||
});
|
||||
beforeArguments.push(beforeOrdered);
|
||||
}
|
||||
let submitRequestQuery = JSON.stringify(requestArguments);
|
||||
let beforeRequestQuery = JSON.stringify(beforeArguments);
|
||||
if (submitRequestQuery !== beforeRequestQuery && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
} else {
|
||||
let submitRequestQuery = JSON.stringify(this.api.request.arguments);
|
||||
let beforeRequestQuery = JSON.stringify(this.beforeRequest.arguments);
|
||||
if (submitRequestQuery !== beforeRequestQuery && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.api.request.rest && this.beforeRequest.rest) {
|
||||
if (this.api.request.rest.length === this.beforeRequest.rest.length) {
|
||||
let requestRest = [];
|
||||
let beforeRest = [];
|
||||
for (let i = 0; i < this.api.request.rest.length; i++) {
|
||||
if (this.api.request.rest[i].isEdit !== undefined) {
|
||||
this.beforeRequest.rest[i].isEdit = this.api.request.rest[i].isEdit;
|
||||
}
|
||||
if (this.api.request.rest[i].uuid) {
|
||||
this.beforeRequest.rest[i].uuid = this.api.request.rest[i].uuid;
|
||||
}
|
||||
if (this.api.request.rest[i].time) {
|
||||
this.beforeRequest.rest[i].time = this.api.request.rest[i].time;
|
||||
}
|
||||
if (this.api.request.rest[i].name === undefined) {
|
||||
this.beforeRequest.rest[i].name = undefined;
|
||||
}
|
||||
this.beforeRequest.rest[i].valid = this.api.request.rest[i].valid;
|
||||
|
||||
let newRequest = this.api.request.rest[i];
|
||||
const ordered = {};
|
||||
Object.keys(newRequest)
|
||||
.sort()
|
||||
.forEach(function (key) {
|
||||
ordered[key] = newRequest[key];
|
||||
});
|
||||
requestRest.push(ordered);
|
||||
let beforeRequest = this.beforeRequest.rest[i];
|
||||
const beforeOrdered = {};
|
||||
Object.keys(beforeRequest)
|
||||
.sort()
|
||||
.forEach(function (key) {
|
||||
beforeOrdered[key] = beforeRequest[key];
|
||||
});
|
||||
beforeRest.push(beforeOrdered);
|
||||
}
|
||||
let submitRequestRest = JSON.stringify(requestRest);
|
||||
let beforeRequestRest = JSON.stringify(beforeRest);
|
||||
if (submitRequestRest !== beforeRequestRest && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
} else {
|
||||
let submitRequestRest = JSON.stringify(this.api.request.rest);
|
||||
let beforeRequestRest = JSON.stringify(this.beforeRequest.rest);
|
||||
if (submitRequestRest !== beforeRequestRest && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.api.request.body && this.beforeRequest.body) {
|
||||
if (this.api.request.body.valid) {
|
||||
this.beforeRequest.body.valid = this.api.request.body.valid;
|
||||
}
|
||||
if (this.api.request.body.kvs.length === this.beforeRequest.body.kvs.length) {
|
||||
let requestKvs = [];
|
||||
let beforeKvs = [];
|
||||
for (let i = 0; i < this.api.request.body.kvs.length; i++) {
|
||||
if (this.api.request.body.kvs[i].isEdit !== undefined) {
|
||||
this.beforeRequest.body.kvs[i].isEdit = this.api.request.body.kvs[i].isEdit;
|
||||
}
|
||||
if (this.api.request.body.kvs[i].files !== null && this.api.request.body.kvs[i].files.length === 0) {
|
||||
this.beforeRequest.body.kvs[i].files = this.api.request.body.kvs[i].files;
|
||||
}
|
||||
if (this.api.request.body.kvs[i].uuid) {
|
||||
this.beforeRequest.body.kvs[i].uuid = this.api.request.body.kvs[i].uuid;
|
||||
}
|
||||
if (this.api.request.body.kvs[i].time) {
|
||||
this.beforeRequest.body.kvs[i].time = this.api.request.body.kvs[i].time;
|
||||
}
|
||||
if (this.api.request.body.kvs[i].name === undefined) {
|
||||
this.beforeRequest.body.kvs[i].name = undefined;
|
||||
}
|
||||
this.beforeRequest.body.kvs[i].valid = this.api.request.body.kvs[i].valid;
|
||||
|
||||
let newRequest = this.api.request.body.kvs[i];
|
||||
const ordered = {};
|
||||
Object.keys(newRequest)
|
||||
.sort()
|
||||
.forEach(function (key) {
|
||||
ordered[key] = newRequest[key];
|
||||
});
|
||||
requestKvs.push(ordered);
|
||||
let beforeRequest = this.api.request.body.kvs[i];
|
||||
const beforeOrdered = {};
|
||||
Object.keys(beforeRequest)
|
||||
.sort()
|
||||
.forEach(function (key) {
|
||||
beforeOrdered[key] = beforeRequest[key];
|
||||
});
|
||||
beforeKvs.push(beforeOrdered);
|
||||
}
|
||||
this.api.request.body.kvs = requestKvs;
|
||||
this.beforeRequest.body.kvs = beforeKvs;
|
||||
}
|
||||
let submitRequestBody = JSON.stringify(this.api.request.body);
|
||||
let beforeRequestBody = JSON.stringify(this.beforeRequest.body);
|
||||
if (submitRequestBody !== beforeRequestBody && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
if (this.api.request.authManager && this.beforeRequest.authManager) {
|
||||
let submitRequestAuthManager = JSON.stringify(this.api.request.authManager);
|
||||
let beforeRequestAuthManager = JSON.stringify(this.beforeRequest.authManager);
|
||||
if (submitRequestAuthManager !== beforeRequestAuthManager && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
if (this.api.request.hashTree && this.beforeRequest.hashTree) {
|
||||
let submitRequestHashTree = JSON.stringify(this.api.request.hashTree);
|
||||
let beforeRequestHashTree = JSON.stringify(this.beforeRequest.hashTree);
|
||||
if (submitRequestHashTree !== beforeRequestHashTree && !this.noShowSyncRuleRelation) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
}
|
||||
if (
|
||||
(this.api.request.connectTimeout !== this.beforeRequest.connectTimeout ||
|
||||
this.api.request.responseTimeout !== this.beforeRequest.responseTimeout ||
|
||||
this.api.request.followRedirects !== this.beforeRequest.followRedirects ||
|
||||
this.api.request.alias !== this.beforeRequest.alias ||
|
||||
this.apiSyncRuleRelation.showUpdateRule === true) &&
|
||||
!this.noShowSyncRuleRelation
|
||||
) {
|
||||
this.batchSyncApiVisible = true;
|
||||
this.$refs.syncCaseConfig.show();
|
||||
}
|
||||
if (this.batchSyncApiVisible !== true) {
|
||||
updateDefinition(null, null, bodyFiles, this.api).then(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
if (this.syncTabs.indexOf(this.api.id) === -1) {
|
||||
|
@ -402,6 +680,65 @@ export default {
|
|||
this.$emit('syncApi', this.api);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
updateDefinition(null, null, bodyFiles, this.api).then(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
if (this.syncTabs.indexOf(this.api.id) === -1) {
|
||||
this.syncTabs.push(this.api.id);
|
||||
this.$emit('syncApi', this.api);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
batchSync(fromData) {
|
||||
this.beforeHttpForm = deepClone(this.api);
|
||||
this.beforeRequest = deepClone(this.api.request);
|
||||
this.beforeResponse = deepClone(this.api.response);
|
||||
this.batchSyncApiVisible = false;
|
||||
if (hasLicense() && (this.api.caseTotal > 0 || this.citedScenarioCount > 0)) {
|
||||
this.api.triggerUpdate = JSON.stringify(fromData);
|
||||
this.apiSyncRuleRelation.apiSyncCaseRequest = JSON.stringify(fromData);
|
||||
if (this.apiSyncRuleRelation.sendNotice && this.apiSyncRuleRelation.sendNotice === true) {
|
||||
this.api.sendSpecialMessage = this.apiSyncRuleRelation.sendNotice;
|
||||
} else {
|
||||
this.api.sendSpecialMessage = false;
|
||||
}
|
||||
|
||||
if (this.apiSyncRuleRelation.caseCreator && this.apiSyncRuleRelation.caseCreator === true) {
|
||||
this.api.caseCreator = this.apiSyncRuleRelation.caseCreator;
|
||||
} else {
|
||||
this.api.caseCreator = false;
|
||||
}
|
||||
if (this.apiSyncRuleRelation.scenarioCreator && this.apiSyncRuleRelation.scenarioCreator === true) {
|
||||
this.api.scenarioCreator = this.apiSyncRuleRelation.scenarioCreator;
|
||||
} else {
|
||||
this.api.scenarioCreator = false;
|
||||
}
|
||||
this.apiSyncRuleRelation.resourceId = this.api.id;
|
||||
this.apiSyncRuleRelation.resourceType = 'API';
|
||||
this.saveApiSyncRuleRelation(this.apiSyncRuleRelation);
|
||||
}
|
||||
},
|
||||
saveApiSyncRuleRelation(apiSyncRuleRelation) {
|
||||
let bodyFiles = this.getBodyUploadFiles(this.api);
|
||||
updateRuleRelation(apiSyncRuleRelation.resourceId, apiSyncRuleRelation).then(() => {
|
||||
updateDefinition(null, null, bodyFiles, this.api).then(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
if (this.syncTabs.indexOf(this.api.id) === -1) {
|
||||
this.syncTabs.push(this.api.id);
|
||||
this.$emit('syncApi', this.api);
|
||||
}
|
||||
});
|
||||
this.$refs.syncCaseConfig.close();
|
||||
});
|
||||
},
|
||||
getCitedScenarioCount() {
|
||||
citedApiScenarioCount(this.api.id).then((response) => {
|
||||
if (response.data) {
|
||||
this.citedScenarioCount = response.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
selectTestCase(item) {
|
||||
if (item != null) {
|
||||
|
@ -440,9 +777,58 @@ export default {
|
|||
if (!this.api.environmentId && store.useEnvironment) {
|
||||
this.api.environmentId = store.useEnvironment;
|
||||
}
|
||||
getLastResultDetail(this.api.id, this);
|
||||
// getLastResultDetail(this.api.id, this);
|
||||
this.runLoading = false;
|
||||
this.checkVersionEnable();
|
||||
this.getCaseCount();
|
||||
if (hasLicense()) {
|
||||
this.isXpack = true;
|
||||
this.getOldVersionData();
|
||||
this.getSyncRule();
|
||||
this.getCitedScenarioCount();
|
||||
}
|
||||
},
|
||||
getSyncRule() {
|
||||
relationGet(this.api.id, 'API').then((response) => {
|
||||
if (response.data) {
|
||||
this.apiSyncRuleRelation = response.data;
|
||||
if (this.apiSyncRuleRelation.apiSyncCaseRequest) {
|
||||
this.apiSyncRuleRelation.apiSyncConfig = JSON.parse(this.apiSyncRuleRelation.apiSyncCaseRequest);
|
||||
}
|
||||
if (this.apiSyncRuleRelation.caseCreator === null || this.apiSyncRuleRelation.caseCreator === undefined) {
|
||||
this.apiSyncRuleRelation.caseCreator = true;
|
||||
}
|
||||
if (
|
||||
this.apiSyncRuleRelation.scenarioCreator === null ||
|
||||
this.apiSyncRuleRelation.scenarioCreator === undefined
|
||||
) {
|
||||
this.apiSyncRuleRelation.scenarioCreator = true;
|
||||
}
|
||||
if (this.apiSyncRuleRelation.syncCase === null || this.apiSyncRuleRelation.syncCase === undefined) {
|
||||
this.apiSyncRuleRelation.syncCase = true;
|
||||
}
|
||||
if (this.apiSyncRuleRelation.sendNotice === null || this.apiSyncRuleRelation.sendNotice === undefined) {
|
||||
this.apiSyncRuleRelation.sendNotice = true;
|
||||
}
|
||||
this.noShowSyncRuleRelation = this.apiSyncRuleRelation.showUpdateRule;
|
||||
}
|
||||
});
|
||||
},
|
||||
getCaseCount() {
|
||||
apiTestCaseCount({ id: this.api.id }).then((response) => {
|
||||
if (response.data > 0) {
|
||||
this.api.caseTotal = response.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
getOldVersionData() {
|
||||
getDefinitionVersions(this.api.id).then((response) => {
|
||||
if (response.data[0]) {
|
||||
this.beforeHttpForm = response.data[0];
|
||||
this.beforeRequest = JSON.parse(response.data[0].request);
|
||||
this.beforeResponse = JSON.parse(response.data[0].response);
|
||||
}
|
||||
});
|
||||
},
|
||||
margeFiles(targetFiles, sourceFiles) {
|
||||
targetFiles.forEach((target) => {
|
||||
|
|
|
@ -341,7 +341,7 @@ export default {
|
|||
}
|
||||
this.runLoading = false;
|
||||
this.getEnvironments();
|
||||
getLastResultDetail(this.api.id, this);
|
||||
// getLastResultDetail(this.api.id, this);
|
||||
this.checkVersionEnable();
|
||||
},
|
||||
};
|
||||
|
|
|
@ -342,7 +342,7 @@ export default {
|
|||
}
|
||||
this.currentRequest = this.api.request;
|
||||
this.runLoading = false;
|
||||
getLastResultDetail(this.api.id, this);
|
||||
//getLastResultDetail(this.api.id, this);
|
||||
if (this.api.environmentId) {
|
||||
this.api.request.useEnvironment = this.api.environmentId;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
:visible.sync="batchSyncApiVisible" :close-on-click-modal="false"
|
||||
:title="$t('commons.save') + '&' + $t('workstation.sync') + $t('commons.setting')"
|
||||
v-if="isXpack">
|
||||
<el-row style="margin-bottom: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)">
|
||||
<div class="timeClass">
|
||||
<span style="font-size: 16px; font-weight: bold; padding-left: 10px">{{
|
||||
$t('api_test.definition.one_click_sync') + 'case'
|
||||
}}</span>
|
||||
<el-switch v-model="apiSyncRuleRelation.syncCase" style="float:right; padding-right: 10px"></el-switch>
|
||||
</div>
|
||||
<br/>
|
||||
<span style="font-size: 12px; padding-left: 10px">{{ $t('workstation.batch_sync_api_tips') }}</span
|
||||
><br/><br/>
|
||||
<span v-if="apiSyncRuleRelation.syncCase" style="font-size: 16px; font-weight: bold; padding-left: 10px">
|
||||
{{ $t('workstation.sync') + $t('commons.setting') }}
|
||||
<i class="el-icon-arrow-down" v-if="showApiSyncConfig" @click="showApiSyncConfig = false"/>
|
||||
<i class="el-icon-arrow-right" v-if="!showApiSyncConfig" @click="showApiSyncConfig = true"/> </span
|
||||
><br/><br/>
|
||||
<div v-if="showApiSyncConfig">
|
||||
<sync-setting
|
||||
style="padding-left: 20px"
|
||||
v-if="apiSyncRuleRelation.syncCase"
|
||||
v-bind:sync-data="apiSyncRuleRelation.apiSyncConfig"
|
||||
ref="synSetting"
|
||||
@updateSyncData="updateSyncData"></sync-setting>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row style="margin-bottom: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)">
|
||||
<div class="timeClass">
|
||||
<span style="font-size: 16px; font-weight: bold; padding-left: 10px">
|
||||
{{ $t('api_test.definition.change_notification') }}
|
||||
<el-tooltip
|
||||
class="ms-num"
|
||||
effect="dark"
|
||||
:content="$t('project_application.workstation.api_receiver_tip')"
|
||||
placement="top">
|
||||
<i class="el-icon-warning"/>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<el-switch v-model="apiSyncRuleRelation.sendNotice" style="float:right;padding-right: 10px"></el-switch>
|
||||
</div>
|
||||
<span style="font-size: 12px; padding-left: 10px"> {{ $t('api_test.definition.recipient_tips') }} </span><br/>
|
||||
<p
|
||||
style="
|
||||
font-size: 12px;
|
||||
color: var(--primary_color);
|
||||
margin-bottom: 20px;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
padding-left: 10px;
|
||||
"
|
||||
@click="gotoApiMessage">
|
||||
{{ $t('project_application.workstation.go_to_api_message') }}
|
||||
</p>
|
||||
<el-row v-if="apiSyncRuleRelation.sendNotice" style="margin-bottom: 5px; margin-top: 5px">
|
||||
<el-col :span="4"
|
||||
><span style="font-weight: bold; padding-left: 10px">{{ $t('api_test.definition.recipient') + ':' }}</span>
|
||||
</el-col>
|
||||
<el-col :span="20" style="color: var(--primary_color)">
|
||||
<el-checkbox v-model="apiSyncRuleRelation.caseCreator">{{ 'CASE' + $t('api_test.creator') }}</el-checkbox>
|
||||
<el-checkbox v-model="apiSyncRuleRelation.scenarioCreator">
|
||||
{{ $t('commons.scenario') + $t('api_test.creator') }}
|
||||
</el-checkbox>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-checkbox v-model="apiSyncRuleRelation.showUpdateRule" style="padding-left: 10px"
|
||||
>{{ $t('project_application.workstation.no_show_setting') }}
|
||||
</el-checkbox>
|
||||
<el-tooltip
|
||||
class="ms-num"
|
||||
effect="dark"
|
||||
:content="$t('project_application.workstation.no_show_setting_tip')"
|
||||
placement="top">
|
||||
<i class="el-icon-warning"/>
|
||||
</el-tooltip>
|
||||
</el-row>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="batchSyncApiVisible = false">{{ $t('commons.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="batchSync()">{{ $t('commons.confirm') }}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SyncSetting from "@/business/definition/util/SyncSetting";
|
||||
|
||||
export default {
|
||||
name: "ApiSyncCaseConfig",
|
||||
components: {
|
||||
SyncSetting,
|
||||
},
|
||||
props: {
|
||||
apiSyncRuleRelation: {},
|
||||
showApiSyncConfig: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isXpack: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
batchSyncApiVisible: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateSyncData(value) {
|
||||
this.apiSyncRuleRelation.apiSyncConfig = value;
|
||||
},
|
||||
gotoApiMessage() {
|
||||
let apiResolve = this.$router.resolve({
|
||||
path: '/project/messagesettings',
|
||||
});
|
||||
window.open(apiResolve.href, '_blank');
|
||||
},
|
||||
batchSync() {
|
||||
let fromData;
|
||||
if (this.$refs.synSetting && this.$refs.synSetting.fromData) {
|
||||
fromData = this.$refs.synSetting.fromData;
|
||||
fromData.method = true;
|
||||
fromData.path = true;
|
||||
fromData.protocol = true;
|
||||
}
|
||||
this.$emit('batchSync', fromData)
|
||||
},
|
||||
show() {
|
||||
this.batchSyncApiVisible = true
|
||||
},
|
||||
close() {
|
||||
this.batchSyncApiVisible = false
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -6,6 +6,7 @@
|
|||
class="ms-htt-width"
|
||||
:placeholder="$t('api_test.definition.request.run_env')"
|
||||
filterable
|
||||
@click.native="refreshEnv"
|
||||
@change="environmentChange"
|
||||
clearable>
|
||||
<el-option
|
||||
|
@ -54,6 +55,9 @@ export default {
|
|||
this.getEnvironments();
|
||||
},
|
||||
methods: {
|
||||
refreshEnv() {
|
||||
this.getEnvironments();
|
||||
},
|
||||
getEnvironments() {
|
||||
if (this.projectId) {
|
||||
getEnvironmentByProjectId(this.projectId).then((response) => {
|
||||
|
|
|
@ -15,7 +15,14 @@
|
|||
:closable="!readOnly"
|
||||
:disable-transitions="false"
|
||||
@close="remove(idx)">
|
||||
{{ tag && tag.length > 10 ? tag.substring(0, 10) + "..." : tag }}
|
||||
<span v-if="tag && tag.length > 10">
|
||||
<el-tooltip class="item" effect="light" :content="tag" placement="top" :enterable="false">
|
||||
<span>{{ tag && tag.length > 10 ? tag.substring(0, 10) + "..." : tag }}</span>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ tag }}
|
||||
</span>
|
||||
</el-tag>
|
||||
<input
|
||||
:disabled="readOnly"
|
||||
|
|
|
@ -57,45 +57,6 @@
|
|||
<ms-api-key-value :items="condition.headers" :isShowEnable="true" :suggestions="headerSuggestions"/>
|
||||
</form-section>
|
||||
|
||||
<!-- UI 配置 -->
|
||||
<form-section :title="$t('commons.ui_test')" :init-active=false v-if="condition.type !== 'MODULE'" v-xpack>
|
||||
<el-row :gutter="10" style="padding-top: 10px;">
|
||||
<el-col :span="6">
|
||||
<!-- 浏览器驱动 -->
|
||||
<span style="margin-right: 10px;">{{ $t("ui.browser") }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
v-model="httpConfig.browser"
|
||||
style="width: 100px"
|
||||
>
|
||||
<el-option
|
||||
v-for="b in browsers"
|
||||
:key="b.value"
|
||||
:value="b.value"
|
||||
:label="b.label"
|
||||
></el-option>
|
||||
</el-select>
|
||||
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<!-- 性能模式 -->
|
||||
<el-checkbox
|
||||
v-model="httpConfig.headlessEnabled"
|
||||
>
|
||||
<span> {{ $t("ui.performance_mode") }}</span>
|
||||
</el-checkbox>
|
||||
<ms-instructions-icon size="10" :content="$t('ui.per_tip')"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 当前版本实现免登录是基于 cookie 的但是现在由于安全性问题绝大多数网站都不支持 cookie登录所以先屏蔽了-->
|
||||
<!-- <el-row :gutter="10">-->
|
||||
<!-- <el-col :span="24">-->
|
||||
<!-- <ms-ui-scenario-cookie-table :items="httpConfig.cookie" ref="cookieTable"/>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- </el-row>-->
|
||||
</form-section>
|
||||
|
||||
<div style="margin-top: 20px">
|
||||
<el-button v-if="!condition.id" type="primary" style="float: right" size="mini" @click="add">
|
||||
{{ $t('commons.add') }}
|
||||
|
|
|
@ -18,18 +18,12 @@
|
|||
:content="$t('commons.import')"
|
||||
@click="importJSON"
|
||||
/>
|
||||
<el-dropdown @command="handleExportCommand" class="scenario-ext-btn" trigger="hover"
|
||||
v-permission="['PROJECT_ENVIRONMENT:READ+EXPORT']">
|
||||
<ms-table-button
|
||||
style="margin-left: 10px"
|
||||
v-permission="['PROJECT_ENVIRONMENT:READ+EXPORT']"
|
||||
icon="el-icon-box"
|
||||
:content="$t('commons.export')"
|
||||
@click="exportJSON"
|
||||
/>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="exportApi">{{ $t('envrionment.export_variable_tip') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
|
||||
<el-link
|
||||
style="margin-left: 10px"
|
||||
@click="batchAdd"
|
||||
|
@ -64,31 +58,6 @@
|
|||
>
|
||||
<ms-table-column prop="num" sortable label="ID" min-width="60">
|
||||
</ms-table-column>
|
||||
|
||||
<ms-table-column
|
||||
prop="scope"
|
||||
sortable
|
||||
:label="$t('commons.scope')"
|
||||
:filters="scopeTypeFilters"
|
||||
:filter-method="filterScope"
|
||||
min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-select
|
||||
v-model="scope.row.scope"
|
||||
:placeholder="$t('commons.please_select')"
|
||||
size="mini"
|
||||
@change="changeType(scope.row)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in scopeTypeFilters"
|
||||
:key="item.value"
|
||||
:label="item.text"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</ms-table-column>
|
||||
|
||||
<ms-table-column
|
||||
prop="name"
|
||||
:label="$t('api_test.variable_name')"
|
||||
|
@ -115,9 +84,9 @@
|
|||
<template slot-scope="scope">
|
||||
<el-select
|
||||
v-model="scope.row.type"
|
||||
v-if="!scope.row.scope || scope.row.scope == 'api'"
|
||||
:placeholder="$t('commons.please_select')"
|
||||
size="mini"
|
||||
@change="changeType(scope.row)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in typeSelectOptions"
|
||||
|
@ -126,20 +95,6 @@
|
|||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-else
|
||||
v-model="scope.row.type"
|
||||
:placeholder="$t('commons.please_select')"
|
||||
size="mini"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in uiTypeSelectOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</ms-table-column>
|
||||
|
||||
|
@ -237,7 +192,6 @@ import ApiVariableSetting from "./ApiVariableSetting";
|
|||
import CsvFileUpload from "./variable/CsvFileUpload";
|
||||
import { downloadFile, getUUID, operationConfirm } from "../../../utils";
|
||||
import VariableImport from "./variable/VariableImport";
|
||||
import _ from "lodash";
|
||||
|
||||
export default {
|
||||
name: "MsApiScenarioVariables",
|
||||
|
@ -283,19 +237,9 @@ export default {
|
|||
{ value: "COUNTER", label: this.$t("api_test.automation.counter") },
|
||||
{ value: "RANDOM", label: this.$t("api_test.automation.random") },
|
||||
],
|
||||
uiTypeSelectOptions: [
|
||||
{value: "STRING", label: this.$t("api_test.automation.string")},
|
||||
{value: "ARRAY", label: this.$t("api_test.automation.array")},
|
||||
{value: "JSON", label: this.$t("api_test.automation.json")},
|
||||
{value: "NUMBER", label: this.$t("api_test.automation.number")},
|
||||
],
|
||||
variables: {},
|
||||
selectVariable: "",
|
||||
editData: {},
|
||||
scopeTypeFilters: [
|
||||
{text: this.$t("commons.api"), value: "api"},
|
||||
{text: this.$t("commons.ui_test"), value: "ui"},
|
||||
]
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
|
@ -344,7 +288,7 @@ export default {
|
|||
}
|
||||
if (isNeedCreate) {
|
||||
this.variables.push(
|
||||
new KeyValue({enable: true, id: getUUID(), type: "CONSTANT", scope: "api"})
|
||||
new KeyValue({ enable: true, id: getUUID(), type: "CONSTANT" })
|
||||
);
|
||||
}
|
||||
this.$emit("change", this.variables);
|
||||
|
@ -361,10 +305,6 @@ export default {
|
|||
data.files = [];
|
||||
data.quotedData = "false";
|
||||
}
|
||||
|
||||
if (!data.scope || data.scope == "ui") {
|
||||
data.type = 'STRING';
|
||||
}
|
||||
},
|
||||
valueText(data) {
|
||||
switch (data.type) {
|
||||
|
@ -407,9 +347,6 @@ export default {
|
|||
this.$set(item, "description", item.remark);
|
||||
item.remark = undefined;
|
||||
}
|
||||
if (!item.scope) {
|
||||
this.$set(item, "scope", "api");
|
||||
}
|
||||
index++;
|
||||
});
|
||||
},
|
||||
|
@ -433,7 +370,7 @@ export default {
|
|||
}
|
||||
);
|
||||
},
|
||||
filter(scope) {
|
||||
filter() {
|
||||
let datas = [];
|
||||
this.variables.forEach((item) => {
|
||||
if (this.selectVariable && this.selectVariable != "" && item.name) {
|
||||
|
@ -453,12 +390,6 @@ export default {
|
|||
});
|
||||
this.variables = datas;
|
||||
},
|
||||
filterScope(value, row) {
|
||||
if (value == "ui") {
|
||||
return row.scope == "ui";
|
||||
}
|
||||
return !row.scope || row.scope == "api";
|
||||
},
|
||||
openSetting(data) {
|
||||
this.$refs.apiVariableSetting.open(data);
|
||||
},
|
||||
|
@ -519,15 +450,8 @@ export default {
|
|||
this.sortParameters();
|
||||
},
|
||||
exportJSON() {
|
||||
let apiVariable = [];
|
||||
this.$refs.variableTable.selectRows.forEach((r) => {
|
||||
if (!r.scope || r.scope != "ui") {
|
||||
apiVariable.push(r);
|
||||
}
|
||||
});
|
||||
|
||||
if (apiVariable.length < 1) {
|
||||
this.$warning(this.$t("api_test.environment.select_api_variable"));
|
||||
if (this.$refs.variableTable.selectIds.length < 1) {
|
||||
this.$warning(this.$t("api_test.environment.select_variable"));
|
||||
return;
|
||||
}
|
||||
let variablesJson = [];
|
||||
|
@ -537,7 +461,7 @@ export default {
|
|||
if (row.type === "CSV") {
|
||||
messages = this.$t("variables.csv_download");
|
||||
}
|
||||
if (row.name && (!row.scope || row.scope == "api")) {
|
||||
if (row.name) {
|
||||
variablesJson.push(row);
|
||||
}
|
||||
});
|
||||
|
@ -570,21 +494,10 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
handleExportCommand(command){
|
||||
this.exportJSON();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.items.length === 0) {
|
||||
this.items.push(new KeyValue({enable: true, scope: "api"}));
|
||||
} else {
|
||||
//历史数据默认是 api 应用场景
|
||||
_.forEach(this.items, item => {
|
||||
if (!item.scope) {
|
||||
this.$set(item, "scope", "api");
|
||||
}
|
||||
})
|
||||
this.variables = this.items;
|
||||
this.items.push(new KeyValue({ enable: true }));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import i18n from "../i18n";
|
||||
import { getCurrentUserId } from "../utils/token";
|
||||
import {getCurrentProjectID, getCurrentUser} from "../utils/token";
|
||||
import { SYSTEM_FIELD_NAME_MAP } from "../utils/table-constants";
|
||||
|
||||
function setDefaultValue(item, value) {
|
||||
|
@ -39,7 +39,15 @@ export function parseCustomField(data, template, rules, oldFields) {
|
|||
val &&
|
||||
val === "CURRENT_USER"
|
||||
) {
|
||||
val = getCurrentUserId();
|
||||
val = '';
|
||||
const {id, userGroups} = getCurrentUser();
|
||||
if (userGroups) {
|
||||
// CURRENT_USER是否是当前项目下的成员
|
||||
let index = userGroups.findIndex(ug => ug.sourceId === getCurrentProjectID());
|
||||
if (index !== -1) {
|
||||
val = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
setDefaultValue(item, val);
|
||||
}
|
||||
|
|
4
pom.xml
4
pom.xml
|
@ -42,9 +42,9 @@
|
|||
<bcprov-jdk15on.version>1.70</bcprov-jdk15on.version>
|
||||
<commons-io.version>2.11.0</commons-io.version>
|
||||
<commons-text.version>1.10.0</commons-text.version>
|
||||
<xstream.version>1.4.19</xstream.version>
|
||||
<xstream.version>1.4.20</xstream.version>
|
||||
<xmlbeans.version>3.1.0</xmlbeans.version>
|
||||
<swagger-parser.version>2.1.5</swagger-parser.version>
|
||||
<swagger-parser.version>2.1.8</swagger-parser.version>
|
||||
<rhino.version>1.7.14</rhino.version>
|
||||
<jsoup.version>1.15.3</jsoup.version>
|
||||
<commonmark.version>0.19.0</commonmark.version>
|
||||
|
|
|
@ -136,8 +136,8 @@ import MsTableOperator from "metersphere-frontend/src/components/MsTableOperator
|
|||
import MsTableOperatorButton from "metersphere-frontend/src/components/MsTableOperatorButton";
|
||||
import MsTablePagination from "metersphere-frontend/src/components/pagination/TablePagination";
|
||||
import ApiEnvironmentConfig from "metersphere-frontend/src/components/environment/ApiEnvironmentConfig";
|
||||
import {Environment, parseEnvironment, HttpConfig} from "metersphere-frontend/src/model/EnvironmentModel";
|
||||
import EnvironmentEdit from "./components/EnvironmentEdit";
|
||||
import {Environment, parseEnvironment} from "metersphere-frontend/src/model/EnvironmentModel";
|
||||
import EnvironmentEdit from "metersphere-frontend/src/components/environment/EnvironmentEdit";
|
||||
import MsAsideItem from "metersphere-frontend/src/components/MsAsideItem";
|
||||
import MsAsideContainer from "metersphere-frontend/src/components/MsAsideContainer";
|
||||
import ProjectSwitch from "metersphere-frontend/src/components/head/ProjectSwitch";
|
||||
|
@ -174,7 +174,7 @@ export default {
|
|||
projectList: [],
|
||||
condition: {}, //封装传递给后端的查询条件
|
||||
environments: [],
|
||||
currentEnvironment: new Environment({httpConfig: new HttpConfig()}),
|
||||
currentEnvironment: new Environment(),
|
||||
result: {},
|
||||
loading: false,
|
||||
dialogVisible: false,
|
||||
|
@ -288,7 +288,7 @@ export default {
|
|||
createEnv() {
|
||||
this.dialogTitle = this.$t('api_test.environment.create');
|
||||
this.dialogVisible = true;
|
||||
this.currentEnvironment = new Environment({httpConfig: new HttpConfig()});
|
||||
this.currentEnvironment = new Environment();
|
||||
this.currentEnvironment.projectId = this.currentProjectId;
|
||||
this.currentEnvironment.currentProjectId = this.currentProjectId;
|
||||
this.ifCreate = true;
|
||||
|
|
|
@ -155,7 +155,7 @@ import {REQUEST_HEADERS} from "metersphere-frontend/src/utils/constants";
|
|||
import {CommonConfig, Environment} from "metersphere-frontend/src/model/EnvironmentModel";
|
||||
import MsApiHostTable from "metersphere-frontend/src/components/environment/commons/ApiHostTable";
|
||||
import MsDatabaseConfig from "metersphere-frontend/src/components/environment/database/DatabaseConfig";
|
||||
import MsEnvironmentHttpConfig from "./EnvironmentHttpConfig";
|
||||
import MsEnvironmentHttpConfig from "metersphere-frontend/src/components/environment/EnvironmentHttpConfig";
|
||||
import MsEnvironmentCommonConfig from "metersphere-frontend/src/components/environment/EnvironmentCommonConfig";
|
||||
import MsEnvironmentSSLConfig from "metersphere-frontend/src/components/environment/EnvironmentSSLConfig";
|
||||
import MsApiAuthConfig from "metersphere-frontend/src/components/environment/auth/ApiAuthConfig";
|
||||
|
|
|
@ -57,45 +57,6 @@
|
|||
<ms-api-key-value :items="condition.headers" :isShowEnable="true" :suggestions="headerSuggestions"/>
|
||||
</form-section>
|
||||
|
||||
<!-- UI 配置 -->
|
||||
<form-section :title="$t('commons.ui_test')" :init-active=false v-if="condition.type !== 'MODULE'">
|
||||
<el-row :gutter="10" style="padding-top: 10px;">
|
||||
<el-col :span="6">
|
||||
<!-- 浏览器驱动 -->
|
||||
<span style="margin-right: 10px;">{{ $t("ui.browser") }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
v-model="httpConfig.browser"
|
||||
style="width: 100px"
|
||||
>
|
||||
<el-option
|
||||
v-for="b in browsers"
|
||||
:key="b.value"
|
||||
:value="b.value"
|
||||
:label="b.label"
|
||||
></el-option>
|
||||
</el-select>
|
||||
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<!-- 性能模式 -->
|
||||
<el-checkbox
|
||||
v-model="httpConfig.headlessEnabled"
|
||||
>
|
||||
<span> {{ $t("ui.performance_mode") }}</span>
|
||||
</el-checkbox>
|
||||
<ms-instructions-icon size="10" :content="$t('ui.per_tip')"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 当前版本实现免登录是基于 cookie 的但是现在由于安全性问题绝大多数网站都不支持 cookie登录所以先屏蔽了-->
|
||||
<!-- <el-row :gutter="10">-->
|
||||
<!-- <el-col :span="24">-->
|
||||
<!-- <ms-ui-scenario-cookie-table :items="httpConfig.cookie" ref="cookieTable"/>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- </el-row>-->
|
||||
</form-section>
|
||||
|
||||
<div style="margin-top: 20px">
|
||||
<el-button v-if="!condition.id" type="primary" style="float: right" size="mini" @click="add">
|
||||
{{ $t('commons.add') }}
|
||||
|
|
|
@ -15,7 +15,14 @@
|
|||
:closable="!readOnly"
|
||||
:disable-transitions="false"
|
||||
@close="remove(idx)">
|
||||
{{ tag && tag.length > 10 ? tag.substring(0, 10) + "..." : tag }}
|
||||
<span v-if="tag && tag.length > 10">
|
||||
<el-tooltip class="item" effect="light" :content="tag" placement="top" :enterable="false">
|
||||
<span>{{ tag && tag.length > 10 ? tag.substring(0, 10) + "..." : tag }}</span>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ tag }}
|
||||
</span>
|
||||
</el-tag>
|
||||
<input
|
||||
:disabled="readOnly"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
-- 清理超级用户组权限信息,改为默认拥有全部权限
|
||||
delete from user_group_permission where group_id = 'super_group';
|
|
@ -8,6 +8,10 @@
|
|||
<div class="license-content">
|
||||
<div v-if="license.status !== 'Fail'">
|
||||
<table>
|
||||
<tr v-if="license.serialNo">
|
||||
<th>{{ $t('license.serial_num') }}</th>
|
||||
<td>{{ license.serialNo }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ $t('license.corporation') }}</th>
|
||||
<td>{{ license.corporation }}</td>
|
||||
|
@ -37,14 +41,6 @@
|
|||
<th>{{ $t('license.count') }}</th>
|
||||
<td>{{ license.count }}</td>
|
||||
</tr>
|
||||
<tr v-if="license.serialNo">
|
||||
<th>{{ $t('license.serial_num') }}</th>
|
||||
<td>{{ license.serialNo }}</td>
|
||||
</tr>
|
||||
<tr v-if="license.remark">
|
||||
<th>{{ $t('license.remark') }}</th>
|
||||
<td>{{ license.remark }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ $t('license.status') }}</th>
|
||||
<td>
|
||||
|
@ -57,6 +53,10 @@
|
|||
<label class="ms-license-label" v-else>{{ $t('license.invalid') }}</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="license.remark">
|
||||
<th>{{ $t('license.remark') }}</th>
|
||||
<td>{{ license.remark }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<el-link type="primary" class="license-update" @click="create()" :disabled="disabled">
|
||||
|
@ -148,7 +148,6 @@ export default {
|
|||
|
||||
.license-container {
|
||||
margin: auto;
|
||||
height: 400px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,15 +89,12 @@
|
|||
inner join project p
|
||||
on i.project_id = p.id and p.workspace_id = #{request.workspaceId}
|
||||
left join custom_field_issues cfi
|
||||
on i.id = cfi.resource_id and field_id in (
|
||||
select cf.id
|
||||
on i.id = cfi.resource_id and field_id in (select cf.id
|
||||
from custom_field cf
|
||||
left join project pr
|
||||
on cf.project_id = pr.id
|
||||
inner join custom_field_template cft on cft.template_id = pr.issue_template_id
|
||||
where cf.scene = 'ISSUE' and cf.name = '状态'
|
||||
and (pr.workspace_id = #{request.workspaceId} or global = true)
|
||||
)
|
||||
inner join custom_field_template cft on cft.template_id = p.issue_template_id
|
||||
where cf.scene = 'ISSUE'
|
||||
and cf.name = '状态'
|
||||
and (p.workspace_id = #{request.workspaceId} or cf.global = true))
|
||||
where i.creator = #{request.creator}
|
||||
group by statusValue;
|
||||
</select>
|
||||
|
|
|
@ -65,6 +65,8 @@ import org.springframework.kafka.core.KafkaTemplate;
|
|||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
|
@ -1554,10 +1556,6 @@ public class TestPlanService {
|
|||
envMap = planTestPlanApiCaseService.getApiCaseEnv(planId);
|
||||
Map<String, List<String>> scenarioEnv = planTestPlanScenarioCaseService.getApiScenarioEnv(planId);
|
||||
|
||||
if (DiscoveryUtil.hasService(MicroServiceName.UI_TEST)) {
|
||||
scenarioEnv = mergeUiScenarioEnv(planId, scenarioEnv);
|
||||
}
|
||||
|
||||
Set<String> projectIds = scenarioEnv.keySet();
|
||||
for (String projectId : projectIds) {
|
||||
if (envMap.containsKey(projectId)) {
|
||||
|
@ -1580,32 +1578,6 @@ public class TestPlanService {
|
|||
return envMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并ui场景的环境信息
|
||||
* @param planId
|
||||
* @param scenarioEnv
|
||||
* @return
|
||||
*/
|
||||
private Map<String, List<String>> mergeUiScenarioEnv(String planId, Map<String, List<String>> scenarioEnv) {
|
||||
Map<String, List<String>> uiScenarioEnv = planTestPlanUiScenarioCaseService.getUiScenarioEnv(planId);
|
||||
if (MapUtils.isEmpty(scenarioEnv)) {
|
||||
return uiScenarioEnv;
|
||||
}
|
||||
if (MapUtils.isNotEmpty(uiScenarioEnv)) {
|
||||
uiScenarioEnv.entrySet().forEach(entry -> {
|
||||
if (scenarioEnv.containsKey(entry.getKey())) {
|
||||
List<String> environmentIds = scenarioEnv.get(entry.getKey());
|
||||
entry.getValue().forEach(eId -> {
|
||||
if (!environmentIds.contains(eId)) {
|
||||
environmentIds.add(eId);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return scenarioEnv;
|
||||
}
|
||||
|
||||
public String runPlan(TestPlanRunRequest testplanRunRequest) {
|
||||
//检查测试计划下有没有可以执行的用例;
|
||||
if (!haveExecCase(testplanRunRequest.getTestPlanId(), false)) {
|
||||
|
@ -1669,6 +1641,10 @@ public class TestPlanService {
|
|||
planTestPlanApiCaseService.setApiCaseEnv(planId, runModeConfig);
|
||||
planTestPlanScenarioCaseService.setScenarioEnv(planId, runModeConfig);
|
||||
}
|
||||
|
||||
if (DiscoveryUtil.hasService(MicroServiceName.UI_TEST)) {
|
||||
planTestPlanUiScenarioCaseService.setScenarioEnv(planId, runModeConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public void editReportConfig(TestPlanDTO testPlanDTO) {
|
||||
|
|
|
@ -161,4 +161,8 @@ public class PlanTestPlanUiScenarioCaseService extends UiTestService {
|
|||
public List<String> getUiScenarioProjectIds(String planId) {
|
||||
return microService.getForData(serviceName, BASE_URL + "/get/project/ids/" + planId, List.class);
|
||||
}
|
||||
|
||||
public RunModeConfigDTO setScenarioEnv(String planId, RunModeConfigDTO runModeConfig) {
|
||||
return microService.postForData(serviceName, BASE_URL + "/set/env/" + planId, runModeConfig, RunModeConfigDTO.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,11 @@ public class UserService {
|
|||
UserMapper userMapper;
|
||||
|
||||
public UserDTO.PlatformInfo getCurrentPlatformInfo(String workspaceId) {
|
||||
return JSON.parseObject(getCurrentPlatformInfoStr(workspaceId), UserDTO.PlatformInfo.class);
|
||||
String currentPlatformInfoStr = getCurrentPlatformInfoStr(workspaceId);
|
||||
if (StringUtils.isNotBlank(currentPlatformInfoStr)) {
|
||||
JSON.parseObject(currentPlatformInfoStr, UserDTO.PlatformInfo.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getCurrentPlatformInfoStr(String workspaceId) {
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
-- init sql
|
||||
-- 工单名称 v26_create_index
|
||||
-- 创建人 guoyuqi
|
||||
ALTER table issues ADD INDEX project_id_index(project_id);
|
||||
|
||||
ALTER table issues ADD INDEX creator_index(creator);
|
||||
|
||||
ALTER table custom_field ADD INDEX global_index(global);
|
||||
|
||||
ALTER table custom_field ADD INDEX scene_index(scene);
|
||||
|
||||
ALTER table custom_field ADD INDEX name_index(name);
|
|
@ -1,21 +1,5 @@
|
|||
<template>
|
||||
<div v-loading="loading">
|
||||
<env-group-popover
|
||||
:env-map="projectEnvMap"
|
||||
:project-ids="projectIds"
|
||||
:show-env-group="false"
|
||||
@setProjectEnvMap="setProjectEnvMap"
|
||||
:environment-type.sync="environmentType"
|
||||
:group-id="envGroupId"
|
||||
:is-scenario="false"
|
||||
@setEnvGroup="setEnvGroup"
|
||||
:show-config-button-with-out-permission="
|
||||
showConfigButtonWithOutPermission
|
||||
"
|
||||
:project-list="projectList"
|
||||
ref="envPopover"
|
||||
class="env-popover"
|
||||
/>
|
||||
|
||||
<ms-table-adv-search-bar :condition.sync="condition" class="adv-search-bar"
|
||||
v-if="condition.components !== undefined && condition.components.length > 0"
|
||||
|
@ -115,9 +99,6 @@ import {
|
|||
getCustomTableWidth
|
||||
} from "metersphere-frontend/src/utils/tableUtils";
|
||||
import MsTableColumn from "metersphere-frontend/src/components/table/MsTableColumn";
|
||||
import EnvGroupPopover from "@/business/plan/env/EnvGroupPopover";
|
||||
import {getApiScenarioEnvByProjectId} from "@/api/remote/api/api-automation";
|
||||
import {getUiScenarioEnvByProjectId} from "@/api/remote/ui/ui-automation";
|
||||
|
||||
export default {
|
||||
name: "RelevanceUiScenarioList",
|
||||
|
@ -131,7 +112,6 @@ export default {
|
|||
MsTag,
|
||||
MsTableAdvSearchBar,
|
||||
MsTableColumn,
|
||||
EnvGroupPopover,
|
||||
},
|
||||
props: {
|
||||
referenced: {
|
||||
|
@ -167,7 +147,6 @@ export default {
|
|||
envGroupId: "",
|
||||
versionFilters: [],
|
||||
fieldsWidth: getCustomTableWidth('TEST_PLAN_UI_SCENARIO_CASE'),
|
||||
projectIds: new Set()
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -265,24 +244,9 @@ export default {
|
|||
selectCountChange(data) {
|
||||
this.selectRows = this.$refs.scenarioTable.selectRows;
|
||||
this.$emit("selectCountChange", data);
|
||||
this.initProjectIds();
|
||||
},
|
||||
showReport() {
|
||||
|
||||
},
|
||||
initProjectIds() {
|
||||
this.projectIds.clear();
|
||||
// this.map.clear();
|
||||
this.selectRows.forEach((row) => {
|
||||
getUiScenarioEnvByProjectId(row.id).then((res) => {
|
||||
let data = res.data;
|
||||
data.projectIds.forEach((d) => this.projectIds.add(d));
|
||||
// this.map.set(row.id, data.projectIds);
|
||||
});
|
||||
});
|
||||
},
|
||||
closeEnv(){
|
||||
this.$refs.envPopover.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -150,10 +150,6 @@ export default {
|
|||
let map = this.$refs.apiScenarioList.map;
|
||||
let envGroupId = this.$refs.apiScenarioList.envGroupId;
|
||||
|
||||
if (!envMap || envMap.size == 0) {
|
||||
this.$warning(this.$t('api_test.environment.select_environment'));
|
||||
return;
|
||||
}
|
||||
selectRows.forEach(row => {
|
||||
selectIds.push(row.id);
|
||||
})
|
||||
|
@ -185,6 +181,8 @@ export default {
|
|||
this.autoCheckStatus();
|
||||
this.$refs.baseRelevance.close();
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
autoCheckStatus() { // 检查执行结果,自动更新计划状态
|
||||
if (!this.planId) {
|
||||
|
|
|
@ -147,8 +147,7 @@
|
|||
:filters="apiscenariofilters.RESULT_FILTERS"
|
||||
:label="$t('api_test.automation.last_result')">
|
||||
<template v-slot:default="{row}">
|
||||
<el-link @click="showReport(row)"
|
||||
:disabled="!row.lastResult || row.lastResult==='PENDING' || row.lastResult==='UnExecute'">
|
||||
<el-link @click="showReport(row)" :disabled="!row.lastResult || row.lastResult==='PENDING' || row.lastResult==='UnExecute'">
|
||||
<ms-test-plan-api-status :status="row.lastResult==='UnExecute' ? 'PENDING' : row.lastResult"/>
|
||||
</el-link>
|
||||
</template>
|
||||
|
@ -178,7 +177,7 @@
|
|||
@batchEdit="batchEdit"/>
|
||||
|
||||
<ui-run-mode @handleRunBatch="handleRunBatch" ref="runMode" :custom-run-mode="true"
|
||||
:custom-serial-on-sample-error="true" :request="conditionRequest"/>
|
||||
:custom-serial-on-sample-error="true"/>
|
||||
|
||||
<ms-task-center ref="taskCenter" :show-menu="false"/>
|
||||
</div>
|
||||
|
@ -328,8 +327,6 @@ export default {
|
|||
]
|
||||
},
|
||||
versionFilters: [],
|
||||
//
|
||||
conditionRequest: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -440,19 +437,12 @@ export default {
|
|||
let rows = this.orderBySelectRows(this.$refs.table.selectRows);
|
||||
this.planCaseIds = [];
|
||||
rows.forEach(row => {
|
||||
this.planCaseIds.push(row.caseId);
|
||||
this.planCaseIds.push(row.id);
|
||||
})
|
||||
this.conditionRequest.id = getUUID();
|
||||
this.conditionRequest.ids = this.planCaseIds;
|
||||
this.conditionRequest.projectId = this.projectId;
|
||||
this.conditionRequest.condition = this.condition;
|
||||
this.$refs.runMode.open();
|
||||
},
|
||||
orderBySelectRows(rows) {
|
||||
let selectIds = this.$refs.table.selectIds;
|
||||
if (rows) {
|
||||
selectIds = Array.from(rows).map(row => row.id);
|
||||
}
|
||||
let selectIds = Array.from(rows).map(row => row.id);
|
||||
let array = [];
|
||||
for (let i in this.tableData) {
|
||||
if (selectIds.indexOf(this.tableData[i].id) !== -1) {
|
||||
|
|
|
@ -8,21 +8,6 @@
|
|||
>
|
||||
<div class="mode-container">
|
||||
|
||||
<div>
|
||||
<div>{{ $t("commons.environment") }}:</div>
|
||||
<env-select-popover :project-ids="projectIds"
|
||||
:project-list="projectList"
|
||||
:project-env-map="projectEnvListMap"
|
||||
:environment-type="'JSON'"
|
||||
:has-option-group="false"
|
||||
:show-env-group="false"
|
||||
:group-id="runConfig.environmentGroupId"
|
||||
@setProjectEnvMap="setProjectEnvMap"
|
||||
ref="envSelectPopover"
|
||||
class="mode-row"
|
||||
></env-select-popover>
|
||||
</div>
|
||||
|
||||
<!-- 浏览器 -->
|
||||
<div class="browser-row wrap">
|
||||
<div class="title">{{ $t("ui.browser") }}:</div>
|
||||
|
@ -282,7 +267,6 @@ export default {
|
|||
};
|
||||
this.runModeVisible = true;
|
||||
this.getWsProjects();
|
||||
this.showPopover();
|
||||
},
|
||||
changeMode() {
|
||||
this.runConfig.runWithinResourcePool = false;
|
||||
|
|
|
@ -88,7 +88,6 @@ const TRACK_HEADER = {
|
|||
{id: 'name', key: '2', label: 'api_test.automation.scenario_name'},
|
||||
{id: 'versionId', key: 'd', label: 'commons.version'},
|
||||
{id: 'level', key: '3', label: 'api_test.automation.case_level'},
|
||||
{id: 'envs', key: '8', label: 'commons.environment'},
|
||||
{id: 'tagNames', key: '4', label: 'api_test.automation.tag'},
|
||||
{id: 'stepTotal', key: '7', label: 'api_test.automation.step'},
|
||||
{id: 'passRate', key: '9', label: 'api_test.automation.passing_rate'},
|
||||
|
|
|
@ -17,131 +17,77 @@
|
|||
@refresh="getIssues"
|
||||
ref="table"
|
||||
>
|
||||
<span v-for="(item) in fields" :key="item.key">
|
||||
<ms-table-column
|
||||
:label="$t('test_track.issue.id')"
|
||||
prop="num"
|
||||
:field="item"
|
||||
sortable
|
||||
min-width="100"
|
||||
:fields-width="fieldsWidth">
|
||||
</ms-table-column>
|
||||
|
||||
<ms-table-column
|
||||
v-for="(item) in fields" :key="item.key"
|
||||
:label="item.label"
|
||||
:prop="item.id"
|
||||
:field="item"
|
||||
:sortable="item.sortable"
|
||||
:min-width="item.minWidth"
|
||||
:column-key="item.columnKey"
|
||||
:fields-width="fieldsWidth"
|
||||
:label="$t('test_track.issue.title')"
|
||||
min-width="100"
|
||||
prop="title">
|
||||
</ms-table-column>
|
||||
|
||||
<ms-table-column
|
||||
:field="item"
|
||||
:fields-width="fieldsWidth"
|
||||
sortable
|
||||
min-width="110"
|
||||
:label="$t('test_track.issue.platform_status') "
|
||||
prop="platformStatus">
|
||||
:filters="item.filters"
|
||||
>
|
||||
<template v-slot="scope">
|
||||
<span
|
||||
v-if="scope.row.platform ==='Zentao'">{{ scope.row.platformStatus ? issueStatusMap[scope.row.platformStatus] : '--' }}</span>
|
||||
<span v-else>{{ scope.row.platformStatus ? scope.row.platformStatus : '--' }}</span>
|
||||
</template>
|
||||
</ms-table-column>
|
||||
|
||||
<ms-table-column
|
||||
:field="item"
|
||||
:fields-width="fieldsWidth"
|
||||
:filters="platformFilters"
|
||||
:label="$t('test_track.issue.platform')"
|
||||
min-width="100"
|
||||
prop="platform">
|
||||
</ms-table-column>
|
||||
<span v-if="item.id === 'platformStatus'">
|
||||
<span v-if="scope.row.platform === 'Tapd'">
|
||||
{{ scope.row.platformStatus ? tapdIssueStatusMap[scope.row.platformStatus] : '--' }}
|
||||
</span>
|
||||
<span v-else-if="scope.row.platform ==='Local'">
|
||||
{{ scope.row.platformStatus ? tapdIssueStatusMap[scope.row.platformStatus] : '--' }}
|
||||
</span>
|
||||
<span v-else-if="platformStatusMap && platformStatusMap.get(scope.row.platformStatus)">
|
||||
{{ platformStatusMap.get(scope.row.platformStatus) }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ scope.row.platformStatus ? scope.row.platformStatus : '--' }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<ms-table-column
|
||||
prop="createTime"
|
||||
:field="item"
|
||||
:fields-width="fieldsWidth"
|
||||
:label="$t('commons.create_time')"
|
||||
sortable
|
||||
min-width="140px">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | datetimeFormat }}</span>
|
||||
</template>
|
||||
</ms-table-column>
|
||||
<ms-review-table-item
|
||||
v-else-if="item.id === 'description'"
|
||||
:data="scope.row"
|
||||
prop="description"/>
|
||||
|
||||
<ms-table-column
|
||||
prop="projectName"
|
||||
:field="item"
|
||||
:fields-width="fieldsWidth"
|
||||
:label="$t('test_track.issue.issue_project')"
|
||||
min-width="80">
|
||||
<template v-slot="scope">
|
||||
{{ scope.row.projectName ? scope.row.projectName : '--' }}
|
||||
</template>
|
||||
</ms-table-column>
|
||||
<ms-table-column
|
||||
:field="item"
|
||||
v-if="isShowAllColumn"
|
||||
:fields-width="fieldsWidth"
|
||||
column-key="creator"
|
||||
min-width="100"
|
||||
:label="$t('custom_field.issue_creator')"
|
||||
prop="creatorName">
|
||||
</ms-table-column>
|
||||
|
||||
<ms-table-column
|
||||
:field="item"
|
||||
v-if="isShowAllColumn"
|
||||
:fields-width="fieldsWidth"
|
||||
:label="$t('test_track.issue.issue_resource')"
|
||||
min-width="120"
|
||||
prop="resourceName">
|
||||
<template v-slot="scope">
|
||||
<el-link v-if="scope.row.resourceName" @click="$router.push('/track/plan/view/' + scope.row.resourceId)">
|
||||
<span v-else-if="item.id === 'resourceName'">
|
||||
<el-link v-if="scope.row.resourceName"
|
||||
@click="$router.push('/track/plan/view/' + scope.row.resourceId)">
|
||||
{{ scope.row.resourceName }}
|
||||
</el-link>
|
||||
<span v-else>
|
||||
--
|
||||
</span>
|
||||
</template>
|
||||
</ms-table-column>
|
||||
</span>
|
||||
|
||||
<issue-description-table-item :fields-width="fieldsWidth" :field="item" v-if="isShowAllColumn"/>
|
||||
<span v-else-if="item.id === 'createTime'">
|
||||
{{ scope.row.createTime | datetimeFormat }}
|
||||
</span>
|
||||
|
||||
<ms-table-column
|
||||
:field="item"
|
||||
v-if="isShowAllColumn"
|
||||
:fields-width="fieldsWidth"
|
||||
:label="item.label"
|
||||
prop="caseCount">
|
||||
<template v-slot="scope">
|
||||
<span v-else-if="item.id === 'caseCount'">
|
||||
<router-link
|
||||
:to="scope.row.caseCount > 0 ? {name: 'testCase', params: { projectId: 'all', ids: scope.row.caseIds }} : {}">
|
||||
{{ scope.row.caseCount }}
|
||||
</router-link>
|
||||
</template>
|
||||
</ms-table-column>
|
||||
</span>
|
||||
|
||||
<div v-if="isShowAllColumn">
|
||||
<ms-table-column v-for="field in issueTemplate.customFields" :key="field.id"
|
||||
:field="item"
|
||||
min-width="120"
|
||||
:fields-width="fieldsWidth"
|
||||
:label="field.system ? $t(systemNameMap[field.name]) :field.name"
|
||||
:prop="field.name">
|
||||
<template v-slot="scope">
|
||||
<span v-if="field.name === '状态'">
|
||||
{{ getCustomFieldValue(scope.row, field) ? getCustomFieldValue(scope.row, field) : issueStatusMap[scope.row.status] }}
|
||||
<!-- 自定义字段 -->
|
||||
<span v-else-if="item.isCustom">
|
||||
<span v-if="item.type === 'richText' && scope.row.displayValueMap[item.id]">
|
||||
<ms-review-table-item
|
||||
:data="scope.row.displayValueMap" :prop="item.id"/>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ getCustomFieldValue(scope.row, field) }}
|
||||
{{ scope.row.displayValueMap[item.id] }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span v-else>
|
||||
{{ scope.row[item.id] }}
|
||||
</span>
|
||||
|
||||
</template>
|
||||
</ms-table-column>
|
||||
</div>
|
||||
|
||||
</span>
|
||||
</ms-table>
|
||||
|
||||
<ms-table-pagination :change="getIssues" :current-page.sync="page.currentPage" :page-size.sync="page.pageSize"
|
||||
|
@ -155,7 +101,12 @@ import MsTableColumn from "metersphere-frontend/src/components/table/MsTableColu
|
|||
import MsTableOperators from "metersphere-frontend/src/components/MsTableOperators";
|
||||
import MsTableButton from "metersphere-frontend/src/components/MsTableButton";
|
||||
import MsTablePagination from "metersphere-frontend/src/components/pagination/TablePagination";
|
||||
import {ISSUE_PLATFORM_OPTION, ISSUE_STATUS_MAP, SYSTEM_FIELD_NAME_MAP} from "metersphere-frontend/src/utils/table-constants";
|
||||
import {
|
||||
ISSUE_PLATFORM_OPTION,
|
||||
ISSUE_STATUS_MAP,
|
||||
SYSTEM_FIELD_NAME_MAP,
|
||||
TAPD_ISSUE_STATUS_MAP
|
||||
} from "metersphere-frontend/src/utils/table-constants";
|
||||
import MsTableHeader from "metersphere-frontend/src/components/MsTableHeader";
|
||||
import {getDashboardIssues, getIssuePartTemplateWithProject, getIssues, getPlatformOption} from "@/api/issue";
|
||||
import {
|
||||
|
@ -171,15 +122,15 @@ import {getCurrentProjectID, getCurrentWorkspaceId} from "metersphere-frontend/s
|
|||
import {getProjectMember} from "@/api/user";
|
||||
import {getTableHeaderWithCustomFieldsByXpack} from "@/business/component/js/table-head-util";
|
||||
import {LOCAL} from "metersphere-frontend/src/utils/constants";
|
||||
import IssueDescriptionTableItem from "@/business/component/IssueDescriptionTableItem";
|
||||
import MsReviewTableItem from "@/business/component/MsReviewTableItem";
|
||||
import {getUUID} from "metersphere-frontend/src/utils";
|
||||
|
||||
export default {
|
||||
name: "IssueTableList",
|
||||
components: {
|
||||
MsMainContainer,
|
||||
MsReviewTableItem,
|
||||
MsContainer,
|
||||
IssueDescriptionTableItem,
|
||||
MsTableHeader,
|
||||
MsTablePagination, MsTableButton, MsTableOperators, MsTableColumn, MsTable
|
||||
},
|
||||
|
@ -238,6 +189,9 @@ export default {
|
|||
issueStatusMap() {
|
||||
return ISSUE_STATUS_MAP;
|
||||
},
|
||||
tapdIssueStatusMap() {
|
||||
return TAPD_ISSUE_STATUS_MAP;
|
||||
},
|
||||
systemNameMap() {
|
||||
return SYSTEM_FIELD_NAME_MAP;
|
||||
},
|
||||
|
@ -324,6 +278,7 @@ export default {
|
|||
this.page.total = data.itemCount;
|
||||
this.page.data = data.listObject;
|
||||
parseCustomFilesForList(this.page.data);
|
||||
this.initCustomFieldValue();
|
||||
});
|
||||
} else {
|
||||
this.page.result.loading = getIssues(this.page).then((response) => {
|
||||
|
@ -331,9 +286,34 @@ export default {
|
|||
this.page.total = data.itemCount;
|
||||
this.page.data = data.listObject;
|
||||
parseCustomFilesForList(this.page.data);
|
||||
this.initCustomFieldValue();
|
||||
});
|
||||
}
|
||||
},
|
||||
initCustomFieldValue() {
|
||||
if (this.fields.length <= 0) {
|
||||
return;
|
||||
}
|
||||
this.page.data.forEach(item => {
|
||||
let displayValueMap = {};
|
||||
let fieldIdSet = new Set(this.fields.map(i => i.id));
|
||||
this.issueTemplate.customFields.forEach(field => {
|
||||
let displayValue;
|
||||
if (!fieldIdSet.has(field.name)) {
|
||||
return;
|
||||
}
|
||||
if (field.name === '状态') {
|
||||
displayValue = this.getCustomFieldValue(item, field, this.issueStatusMap[item.status]);
|
||||
} else {
|
||||
displayValue = this.getCustomFieldValue(item, field);
|
||||
}
|
||||
displayValueMap[field.name] = displayValue;
|
||||
});
|
||||
item.displayValueMap = displayValueMap;
|
||||
});
|
||||
this.loading = false;
|
||||
},
|
||||
|
||||
handleEdit(resource) {
|
||||
let issueData = this.$router.resolve({path: '/track/issue', query: {id: resource.id}});
|
||||
window.open(issueData.href, '_blank');
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<el-popover
|
||||
placement="right"
|
||||
width="500"
|
||||
trigger="hover"
|
||||
popper-class="issues-popover">
|
||||
<ms-mark-down-text :prop="prop" :data="data" :disabled="true"/>
|
||||
<el-button slot="reference" type="text">{{ $t('test_track.issue.preview') }}</el-button>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTableColumn from "metersphere-frontend/src/components/table/MsTableColumn";
|
||||
import MsMarkDownText from "metersphere-frontend/src/components/MsMarkDownText";
|
||||
|
||||
export default {
|
||||
name: "MsReviewTableItem",
|
||||
components: {MsMarkDownText, MsTableColumn},
|
||||
props: {
|
||||
data: Object,
|
||||
prop: String,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
Loading…
Reference in New Issue