mirror of
https://gitee.com/eolink_admin/postcat.git
synced 2024-11-29 18:28:09 +08:00
chore: relese 1.8.1 (#160)
* pref: merge apiData & apiGroup request * text tips * fix: response text save fail * fix: mock not found * chore: relese 1.8.1 Co-authored-by: scarqin <1054139596@qq.com>
This commit is contained in:
parent
be8f28f691
commit
54a8e6d46c
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "eoapi",
|
||||
"souceLocale": "zh-Hans",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.1",
|
||||
"main": "out/app/electron-main/main.js",
|
||||
"description": "A lightweight, extensible API tool",
|
||||
"homepage": "https://github.com/eolinker/eoapi.git",
|
||||
|
@ -90,6 +90,30 @@ export class MockServer {
|
||||
// next();
|
||||
// }
|
||||
});
|
||||
this.app.all('/:workspaceID/:projectID/mock/:mockID/*', (req, res, next) => {
|
||||
// if (!protocolReg.test(req.url)) {
|
||||
// match request type
|
||||
const isMatchType = this.configuration.getModuleSettings<boolean>('eoapi-features.mock.matchType');
|
||||
if (req.params.mockID || isMatchType !== false) {
|
||||
this.view.webContents.send('getMockApiList', JSON.parse(jsonStringify(req)));
|
||||
ipcMain.once('getMockApiList', (event, message) => {
|
||||
const { response = {}, statusCode = 200 } = message;
|
||||
res.statusCode = statusCode;
|
||||
if (res.statusCode === 404) {
|
||||
this.send404(res, isMatchType);
|
||||
} else {
|
||||
res.send(response);
|
||||
}
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
this.send404(res, isMatchType);
|
||||
next();
|
||||
}
|
||||
// } else {
|
||||
// next();
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,15 +1,20 @@
|
||||
import { tree2obj } from './utils/tree/tree.utils';
|
||||
import { Injectable } from '@angular/core';
|
||||
import type { IpcRenderer } from 'electron';
|
||||
import { ApiData, ApiMockEntity } from 'eo/workbench/browser/src/app/shared/services/storage/index.model';
|
||||
import { IndexedDBStorage } from 'eo/workbench/browser/src/app/shared/services/storage/IndexedDB/lib/';
|
||||
import {
|
||||
ApiData,
|
||||
ApiMockEntity,
|
||||
StorageRes,
|
||||
StorageResStatus,
|
||||
} from 'eo/workbench/browser/src/app/shared/services/storage/index.model';
|
||||
import { StorageService } from 'eo/workbench/browser/src/app/shared/services/storage/storage.service';
|
||||
import { DataSourceService } from 'eo/workbench/browser/src/app/shared/services/data-source/data-source.service';
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
private ipcRenderer: IpcRenderer = window.require?.('electron')?.ipcRenderer;
|
||||
|
||||
constructor(private indexedDBStorage: IndexedDBStorage, private dataSource: DataSourceService) {}
|
||||
constructor(private storageService: StorageService, private dataSource: DataSourceService) {}
|
||||
|
||||
init() {
|
||||
if (this.ipcRenderer) {
|
||||
@ -88,14 +93,12 @@ export class AppService {
|
||||
*/
|
||||
getMockByMockID(mockID: number): Promise<ApiMockEntity> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.indexedDBStorage.mockLoad(mockID).subscribe(
|
||||
(res: any) => {
|
||||
resolve(res.data);
|
||||
},
|
||||
(error: any) => {
|
||||
reject(error);
|
||||
this.storageService.run('mockLoad', [mockID], async (result: StorageRes) => {
|
||||
if (result.status === StorageResStatus.success) {
|
||||
return resolve(result.data);
|
||||
}
|
||||
);
|
||||
return reject(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
@ -106,14 +109,12 @@ export class AppService {
|
||||
*/
|
||||
getApiData(apiDataID: number): Promise<ApiData> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.indexedDBStorage.apiDataLoad(apiDataID).subscribe(
|
||||
(res: any) => {
|
||||
resolve(res.data);
|
||||
},
|
||||
(error: any) => {
|
||||
reject(error);
|
||||
this.storageService.run('apiDataLoad', [apiDataID], async (result: StorageRes) => {
|
||||
if (result.status === StorageResStatus.success) {
|
||||
return resolve(result.data);
|
||||
}
|
||||
);
|
||||
return reject(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
@ -121,14 +122,12 @@ export class AppService {
|
||||
*/
|
||||
getAllApi(projectID = 1): Promise<ApiData[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.indexedDBStorage.apiDataLoadAllByProjectID(projectID).subscribe(
|
||||
(res: any) => {
|
||||
resolve(res.data);
|
||||
},
|
||||
(error: any) => {
|
||||
reject(error);
|
||||
this.storageService.run('apiDataLoadAllByProjectID', [projectID], async (result: StorageRes) => {
|
||||
if (result.status === StorageResStatus.success) {
|
||||
return resolve(result.data);
|
||||
}
|
||||
);
|
||||
return reject(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
||||
import { StorageRes, StorageResStatus } from '../../shared/services/storage/index.model';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
import { filter, Subject, takeUntil } from 'rxjs';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { Message, MessageService } from '../../shared/services/message';
|
||||
import { StorageService } from '../../shared/services/storage';
|
||||
@ -75,8 +75,7 @@ export class ApiComponent implements OnInit, OnDestroy {
|
||||
private storage: StorageService,
|
||||
private electron: ElectronService,
|
||||
private store: Store
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
get envUuid(): number | null {
|
||||
return Number(localStorage.getItem('env:selected')) || 0;
|
||||
}
|
||||
@ -137,9 +136,12 @@ export class ApiComponent implements OnInit, OnDestroy {
|
||||
* Get current API ID to show content tab
|
||||
*/
|
||||
watchRouterChange() {
|
||||
this.router.events.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
||||
this.id = Number(this.route.snapshot.queryParams.uuid);
|
||||
});
|
||||
this.router.events
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.pipe(filter((event) => event instanceof NavigationEnd))
|
||||
.subscribe(() => {
|
||||
this.id = Number(this.route.snapshot.queryParams.uuid);
|
||||
});
|
||||
}
|
||||
|
||||
onSideResize({ width }: NzResizeEvent): void {
|
||||
|
@ -115,7 +115,8 @@ export class ApiGroupEditComponent implements OnInit {
|
||||
if (result.status === StorageResStatus.success) {
|
||||
//delete group api
|
||||
if (data.api.length > 0) {
|
||||
this.apiService.bulkDelete(data.api);
|
||||
// this.apiService.bulkDelete(data.api);
|
||||
this.messageService.send({ type: 'deleteApiSuccess', data: { uuids: data.api } });
|
||||
} else {
|
||||
this.messageService.send({ type: 'updateGroupSuccess', data: {} });
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import { ElectronService } from '../../../../core/services';
|
||||
import { ApiService } from 'eo/workbench/browser/src/app/pages/api/api.service';
|
||||
import { ImportApiComponent } from 'eo/workbench/browser/src/app/shared/components/import-api/import-api.component';
|
||||
import { EoMessageService } from 'eo/workbench/browser/src/app/eoui/message/eo-message.service';
|
||||
import { ProjectService } from 'eo/workbench/browser/src/app/shared/services/project/project.service';
|
||||
@Component({
|
||||
selector: 'eo-api-group-tree',
|
||||
templateUrl: './api-group-tree.component.html',
|
||||
@ -73,6 +74,7 @@ export class ApiGroupTreeComponent implements OnInit, OnDestroy {
|
||||
private storage: StorageService,
|
||||
public electron: ElectronService,
|
||||
private apiService: ApiService,
|
||||
private projectService: ProjectService,
|
||||
private nzModalService: NzModalService
|
||||
) {}
|
||||
ngOnInit(): void {
|
||||
@ -101,52 +103,53 @@ export class ApiGroupTreeComponent implements OnInit, OnDestroy {
|
||||
buildGroupTreeData = debounce(() => {
|
||||
this.groupByID = {};
|
||||
this.treeItems = [];
|
||||
this.getGroups();
|
||||
this.getProjectCollections();
|
||||
});
|
||||
getGroups() {
|
||||
|
||||
getProjectCollections() {
|
||||
this.apiDataLoading = true;
|
||||
this.storage.run('groupLoadAllByProjectID', [this.projectID], (result: StorageRes) => {
|
||||
this.storage.run('projectCollections', [this.projectService.currentProjectID], (result: StorageRes) => {
|
||||
if (result.status === StorageResStatus.success) {
|
||||
result.data.forEach((item) => {
|
||||
delete item.updatedAt;
|
||||
this.groupByID[item.uuid] = item;
|
||||
this.treeItems.push({
|
||||
title: item.name,
|
||||
key: `group-${item.uuid}`,
|
||||
weight: item.weight || 0,
|
||||
parentID: item.parentID ? `group-${item.parentID}` : '0',
|
||||
isLeaf: false,
|
||||
});
|
||||
});
|
||||
const { groups, apis } = result.data;
|
||||
this.getGroups(groups);
|
||||
this.getApis(apis);
|
||||
}
|
||||
this.getApis().finally(() => {
|
||||
this.apiDataLoading = false;
|
||||
this.apiDataLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
getGroups(apiGroups = []) {
|
||||
apiGroups.forEach((item) => {
|
||||
delete item.updatedAt;
|
||||
this.groupByID[item.uuid] = item;
|
||||
this.treeItems.push({
|
||||
title: item.name,
|
||||
key: `group-${item.uuid}`,
|
||||
weight: item.weight || 0,
|
||||
parentID: item.parentID ? `group-${item.parentID}` : '0',
|
||||
isLeaf: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
async getApis() {
|
||||
const result: StorageRes = await this.apiService.getAll(this.projectID);
|
||||
const { success, empty } = StorageResStatus;
|
||||
if ([success, empty].includes(result.status)) {
|
||||
const apiItems = {};
|
||||
[].concat(result.data).forEach((item: ApiData) => {
|
||||
delete item.updatedAt;
|
||||
apiItems[item.uuid] = item;
|
||||
this.treeItems.push({
|
||||
title: item.name,
|
||||
key: item.uuid.toString(),
|
||||
weight: item.weight || 0,
|
||||
parentID: item.groupID ? `group-${item.groupID}` : '0',
|
||||
method: item.method,
|
||||
isLeaf: true,
|
||||
});
|
||||
async getApis(apis) {
|
||||
const apiItems = {};
|
||||
[].concat(apis).forEach((item: ApiData) => {
|
||||
delete item.updatedAt;
|
||||
apiItems[item.uuid] = item;
|
||||
this.treeItems.push({
|
||||
title: item.name,
|
||||
key: item.uuid.toString(),
|
||||
weight: item.weight || 0,
|
||||
parentID: item.groupID ? `group-${item.groupID}` : '0',
|
||||
method: item.method,
|
||||
isLeaf: true,
|
||||
});
|
||||
this.apiDataItems = apiItems;
|
||||
this.messageService.send({ type: 'loadApi', data: this.apiDataItems });
|
||||
this.setSelectedKeys();
|
||||
this.generateGroupTreeData();
|
||||
this.restoreExpandStatus();
|
||||
}
|
||||
});
|
||||
this.apiDataItems = apiItems;
|
||||
this.messageService.send({ type: 'loadApi', data: this.apiDataItems });
|
||||
this.setSelectedKeys();
|
||||
this.generateGroupTreeData();
|
||||
this.restoreExpandStatus();
|
||||
}
|
||||
restoreExpandStatus() {
|
||||
const key = this.expandKeys.slice(0);
|
||||
|
@ -41,8 +41,7 @@ export class ApiTestResultResponseComponent implements OnInit, OnChanges {
|
||||
}
|
||||
}
|
||||
}
|
||||
ngOnInit(): void {
|
||||
}
|
||||
ngOnInit(): void {}
|
||||
|
||||
contextMenu($event: MouseEvent, menu: NzDropdownMenuComponent): void {
|
||||
this.nzContextMenuService.create($event, menu);
|
||||
@ -50,7 +49,7 @@ export class ApiTestResultResponseComponent implements OnInit, OnChanges {
|
||||
|
||||
downloadResponseText() {
|
||||
this.blobUrl = getBlobUrl(this.model.body, this.model.contentType);
|
||||
const blobFileName = decodeURI(this.model.blobFileName);
|
||||
const blobFileName = decodeURI(this.model.blobFileName || 'test_response');
|
||||
const tmpAElem = document.createElement('a');
|
||||
if ('download' in tmpAElem) {
|
||||
tmpAElem.style.visibility = 'hidden';
|
||||
|
@ -1,56 +1,33 @@
|
||||
<!-- {{getConsoleTabs()|json}} -->
|
||||
<nz-tabset
|
||||
[(nzSelectedIndex)]="tabOperate.selectedIndex"
|
||||
nzType="editable-card"
|
||||
[nzHideAdd]="true"
|
||||
[nzCanDeactivate]=" canDeactivate"
|
||||
(nzSelectChange)="selectChange($event)"
|
||||
[nzTabBarExtraContent]="extraTemplate"
|
||||
>
|
||||
<nz-tabset [(nzSelectedIndex)]="tabOperate.selectedIndex" nzType="editable-card" [nzHideAdd]="true"
|
||||
[nzCanDeactivate]=" canDeactivate" (nzSelectChange)="selectChange($event)" [nzTabBarExtraContent]="extraTemplate">
|
||||
<nz-tab *ngFor="let uuid of tabStorage.tabOrder; let i = index" [nzTitle]="titleTemplate">
|
||||
<ng-template #titleTemplate>
|
||||
<div
|
||||
class="flex items-center tab-item-container"
|
||||
[ngClass]="{ 'fixed-tab-item-container': tabStorage.tabsByID.get(uuid).isFixed }"
|
||||
>
|
||||
<div class="flex items-center tab-item-container"
|
||||
[ngClass]="{ 'fixed-tab-item-container': tabStorage.tabsByID.get(uuid)?.isFixed }">
|
||||
<!-- loading -->
|
||||
<nz-spin nzSimple class="mr10" [nzSize]="'small'" *ngIf="tabStorage.tabsByID.get(uuid).isLoading"></nz-spin>
|
||||
<eo-iconpark-icon
|
||||
class="mr5"
|
||||
name="{{ tabStorage.tabsByID.get(uuid).icon }}"
|
||||
size="14px"
|
||||
*ngIf="tabStorage.tabsByID.get(uuid).icon"
|
||||
></eo-iconpark-icon>
|
||||
<span
|
||||
class="mr5 method-text method_text_{{ tabStorage.tabsByID.get(uuid).extends.method }}"
|
||||
*ngIf="tabStorage.tabsByID.get(uuid).extends?.method"
|
||||
>{{ tabStorage.tabsByID.get(uuid).extends.method }}</span
|
||||
>
|
||||
<eo-iconpark-icon class="mr5" name="{{ tabStorage.tabsByID.get(uuid).icon }}" size="14px"
|
||||
*ngIf="tabStorage.tabsByID.get(uuid).icon"></eo-iconpark-icon>
|
||||
<span class="mr5 method-text method_text_{{ tabStorage.tabsByID.get(uuid).extends.method }}"
|
||||
*ngIf="tabStorage.tabsByID.get(uuid).extends?.method">{{ tabStorage.tabsByID.get(uuid).extends.method
|
||||
}}</span>
|
||||
<span class="text_omit tab_text" [title]="tabStorage.tabsByID.get(uuid).title">
|
||||
{{ tabStorage.tabsByID.get(uuid).title }}</span
|
||||
>
|
||||
{{ tabStorage.tabsByID.get(uuid).title }}</span>
|
||||
<!-- Close/HasEdit -->
|
||||
<div class="flex items-center tab-item-button-group">
|
||||
<span class="tab-has-edit-icon eo-tab-theme-icon" *ngIf="tabStorage.tabsByID.get(uuid).hasChanged"></span>
|
||||
<button
|
||||
aria-label="Close tab"
|
||||
(click)="closeTab({ $event: $event, index: i, tab: tabStorage.tabsByID.get(uuid) })"
|
||||
type="button"
|
||||
nz-tab-close-button=""
|
||||
class="ant-tabs-tab-remove"
|
||||
></button>
|
||||
<button aria-label="Close tab"
|
||||
(click)="closeTab({ $event: $event, index: i, tab: tabStorage.tabsByID.get(uuid) })" type="button"
|
||||
nz-tab-close-button="" class="ant-tabs-tab-remove"></button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</nz-tab>
|
||||
</nz-tabset>
|
||||
<ng-template #extraTemplate>
|
||||
<button
|
||||
(click)="newTab()"
|
||||
nz-dropdown
|
||||
[nzDropdownMenu]="addMenu"
|
||||
class="ant-tabs-nav-add {{ tabStorage.tabOrder.length >= MAX_TAB_LIMIT ? 'hidden' : '' }}"
|
||||
>
|
||||
<button (click)="newTab()" nz-dropdown [nzDropdownMenu]="addMenu"
|
||||
class="ant-tabs-nav-add {{ tabStorage.tabOrder.length >= MAX_TAB_LIMIT ? 'hidden' : '' }}">
|
||||
<eo-iconpark-icon name="plus" size="16px"></eo-iconpark-icon>
|
||||
</button>
|
||||
<nz-dropdown-menu #addMenu="nzDropdownMenu">
|
||||
@ -59,8 +36,10 @@
|
||||
<li nz-menu-item (click)="newTab('/home/api/ws/test')">Websocket</li>
|
||||
</ul>
|
||||
</nz-dropdown-menu>
|
||||
<a nz-dropdown [nzDropdownMenu]="menu">
|
||||
<button class="ant-tabs-nav-more"><eo-iconpark-icon class="mr5" name="more" size="16px"></eo-iconpark-icon></button>
|
||||
<a nz-dropdown [nzDropdownMenu]="menu">
|
||||
<button class="ant-tabs-nav-more">
|
||||
<eo-iconpark-icon class="mr5" name="more" size="16px"></eo-iconpark-icon>
|
||||
</button>
|
||||
</a>
|
||||
<nz-dropdown-menu #menu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
@ -71,12 +50,8 @@
|
||||
<li nz-menu-item (click)="closeTabByOperate('closeLeft')" [nzDisabled]="tabOperate.selectedIndex === 0" i18n>
|
||||
Close Tabs To the Left
|
||||
</li>
|
||||
<li
|
||||
nz-menu-item
|
||||
[nzDisabled]="tabStorage.tabOrder.length - 1 === tabOperate.selectedIndex"
|
||||
(click)="closeTabByOperate('closeRight')"
|
||||
i18n
|
||||
>
|
||||
<li nz-menu-item [nzDisabled]="tabStorage.tabOrder.length - 1 === tabOperate.selectedIndex"
|
||||
(click)="closeTabByOperate('closeRight')" i18n>
|
||||
Close Tabs to the Right
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -23,7 +23,7 @@
|
||||
</div>
|
||||
<ng-template #empty>
|
||||
<div class="text mb-4" i18n>
|
||||
This feature requires plugin support, please move to<a class="eo_link" routerLink="/home/extension/list"> Extensions </a> download
|
||||
This feature requires plugin support, please move to<a class="eo_link" routerLink="/home/extension/list"> Extensions </a> download or open exist extensions.
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
|
@ -654,6 +654,24 @@ export class IndexedDBStorage extends Dexie implements StorageInterface {
|
||||
groupLoadAllByProjectID(projectID: number | string): Observable<object> {
|
||||
return this.loadAllByConditions(this.group, { projectID });
|
||||
}
|
||||
/**
|
||||
* Load project collections
|
||||
* @param projectID
|
||||
* @returns
|
||||
*/
|
||||
projectCollections(projectID: number | string): Observable<object> {
|
||||
return new Observable((obs) => {
|
||||
const fun = async () => {
|
||||
const result = {
|
||||
groups: await this.group.where({ projectID }).toArray(),
|
||||
apis: await this.apiData.where({ projectID }).toArray(),
|
||||
};
|
||||
obs.next(this.resProxy(result));
|
||||
obs.complete();
|
||||
};
|
||||
fun();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete group item.
|
||||
|
@ -23,6 +23,10 @@ export class HttpStorage implements StorageInterface {
|
||||
projectImport(uuid: number, item: Project) {
|
||||
return this.http.put(`/project/${uuid}/import`, item) as Observable<object>;
|
||||
}
|
||||
// Project collections
|
||||
projectCollections(uuid: number) {
|
||||
return this.http.get(`/project/${uuid}/collections`) as Observable<object>;
|
||||
}
|
||||
projectCreate(item: Project) {
|
||||
return this.http.post(`/project`, item) as Observable<object>;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ const base64ToUint8Array = (inputBase64String) => {
|
||||
export const getBlobUrl = (inputStream, inputFileType) => {
|
||||
let tmpBlob;
|
||||
try {
|
||||
inputStream = base64ToUint8Array(inputStream);
|
||||
// inputStream = base64ToUint8Array(inputStream);
|
||||
if (typeof window.Blob === 'function') {
|
||||
tmpBlob = new Blob([inputStream], {
|
||||
type: inputFileType,
|
||||
|
@ -61,7 +61,6 @@ export const createStorage = ({ prefixKey = '', storage = localStorage } = {}) =
|
||||
* @param {string} key
|
||||
*/
|
||||
remove(key: string) {
|
||||
console.log(key, '搜索');
|
||||
this.storage.removeItem(this.getKey(key));
|
||||
}
|
||||
|
||||
|
@ -417,12 +417,12 @@ const { resolve } = require('path');
|
||||
tmpFileBinary,
|
||||
blobFileName;
|
||||
try {
|
||||
blobFileName = _ContentDisposition.parse(inputRes.headers['content-disposition'] || 'undefined')
|
||||
blobFileName = _ContentDisposition.parse(inputRes.headers['content-disposition'] || 'test_response')
|
||||
.parameters.filename;
|
||||
} catch (PARSE_CONTENT_DISPOSITION_ERR) {
|
||||
try {
|
||||
blobFileName = _ContentDisposition.parse(
|
||||
encodeURI(inputRes.headers['content-disposition'] || 'undefined').replace(/\?/g, '')
|
||||
encodeURI(inputRes.headers['content-disposition'] || 'test_response').replace(/\?/g, '')
|
||||
).parameters.filename;
|
||||
} catch (URL_ENCODE_PARSE_CONTENT_DISPOSITION_ERR) {}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user