Skip to content

Commit

Permalink
fix: The new API cannot open two tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
scarqin committed Aug 11, 2022
1 parent fb40e3c commit 8fd46d2
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 109 deletions.
41 changes: 25 additions & 16 deletions src/workbench/browser/src/app/pages/api/api-tab.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ export class ApiTabService {
return Object.values(this.BASIC_TBAS).find((val) => this.router.url.includes(val.pathname))?.type || 'preview';
}
private changeContent$: Subject<any> = new Subject();
BASIC_TBAS = {
test: { pathname: '/home/api/test', type: 'edit', title: $localize`New Request`, extends: { method: 'POST' } },
edit: { pathname: '/home/api/edit', type: 'edit', title: $localize`New API` },
BASIC_TBAS: { [key: string]: Partial<TabItem> } = {
test: {
pathname: '/home/api/test',
type: 'edit',
title: $localize`New Request`,
extends: { method: 'POST' },
},
edit: { pathname: '/home/api/edit', isFixed: true, type: 'edit', title: $localize`New API` },
detail: { pathname: '/home/api/detail', type: 'preview', title: $localize`Preview` },
overview: { pathname: '/home/api/overview', type: 'preview', title: $localize`:@@API Index:Index`, icon: 'home' },
mock: { pathname: '/home/api/mock', type: 'preview', title: 'Mock' },
Expand Down Expand Up @@ -115,7 +120,7 @@ export class ApiTabService {
}
//?Why should use getCurrentTab()?
//Because maybe current tab has't finish init
const currentTab = this.apiTabComponent.getTabByUrl(url);
const currentTab = this.apiTabComponent.getExistTabByUrl(url);
const contentID = this.getContentID(url);
//Get tab cache
this.componentRef.model = currentTab?.content?.[contentID] || null;
Expand All @@ -124,9 +129,11 @@ export class ApiTabService {
}
updateTab(currentTab, inData) {
const model = inData.model;
const contentID = this.getContentID(currentTab.pathname);

//Set tabItem
const replaceTab: Partial<TabItem> = {
hasChanged: currentTab.hasChanged,
isLoading: false,
extends: {},
};
Expand All @@ -148,7 +155,6 @@ export class ApiTabService {
}
//Only hasChanged edit page storage data
if (currentTab.type === 'edit') {
const contentID = this.getContentID(currentTab.pathname);
//Set hasChange
if (!this.componentRef?.isFormChange) {
throw new Error(
Expand All @@ -157,7 +163,10 @@ export class ApiTabService {
}
switch (inData.when) {
case 'editing': {
replaceTab.hasChanged = this.componentRef.isFormChange();
// Saved APIs do not need to verify changes
if (!currentTab.params.uuid || currentTab.params.uuid.includes('history')) {
replaceTab.hasChanged = this.componentRef.isFormChange();
}
break;
}
case 'saved': {
Expand All @@ -170,15 +179,6 @@ export class ApiTabService {
replaceTab.hasChanged =
currentTab.extends?.hasChanged?.[contentID === 'edit' ? 'test' : 'edit'] || replaceTab.hasChanged;

//Set isFixed
if (replaceTab.hasChanged) {
replaceTab.isFixed = true;
}
//Has tested set fixed
if (currentTab.pathname === '/home/api/test' && model.testStartTime !== undefined) {
replaceTab.isFixed = true;
}

// Set storage
//Set baseContent
if (['init', 'saved'].includes(inData.when)) {
Expand All @@ -190,6 +190,15 @@ export class ApiTabService {
replaceTab.content = inData.when === 'saved' ? {} : currentTab.content || {};
replaceTab.content[contentID] = model && !isEmptyObj(model) ? model : null;
}

//Set isFixed
if (replaceTab.hasChanged) {
replaceTab.isFixed = true;
}
//Has tested/exsix api set fixed
if (currentTab.pathname === '/home/api/test' && (model.testStartTime !== undefined || currentTab.params.uuid)) {
replaceTab.isFixed = true;
}
}
// console.log('updatePartialTab',inData.url,currentTab, replaceTab);
this.apiTabComponent.updatePartialTab(inData.url, replaceTab);
Expand All @@ -205,7 +214,7 @@ export class ApiTabService {
console.warn(`EO_WARNING:apiTabComponent hasn't init yet!`);
return;
}
const currentTab = this.apiTabComponent.getTabByUrl(inData.url);
const currentTab = this.apiTabComponent.getExistTabByUrl(inData.url);
if (!currentTab) {
console.warn(`has't find the tab fit child component ,url:${inData.url}`);
return;
Expand Down
170 changes: 97 additions & 73 deletions src/workbench/browser/src/app/pages/api/tab/api-tab-operate.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,22 +139,26 @@ export class ApiTabOperateService {
/**
* Get exist tab index
*
* @param type sameTab means has same {params.uuid}
* @param type sameTab means has same pageID and same {params.uuid}
* @param tab
* @returns
*/
getSameContentTabIndex(tab: TabItem): number {
let result = -1;
const sameTabIDTab = this.tabStorage.tabsByID.get(tab.uuid);
if (sameTabIDTab && !sameTabIDTab.params.uuid && sameTabIDTab.pathname === tab.pathname) {
return this.tabStorage.tabOrder.findIndex((uuid) => uuid === sameTabIDTab.uuid);
getSameContentTab(tab: Partial<TabItem>): TabItem | null {
let result = null;
if (!tab.params.uuid) {
const sameTabIDTab = this.tabStorage.tabsByID.get(tab.uuid);
if (sameTabIDTab && sameTabIDTab.pathname === tab.pathname) {
return sameTabIDTab;
}
return result;
}
//Get exist params.uuid content tab,same pathname and uuid match
const mapObj = Object.fromEntries(this.tabStorage.tabsByID);
for (const key in mapObj) {
if (Object.prototype.hasOwnProperty.call(mapObj, key)) {
const tabInfo = mapObj[key];
if (tabInfo.params.uuid && tabInfo.params.uuid === tab.params.uuid && tabInfo.pathname === tab.pathname) {
result = this.tabStorage.tabOrder.findIndex((uuid) => uuid === tabInfo.uuid);
if (tabInfo.params.uuid === tab.params.uuid && tabInfo.pathname === tab.pathname) {
result = tabInfo;
break;
}
}
Expand All @@ -167,10 +171,9 @@ export class ApiTabOperateService {
* @param url
* @returns tabInfo
*/
getBaiscTabFromUrl(url): TabItem {
getTabInfoFromUrl(url): { uuid: number; pathname: string; params: any } {
const urlArr = url.split('?');
const params: any = {};
const timestamp = Date.now();
const basicTab = Object.values(this.BASIC_TABS).find((val) => urlArr[0].includes(val.pathname));
if (!basicTab) {
throw new Error(`EO_ERROR: Please check this router has added in BASIC_TABS,current route:${url}`);
Expand All @@ -183,109 +186,99 @@ export class ApiTabOperateService {
}
params[key] = value;
});
params.pageID = params.pageID || timestamp;
const result = {
//If data need load from ajax/indexeddb,add loading
uuid: params.pageID,
isLoading: params.uuid ? true : false,
pathname: basicTab.pathname,
params,
};
['title', 'icon', 'type', 'extends'].forEach((keyName) => {
result[keyName] = basicTab[keyName];
});
return result;
}
/**
* Get basic tab info from url
*
* @param url
* @returns tabInfo
*/
getBaiscTabFromUrl(url): TabItem {
const result = this.getTabInfoFromUrl(url);
const basicTab = Object.values(this.BASIC_TABS).find((val) => result.pathname === val.pathname);
if (!basicTab) {
throw new Error(`EO_ERROR: Please check this router has added in BASIC_TABS,current route:${url}`);
}
result.params.pageID = result.params.pageID || Date.now();
Object.assign(result, basicTab);
return result as TabItem;
}

/**
* Operate tab after router change,router triggle tab change
* Such as new tab,pick tab,close tab...
*
* @param res.url location.pathname+location.search
*/
operateTabAfterRouteChange(res: { url: string }) {
const tmpTabItem = this.getBaiscTabFromUrl(res.url);
const sameContentIndex = this.getSameContentTabIndex(tmpTabItem);
const existTab = this.getTabByIndex(sameContentIndex);
console.log('operateTabAfterRouteChange', existTab, tmpTabItem);
//If page lack pageID
//Jump to exist tab item to keep same pageID and so on
if (!res.url.includes('pageID')) {
const pureTab = this.getTabInfoFromUrl(res.url);
const nextTab = this.getBaiscTabFromUrl(res.url);
const existTab = this.getSameContentTab(pureTab);
//!Every tab must has pageID
//If lack pageID,Jump to exist tab item to keep same pageID and so on
if (!pureTab.uuid) {
if (existTab) {
tmpTabItem.uuid = tmpTabItem.params.pageID = existTab.uuid;
pureTab.uuid = pureTab.params.pageID = existTab.uuid;
}
this.navigateTabRoute(tmpTabItem);
this.navigateTabRoute(nextTab);
return;
}

if (this.tabStorage.tabOrder.length === 0) {
this.tabStorage.addTab(tmpTabItem);
this.tabStorage.addTab(nextTab);
this.updateChildView();
return;
}

//same tab content,selected it
if (existTab) {
this.selectedIndex = sameContentIndex;
this.selectedIndex = this.tabStorage.tabOrder.findIndex((uuid) => uuid === existTab.uuid);
this.updateChildView();
return;
}
//If has same content tab (same {params.uuid}),replace it and merge data
const mapObj = Object.fromEntries(this.tabStorage.tabsByID);
for (const key in mapObj) {
if (Object.prototype.hasOwnProperty.call(mapObj, key)) {
const tab = mapObj[key];
if (tab.params.uuid && tab.params.uuid === tmpTabItem.params.uuid) {
const mergeTab = this.preventBlankTab(tab, tmpTabItem);
mergeTab.content = tab.content;
mergeTab.baseContent = tab.baseContent;
mergeTab.extends = Object.assign(mergeTab.extends || {}, tab.extends);
this.selectedIndex = this.tabStorage.tabOrder.findIndex((uuid) => uuid === tab.uuid);
this.tabStorage.updateTab(this.selectedIndex, mergeTab);
this.updateChildView();
return;
}
//!Same params.uuid can only open one Tab
//If has same subTab (same {params.uuid}), merge data and replace it
if (nextTab.params?.uuid) {
const hasFind = this.jumpToSameSubTab(nextTab);
if (hasFind) {
return;
}
}
//If has same tab (same uuid),replace it
const samePageID = this.tabStorage.tabsByID.has(tmpTabItem.uuid);
if (samePageID) {
this.selectedIndex = this.tabStorage.tabOrder.findIndex((uuid) => uuid === tmpTabItem.uuid);
this.tabStorage.updateTab(this.selectedIndex, tmpTabItem);
//Determine whether to replace the current Tab
let canbeReplaceTab = null;
if (this.tabStorage.tabsByID.has(pureTab.uuid)) {
//If the same tab exists, directly replace
canbeReplaceTab = nextTab;
} else {
canbeReplaceTab = this.findTabCanbeReplace();
}

//Find other tab to be replace
const currentTab = this.getCurrentTab();
//* Replace current tab first
const canbeReplaceTab =
currentTab && this.canbeReplace(currentTab)
? currentTab
: Object.values(mapObj).find((val) => this.canbeReplace(val));
if (canbeReplaceTab) {
this.selectedIndex = this.tabStorage.tabOrder.findIndex((uuid) => uuid === canbeReplaceTab.uuid);
this.tabStorage.updateTab(this.selectedIndex, tmpTabItem);
this.tabStorage.updateTab(this.selectedIndex, nextTab);
this.updateChildView();
return;
}

//No one can be replace,add tab
this.tabStorage.addTab(tmpTabItem);
this.tabStorage.addTab(nextTab);
this.selectedIndex = this.tabStorage.tabOrder.length - 1;
this.updateChildView();
}
//*Prevent toggling splash screen with empty tab title
preventBlankTab(origin, target) {
private preventBlankTab(origin, target) {
const result = target;
/**
* Keyname effect show tab
*/
['title', 'hasChanged', 'isFixed', 'isLoading'].forEach((keyName) => {
//Dont't replace is loading tab content
if (result[keyName] && !result.isLoading) {
return;
}
['title', 'hasChanged', 'isLoading'].forEach((keyName) => {
result[keyName] = origin[keyName];
});
result.isLoading = false;
return result;
}
canbeReplace(tabItem: TabItem) {
Expand All @@ -304,15 +297,46 @@ export class ApiTabOperateService {
getCurrentTab() {
return this.getTabByIndex(this.selectedIndex);
}
private getUrlByTab(tab: TabItem) {
return (
tab.pathname +
'?' +
Object.keys(tab.params)
.sort()
.map((keyName) => `${keyName}=${tab.params[keyName]}`)
.join('&')
);
/**
* Same sub means tab has same {params.uuid}
*
* @param inTab
* @returns hasFind
*/
private jumpToSameSubTab(inTab): boolean {
const mapObj = Object.fromEntries(this.tabStorage.tabsByID);
for (const key in mapObj) {
if (Object.prototype.hasOwnProperty.call(mapObj, key)) {
const tab = mapObj[key];
if (tab.params.uuid && tab.params.uuid === inTab.params.uuid) {
const mergeTab = this.preventBlankTab(tab, inTab);
mergeTab.content = tab.content;
mergeTab.baseContent = tab.baseContent;
mergeTab.extends = Object.assign(mergeTab.extends || {}, tab.extends);
this.selectedIndex = this.tabStorage.tabOrder.findIndex((uuid) => uuid === tab.uuid);
this.tabStorage.updateTab(this.selectedIndex, mergeTab);
this.updateChildView();
return true;
}
}
}
return false;
}

/**
* Find can be replace tab
*
* @returns
*/
private findTabCanbeReplace(): TabItem {
const mapObj = Object.fromEntries(this.tabStorage.tabsByID);
const currentTab = this.getCurrentTab();
//* Replace current tab first
const result =
currentTab && this.canbeReplace(currentTab)
? currentTab
: Object.values(mapObj).find((val) => this.canbeReplace(val));
return result;
}
private updateChildView() {
this.messageService.send({ type: 'tabContentInit', data: {} });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<!-- {{getConsoleTabs()|json}} -->
<nz-tabset
[(nzSelectedIndex)]="tabOperate.selectedIndex"
nzType="editable-card"
Expand All @@ -24,7 +23,7 @@
>
<span class="text_omit tab_text"> {{ tabStorage.tabsByID.get(uuid).title }}</span>
<!-- Close/HasEdit -->
<div class="tab-item-button-group">
<div class="tab-item-button-group flex items-center">
<span class="tab-has-edit-icon eo-tab-theme-icon" *ngIf="tabStorage.tabsByID.get(uuid).hasChanged"></span>
<button
aria-label="Close tab"
Expand Down
15 changes: 11 additions & 4 deletions src/workbench/browser/src/app/pages/api/tab/api-tab.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,19 @@
}
.tab-item-button-group {
position: absolute;
background: var(--MAIN_BG);
padding-right: 10px;
right: 0px;
margin-right: 10px;
right: 0;
}
.ant-tabs-tab-remove {
padding: 3px;
margin-left: 3px;
border-radius: 50%;
&:hover {
background-color: #eee;
}
}
}
.fixed-tab-item-container{
.fixed-tab-item-container {
font-style: initial;
}
}
Expand Down
Loading

0 comments on commit 8fd46d2

Please sign in to comment.