mirror of
https://gitee.com/eolink_admin/postcat.git
synced 2024-12-02 03:38:03 +08:00
feat: api test support execute in different tab
This commit is contained in:
parent
4e66601b57
commit
91dabd30fc
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "eoapi",
|
||||
"souceLocale": "zh-Hans",
|
||||
"version": "1.4.0-beta",
|
||||
"version": "1.5.0",
|
||||
"main": "out/app/electron-main/main.js",
|
||||
"description": "A lightweight, extensible API tool",
|
||||
"homepage": "https://github.com/eolinker/eoapi.git",
|
||||
|
@ -174,6 +174,10 @@ export class ApiTabService {
|
||||
if (replaceTab.hasChanged) {
|
||||
replaceTab.isFixed = true;
|
||||
}
|
||||
//Has tested set fixed
|
||||
if(currentTab.pathname === '/home/api/test'&&model.testStartTime!==undefined){
|
||||
replaceTab.isFixed = true;
|
||||
}
|
||||
|
||||
// Set storage
|
||||
//Set baseContent
|
||||
@ -186,7 +190,7 @@ export class ApiTabService {
|
||||
replaceTab.content = inData.when === 'saved' ? {} : currentTab.content || {};
|
||||
replaceTab.content[contentID] = model && !isEmptyObj(model) ? model : null;
|
||||
}
|
||||
// console.log('updatePartialTab', currentTab.uuid, replaceTab);
|
||||
console.log('updatePartialTab', currentTab.uuid, replaceTab);
|
||||
this.apiTabComponent.updatePartialTab(inData.url, replaceTab);
|
||||
}
|
||||
/**
|
||||
@ -195,7 +199,7 @@ export class ApiTabService {
|
||||
*
|
||||
* @param inData.url get component fit tab data
|
||||
*/
|
||||
afterContentChanged(inData: { when: 'init' | 'editing' | 'saved'; url: string; model: any }) {
|
||||
afterContentChanged(inData: { when: 'init' | 'editing' |'saved'; url: string; model: any }) {
|
||||
if (!this.apiTabComponent) {
|
||||
console.warn(`EO_WARNING:apiTabComponent hasn't init yet!`);
|
||||
return;
|
||||
|
@ -68,7 +68,7 @@
|
||||
</div>
|
||||
<div class="content_container {{ this.id ? 'has_tab_page' : '' }}">
|
||||
<!-- Manually pick pageID,Because pageID always change -->
|
||||
<nz-tabset class="inside_page_tab" *ngIf="this.id" nzLinkRouter>
|
||||
<nz-tabset class="inside_page_tabset" *ngIf="this.id" nzLinkRouter>
|
||||
<nz-tab *ngFor="let tab of TABS">
|
||||
<a
|
||||
*nzTabLink
|
||||
|
@ -145,28 +145,15 @@ export class ApiTabOperateService {
|
||||
* @param tab
|
||||
* @returns
|
||||
*/
|
||||
getTabIndex(type, tab: TabItem): number {
|
||||
getSameContentTabIndex(tab: TabItem): number {
|
||||
let result = -1;
|
||||
//If exist tab,return exist TabIndex
|
||||
if (this.tabStorage.tabsByID.get(tab.uuid)) {
|
||||
return this.tabStorage.tabOrder.findIndex((uuid) => uuid === tab.uuid);
|
||||
}
|
||||
|
||||
const mapObj = Object.fromEntries(this.tabStorage.tabsByID);
|
||||
for (const key in mapObj) {
|
||||
if (Object.prototype.hasOwnProperty.call(mapObj, key)) {
|
||||
const tabInfo = mapObj[key];
|
||||
if (tabInfo.params.uuid && tabInfo.params.uuid === tab.params.uuid) {
|
||||
if (type === 'sameContent') {
|
||||
if (tabInfo.pathname === tab.pathname) {
|
||||
result = this.tabStorage.tabOrder.findIndex((uuid) => uuid === tabInfo.uuid);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
result = this.tabStorage.tabOrder.findIndex((uuid) => uuid === tabInfo.uuid);
|
||||
}
|
||||
if (tabInfo.params.uuid && tabInfo.params.uuid === tab.params.uuid && tabInfo.pathname === tab.pathname) {
|
||||
result = this.tabStorage.tabOrder.findIndex((uuid) => uuid === tabInfo.uuid);
|
||||
break;
|
||||
//TODO how to replace current exist tab but editing
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -207,26 +194,6 @@ export class ApiTabOperateService {
|
||||
});
|
||||
return result as TabItem;
|
||||
}
|
||||
formatUrl(url) {
|
||||
const urlArr = url.split('?');
|
||||
// Parse query params
|
||||
const params = {};
|
||||
new URLSearchParams(urlArr[1]).forEach((value, key) => {
|
||||
if (key === 'pageID') {
|
||||
params[key] = Number(value);
|
||||
return;
|
||||
}
|
||||
params[key] = value;
|
||||
});
|
||||
return (
|
||||
urlArr[0] +
|
||||
'?' +
|
||||
Object.keys(params)
|
||||
.sort()
|
||||
.map((keyName) => `${keyName}=${params[keyName]}`)
|
||||
.join('&')
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Operate tab after router change,router triggle tab change
|
||||
* Such as new tab,pick tab,close tab...
|
||||
@ -235,19 +202,14 @@ export class ApiTabOperateService {
|
||||
*/
|
||||
operateTabAfterRouteChange(res: { url: string }) {
|
||||
const tmpTabItem = this.getBaiscTabFromUrl(res.url);
|
||||
const sameContentIndex = this.getTabIndex('sameContent', tmpTabItem);
|
||||
const sameContentIndex = this.getSameContentTabIndex(tmpTabItem);
|
||||
const existTab = this.getTabByIndex(sameContentIndex);
|
||||
const samePageID = this.tabStorage.tabsByID.has(tmpTabItem.uuid);
|
||||
console.log('operateTabAfterRouteChange', existTab, tmpTabItem);
|
||||
//If page repeat or final url is different(lack of id/additional params)
|
||||
//jump to exist tab item to keep same pageID and so on
|
||||
//If page lack pageID
|
||||
//Jump to exist tab item to keep same pageID and so on
|
||||
if (!res.url.includes('pageID')) {
|
||||
if (existTab) {
|
||||
if (existTab.pathname !== tmpTabItem.pathname) {
|
||||
tmpTabItem.uuid = tmpTabItem.params.pageID = Date.now();
|
||||
} else {
|
||||
tmpTabItem.uuid = tmpTabItem.params.pageID = existTab.uuid;
|
||||
}
|
||||
tmpTabItem.uuid = tmpTabItem.params.pageID = existTab.uuid;
|
||||
}
|
||||
this.navigateTabRoute(tmpTabItem);
|
||||
return;
|
||||
@ -260,7 +222,7 @@ export class ApiTabOperateService {
|
||||
}
|
||||
|
||||
//same tab content,selected it
|
||||
if (existTab && this.getUrlByTab(existTab) === this.formatUrl(res.url)) {
|
||||
if (existTab) {
|
||||
this.selectedIndex = sameContentIndex;
|
||||
this.updateChildView();
|
||||
return;
|
||||
@ -282,8 +244,8 @@ export class ApiTabOperateService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If has same tab (same uuid),replace it
|
||||
const samePageID = this.tabStorage.tabsByID.has(tmpTabItem.uuid);
|
||||
if (samePageID) {
|
||||
this.selectedIndex = this.tabStorage.tabOrder.findIndex((uuid) => uuid === tmpTabItem.uuid);
|
||||
this.tabStorage.updateTab(this.selectedIndex, tmpTabItem);
|
||||
|
@ -1,4 +1,4 @@
|
||||
{{getConsoleTabs()|json}}
|
||||
<!-- {{getConsoleTabs()|json}} -->
|
||||
<nz-tabset
|
||||
[(nzSelectedIndex)]="tabOperate.selectedIndex"
|
||||
nzType="editable-card"
|
||||
|
@ -116,7 +116,7 @@ export class ApiTabComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
getTabByUrl(url: string): TabItem | null {
|
||||
const tabItem = this.tabOperate.getBaiscTabFromUrl(url);
|
||||
const existTabIndex = this.tabOperate.getTabIndex('sameTab', tabItem);
|
||||
const existTabIndex = this.tabOperate.getSameContentTabIndex(tabItem);
|
||||
if (existTabIndex === -1) {
|
||||
return null;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
import { MessageService } from '../../../shared/services/message';
|
||||
|
||||
import { interval, Subscription, Observable, Subject } from 'rxjs';
|
||||
import { take, takeUntil, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { takeUntil, distinctUntilChanged } from 'rxjs/operators';
|
||||
|
||||
import { TestServerService } from '../../../shared/services/api-test/test-server.service';
|
||||
import { ApiTestUtilService } from './api-test-util.service';
|
||||
@ -39,6 +39,7 @@ import { AnyRecord } from 'dns';
|
||||
const API_TEST_DRAG_TOP_HEIGHT_KEY = 'API_TEST_DRAG_TOP_HEIGHT';
|
||||
interface testViewModel {
|
||||
request: ApiTestData;
|
||||
testStartTime?: number;
|
||||
testResult: {
|
||||
request: any;
|
||||
response: any;
|
||||
@ -77,14 +78,15 @@ export class ApiTestComponent implements OnInit, OnDestroy {
|
||||
status: 'start' | 'testing' | 'tested' = 'start';
|
||||
waitSeconds = 0;
|
||||
responseTabIndexRes = 0;
|
||||
initTimes = 0;
|
||||
|
||||
isRequestBodyLoaded = false;
|
||||
initHeight = localStorage.getItem(API_TEST_DRAG_TOP_HEIGHT_KEY) || '45%';
|
||||
testServer: TestServerLocalNodeService | TestServerServerlessService | TestServerRemoteService;
|
||||
REQUEST_METHOD = objectToArray(RequestMethod);
|
||||
REQUEST_PROTOCOL = objectToArray(RequestProtocol);
|
||||
MAX_TEST_SECONDS = 60;
|
||||
|
||||
private initTimes = 0;
|
||||
private status$: Subject<string> = new Subject<string>();
|
||||
private timer$: Subscription;
|
||||
private destroy$: Subject<void> = new Subject<void>();
|
||||
@ -145,10 +147,20 @@ export class ApiTestComponent implements OnInit, OnDestroy {
|
||||
//!Prevent await async ,replace current api data
|
||||
if (initTimes >= this.initTimes) {
|
||||
this.model.request = requestInfo;
|
||||
}else{
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
this.initContentType();
|
||||
this.waitSeconds = 0;
|
||||
this.status = 'start';
|
||||
} else {
|
||||
if (this.timer$ && this.model.testStartTime) {
|
||||
this.waitSeconds = Math.round((Date.now() - this.model.testStartTime) / 1000);
|
||||
this.status$.next('testing');
|
||||
} else {
|
||||
this.waitSeconds = 0;
|
||||
this.status$.next('start');
|
||||
}
|
||||
}
|
||||
this.initBasicForm();
|
||||
//! Set this two function to reset form
|
||||
@ -236,12 +248,12 @@ export class ApiTestComponent implements OnInit, OnDestroy {
|
||||
if (!this.initialModel.request || !this.model.request) {
|
||||
return false;
|
||||
}
|
||||
console.log(
|
||||
'api test origin:',
|
||||
this.apiTestUtil.formatEditingApiData(this.initialModel.request),
|
||||
'after:',
|
||||
this.apiTestUtil.formatEditingApiData(this.model.request)
|
||||
);
|
||||
// console.log(
|
||||
// 'api test origin:',
|
||||
// this.apiTestUtil.formatEditingApiData(this.initialModel.request),
|
||||
// 'after:',
|
||||
// this.apiTestUtil.formatEditingApiData(this.model.request)
|
||||
// );
|
||||
const originText = JSON.stringify(this.apiTestUtil.formatEditingApiData(this.initialModel.request));
|
||||
const afterText = JSON.stringify(this.apiTestUtil.formatEditingApiData(this.model.request));
|
||||
if (originText !== afterText) {
|
||||
@ -298,7 +310,7 @@ export class ApiTestComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
private test() {
|
||||
this.testServer.send('unitTest', {
|
||||
// id: this.apiTab.tabID,
|
||||
id: this.route.snapshot.queryParams.pageID,
|
||||
action: 'ajax',
|
||||
data: this.testServer.formatRequestData(this.model.request, {
|
||||
env: this.env,
|
||||
@ -308,11 +320,12 @@ export class ApiTestComponent implements OnInit, OnDestroy {
|
||||
lang: this.lang.systemLanguage === 'zh-Hans' ? 'cn' : 'en',
|
||||
}),
|
||||
});
|
||||
this.model.testStartTime = Date.now();
|
||||
this.status$.next('testing');
|
||||
}
|
||||
private abort() {
|
||||
this.testServer.send('unitTest', {
|
||||
// id: this.apiTab.tabID,
|
||||
id: this.route.snapshot.queryParams.pageID,
|
||||
action: 'abort',
|
||||
});
|
||||
this.status$.next('tested');
|
||||
@ -332,7 +345,6 @@ export class ApiTestComponent implements OnInit, OnDestroy {
|
||||
response: message.response,
|
||||
};
|
||||
this.model.testResult = tmpHistory;
|
||||
this.modelChange.emit(this.model);
|
||||
this.status$.next('tested');
|
||||
if (message.status === 'error') {
|
||||
return;
|
||||
@ -349,6 +361,24 @@ export class ApiTestComponent implements OnInit, OnDestroy {
|
||||
// TODO Other tab test finish,support multiple tab test same time
|
||||
this.addHistory(message.history, this.model.request.uuid);
|
||||
}
|
||||
setTestSecondsTimmer() {
|
||||
if (this.timer$) {
|
||||
this.timer$.unsubscribe();
|
||||
}
|
||||
const that = this;
|
||||
this.timer$ = interval(1000)
|
||||
.subscribe({
|
||||
next(val) {
|
||||
that.waitSeconds++;
|
||||
if (that.waitSeconds >= that.MAX_TEST_SECONDS) {
|
||||
this.complete();
|
||||
}
|
||||
},
|
||||
complete() {
|
||||
that.changeStatus('tested');
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Change test status
|
||||
*
|
||||
@ -356,23 +386,15 @@ export class ApiTestComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
private changeStatus(status) {
|
||||
this.status = status;
|
||||
const that = this;
|
||||
console.log('changeStatus',status);
|
||||
switch (status) {
|
||||
case 'testing': {
|
||||
this.timer$ = interval(1000)
|
||||
.pipe(take(60))
|
||||
.subscribe({
|
||||
next(val) {
|
||||
console.log('next');
|
||||
that.waitSeconds = val + 1;
|
||||
},
|
||||
complete() {
|
||||
that.changeStatus('tested');
|
||||
},
|
||||
});
|
||||
this.setTestSecondsTimmer();
|
||||
break;
|
||||
}
|
||||
case 'tested': {
|
||||
this.model.testStartTime = 0;
|
||||
this.modelChange.emit(this.model);
|
||||
this.timer$.unsubscribe();
|
||||
this.waitSeconds = 0;
|
||||
this.responseTabIndexRes = 0;
|
||||
|
@ -18,7 +18,7 @@ export class TestServerRemoteService implements TestServer {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this.xhrByTabID[message.id].abort();
|
||||
this.xhrByTabID[message.id]?.abort();
|
||||
}
|
||||
}
|
||||
if (message.action !== 'ajax') {return;}
|
||||
|
@ -20,7 +20,7 @@ export class TestServerServerlessService implements TestServer {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this.xhrByTabID[message.id].abort();
|
||||
this.xhrByTabID[message.id]?.abort();
|
||||
}
|
||||
}
|
||||
if (message.action !== 'ajax') {return;}
|
||||
|
@ -129,7 +129,7 @@
|
||||
<context context-type="sourcefile">src/app/pages/api/api-tab.service.ts</context>
|
||||
<context context-type="linenumber">19</context>
|
||||
</context-group>
|
||||
<target state="translated">新 API</target>
|
||||
<target state="translated">添加 API</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="1295614462098694869" datatype="html">
|
||||
<source>Preview</source>
|
||||
@ -430,7 +430,7 @@
|
||||
<context context-type="sourcefile">src/app/pages/api/detail/api-detail-util.service.ts</context>
|
||||
<context context-type="linenumber">154</context>
|
||||
</context-group>
|
||||
<target state="translated"><button type="button" class="eo-operate-btn" ng-click="$ctrl.data.isSpreedBtnClick=!$ctrl.data.isSpreedBtnClick;$ctrl.data.isSpreed=true;$ctrl.mainObject.baseFun.spreedAll($event);$ctrl.data.isSpreed=false;">{{$ctrl.data.isSpreedBtnClick?"全部展开":"全部收缩"}}</button></target>
|
||||
<target state="translated"><button type="button" class="eo-operate-btn" ng-click="$ctrl.data.isSpreedBtnClick=!$ctrl.data.isSpreedBtnClick;$ctrl.data.isSpreed=true;$ctrl.mainObject.baseFun.spreedAll($event);$ctrl.data.isSpreed=false;">{{$ctrl.data.isSpreedBtnClick?"全部收缩":"全部展开"}}</button></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="5531234025897938404" datatype="html">
|
||||
<source><span class="eo-operate-btn fs12" ng-show="item.minimum ||
|
||||
@ -446,7 +446,7 @@
|
||||
item.maximum ||
|
||||
item.minLength ||
|
||||
item.maxLength ||
|
||||
(item.enum && item.enum.length > 0 && item.enum[0].value)">{{item.isClick?"展开":"收缩"}}</span></target>
|
||||
(item.enum && item.enum.length > 0 && item.enum[0].value)">{{item.isClick?"收缩":"展开"}}</span></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="9b985691961fb794ada1fb16421cc0c677c6480a" datatype="html">
|
||||
<source>Request Headers</source>
|
||||
@ -526,7 +526,7 @@
|
||||
<context context-type="sourcefile">src/app/pages/api/detail/api-detail.component.html</context>
|
||||
<context context-type="linenumber">32</context>
|
||||
</context-group>
|
||||
<target state="needs-translation">The outermost structure is: <x id="INTERPOLATION" equiv-text="{{ CONST.JSON_ROOT_TYPE[model.requestBodyJsonType] }}"/></target>
|
||||
<target state="translated">JSON 根类型: <x id="INTERPOLATION" equiv-text="{{ CONST.JSON_ROOT_TYPE[model.requestBodyJsonType] }}"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="a0b40184f4ad0e2da08dabf8c5209d23f02513b7" datatype="html">
|
||||
<source>Response Headers</source>
|
||||
@ -574,7 +574,7 @@
|
||||
<context context-type="sourcefile">src/app/pages/api/detail/api-detail.component.html</context>
|
||||
<context context-type="linenumber">54</context>
|
||||
</context-group>
|
||||
<target state="needs-translation">The outermost structure is: <x id="INTERPOLATION" equiv-text="{{ CONST.JSON_ROOT_TYPE[model.responseBodyJsonType] }}"/></target>
|
||||
<target state="translated">JSON 根类型: <x id="INTERPOLATION" equiv-text="{{ CONST.JSON_ROOT_TYPE[model.responseBodyJsonType] }}"/></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="150b08e70491356590c3f3706be1715d0b099467" datatype="html">
|
||||
<source>MOCK</source>
|
||||
@ -894,7 +894,7 @@
|
||||
<context context-type="sourcefile">src/app/pages/api/edit/api-edit.component.ts</context>
|
||||
<context context-type="linenumber">138</context>
|
||||
</context-group>
|
||||
<target state="needs-translation">Failed Operation</target>
|
||||
<target state="translated">操作失败</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="4926605800185679045" datatype="html">
|
||||
<source>Root directory</source>
|
||||
@ -926,7 +926,7 @@
|
||||
<context context-type="sourcefile">src/app/pages/api/edit/extra-setting/api-params-extra-setting.component.ts</context>
|
||||
<context context-type="linenumber">45</context>
|
||||
</context-group>
|
||||
<target state="needs-translation">Minimum length</target>
|
||||
<target state="translated">最小长度</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="1834980375662449209" datatype="html">
|
||||
<source>Maximum Length</source>
|
||||
@ -934,7 +934,7 @@
|
||||
<context context-type="sourcefile">src/app/pages/api/edit/extra-setting/api-params-extra-setting.component.ts</context>
|
||||
<context context-type="linenumber">53</context>
|
||||
</context-group>
|
||||
<target state="needs-translation">Maximum Length</target>
|
||||
<target state="translated">最大长度</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="1571736586383450200" datatype="html">
|
||||
<source>Minimum</source>
|
||||
@ -1126,7 +1126,9 @@
|
||||
<context context-type="sourcefile">src/app/pages/api/mock/api-mock.component.html</context>
|
||||
<context context-type="linenumber">20,21</context>
|
||||
</context-group>
|
||||
<target state="translated"> <x id="INTERPOLATION" equiv-text="{{ scope.createWay === 'system' ? '预览' : '编辑' }}"/></target>
|
||||
<target state="translated">
|
||||
<x id="INTERPOLATION" equiv-text="{{ scope.createWay === 'system' ? '预览' : '编辑' }}"/>
|
||||
</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="feacc7017fd641efba1aeb4883e42a352d9d5b6c" datatype="html">
|
||||
<source>Are you sure you want to delete this Mock?</source>
|
||||
@ -3220,7 +3222,9 @@
|
||||
<context context-type="sourcefile">src/app/shared/components/setting/common/extensions.component.ts</context>
|
||||
<context context-type="linenumber">40,42</context>
|
||||
</context-group>
|
||||
<target state="translated"><x id="INTERPOLATION" equiv-text="{{ module.properties[field]?.placeholder ?? '请输入 ' + module.properties[field]?.label }}"/></target>
|
||||
<target state="translated">
|
||||
<x id="INTERPOLATION" equiv-text="{{ module.properties[field]?.placeholder ?? '请输入 ' + module.properties[field]?.label }}"/>
|
||||
</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="e0d1ece694da029a20f5a97fbf3302f6213da891" datatype="html">
|
||||
<source>No plugins are currently installed,<x id="START_LINK" ctype="x-a" equiv-text="<a class="eo_link" (click)="navToExtensionList()">"/> go to install <x id="CLOSE_LINK" ctype="x-a" equiv-text="</a>"/></source>
|
||||
|
Loading…
Reference in New Issue
Block a user