feat(接口自动化): 获取实时执行步骤结果
This commit is contained in:
parent
fe677b0b40
commit
6743dac777
|
@ -62,4 +62,9 @@ public class APIScenarioReportController {
|
|||
return resultService.getResult(reportId);
|
||||
}
|
||||
|
||||
@GetMapping("/remove/real/{reportId}")
|
||||
public void removeRealReport(@PathVariable String reportId) {
|
||||
resultService.delete(reportId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,7 +39,9 @@ public class MsResultService {
|
|||
testResult = new TestResult();
|
||||
}
|
||||
if (result.getResponseCode().equals(MsResultCollector.TEST_END)) {
|
||||
|
||||
testResult.setEnd(true);
|
||||
this.cache.put(key, testResult);
|
||||
return;
|
||||
}
|
||||
testResult.setTestId(key);
|
||||
testResult.setConsole(getJmeterLogger(key, false));
|
||||
|
@ -50,7 +52,7 @@ public class MsResultService {
|
|||
|
||||
testResult.getScenarios().addAll(scenarios.values());
|
||||
testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId));
|
||||
|
||||
System.out.println(key + "=======" + result.getURL());
|
||||
this.cache.put(key, testResult);
|
||||
}
|
||||
|
||||
|
|
|
@ -136,24 +136,21 @@
|
|||
<el-col :span="3" class="ms-col-one ms-font">
|
||||
<el-checkbox v-model="onSampleError">{{ $t('commons.failure_continues') }}</el-checkbox>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-col :span="8">
|
||||
<div style=" float: right">
|
||||
<env-popover :disabled="scenarioDefinition.length < 1" :env-map="projectEnvMap"
|
||||
:project-ids="projectIds" @setProjectEnvMap="setProjectEnvMap" :result="envResult"
|
||||
:show-config-button-with-out-permission="showConfigButtonWithOutPermission"
|
||||
:isReadOnly="scenarioDefinition.length < 1" @showPopover="showPopover"
|
||||
:project-list="projectList" ref="envPopover"/>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<!-- <el-dropdown split-button type="primary" @click="runDebug" style="margin-right: 10px" size="mini" @command="handleCommand">-->
|
||||
<!-- {{ $t('api_test.request.debug') }}-->
|
||||
<!-- <el-dropdown-menu slot="dropdown">-->
|
||||
<!-- <el-dropdown-item>{{ $t('api_test.run') }}</el-dropdown-item>-->
|
||||
<!-- </el-dropdown-menu>-->
|
||||
<!-- </el-dropdown>-->
|
||||
<el-button :disabled="scenarioDefinition.length < 1" size="mini" type="primary" v-prevent-re-click
|
||||
@click="runDebug">{{ $t('api_test.request.debug') }}
|
||||
</el-button>
|
||||
<el-tooltip class="item" effect="dark" :content="$t('commons.refresh')" placement="right-start">
|
||||
:project-list="projectList" ref="envPopover" style="margin-right: 10px"/>
|
||||
<el-dropdown split-button type="primary" @click="runDebug" style="margin-right: 10px" size="mini" @command="handleCommand" v-if="!debugLoading">
|
||||
{{ $t('api_test.request.debug') }}
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item>{{ $t('test_track.case.steps') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<el-button icon="el-icon-loading" size="mini" type="primary" :disabled="debug" v-else>执行中</el-button>
|
||||
<el-tooltip class="item" effect="dark" :content="$t('commons.refresh')" placement="top-start">
|
||||
<el-button :disabled="scenarioDefinition.length < 1" size="mini" icon="el-icon-refresh"
|
||||
v-prevent-re-click @click="getApiScenario"></el-button>
|
||||
</el-tooltip>
|
||||
|
@ -161,6 +158,7 @@
|
|||
placement="top-start">
|
||||
<font-awesome-icon class="alt-ico" :icon="['fa', 'expand-alt']" size="lg" @click="fullScreen"/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
@ -179,7 +177,7 @@
|
|||
<font-awesome-icon class="ms-open-btn" :icon="['fas', 'toggle-on']" v-prevent-re-click @click="disableAll"/>
|
||||
</el-tooltip>
|
||||
<div class="ms-debug-result" v-if="debug">
|
||||
354 ms 请求 10 成功 8 失败 2
|
||||
{{ reqTotalTime }} ms 请求 {{ reqTotal }} 成功 {{ reqSuccess }} 失败 {{ reqError }}
|
||||
</div>
|
||||
<el-tree node-key="resourceId" :props="props" :data="scenarioDefinition" class="ms-tree"
|
||||
:default-expanded-keys="expandedNode"
|
||||
|
@ -256,15 +254,17 @@
|
|||
:projectIds.sync="projectIds" :projectList="projectList"
|
||||
:scenarioDefinition="scenarioDefinition" :enableCookieShare="enableCookieShare"
|
||||
:onSampleError="onSampleError"
|
||||
:execDebug="stopDebug"
|
||||
:isFullUrl.sync="isFullUrl" @closePage="close" @unFullScreen="unFullScreen"
|
||||
@showAllBtn="showAllBtn" @runDebug="runDebug" @setProjectEnvMap="setProjectEnvMap"
|
||||
@showAllBtn="showAllBtn" @runDebug="runDebug" @handleCommand="handleCommand" @setProjectEnvMap="setProjectEnvMap"
|
||||
@showScenarioParameters="showScenarioParameters"
|
||||
@setCookieShare="setCookieShare" @setSampleError="setSampleError"
|
||||
ref="maximizeHeader"/>
|
||||
</template>
|
||||
|
||||
<maximize-scenario :scenario-definition="scenarioDefinition" :envMap="projectEnvMap" :moduleOptions="moduleOptions"
|
||||
:currentScenario="currentScenario" :type="type" :stepReEnable="stepEnable" ref="maximizeScenario" @openScenario="openScenario"/>
|
||||
:req-error="reqError" :req-success="reqSuccess" :req-total="reqTotal" :req-total-time="reqTotalTime"
|
||||
:currentScenario="currentScenario" :type="type" :debug="debug" :reloadDebug="reloadDebug" :stepReEnable="stepEnable" ref="maximizeScenario" @openScenario="openScenario"/>
|
||||
</ms-drawer>
|
||||
<ms-change-history ref="changeHistory"/>
|
||||
|
||||
|
@ -274,16 +274,7 @@
|
|||
|
||||
<script>
|
||||
import {API_STATUS, PRIORITY} from "../../definition/model/JsonData";
|
||||
import {WORKSPACE_ID} from '@/common/js/constants';
|
||||
import {
|
||||
Assertions,
|
||||
ConstantTimer,
|
||||
Extract,
|
||||
IfController,
|
||||
JSR223Processor,
|
||||
LoopController,
|
||||
TransactionController
|
||||
} from "../../definition/model/ApiTestModel";
|
||||
import {buttons, setComponent} from './menu/Menu';
|
||||
import {parseEnvironment} from "../../definition/model/EnvironmentModel";
|
||||
import {ELEMENT_TYPE, ELEMENTS} from "./Setting";
|
||||
import MsApiCustomize from "./ApiCustomize";
|
||||
|
@ -402,12 +393,21 @@ export default {
|
|||
loading: false
|
||||
},
|
||||
debug: false,
|
||||
debugLoading: false,
|
||||
reqTotal: 0,
|
||||
reqSuccess: 0,
|
||||
reqError: 0,
|
||||
reqTotalTime: 0,
|
||||
reloadDebug: "",
|
||||
stopDebug: "",
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (!this.currentScenario.apiScenarioModuleId) {
|
||||
this.currentScenario.apiScenarioModuleId = "";
|
||||
}
|
||||
this.debug = false;
|
||||
this.debugLoading = false;
|
||||
this.operatingElements = ELEMENTS.get("ALL");
|
||||
this.getWsProjects();
|
||||
this.getMaintainerOptions();
|
||||
|
@ -417,147 +417,106 @@ export default {
|
|||
},
|
||||
directives: {OutsideClick},
|
||||
computed: {
|
||||
buttons() {
|
||||
let buttons = [
|
||||
{
|
||||
title: this.$t('api_test.definition.request.extract_param'),
|
||||
show: this.showButton("Extract"),
|
||||
titleColor: "#015478",
|
||||
titleBgColor: "#E6EEF2",
|
||||
icon: "colorize",
|
||||
click: () => {
|
||||
this.addComponent('Extract')
|
||||
}
|
||||
},
|
||||
{
|
||||
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.pre_script'),
|
||||
show: this.showButton("JSR223PreProcessor"),
|
||||
titleColor: "#B8741A",
|
||||
titleBgColor: "#F9F1EA",
|
||||
icon: "skip_previous",
|
||||
click: () => {
|
||||
this.addComponent('JSR223PreProcessor')
|
||||
}
|
||||
},
|
||||
{
|
||||
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.if_controller'),
|
||||
show: this.showButton("IfController"),
|
||||
titleColor: "#E6A23C",
|
||||
titleBgColor: "#FCF6EE",
|
||||
icon: "alt_route",
|
||||
click: () => {
|
||||
this.addComponent('IfController')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('api_test.automation.loop_controller'),
|
||||
show: this.showButton("LoopController"),
|
||||
titleColor: "#02A7F0",
|
||||
titleBgColor: "#F4F4F5",
|
||||
icon: "next_plan",
|
||||
click: () => {
|
||||
this.addComponent('LoopController')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('api_test.automation.transcation_controller'),
|
||||
show: this.showButton("TransactionController"),
|
||||
titleColor: "#6D317C",
|
||||
titleBgColor: "#F4F4F5",
|
||||
icon: "alt_route",
|
||||
click: () => {
|
||||
this.addComponent('TransactionController')
|
||||
}
|
||||
},
|
||||
{
|
||||
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.definition.request.assertions_rule'),
|
||||
show: this.showButton("Assertions"),
|
||||
titleColor: "#A30014",
|
||||
titleBgColor: "#F7E6E9",
|
||||
icon: "next_plan",
|
||||
click: () => {
|
||||
this.addComponent('Assertions')
|
||||
}
|
||||
},
|
||||
{
|
||||
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.automation.scenario_import'),
|
||||
show: this.showButton("scenario"),
|
||||
titleColor: "#606266",
|
||||
titleBgColor: "#F4F4F5",
|
||||
icon: "movie",
|
||||
click: () => {
|
||||
this.addComponent('scenario')
|
||||
}
|
||||
},
|
||||
{
|
||||
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
|
||||
}
|
||||
];
|
||||
return buttons.filter(btn => btn.show);
|
||||
},
|
||||
buttons,
|
||||
projectId() {
|
||||
return getCurrentProjectID();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clearDebug() {
|
||||
this.reqError = 0;
|
||||
this.reqTotalTime = 0;
|
||||
this.reqTotal = 0;
|
||||
this.reqSuccess = 0;
|
||||
},
|
||||
editParent(node, status) {
|
||||
if (!status) {
|
||||
node.data.code = "error";
|
||||
}
|
||||
node.data.debug = true;
|
||||
if (node.parent && node.parent.data && node.parent.data.id) {
|
||||
this.editParent(node.parent, status);
|
||||
}
|
||||
},
|
||||
findNodeChild(arr, name, index, status) {
|
||||
arr.forEach(item => {
|
||||
if (item.data.name === name && item.data.index === index) {
|
||||
this.editParent(item.parent, status);
|
||||
}
|
||||
if (item.childNodes && item.childNodes.length > 0) {
|
||||
this.findNodeChild(item.childNodes, name, index, status);
|
||||
}
|
||||
})
|
||||
},
|
||||
findNode(name, index, status) {
|
||||
if (this.$refs.stepTree && this.$refs.stepTree.root) {
|
||||
this.$refs.stepTree.root.childNodes.forEach(item => {
|
||||
if (item.childNodes && item.childNodes.length > 0) {
|
||||
this.findNodeChild(item.childNodes, name, index, status);
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
getReport() {
|
||||
if (this.debug) {
|
||||
let url = "/api/scenario/report/get/real/" + this.reportId;
|
||||
this.$get(url, response => {
|
||||
// if (response.data && response.data.end) {
|
||||
// console.log(response.data);
|
||||
// } else {
|
||||
// setTimeout(this.getReport, 2000)
|
||||
// }
|
||||
|
||||
if (response.data) {
|
||||
this.formatResult(response.data);
|
||||
if (response.data.end) {
|
||||
this.removeReport();
|
||||
this.debugLoading = false;
|
||||
this.stopDebug = "stop";
|
||||
} else {
|
||||
setTimeout(this.getReport, 2000)
|
||||
}
|
||||
} else {
|
||||
setTimeout(this.getReport, 2000)
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
formatResult(res) {
|
||||
let resMap = new Map;
|
||||
let startTime = 99991611737506593;
|
||||
let endTime = 0;
|
||||
this.clearDebug();
|
||||
if (res && res.scenarios) {
|
||||
res.scenarios.forEach(item => {
|
||||
this.reqTotal += item.requestResults.length;
|
||||
if (item && item.requestResults) {
|
||||
item.requestResults.forEach(req => {
|
||||
req.responseResult.console = res.console;
|
||||
let name = req.name.split('<->')[0];
|
||||
resMap.set(req.id + name, req);
|
||||
if (req.success) {
|
||||
this.reqSuccess++;
|
||||
} else {
|
||||
this.reqError++;
|
||||
}
|
||||
if (req.startTime && Number(req.startTime) < startTime) {
|
||||
startTime = req.startTime;
|
||||
}
|
||||
if (req.endTime && Number(req.endTime) > endTime) {
|
||||
endTime = req.endTime;
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
if (startTime < endTime) {
|
||||
this.reqTotalTime = endTime - startTime + 100;
|
||||
}
|
||||
this.debugResult = resMap;
|
||||
this.sort();
|
||||
this.reload();
|
||||
this.reloadDebug = getUUID();
|
||||
},
|
||||
removeReport() {
|
||||
let url = "/api/scenario/report/remove/real/" + this.reportId;
|
||||
this.$get(url, response => {
|
||||
});
|
||||
},
|
||||
handleCommand() {
|
||||
this.debug = false;
|
||||
/*触发执行操作*/
|
||||
|
@ -591,7 +550,6 @@ export default {
|
|||
}
|
||||
})
|
||||
},
|
||||
|
||||
openHis() {
|
||||
this.$refs.changeHistory.open(this.currentScenario.id);
|
||||
},
|
||||
|
@ -658,59 +616,7 @@ export default {
|
|||
}
|
||||
},
|
||||
addComponent(type) {
|
||||
switch (type) {
|
||||
case ELEMENT_TYPE.IfController:
|
||||
this.selectedTreeNode !== undefined ? this.selectedTreeNode.hashTree.push(new IfController()) :
|
||||
this.scenarioDefinition.push(new IfController());
|
||||
break;
|
||||
case ELEMENT_TYPE.ConstantTimer:
|
||||
this.selectedTreeNode !== undefined ? this.selectedTreeNode.hashTree.push(new ConstantTimer()) :
|
||||
this.scenarioDefinition.push(new ConstantTimer());
|
||||
break;
|
||||
case ELEMENT_TYPE.JSR223Processor:
|
||||
this.selectedTreeNode !== undefined ? this.selectedTreeNode.hashTree.push(new JSR223Processor()) :
|
||||
this.scenarioDefinition.push(new JSR223Processor());
|
||||
break;
|
||||
case ELEMENT_TYPE.JSR223PreProcessor:
|
||||
this.selectedTreeNode !== undefined ? this.selectedTreeNode.hashTree.push(new JSR223Processor({type: "JSR223PreProcessor"})) :
|
||||
this.scenarioDefinition.push(new JSR223Processor({type: "JSR223PreProcessor"}));
|
||||
break;
|
||||
case ELEMENT_TYPE.JSR223PostProcessor:
|
||||
this.selectedTreeNode !== undefined ? this.selectedTreeNode.hashTree.push(new JSR223Processor({type: "JSR223PostProcessor"})) :
|
||||
this.scenarioDefinition.push(new JSR223Processor({type: "JSR223PostProcessor"}));
|
||||
break;
|
||||
case ELEMENT_TYPE.Assertions:
|
||||
this.selectedTreeNode !== undefined ? this.selectedTreeNode.hashTree.push(new Assertions()) :
|
||||
this.scenarioDefinition.push(new Assertions());
|
||||
break;
|
||||
case ELEMENT_TYPE.Extract:
|
||||
this.selectedTreeNode !== undefined ? this.selectedTreeNode.hashTree.push(new Extract()) :
|
||||
this.scenarioDefinition.push(new Extract());
|
||||
break;
|
||||
case ELEMENT_TYPE.CustomizeReq:
|
||||
this.customizeRequest = {protocol: "HTTP", type: "API", hashTree: [], referenced: 'Created', active: false};
|
||||
this.customizeVisible = true;
|
||||
break;
|
||||
case ELEMENT_TYPE.LoopController:
|
||||
this.selectedTreeNode !== undefined ? this.selectedTreeNode.hashTree.push(new LoopController()) :
|
||||
this.scenarioDefinition.push(new LoopController());
|
||||
break;
|
||||
case ELEMENT_TYPE.TransactionController:
|
||||
this.selectedTreeNode !== undefined ? this.selectedTreeNode.hashTree.push(new TransactionController()) :
|
||||
this.scenarioDefinition.push(new TransactionController());
|
||||
break;
|
||||
case ELEMENT_TYPE.scenario:
|
||||
this.isBtnHide = true;
|
||||
this.$refs.scenarioRelevance.open();
|
||||
break;
|
||||
default:
|
||||
this.$refs.apiImport.open();
|
||||
break;
|
||||
}
|
||||
if (this.selectedNode) {
|
||||
this.selectedNode.expanded = true;
|
||||
}
|
||||
this.sort();
|
||||
setComponent(type, this);
|
||||
},
|
||||
nodeClick(data, node) {
|
||||
if (data.referenced != 'REF' && data.referenced != 'Deleted' && !data.disabled) {
|
||||
|
@ -763,6 +669,8 @@ export default {
|
|||
// 添加debug结果
|
||||
if (this.debugResult && this.debugResult.get(arr[i].id + arr[i].name)) {
|
||||
arr[i].requestResult = this.debugResult.get(arr[i].id + arr[i].name);
|
||||
arr[i].debug = this.debug;
|
||||
this.findNode(arr[i].name, arr[i].index, arr[i].requestResult.success);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -794,6 +702,7 @@ export default {
|
|||
// 添加debug结果
|
||||
if (this.debugResult && this.debugResult.get(this.scenarioDefinition[i].id + this.scenarioDefinition[i].name)) {
|
||||
this.scenarioDefinition[i].requestResult = this.debugResult.get(this.scenarioDefinition[i].id + this.scenarioDefinition[i].name);
|
||||
this.scenarioDefinition[i].debug = this.debug;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -928,7 +837,10 @@ export default {
|
|||
if (this.scenarioDefinition.length < 1) {
|
||||
return;
|
||||
}
|
||||
// this.debug = true;
|
||||
this.debug = true;
|
||||
this.debugLoading = true;
|
||||
this.stopDebug = "";
|
||||
this.clearDebug();
|
||||
/*触发执行操作*/
|
||||
this.$refs['currentScenario'].validate((valid) => {
|
||||
if (valid) {
|
||||
|
@ -955,11 +867,7 @@ export default {
|
|||
onSampleError: this.onSampleError,
|
||||
};
|
||||
this.reportId = getUUID().substring(0, 8);
|
||||
// this.editScenario().then(() => {
|
||||
//
|
||||
// })
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -1463,7 +1371,6 @@ export default {
|
|||
.alt-ico:hover {
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.scenario-name {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<el-tag class="ms-left-btn" size="small" :style="{'color': color, 'background-color': backgroundColor}">{{title}}</el-tag>
|
||||
<el-tag size="mini" v-if="data.method">{{getMethod()}}</el-tag>
|
||||
</slot>
|
||||
<slot name="behindHeaderLeft" v-if="!isMax"></slot>
|
||||
|
||||
<span>
|
||||
<slot name="headerLeft">
|
||||
|
@ -25,11 +26,11 @@
|
|||
</el-tooltip>
|
||||
</span>
|
||||
</slot>
|
||||
<slot name="behindHeaderLeft" v-if="!isMax"></slot>
|
||||
</span>
|
||||
|
||||
<div class="header-right" @click.stop>
|
||||
<slot name="message"></slot>
|
||||
<slot name="debugStepCode"></slot>
|
||||
<el-tooltip :content="$t('test_resource_pool.enable_disable')" placement="top" v-if="showBtn">
|
||||
<el-switch v-model="data.enable" class="enable-switch" size="mini" :disabled="data.disabled && !data.root" style="width: 30px"/>
|
||||
</el-tooltip>
|
||||
|
@ -202,7 +203,7 @@
|
|||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
width: 180px;
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.scenario-name {
|
||||
|
@ -214,7 +215,7 @@
|
|||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
width: calc(100% - 30rem);
|
||||
width: calc(100% - 35rem);
|
||||
}
|
||||
|
||||
/deep/ .el-step__icon {
|
||||
|
@ -240,4 +241,5 @@
|
|||
white-space: nowrap;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -20,7 +20,13 @@
|
|||
<el-tag size="mini" class="ms-tag" v-if="request.referenced ==='REF'">{{ $t('api_test.scenario.reference') }}</el-tag>
|
||||
<span class="ms-tag">{{ getProjectName(request.projectId) }}</span>
|
||||
</template>
|
||||
|
||||
<template v-slot:debugStepCode>
|
||||
<el-tooltip :content="request.requestResult.responseResult.responseCode" v-if="request.debug && request.requestResult && request.requestResult.responseResult">
|
||||
<span class="ms-step-debug-code" :class="request.requestResult.success?'ms-req-success':'ms-req-error'">
|
||||
{{ request.requestResult.responseResult.responseCode }}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template v-slot:button>
|
||||
<el-tooltip :content="$t('api_test.run')" placement="top">
|
||||
<el-button :disabled="!request.enable" @click="run" icon="el-icon-video-play" style="padding: 5px" class="ms-btn" size="mini" circle/>
|
||||
|
@ -38,23 +44,22 @@
|
|||
:headers="request.headers "
|
||||
:is-read-only="isCompReadOnly"
|
||||
:request="request"/>
|
||||
|
||||
<esb-definition v-if="showXpackCompnent&&request.esbDataStruct!=null"
|
||||
v-xpack
|
||||
:request="request"
|
||||
:showScript="false"
|
||||
:is-read-only="isCompReadOnly"
|
||||
ref="esbDefinition"/>
|
||||
<!-- <ms-tcp-basis-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null "-->
|
||||
<!-- :request="request"-->
|
||||
<!-- :is-read-only="isCompReadOnly"-->
|
||||
<!-- :showScript="false"/>-->
|
||||
:is-read-only="isCompReadOnly" ref="esbDefinition"/>
|
||||
|
||||
<ms-tcp-format-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null "
|
||||
:is-read-only="isCompReadOnly"
|
||||
:show-script="false" :request="request"/>
|
||||
|
||||
<ms-sql-basis-parameters v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'"
|
||||
:request="request"
|
||||
:is-read-only="isCompReadOnly"
|
||||
:showScript="false"/>
|
||||
|
||||
<ms-dubbo-basis-parameters v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'"
|
||||
:request="request"
|
||||
:is-read-only="isCompReadOnly"
|
||||
|
@ -94,7 +99,6 @@
|
|||
|
||||
<script>
|
||||
import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters";
|
||||
// import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters";
|
||||
import MsTcpFormatParameters from "../../../definition/components/request/tcp/TcpFormatParameters";
|
||||
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
|
||||
import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm";
|
||||
|
@ -104,6 +108,7 @@ import {getUUID, getCurrentProjectID} from "@/common/js/utils";
|
|||
import ApiBaseComponent from "../common/ApiBaseComponent";
|
||||
import ApiResponseComponent from "./ApiResponseComponent";
|
||||
import CustomizeReqInfo from "@/business/components/api/automation/scenario/common/CustomizeReqInfo";
|
||||
import TemplateComponent from "@/business/components/track/plan/view/comonents/report/TemplateComponent/TemplateComponent";
|
||||
|
||||
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
|
||||
const esbDefinition = (requireComponent != null && requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinition.vue") : {};
|
||||
|
@ -133,6 +138,7 @@ export default {
|
|||
envMap: Map
|
||||
},
|
||||
components: {
|
||||
TemplateComponent,
|
||||
CustomizeReqInfo,
|
||||
ApiBaseComponent, ApiResponseComponent,
|
||||
MsSqlBasisParameters, MsTcpFormatParameters, MsDubboBasisParameters, MsApiRequestForm, MsRequestResultTail, MsRun,
|
||||
|
@ -147,6 +153,7 @@ export default {
|
|||
isShowInput: false,
|
||||
showXpackCompnent: false,
|
||||
environment: {},
|
||||
result: {},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -462,6 +469,25 @@ export default {
|
|||
}
|
||||
|
||||
.ms-tag {
|
||||
margin-left: 20px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.ms-step-debug-code {
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
overflow-x: hidden;
|
||||
padding-bottom: 0;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.ms-req-error {
|
||||
color: #F56C6C;
|
||||
}
|
||||
|
||||
.ms-req-success {
|
||||
color: #67C23A;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -22,6 +22,13 @@
|
|||
|
||||
<span class="ms-tag">{{ getProjectName(scenario.projectId) }}</span>
|
||||
</template>
|
||||
<template v-slot:debugStepCode>
|
||||
<el-tooltip :content="getCode()" v-if="node.data.debug">
|
||||
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'">
|
||||
{{ getCode() }}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
</api-base-component>
|
||||
</template>
|
||||
|
@ -107,6 +114,16 @@
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
getCode() {
|
||||
if (this.node && this.node.data.debug) {
|
||||
if (this.node.data.code && this.node.data.code === 'error') {
|
||||
return 'error';
|
||||
} else {
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
remove() {
|
||||
this.$emit('remove', this.scenario, this.node);
|
||||
},
|
||||
|
@ -179,6 +196,14 @@
|
|||
}
|
||||
|
||||
.ms-tag {
|
||||
margin-left: 20px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.ms-req-error {
|
||||
color: #F56C6C;
|
||||
}
|
||||
|
||||
.ms-req-success {
|
||||
color: #67C23A;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -23,6 +23,13 @@
|
|||
<el-input draggable size="mini" v-model="controller.value" :placeholder="$t('api_test.value')" v-if="!hasEmptyOperator" class="ms-btn"/>
|
||||
</template>
|
||||
|
||||
<template v-slot:debugStepCode>
|
||||
<el-tooltip :content="getCode()" v-if="node.data.debug">
|
||||
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'">
|
||||
{{ getCode() }}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</api-base-component>
|
||||
</template>
|
||||
|
||||
|
@ -88,6 +95,16 @@
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
getCode() {
|
||||
if (this.node && this.node.data.debug) {
|
||||
if (this.node.data.code && this.node.data.code === 'error') {
|
||||
return 'error';
|
||||
} else {
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
remove() {
|
||||
this.$emit('remove', this.controller, this.node);
|
||||
},
|
||||
|
@ -118,4 +135,12 @@
|
|||
width: 15%;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.ms-req-error {
|
||||
color: #F56C6C;
|
||||
}
|
||||
|
||||
.ms-req-success {
|
||||
color: #67C23A;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -69,6 +69,14 @@
|
|||
<el-input-number size="small" v-model="controller.whileController.timeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="3000" :step="1000"/>
|
||||
<span class="ms-span ms-radio">ms</span>
|
||||
</div>
|
||||
|
||||
<template v-slot:debugStepCode>
|
||||
<el-tooltip :content="getCode()" v-if="node.data.debug">
|
||||
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'">
|
||||
{{ getCode() }}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</api-base-component>
|
||||
|
||||
</div>
|
||||
|
@ -151,6 +159,16 @@
|
|||
};
|
||||
},
|
||||
methods: {
|
||||
getCode() {
|
||||
if (this.node && this.node.data.debug) {
|
||||
if (this.node.data.code && this.node.data.code === 'error') {
|
||||
return 'error';
|
||||
} else {
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
initResult() {
|
||||
if (this.controller) {
|
||||
switch (this.controller.loopType) {
|
||||
|
@ -363,6 +381,13 @@
|
|||
.icon.is-active {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
.ms-req-error {
|
||||
color: #F56C6C;
|
||||
}
|
||||
|
||||
.ms-req-success {
|
||||
color: #67C23A;
|
||||
}
|
||||
|
||||
/deep/ .el-radio {
|
||||
margin-right: 5px;
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
<el-tooltip :content="$t('api_test.scenario.enable')" placement="top" effect="light" v-else>
|
||||
<font-awesome-icon class="ms-open-btn" :icon="['fas', 'toggle-on']" @click="disableAll"/>
|
||||
</el-tooltip>
|
||||
<span class="ms-debug-result" v-if="debug">
|
||||
{{ reqTotalTime }} ms 请求 {{ reqTotal }} 成功 {{ reqSuccess }} 失败 {{ reqError }}
|
||||
</span>
|
||||
|
||||
<el-tree node-key="resourceId"
|
||||
:props="props"
|
||||
:data="scenarioDefinition"
|
||||
|
@ -175,9 +179,15 @@ export default {
|
|||
moduleOptions: Array,
|
||||
currentScenario: {},
|
||||
type: String,
|
||||
debug: Boolean,
|
||||
reloadDebug: String,
|
||||
stepReEnable: Boolean,
|
||||
scenarioDefinition: Array,
|
||||
envMap: Map,
|
||||
reqTotal: Number,
|
||||
reqSuccess: Number,
|
||||
reqError: Number,
|
||||
reqTotalTime: Number,
|
||||
},
|
||||
components: {
|
||||
MsVariableList,
|
||||
|
@ -242,6 +252,7 @@ export default {
|
|||
debugResult: new Map,
|
||||
expandedStatus: false,
|
||||
stepEnable: true,
|
||||
debugLoading: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -255,6 +266,9 @@ export default {
|
|||
watch: {
|
||||
envMap() {
|
||||
this.projectEnvMap = this.envMap;
|
||||
},
|
||||
reloadDebug() {
|
||||
this.reload();
|
||||
}
|
||||
},
|
||||
directives: {OutsideClick},
|
||||
|
@ -1198,4 +1212,10 @@ export default {
|
|||
.ms-open-btn-left {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.ms-debug-result {
|
||||
float: right;
|
||||
margin-right: 30px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -25,10 +25,13 @@
|
|||
@showPopover="showPopover" :project-list="projectList" ref="envPopover" class="ms-right"
|
||||
:result="envResult"/>
|
||||
|
||||
<el-button :disabled="scenarioDefinition.length < 1" size="mini" type="primary" v-prevent-re-click
|
||||
@click="runDebug">{{ $t('api_test.request.debug') }}
|
||||
</el-button>
|
||||
|
||||
<el-dropdown split-button type="primary" @click="runDebug" style="margin-right: 10px" size="mini" @command="handleCommand" v-if="!debug">
|
||||
{{ $t('api_test.request.debug') }}
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item>{{ $t('test_track.case.steps') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<el-button icon="el-icon-loading" size="mini" type="primary" :disabled="debug" v-else>执行中</el-button>
|
||||
<font-awesome-icon class="ms-alt-ico" :icon="['fa', 'compress-alt']" size="lg" @click="unFullScreen"/>
|
||||
<!-- <i class="el-icon-close alt-ico-close" @click="close"/>-->
|
||||
</div>
|
||||
|
@ -48,7 +51,8 @@ import html2canvas from 'html2canvas';
|
|||
projectEnvMap: Map,
|
||||
projectIds: Set,
|
||||
projectList: Array,
|
||||
isFullUrl: Boolean
|
||||
isFullUrl: Boolean,
|
||||
execDebug: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -59,12 +63,23 @@ import html2canvas from 'html2canvas';
|
|||
sampleError: true,
|
||||
envResult: {
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
debugLoading: false,
|
||||
reqTotal: 0,
|
||||
reqSuccess: 0,
|
||||
reqError: 0,
|
||||
reqTotalTime: 0,
|
||||
debug: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
projectId() {
|
||||
return getCurrentProjectID();
|
||||
},
|
||||
},
|
||||
watch:{
|
||||
execDebug(){
|
||||
this.debug = false;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -96,8 +111,15 @@ import html2canvas from 'html2canvas';
|
|||
this.$emit('unFullScreen');
|
||||
},
|
||||
runDebug() {
|
||||
this.debug = true;
|
||||
this.debugLoading = true;
|
||||
this.$emit('runDebug');
|
||||
},
|
||||
handleCommand() {
|
||||
this.debug = false;
|
||||
this.debugLoading = false;
|
||||
this.$emit('handleCommand');
|
||||
},
|
||||
setCookieShare() {
|
||||
this.$emit('setCookieShare', this.cookieShare);
|
||||
},
|
||||
|
@ -169,7 +191,7 @@ import html2canvas from 'html2canvas';
|
|||
|
||||
.ms-header-right {
|
||||
float: right;
|
||||
width: 500px;
|
||||
width: 540px;
|
||||
margin-top: 4px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
@ -209,6 +231,7 @@ import html2canvas from 'html2canvas';
|
|||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.ms-scenario-name {
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
|
@ -219,4 +242,5 @@ import html2canvas from 'html2canvas';
|
|||
white-space: nowrap;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
import {ELEMENT_TYPE} from "@/business/components/api/automation/scenario/Setting";
|
||||
import {Assertions, ConstantTimer, Extract, IfController, JSR223Processor, LoopController, TransactionController} from "@/business/components/api/definition/model/ApiTestModel";
|
||||
|
||||
export function buttons() {
|
||||
let buttons = [
|
||||
{
|
||||
title: this.$t('api_test.definition.request.extract_param'),
|
||||
show: this.showButton("Extract"),
|
||||
titleColor: "#015478",
|
||||
titleBgColor: "#E6EEF2",
|
||||
icon: "colorize",
|
||||
click: () => {
|
||||
this.addComponent('Extract')
|
||||
}
|
||||
},
|
||||
{
|
||||
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.pre_script'),
|
||||
show: this.showButton("JSR223PreProcessor"),
|
||||
titleColor: "#B8741A",
|
||||
titleBgColor: "#F9F1EA",
|
||||
icon: "skip_previous",
|
||||
click: () => {
|
||||
this.addComponent('JSR223PreProcessor')
|
||||
}
|
||||
},
|
||||
{
|
||||
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.if_controller'),
|
||||
show: this.showButton("IfController"),
|
||||
titleColor: "#E6A23C",
|
||||
titleBgColor: "#FCF6EE",
|
||||
icon: "alt_route",
|
||||
click: () => {
|
||||
this.addComponent('IfController')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('api_test.automation.loop_controller'),
|
||||
show: this.showButton("LoopController"),
|
||||
titleColor: "#02A7F0",
|
||||
titleBgColor: "#F4F4F5",
|
||||
icon: "next_plan",
|
||||
click: () => {
|
||||
this.addComponent('LoopController')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('api_test.automation.transcation_controller'),
|
||||
show: this.showButton("TransactionController"),
|
||||
titleColor: "#6D317C",
|
||||
titleBgColor: "#F4F4F5",
|
||||
icon: "alt_route",
|
||||
click: () => {
|
||||
this.addComponent('TransactionController')
|
||||
}
|
||||
},
|
||||
{
|
||||
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.definition.request.assertions_rule'),
|
||||
show: this.showButton("Assertions"),
|
||||
titleColor: "#A30014",
|
||||
titleBgColor: "#F7E6E9",
|
||||
icon: "next_plan",
|
||||
click: () => {
|
||||
this.addComponent('Assertions')
|
||||
}
|
||||
},
|
||||
{
|
||||
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.automation.scenario_import'),
|
||||
show: this.showButton("scenario"),
|
||||
titleColor: "#606266",
|
||||
titleBgColor: "#F4F4F5",
|
||||
icon: "movie",
|
||||
click: () => {
|
||||
this.addComponent('scenario')
|
||||
}
|
||||
},
|
||||
{
|
||||
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
|
||||
}
|
||||
];
|
||||
return buttons.filter(btn => btn.show);
|
||||
}
|
||||
|
||||
export function setComponent(type, _this) {
|
||||
switch (type) {
|
||||
case ELEMENT_TYPE.IfController:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new IfController()) :
|
||||
_this.scenarioDefinition.push(new IfController());
|
||||
break;
|
||||
case ELEMENT_TYPE.ConstantTimer:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new ConstantTimer()) :
|
||||
_this.scenarioDefinition.push(new ConstantTimer());
|
||||
break;
|
||||
case ELEMENT_TYPE.JSR223Processor:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JSR223Processor()) :
|
||||
_this.scenarioDefinition.push(new JSR223Processor());
|
||||
break;
|
||||
case ELEMENT_TYPE.JSR223PreProcessor:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JSR223Processor({type: "JSR223PreProcessor"})) :
|
||||
_this.scenarioDefinition.push(new JSR223Processor({type: "JSR223PreProcessor"}));
|
||||
break;
|
||||
case ELEMENT_TYPE.JSR223PostProcessor:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JSR223Processor({type: "JSR223PostProcessor"})) :
|
||||
_this.scenarioDefinition.push(new JSR223Processor({type: "JSR223PostProcessor"}));
|
||||
break;
|
||||
case ELEMENT_TYPE.Assertions:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new Assertions()) :
|
||||
_this.scenarioDefinition.push(new Assertions());
|
||||
break;
|
||||
case ELEMENT_TYPE.Extract:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new Extract()) :
|
||||
_this.scenarioDefinition.push(new Extract());
|
||||
break;
|
||||
case ELEMENT_TYPE.CustomizeReq:
|
||||
_this.customizeRequest = {protocol: "HTTP", type: "API", hashTree: [], referenced: 'Created', active: false};
|
||||
_this.customizeVisible = true;
|
||||
break;
|
||||
case ELEMENT_TYPE.LoopController:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new LoopController()) :
|
||||
_this.scenarioDefinition.push(new LoopController());
|
||||
break;
|
||||
case ELEMENT_TYPE.TransactionController:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new TransactionController()) :
|
||||
_this.scenarioDefinition.push(new TransactionController());
|
||||
break;
|
||||
case ELEMENT_TYPE.scenario:
|
||||
_this.isBtnHide = true;
|
||||
_this.$refs.scenarioRelevance.open();
|
||||
break;
|
||||
default:
|
||||
_this.$refs.apiImport.open();
|
||||
break;
|
||||
}
|
||||
if (_this.selectedNode) {
|
||||
_this.selectedNode.expanded = true;
|
||||
}
|
||||
_this.sort();
|
||||
}
|
Loading…
Reference in New Issue