merge feat/import

This commit is contained in:
scarqin 2022-08-23 22:08:23 +08:00
parent af64099769
commit d230860670
27 changed files with 760 additions and 279 deletions

View File

@ -1,7 +1,7 @@
{
"name": "eoapi",
"souceLocale": "zh-Hans",
"version": "1.5.1",
"version": "1.6.0",
"main": "out/app/electron-main/main.js",
"description": "A lightweight, extensible API tool",
"homepage": "https://github.com/eolinker/eoapi.git",

View File

@ -53,7 +53,6 @@ window.eo.loadFeatureModule = (moduleID) => {
if (!featureModules.has(moduleID)) {
try {
const module = window.eo.getModule(moduleID);
console.log('featureModules module', module);
window.eo._currentExtensionID = moduleID;
const _module = require(module.baseDir);
featureModules.set(moduleID, _module);

View File

@ -33,12 +33,13 @@
"@ant-design/icons-angular": "13.1.0",
"@babel/runtime": "7.18.3",
"@ngxs/store": "3.7.4",
"ajv": "8.11.0",
"angular": "1.8.2",
"brace": "0.11.1",
"js-beautify": "1.14.4",
"markdown-it": "13.0.1",
"monaco-editor": "0.33.0",
"ng-zorro-antd": "13.3.2",
"ng-zorro-antd": "13.4.0",
"ngx-ace-wrapper": "12.0.0",
"qs": "6.11.0",
"rxjs": "7.5.5",
@ -93,4 +94,4 @@
"chrome 98"
],
"__npminstall_done": false
}
}

View File

@ -11,11 +11,12 @@ export class LanguageService {
languages = LANGUAGES;
//If the user does not set it, the system default language is used
// Web from nginx setting and App from computer system setting
systemLanguage =
systemLanguage =this.setting.getSettings()?.['eoapi-language']||
this.languages.find((val) => window.location.href.includes(`/${val.path}`))?.value ||
(navigator.language.includes('zh') ? 'zh-Hans' : 'en-US');
constructor(private remote: RemoteService, private electron: ElectronService,private setting:SettingService) {}
constructor(private remote: RemoteService, private electron: ElectronService,private setting: SettingService) {
}
init() {
this.changeLanguage(this.setting.getSettings()?.['eoapi-language']);

View File

@ -43,6 +43,10 @@ import { ApiTabStorageService } from 'eo/workbench/browser/src/app/pages/api/tab
import { ApiTabOperateService } from 'eo/workbench/browser/src/app/pages/api/tab/api-tab-operate.service';
import { ApiTabService } from 'eo/workbench/browser/src/app/pages/api/api-tab.service';
import { NzSpinModule } from 'ng-zorro-antd/spin';
import { ImportOutline, ExportOutline, SyncOutline,PlusOutline } from '@ant-design/icons-angular/icons';
import { IconDefinition } from '@ant-design/icons-angular';
const icons: IconDefinition[] = [ ImportOutline, ExportOutline, SyncOutline,PlusOutline ];
const COMPONENTS = [
ApiComponent,
ApiGroupEditComponent,
@ -59,11 +63,11 @@ const COMPONENTS = [
imports: [
HttpClientModule,
FormsModule,
NzIconModule.forRoot(icons),
ReactiveFormsModule,
CommonModule,
ApiRoutingModule,
NzButtonModule,
NzIconModule,
NzTabsModule,
NzLayoutModule,
NzTreeModule,

View File

@ -12,6 +12,7 @@ import { StorageService } from '../../../shared/services/storage';
import {
Group,
ApiEditViewData,
ApiData,
RequestProtocol,
RequestMethod,
@ -30,15 +31,15 @@ import { ApiEditUtilService } from './api-edit-util.service';
styleUrls: ['./api-edit.component.scss'],
})
export class ApiEditComponent implements OnInit, OnDestroy {
@Input() model: ApiData;
@Input() model: ApiEditViewData;
/**
* Intial model from outside,check form is change
* * Usually restored from tab
*/
@Input() initialModel: ApiData;
@Output() modelChange = new EventEmitter<ApiData>();
@Output() afterInit = new EventEmitter<ApiData>();
@Output() afterSaved = new EventEmitter<ApiData>();
@Input() initialModel: ApiEditViewData;
@Output() modelChange = new EventEmitter<ApiEditViewData>();
@Output() afterInit = new EventEmitter<ApiEditViewData>();
@Output() afterSaved = new EventEmitter<ApiEditViewData>();
@ViewChild('apiGroup') apiGroup: NzTreeSelectComponent;
validateForm: FormGroup;
groups: any[];
@ -72,7 +73,7 @@ export class ApiEditComponent implements OnInit, OnDestroy {
const id = Number(this.route.snapshot.queryParams.uuid);
const groupID = Number(this.route.snapshot.queryParams.groupID || 0);
if (!this.model || isEmptyObj(this.model)) {
this.model = {} as ApiData;
this.model = {} as ApiEditViewData;
const initTimes = this.initTimes;
const result = await this.apiEdit.getApi({
id,
@ -213,7 +214,7 @@ export class ApiEditComponent implements OnInit, OnDestroy {
* Resolve the problem that groupID change but view not change
*/
private resetGroupID() {
let groupID: number | string = '-1';
let groupID = '-1';
if (this.model && this.model.groupID) {
groupID = this.model.groupID;
this.model.groupID = '';
@ -229,7 +230,7 @@ export class ApiEditComponent implements OnInit, OnDestroy {
private initBasicForm() {
//Prevent init error
if (!this.model) {
this.model = {} as ApiData;
this.model = {} as ApiEditViewData;
}
const controls = {};
['protocol', 'method', 'uri', 'groupID', 'name'].forEach((name) => {

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { ApiService } from 'eo/workbench/browser/src/app/pages/api/api.service';
import { StorageService } from 'eo/workbench/browser/src/app/shared/services/storage';
import { ApiData, StorageRes } from 'eo/workbench/browser/src/app/shared/services/storage/index.model';
import { ApiBodyType, ApiData, ApiEditViewData, JsonRootType, StorageRes } from 'eo/workbench/browser/src/app/shared/services/storage/index.model';
import { RequestMethod, RequestProtocol } from '../../../shared/services/storage/index.model';
import { ApiEditUtilService } from './api-edit-util.service';
@Injectable()
@ -22,21 +22,21 @@ export class ApiEditService {
method: RequestMethod.POST,
},
{
requestBodyType: 'json',
requestBodyJsonType: 'object',
requestBodyType: ApiBodyType.JSON,
requestBodyJsonType: JsonRootType.Object,
requestBody: [],
queryParams: [],
restParams: [],
requestHeaders: [],
responseHeaders: [],
responseBodyType: 'json',
responseBodyJsonType: 'object',
responseBodyType: ApiBodyType.JSON,
responseBodyJsonType: JsonRootType.Object,
responseBody: [],
}
);
}
async getApi({ id, groupID }): Promise<ApiData> {
let result: ApiData = {} as ApiData;
async getApi({ id, groupID }): Promise<ApiEditViewData> {
let result= {} as ApiData;
if (!id) {
// From test page/copy api data;
let tmpApiData = window.sessionStorage.getItem('apiDataWillbeSave');
@ -55,7 +55,7 @@ export class ApiEditService {
result = pureApi;
}
} else {
result = (await this.apiService.get(id)) as ApiData;
result = (await this.apiService.get(id));
}
return this.apiEditUtil.getFormdataFromApiData(result);
}

View File

@ -14,7 +14,6 @@ import { NzTreeComponent } from 'ng-zorro-antd/tree';
import { ModalService } from '../../../../shared/services/modal.service';
import { StorageService } from '../../../../shared/services/storage';
import { ElectronService } from '../../../../core/services';
import { createMockObj, IndexedDBStorage } from 'eo/workbench/browser/src/app/shared/services/storage/IndexedDB/lib/';
import { ApiService } from 'eo/workbench/browser/src/app/pages/api/api.service';
@Component({
selector: 'eo-api-group-tree',
@ -69,7 +68,6 @@ export class ApiGroupTreeComponent implements OnInit, OnDestroy {
private messageService: MessageService,
private storage: StorageService,
public electron: ElectronService,
public storageInstance: IndexedDBStorage,
private apiService: ApiService,
private nzModalService: NzModalService
) {}
@ -163,17 +161,6 @@ export class ApiGroupTreeComponent implements OnInit, OnDestroy {
...(getExpandGroupByKey(this.apiGroup, this.route.snapshot.queryParams.uuid) || []),
];
}
async createGroup({ name, projectID, content }) {
const groupID = await this.storageInstance.group.add({ name: name.replace(/\.json$/, ''), projectID });
const result = content.apiData.map(({ uuid, ...it }, index) => ({ ...it, groupID }));
const apiDataKeys = await this.storageInstance.apiData.bulkAdd(result, { allKeys: true });
const apiData = result.map((n, i) =>
createMockObj(n, { name: $localize`Default Mock`, createWay: 'system', apiDataID: apiDataKeys.at(i) })
);
this.storageInstance.mock.bulkAdd(apiData);
this.buildGroupTreeData();
}
/**
* Watch apiData change event.
*/
@ -187,13 +174,11 @@ export class ApiGroupTreeComponent implements OnInit, OnDestroy {
case 'editApiSuccess':
case 'copyApiSuccess':
case 'deleteApiSuccess':
case 'importSuccess':
case 'updateGroupSuccess': {
this.buildGroupTreeData();
break;
}
case 'importSuccess': {
this.createGroup({ projectID: 1, ...inArg.data });
}
}
});
}

View File

@ -240,7 +240,9 @@ export class ApiTestUtilService {
result[keyName] = this.testTableData2ApiBody(result[keyName]);
});
if (inData.history.response.responseType === 'text') {
console.log('inData.history.response.body', inData.history.response.body);
const bodyInfo = text2UiData(inData.history.response.body);
console.log('bodyInfo', bodyInfo);
result.responseBody = listToTreeHasLevel(bodyInfo.data);
result.responseBodyType = bodyInfo.textType;
result.responseBodyJsonType = bodyInfo.rootType;

View File

@ -5,7 +5,7 @@
class="bd_all w-full min-h-[140px] p-5 flex flex-col flex-wrap items-center plugin-block hover:border-green-700 hover:shadow-lg transition-shadow duration-300"
*ngFor="let it of renderList" (click)="clickExtension(it)">
<div class="flex w-full">
<div class="shrink-0 block w-[40px] h-[40px] rounded-lg bg-cover bg-center bg-no-repeat mr-[20px]"
<div class="shrink-0 block w-[40px] h-[40px] rounded-lg bg-[length:90%] bg-center bg-no-repeat mr-[20px]"
[ngClass]="{ 'bg-gray-100': it.logo }" [ngStyle]="{ 'background-image': 'url(' + (it.logo || '') + ')' }">
</div>

View File

@ -40,7 +40,7 @@
<i nz-icon nzType="inbox"></i>
</p>
<p class="ant-upload-text" i18n>Tap or drag files directly to this area</p>
<p class="ant-upload-hint" i18n>Only individual files in Json format are supported</p>
<p class="ant-upload-hint" i18n>Only supports importing a single file</p>
</nz-upload>
<div class="text h-4 my-2">{{ filename }}</div>
</div>

View File

@ -10,7 +10,7 @@
transition: all 0.3s ease;
.logobg {
background-repeat: no-repeat;
background-size: contain;
background-size: 45px;
background-position: center center;
}
&.active {

View File

@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core';
import { FeatureType } from '../../types';
import { EoMessageService } from 'eo/workbench/browser/src/app/eoui/message/eo-message.service';
import { MessageService } from 'eo/workbench/browser/src/app/shared/services/message/message.service';
import { StorageService } from 'eo/workbench/browser/src/app/shared/services/storage';
import { StorageRes, StorageResStatus } from 'eo/workbench/browser/src/app/shared/services/storage/index.model';
// const optionList = [
// {
@ -48,7 +50,11 @@ export class ImportApiComponent implements OnInit {
currentExtension = '';
uploadData = null;
featureMap = window.eo.getFeature('apimanage.import');
constructor(private messageService: MessageService, private eoMessage: EoMessageService) {}
constructor(
private messageService: MessageService,
private storage: StorageService,
private eoMessage: EoMessageService
) {}
ngOnInit(): void {
this.featureMap?.forEach((data: FeatureType, key: string) => {
this.supportList.push({
@ -65,6 +71,10 @@ export class ImportApiComponent implements OnInit {
this.uploadData = data;
}
async submit(callback) {
if(!this.uploadData){
this.eoMessage.error($localize `Please import the file first`);
return;
}
// * this.currentExtension is extension's key, like 'eoapi-import-openapi'
const feature = this.featureMap.get(this.currentExtension);
const action = feature.action || null;
@ -76,10 +86,14 @@ export class ImportApiComponent implements OnInit {
callback(false);
return;
}
// console.log(JSON.stringify(data, null, 2));
this.messageService.send({
type: 'importSuccess',
data: { name, content: data },
console.log(data);
this.storage.run('projectImport', [1, data], (result: StorageRes) => {
if (result.status === StorageResStatus.success) {
this.messageService.send({
type: 'importSuccess',
data: { },
});
}
});
callback(true);
}

View File

@ -1,4 +1,5 @@
import { ApiData } from '../../index.model';
import { JsonRootType, RequestProtocol, RequestMethod, ApiBodyType } from '../../index.model';
export const sampleApiData: ApiData[] = [
{
@ -6,10 +7,10 @@ export const sampleApiData: ApiData[] = [
projectID: 1,
uri: 'http://www.weather.com.cn/data/cityinfo/{cityCode}.html',
groupID: 0,
protocol: 'http',
method: 'GET',
requestBodyType: 'raw',
requestBodyJsonType: 'object',
protocol: RequestProtocol.HTTP,
method: RequestMethod.GET,
requestBodyType: ApiBodyType.Raw,
requestBodyJsonType: JsonRootType.Object,
requestBody: '',
queryParams: [],
restParams: [
@ -27,8 +28,8 @@ export const sampleApiData: ApiData[] = [
],
requestHeaders: [],
responseHeaders: [],
responseBodyType: 'json',
responseBodyJsonType: 'object',
responseBodyType: ApiBodyType.JSON,
responseBodyJsonType: JsonRootType.Object,
responseBody: [
{
name: 'weatherinfo',
@ -39,8 +40,20 @@ export const sampleApiData: ApiData[] = [
children: [
{ name: 'city', description: '', type: 'string', required: true, example: '北京' },
{ name: 'cityid', description: '', type: 'string', required: true, example: '101010100' },
{ name: 'temp1', description: $localize`minimum temperature`, type: 'string', required: true, example: '18℃' },
{ name: 'temp2', description: $localize`maximun temperature`, type: 'string', required: true, example: '31℃' },
{
name: 'temp1',
description: $localize`minimum temperature`,
type: 'string',
required: true,
example: '18℃',
},
{
name: 'temp2',
description: $localize`maximun temperature`,
type: 'string',
required: true,
example: '31℃',
},
{ name: 'weather', description: '', type: 'string', required: true, example: '多云转阴' },
{ name: 'img1', description: '', type: 'string', required: true, example: 'n1.gif' },
{ name: 'img2', description: '', type: 'string', required: true, example: 'd2.gif' },
@ -55,12 +68,12 @@ export const sampleApiData: ApiData[] = [
projectID: 1,
uri: 'https://view.inews.qq.com/g2/getOnsInfo',
groupID: 0,
protocol: 'http',
method: 'GET',
requestBodyType: 'raw',
requestBodyJsonType: 'object',
protocol: RequestProtocol.HTTP,
method: RequestMethod.GET,
requestBodyType: ApiBodyType.Raw,
requestBodyJsonType: JsonRootType.Object,
requestBody: '',
queryParams: [{ name: 'name', required: true, example: 'disease_h5',description:'' }],
queryParams: [{ name: 'name', required: true, example: 'disease_h5', description: '' }],
restParams: [],
requestHeaders: [],
responseHeaders: [
@ -73,8 +86,8 @@ export const sampleApiData: ApiData[] = [
{ name: 'x-client-ip', required: true, description: '', example: '120.26.198.150' },
{ name: 'x-server-ip', required: true, description: '', example: '58.250.137.40' },
],
responseBodyType: 'json',
responseBodyJsonType: 'object',
responseBodyType: ApiBodyType.JSON,
responseBodyJsonType: JsonRootType.Object,
responseBody: [
{ name: 'ret', description: '', type: 'number', required: true, example: '' },
{

View File

@ -1,10 +1,9 @@
import Dexie, { Table } from 'dexie';
import { getSettings } from 'eo/workbench/browser/src/app/core/services/settings/settings.service';
import { messageService } from 'eo/workbench/browser/src/app/shared/services/message/message.service';
import { DataSourceType } from 'eo/workbench/browser/src/app/shared/services/storage/storage.service';
import { uniqueSlash } from 'eo/workbench/browser/src/app/utils/api';
import { tree2obj } from 'eo/workbench/browser/src/app/utils/tree/tree.utils';
import { Observable } from 'rxjs';
import { firstValueFrom, Observable } from 'rxjs';
import {
Project,
Environment,
@ -16,7 +15,9 @@ import {
StorageItem,
StorageResStatus,
} from '../../index.model';
import { sampleApiData } from '../sample';
import { parseAndCheckApiData, parseAndCheckEnv, parseAndCheckGroup } from './validate';
import { sampleApiData } from './index.constant';
export type ResultType<T = any> = {
status: StorageResStatus.success;
@ -94,11 +95,6 @@ export class IndexedDBStorage extends Dexie implements StorageInterface {
status: StorageResStatus.success,
data,
};
// if (isNotEmpty(data)) {
// result.status = StorageResStatus.success;
// } else {
// result.status = StorageResStatus.empty;
// }
return result as ResultType;
}
/**
@ -107,7 +103,7 @@ export class IndexedDBStorage extends Dexie implements StorageInterface {
* @param table
* @param item
*/
private create(table: Table, item: StorageItem): Observable<object> {
private create(table: Table, item: StorageItem): Observable<any> {
if (!item.createdAt) {
item.createdAt = new Date();
}
@ -134,6 +130,7 @@ export class IndexedDBStorage extends Dexie implements StorageInterface {
*/
private bulkCreate(table: Table, items: Array<StorageItem>): Observable<object> {
items = items.map((item: StorageItem) => {
delete item.uuid;
if (!item.createdAt) {
item.createdAt = new Date();
}
@ -470,9 +467,7 @@ export class IndexedDBStorage extends Dexie implements StorageInterface {
*
* @param uuid
*/
apiTestHistoryLoad = (uuid: number | string): Observable<object> => {
return this.load(this.apiTestHistory, uuid);
};
apiTestHistoryLoad = (uuid: number | string): Observable<object> => this.load(this.apiTestHistory, uuid);
/**
* Load all apiTestHistory items by apiDataID.
@ -643,7 +638,7 @@ export class IndexedDBStorage extends Dexie implements StorageInterface {
*
* @param item
*/
groupCreate(item: Group): Observable<object> {
groupCreate(item: Group): Observable<ResultType<Group>> {
return this.create(this.group, item);
}
@ -678,12 +673,66 @@ export class IndexedDBStorage extends Dexie implements StorageInterface {
groupUpdate(item: Group, uuid: number | string): Observable<object> {
return this.update(this.group, item, uuid);
}
projectImport(uuid: number, data): Observable<object> {
return new Observable((obs) => {
const errors = {
apiData: [],
};
//Add api and group
const deepFn = (collections, parentID) =>
new Promise((resolve) => {
collections.forEach(async (item) => {
item.projectID = uuid;
//Judge item is api or group
if (item.uri || item.method || item.protocol) {
delete item.uuid;
item.groupID = parentID;
const result = parseAndCheckApiData(item);
if (!result.validate) {
errors.apiData.push(item.name || item.uri);
return;
}
this.apiDataCreate(result.data);
} else {
item.parentID = parentID;
const result = parseAndCheckGroup(item);
if (!result.validate) {
return;
}
item.uuid = (await firstValueFrom(this.groupCreate(result.data))).data.uuid;
}
if (item.children?.length) {
await deepFn(item.children, item.uuid);
}
resolve('');
});
});
deepFn(data.collections, 0);
//Add env
if (data.enviroments && data.enviroments.length) {
data.enviroments.forEach((item) => {
item.projectID = uuid;
const result = parseAndCheckEnv(item);
if (!result.validate) {
return;
}
this.environmentCreate(result.data);
});
}
obs.next(
this.resProxy({
errors,
})
);
obs.complete();
});
}
/**
* Bulk create project items.
*
* @param items
*/
projectBulkCreate(items: Array<Project>): Observable<object> {
return this.bulkCreate(this.project, items);
}
@ -691,9 +740,8 @@ export class IndexedDBStorage extends Dexie implements StorageInterface {
return new Observable((obs) => {
const fun = async () => {
const result = {};
const tables = ['environment', 'group', 'project', 'apiData'];
for (let i = 0; i < tables.length; i++) {
const tableName = tables[i];
const tables = ['environment', 'group', 'project', 'apiData', 'mock'];
for (const tableName of tables) {
if (tableName === 'project') {
result[tableName] = (await this[tableName].toArray())[0];
} else {

View File

@ -0,0 +1,70 @@
import Ajv, { JSONSchemaType } from 'ajv';
import { ApiData, Environment, Group } from '../../index.model';
import { whatType } from 'eo/workbench/browser/src/app/utils';
import apiDataSchema from '../schema/apiData.json';
import { ApiBodyType } from '../../index.model';
import envSchema from '../schema/env.json';
export const parseAndCheckApiData = (apiData): { validate: boolean; data?: ApiData; error?: any } => {
const ajv = new Ajv({
useDefaults: true,
removeAdditional: true,
});
const validate = ajv.compile<ApiData>(apiDataSchema);
if (validate(apiData)) {
['requestBody', 'responseBody'].forEach((keyName) => {
if (
[ApiBodyType['Form-data'], ApiBodyType.JSON, ApiBodyType.XML].includes(apiData[`${keyName}Type`]) &&
whatType(apiData[keyName]) !== 'array'
) {
//Handle xml\formdata\json data
apiData[keyName] = [];
} else if (
[ApiBodyType.Raw, ApiBodyType.Binary].includes(apiData[`${keyName}Type`]) &&
whatType(apiData[keyName]) !== 'string'
) {
//Handle raw\binary data
apiData[keyName] = '';
}
});
return { validate: true, data: apiData };
} else {
console.error(validate.errors);
return { validate: false, error: validate.errors };
}
};
export const parseAndCheckGroup = (group): { validate: boolean; data?: Group } => {
if (group.name) {
return {
validate: true,
data: {
projectID: group.projectID,
parentID: group.parentID,
name: group.name,
},
};
} else {
return { validate: false };
}
};
export const parseAndCheckEnv = (env): { validate: boolean; data?: Environment; error?: any } => {
const ajv = new Ajv({
useDefaults: true,
removeAdditional: true,
});
const validate = ajv.compile<Environment>(envSchema);
if (validate(env)) {
return {
validate: true,
data: {
projectID: env.projectID,
name: env.name,
hostUri: env.hostUri,
parameters: env.parameters,
},
};
} else {
console.error(validate.errors);
return { validate: false, error: validate.errors };
}
};

View File

@ -0,0 +1,38 @@
# JSON schema
Check data Valide
# Genreate JSON schema from Typescript interface
1. install
```
npm install typescript-json-schema -g
```
2. genreate
```
cd src/workbench/browser/src/app/shared/services/storage
//genrate apidata
typescript-json-schema "index.model.ts" 'ApiData' -o "./indexedDB/schema/apiData.json"
//genrate env
typescript-json-schema "index.model.ts" 'Environment' -o "./indexedDB/schema/env.json"
```
3. compare and merge
The generated rule verification is not strict enough and needs to be merged manually
# Check
```javascript
const ajv = new Ajv({
useDefaults: true,
});
const validate = ajv.compile < ApiData > apiDataSchema;
if (validate(apiData)) {
return { validate: true, data: apiData };
} else {
return { validate: false, error: validate.errors };
}
```

View File

@ -0,0 +1,260 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ApiBodyType": {
"nullable": true,
"enum": ["binary", "formData", "json", "raw", "xml"],
"type": "string"
},
"ApiEditBody": {
"properties": {
"attribute": {
"description": "XML attribute",
"type": "string"
},
"children": {
"description": "子参数",
"items": {
"$ref": "#/definitions/ApiEditBody"
},
"type": "array"
},
"description": {
"description": "说明",
"type": "string"
},
"enum": {
"description": "值可能性",
"items": {
"$ref": "#/definitions/ParamsEnum"
},
"type": "array"
},
"example": {
"description": "param example",
"type": "string"
},
"maxLength": {
"description": "最大长度",
"type": "number"
},
"maximum": {
"description": "最大值",
"type": "number"
},
"minLength": {
"description": "最小长度",
"type": "number"
},
"minimum": {
"description": "最小值",
"type": "number"
},
"name": {
"description": "参数名",
"type": "string"
},
"required": {
"description": "is response/request must contain param",
"type": "boolean"
},
"type": {
"description": "参数类型",
"type": "string"
}
},
"type": "object"
},
"BasiApiEditParams": {
"properties": {
"description": {
"description": "说明",
"type": "string"
},
"enum": {
"description": "值可能性",
"items": {
"$ref": "#/definitions/ParamsEnum"
},
"type": "array"
},
"example": {
"description": "param example",
"type": "string"
},
"name": {
"description": "参数名",
"type": "string"
},
"required": {
"description": "is response/request must contain param",
"type": "boolean"
}
},
"type": "object"
},
"JsonRootType": {
"description": "body type is json,set root type of object/array",
"enum": ["array", "object"],
"nullable": true,
"type": "string"
},
"ParamsEnum": {
"properties": {
"default": {
"description": "is default param value",
"type": "boolean"
},
"description": {
"description": "param value description",
"type": "string"
},
"value": {
"description": "param value",
"type": "string"
}
},
"description": "ParamsEnum",
"type": "object"
},
"RequestMethod": {
"enum": ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"],
"type": "string"
},
"RequestProtocol": {
"enum": ["http", "https"],
"type": "string"
}
},
"properties": {
"createdAt": {
"description": "创建时间,可为空",
"type": "string"
},
"groupID": {
"type": "number",
"default": 0
},
"method": {
"$ref": "#/definitions/RequestMethod",
"default":"POST",
"description": "Request method [POST, GET, PUT, ...]"
},
"name": {
"description": "name",
"type": "string"
},
"projectID": {
"description": "Belongs to which project",
"type": "number"
},
"protocol": {
"$ref": "#/definitions/RequestProtocol",
"description": "API protocol [http, https, ...]"
},
"queryParams": {
"description": "get请求参数数据用json存储",
"type": "array",
"items": {
"$ref": "#/definitions/BasiApiEditParams"
},
"default": []
},
"requestBody": {
"anyOf": [
{
"items": {
"$ref": "#/definitions/ApiEditBody"
},
"type": "array",
"default":[]
},
{
"type": "string",
"default":""
}
],
"default": "",
"description": "请求参数(多层结构)数据用json存储"
},
"requestBodyJsonType": {
"$ref": "#/definitions/JsonRootType",
"description": "请求的json参数根类型",
"default": "object"
},
"requestBodyType": {
"$ref": "#/definitions/ApiBodyType",
"description": "请求的参数类型",
"default": "raw"
},
"requestHeaders": {
"description": "请求头数据数据用json存储",
"items": {
"$ref": "#/definitions/BasiApiEditParams"
},
"type": "array",
"default": []
},
"responseBody": {
"anyOf": [
{
"items": {
"$ref": "#/definitions/ApiEditBody"
},
"type": "array"
},
{
"type": "string"
}
],
"description": "Response(多层结构)数据用json存储",
"default": ""
},
"responseBodyJsonType": {
"$ref": "#/definitions/JsonRootType",
"description": "Responsejson根类型",
"default": "object"
},
"responseBodyType": {
"$ref": "#/definitions/ApiBodyType",
"description": "返回的参数类型",
"default": "raw"
},
"responseHeaders": {
"description": "返回头数据数据用json存储",
"type": "array",
"items": {
"$ref": "#/definitions/BasiApiEditParams"
},
"default": []
},
"restParams": {
"description": "rest请求参数数据用json存储",
"items": {
"$ref": "#/definitions/BasiApiEditParams"
},
"type": "array",
"default": []
},
"updatedAt": {
"description": "更新时间,可为空",
"type": "string"
},
"uri": {
"description": "Request url,Usually value is path",
"type": "string"
},
"uuid": {
"description": "主键UUID字符串UUID或数值型",
"type": "number"
},
"weight": {
"description": "api show order",
"type": "number",
"default": 0
}
},
"required": ["method", "name", "uri", "protocol"],
"additionalProperties": false,
"type": "object"
}

View File

@ -0,0 +1,59 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "环境对象接口",
"definitions": {
"BasicParams": {
"properties": {
"name": {
"description": "参数名",
"type": "string",
"default":""
},
"value": {
"description": "param value",
"type": "string",
"default":""
}
},
"type": "object"
}
},
"properties": {
"createdAt": {
"description": "创建时间,可为空",
"type": "string"
},
"hostUri": {
"description": "前置url",
"type": "string",
"default": ""
},
"name": {
"description": "名称",
"type": "string"
},
"parameters": {
"description": "环境变量(可选)",
"type": "array",
"items": {
"$ref": "#/definitions/BasicParams"
},
"default": []
},
"projectID": {
"description": "项目主键ID",
"type": "number"
},
"updatedAt": {
"description": "更新时间,可为空",
"type": "string"
},
"uuid": {
"description": "主键UUID字符串UUID或数值型",
"type": "number"
}
},
"required": ["name"],
"additionalProperties": false,
"type": "object"
}

View File

@ -20,6 +20,9 @@ export class HttpStorage implements StorageInterface {
return this.http.get('/system/status') as Observable<object>;
}
// Project
projectImport(uuid: number, item: Project) {
return this.http.put(`/project/${uuid}/import`, item) as Observable<object>;
}
projectCreate(item: Project) {
return this.http.post(`/project`, item) as Observable<object>;
}

View File

@ -1,9 +1,4 @@
import {
ApiTestBody,
ApiTestBodyType,
ApiTestHeaders,
ApiTestQuery,
} from 'eo/workbench/browser/src/app/shared/services/api-test/api-test.model';
import { ApiTestBody, ApiTestBodyType, ApiTestHeaders } from './../api-test/api-test.model';
import { Observable } from 'rxjs';
/**
@ -13,9 +8,9 @@ interface StorageModel {
/**
* UUIDUUID或数值型
*
* @type {string|number}
* @type {number}
*/
uuid?: string | number;
uuid?: number;
/**
*
@ -24,13 +19,6 @@ interface StorageModel {
*/
name?: string;
/**
*
*
* @type {string}
*/
description?: string;
/**
*
*
@ -51,32 +39,30 @@ interface StorageModel {
*/
export interface Environment extends StorageModel {
/**
*
* Env name
*
* @type {string}
*/
name: string;
/**
* ID
* Project primary ID
*
* @type {string|number}
* @type {number}
*/
projectID: string | number;
projectID: number;
/**
* url
* Host uri
*
* @type {string}
*/
hostUri: string;
hostUri?: string;
/**
*
*
* @type {object}
* Env parameters
*/
parameters?: object;
parameters?: { name: string; value: string }[];
}
/**
@ -327,7 +313,7 @@ export enum RequestProtocol {
/**
* API Data
*/
export interface ApiData extends StorageModel {
interface BasicApiData extends StorageModel {
/**
* name
*
@ -335,39 +321,23 @@ export interface ApiData extends StorageModel {
*/
name: string;
/**
* Belongs to which project
*
* @type {string|number}
*/
projectID?: string | number;
/**
* Belongs to which group
*
* @type {string|number}
*/
groupID: string | number;
/**
* Request url,Usually value is path
*
* @type {string}
*/
uri: string;
/**
* API protocol [http, https, ...]
*
* @type {RequestProtocol|string}
*/
protocol: RequestProtocol | string;
protocol: RequestProtocol;
/**
* Request method [POST, GET, PUT, ...]
*
* @type {RequestMethod|string}
*/
method: RequestMethod | string;
method: RequestMethod;
/**
* api show order
@ -379,28 +349,23 @@ export interface ApiData extends StorageModel {
/**
*
*
* @type {ApiBodyType|string}
*/
requestBodyType?: ApiBodyType | string;
requestBodyType?: ApiBodyType;
/**
* json存储
*
* @type {object}
*/
requestHeaders?: ApiEditHeaders[];
/**
* json参数根类型
*
* @type {JsonRootType|string}
*/
requestBodyJsonType?: JsonRootType | string;
requestBodyJsonType?: JsonRootType;
/**
* ()json存储
*
* @type {object}
*/
requestBody?: ApiEditBody[] | string;
@ -421,30 +386,37 @@ export interface ApiData extends StorageModel {
/**
* json存储
*
* @type {object}
*/
responseHeaders?: ApiEditHeaders[];
/**
* Response()json存储
*
* @type {ApiEditBody[] | string}
*/
responseBody?: ApiEditBody[] | string;
/**
*
*
* @type {ApiBodyType|string}
*/
responseBodyType?: ApiBodyType | string;
responseBodyType?: ApiBodyType;
/**
* Responsejson根类型
*
* @type {JsonRootType|string}
*/
responseBodyJsonType?: JsonRootType | string;
responseBodyJsonType?: JsonRootType;
}
export interface ApiData extends BasicApiData {
/**
* Belongs to which project
*
*/
projectID: number;
groupID: number;
}
/**
* API data view model
*/
export interface ApiEditViewData extends BasicApiData {
groupID: string;
}
/**
* API Test Data
@ -524,11 +496,11 @@ export interface ApiTestData {
/**
* Javascript code before test
*/
beforeScript: string;
beforeScript?: string;
/**
* Javascript code after api response
*/
afterScript: string;
afterScript?: string;
}
/**
@ -666,6 +638,7 @@ export interface StorageInterface {
*/
systemCheck?: () => Observable<object>;
// Project
projectImport: (uuid: number, item: any) => Observable<object>;
projectCreate: (item: Project) => Observable<object>;
projectUpdate: (item: Project, uuid: number | string) => Observable<object>;
projectBulkUpdate: (items: Array<Project>) => Observable<object>;

View File

@ -96,12 +96,12 @@ export const xml2json = (tmpl) => {
let index = null;
while (xml) {
// * handle end tags
if (xml.substring(0, 2) === '</') {
if (xml.trim().substring(0, 2) === '</') {
const end = xml.match(endTag);
const [str, label] = end;
const last = stack.pop();
if (last.tagName !== label) {
throw new Error('Parse error 101');
throw new Error(`Parse error 101. [${last.tagName}] is not eq [${label}]`);
}
if (stack.length === 0) {
result.push(last);
@ -110,12 +110,25 @@ export const xml2json = (tmpl) => {
parent.children.push(last);
stack.push(parent);
}
xml = xml.substring(str.length);
xml = xml.trim().substring(str.length);
continue;
}
// * handle start tags
if ((start = xml.match(startTag))) {
const [str, label, attr] = start;
if (str.slice(-2) === '/>') {
// * single tag
const parent = stack.pop();
parent.children.push({
tagName: label.trim(),
attr: attr.trim(),
content: '',
children: [],
});
stack.push(parent);
xml = xml.trim().substring(str.length);
continue;
}
stack.push({
tagName: label.trim(),
attr: attr.trim(),
@ -139,6 +152,7 @@ export const xml2json = (tmpl) => {
if (stack.length) {
throw new Error('Parse error 102');
}
// console.log(JSON.stringify(result, null, 2));
return result;
};
@ -147,6 +161,7 @@ type uiData = {
rootType: JsonRootType | string;
data: ApiEditBody | any;
};
export const xml2UiData = (text) => {
const data: any[] = xml2json(text);
const deep = (list = []) =>
@ -265,7 +280,7 @@ export const uiData2Json = function (eoapiArr: ApiEditBody[], inputOptions) {
if (inputOptions.checkXmlAttr) {
inputObject['@eo_attr'] = inputObject['@eo_attr'] || {};
}
for (const val of inputArr) {
for (const val of inputArr || []) {
if (!val.name) {
continue;
}

View File

@ -1,12 +0,0 @@
{
"PAGES": {
"HOME": {
"TITLE": "App works !",
"GO_TO_DETAIL": "Go to Detail1"
},
"DETAIL": {
"TITLE": "Detail page !",
"BACK_TO_HOME": "Back to Home"
}
}
}

View File

@ -95,15 +95,15 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/detail/mock/api-detail-mock.component.ts</context>
<context context-type="linenumber">134</context>
<context context-type="linenumber">133</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/mock/api-mock.component.ts</context>
<context context-type="linenumber">261</context>
<context context-type="linenumber">260</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/monaco-editor/monaco-editor.component.ts</context>
<context context-type="linenumber">290</context>
<context context-type="linenumber">292</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/utils/index.ts</context>
@ -143,7 +143,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">54</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/overview/api-overview.component.html</context>
@ -238,7 +238,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">14</context>
<context context-type="linenumber">15</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/body/api-test-body.component.ts</context>
@ -265,7 +265,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">15</context>
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="7045123878111147511" datatype="html">
@ -368,11 +368,11 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">97</context>
<context context-type="linenumber">98</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/api-script/constant.ts</context>
@ -395,7 +395,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">105</context>
<context context-type="linenumber">106</context>
</context-group>
</trans-unit>
<trans-unit id="3170454287339201082" datatype="html">
@ -711,11 +711,11 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">137</context>
<context context-type="linenumber">138</context>
</context-group>
</trans-unit>
<trans-unit id="3098390606978669021" datatype="html">
@ -740,7 +740,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">132</context>
<context context-type="linenumber">133</context>
</context-group>
</trans-unit>
<trans-unit id="52c9a103b812f258bcddc3d90a6e3f46871d25fe" datatype="html">
@ -797,11 +797,11 @@
<source>Edited successfully</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/edit/api-edit.component.ts</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">128</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/mock/api-mock.component.ts</context>
<context context-type="linenumber">235</context>
<context context-type="linenumber">234</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/env/env.component.ts</context>
@ -812,11 +812,11 @@
<source>Added successfully</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/edit/api-edit.component.ts</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">128</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/mock/api-mock.component.ts</context>
<context context-type="linenumber">240</context>
<context context-type="linenumber">239</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/env/env.component.ts</context>
@ -827,14 +827,14 @@
<source>Failed Operation</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/edit/api-edit.component.ts</context>
<context context-type="linenumber">141</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit id="4926605800185679045" datatype="html">
<source>Root directory</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/edit/api-edit.component.ts</context>
<context context-type="linenumber">185</context>
<context context-type="linenumber">186</context>
</context-group>
</trans-unit>
<trans-unit id="bc0fd905b5fa45043121b5607fa0f2e91201ff98" datatype="html">
@ -988,57 +988,46 @@
<context context-type="linenumber">87</context>
</context-group>
</trans-unit>
<trans-unit id="7245969617352349881" datatype="html">
<source>Default Mock</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">171</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.ts</context>
<context context-type="linenumber">87</context>
</context-group>
</trans-unit>
<trans-unit id="1623775429516238560" datatype="html">
<source>Deletion Confirmation?</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">232</context>
<context context-type="linenumber">217</context>
</context-group>
</trans-unit>
<trans-unit id="9142685431369791033" datatype="html">
<source>Are you sure you want to delete the data &lt;strong title=&quot;<x id="PH" equiv-text="apiInfo.name"/>&quot;&gt;<x id="PH_1" equiv-text="apiInfo.name.length &gt; 50 ? apiInfo.name.slice(0, 50) + &apos;...&apos; : apiInfo.name"/>&lt;/strong&gt; ? You cannot restore it once deleted!</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">233,235</context>
<context context-type="linenumber">218,220</context>
</context-group>
</trans-unit>
<trans-unit id="9124347207158517893" datatype="html">
<source>Add Group</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">291</context>
<context context-type="linenumber">276</context>
</context-group>
</trans-unit>
<trans-unit id="6661660398413994526" datatype="html">
<source>Add Subgroup</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">300</context>
<context context-type="linenumber">285</context>
</context-group>
</trans-unit>
<trans-unit id="5908762969513689727" datatype="html">
<source>Edit Group</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">309</context>
<context context-type="linenumber">294</context>
</context-group>
</trans-unit>
<trans-unit id="3596210590059423029" datatype="html">
<source>Delete Group</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">318</context>
<context context-type="linenumber">303</context>
</context-group>
</trans-unit>
<trans-unit id="c6b146602288a87386004d591558477a97497e60" datatype="html">
@ -1102,7 +1091,7 @@
<source>Delete Succeeded</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/mock/api-mock.component.ts</context>
<context context-type="linenumber">224</context>
<context context-type="linenumber">223</context>
</context-group>
</trans-unit>
<trans-unit id="1071721880474488785" datatype="html">
@ -1239,18 +1228,18 @@
<source><x id="PH" equiv-text="opts.title"/> Value</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">16</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="6555318547274416232" datatype="html">
<source>Value</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">118</context>
<context context-type="linenumber">119</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">123</context>
<context context-type="linenumber">124</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/header/api-test-header.component.ts</context>
@ -2749,8 +2738,8 @@
<context context-type="linenumber">24,26</context>
</context-group>
</trans-unit>
<trans-unit id="48337f1cc97660a13f3327ba705a66f31faec719" datatype="html">
<source>Only individual files in Json format are supported</source>
<trans-unit id="15c7e4510fb38a7b8ca73e1af4fa3a199f2d1a44" datatype="html">
<source>Only supports importing a single file</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/extension-select/extension-select.component.html</context>
<context context-type="linenumber">43</context>
@ -2763,6 +2752,13 @@
<context context-type="linenumber">44</context>
</context-group>
</trans-unit>
<trans-unit id="7946321398772270161" datatype="html">
<source>Please import the file first</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/import-api/import-api.component.ts</context>
<context context-type="linenumber">75</context>
</context-group>
</trans-unit>
<trans-unit id="a059709f71aa4c0ac219e160e78a738682ca6a36" datatype="html">
<source>Import</source>
<context-group purpose="location">
@ -2926,25 +2922,25 @@
<source>Only the client can connect to the remote server. You need to download the client first.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/setting/common/data-storage.component.ts</context>
<context context-type="linenumber">110</context>
<context context-type="linenumber">112</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/setting/common/data-storage.component.ts</context>
<context context-type="linenumber">156</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="8244321085825115351" datatype="html">
<source>Remote server connection failed!!</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/setting/common/data-storage.component.ts</context>
<context context-type="linenumber">144</context>
<context context-type="linenumber">146</context>
</context-group>
</trans-unit>
<trans-unit id="2875796658938124573" datatype="html">
<source>The remote data source connection is successful!</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/setting/common/data-storage.component.ts</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">172</context>
</context-group>
</trans-unit>
<trans-unit id="0feab442129ba239106e55cf029069d3d4adeadc" datatype="html">
@ -3076,43 +3072,50 @@
<trans-unit id="3618702844543429787" datatype="html">
<source>Get City Weather Today</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">5</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">6</context>
</context-group>
</trans-unit>
<trans-unit id="2290605059653855867" datatype="html">
<source>City Code : http://www.mca.gov.cn/article/sj/xzqh/2020/20201201.html</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">20</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">21</context>
</context-group>
</trans-unit>
<trans-unit id="7782559081118681676" datatype="html">
<source>minimum temperature</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">42</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="4661147653025473439" datatype="html">
<source>maximun temperature</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">43</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">52</context>
</context-group>
</trans-unit>
<trans-unit id="8259972015663673459" datatype="html">
<source>COVID-19 national epidemic</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">54</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="3950552443739162649" datatype="html">
<source>The actual parameter is string, in order to show the document expansion display</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">82</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">95</context>
</context-group>
</trans-unit>
<trans-unit id="7245969617352349881" datatype="html">
<source>Default Mock</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.ts</context>
<context context-type="linenumber">88</context>
</context-group>
</trans-unit>
</body>

View File

@ -103,15 +103,15 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/detail/mock/api-detail-mock.component.ts</context>
<context context-type="linenumber">134</context>
<context context-type="linenumber">133</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/mock/api-mock.component.ts</context>
<context context-type="linenumber">261</context>
<context context-type="linenumber">260</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/monaco-editor/monaco-editor.component.ts</context>
<context context-type="linenumber">290</context>
<context context-type="linenumber">292</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/utils/index.ts</context>
@ -155,7 +155,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">54</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/overview/api-overview.component.html</context>
@ -260,7 +260,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">14</context>
<context context-type="linenumber">15</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/body/api-test-body.component.ts</context>
@ -288,7 +288,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">15</context>
<context context-type="linenumber">16</context>
</context-group>
<target state="translated"><x id="PH" equiv-text="opts.title"/>名</target>
</trans-unit>
@ -396,11 +396,11 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">97</context>
<context context-type="linenumber">98</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">100</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/api-script/constant.ts</context>
@ -424,7 +424,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">105</context>
<context context-type="linenumber">106</context>
</context-group>
<target state="translated">类型</target>
</trans-unit>
@ -768,11 +768,11 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">137</context>
<context context-type="linenumber">138</context>
</context-group>
<target state="translated">删除</target>
</trans-unit>
@ -800,7 +800,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">132</context>
<context context-type="linenumber">133</context>
</context-group>
<target state="translated">添加子字段</target>
</trans-unit>
@ -864,11 +864,11 @@
<source>Edited successfully</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/edit/api-edit.component.ts</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">128</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/mock/api-mock.component.ts</context>
<context context-type="linenumber">235</context>
<context context-type="linenumber">234</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/env/env.component.ts</context>
@ -880,11 +880,11 @@
<source>Added successfully</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/edit/api-edit.component.ts</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">128</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/mock/api-mock.component.ts</context>
<context context-type="linenumber">240</context>
<context context-type="linenumber">239</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/env/env.component.ts</context>
@ -896,7 +896,7 @@
<source>Failed Operation</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/edit/api-edit.component.ts</context>
<context context-type="linenumber">141</context>
<context context-type="linenumber">142</context>
</context-group>
<target state="translated">操作失败</target>
</trans-unit>
@ -904,7 +904,7 @@
<source>Root directory</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/edit/api-edit.component.ts</context>
<context context-type="linenumber">185</context>
<context context-type="linenumber">186</context>
</context-group>
<target state="translated">根目录</target>
</trans-unit>
@ -1078,23 +1078,11 @@
</context-group>
<target state="translated">编辑</target>
</trans-unit>
<trans-unit id="7245969617352349881" datatype="html">
<source>Default Mock</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">171</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.ts</context>
<context context-type="linenumber">87</context>
</context-group>
<target state="translated">默认 Mock</target>
</trans-unit>
<trans-unit id="1623775429516238560" datatype="html">
<source>Deletion Confirmation?</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">232</context>
<context context-type="linenumber">217</context>
</context-group>
<target state="translated">确认删除?</target>
</trans-unit>
@ -1102,7 +1090,7 @@
<source>Are you sure you want to delete the data &lt;strong title=&quot;<x id="PH" equiv-text="apiInfo.name"/>&quot;&gt;<x id="PH_1" equiv-text="apiInfo.name.length &gt; 50 ? apiInfo.name.slice(0, 50) + &apos;...&apos; : apiInfo.name"/>&lt;/strong&gt; ? You cannot restore it once deleted!</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">233,235</context>
<context context-type="linenumber">218,220</context>
</context-group>
<target state="translated">确认要删除数据 &lt;strong title="<x id="PH" equiv-text="apiInfo.name"/>"&gt;<x id="PH_1" equiv-text="apiInfo.name.length &gt; 50 ? apiInfo.name.slice(0, 50) + '...' : apiInfo.name"/>&lt;/strong&gt; 吗?删除后不可恢复!</target>
</trans-unit>
@ -1110,7 +1098,7 @@
<source>Add Group</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">291</context>
<context context-type="linenumber">276</context>
</context-group>
<target state="translated">添加分组</target>
</trans-unit>
@ -1118,7 +1106,7 @@
<source>Add Subgroup</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">300</context>
<context context-type="linenumber">285</context>
</context-group>
<target state="translated">添加子分组</target>
</trans-unit>
@ -1126,7 +1114,7 @@
<source>Edit Group</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">309</context>
<context context-type="linenumber">294</context>
</context-group>
<target state="translated">编辑分组</target>
</trans-unit>
@ -1134,7 +1122,7 @@
<source>Delete Group</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/group/tree/api-group-tree.component.ts</context>
<context context-type="linenumber">318</context>
<context context-type="linenumber">303</context>
</context-group>
<target state="translated">删除分组</target>
</trans-unit>
@ -1208,7 +1196,7 @@
<source>Delete Succeeded</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/mock/api-mock.component.ts</context>
<context context-type="linenumber">224</context>
<context context-type="linenumber">223</context>
</context-group>
<target state="translated">删除成功</target>
</trans-unit>
@ -1364,7 +1352,7 @@
<source><x id="PH" equiv-text="opts.title"/> Value</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">16</context>
<context context-type="linenumber">17</context>
</context-group>
<target state="translated"><x id="PH" equiv-text="opts.title"/>值</target>
</trans-unit>
@ -1372,11 +1360,11 @@
<source>Value</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">118</context>
<context context-type="linenumber">119</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/api-test-util.service.ts</context>
<context context-type="linenumber">123</context>
<context context-type="linenumber">124</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/pages/api/test/header/api-test-header.component.ts</context>
@ -3036,13 +3024,13 @@
</context-group>
<target state="translated"> 该功能需要插件支持,请移步至<x id="START_LINK" ctype="x-a" equiv-text="&lt;a class=&quot;eo_link&quot; routerLink=&quot;/home/extension/list&quot;&gt;"/>插件广场<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>下载 </target>
</trans-unit>
<trans-unit id="48337f1cc97660a13f3327ba705a66f31faec719" datatype="html">
<source>Only individual files in Json format are supported</source>
<trans-unit id="15c7e4510fb38a7b8ca73e1af4fa3a199f2d1a44" datatype="html">
<source>Only supports importing a single file</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/extension-select/extension-select.component.html</context>
<context context-type="linenumber">43</context>
</context-group>
<target state="translated">仅支持JSON格式的单个文件导入</target>
<target state="translated">仅支持导入单个文件</target>
</trans-unit>
<trans-unit id="4141575162728577645" datatype="html">
<source>Only files in JSON format are supported</source>
@ -3052,6 +3040,14 @@
</context-group>
<target state="translated">仅支持上传 JSON 格式的文件</target>
</trans-unit>
<trans-unit id="7946321398772270161" datatype="html">
<source>Please import the file first</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/import-api/import-api.component.ts</context>
<context context-type="linenumber">75</context>
</context-group>
<target state="translated">请先导入文件</target>
</trans-unit>
<trans-unit id="a059709f71aa4c0ac219e160e78a738682ca6a36" datatype="html">
<source>Import</source>
<context-group purpose="location">
@ -3236,11 +3232,11 @@
<source>Only the client can connect to the remote server. You need to download the client first.</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/setting/common/data-storage.component.ts</context>
<context context-type="linenumber">110</context>
<context context-type="linenumber">112</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/setting/common/data-storage.component.ts</context>
<context context-type="linenumber">156</context>
<context context-type="linenumber">159</context>
</context-group>
<target state="translated">仅客户端支持连接远程服务器,需要先下载客户端。</target>
</trans-unit>
@ -3248,7 +3244,7 @@
<source>Remote server connection failed!!</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/setting/common/data-storage.component.ts</context>
<context context-type="linenumber">144</context>
<context context-type="linenumber">146</context>
</context-group>
<target state="translated">远程服务器连接失败</target>
</trans-unit>
@ -3256,7 +3252,7 @@
<source>The remote data source connection is successful!</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/components/setting/common/data-storage.component.ts</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">172</context>
</context-group>
<target state="translated">远程数据源连接成功!</target>
</trans-unit>
@ -3405,51 +3401,59 @@
<trans-unit id="3618702844543429787" datatype="html">
<source>Get City Weather Today</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">5</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">6</context>
</context-group>
<target state="translated">获取城市今日天气</target>
</trans-unit>
<trans-unit id="2290605059653855867" datatype="html">
<source>City Code : http://www.mca.gov.cn/article/sj/xzqh/2020/20201201.html</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">20</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">21</context>
</context-group>
<target state="translated">城市代码 : http://www.mca.gov.cn/article/sj/xzqh/2020/20201201.html</target>
</trans-unit>
<trans-unit id="7782559081118681676" datatype="html">
<source>minimum temperature</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">42</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">45</context>
</context-group>
<target state="translated">最低温度</target>
</trans-unit>
<trans-unit id="4661147653025473439" datatype="html">
<source>maximun temperature</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">43</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">52</context>
</context-group>
<target state="translated">最高温度</target>
</trans-unit>
<trans-unit id="8259972015663673459" datatype="html">
<source>COVID-19 national epidemic</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">54</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">67</context>
</context-group>
<target state="translated">新冠全国疫情</target>
</trans-unit>
<trans-unit id="3950552443739162649" datatype="html">
<source>The actual parameter is string, in order to show the document expansion display</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/sample/index.ts</context>
<context context-type="linenumber">82</context>
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.constant.ts</context>
<context context-type="linenumber">95</context>
</context-group>
<target state="translated">实际参数是 string以便显示文档扩展显示</target>
</trans-unit>
<trans-unit id="7245969617352349881" datatype="html">
<source>Default Mock</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/shared/services/storage/IndexedDB/lib/index.ts</context>
<context context-type="linenumber">88</context>
</context-group>
<target state="translated">默认 Mock</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -5,7 +5,7 @@
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"emitDecoratorMetadata": false,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"experimentalDecorators": true,

View File

@ -9204,10 +9204,10 @@ neo-async@^2.6.0, neo-async@^2.6.2:
resolved "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
ng-zorro-antd@13.3.2:
version "13.3.2"
resolved "https://registry.npmmirror.com/ng-zorro-antd/-/ng-zorro-antd-13.3.2.tgz#04d79f884231afdfdb5759919c0fa202f431cc8f"
integrity sha512-bmpolaSevoZSVlP2nVpvi/CrFFu7hdaK/vz1k0R84db4AYOYFHcRwlAUBaWVKjWGaCHek+k1atC/pckXZqEgIA==
ng-zorro-antd@13.4.0:
version "13.4.0"
resolved "https://registry.yarnpkg.com/ng-zorro-antd/-/ng-zorro-antd-13.4.0.tgz#a62a9df914d7241a6f5baabe1f4740ddd724b737"
integrity sha512-ZIXeeXtTUNg3mdXNg2A3gJGh0aqN/pM3Ii61FiUhwkVwmVzIIDwYfGZZNNOl+cURL5HGzrwQ10nrYgdfFfZ20g==
dependencies:
"@angular/cdk" "^13.0.1"
"@ant-design/icons-angular" "^13.0.1"