From 59a3c84b52597964e7f2aecb442e0ea86bf84b4b Mon Sep 17 00:00:00 2001 From: Scarqin Date: Wed, 22 Mar 2023 22:32:52 +0800 Subject: [PATCH] feat/v0.4.1 (#281) * fix: import dataType problem * refactor: eletronmanin and extionsionschange code optimize * fix: bug repairs * refactor: electron main and extensionschange optimize * fix: import formdata bug * test: env e2e * refactor: resolve review * style: test status bar * wip: merge yzaio * fix: env select hover * fix: test error&&chat GPT length error * style: environment error * fix: env select boxshadow * fix: content-type match bodyType error * feat: 0.4.1 --------- Co-authored-by: sunzhouyang --- package.json | 2 +- src/app/electron-main/main.ts | 154 ++++++++++-------- src/browser/package.json | 1 + .../chat-robot-message.component.scss | 1 - .../monaco-editor/monaco-editor.component.ts | 1 - .../export-api/export-api.component.ts | 18 +- .../import-api/import-api.component.ts | 17 +- .../push-api/push-api.component.ts | 25 +-- .../select/extension-select.component.ts | 14 +- .../sync-api/sync-api.component.ts | 32 ++-- .../nps-mask/component/nps-mask.component.ts | 8 +- .../nps-mask/nps-mask-postion.directive.ts | 11 +- .../feature-control.service.ts | 40 ++--- .../app/core/services/theme/theme.service.ts | 50 +++--- .../app/layouts/sidebar/sidebar.component.ts | 27 ++- .../chatgpt-robot/chatgpt-robot.component.ts | 83 +++++++--- .../overview/edit/workspace-edit.component.ts | 2 +- .../workspace/project/api/api.component.ts | 16 +- .../api-test-form/api-test-form.component.ts | 10 +- .../authorization-extension-form.component.ts | 18 +- .../group/tree/api-group-tree.component.ts | 7 +- .../history/eo-history.component.html | 1 - .../params-import/params-import.component.ts | 1 - .../env/env-select/env-select.component.scss | 44 +++-- .../env/env-select/env-select.component.ts | 10 +- .../api/http/edit/api-edit-util.service.ts | 9 +- .../api/http/edit/api-edit.component.ts | 4 + .../http/edit/form/api-edit-form.component.ts | 2 +- .../api/http/test/api-test.component.html | 36 ++-- .../api/http/test/api-test.component.scss | 4 - .../api/http/test/api-test.component.ts | 95 +++++++---- .../project/api/http/test/api-test.module.ts | 3 +- .../http/test/body/api-test-body.component.ts | 2 +- .../api-test-result-response.component.html | 13 +- .../api-test-result-response.component.scss | 36 +--- .../api-test-result-response.component.ts | 12 +- .../test/result-response/get-size.pipe.ts | 8 +- .../test-status-bar.component.scss | 15 ++ .../test-status-bar.component.ts | 50 ++++++ .../api/service/api-test-util.service.ts | 37 +---- .../test-server/test-server.service.ts | 5 +- .../project/api/store/api-state.service.ts | 13 ++ .../setting/project-setting.component.ts | 17 +- .../services/extensions/extension.service.ts | 4 +- .../app/services/storage/db/models/apiData.ts | 2 + .../src/app/shared/constans/featureName.ts | 9 + .../src/app/shared/decorators/index.ts | 50 ++++++ .../src/app/shared/models/extension.ts | 2 +- src/browser/src/app/shared/shared.module.ts | 2 + .../data-transfer/data-transfer.utils.ts | 2 +- .../src/app/shared/utils/index.utils.ts | 12 +- src/browser/src/app/store/effect.service.ts | 3 +- src/node/test-server/package.json | 4 +- src/node/test-server/request/libs/apiUtil.js | 12 +- src/node/test-server/request/unit.js | 2 +- .../node/extension-manager/manager.ts | 4 +- src/shared/electron-main/constant.ts | 12 ++ test/e2e/src/env.spec.ts | 10 +- .../test-failed-1.png | Bin 0 -> 21426 bytes yarn.lock | 12 ++ 60 files changed, 666 insertions(+), 430 deletions(-) create mode 100644 src/browser/src/app/pages/workspace/project/api/http/test/test-status-bar/test-status-bar.component.scss create mode 100644 src/browser/src/app/pages/workspace/project/api/http/test/test-status-bar/test-status-bar.component.ts create mode 100644 src/browser/src/app/shared/constans/featureName.ts create mode 100644 src/browser/src/app/shared/decorators/index.ts create mode 100644 test/e2e/test-results/src-user-User-Opeate-chromium/test-failed-1.png diff --git a/package.json b/package.json index 67880bbb2..16118eea1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postcat", - "version": "0.4.0", + "version": "0.4.1", "main": "out/app/electron-main/main.js", "description": "A lightweight, extensible API tool", "homepage": "https://github.com/Postcatlab/postcat.git", diff --git a/src/app/electron-main/main.ts b/src/app/electron-main/main.ts index 893cda992..a328466da 100644 --- a/src/app/electron-main/main.ts +++ b/src/app/electron-main/main.ts @@ -3,6 +3,19 @@ import { app, BrowserWindow, ipcMain } from 'electron'; import Store from 'electron-store'; import { LanguageService } from 'pc/app/electron-main/language.service'; import { MockServer } from 'pc/platform/node/mock-server'; +import { + GET_EXT_TABS, + GET_FEATURE, + GET_MOCK_URL, + GET_MODULE, + GET_MODULES, + GET_SIDEBAR_VIEW, + GET_SIDEBAR_VIEWS, + GET_WEBSOCKET_PORT, + INSTALL_MODULE, + LOGIN_WITH, + UNINSTALL_MODULE +} from 'pc/shared/electron-main/constant'; import portfinder from 'portfinder'; import { UnitWorkerModule } from '../../node/test-server/electron/main'; @@ -195,73 +208,86 @@ try { } }); let loginWindow = null; - // 这里可以封装成类+方法匹配调用,不用多个if else - ['on', 'handle'].forEach(eventName => - ipcMain[eventName]('eo-sync', async (event, arg) => { - let returnValue: any; - if (arg.action === 'getModules') { - returnValue = moduleManager.getModules(); - } else if (arg.action === 'getModule') { - returnValue = moduleManager.getModule(arg.data.id); - } else if (arg.action === 'installModule') { - const data = await moduleManager.installExt(arg.data); - returnValue = Object.assign(data, { modules: moduleManager.getModules() }); - } else if (arg.action === 'uninstallModule') { - const data = await moduleManager.uninstall(arg.data); - returnValue = Object.assign(data, { modules: moduleManager.getModules() }); - } else if (arg.action === 'getExtensionPackage') { - returnValue = await moduleManager.getExtensionPackage(arg.data.feature, arg.data.params); - } else if (arg.action === 'getFeature') { - returnValue = moduleManager.getFeature(arg.data.featureKey); - } else if (arg.action === 'getMockUrl') { - // 获取mock服务地址 - returnValue = mockServer.getMockUrl(); - } else if (arg.action === 'getWebsocketPort') { - // 获取websocket服务端口 - returnValue = websocketPort; - } else if (arg.action === 'getExtTabs') { - returnValue = moduleManager.getExtTabs(arg.data.extName); - } else if (arg.action === 'loginWith') { - // * It is eletron, open a new window for login - if (loginWindow) { - loginWindow.destroy(); - loginWindow = null; - } - loginWindow = new BrowserWindow({ - width: 990, - height: 655, - autoHideMenuBar: true, - webPreferences: { - nodeIntegration: false, - contextIsolation: false, - preload: path.join(__dirname, '../../platform/electron-browser/preload.js') - } - }); - loginWindow.loadURL(arg.data.url); - //* Watch the login result - loginWindow.webContents.on('did-navigate', ($event, url = '') => { - const isError = url.includes('request-errors'); - const isSuccess = url.includes('code='); - if (isError || isSuccess) { - loginWindow?.destroy(); - loginWindow = null; - const querys = new URLSearchParams(url.split('?')?.[1]); - eoBrowserWindow.win.webContents.send('thirdLoginCallback', { - isSuccess: isSuccess, - code: querys?.get('code') - }); - } - }); + const getModules = () => Promise.resolve(moduleManager.getModules()); + + const getModule = arg => Promise.resolve(moduleManager.getModule(arg.data.id)); + + const installModule = async arg => { + const data = await moduleManager.installExt(arg.data); + return Object.assign(data, { modules: moduleManager.getModules() }); + }; + + const uninstallModule = async arg => { + const data = await moduleManager.uninstall(arg.data); + return Object.assign(data, { modules: moduleManager.getModules() }); + }; + + const getFeature = arg => Promise.resolve(moduleManager.getFeature(arg.data.featureKey)); + + const getMockUrl = () => Promise.resolve(mockServer.getMockUrl()); + + const getWebsocketPort = () => Promise.resolve(websocketPort); + + const getExtTabs = arg => Promise.resolve(moduleManager.getExtTabs(arg.data.extName)); + + const loginWith = arg => { + if (loginWindow) { + loginWindow.destroy(); + loginWindow = null; + } + loginWindow = new BrowserWindow({ + width: 990, + height: 655, + autoHideMenuBar: true, + webPreferences: { + nodeIntegration: false, + contextIsolation: false, + preload: path.join(__dirname, '../../platform/electron-browser/preload.js') + } + }); + loginWindow.loadURL(arg.data.url); - returnValue = ''; - } else if (arg.action === 'getSidebarView') { - returnValue = moduleManager.getSidebarView(arg.data.extName); - } else if (arg.action === 'getSidebarViews') { - returnValue = moduleManager.getSidebarViews(); - } else { - returnValue = 'Invalid data'; + //* Watch the login result + loginWindow.webContents.on('did-navigate', ($event, url = '') => { + const isError = url.includes('request-errors'); + const isSuccess = url.includes('code='); + if (isError || isSuccess) { + loginWindow?.destroy(); + loginWindow = null; + const querys = new URLSearchParams(url.split('?')?.[1]); + eoBrowserWindow.win.webContents.send('thirdLoginCallback', { + isSuccess: isSuccess, + code: querys?.get('code') + }); } + }); + + return Promise.resolve(''); + }; + + const getSidebarView = arg => Promise.resolve(moduleManager.getSidebarView(arg.data.extName)); + + const getSidebarViews = () => Promise.resolve(moduleManager.getSidebarViews()); + + const action = { + [GET_MODULES]: getModules, + [GET_MODULE]: getModule, + [INSTALL_MODULE]: installModule, + [UNINSTALL_MODULE]: uninstallModule, + [GET_FEATURE]: getFeature, + [GET_MOCK_URL]: getMockUrl, + [GET_WEBSOCKET_PORT]: getWebsocketPort, + [GET_EXT_TABS]: getExtTabs, + // * It is eletron, open a new window for login + [LOGIN_WITH]: loginWith, + [GET_SIDEBAR_VIEW]: getSidebarView, + [GET_SIDEBAR_VIEWS]: getSidebarViews + }; + + ['on', 'handle'].forEach(eventName => + ipcMain[eventName]('eo-sync', async (event, arg) => { + let returnValue = Object.keys(action).includes(arg.action) ? await action[arg.action](arg) : 'Invalid data'; event.returnValue = returnValue; return returnValue; }) diff --git a/src/browser/package.json b/src/browser/package.json index 865c794da..4b5b22d4d 100644 --- a/src/browser/package.json +++ b/src/browser/package.json @@ -53,6 +53,7 @@ "eo-ng-table": "0.1.14", "eo-ng-tabs": "0.1.11", "eo-ng-tree": "0.1.16", + "gpt3-tokenizer": "1.1.5", "is-xml": "0.1.0", "js-beautify": "1.14.7", "lodash-es": "4.17.21", diff --git a/src/browser/src/app/components/chat-robot/chat-robot-message/chat-robot-message.component.scss b/src/browser/src/app/components/chat-robot/chat-robot-message/chat-robot-message.component.scss index 1fbbd793b..7dd22ce72 100644 --- a/src/browser/src/app/components/chat-robot/chat-robot-message/chat-robot-message.component.scss +++ b/src/browser/src/app/components/chat-robot/chat-robot-message/chat-robot-message.component.scss @@ -5,7 +5,6 @@ .message-content { padding: 1rem; border-radius: 0.5rem; - min-width: fit-content; max-width: 400px; } diff --git a/src/browser/src/app/components/eo-ui/monaco-editor/monaco-editor.component.ts b/src/browser/src/app/components/eo-ui/monaco-editor/monaco-editor.component.ts index 6b6f88537..6169ebad9 100644 --- a/src/browser/src/app/components/eo-ui/monaco-editor/monaco-editor.component.ts +++ b/src/browser/src/app/components/eo-ui/monaco-editor/monaco-editor.component.ts @@ -189,7 +189,6 @@ export class EoMonacoEditorComponent implements AfterViewInit, OnInit, OnChanges if (val === this.$$code) { return; } - let code = val; try { if (typeof val === 'object') { diff --git a/src/browser/src/app/components/extension-select/export-api/export-api.component.ts b/src/browser/src/app/components/extension-select/export-api/export-api.component.ts index e7fafc046..a953eb276 100644 --- a/src/browser/src/app/components/extension-select/export-api/export-api.component.ts +++ b/src/browser/src/app/components/extension-select/export-api/export-api.component.ts @@ -4,6 +4,8 @@ import { ExtensionService } from 'pc/browser/src/app/services/extensions/extensi import { Message, MessageService } from 'pc/browser/src/app/services/message'; import { ApiService } from 'pc/browser/src/app/services/storage/api.service'; import { TraceService } from 'pc/browser/src/app/services/trace.service'; +import { EXPORT_API } from 'pc/browser/src/app/shared/constans/featureName'; +import { ExtensionChange } from 'pc/browser/src/app/shared/decorators'; import { FeatureInfo } from 'pc/browser/src/app/shared/models/extension-manager'; import StorageUtil from 'pc/browser/src/app/shared/utils/storage/storage.utils'; import { StoreService } from 'pc/browser/src/app/store/state.service'; @@ -32,17 +34,11 @@ export class ExportApiComponent implements OnInit { ) {} ngOnInit(): void { this.initData(); - this.messageService - .get() - .pipe(takeUntil(this.destroy$)) - .subscribe((inArg: Message) => { - if (inArg.type === 'extensionsChange') { - this.initData(); - } - }); } - initData = () => { - this.featureMap = this.extensionService.getValidExtensionsByFature('exportAPI'); + @ExtensionChange(EXPORT_API, true) + initData() { + console.log('initData'); + this.featureMap = this.extensionService.getValidExtensionsByFature(EXPORT_API); this.supportList = []; this.featureMap?.forEach((data: FeatureInfo, key: string) => { this.supportList.push({ @@ -55,7 +51,7 @@ export class ExportApiComponent implements OnInit { if (!(this.currentExtension && this.supportList.find(val => val.key === this.currentExtension))) { this.currentExtension = key || ''; } - }; + } submit(callback: () => boolean) { this.export(callback); } diff --git a/src/browser/src/app/components/extension-select/import-api/import-api.component.ts b/src/browser/src/app/components/extension-select/import-api/import-api.component.ts index 013accde4..b06f23056 100644 --- a/src/browser/src/app/components/extension-select/import-api/import-api.component.ts +++ b/src/browser/src/app/components/extension-select/import-api/import-api.component.ts @@ -6,6 +6,8 @@ import { Message, MessageService } from 'pc/browser/src/app/services/message'; import { ApiService } from 'pc/browser/src/app/services/storage/api.service'; import { parseAndCheckCollections, parseAndCheckEnv } from 'pc/browser/src/app/services/storage/db/validate/validate'; import { TraceService } from 'pc/browser/src/app/services/trace.service'; +import { IMPORT_API } from 'pc/browser/src/app/shared/constans/featureName'; +import { ExtensionChange } from 'pc/browser/src/app/shared/decorators'; import { FeatureInfo } from 'pc/browser/src/app/shared/models/extension-manager'; import { StoreService } from 'pc/browser/src/app/store/state.service'; import { Subject } from 'rxjs'; @@ -76,14 +78,12 @@ export class ImportApiComponent implements OnInit { this.messageService .get() .pipe(takeUntil(this.destroy$)) - .subscribe((inArg: Message) => { - if (inArg.type === 'extensionsChange') { - this.initData(); - } - }); + .subscribe((inArg: Message) => {}); } - initData = () => { - this.featureMap = this.extensionService.getValidExtensionsByFature('importAPI'); + + @ExtensionChange(IMPORT_API, true) + initData() { + this.featureMap = this.extensionService.getValidExtensionsByFature(IMPORT_API); this.supportList = []; this.featureMap?.forEach((data: FeatureInfo, key: string) => { this.supportList.push({ @@ -96,7 +96,7 @@ export class ImportApiComponent implements OnInit { if (!(this.currentExtension && this.supportList.find(val => val.key === this.currentExtension))) { this.currentExtension = key || ''; } - }; + } uploadChange(data) { this.uploadData = data; } @@ -116,6 +116,7 @@ export class ImportApiComponent implements OnInit { const [data, err] = module[action](content); console.log('import data', window.structuredClone?.(data)); if (err) { + this.eoMessage.error(err.msg); console.error(err.msg); callback(false); return; diff --git a/src/browser/src/app/components/extension-select/push-api/push-api.component.ts b/src/browser/src/app/components/extension-select/push-api/push-api.component.ts index efd635995..5d8297e37 100644 --- a/src/browser/src/app/components/extension-select/push-api/push-api.component.ts +++ b/src/browser/src/app/components/extension-select/push-api/push-api.component.ts @@ -4,6 +4,8 @@ import { has } from 'lodash-es'; import { ExtensionService } from 'pc/browser/src/app/services/extensions/extension.service'; import { Message, MessageService } from 'pc/browser/src/app/services/message'; import { ApiService } from 'pc/browser/src/app/services/storage/api.service'; +import { PUSH_API } from 'pc/browser/src/app/shared/constans/featureName'; +import { ExtensionChange } from 'pc/browser/src/app/shared/decorators'; import { FeatureInfo } from 'pc/browser/src/app/shared/models/extension-manager'; import { Subject, takeUntil } from 'rxjs'; @@ -31,14 +33,12 @@ export class PushApiComponent implements OnInit { this.messageService .get() .pipe(takeUntil(this.destroy$)) - .subscribe((inArg: Message) => { - if (inArg.type === 'extensionsChange') { - this.initData(); - } - }); + .subscribe((inArg: Message) => {}); } - initData = () => { - this.featureMap = this.extensionService.getValidExtensionsByFature('pushAPI'); + + @ExtensionChange(PUSH_API, true) + initData() { + this.featureMap = this.extensionService.getValidExtensionsByFature(PUSH_API); this.supportList = []; this.featureMap?.forEach((data: FeatureInfo, key: string) => { this.supportList.push({ @@ -46,11 +46,16 @@ export class PushApiComponent implements OnInit { ...data }); }); - { - const { key } = this.supportList?.at(0); + // { + // const { key } = this.supportList?.at(0); + // this.currentExtension = key || ''; + // } + if (!this.supportList.length) return; + const { key } = this.supportList.at(0); + if (!(this.currentExtension && this.supportList.find(val => val.key === this.currentExtension))) { this.currentExtension = key || ''; } - }; + } async submit(callback) { const feature = this.featureMap.get(this.currentExtension); if (!feature) { diff --git a/src/browser/src/app/components/extension-select/select/extension-select.component.ts b/src/browser/src/app/components/extension-select/select/extension-select.component.ts index 6ddd4e774..bee041cef 100644 --- a/src/browser/src/app/components/extension-select/select/extension-select.component.ts +++ b/src/browser/src/app/components/extension-select/select/extension-select.component.ts @@ -48,10 +48,14 @@ export class ExtensionSelectComponent { observer.complete(); return; } - parserJsonFile(file).then((result: { name: string }) => { - this.filename = result.name; - this.uploadChange.emit(result); - observer.complete(); - }); + parserJsonFile(file) + .then((result: { name: string }) => { + this.filename = result.name; + this.uploadChange.emit(result); + observer.complete(); + }) + .catch(err => { + this.message.error(err); + }); }); } diff --git a/src/browser/src/app/components/extension-select/sync-api/sync-api.component.ts b/src/browser/src/app/components/extension-select/sync-api/sync-api.component.ts index aba60863e..eec4be043 100644 --- a/src/browser/src/app/components/extension-select/sync-api/sync-api.component.ts +++ b/src/browser/src/app/components/extension-select/sync-api/sync-api.component.ts @@ -6,6 +6,8 @@ import { Message, MessageService } from 'pc/browser/src/app/services/message'; import { ApiService } from 'pc/browser/src/app/services/storage/api.service'; import { TraceService } from 'pc/browser/src/app/services/trace.service'; import { EoSchemaFormComponent } from 'pc/browser/src/app/shared/components/schema-form/schema-form.component'; +import { PULL_API } from 'pc/browser/src/app/shared/constans/featureName'; +import { ExtensionChange } from 'pc/browser/src/app/shared/decorators'; import { FeatureInfo } from 'pc/browser/src/app/shared/models/extension-manager'; import { EffectService } from 'pc/browser/src/app/store/effect.service'; import { StoreService } from 'pc/browser/src/app/store/state.service'; @@ -52,21 +54,7 @@ export class SyncApiComponent implements OnInit, OnChanges { ngOnInit(): void { this.getSyncSettingList(); this.initData(); - this.messageService - .get() - .pipe(takeUntil(this.destroy$)) - .subscribe((inArg: Message) => { - if (inArg.type === 'extensionsChange') { - this.initData(() => { - if (this.supportList?.length) { - const { key } = this.supportList.at(0); - this.model.__formater = key || ''; - } else { - this.model.__formater = ''; - } - }); - } - }); + this.watchInstalledExtensionsChange(); } ngOnChanges(changes: SimpleChanges) { @@ -76,6 +64,18 @@ export class SyncApiComponent implements OnInit, OnChanges { } } + @ExtensionChange(PULL_API) + watchInstalledExtensionsChange() { + this.initData(() => { + if (this.supportList?.length) { + const { key } = this.supportList.at(0); + this.model.__formater = key || ''; + } else { + this.model.__formater = ''; + } + }); + } + handleValueChanges(val) { if (val.__formater !== this.currentFormater?.pluginId) { this.model.__formater = val.__formater; @@ -104,7 +104,7 @@ export class SyncApiComponent implements OnInit, OnChanges { } initData = debounce((afterInitCallback?) => { - this.featureMap = this.extensionService.getValidExtensionsByFature('pullAPI'); + this.featureMap = this.extensionService.getValidExtensionsByFature(PULL_API); this.supportList = []; this.featureMap?.forEach((data: FeatureInfo, key: string) => { this.supportList.push({ diff --git a/src/browser/src/app/components/nps-mask/component/nps-mask.component.ts b/src/browser/src/app/components/nps-mask/component/nps-mask.component.ts index 0c711e19a..61a3c7d97 100644 --- a/src/browser/src/app/components/nps-mask/component/nps-mask.component.ts +++ b/src/browser/src/app/components/nps-mask/component/nps-mask.component.ts @@ -1,8 +1,8 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { NpsPositionDirective } from 'pc/browser/src/app/components/nps-mask/nps-mask-postion.directive'; import { APP_CONFIG } from 'pc/browser/src/environments/environment'; import { StoreService } from '../../../store/state.service'; -import { NpsPositionDirective } from '../nps-mask-postion.directive'; @Component({ selector: 'pc-nps-mask', @@ -10,8 +10,8 @@ import { NpsPositionDirective } from '../nps-mask-postion.directive';
`, - styleUrls: ['./nps-mask.component.scss'] - // hostDirectives: [NpsPositionDirective] + styleUrls: ['./nps-mask.component.scss'], + hostDirectives: [NpsPositionDirective] }) export class NpsMaskComponent implements OnInit { /** diff --git a/src/browser/src/app/components/nps-mask/nps-mask-postion.directive.ts b/src/browser/src/app/components/nps-mask/nps-mask-postion.directive.ts index 8f5216a7f..99cf8586e 100644 --- a/src/browser/src/app/components/nps-mask/nps-mask-postion.directive.ts +++ b/src/browser/src/app/components/nps-mask/nps-mask-postion.directive.ts @@ -32,7 +32,7 @@ export class NpsPositionDirective { width: `${rect.width - this.padding}px` }); } - resettipsPostion(rect) { + resetTipsPostion(rect) { const tipsDom = this.el.nativeElement.querySelector('.tips'); this.batchSetPropery(tipsDom, { right: `${24}px`, @@ -43,7 +43,7 @@ export class NpsPositionDirective { resetMaskPostion(dom: HTMLIFrameElement) { const rect = dom.getBoundingClientRect(); this.resetTitlePostion(rect); - this.resettipsPostion(rect); + this.resetTipsPostion(rect); } showMask(iframe: HTMLIFrameElement) { this.showTitle = true; @@ -66,8 +66,8 @@ export class NpsPositionDirective { const callback = (mutationList, observer) => { for (const mutation of mutationList) { if (mutation.type !== 'childList' || !mutation.addedNodes.length) return; - const npsDom = mutation.addedNodes[0]; - if (!npsDom.id.includes('howxmSDK')) return; + const npsDom = mutation.previousSibling || mutation.addedNodes[0]; + if (!npsDom?.id?.includes('howxmSDK')) return; //* Reset status after update body,such as refresh page this.hideMask(); @@ -82,11 +82,10 @@ export class NpsPositionDirective { const npsSlideIn = className.includes('widget_SlideInRightBottom'); const hasSubmit = className.includes('modal-widget_widgetTransition') && e[0].attributeName === 'style'; const hasClose = className.includes('modal-widget_backdropBase') && !className.includes('modal-widget_backdropIn'); - // console.log(step, className, npsSlideIn, hasSubmit, hasClose); + console.log(step, className, npsSlideIn, hasSubmit, hasClose); //* 1. Show mask if (iframe && npsSlideIn && step < 1) { step = 1; - // console.log('showMask'); setTimeout(() => { this.showMask(iframe as HTMLIFrameElement); }, 150); diff --git a/src/browser/src/app/core/services/feature-control/feature-control.service.ts b/src/browser/src/app/core/services/feature-control/feature-control.service.ts index aea4c397b..f9a283b0c 100644 --- a/src/browser/src/app/core/services/feature-control/feature-control.service.ts +++ b/src/browser/src/app/core/services/feature-control/feature-control.service.ts @@ -1,5 +1,7 @@ import { Injectable } from '@angular/core'; import { Message, MessageService } from 'pc/browser/src/app/services/message'; +import { FEATURE_CONTROL } from 'pc/browser/src/app/shared/constans/featureName'; +import { ExtensionChange, ExtensionMessage } from 'pc/browser/src/app/shared/decorators'; import featureJSON from './feature.json'; type configKey = keyof typeof featureJSON; @@ -14,28 +16,26 @@ export class FeatureControlService { init() { this.watchExtensionChange(); } - watchExtensionChange() { - this.message.get().subscribe((inArg: Message) => { - if (inArg.type !== 'extensionsChange') return; - const extension = inArg.data.extension; - if (!extension?.features?.featureControl?.length) return; - let aciton = inArg.data.action; - if (inArg.data.action === 'init') { - aciton = extension.enable ? 'enable' : 'disable'; + @ExtensionChange(FEATURE_CONTROL) + watchExtensionChange(inArg?: ExtensionMessage) { + const extension = inArg.data.extension; + let aciton = inArg.data.action; + if (inArg.data.action === 'init') { + aciton = extension.enable ? 'enable' : 'disable'; + } + switch (aciton) { + case 'install': + case 'enable': { + this.openFearure(extension?.features?.featureControl); + break; } - switch (aciton) { - case 'install': - case 'enable': { - this.openFearure(extension?.features?.featureControl); - break; - } - case 'disable': - case 'uninstall': { - this.closeFeature(extension?.features?.featureControl); - break; - } + case 'disable': + case 'uninstall': { + this.closeFeature(extension?.features?.featureControl); + break; } - }); + } + // }); } openFearure(features) { features.forEach(({ id }) => { diff --git a/src/browser/src/app/core/services/theme/theme.service.ts b/src/browser/src/app/core/services/theme/theme.service.ts index f19520caa..fa09aea5f 100644 --- a/src/browser/src/app/core/services/theme/theme.service.ts +++ b/src/browser/src/app/core/services/theme/theme.service.ts @@ -1,6 +1,8 @@ import { DOCUMENT } from '@angular/common'; import { Inject, Injectable } from '@angular/core'; import { kebabCase } from 'lodash-es'; +import { THEME } from 'pc/browser/src/app/shared/constans/featureName'; +import { ExtensionChange, ExtensionMessage } from 'pc/browser/src/app/shared/decorators'; import { SettingService } from '../../../components/system-setting/settings.service'; import { Message, MessageService } from '../../../services/message'; @@ -193,33 +195,31 @@ export class ThemeService { this.changeTheme(currentTheme); } } - watchInstalledExtensionsChange() { - this.message.get().subscribe((inArg: Message) => { - if (inArg.type !== 'extensionsChange') return; - //Rest newest theme list - this.themes = this.themes.filter(val => !val.isExtension); - this.queryExtensionThemes(); - this.afterAllThemeLoad(); + @ExtensionChange(THEME) + watchInstalledExtensionsChange(inArg?: ExtensionMessage) { + if (!inArg) return; + //Rest newest theme list + this.themes = this.themes.filter(val => !val.isExtension); + this.queryExtensionThemes(); + this.afterAllThemeLoad(); - switch (inArg.data.action) { - case 'enable': - case 'install': { - const name = inArg.data.name; - const extension: ExtensionInfo = inArg.data.installedMap.get(name); - if (!extension?.features?.theme?.length) break; + switch (inArg.data.action) { + case 'enable': + case 'install': { + const name = inArg.data.name; + const extension: ExtensionInfo = inArg.data.installedMap.get(name); - //Change theme after install/enable extension - const themeID = extension.features.theme[0].id; - const id = this.themeExtension.getExtensionID(name, themeID); - const theme = this.themes.find(val => val.id === id); - if (!theme) return; - this.changeTheme(theme); - break; - } - default: { - break; - } + //Change theme after install/enable extension + const themeID = extension.features.theme[0].id; + const id = this.themeExtension.getExtensionID(name, themeID); + const theme = this.themes.find(val => val.id === id); + if (!theme) return; + this.changeTheme(theme); + break; } - }); + default: { + break; + } + } } } diff --git a/src/browser/src/app/layouts/sidebar/sidebar.component.ts b/src/browser/src/app/layouts/sidebar/sidebar.component.ts index d7c5b2d13..40396b179 100644 --- a/src/browser/src/app/layouts/sidebar/sidebar.component.ts +++ b/src/browser/src/app/layouts/sidebar/sidebar.component.ts @@ -3,6 +3,8 @@ import { NavigationEnd, Router } from '@angular/router'; import { autorun } from 'mobx'; import { ExtensionService } from 'pc/browser/src/app/services/extensions/extension.service'; import { Message, MessageService } from 'pc/browser/src/app/services/message'; +import { SIDEBAR_VIEW } from 'pc/browser/src/app/shared/constans/featureName'; +import { ExtensionChange, ExtensionMessage } from 'pc/browser/src/app/shared/decorators'; import { ExtensionInfo } from 'pc/browser/src/app/shared/models/extension-manager'; import { StoreService } from 'pc/browser/src/app/store/state.service'; import { Subscription } from 'rxjs'; @@ -68,20 +70,17 @@ export class SidebarComponent implements OnInit, OnDestroy { sidebarViews?.length && this.getIDFromRoute(); } - watchInstalledExtensionsChange() { - this.messageService.get().subscribe((inArg: Message) => { - if (inArg.type === 'extensionsChange') { - if (!this.sidebar.visible) return; - const installedMap = inArg.data.installedMap; - const extensionIDs = Array.isArray(installedMap) ? installedMap.map(n => n.name) : [...installedMap.keys()]; - this.modules = this.modules.filter(n => n.isOffical || extensionIDs.includes(n.id)); - this.initSidebarViews(); - if (!this.modules.some(val => this.router.url.includes(val.activeRoute))) { - pcConsole.warn('sidebar activeRoute not found, redirect to home'); - this.router.navigate(['/home/workspace/project/api']); - } - } - }); + @ExtensionChange(SIDEBAR_VIEW) + watchInstalledExtensionsChange(inArg?: ExtensionMessage) { + if (!this.sidebar.visible) return; + const installedMap = inArg.data.installedMap; + const extensionIDs = Array.isArray(installedMap) ? installedMap.map(n => n.name) : [...installedMap.keys()]; + this.modules = this.modules.filter(n => n.isOffical || extensionIDs.includes(n.id)); + this.initSidebarViews(); + if (!this.modules.some(val => this.router.url.includes(val.activeRoute))) { + pcConsole.warn('sidebar activeRoute not found, redirect to home'); + this.router.navigate(['/home/workspace/project/api']); + } } watchRouterChange() { diff --git a/src/browser/src/app/pages/components/chatgpt-robot/chatgpt-robot.component.ts b/src/browser/src/app/pages/components/chatgpt-robot/chatgpt-robot.component.ts index 319fbbdf5..62e642451 100644 --- a/src/browser/src/app/pages/components/chatgpt-robot/chatgpt-robot.component.ts +++ b/src/browser/src/app/pages/components/chatgpt-robot/chatgpt-robot.component.ts @@ -3,9 +3,12 @@ import { CommonModule } from '@angular/common'; import { HttpClient } from '@angular/common/http'; import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { EoNgButtonModule } from 'eo-ng-button'; +import GPT3Tokenizer from 'gpt3-tokenizer'; import { FeatureControlService } from 'pc/browser/src/app/core/services/feature-control/feature-control.service'; import { Message, MessageService } from 'pc/browser/src/app/services/message'; import { TraceService } from 'pc/browser/src/app/services/trace.service'; +import { FEATURE_CONTROL } from 'pc/browser/src/app/shared/constans/featureName'; +import { ExtensionChange, ExtensionMessage } from 'pc/browser/src/app/shared/decorators'; import { ExtensionInfo } from 'pc/browser/src/app/shared/models/extension-manager'; import StorageUtil from 'pc/browser/src/app/shared/utils/storage/storage.utils'; import { StoreService } from 'pc/browser/src/app/store/state.service'; @@ -81,13 +84,15 @@ export class ChatgptRobotComponent implements OnInit { title = $localize`ChatGPT Robot`; loading = false; MAX_LIMIT = 5; + MAX_TOKEN_LENTH_LIMIT = 4000; + appName = 'Postcat'; nowUsage = StorageUtil.get('cr_usage'); initMessage = { date: new Date(), reply: true, type: 'init', user: { - name: 'Postcat', + name: this.appName, avatar: './assets/images/logo.svg' } }; @@ -118,24 +123,63 @@ export class ChatgptRobotComponent implements OnInit { StorageUtil.set('cr_usage', this.nowUsage); }, 5000); } + private getTextLenth(text: string) { + const tokenizer = new GPT3Tokenizer({ type: 'gpt3' }); // or 'codex' + const encoded: { bpe: number[]; text: string[] } = tokenizer.encode(text); + return encoded.text ? encoded.text.length : text.length; + } + private getMessageLength(message: messageItem[]) { + const text = message.map(val => val.text).join(); + return this.getTextLenth(text); + } + private transferMessage2Body(message: messageItem[]): string[] { + return message.map(val => { + if (val.reply) { + return `assistant: ${val.text}`; + } + return `user: ${val.text}`; + }); + } + /** + * Get message object for send API + * + * @param messageNumber number of send/recieve message, 15 messages are kept by default + * @returns + */ + private getMessage(messageNumber = 15): messageItem[] { + if (messageNumber <= 0) return []; + + //Get message by messageNumber,filter out the error message/official message + const result = this.messages + .filter(val => !val.reply || (val.reply && (!val.text.includes('ChatGPT Error:') || val.user?.name === this.appName))) + .slice(-messageNumber); + + //If last question is too long, we need to split it + if (this.getTextLenth(result.at(-1).text) >= this.MAX_TOKEN_LENTH_LIMIT) { + return [{ ...result.at(-1), text: result.at(-1).text.slice(0, this.MAX_TOKEN_LENTH_LIMIT) }]; + } + + //If all messages(ctx) are too long, we need to split it + if (this.getMessageLength(result) >= this.MAX_TOKEN_LENTH_LIMIT) { + const len = Math.floor(messageNumber / 2); + return this.getMessage(len); + } + return result; + } sendChatGPTMessage($event) { this.loading = true; this.trace.report('send_chatGPT'); this.http .post(`${APP_CONFIG.EXTENSION_URL}/chatGPT`, { - message: this.messages.map(val => { - if (val.reply) { - return `assistant: ${val.text}`; - } - return `user: ${val.text}`; - }) + message: this.transferMessage2Body(this.getMessage()) }) .subscribe({ next: (res: any) => { this.loading = false; if (!res?.result) { + const error = res?.error || res?.msg || 'unknown error'; this.messages.push({ - text: `ChatGPT Error: ${res?.error || res?.msg || 'unknown error'}`, + text: `ChatGPT Error: ${error}`, date: new Date(), reply: true, type: 'text', @@ -192,7 +236,7 @@ export class ChatgptRobotComponent implements OnInit { reply: true, type: 'text', user: { - name: 'Postcat', + name: this.appName, avatar: './assets/images/logo.svg' } }); @@ -200,18 +244,15 @@ export class ChatgptRobotComponent implements OnInit { } this.sendChatGPTMessage($event); } - watchExtensionChange() { - this.message.get().subscribe((inArg: Message) => { - if (inArg.type !== 'extensionsChange') return; - const extension: ExtensionInfo = inArg.data.extension; - if (!extension?.features?.featureControl?.length) return; - switch (inArg.data.action) { - case 'install': - case 'enable': { - this.chat.open(); - break; - } + @ExtensionChange(FEATURE_CONTROL) + watchExtensionChange(inArg?: ExtensionMessage) { + switch (inArg.data.action) { + case 'install': + case 'enable': { + this.chat.open(); + break; } - }); + } + // }); } } diff --git a/src/browser/src/app/pages/workspace/overview/edit/workspace-edit.component.ts b/src/browser/src/app/pages/workspace/overview/edit/workspace-edit.component.ts index e99cf00ca..e7d5c2af1 100644 --- a/src/browser/src/app/pages/workspace/overview/edit/workspace-edit.component.ts +++ b/src/browser/src/app/pages/workspace/overview/edit/workspace-edit.component.ts @@ -122,7 +122,7 @@ export class WorkspaceSettingComponent { this.message.error($localize`Delete failed !`); return; } - this.message.success($localize`Delete success !`); + this.message.success($localize`Delete Succeeded`); await this.effect.updateWorkspaceList(); await this.effect.switchWorkspace(this.store.getLocalWorkspace.workSpaceUuid); } diff --git a/src/browser/src/app/pages/workspace/project/api/api.component.ts b/src/browser/src/app/pages/workspace/project/api/api.component.ts index d9b128c6e..08c3c2347 100644 --- a/src/browser/src/app/pages/workspace/project/api/api.component.ts +++ b/src/browser/src/app/pages/workspace/project/api/api.component.ts @@ -6,6 +6,8 @@ import { WebService } from 'pc/browser/src/app/core/services'; import { ExtensionService } from 'pc/browser/src/app/services/extensions/extension.service'; import { ApiData } from 'pc/browser/src/app/services/storage/index.model'; import { TraceService } from 'pc/browser/src/app/services/trace.service'; +import { API_PREVIEW_TAB } from 'pc/browser/src/app/shared/constans/featureName'; +import { ExtensionChange } from 'pc/browser/src/app/shared/decorators'; import { StoreService } from 'pc/browser/src/app/store/state.service'; import { filter, Subject, takeUntil } from 'rxjs'; @@ -94,22 +96,12 @@ export class ApiComponent implements OnInit, OnDestroy { private trace: TraceService ) { this.initExtensionExtra(); - this.watchInstalledExtensionsChange(); - } - watchInstalledExtensionsChange() { - this.messageService.get().subscribe((inArg: Message) => { - if (inArg.type === 'extensionsChange') { - const name = inArg.data.name; - const extension: ExtensionInfo = inArg.data.installedMap.get(name); - if (!extension?.features?.apiPreviewTab) return; - this.initExtensionExtra(); - } - }); } + @ExtensionChange(API_PREVIEW_TAB, true) async initExtensionExtra() { this.rightExtras = []; if (!this.router.url.includes('home/workspace/project/api/http/detail')) return; - const apiPreviewTab = this.extensionService.getValidExtensionsByFature('apiPreviewTab'); + const apiPreviewTab = this.extensionService.getValidExtensionsByFature(API_PREVIEW_TAB); apiPreviewTab?.forEach(async (value, key) => { const module = await this.extensionService.getExtensionPackage(key); const rightExtra = value.rightExtra?.reduce((prev, curr) => { diff --git a/src/browser/src/app/pages/workspace/project/api/components/api-test-form/api-test-form.component.ts b/src/browser/src/app/pages/workspace/project/api/components/api-test-form/api-test-form.component.ts index 79137f04e..2c729512f 100644 --- a/src/browser/src/app/pages/workspace/project/api/components/api-test-form/api-test-form.component.ts +++ b/src/browser/src/app/pages/workspace/project/api/components/api-test-form/api-test-form.component.ts @@ -9,7 +9,12 @@ import { ApiTableService } from '../../service/api-table.service'; selector: 'pc-api-test-form', template: `
- +
@@ -55,6 +60,9 @@ export class ApiTestFormComponent implements OnInit, OnDestroy { this.destroy$.next(); this.destroy$.complete(); } + changeFn($event) { + this.modelChange.emit($event); + } private initListConf() { const config = this.apiTable.initTestTable({ in: this.module, diff --git a/src/browser/src/app/pages/workspace/project/api/components/authorization-extension-form/authorization-extension-form.component.ts b/src/browser/src/app/pages/workspace/project/api/components/authorization-extension-form/authorization-extension-form.component.ts index 966c9ea5e..3f14e902a 100644 --- a/src/browser/src/app/pages/workspace/project/api/components/authorization-extension-form/authorization-extension-form.component.ts +++ b/src/browser/src/app/pages/workspace/project/api/components/authorization-extension-form/authorization-extension-form.component.ts @@ -7,6 +7,8 @@ import { ExtensionService } from 'pc/browser/src/app/services/extensions/extensi import { Message, MessageService } from 'pc/browser/src/app/services/message'; import { Group } from 'pc/browser/src/app/services/storage/db/models'; import { EoSchemaFormComponent } from 'pc/browser/src/app/shared/components/schema-form/schema-form.component'; +import { AUTH_API } from 'pc/browser/src/app/shared/constans/featureName'; +import { ExtensionChange } from 'pc/browser/src/app/shared/decorators'; import { FeatureInfo } from 'pc/browser/src/app/shared/models/extension-manager'; import { PCTree } from 'pc/browser/src/app/shared/utils/tree/tree.utils'; import { Subject, takeUntil } from 'rxjs'; @@ -127,17 +129,13 @@ export class AuthorizationExtensionFormComponent implements OnChanges { makeObservable(this); this.initExtensions(); this.initAutorun(); + this.watchInstalledExtensionsChange(); + } - this.messageService - .get() - .pipe(takeUntil(this.destroy$)) - .subscribe((inArg: Message) => { - if (inArg.type !== 'extensionsChange') return; - const extension = inArg.data.extension; - if (!extension?.features?.authAPI) return; - this.initExtensions(); - this.updateSchema(this.authType); - }); + @ExtensionChange(AUTH_API) + watchInstalledExtensionsChange() { + this.initExtensions(); + this.updateSchema(this.authType); } init() { diff --git a/src/browser/src/app/pages/workspace/project/api/components/group/tree/api-group-tree.component.ts b/src/browser/src/app/pages/workspace/project/api/components/group/tree/api-group-tree.component.ts index c2a76e48f..561a3d66a 100644 --- a/src/browser/src/app/pages/workspace/project/api/components/group/tree/api-group-tree.component.ts +++ b/src/browser/src/app/pages/workspace/project/api/components/group/tree/api-group-tree.component.ts @@ -38,7 +38,7 @@ export class ApiGroupTreeComponent implements OnInit { /** * Expanded keys of tree. */ - expandKeys: string[] = []; + expandKeys: Array = []; requestMethodMap = requestMethodMap; nzSelectedKeys = []; searchValue = ''; @@ -118,7 +118,7 @@ export class ApiGroupTreeComponent implements OnInit { this.isLoading = false; }); autorun(() => { - this.expandKeys = this.getExpandKeys(); + this.expandKeys = [...this.getExpandKeys(), ...this.store.getExpandList].map(Number); this.apiGroupTree = this.store.getApiGroupTree; waitNextTick().then(() => { this.initSelectKeys(); @@ -191,6 +191,8 @@ export class ApiGroupTreeComponent implements OnInit { } addAPI(group?) { const prefix = this.globalStore.isShare ? 'share' : '/home/workspace/project/api'; + // console.log(group?.key); + // this.expandKeys = [...this.expandKeys, group.key]; this.router.navigate([`${prefix}/http/edit`], { queryParams: { groupId: group?.key, pageID: Date.now() } }); @@ -222,6 +224,7 @@ export class ApiGroupTreeComponent implements OnInit { if (node?.group) { node.group.isExpanded = true; } + this.message.success('Add Group successfully'); } importAPI(type: keyof typeof actionComponent, title) { const modal = this.modalService.create({ diff --git a/src/browser/src/app/pages/workspace/project/api/components/history/eo-history.component.html b/src/browser/src/app/pages/workspace/project/api/components/history/eo-history.component.html index 8047ee234..43b7f7ecb 100644 --- a/src/browser/src/app/pages/workspace/project/api/components/history/eo-history.component.html +++ b/src/browser/src/app/pages/workspace/project/api/components/history/eo-history.component.html @@ -7,7 +7,6 @@ nzType="text" [disabled]="!getTestHistory.length" i18n-nzTooltipTitle - nzTooltipTitle="Clear All" eoNgFeedbackTooltip nz-popconfirm i18n-nzPopconfirmTitle diff --git a/src/browser/src/app/pages/workspace/project/api/components/params-import/params-import.component.ts b/src/browser/src/app/pages/workspace/project/api/components/params-import/params-import.component.ts index d010e92af..e88b723f7 100644 --- a/src/browser/src/app/pages/workspace/project/api/components/params-import/params-import.component.ts +++ b/src/browser/src/app/pages/workspace/project/api/components/params-import/params-import.component.ts @@ -81,7 +81,6 @@ export class ParamsImportComponent implements OnInit { } catch (error) {} } else if (['formData', 'header'].includes(this.contentType)) { const arr = form2json(clipText); - console.log(arr); if (Array.isArray(arr) && arr.length && clipText.split(':').length > 1) { this.paramCode = clipText; } diff --git a/src/browser/src/app/pages/workspace/project/api/env/env-select/env-select.component.scss b/src/browser/src/app/pages/workspace/project/api/env/env-select/env-select.component.scss index d1d082955..0381866d1 100644 --- a/src/browser/src/app/pages/workspace/project/api/env/env-select/env-select.component.scss +++ b/src/browser/src/app/pages/workspace/project/api/env/env-select/env-select.component.scss @@ -2,6 +2,28 @@ --select-background-color: var(--background-color); border-bottom: 1px solid var(--border-color); + + ::ng-deep .ant-select .clear-btn:hover eo-iconpark-icon { + background-color: var(--item-active-background-color); + } + + ::ng-deep .ant-select .clear-btn:hover eo-iconpark-icon svg { + color: var(--icon-color) !important; + } + + .clear-btn eo-iconpark-icon { + padding: 3px; + vertical-align: middle; + border-radius: 50%; + transform: translateY(-25%); + } +} + +// TODO: Modify component style + +.ant-tabs-tab-remove { + padding: 0; + margin: 0; } nz-divider { @@ -9,26 +31,22 @@ nz-divider { } :host ::ng-deep { - .env-select-componnet { - .ant-select-clear { - border: 1px solid var(--system-border-color); - border-radius: 50%; - width: 18px; - height: 18px; - display: flex; - align-items: center; - justify-content: center; - margin-top: -8px; - } - } - eo-ng-select eo-ng-select-top-control { border: none !important; } + .ant-select:not(.ant-select-customize-input) .ant-select-selector { + background-color: unset !important; + border: unset !important; + } + .ant-select { width: 140px; } + + .ant-select-selector { + box-shadow: unset !important; + } } .content { diff --git a/src/browser/src/app/pages/workspace/project/api/env/env-select/env-select.component.ts b/src/browser/src/app/pages/workspace/project/api/env/env-select/env-select.component.ts index 6ffd77ee1..eb01e94dd 100644 --- a/src/browser/src/app/pages/workspace/project/api/env/env-select/env-select.component.ts +++ b/src/browser/src/app/pages/workspace/project/api/env/env-select/env-select.component.ts @@ -64,7 +64,7 @@ import { ApiStoreService } from '../../store/api-state.service'; - - + Manage Environment + +
+ +
+
`, styleUrls: ['./env-select.component.scss'] diff --git a/src/browser/src/app/pages/workspace/project/api/http/edit/api-edit-util.service.ts b/src/browser/src/app/pages/workspace/project/api/http/edit/api-edit-util.service.ts index 93b813de1..e64b4da7d 100644 --- a/src/browser/src/app/pages/workspace/project/api/http/edit/api-edit-util.service.ts +++ b/src/browser/src/app/pages/workspace/project/api/http/edit/api-edit-util.service.ts @@ -34,6 +34,7 @@ export class ApiEditUtilService { filterFn: item => { item.partType = mui[tableName]; item.paramType = 0; + delete item['paramAttr.example']; return filterArrFun(item); } }); @@ -46,9 +47,11 @@ export class ApiEditUtilService { ['bodyParams', 'headerParams'].forEach(tableName => { if (tableName === 'bodyParams' && [ApiBodyType.Binary, ApiBodyType.Raw].includes(result.responseList[0].contentType)) { if (result.responseList[0].bodyParams?.[0]) { - result.responseList[0].bodyParams[0].orderNo = 0; - result.responseList[0].bodyParams[0].paramType = 1; - result.responseList[0].bodyParams[0].partType = mui['bodyParams']; + const item = result.responseList[0].bodyParams[0]; + item.orderNo = 0; + item.paramType = 1; + item.partType = mui['bodyParams']; + delete item['paramAttr.example']; } return; } diff --git a/src/browser/src/app/pages/workspace/project/api/http/edit/api-edit.component.ts b/src/browser/src/app/pages/workspace/project/api/http/edit/api-edit.component.ts index 97a07c76e..3b3e89616 100644 --- a/src/browser/src/app/pages/workspace/project/api/http/edit/api-edit.component.ts +++ b/src/browser/src/app/pages/workspace/project/api/http/edit/api-edit.component.ts @@ -170,6 +170,10 @@ export class ApiEditComponent implements OnDestroy, TabViewComponent { } // Add success this.message.success(title); + + if (this.route.snapshot.queryParams.groupId) { + this.store.addApiSuccess(this.route.snapshot.queryParams.groupId); + } busEvent === 'addApi' && this.trace.report('add_api_document_success', { trigger_way: ux, diff --git a/src/browser/src/app/pages/workspace/project/api/http/edit/form/api-edit-form.component.ts b/src/browser/src/app/pages/workspace/project/api/http/edit/form/api-edit-form.component.ts index aa5b29bc7..72efc1ea8 100644 --- a/src/browser/src/app/pages/workspace/project/api/http/edit/form/api-edit-form.component.ts +++ b/src/browser/src/app/pages/workspace/project/api/http/edit/form/api-edit-form.component.ts @@ -42,7 +42,7 @@ export class ApiEditFormComponent implements OnInit { this.initListConf(); } changeFn($event) { - this.modelChange.emit(this.model); + this.modelChange.emit($event); } private initListConf() { const config = this.apiTable.initTable( diff --git a/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.html b/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.html index 2a3d709ec..971d2a119 100644 --- a/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.html +++ b/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.html @@ -87,10 +87,9 @@ > -
- + +
+ + +
+ +
diff --git a/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.scss b/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.scss index 56fc57115..3036e3a1c 100644 --- a/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.scss +++ b/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.scss @@ -90,10 +90,6 @@ div.ant-typography { .response_container { @apply h-full overflow-hidden; - - .ant-tabs-tabpane { - min-height: 208px; - } } .top_container { diff --git a/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.ts b/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.ts index 578d913f6..eed6cf8de 100644 --- a/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.ts +++ b/src/browser/src/app/pages/workspace/project/api/http/test/api-test.component.ts @@ -62,7 +62,7 @@ const contentTypeMap = { interface testViewModel { testStartTime?: number; - contentType: ContentType; + monacoContentType: ContentType; autoSetContentType: boolean; requestTabIndex: number; responseTabIndex: number; @@ -110,7 +110,6 @@ export class ApiTestComponent implements OnInit, AfterViewInit, OnDestroy, TabVi REQUEST_METHOD = enumsToArr(RequestMethod); MAX_TEST_SECONDS = 60; isEmpty = isEmpty; - $$contentType: ContentType = contentTypeMap[0]; get uuid() { return this.route.snapshot.queryParams.uuid; @@ -126,12 +125,6 @@ export class ApiTestComponent implements OnInit, AfterViewInit, OnDestroy, TabVi const { uuid } = this.route.snapshot.queryParams; return uuid?.includes?.('history_') ? 'api-test-history' : 'api-test'; } - get contentType(): ContentType { - return contentTypeMap[this.model.request.apiAttrInfo.contentType]; - } - set contentType(value) { - this.$$contentType = value; - } private initTimes = 0; private status$: Subject = new Subject(); @@ -233,7 +226,7 @@ export class ApiTestComponent implements OnInit, AfterViewInit, OnDestroy, TabVi } else { return; } - this.initContentType(); + this.setMonacoContentType(); this.waitSeconds = 0; this.status = 'start'; } else { @@ -253,6 +246,7 @@ export class ApiTestComponent implements OnInit, AfterViewInit, OnDestroy, TabVi if (!this.initialModel) { this.initialModel = eoDeepCopy(this.model); } + this.eoOnInit.emit(this.model); this.cdRef.detectChanges(); } @@ -319,7 +313,7 @@ export class ApiTestComponent implements OnInit, AfterViewInit, OnDestroy, TabVi isFormChange(): boolean { //Has exist api can't save //TODO If has test case,test data will be saved to test case - if (this.model.request.apiUuid) { + if (!this.isEmptyTestPage) { return false; } if (!this.initialModel?.request || !this.model.request) { @@ -340,14 +334,49 @@ export class ApiTestComponent implements OnInit, AfterViewInit, OnDestroy, TabVi return false; } - changeContentType(contentType) { - this.model.request.requestParams.headerParams = this.apiTestUtil.addOrReplaceContentType( - contentType, - this.model.request.requestParams.headerParams - ); + /** + * Return contentType header value by bodyType and monacoContentType + * + * @param bodyType + * @returns + */ + getContentTypeByBodyType(bodyType: ApiBodyType = this.model.request?.apiAttrInfo?.contentType): ContentType | string { + switch (bodyType) { + case ApiBodyType.Raw: { + return this.model?.monacoContentType; + } + case ApiBodyType.FormData: { + return 'multiple/form-data'; + } + case ApiBodyType.Binary: { + return ''; + } + } + } + setHeaderContentType() { + const bodyType = this.model.request?.apiAttrInfo?.contentType; + + if (bodyType !== ApiBodyType.Binary) { + const contentType = this.getContentTypeByBodyType(); + this.model.request.requestParams.headerParams = this.apiTestUtil.addOrReplaceContentType( + contentType, + this.model.request.requestParams.headerParams + ); + return; + } + + //Binary unset request header + const headerIndex = this.model.request.requestParams.headerParams.findIndex(val => val.name.toLowerCase() === 'content-type'); + if (headerIndex === -1) return; + this.model.request.requestParams.headerParams.splice(headerIndex, 1); + + //Angular change value by onPush + this.model.request.requestParams.headerParams = [...this.model.request.requestParams.headerParams]; } changeBodyType($event) { - this.initContentType(); + StorageUtil.set('api_test_body_type', $event); + this.setMonacoContentType(); + this.setHeaderContentType(); } handleBottomTabSelect(tab) { if (tab.index === 2) { @@ -500,11 +529,10 @@ export class ApiTestComponent implements OnInit, AfterViewInit, OnDestroy, TabVi } } } - private initContentType() { + setMonacoContentType($event = this.model.monacoContentType) { const contentType = this.model.request?.apiAttrInfo?.contentType; - if (contentType === ApiBodyType.Raw) { - this.model.contentType = this.apiTestUtil.getContentType(this.model.request.requestParams.headerParams) || 'text/plain'; - } + if (contentType !== ApiBodyType.Raw) return; + this.model.monacoContentType = this.apiTestUtil.getContentType(this.model.request.requestParams.headerParams) || 'text/plain'; } private watchEnvChange() { reaction( @@ -520,9 +548,24 @@ export class ApiTestComponent implements OnInit, AfterViewInit, OnDestroy, TabVi ); } private resetModel() { + const bodyType = typeof StorageUtil.get('api_test_body_type') === 'number' ? StorageUtil.get('api_test_body_type') : ApiBodyType.Raw; + + const headerParams = []; + const contentType = this.getContentTypeByBodyType(bodyType) || contentTypeMap[ApiBodyType.JSON]; + if (bodyType !== ApiBodyType.Binary) { + headerParams.push({ + isRequired: 1, + name: 'content-type', + paramAttr: { + example: contentType + } + }); + } + return { requestTabIndex: 1, responseTabIndex: 0, + monacoContentType: contentType, request: { authInfo: { authInfo: {}, @@ -530,22 +573,14 @@ export class ApiTestComponent implements OnInit, AfterViewInit, OnDestroy, TabVi isInherited: 0 }, apiAttrInfo: { - contentType: ContentTypeEnum.RAW, + contentType: bodyType, requestMethod: 0, beforeInject: '', afterInject: '' }, requestParams: { queryParams: [], - headerParams: [ - { - isRequired: 1, - name: 'content-type', - paramAttr: { - example: CONTENT_TYPE_BY_ABRIDGE[0].value - } - } - ], + headerParams: headerParams, restParams: [], bodyParams: [ { diff --git a/src/browser/src/app/pages/workspace/project/api/http/test/api-test.module.ts b/src/browser/src/app/pages/workspace/project/api/http/test/api-test.module.ts index 8014a96e8..45deee093 100644 --- a/src/browser/src/app/pages/workspace/project/api/http/test/api-test.module.ts +++ b/src/browser/src/app/pages/workspace/project/api/http/test/api-test.module.ts @@ -27,6 +27,7 @@ import { ApiTestBodyComponent } from './body/api-test-body.component'; import { ApiTestResultRequestBodyComponent } from './result-request-body/api-test-result-request-body.component'; import { ApiTestResultResponseComponent } from './result-response/api-test-result-response.component'; import { ByteToStringPipe } from './result-response/get-size.pipe'; +import { TestStatusBarComponent } from './test-status-bar/test-status-bar.component'; const UI_COMPONETS = [ NzTabsModule, @@ -46,7 +47,7 @@ const COMPONENTS = [ ApiScriptComponent ]; @NgModule({ - declarations: [...COMPONENTS, ByteToStringPipe], + declarations: [...COMPONENTS, ByteToStringPipe, TestStatusBarComponent], exports: [...COMPONENTS], imports: [ RouterModule.forChild([ diff --git a/src/browser/src/app/pages/workspace/project/api/http/test/body/api-test-body.component.ts b/src/browser/src/app/pages/workspace/project/api/http/test/body/api-test-body.component.ts index 4e4864ab8..a56f6c488 100644 --- a/src/browser/src/app/pages/workspace/project/api/http/test/body/api-test-body.component.ts +++ b/src/browser/src/app/pages/workspace/project/api/http/test/body/api-test-body.component.ts @@ -73,7 +73,7 @@ export class ApiTestBodyComponent implements OnInit, OnChanges, OnDestroy { private bodyType$: Subject = new Subject(); private destroy$: Subject = new Subject(); get editorType() { - return this.contentType.replace(/.*\//, ''); + return this.contentType?.replace(/.*\//, ''); } constructor(private apiTable: ApiTableService, private message: EoNgFeedbackMessageService) { this.bodyType$.pipe(pairwise(), takeUntil(this.destroy$)).subscribe(val => { diff --git a/src/browser/src/app/pages/workspace/project/api/http/test/result-response/api-test-result-response.component.html b/src/browser/src/app/pages/workspace/project/api/http/test/result-response/api-test-result-response.component.html index 250cb9696..573482bb4 100644 --- a/src/browser/src/app/pages/workspace/project/api/http/test/result-response/api-test-result-response.component.html +++ b/src/browser/src/app/pages/workspace/project/api/http/test/result-response/api-test-result-response.component.html @@ -6,17 +6,6 @@
- -
-
{{ model.statusCode || 'No Response' }}
-
- Size: {{ model.responseLength | byteToString }} - Time: {{ model.time }}ms -
-
+ {{ model.statusCode || 'No Response' }} + Size: {{ model.responseLength | byteToString }} + Time: {{ model.time }} ms +
+ `, + styleUrls: ['./test-status-bar.component.scss'] +}) +export class TestStatusBarComponent implements OnChanges { + @Input() model: ApiTestResData; + codeStatus; + private HTTP_CODE_STATUS = [ + { + cap: 199, + class: 'test-default' + }, + { + status: 'success', + cap: 299, + class: 'test-success' + }, + { + status: 'redirect', + cap: 399, + class: 'test-warning' + }, + { + status: 'clientError', + cap: 499, + class: 'test-error' + }, + { + status: 'serverError', + cap: 599, + class: 'test-error' + } + ]; + ngOnChanges() { + this.codeStatus = this.getHTTPStatus(this.model.statusCode); + } + private getHTTPStatus(statusCode) { + return this.HTTP_CODE_STATUS.find(val => statusCode <= val.cap); + } +} diff --git a/src/browser/src/app/pages/workspace/project/api/service/api-test-util.service.ts b/src/browser/src/app/pages/workspace/project/api/service/api-test-util.service.ts index 16702b78e..364629654 100644 --- a/src/browser/src/app/pages/workspace/project/api/service/api-test-util.service.ts +++ b/src/browser/src/app/pages/workspace/project/api/service/api-test-util.service.ts @@ -14,36 +14,6 @@ import { ApiTestResData } from './test-server/test-server.model'; export class ApiTestUtilService { globalStorageKey = 'EO_TEST_VAR_GLOBALS'; constructor(private apiEditUtil: ApiEditUtilService) {} - getHTTPStatus(statusCode) { - const HTTP_CODE_STATUS = [ - { - status: 'info', - cap: 199, - class: 'test-default' - }, - { - status: 'success', - cap: 299, - class: 'test-success' - }, - { - status: 'redirect', - cap: 399, - class: 'test-warning' - }, - { - status: 'clientError', - cap: 499, - class: 'test-error' - }, - { - status: 'serverError', - cap: 599, - class: 'test-error' - } - ]; - return HTTP_CODE_STATUS.find(val => statusCode <= val.cap); - } /** * Handle api data for judge page has edit * Unlike the saved data, the api data being edited is not as strict @@ -232,7 +202,7 @@ export class ApiTestUtilService { * @param type content-type be added/replaced * @param headers */ - addOrReplaceContentType(contentType: ContentType, headers: HeaderParam[] | any = []) { + addOrReplaceContentType(contentType: ContentType | string, headers: HeaderParam[] | any = []) { const existHeader = headers.find(val => val.name.toLowerCase() === 'content-type'); if (existHeader) { existHeader['paramAttr.example'] = contentType; @@ -242,7 +212,10 @@ export class ApiTestUtilService { { isRequired: 1, name: 'content-type', - 'paramAttr.example': contentType + 'paramAttr.example': contentType, + paramAttr: { + example: contentType + } }, ...headers ]; diff --git a/src/browser/src/app/pages/workspace/project/api/service/test-server/test-server.service.ts b/src/browser/src/app/pages/workspace/project/api/service/test-server/test-server.service.ts index 54a68badd..833a770eb 100644 --- a/src/browser/src/app/pages/workspace/project/api/service/test-server/test-server.service.ts +++ b/src/browser/src/app/pages/workspace/project/api/service/test-server/test-server.service.ts @@ -1,5 +1,5 @@ import { formatDate } from '@angular/common'; -import { Inject, Injectable, LOCALE_ID } from '@angular/core'; +import { Inject, Injectable, Input, LOCALE_ID } from '@angular/core'; import { ApiBodyType, ApiParamsType, JsonRootType, requestMethodMap } from 'pc/browser/src/app/pages/workspace/project/api/api.model'; import { ApiTestUtilService } from 'pc/browser/src/app/pages/workspace/project/api/service/api-test-util.service'; import { @@ -42,10 +42,9 @@ export abstract class TestServerService implements TestServer { .map(val => ({ listDepth: 0, paramKey: val.name, - //@ts-ignore files: val.files?.map(file => file.content), paramType: val.dataType === ApiParamsType.file ? '1' : '0', - paramInfo: val.paramAttr?.example || '' + paramInfo: val.dataType === ApiParamsType.file ? val.files?.map(val => val.name).join(',') : val.paramAttr?.example || '' })); } } diff --git a/src/browser/src/app/pages/workspace/project/api/store/api-state.service.ts b/src/browser/src/app/pages/workspace/project/api/store/api-state.service.ts index dde3fc788..3b08a2774 100644 --- a/src/browser/src/app/pages/workspace/project/api/store/api-state.service.ts +++ b/src/browser/src/app/pages/workspace/project/api/store/api-state.service.ts @@ -12,6 +12,8 @@ export class ApiStoreService { @observable private rootGroup: Group; @observable private groupList: Group[] = []; + @observable private expandList: Array = []; + //? api @observable private apiList = []; @@ -45,6 +47,9 @@ export class ApiStoreService { @computed get getApiList() { return this.apiList; } + @computed get getExpandList() { + return this.expandList; + } @computed get getGroupList() { return this.groupList; } @@ -90,10 +95,18 @@ export class ApiStoreService { this.apiList = list; } + @action addApiSuccess(groupId: string | number) { + this.setExpandsList(groupId); + } + @action setGroupList(list = []) { this.groupList = hangGroupToApi(list); } + @action setExpandsList(expandKey: string | number) { + this.expandList = [...this.expandList, expandKey]; + } + @action setEnvUuid(data) { this.envUuid = data; StorageUtil.set('env:selected', data); diff --git a/src/browser/src/app/pages/workspace/project/setting/project-setting.component.ts b/src/browser/src/app/pages/workspace/project/setting/project-setting.component.ts index ea6b20e71..bede5ca6d 100644 --- a/src/browser/src/app/pages/workspace/project/setting/project-setting.component.ts +++ b/src/browser/src/app/pages/workspace/project/setting/project-setting.component.ts @@ -1,7 +1,7 @@ import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { Router } from '@angular/router'; import { EoNgFeedbackMessageService } from 'eo-ng-feedback'; -import { autorun, toJS } from 'mobx'; +import { autorun, reaction, toJS } from 'mobx'; import { NzModalRef } from 'ng-zorro-antd/modal'; import { ExtensionService } from 'pc/browser/src/app/services/extensions/extension.service'; import { TraceService } from 'pc/browser/src/app/services/trace.service'; @@ -117,10 +117,17 @@ export class ProjectSettingComponent implements OnInit { ]; ngOnInit(): void { - autorun(() => { - this.projectName = this.store.getCurrentProject.name; - this.isInit = true; - }); + this.projectName = this.store.getCurrentProject?.name; + reaction( + () => this.store.getCurrentProject, + project => { + console.log(project); + if (project.name) { + this.projectName = project.name; + } + this.isInit = true; + } + ); } startEditProjectName() { diff --git a/src/browser/src/app/services/extensions/extension.service.ts b/src/browser/src/app/services/extensions/extension.service.ts index fb7e410da..d4cfba3b3 100644 --- a/src/browser/src/app/services/extensions/extension.service.ts +++ b/src/browser/src/app/services/extensions/extension.service.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'; import { ElectronService } from 'pc/browser/src/app/core/services'; import { LanguageService } from 'pc/browser/src/app/core/services/language/language.service'; import { MessageService } from 'pc/browser/src/app/services/message'; +import { extensionMessageSubject } from 'pc/browser/src/app/shared/decorators'; import { defaultExtensions } from 'pc/browser/src/app/shared/models/extension'; import { FeatureInfo, ExtensionInfo, SidebarView } from 'pc/browser/src/app/shared/models/extension-manager'; import { DISABLE_EXTENSION_NAMES } from 'pc/browser/src/app/shared/models/storageKeys.constant'; @@ -92,8 +93,7 @@ export class ExtensionService { }); this.extensionIDs = this.updateExtensionIDs(); this.installedList = Array.from(this.installedMap.values()).filter(it => this.extensionIDs.includes(it.name)); - this.messageService.send({ - type: 'extensionsChange', + extensionMessageSubject.next({ data: { installedMap: this.installedMap, extension: this.installedList.find(val => val.name === opts.name), diff --git a/src/browser/src/app/services/storage/db/models/apiData.ts b/src/browser/src/app/services/storage/db/models/apiData.ts index 986ab8399..5fc74d3d7 100644 --- a/src/browser/src/app/services/storage/db/models/apiData.ts +++ b/src/browser/src/app/services/storage/db/models/apiData.ts @@ -170,6 +170,8 @@ export interface BodyParam { structureId?: number; structureParamId?: string; isRequired?: number; + //Use in test page + files?: any[]; binaryRawData?: string; description?: string; orderNo?: number; diff --git a/src/browser/src/app/shared/constans/featureName.ts b/src/browser/src/app/shared/constans/featureName.ts new file mode 100644 index 000000000..8b7fbf02d --- /dev/null +++ b/src/browser/src/app/shared/constans/featureName.ts @@ -0,0 +1,9 @@ +export const IMPORT_API = 'importAPI'; +export const API_PREVIEW_TAB = 'apiPreviewTab'; +export const EXPORT_API = 'exportAPI'; +export const PUSH_API = 'pushAPI'; +export const PULL_API = 'pullAPI'; +export const FEATURE_CONTROL = 'featureControl'; +export const THEME = 'theme'; +export const SIDEBAR_VIEW = 'sidebarView'; +export const AUTH_API = 'authAPI'; diff --git a/src/browser/src/app/shared/decorators/index.ts b/src/browser/src/app/shared/decorators/index.ts new file mode 100644 index 000000000..5d335b6e0 --- /dev/null +++ b/src/browser/src/app/shared/decorators/index.ts @@ -0,0 +1,50 @@ +import { ExtensionInfo } from 'pc/browser/src/app/shared/models/extension-manager'; +import { Observable, Subject } from 'rxjs'; + +export interface DataType { + installedMap: Map; + extension: ExtensionInfo; + action: string; + name: string; +} + +export type ExtensionMessage = { + /** + * Message data + * + * @data {DataType} + */ + data: DataType; +}; + +export const extensionMessageSubject = new Subject(); + +const extensionsChangeObserve: Observable = extensionMessageSubject.asObservable(); + +/** + * @description Plug-in manipulates the decorator + * @param {string} feature feature + * @param {boolean} autoRun autoRun + * @return {(Object, string, PropertyDescriptor) => PropertyDescriptor} function + */ +export function ExtensionChange(feature: string, autoRun: boolean = false) { + return function (target: Object, key: string, descriptor: PropertyDescriptor) { + const original = descriptor.value; + descriptor.value = function (...args: any[]) { + if (autoRun) { + // It is recommended to call the outer function directly only once + original.apply(this, args); + } + extensionsChangeObserve.subscribe((inArg: ExtensionMessage) => { + const extension: ExtensionInfo = inArg.data.extension; + if (Object.keys(extension?.features).includes(feature)) { + const result = original.apply(this, [...args, inArg]); + return result; + } else { + return null; + } + }); + }; + return descriptor; + }; +} diff --git a/src/browser/src/app/shared/models/extension.ts b/src/browser/src/app/shared/models/extension.ts index bcb0c5e11..d65237de0 100644 --- a/src/browser/src/app/shared/models/extension.ts +++ b/src/browser/src/app/shared/models/extension.ts @@ -1 +1 @@ -export const defaultExtensions = ['postcat-export-openapi', 'postcat-import-openapi']; +export const defaultExtensions = ['postcat-export-openapi', 'postcat-import-openapi', 'postcat-basic-auth']; diff --git a/src/browser/src/app/shared/shared.module.ts b/src/browser/src/app/shared/shared.module.ts index 57823ac46..2ba704757 100644 --- a/src/browser/src/app/shared/shared.module.ts +++ b/src/browser/src/app/shared/shared.module.ts @@ -18,6 +18,7 @@ import { NzListModule } from 'ng-zorro-antd/list'; import { NzModalModule } from 'ng-zorro-antd/modal'; import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; import { NzPopoverModule } from 'ng-zorro-antd/popover'; +import { NzSelectModule } from 'ng-zorro-antd/select'; import { NzSkeletonModule } from 'ng-zorro-antd/skeleton'; import { NzSpinModule } from 'ng-zorro-antd/spin'; import { NzTypographyModule } from 'ng-zorro-antd/typography'; @@ -62,6 +63,7 @@ const SHARED_UI_MODULE = [ NzEmptyModule, NzModalModule, NzListModule, + NzSelectModule, NzPopconfirmModule ]; const SHARED_MODULE = [CommonModule, FormsModule, RouterModule, ReactiveFormsModule]; diff --git a/src/browser/src/app/shared/utils/data-transfer/data-transfer.utils.ts b/src/browser/src/app/shared/utils/data-transfer/data-transfer.utils.ts index 24c164cc3..09c6052ef 100644 --- a/src/browser/src/app/shared/utils/data-transfer/data-transfer.utils.ts +++ b/src/browser/src/app/shared/utils/data-transfer/data-transfer.utils.ts @@ -69,7 +69,7 @@ export const form2json = tmpl => tmpl .split('\n') .filter(it => it.trim()) - .map(it => it.split(':')) + .map(it => [it.slice(0, it.indexOf(':')), it.slice(it.indexOf(':') + 1)]) .map(it => { const [key, value] = it; return { key: key?.trim(), value: value?.trim() }; diff --git a/src/browser/src/app/shared/utils/index.utils.ts b/src/browser/src/app/shared/utils/index.utils.ts index 3a1fc0428..4dc515c63 100644 --- a/src/browser/src/app/shared/utils/index.utils.ts +++ b/src/browser/src/app/shared/utils/index.utils.ts @@ -111,13 +111,17 @@ export const transferFileToDataUrl = file => }; }); export const parserJsonFile = (file, type = 'UTF-8') => - new Promise(resolve => { + new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsText(file, type); reader.onload = ev => { - const fileString: string = ev.target.result as string; - const json = JSON.parse(fileString); - resolve({ name: file.name, content: json }); + try { + const fileString: string = ev.target.result as string; + const json = JSON.parse(fileString); + resolve({ name: file.name, content: json }); + } catch (err) { + reject('This is not a json'); + } }; }); diff --git a/src/browser/src/app/store/effect.service.ts b/src/browser/src/app/store/effect.service.ts index 5318decdd..9bd29491b 100644 --- a/src/browser/src/app/store/effect.service.ts +++ b/src/browser/src/app/store/effect.service.ts @@ -174,7 +174,8 @@ export class EffectService { } // * update project auth const [data, err]: any = await this.api.api_projectGetRole({}); - if (err) { + if (err || !data.length) { + pcConsole.error('Get Project Role error'); return; } const { permissions, roles } = data.at(0); diff --git a/src/node/test-server/package.json b/src/node/test-server/package.json index c5bdbf85f..63815cf9a 100644 --- a/src/node/test-server/package.json +++ b/src/node/test-server/package.json @@ -8,7 +8,9 @@ "url": "git+git@github.com:Postcatlab/postcat.git" }, "scripts": { - "dev": "node ./server/main.js&&node ./server/socketio.js", + "dev": "npm-run-all -p dev:http dev:ws", + "dev:http":"node ./server/main.js", + "dev:ws":"node ./server/socketio.js", "start": "pm2 start ecosystem.config.js", "start:watch": "pm2-runtime start ecosystem.config.js", "stop": "pm2 stop ecosystem.config.js", diff --git a/src/node/test-server/request/libs/apiUtil.js b/src/node/test-server/request/libs/apiUtil.js index c4782af63..2610debfb 100644 --- a/src/node/test-server/request/libs/apiUtil.js +++ b/src/node/test-server/request/libs/apiUtil.js @@ -419,7 +419,6 @@ privateFun.parseBeforeCode = async function (scritEngines = 'pm', inputData, inp let tmpEnviroments; let tmpBinary = inputData.binary; inputOpts.authInfo = inputOpts.authInfo || { authType: 'none', authInfo: {} }; - switch (scritEngines) { case 'pm': { tmpTargetTypeEnv = { @@ -522,10 +521,9 @@ privateFun.parseBeforeCode = async function (scritEngines = 'pm', inputData, inp authInfo = JSON.parse(authInfoStr); const { action } = packageJson.features.authAPI; const func = extension[action]; - const config = (authInfo || []).reduce((acc, cur) => ({ [cur.key]: cur.value, ...acc }), {}); + const config = (authInfo || []).reduce((acc, cur) => ({ ...acc, [cur.key]: cur.value }), {}); //Execute at runtime const code = await func(config); - console.log(code); const [authPmRes, err] = await pmRuntime.executeSync(ctx, code, { context: pmRes }); @@ -548,11 +546,11 @@ privateFun.parseBeforeCode = async function (scritEngines = 'pm', inputData, inp tmpTargetTypeData = { apiUrl: apiUrl.toString(), bodyParam: pmRes.request.body.raw, - bodyParseParam: (pmRes.request.body.urlencoded || []).reduce((acc, cur) => ({ [cur.key]: cur.value, ...acc }), {}), - queryParam: (pmRes.request.url.query || []).reduce((acc, cur) => ({ [cur.key]: cur.value, ...acc }), {}), - headerParam: (pmRes.request.header || []).reduce((acc, cur) => ({ [cur.key]: cur.value, ...acc }), {}) + bodyParseParam: (pmRes.request.body.urlencoded || []).reduce((acc, cur) => ({ ...acc, [cur.key]: cur.value }), {}), + queryParam: (pmRes.request.url.query || []).reduce((acc, cur) => ({ ...acc, [cur.key]: cur.value }), {}), + headerParam: (pmRes.request.header || []).reduce((acc, cur) => ({ ...acc, [cur.key]: cur.value }), {}) }; - global.eoTestGlobals = (pmRes.globals.values || []).reduce((acc, cur) => ({ [cur.key]: cur.value, ...acc }), {}); + global.eoTestGlobals = (pmRes.globals.values || []).reduce((acc, cur) => ({ ...acc, [cur.key]: cur.value }), {}); //for fit eolink tmpOutput.url = apiUrl.toString().split('?')[0]; break; diff --git a/src/node/test-server/request/unit.js b/src/node/test-server/request/unit.js index 5557dee72..665338e93 100644 --- a/src/node/test-server/request/unit.js +++ b/src/node/test-server/request/unit.js @@ -715,7 +715,7 @@ const { resolve } = require('path'); value: typeof tmpDecorateObj.history.body[key][childKey] == 'string' ? tmpDecorateObj.history.body[key][childKey] - : '[file]' + : '(binary)' }); if (typeof tmpDecorateObj.history.body[key][childKey] != 'string') break; } diff --git a/src/platform/node/extension-manager/manager.ts b/src/platform/node/extension-manager/manager.ts index 5fcd4e0a1..50f455b57 100644 --- a/src/platform/node/extension-manager/manager.ts +++ b/src/platform/node/extension-manager/manager.ts @@ -1,5 +1,6 @@ import { createServer } from 'http-server/lib/http-server'; import { LanguageService } from 'pc/app/electron-main/language.service'; +import { defaultExtensions } from 'pc/browser/src/app/shared/models/extension'; import { ExtensionInfo, SidebarView, FeatureInfo } from 'pc/browser/src/app/shared/models/extension-manager'; import { isNotEmpty } from 'pc/shared/common/common'; import { HOME_DIR } from 'pc/shared/electron-main/constant'; @@ -17,7 +18,6 @@ import path from 'node:path'; const extServerMap = new Map(); // * npm pkg name -const defaultExtension = [{ name: 'postcat-export-openapi' }, { name: 'postcat-import-openapi' }, { name: 'postcat-basic-auth' }]; const isExists = async filePath => await promises .access(filePath) @@ -123,7 +123,7 @@ export class ModuleManager { const { extensions } = JSON.parse(debuggerExtension); debugExtension = extensions; } - const localExtensionName = [...new Set(list.map(it => it.name).concat(defaultExtension.map(it => it.name)))]; + const localExtensionName = [...new Set(list.map(it => it.name).concat(defaultExtensions))]; this.installExtension = remoteExtension .filter(it => localExtensionName.includes(it.name)) .filter(it => !debugExtension.includes(it.name)); diff --git a/src/shared/electron-main/constant.ts b/src/shared/electron-main/constant.ts index bc2f8a1df..084eaa83a 100644 --- a/src/shared/electron-main/constant.ts +++ b/src/shared/electron-main/constant.ts @@ -5,3 +5,15 @@ import * as path from 'path'; export const home: string = app.getPath('home'); export const HOME_DIR = path.join(home, '.postcat'); export const STORAGE_TEMP = path.join(HOME_DIR, 'tmp.storage'); + +export const GET_MODULES = 'getModules'; +export const GET_MODULE = 'getModule'; +export const INSTALL_MODULE = 'installModule'; +export const UNINSTALL_MODULE = 'uninstallModule'; +export const GET_FEATURE = 'getFeature'; +export const GET_MOCK_URL = 'getMockUrl'; +export const GET_WEBSOCKET_PORT = 'getWebsocketPort'; +export const GET_EXT_TABS = 'getExtTabs'; +export const LOGIN_WITH = 'loginWith'; +export const GET_SIDEBAR_VIEW = 'getSidebarView'; +export const GET_SIDEBAR_VIEWS = 'getSidebarViews'; diff --git a/test/e2e/src/env.spec.ts b/test/e2e/src/env.spec.ts index 4eff98a14..e7f4435c1 100644 --- a/test/e2e/src/env.spec.ts +++ b/test/e2e/src/env.spec.ts @@ -24,14 +24,20 @@ test.describe('Env Operate', () => { //Add first env will choose it //Edit env - await page.locator('body').press('Meta+c'); + await page.getByRole('tablist').locator('div').filter({ hasText: 'DEV' }).nth(2).hover(); await page.getByRole('button', { name: 'Close tab' }).click(); - await page.locator('div').filter({ hasText: 'DEV' }).nth(2).click(); + await page.locator('div').filter({ hasText: 'DEV' }).click(); await page.getByLabel('Name').press('Meta+s'); await ifTipsExist(page, 'Edited successfully'); //Delete env }); + + test('Env Delete', async ({ page }) => { + await page.locator('nz-tree-node-title div').first().hover(); + await page.locator('nz-tree-node-title').getByRole('button').click(); + await page.getByRole('button', { name: 'Delete' }).click(); + }); // test('Use Env', async ({ page }) => { // //Host uri // //Global variable diff --git a/test/e2e/test-results/src-user-User-Opeate-chromium/test-failed-1.png b/test/e2e/test-results/src-user-User-Opeate-chromium/test-failed-1.png new file mode 100644 index 0000000000000000000000000000000000000000..55b7e24fe3ab3a34ac929be9b843e6617f9241b6 GIT binary patch literal 21426 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 literal 0 HcmV?d00001 diff --git a/yarn.lock b/yarn.lock index 54c4ebbcd..3ed616bf2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3774,6 +3774,11 @@ array-includes@^3.1.4: get-intrinsic "^1.1.3" is-string "^1.0.7" +array-keyed-map@^2.1.3: + version "2.1.3" + resolved "https://registry.npmmirror.com/array-keyed-map/-/array-keyed-map-2.1.3.tgz#0d5c06ed58ccba2755a4f5bfb7a935a31f395b18" + integrity sha512-JIUwuFakO+jHjxyp4YgSiKXSZeC0U+R1jR94bXWBcVlFRBycqXlb+kH9JHxBGcxnVuSqx5bnn0Qz9xtSeKOjiA== + array-union@^1.0.2: version "1.0.2" resolved "https://registry.npmmirror.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -8388,6 +8393,13 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" +gpt3-tokenizer@1.1.5: + version "1.1.5" + resolved "https://registry.npmmirror.com/gpt3-tokenizer/-/gpt3-tokenizer-1.1.5.tgz#79e5f96c435daf9c41a81117411ebce3bf475e78" + integrity sha512-O9iCL8MqGR0Oe9wTh0YftzIbysypNQmS5a5JG3cB3M4LMYjlAVvNnf8LUzVY9MrI7tj+YLY356uHtO2lLX2HpA== + dependencies: + array-keyed-map "^2.1.3" + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"