Skip to content
4 changes: 2 additions & 2 deletions client-app/src/desktop/AppComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {webSocketIndicator} from '@xh/hoist/cmp/websocket';
import {hoistCmp, uses} from '@xh/hoist/core';
import {appBar, appBarSeparator} from '@xh/hoist/desktop/cmp/appbar';
import {panel} from '@xh/hoist/desktop/cmp/panel';
import {tabSwitcher} from '@xh/hoist/desktop/cmp/tab';
import {dynamicTabSwitcher} from '@xh/hoist/desktop/cmp/tab';
import {welcomeMsg} from '../core/cmp/WelcomeMsg';
// @ts-ignore
import xhLogo from '../core/img/xh-toolbox-logo.png';
Expand All @@ -21,7 +21,7 @@ export const AppComponent = hoistCmp({
tbar: appBar({
icon: img({src: xhLogo, onClick: () => model.goHome()}),
title: null,
leftItems: [tabSwitcher({enableOverflow: true})],
leftItems: [dynamicTabSwitcher()],
rightItems: [
webSocketIndicator({iconOnly: true, marginRight: 4}),
appBarSeparator()
Expand Down
69 changes: 63 additions & 6 deletions client-app/src/desktop/AppModel.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import {TabContainerModel} from '@xh/hoist/cmp/tab';
import {span} from '@xh/hoist/cmp/layout';
import {TabContainerModel, TabModel} from '@xh/hoist/cmp/tab';
import {LoadSpec, managed, XH} from '@xh/hoist/core';
import {
autoRefreshAppOption,
sizingModeAppOption,
themeAppOption
} from '@xh/hoist/desktop/cmp/appOption';
import {switchInput} from '@xh/hoist/desktop/cmp/input';
import {DynamicTabSwitcherModel} from '@xh/hoist/desktop/cmp/tab/dynamic/DynamicTabSwitcherModel';
import {fmtDateTimeSec} from '@xh/hoist/format';
import {Icon} from '@xh/hoist/icon';
import {isEmpty} from 'lodash';
import {BaseAppModel} from '../BaseAppModel';
import {GitHubService} from '../core/svc/GitHubService';
import {PortfolioService} from '../core/svc/PortfolioService';
import {
Expand All @@ -16,6 +21,7 @@ import {
simpleTreeMapPanel,
splitTreeMapPanel
} from './tabs/charts';
import {examplesTab} from './tabs/examples/ExamplesTab';
import {formPanel, inputsPanel, toolbarFormPanel} from './tabs/forms';
import {
agGridView,
Expand All @@ -30,6 +36,7 @@ import {
treeGridWithCheckboxPanel,
zoneGridPanel
} from './tabs/grids';
import {homeTab} from './tabs/home/HomeTab';
import {
dashCanvasPanel,
dashContainerPanel,
Expand All @@ -39,8 +46,6 @@ import {
tileFrameContainerPanel,
vboxContainerPanel
} from './tabs/layout';
import {examplesTab} from './tabs/examples/ExamplesTab';
import {homeTab} from './tabs/home/HomeTab';
import {mobileTab} from './tabs/mobile/MobileTab';
import {
appNotificationsPanel,
Expand Down Expand Up @@ -69,9 +74,6 @@ import {
panelSizingPanel,
toolbarPanel
} from './tabs/panels';
import {fmtDateTimeSec} from '@xh/hoist/format';
import {span} from '@xh/hoist/cmp/layout';
import {BaseAppModel} from '../BaseAppModel';

export class AppModel extends BaseAppModel {
/** Singleton instance reference - installed by XH upon init. */
Expand Down Expand Up @@ -216,6 +218,61 @@ export class AppModel extends BaseAppModel {
]
});

@managed
switcherModel: DynamicTabSwitcherModel = new DynamicTabSwitcherModel({
initialFavorites: [...this.tabModel.tabs.map(it => it.id), 'github'],
persistWith: {prefKey: 'appState'},
tabContainerModel: this.tabModel,
extraTabs: [
{
id: 'github',
title: 'XH Github',
tooltip: 'Open XH Github in new window',
icon: Icon.icon({iconName: 'github', prefix: 'fab'}),
actionFn: () => XH.openWindow('https://github.com/xh')
}
],
extraMenuItems: [
{
text: 'Open Tab in New Window',
icon: Icon.openExternal(),
actionFn: (_, {tab}) => {
if (tab instanceof TabModel) {
const {params} = XH.router.getState();
XH.openWindow(
window.origin +
XH.router.buildPath(tab.containerModel.route + '.' + tab.id, params)
);
}
},
prepareFn: (me, {tab}) => {
if (!(tab instanceof TabModel)) {
me.hidden = true;
}
}
},
'-',
{
text: 'More Tabs...',
prepareFn: me => {
const tabs = this.tabModel.tabs.filter(
tab => !this.switcherModel.enabledVisibleTabs.includes(tab)
);
if (isEmpty(tabs)) {
me.hidden = true;
} else {
me.hidden = false;
me.items = tabs.map(tab => ({
text: tab.title,
icon: tab.icon,
actionFn: () => this.tabModel.activateTab(tab)
}));
}
}
}
]
});

override async initAsync() {
await super.initAsync();
await XH.installServicesAsync(GitHubService, PortfolioService);
Expand Down
Loading