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:
bqy_fe 2022-10-13 18:50:22 +08:00 committed by GitHub
parent be8f28f691
commit 54a8e6d46c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 149 additions and 125 deletions

View File

@ -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",

View File

@ -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();
// }
});
}
/**

View File

@ -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);
});
});
}
}

View File

@ -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 {

View File

@ -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: {} });
}

View File

@ -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);

View File

@ -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';

View File

@ -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>

View File

@ -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>

View File

@ -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.

View File

@ -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>;
}

View File

@ -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,

View File

@ -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));
}

View File

@ -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) {}
}