modelview dashboard (#9784)

* modelview dashboard

* styles

* toolbar support

* spaces

* add tab icon support
This commit is contained in:
Alan Ren
2020-04-01 17:30:33 -07:00
committed by GitHub
parent dd56908a06
commit 41d21d799c
12 changed files with 152 additions and 49 deletions

View File

@@ -499,22 +499,23 @@ class TabbedPanelComponentBuilder extends ContainerBuilderImpl<azdata.TabbedPane
items.forEach(item => {
if (item && 'tabs' in item) {
item.tabs.forEach(tab => {
itemConfigs.push(this.toItemConfig(tab.content, tab.title, tab.id, item.title));
itemConfigs.push(this.toItemConfig(tab.content, tab.title, tab.id, item.title, tab.icon));
});
} else {
const tab = <azdata.Tab>item;
itemConfigs.push(this.toItemConfig(tab.content, tab.title, tab.id));
itemConfigs.push(this.toItemConfig(tab.content, tab.title, tab.id, undefined, tab.icon));
}
});
this._component.itemConfigs = itemConfigs;
return this;
}
toItemConfig(content: azdata.Component, title: string, id?: string, group?: string): InternalItemConfig {
toItemConfig(content: azdata.Component, title: string, id?: string, group?: string, icon?: string | URI | { light: string | URI; dark: string | URI }): InternalItemConfig {
return new InternalItemConfig(content as ComponentWrapper, {
title: title,
group: group,
id: id
id: id,
icon: icon
});
}
}

View File

@@ -457,6 +457,57 @@ class WizardImpl implements azdata.window.Wizard {
}
}
class ModelViewDashboardImpl implements azdata.window.ModelViewDashboard {
constructor(
private _editor: ModelViewEditorImpl
) {
}
registerTabs(handler: (view: azdata.ModelView) => Thenable<(azdata.DashboardTab | azdata.DashboardTabGroup)[]>): void {
this._editor.registerContent(async (view) => {
const dashboardTabs = await handler(view);
const tabs: (azdata.TabGroup | azdata.Tab)[] = [];
dashboardTabs.forEach((item: azdata.DashboardTab | azdata.DashboardTabGroup) => {
if ('tabs' in item) {
tabs.push(<azdata.TabGroup>{
title: item.title,
tabs: item.tabs.map(tab => {
return this.createTab(tab, view);
})
});
} else {
tabs.push(this.createTab(item, view));
}
});
const tabbedPanel = view.modelBuilder.tabbedPanel().withTabs(tabs).withLayout({
orientation: 'vertical',
showIcon: true
}).component();
return view.initializeModel(tabbedPanel);
});
}
open(): Thenable<void> {
return this._editor.openEditor();
}
createTab(tab: azdata.DashboardTab, view: azdata.ModelView): azdata.Tab {
if (tab.toolbar) {
const flexContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
flexContainer.addItem(tab.toolbar, { flex: '0 0 auto' });
flexContainer.addItem(tab.content, { flex: '1 1 auto' });
return {
title: tab.title,
id: tab.id,
content: flexContainer,
icon: tab.icon
};
} else {
return tab;
}
}
}
export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
private static _currentHandle = 0;
@@ -562,6 +613,11 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
return editor;
}
public createModelViewDashboard(title: string, extension: IExtensionDescription): azdata.window.ModelViewDashboard {
const editor = this.createModelViewEditor(title, extension, { supportsSave: false }) as ModelViewEditorImpl;
return new ModelViewDashboardImpl(editor);
}
public updateDialogContent(dialog: azdata.window.Dialog): void {
let handle = this.getHandle(dialog);
let tabs = dialog.content;

View File

@@ -418,6 +418,9 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp
createWizard(title: string): azdata.window.Wizard {
return extHostModelViewDialog.createWizard(title);
},
createModelViewDashboard(title: string): azdata.window.ModelViewDashboard {
return extHostModelViewDialog.createModelViewDashboard(title, extension);
},
MessageLevel: sqlExtHostTypes.MessageLevel
};

View File

@@ -839,4 +839,5 @@ export enum TabOrientation {
export interface TabbedPanelLayout {
orientation: TabOrientation;
showIcon: boolean;
}

View File

@@ -332,6 +332,7 @@ export abstract class ContainerBase<T> extends ComponentBase {
}
}));
this._changeRef.detectChanges();
this.onItemsUpdated();
return;
}
@@ -343,6 +344,7 @@ export abstract class ContainerBase<T> extends ComponentBase {
if (index >= 0) {
this.items.splice(index, 1);
this._changeRef.detectChanges();
this.onItemsUpdated();
return true;
}
return false;
@@ -373,4 +375,7 @@ export abstract class ContainerBase<T> extends ComponentBase {
}
abstract setLayout(layout: any): void;
protected onItemsUpdated(): void {
}
}

View File

@@ -14,19 +14,20 @@
border-width: 0px;
}
.vs-dark .tabbedpanel-component .tabbedPanel .tabContainer, .hc-black .tabbedpanel-component .tabbedPanel .tabContainer {
border-color: rgba(128, 128, 128, 0.5);;
.vs-dark .tabbedpanel-component .tabbedPanel .tabContainer,
.hc-black .tabbedpanel-component .tabbedPanel .tabContainer {
border-color: rgba(128, 128, 128, 0.5);
}
.tabbedpanel-component .tabbedPanel.vertical .tabContainer {
.tabbedpanel-component .tabbedPanel.vertical > .title .tabContainer {
border-right-width: 1px;
}
.tabbedpanel-component .tabbedPanel.horizontal .tabContainer {
.tabbedpanel-component .tabbedPanel.horizontal > .title .tabContainer {
border-bottom-width: 1px;
}
.tabbedpanel-component .tabbedPanel .tab>.tabLabel.active {
.tabbedpanel-component .tabbedPanel .tab > .tabLabel.active {
border-bottom: 0px solid;
}
@@ -45,9 +46,10 @@
}
.tabbedpanel-component .tabList .tab-header.active {
background-color: rgb(237, 235, 233);
background-color: #E1F0FE;
}
.vs-dark .tabbedpanel-component .tabList .tab-header.active, .hc-black .tabbedpanel-component .tabList .tab-header.active {
.vs-dark .tabbedpanel-component .tabList .tab-header.active,
.hc-black .tabbedpanel-component .tabList .tab-header.active {
background-color: rgba(128, 128, 128, 0.5);
}

View File

@@ -7,10 +7,9 @@
<div class="tabbedpanel-component">
<panel (onTabChange)="handleTabChange($event)">
<tab [visibilityType]="'visibility'" *ngFor="let tab of tabs" [title]="tab.title" class="fullsize"
[identifier]="tab.id" [type]="tab.type">
[identifier]="tab.id" [type]="tab.type" [iconClass]="tab.iconClass">
<ng-template>
<ng-container *ngIf="tab.type === 'tab'">
{{tab.title}}
<model-component-wrapper [descriptor]="tab.content" [modelStore]="modelStore">
</model-component-wrapper>
</ng-container>

View File

@@ -10,11 +10,13 @@ import { TabOrientation, TabbedPanelLayout } from 'sql/workbench/api/common/sqlE
import { ContainerBase } from 'sql/workbench/browser/modelComponents/componentBase';
import { ComponentEventType, IComponent, IComponentDescriptor, IModelStore } from 'sql/platform/dashboard/browser/interfaces';
import 'vs/css!./media/tabbedPanel';
import { IUserFriendlyIcon, createIconCssClass } from 'sql/workbench/browser/modelComponents/iconUtils';
export interface TabConfig {
title: string;
id?: string;
group: string;
icon?: IUserFriendlyIcon;
}
interface Tab {
@@ -22,6 +24,7 @@ interface Tab {
content?: IComponentDescriptor;
id?: string;
type: TabType;
iconClass?: string;
}
@Component({
@@ -56,7 +59,7 @@ export default class TabbedPanelComponent extends ContainerBase<TabConfig> imple
this._panel.options = {
showTabsWhenOne: true,
layout: layout.orientation === TabOrientation.Horizontal ? NavigationBarLayout.horizontal : NavigationBarLayout.vertical,
showIcon: false
showIcon: layout.showIcon
};
}
@@ -86,6 +89,7 @@ export default class TabbedPanelComponent extends ContainerBase<TabConfig> imple
title: item.config.title,
id: item.config.id,
content: item.descriptor,
iconClass: item.config.icon ? createIconCssClass(item.config.icon) : undefined,
type: 'tab'
});
}
@@ -93,4 +97,11 @@ export default class TabbedPanelComponent extends ContainerBase<TabConfig> imple
}
return this._tabs;
}
onItemsUpdated(): void {
const firstTabIndex = this.tabs.findIndex(tab => tab.type === 'tab');
if (firstTabIndex >= 0) {
this._panel.selectTab(firstTabIndex);
}
}
}