This commit is contained in:
chenjianxing 2020-12-23 19:09:28 +08:00
commit 17581da725
26 changed files with 315 additions and 179 deletions

View File

@ -254,7 +254,7 @@ public class APITestController {
* */ * */
long dateCountByCreateInThisWeek = apiAutomationService.countScenarioByProjectIDAndCreatInThisWeek(projectId); long dateCountByCreateInThisWeek = apiAutomationService.countScenarioByProjectIDAndCreatInThisWeek(projectId);
apiCountResult.setThisWeekAddedCount(dateCountByCreateInThisWeek); apiCountResult.setThisWeekAddedCount(dateCountByCreateInThisWeek);
long executedInThisWeekCountNumber = apiScenarioReportService.countByProjectIDAndCreateInThisWeek(projectId); long executedInThisWeekCountNumber = apiScenarioReportService.countByProjectIdAndCreateInThisWeek(projectId);
apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber); apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber);
long executedCountNumber = apiScenarioReportService.countByProjectID(projectId); long executedCountNumber = apiScenarioReportService.countByProjectID(projectId);
apiCountResult.setExecutedCount(executedCountNumber); apiCountResult.setExecutedCount(executedCountNumber);
@ -275,21 +275,27 @@ public class APITestController {
} }
@GetMapping("/scheduleTaskInfoCount/{workSpaceID}") @GetMapping("/scheduleTaskInfoCount/{projectId}")
public ApiDataCountDTO scheduleTaskInfoCount(@PathVariable String workSpaceID) { public ApiDataCountDTO scheduleTaskInfoCount(@PathVariable String projectId) {
ApiDataCountDTO apiCountResult = new ApiDataCountDTO(); ApiDataCountDTO apiCountResult = new ApiDataCountDTO();
long allTaskCount = scheduleService.countTaskByWorkspaceIdAndGroup(workSpaceID,ScheduleGroup.API_TEST.name()); long allTaskCount = scheduleService.countTaskByProjectId(projectId);
apiCountResult.setAllApiDataCountNumber(allTaskCount); apiCountResult.setAllApiDataCountNumber(allTaskCount);
long taskCountInThisWeek = scheduleService.countTaskByWorkspaceIdAndGroupInThisWeek(workSpaceID,ScheduleGroup.API_TEST.name()); long taskCountInThisWeek = scheduleService.countTaskByProjectIdInThisWeek(projectId);
apiCountResult.setThisWeekAddedCount(taskCountInThisWeek); apiCountResult.setThisWeekAddedCount(taskCountInThisWeek);
long executedInThisWeekCountNumber = apiReportService.countByWorkspaceIdAndGroupAndCreateInThisWeek(workSpaceID,ScheduleGroup.API_TEST.name()); long api_executedInThisWeekCountNumber = apiReportService.countByProjectIdAndCreateInThisWeek(projectId);
long scene_executedInThisWeekCountNumber = apiScenarioReportService.countByProjectIdAndCreateAndByScheduleInThisWeek(projectId);
long executedInThisWeekCountNumber = api_executedInThisWeekCountNumber+scene_executedInThisWeekCountNumber;
apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber); apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber);
//统计 失败 成功 以及总数 //统计 失败 成功 以及总数
List<ApiDataCountResult> allExecuteResult = apiReportService.countByWorkspaceIdAndGroupGroupByExecuteResult(workSpaceID,ScheduleGroup.API_TEST.name()); List<ApiDataCountResult> api_allExecuteResult = apiReportService.countByProjectIdGroupByExecuteResult(projectId);
List<ApiDataCountResult> scene_allExecuteResult = apiScenarioReportService.countByProjectIdGroupByExecuteResult(projectId);
List<ApiDataCountResult> allExecuteResult = new ArrayList<>();
allExecuteResult.addAll(api_allExecuteResult);
allExecuteResult.addAll(scene_allExecuteResult);
apiCountResult.countScheduleExecute(allExecuteResult); apiCountResult.countScheduleExecute(allExecuteResult);
long allCount = apiCountResult.getExecutedCount(); long allCount = apiCountResult.getExecutedCount();
@ -330,10 +336,10 @@ public class APITestController {
return returnList; return returnList;
} }
@GetMapping("/runningTask/{workspaceID}") @GetMapping("/runningTask/{projectID}")
public List<TaskInfoResult> runningTask(@PathVariable String workspaceID) { public List<TaskInfoResult> runningTask(@PathVariable String projectID) {
List<TaskInfoResult> resultList = scheduleService.findRunningTaskInfoByWorkspaceID(workspaceID); List<TaskInfoResult> resultList = scheduleService.findRunningTaskInfoByProjectID(projectID);
for (TaskInfoResult taskInfo : for (TaskInfoResult taskInfo :
resultList) { resultList) {
Date nextExecutionTime = CronUtils.getNextTriggerTime(taskInfo.getRule()); Date nextExecutionTime = CronUtils.getNextTriggerTime(taskInfo.getRule());

View File

@ -110,7 +110,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
if (useEnvironment != null) { if (useEnvironment != null) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class); ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(useEnvironment); ApiTestEnvironmentWithBLOBs environment = environmentService.get(useEnvironment);
config.setConfig(JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class)); if (environment != null && environment.getConfig() != null) {
config.setConfig(JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class));
}
} }
try { try {
if (config != null && config.getConfig() != null) { if (config != null && config.getConfig() != null) {

View File

@ -212,7 +212,7 @@ public class APIReportService {
apiTestReportMapper.deleteByExample(apiTestReportExample); apiTestReportMapper.deleteByExample(apiTestReportExample);
} }
public long countByWorkspaceIdAndGroupAndCreateInThisWeek(String workspaceID, String group) { public long countByProjectIdAndCreateInThisWeek(String projectId) {
Map<String, Date> startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date()); Map<String, Date> startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date());
Date firstTime = startAndEndDateInWeek.get("firstTime"); Date firstTime = startAndEndDateInWeek.get("firstTime");
@ -221,11 +221,11 @@ public class APIReportService {
if(firstTime==null || lastTime == null){ if(firstTime==null || lastTime == null){
return 0; return 0;
}else { }else {
return extApiTestReportMapper.countByProjectIDAndCreateInThisWeek(workspaceID,group,firstTime.getTime(),lastTime.getTime()); return extApiTestReportMapper.countByProjectIDAndCreateInThisWeek(projectId,firstTime.getTime(),lastTime.getTime());
} }
} }
public List<ApiDataCountResult> countByWorkspaceIdAndGroupGroupByExecuteResult(String workspaceID, String group) { public List<ApiDataCountResult> countByProjectIdGroupByExecuteResult(String projectId) {
return extApiTestReportMapper.countByWorkspaceIdAndGroupGroupByExecuteResult(workspaceID,group); return extApiTestReportMapper.countByProjectIdGroupByExecuteResult(projectId);
} }
} }

View File

@ -161,6 +161,7 @@ public class ApiAutomationService {
} }
public void preDelete(String scenarioID){ public void preDelete(String scenarioID){
scheduleService.deleteByResourceId(scenarioID);
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample(); TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
example.createCriteria().andApiScenarioIdEqualTo(scenarioID); example.createCriteria().andApiScenarioIdEqualTo(scenarioID);
@ -172,27 +173,34 @@ public class ApiAutomationService {
idList.add(api.getId()); idList.add(api.getId());
} }
example = new TestPlanApiScenarioExample(); example = new TestPlanApiScenarioExample();
example.createCriteria()
.andIdIn(idList); if(!idList.isEmpty()){
testPlanApiScenarioMapper.deleteByExample(example); example.createCriteria().andIdIn(idList);
testPlanApiScenarioMapper.deleteByExample(example);
}
} }
public void preDelete(List<String> scenarioIDList){ public void preDelete(List<String> scenarioIDList){
List<String> idList = new ArrayList<>(); List<String> testPlanApiScenarioIdList = new ArrayList<>();
List<String> scheduleIdList = new ArrayList<>();
for (String id :scenarioIDList) { for (String id :scenarioIDList) {
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample(); TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
example.createCriteria().andApiScenarioIdEqualTo(id); example.createCriteria().andApiScenarioIdEqualTo(id);
List<TestPlanApiScenario> testPlanApiScenarioList = testPlanApiScenarioMapper.selectByExample(example); List<TestPlanApiScenario> testPlanApiScenarioList = testPlanApiScenarioMapper.selectByExample(example);
for (TestPlanApiScenario api :testPlanApiScenarioList) { for (TestPlanApiScenario api :testPlanApiScenarioList) {
if(!idList.contains(api.getId())){ if(!testPlanApiScenarioIdList.contains(api.getId())){
idList.add(api.getId()); testPlanApiScenarioIdList.add(api.getId());
} }
} }
scheduleService.deleteByResourceId(id);
} }
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample(); if(!testPlanApiScenarioIdList.isEmpty()){
example.createCriteria() TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
.andIdIn(idList); example.createCriteria().andIdIn(testPlanApiScenarioIdList);
testPlanApiScenarioMapper.deleteByExample(example); testPlanApiScenarioMapper.deleteByExample(example);
}
} }
public void deleteBatch(List<String> ids) { public void deleteBatch(List<String> ids) {
//及连删除外键表 //及连删除外键表

View File

@ -6,6 +6,7 @@ import io.metersphere.api.dto.DeleteAPIReportRequest;
import io.metersphere.api.dto.QueryAPIReportRequest; import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult; import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.automation.ExecuteType; import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.jmeter.ScenarioResult; import io.metersphere.api.jmeter.ScenarioResult;
import io.metersphere.api.jmeter.TestResult; import io.metersphere.api.jmeter.TestResult;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
@ -254,7 +255,7 @@ public class ApiScenarioReportService {
return extApiScenarioReportMapper.countByProjectID(projectId); return extApiScenarioReportMapper.countByProjectID(projectId);
} }
public long countByProjectIDAndCreateInThisWeek(String projectId) { public long countByProjectIdAndCreateAndByScheduleInThisWeek(String projectId) {
Map<String, Date> startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date()); Map<String, Date> startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date());
Date firstTime = startAndEndDateInWeek.get("firstTime"); Date firstTime = startAndEndDateInWeek.get("firstTime");
@ -263,7 +264,24 @@ public class ApiScenarioReportService {
if (firstTime == null || lastTime == null) { if (firstTime == null || lastTime == null) {
return 0; return 0;
} else { } else {
return extApiScenarioReportMapper.countByProjectIDAndCreateInThisWeek(projectId, firstTime.getTime(), lastTime.getTime()); return extApiScenarioReportMapper.countByProjectIdAndCreateAndByScheduleInThisWeek(projectId, firstTime.getTime(), lastTime.getTime());
} }
} }
public long countByProjectIdAndCreateInThisWeek(String projectId) {
Map<String, Date> startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date());
Date firstTime = startAndEndDateInWeek.get("firstTime");
Date lastTime = startAndEndDateInWeek.get("lastTime");
if (firstTime == null || lastTime == null) {
return 0;
} else {
return extApiScenarioReportMapper.countByProjectIdAndCreateInThisWeek(projectId, firstTime.getTime(), lastTime.getTime());
}
}
public List<ApiDataCountResult> countByProjectIdGroupByExecuteResult(String projectId) {
return extApiScenarioReportMapper.countByProjectIdGroupByExecuteResult(projectId);
}
} }

View File

@ -37,7 +37,8 @@
SELECT testCase.testCaseName AS caseName,testCase.testPlanName AS testPlan ,caseErrorCountData.dataCountNumber AS failureTimes,'apiCase' AS caseType SELECT testCase.testCaseName AS caseName,testCase.testPlanName AS testPlan ,caseErrorCountData.dataCountNumber AS failureTimes,'apiCase' AS caseType
FROM ( FROM (
SELECT apiCase.id AS testCaseID,apiCase.`name` AS testCaseName,group_concat(testPlan.`name`) AS testPlanName FROM api_test_case apiCase SELECT apiCase.id AS testCaseID,apiCase.`name` AS testCaseName,group_concat(testPlan.`name`) AS testPlanName FROM api_test_case apiCase
LEFT JOIN test_plan testPlan ON testPlan.api_ids like concat('%"',apiCase.id,'"%') LEFT JOIN test_plan_api_case testPlanCase ON testPlanCase.api_case_id = apiCase.id
LEFT JOIN test_plan testPlan ON testPlan.id = testPlanCase.test_plan_id
GROUP BY apiCase.id GROUP BY apiCase.id
ORDER BY apiCase.create_time DESC ORDER BY apiCase.create_time DESC
)testCase )testCase

View File

@ -2,6 +2,7 @@ package io.metersphere.base.mapper.ext;
import io.metersphere.api.dto.QueryAPIReportRequest; import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult; import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
@ -14,6 +15,9 @@ public interface ExtApiScenarioReportMapper {
long countByProjectID(String projectId); long countByProjectID(String projectId);
long countByProjectIDAndCreateInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp); long countByProjectIdAndCreateInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp);
long countByProjectIdAndCreateAndByScheduleInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp);
List<ApiDataCountResult> countByProjectIdGroupByExecuteResult(String projectId);
} }

View File

@ -169,9 +169,28 @@
<select id="countByProjectID" resultType="java.lang.Long"> <select id="countByProjectID" resultType="java.lang.Long">
SELECT count(id) AS countNumber FROM api_scenario_report WHERE project_id = #{0} SELECT count(id) AS countNumber FROM api_scenario_report WHERE project_id = #{0}
</select> </select>
<select id="countByProjectIDAndCreateInThisWeek" resultType="java.lang.Long"> <select id="countByProjectIdAndCreateInThisWeek" resultType="java.lang.Long">
SELECT count(id) AS countNumber FROM api_scenario_report SELECT count(id) AS countNumber FROM api_scenario_report
WHERE project_id = #{projectId} WHERE project_id = #{projectId}
AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp} AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp}
</select> </select>
<select id="countByProjectIdAndCreateAndByScheduleInThisWeek" resultType="java.lang.Long">
SELECT count(acr.report_id) AS countNumber FROM api_scenario_report_detail acr
INNER JOIN api_scenario_report ar ON ar.id = acr.report_id
INNER JOIN (
SELECT acitem.id FROM api_scenario acitem INNER JOIN `schedule` sc ON acitem.id = sc.resource_id
) ac on acr.content like CONCAT('%', ac.id,'%')
WHERE acr.project_id = #{projectId} AND ar.create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp}
</select>
<select id="countByProjectIdGroupByExecuteResult" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult">
SELECT count(acr.report_id) AS countNumber,ar.status AS groupField
FROM api_scenario_report_detail acr
INNER JOIN api_scenario_report ar ON ar.id = acr.report_id
INNER JOIN (
SELECT acitem.id FROM api_scenario acitem INNER JOIN `schedule` sc ON acitem.id = sc.resource_id
) ac on acr.content like CONCAT('%', ac.id,'%')
WHERE acr.project_id = #{projectId}
</select>
</mapper> </mapper>

View File

@ -18,7 +18,7 @@ public interface ExtApiTestReportMapper {
List<DashboardTestDTO> selectDashboardTests(@Param("workspaceId") String workspaceId, @Param("startTimestamp") long startTimestamp); List<DashboardTestDTO> selectDashboardTests(@Param("workspaceId") String workspaceId, @Param("startTimestamp") long startTimestamp);
List<ApiDataCountResult> countByWorkspaceIdAndGroupGroupByExecuteResult(@Param("workspaceID") String workspaceID, @Param("group")String group); List<ApiDataCountResult> countByProjectIdGroupByExecuteResult(String projectId);
long countByProjectIDAndCreateInThisWeek(@Param("workspaceID") String workspaceID, @Param("group")String group, @Param("startTime") long startTime, @Param("endTime")long endTime); long countByProjectIDAndCreateInThisWeek(@Param("projectId") String projectId, @Param("startTime") long startTime, @Param("endTime")long endTime);
} }

View File

@ -152,19 +152,24 @@
GROUP BY x GROUP BY x
</select> </select>
<select id="countByWorkspaceIdAndGroupGroupByExecuteResult" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult"> <select id="countByProjectIdGroupByExecuteResult" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult">
SELECT testReport.`status` AS groupField,COUNT(testReportDetail.report_id) AS countNumber SELECT testReport.`status` AS groupField,COUNT(testReportDetail.report_id) AS countNumber
FROM api_test_report_detail testReportDetail FROM api_test_report_detail testReportDetail
INNER JOIN `schedule` sch ON sch.resource_id = testReportDetail.test_id INNER JOIN `schedule` sch ON sch.resource_id = testReportDetail.test_id
INNER JOIN api_test_report testReport ON testReportDetail.report_id = testReport.id INNER JOIN api_test_report testReport ON testReportDetail.report_id = testReport.id
WHERE workspace_id = #{workspaceID} AND `group` = #{group} WHERE sch.resource_id IN (
SELECT id FROM api_test WHERE project_id = #{projectId,jdbcType=VARCHAR}
)
AND `group` = #{group}
</select> </select>
<select id="countByProjectIDAndCreateInThisWeek" resultType="java.lang.Long"> <select id="countByProjectIDAndCreateInThisWeek" resultType="java.lang.Long">
SELECT COUNT(testReportDetail.report_id) AS countNumber FROM api_test_report_detail testReportDetail SELECT COUNT(testReportDetail.report_id) AS countNumber FROM api_test_report_detail testReportDetail
INNER JOIN `schedule` sch ON sch.resource_id = testReportDetail.test_id INNER JOIN `schedule` sch ON sch.resource_id = testReportDetail.test_id
INNER JOIN api_test_report testReport ON testReportDetail.report_id = testReport.id INNER JOIN api_test_report testReport ON testReportDetail.report_id = testReport.id
WHERE workspace_id = #{workspaceID} AND `group` = #{group} WHERE sch.resource_id IN (
SELECT id FROM api_test WHERE project_id = #{projectId,jdbcType=VARCHAR}
)
AND testReport.create_time BETWEEN #{startTime} and #{endTime} AND testReport.create_time BETWEEN #{startTime} and #{endTime}
</select> </select>
</mapper> </mapper>

View File

@ -10,9 +10,9 @@ import java.util.List;
public interface ExtScheduleMapper { public interface ExtScheduleMapper {
List<ScheduleDao> list(@Param("request") QueryScheduleRequest request); List<ScheduleDao> list(@Param("request") QueryScheduleRequest request);
long countTaskByWorkspaceIdAndGroup(@Param("workspaceId") String workspaceId,@Param("group") String group); long countTaskByProjectId(String workspaceId);
long countTaskByWorkspaceIdAndGroupAndCreateTimeRange(@Param("workspaceId")String workspaceId,@Param("group") String group, @Param("startTime") long startTime, @Param("endTime") long endTime); long countTaskByProjectIdAndCreateTimeRange(@Param("projectId")String projectId, @Param("startTime") long startTime, @Param("endTime") long endTime);
List<TaskInfoResult> findRunningTaskInfoByWorkspaceID(String workspaceID); List<TaskInfoResult> findRunningTaskInfoByProjectID(String workspaceID);
} }

View File

@ -36,26 +36,33 @@
</if> </if>
</select> </select>
<select id="countTaskByWorkspaceIdAndGroup" resultType="java.lang.Long"> <select id="countTaskByProjectId" resultType="java.lang.Long">
SELECT COUNT(id) AS countNumber FROM `schedule` WHERE `workspace_id` = #{workspaceId} AND `group` = #{group} SELECT COUNT(id) AS countNumber FROM `schedule` WHERE resource_id IN (
SELECT id FROM api_test WHERE project_id = #{0,jdbcType=VARCHAR}
UNION
SELECT id FROM api_scenario WHERE project_id = #{0,jdbcType=VARCHAR}
)
</select> </select>
<select id="countTaskByWorkspaceIdAndGroupAndCreateTimeRange" resultType="java.lang.Long"> <select id="countTaskByProjectIdAndCreateTimeRange" resultType="java.lang.Long">
SELECT COUNT(id) AS countNumber FROM `schedule` SELECT COUNT(id) AS countNumber FROM `schedule`
WHERE workspace_id = #{workspaceId} WHERE resource_id IN (
AND `group` = #{group} SELECT id FROM api_test WHERE project_id = #{projectId,jdbcType=VARCHAR}
UNION
SELECT id FROM api_scenario WHERE project_id = #{projectId,jdbcType=VARCHAR}
)
AND create_time BETWEEN #{startTime} and #{endTime} AND create_time BETWEEN #{startTime} and #{endTime}
</select> </select>
<select id="findRunningTaskInfoByWorkspaceID" resultType="io.metersphere.api.dto.datacount.response.TaskInfoResult"> <select id="findRunningTaskInfoByProjectID" resultType="io.metersphere.api.dto.datacount.response.TaskInfoResult">
SELECT apiTest.`name` AS scenario,sch.id AS taskID,sch.`value` AS rule,sch.`enable` AS `taskStatus`,u.`name` AS creator,sch.update_time AS updateTime SELECT apiTest.`name` AS scenario,sch.id AS taskID,sch.`value` AS rule,sch.`enable` AS `taskStatus`,u.`name` AS creator,sch.update_time AS updateTime
FROM api_test apiTest FROM api_test apiTest
INNER JOIN `schedule` sch ON apiTest.id = sch.resource_id INNER JOIN `schedule` sch ON apiTest.id = sch.resource_id
INNER JOIN `user` u ON u.id = sch.user_id INNER JOIN `user` u ON u.id = sch.user_id
WHERE sch.`enable` = true AND sch.workspace_id = #{0,jdbcType=VARCHAR} WHERE sch.`enable` = true AND apiTest.project_id = #{0,jdbcType=VARCHAR}
UNION UNION
SELECT apiTest.`name` AS scenario,sch.id AS taskID,sch.`value` AS rule,sch.`enable` AS `taskStatus`,u.`name` AS creator,sch.update_time AS updateTime SELECT apiScene.`name` AS scenario,sch.id AS taskID,sch.`value` AS rule,sch.`enable` AS `taskStatus`,u.`name` AS creator,sch.update_time AS updateTime
FROM api_scenario apiTest FROM api_scenario apiScene
INNER JOIN `schedule` sch ON apiTest.id = sch.resource_id INNER JOIN `schedule` sch ON apiScene.id = sch.resource_id
INNER JOIN `user` u ON u.id = sch.user_id INNER JOIN `user` u ON u.id = sch.user_id
WHERE sch.`enable` = true AND sch.workspace_id = #{0,jdbcType=VARCHAR} WHERE sch.`enable` = true AND apiScene.project_id = #{0,jdbcType=VARCHAR}
</select> </select>
</mapper> </mapper>

View File

@ -20,7 +20,6 @@ import io.metersphere.dto.ScheduleDao;
import io.metersphere.job.sechedule.ApiTestJob; import io.metersphere.job.sechedule.ApiTestJob;
import io.metersphere.job.sechedule.ScheduleManager; import io.metersphere.job.sechedule.ScheduleManager;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.quartz.JobDetail;
import org.quartz.JobKey; import org.quartz.JobKey;
import org.quartz.SchedulerException; import org.quartz.SchedulerException;
import org.quartz.TriggerKey; import org.quartz.TriggerKey;
@ -168,11 +167,11 @@ public class ScheduleService {
}); });
} }
public long countTaskByWorkspaceIdAndGroup(String workspaceId,String group) { public long countTaskByProjectId(String projectId) {
return extScheduleMapper.countTaskByWorkspaceIdAndGroup(workspaceId,group); return extScheduleMapper.countTaskByProjectId(projectId);
} }
public long countTaskByWorkspaceIdAndGroupInThisWeek(String workspaceID, String group) { public long countTaskByProjectIdInThisWeek(String projectId) {
Map<String, Date> startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date()); Map<String, Date> startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date());
Date firstTime = startAndEndDateInWeek.get("firstTime"); Date firstTime = startAndEndDateInWeek.get("firstTime");
@ -181,12 +180,12 @@ public class ScheduleService {
if(firstTime==null || lastTime == null){ if(firstTime==null || lastTime == null){
return 0; return 0;
}else { }else {
return extScheduleMapper.countTaskByWorkspaceIdAndGroupAndCreateTimeRange(workspaceID,group,firstTime.getTime(),lastTime.getTime()); return extScheduleMapper.countTaskByProjectIdAndCreateTimeRange(projectId,firstTime.getTime(),lastTime.getTime());
} }
} }
public List<TaskInfoResult> findRunningTaskInfoByWorkspaceID(String workspaceID) { public List<TaskInfoResult> findRunningTaskInfoByProjectID(String projectID) {
List<TaskInfoResult> runningTaskInfoList = extScheduleMapper.findRunningTaskInfoByWorkspaceID(workspaceID); List<TaskInfoResult> runningTaskInfoList = extScheduleMapper.findRunningTaskInfoByProjectID(projectID);
return runningTaskInfoList; return runningTaskInfoList;
} }
} }

View File

@ -33,6 +33,7 @@
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-calendar-heatmap": "^0.8.4", "vue-calendar-heatmap": "^0.8.4",
"vue-echarts": "^4.1.0", "vue-echarts": "^4.1.0",
"vue-float-action-button": "^0.6.6",
"vue-i18n": "^8.15.3", "vue-i18n": "^8.15.3",
"vue-input-tag": "^2.0.7", "vue-input-tag": "^2.0.7",
"vue-pdf": "^4.2.0", "vue-pdf": "^4.2.0",

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog :close-on-click-modal="false" :title="$t('api_test.definition.request.title')" :visible.sync="visible" <el-dialog :close-on-click-modal="false" :title="$t('api_test.automation.add_scenario')" :visible.sync="visible"
width="45%" width="45%"
:destroy-on-close="true"> :destroy-on-close="true">
<el-form :model="scenarioForm" label-position="right" label-width="80px" size="small" :rules="rule" <el-form :model="scenarioForm" label-position="right" label-width="80px" size="small" :rules="rule"

View File

@ -182,42 +182,19 @@
</el-col> </el-col>
<!-- 按钮列表 --> <!-- 按钮列表 -->
<div> <div>
<el-col :span="3" class="ms-left-cell"> <el-col :span="3">
<el-button type="primary" icon="el-icon-refresh" size="small" @click="showAll">{{$t('commons.show_all')}}</el-button> <vue-fab id="fab" mainBtnColor="#783887" :click-auto-close="false">
<br/> <fab-item
<div v-if="operatingElements.indexOf('HTTPSamplerProxy')!=-1 || operatingElements.indexOf('DubboSampler')!=-1 || operatingElements.indexOf('JDBCSampler')!=-1 || operatingElements.indexOf('TCPSampler')!=-1 "> v-for="(item, index) in buttons"
<el-button class="ms-right-buttion ms-btn-1" size="small" @click="apiListImport">+{{$t('api_test.automation.api_list_import')}}</el-button> :key="index"
</div> :idx="getIdx(index)"
<div v-if="operatingElements.indexOf('OT_IMPORT')!=-1"> :title="item.title"
<el-button class="ms-right-buttion" size="small" style="color: #409EFF;background-color: #EEF5FE" @click="addComponent('OT_IMPORT')">+{{$t('api_test.automation.external_import')}}</el-button> :title-bg-color="item.titleBgColor"
</div> :title-color="item.titleColor"
<div v-if="operatingElements.indexOf('ConstantTimer')!=-1"> :color="item.titleColor"
<el-button class="ms-right-buttion ms-btn-3" size="small" @click="addComponent('ConstantTimer')">+{{$t('api_test.automation.wait_controller')}}</el-button> :icon="item.icon"
</div> @clickItem="item.click"/>
<div v-if="operatingElements.indexOf('IfController')!=-1"> </vue-fab>
<el-button class="ms-right-buttion ms-btn-4" size="small" @click="addComponent('IfController')">+{{$t('api_test.automation.if_controller')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('scenario')===0">
<el-button class="ms-right-buttion ms-btn-5" size="small" @click="addComponent('scenario')">+{{$t('api_test.automation.scenario_import')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('JSR223Processor')!=-1">
<el-button class="ms-right-buttion ms-btn-6" size="small" @click="addComponent('JSR223Processor')">+{{$t('api_test.automation.customize_script')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('CustomizeReq')!=-1">
<el-button class="ms-right-buttion ms-btn-7" size="small" @click="addComponent('CustomizeReq')">+{{$t('api_test.automation.customize_req')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('JSR223PreProcessor')!=-1">
<el-button class="ms-right-buttion ms-btn-8" size="small" @click="addComponent('JSR223PreProcessor')">+{{$t('api_test.definition.request.pre_script')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('JSR223PostProcessor')!=-1">
<el-button class="ms-right-buttion ms-btn-9" size="small" @click="addComponent('JSR223PostProcessor')">+{{$t('api_test.definition.request.post_script')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('Assertions')!=-1">
<el-button class="ms-right-buttion ms-btn-10" size="small" @click="addComponent('Assertions')">+{{$t('api_test.definition.request.assertions_rule')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('Extract')!=-1">
<el-button class="ms-right-buttion ms-btn-11" size="small" @click="addComponent('Extract')">+{{$t('api_test.definition.request.extract_param')}}</el-button>
</div>
</el-col> </el-col>
</div> </div>
</el-row> </el-row>
@ -282,6 +259,7 @@
import MsScenarioParameters from "./ScenarioParameters"; import MsScenarioParameters from "./ScenarioParameters";
import ApiImport from "../../definition/components/import/ApiImport"; import ApiImport from "../../definition/components/import/ApiImport";
import InputTag from 'vue-input-tag' import InputTag from 'vue-input-tag'
import "@/common/css/material-icons.css"
export default { export default {
name: "EditApiScenario", name: "EditApiScenario",
@ -363,7 +341,123 @@
, ,
watch: {} watch: {}
, ,
computed: {
buttons() {
let buttons = [
{
title: this.$t('api_test.automation.api_list_import'),
show: this.showButton("HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler"),
titleColor: "#F56C6C",
titleBgColor: "#FCF1F1",
icon: "api",
click: this.apiListImport
}, {
title: this.$t('api_test.automation.external_import'),
show: this.showButton("OT_IMPORT"),
titleColor: "#409EFF",
titleBgColor: "#EEF5FE",
icon: "next_plan",
click: () => {
this.addComponent('OT_IMPORT')
}
}, {
title: this.$t('api_test.automation.wait_controller'),
show: this.showButton("ConstantTimer"),
titleColor: "#67C23A",
titleBgColor: "#F2F9EE",
icon: "access_time",
click: () => {
this.addComponent('ConstantTimer')
}
}, {
title: this.$t('api_test.automation.if_controller'),
show: this.showButton("IfController"),
titleColor: "#E6A23C",
titleBgColor: "#FCF6EE",
icon: "alt_route",
click: () => {
this.addComponent('IfController')
}
}, {
title: this.$t('api_test.automation.scenario_import'),
show: this.operatingElements.indexOf('scenario') === 0,
titleColor: "#606266",
titleBgColor: "#F4F4F5",
icon: "movie",
click: () => {
this.addComponent('scenario')
}
}, {
title: this.$t('api_test.automation.customize_script'),
show: this.showButton("JSR223Processor"),
titleColor: "#7B4D12",
titleBgColor: "#F1EEE9",
icon: "code",
click: () => {
this.addComponent('JSR223Processor')
}
}, {
title: this.$t('api_test.automation.customize_req'),
show: this.showButton("CustomizeReq"),
titleColor: "#008080",
titleBgColor: "#EBF2F2",
icon: "tune",
click: () => {
this.addComponent('CustomizeReq')
}
}, {
title: this.$t('api_test.definition.request.pre_script'),
show: this.showButton("JSR223PreProcessor"),
titleColor: "#B8741A",
titleBgColor: "#F9F1EA",
icon: "skip_previous",
click: () => {
this.addComponent('JSR223PreProcessor')
}
}, {
title: this.$t('api_test.definition.request.post_script'),
show: this.showButton("JSR223PostProcessor"),
titleColor: "#783887",
titleBgColor: "#F2ECF3",
icon: "skip_next",
click: () => {
this.addComponent('JSR223PostProcessor')
}
}, {
title: this.$t('api_test.definition.request.assertions_rule'),
show: this.showButton("Assertions"),
titleColor: "#A30014",
titleBgColor: "#F7E6E9",
icon: "fact_check",
click: () => {
this.addComponent('Assertions')
}
}, {
title: this.$t('api_test.definition.request.extract_param'),
show: this.showButton("Extract"),
titleColor: "#015478",
titleBgColor: "#E6EEF2",
icon: "colorize",
click: () => {
this.addComponent('Extract')
}
}
];
return buttons.filter(btn => btn.show);
}
},
methods: { methods: {
getIdx(index) {
return -1 * index - 2.25; //
},
showButton(...names) {
for (const name of names) {
if (this.operatingElements.includes(name)) {
return true;
}
}
return false;
},
addComponent(type) { addComponent(type) {
switch (type) { switch (type) {
case ELEMENT_TYPE.IfController: case ELEMENT_TYPE.IfController:
@ -842,63 +936,10 @@
margin-top: 5px; margin-top: 5px;
} }
.ms-right-buttion { #fab {
margin-top: 10px; bottom: unset;
} right: 90px;
z-index: 5;
.ms-btn-1 {
color: #F56C6C;
background-color: #FCF1F1
}
.ms-btn-2 {
color: #F56C6C;
background-color: #FCF1F1
}
.ms-btn-3 {
color: #67C23A;
background-color: #F2F9EE
}
.ms-btn-4 {
color: #E6A23C;
background-color: #FCF6EE
}
.ms-btn-5 {
color: #606266;
background-color: #F4F4F5
}
.ms-btn-6 {
color: #7B4D12;
background-color: #F1EEE9
}
.ms-btn-7 {
color: #008080;
background-color: #EBF2F2
}
.ms-btn-8 {
color: #B8741A;
background-color: #F9F1EA
}
.ms-btn-9 {
color: #783887;
background-color: #F2ECF3
}
.ms-btn-10 {
color: #A30014;
background-color: #F7E6E9
}
.ms-btn-11 {
color: #015478;
background-color: #E6EEF2
} }
/deep/ .el-tree-node__content { /deep/ .el-tree-node__content {
@ -944,5 +985,4 @@
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif; font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px; font-size: 13px;
} }
</style> </style>

View File

@ -31,14 +31,14 @@
<style scoped> <style scoped>
ms-input-tag-wrapper >>> .vue-input-tag-wrapper { .ms-input-tag-wrapper >>> .vue-input-tag-wrapper {
border-radius: 2px; border-radius: 2px;
border: 1px solid #a5d24a; border: 1px solid #a5d24a;
color: #909399; color: #909399;
display: inline-block; display: inline-block;
} }
ms-input-remove >>> .remove { .ms-input-remove >>> .remove {
color: #909399; color: #909399;
} }

View File

@ -50,10 +50,12 @@ function defaultCustomValidate() {
} }
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/); const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default { export default {
name: "MsScheduleMaintain", name: "MsScheduleMaintain",
components: {CrontabResult, Crontab, MsScheduleNotification}, components: {CrontabResult, Crontab, MsScheduleNotification,"NoticeTemplate": noticeTemplate.default},
props: { props: {
customValidate: { customValidate: {

View File

@ -20,7 +20,7 @@
<div> <div>
<el-select size="small" :placeholder="$t('api_test.definition.request.grade_info')" v-model="condition.priority" <el-select size="small" :placeholder="$t('api_test.definition.request.grade_info')" v-model="condition.priority"
:disabled="isCaseEdit" :disabled="isCaseEdit"
class="ms-api-header-select" @change="getApiTest" clearable> class="ms-api-header-select" @change="getApiTest" clearable style="margin-right: 20px">
<el-option v-for="grd in priorities" :key="grd.id" :label="grd.name" :value="grd.id"/> <el-option v-for="grd in priorities" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select> </el-select>
</div> </div>

View File

@ -248,7 +248,7 @@
let arr = Array.from(this.selectRows); let arr = Array.from(this.selectRows);
// 1 // 1
if (this.selectRows.size === 1) { if (this.selectRows.size === 1) {
this.$set(arr[0], "showMore", false); this.$set(arr[0], "showMore", true);
} else if (this.selectRows.size === 2) { } else if (this.selectRows.size === 2) {
arr.forEach(row => { arr.forEach(row => {
this.$set(row, "showMore", true); this.$set(row, "showMore", true);

View File

@ -13,12 +13,12 @@
<el-option v-for="(environment, index) in environments" :key="index" <el-option v-for="(environment, index) in environments" :key="index"
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')" :label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
:value="environment.id"/> :value="environment.id"/>
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig"> <el-button class="environment-button" size="small" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }} {{ $t('api_test.environment.environment_config') }}
</el-button> </el-button>
<template v-slot:empty> <template v-slot:empty>
<div class="empty-environment"> <div class="empty-environment">
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig"> <el-button class="environment-button" size="small" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }} {{ $t('api_test.environment.environment_config') }}
</el-button> </el-button>
</div> </div>
@ -43,11 +43,11 @@
<el-form-item :label="$t('api_test.request.sql.result_variable')" prop="resultVariable"> <el-form-item :label="$t('api_test.request.sql.result_variable')" prop="resultVariable">
<el-input v-model="request.resultVariable" maxlength="300" show-word-limit/> <el-input v-model="request.resultVariable" maxlength="300" show-word-limit size="small"/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('api_test.request.sql.variable_names')" prop="variableNames"> <el-form-item :label="$t('api_test.request.sql.variable_names')" prop="variableNames">
<el-input v-model="request.variableNames" maxlength="300" show-word-limit/> <el-input v-model="request.variableNames" maxlength="300" show-word-limit size="small"/>
</el-form-item> </el-form-item>
<el-tabs v-model="activeName"> <el-tabs v-model="activeName">
@ -136,7 +136,7 @@
isReloadData: false, isReloadData: false,
activeName: "variables", activeName: "variables",
rules: { rules: {
environmentId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}], environmentId: [{required: true, message: this.$t('api_test.definition.request.run_env'), trigger: 'change'}],
dataSourceId: [{required: true, message: this.$t('api_test.request.sql.dataSource'), trigger: 'change'}], dataSourceId: [{required: true, message: this.$t('api_test.request.sql.dataSource'), trigger: 'change'}],
}, },
} }
@ -209,6 +209,16 @@
this.environments.forEach(environment => { this.environments.forEach(environment => {
parseEnvironment(environment); parseEnvironment(environment);
}); });
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.request.environmentId) {
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.request.environmentId = undefined;
}
this.initDataSource(); this.initDataSource();
}); });
}, },

View File

@ -7,12 +7,8 @@
</div> </div>
<div v-else-if="dateType==='2'"> <div v-else-if="dateType==='2'">
<el-link href="https://github.com/metersphere/metersphere/issues" target="_blank" type="primary">😔觉得MeterSphere不好用就来https://github.com/metersphere/metersphere/issues</el-link> <el-link href="https://github.com/metersphere/metersphere/issues" target="_blank" type="primary">😔觉得MeterSphere不好用就来https://github.com/metersphere/metersphere/issues</el-link>
<!-- <el-link href="https://jmeter.apache.org/usermanual/component_reference.html#BeanShell_PostProcessor"-->
<!-- type="primary">{{$t('commons.reference_documentation')}}-->
<!-- </el-link>-->
</div> </div>
<div v-else-if="dateType==='3'"> <div v-else-if="dateType==='3'">
<!-- <el-link :herf="'https://github.com/metersphere/metersphere/issues'" target="_blank"></el-link>-->
<el-link href="https://github.com/metersphere/metersphere" target="_blank" type="primary">😄觉得MeterSphere好用就来 https://github.com/metersphere/metersphere star</el-link> <el-link href="https://github.com/metersphere/metersphere" target="_blank" type="primary">😄觉得MeterSphere好用就来 https://github.com/metersphere/metersphere star</el-link>
</div> </div>
<div v-else> <div v-else>
@ -58,21 +54,15 @@ import MsSceneInfoCard from "./components/SceneInfoCard";
import MsScheduleTaskInfoCard from "./components/ScheduleTaskInfoCard"; import MsScheduleTaskInfoCard from "./components/ScheduleTaskInfoCard";
import MsTestCaseInfoCard from "./components/TestCaseInfoCard"; import MsTestCaseInfoCard from "./components/TestCaseInfoCard";
// import MsApiDetailCard from "./components/ApiDetailCard";
// import MsSceneDetailCard from "./components/SceneDetailCard";
// import MsScheduleTaskDetailCard from "./components/ScheduleTaskDetailCard";
// import MsTestCaseDetailCard from "./components/TestCaseDetailCard";
import MsFailureTestCaseList from "./components/FailureTestCaseList"; import MsFailureTestCaseList from "./components/FailureTestCaseList";
import MsRunningTaskList from "./components/RunningTaskList" import MsRunningTaskList from "./components/RunningTaskList"
import {getCurrentProjectID,getCurrentWorkspaceId} from "@/common/js/utils"; import {getCurrentProjectID} from "@/common/js/utils";
export default { export default {
name: "ApiTestHomePage", name: "ApiTestHomePage",
components: { components: {
MsApiInfoCard, MsSceneInfoCard, MsScheduleTaskInfoCard, MsTestCaseInfoCard, MsApiInfoCard, MsSceneInfoCard, MsScheduleTaskInfoCard, MsTestCaseInfoCard,
// MsApiDetailCard, MsSceneDetailCard, MsScheduleTaskDetailCard, MsTestCaseDetailCard,
MsFailureTestCaseList,MsRunningTaskList, MsFailureTestCaseList,MsRunningTaskList,
MsMainContainer, MsContainer MsMainContainer, MsContainer
}, },
@ -121,8 +111,8 @@ export default {
}); });
let workSpaceID = getCurrentWorkspaceId(); // let workSpaceID = getCurrentWorkspaceId();
this.$get("/api/scheduleTaskInfoCount/"+workSpaceID, response => { this.$get("/api/scheduleTaskInfoCount/"+selectProjectId, response => {
this.scheduleTaskCountData = response.data; this.scheduleTaskCountData = response.data;
}); });
}, },

View File

@ -39,7 +39,7 @@
</template> </template>
<script> <script>
import {getCurrentProjectID,getCurrentWorkspaceId} from "@/common/js/utils"; import {getCurrentProjectID} from "@/common/js/utils";
export default { export default {
name: "MsRunningTaskList", name: "MsRunningTaskList",
@ -56,8 +56,8 @@ export default {
methods: { methods: {
search() { search() {
let workSpaceID = getCurrentWorkspaceId(); let projectID = getCurrentProjectID();
this.result = this.$get("/api/runningTask/"+workSpaceID, response => { this.result = this.$get("/api/runningTask/"+projectID, response => {
this.tableData = response.data; this.tableData = response.data;
}); });
}, },

View File

@ -17,6 +17,7 @@ import CalendarHeatmap from "../common/js/calendar-heatmap";
import '../common/css/menu-header.css'; import '../common/css/menu-header.css';
import '../common/css/main.css'; import '../common/css/main.css';
import CKEditor from '@ckeditor/ckeditor5-vue'; import CKEditor from '@ckeditor/ckeditor5-vue';
import VueFab from 'vue-float-action-button'
Vue.config.productionTip = false; Vue.config.productionTip = false;
Vue.use(icon); Vue.use(icon);
@ -29,7 +30,8 @@ Vue.use(chart);
Vue.use(CalendarHeatmap); Vue.use(CalendarHeatmap);
Vue.use(message); Vue.use(message);
Vue.use(CKEditor); Vue.use(CKEditor);
Vue.use(YanProgress) Vue.use(YanProgress);
Vue.use(VueFab);
// v-permission // v-permission
Vue.directive('permission', permission); Vue.directive('permission', permission);

View File

@ -0,0 +1,22 @@
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(./material.woff2) format('woff2');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}

Binary file not shown.