diff --git a/samples/sqlservices/src/controllers/mainController.ts b/samples/sqlservices/src/controllers/mainController.ts index c7c17a135e..9990cc9c3c 100644 --- a/samples/sqlservices/src/controllers/mainController.ts +++ b/samples/sqlservices/src/controllers/mainController.ts @@ -259,18 +259,52 @@ export default class MainController implements vscode.Disposable { let editor = sqlops.workspace.createModelViewEditor('Editor webview2', { retainContextWhenHidden: true }); editor.registerContent(async view => { + let inputBox = view.modelBuilder.inputBox().component(); + let dropdown = view.modelBuilder.dropDown() + .withProperties({ + value: 'aa', + values: ['aa', 'bb', 'cc'] + }) + .component(); + let button = view.modelBuilder.button() + .withProperties({ + label: 'Run' + }).component(); + let toolbarModel = view.modelBuilder.toolbarContainer() + .withToolbarItems([{ + component: inputBox, + title: 'User name:' + }, { + component: dropdown, + title: 'favorite:' + }, { + component: button + }]).component(); + + let webview = view.modelBuilder.webView() .component(); + let flexModel = view.modelBuilder.flexContainer() .withLayout({ flexFlow: 'column', alignItems: 'stretch', height: '100%' }).withItems([ - webview - ], { flex: '1 1 50%' }) + toolbarModel, webview + ], { flex: '1' }) .component(); + // bug: #1531 + // let flexModel = view.modelBuilder.flexContainer().component(); + // flexModel.addItem(toolbarModel, { flex: '0' }); + // flexModel.addItem(webview, { flex: '1' }); + // flexModel.setLayout({ + // flexFlow: 'column', + // alignItems: 'stretch', + // height: '100%' + // }); + let templateValues = {url: 'http://whoisactive.com/docs/'}; Utils.renderTemplateHtml(path.join(__dirname, '..'), 'templateTab.html', templateValues) .then(html => { diff --git a/src/sql/parts/modelComponents/components.contribution.ts b/src/sql/parts/modelComponents/components.contribution.ts index 249dd1c3d2..79da46f03d 100644 --- a/src/sql/parts/modelComponents/components.contribution.ts +++ b/src/sql/parts/modelComponents/components.contribution.ts @@ -5,6 +5,7 @@ import FlexContainer from './flexContainer.component'; import FormContainer from './formContainer.component'; +import ToolbarContainer from './toolbarContainer.component'; import GroupContainer from './groupContainer.component'; import CardComponent from './card.component'; import InputBoxComponent from './inputbox.component'; @@ -23,6 +24,9 @@ registerComponentType(FLEX_CONTAINER, ModelComponentTypes.FlexContainer, FlexCon export const FORM_CONTAINER = 'form-container'; registerComponentType(FORM_CONTAINER, ModelComponentTypes.Form, FormContainer); +export const TOOLBAR_CONTAINER = 'toolbar-container'; +registerComponentType(TOOLBAR_CONTAINER, ModelComponentTypes.Toolbar, ToolbarContainer); + export const GROUP_CONTAINER = 'group-container'; registerComponentType(GROUP_CONTAINER, ModelComponentTypes.Group, GroupContainer); diff --git a/src/sql/parts/modelComponents/toolbarContainer.component.ts b/src/sql/parts/modelComponents/toolbarContainer.component.ts new file mode 100644 index 0000000000..792e3bdafa --- /dev/null +++ b/src/sql/parts/modelComponents/toolbarContainer.component.ts @@ -0,0 +1,91 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import 'vs/css!./toolbarLayout'; + +import { + Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver, + ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList, AfterViewInit +} from '@angular/core'; + +import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces'; + +import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service'; +import { ContainerBase } from 'sql/parts/modelComponents/componentBase'; +import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component'; +import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service'; + +export interface ToolbarItemConfig { + title?: string; +} + +class ToolbarItem { + constructor(public descriptor: IComponentDescriptor, public config: ToolbarItemConfig) { } +} + +@Component({ + selector: 'modelview-toolbarContainer', + template: ` +
+ +
+
+ {{getItemTitle(item)}} +
+
+ + +
+
+
+
+ ` +}) +export default class ToolbarContainer extends ContainerBase implements IComponent, OnDestroy, AfterViewInit { + @Input() descriptor: IComponentDescriptor; + @Input() modelStore: IModelStore; + + @ViewChildren(ModelComponentWrapper) private _componentWrappers: QueryList; + @ViewChild('container', { read: ElementRef }) private _container: ElementRef; + + constructor( + @Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface, + @Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) { + super(changeRef); + } + + ngOnInit(): void { + this.baseInit(); + } + + ngOnDestroy(): void { + this.baseDestroy(); + } + + ngAfterViewInit(): void { + } + + /// IComponent implementation + + public layout(): void { + if (this._componentWrappers) { + this._componentWrappers.forEach(wrapper => { + wrapper.layout(); + }); + } + } + + public setLayout(layout: any): void { + this.layout(); + } + + private getItemTitle(item: ToolbarItem): string { + let itemConfig = item.config; + return itemConfig ? itemConfig.title : ''; + } + + private hasTitle(item: ToolbarItem): boolean { + return item && item.config && item.config.title !== undefined; + } +} diff --git a/src/sql/parts/modelComponents/toolbarLayout.css b/src/sql/parts/modelComponents/toolbarLayout.css new file mode 100644 index 0000000000..ad6819e858 --- /dev/null +++ b/src/sql/parts/modelComponents/toolbarLayout.css @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.modelview-toolbar-container { + display: flex; + padding: 15px; + justify-content: flex-start; + line-height: 1.4em; + white-space: nowrap; + flex-wrap: wrap; + border-bottom-width: .5px; + border-bottom-style: solid; + box-sizing: border-box; + border-bottom-color: rgba(128, 128, 128, 0.35); +} + +.modelview-toolbar-container .modelview-toolbar-item { + flex: 0 0; + flex-direction: row; + display: flex; + padding-left: 10px; +} + +.modelview-toolbar-container .modelview-toolbar-title { + padding-right: 5px; + font-size: 14px; + cursor: pointer; + margin: auto; +} + +.modelview-toolbar-container .modelview-toolbar-component .select-box, +.modelview-toolbar-container .modelview-toolbar-component .monaco-inputbox { + width: 200px; + height: 25px; +} + +.modelview-toolbar-container .modelview-toolbar-component button { + height: 25px; +} + +.modelview-toolbar-container .modelview-toolbar-component button .monaco-text-button { + padding: 0px +} \ No newline at end of file diff --git a/src/sql/sqlops.proposed.d.ts b/src/sql/sqlops.proposed.d.ts index 689f584165..196cc163e2 100644 --- a/src/sql/sqlops.proposed.d.ts +++ b/src/sql/sqlops.proposed.d.ts @@ -30,6 +30,7 @@ declare module 'sqlops' { dashboardWebview(webviewId: string): ComponentBuilder; formContainer(): FormBuilder; groupContainer(): GroupBuilder; + toolbarContainer(): ToolbarBuilder; } export interface ComponentBuilder { @@ -49,6 +50,24 @@ declare module 'sqlops' { export interface GroupBuilder extends ContainerBuilder { } + export interface ToolbarBuilder extends ContainerBuilder { + withToolbarItems(components: ToolbarComponent[]): ContainerBuilder; + + /** + * Creates a collection of child components and adds them all to this container + * + * @param toolbarComponents the definitions + */ + addToolbarItems(toolbarComponents: Array): void; + + /** + * Creates a child component and adds it to this container. + * + * @param toolbarComponent the component to be added + */ + addToolbarItem(toolbarComponent: ToolbarComponent): void; + } + export interface FormBuilder extends ContainerBuilder { withFormItems(components: FormComponent[], itemLayout?: FormItemLayout): ContainerBuilder; @@ -104,6 +123,11 @@ declare module 'sqlops' { actions?: Component[]; } + export interface ToolbarComponent { + component: Component; + title?: string; + } + /** * A component that contains other components */ @@ -212,6 +236,9 @@ declare module 'sqlops' { export interface GroupContainer extends Container { } + export interface ToolbarContainer extends Container { + } + /** * Describes an action to be shown in the UI, with a user-readable label * and a callback to execute the action diff --git a/src/sql/workbench/api/common/sqlExtHostTypes.ts b/src/sql/workbench/api/common/sqlExtHostTypes.ts index ca6fa2aa60..ba7239d209 100644 --- a/src/sql/workbench/api/common/sqlExtHostTypes.ts +++ b/src/sql/workbench/api/common/sqlExtHostTypes.ts @@ -77,7 +77,8 @@ export enum ModelComponentTypes { DashboardWidget, DashboardWebview, Form, - Group + Group, + Toolbar } export interface IComponentShape { diff --git a/src/sql/workbench/api/node/extHostModelView.ts b/src/sql/workbench/api/node/extHostModelView.ts index 84013d9b96..3d3a804a07 100644 --- a/src/sql/workbench/api/node/extHostModelView.ts +++ b/src/sql/workbench/api/node/extHostModelView.ts @@ -45,6 +45,13 @@ class ModelBuilderImpl implements sqlops.ModelBuilder { return container; } + toolbarContainer(): sqlops.ToolbarBuilder { + let id = this.getNextComponentId(); + let container = new ToolbarContainerBuilder(this._proxy, this._handle, ModelComponentTypes.Toolbar, id); + this._componentBuilders.set(id, container); + return container; + } + groupContainer(): sqlops.GroupBuilder { let id = this.getNextComponentId(); let container: ContainerBuilderImpl = new ContainerBuilderImpl(this._proxy, this._handle, ModelComponentTypes.Group, id); @@ -256,6 +263,34 @@ class FormContainerBuilder extends ContainerBuilderImpl implements sqlops.ToolbarBuilder { + withToolbarItems(components: sqlops.ToolbarComponent[]): sqlops.ContainerBuilder { + this._component.itemConfigs = components.map(item => { + return this.convertToItemConfig(item); + }); + return this; + } + + private convertToItemConfig(toolbarComponent: sqlops.ToolbarComponent): InternalItemConfig { + let componentWrapper = toolbarComponent.component as ComponentWrapper; + + return new InternalItemConfig(componentWrapper, { + title: toolbarComponent.title + }); + } + + addToolbarItems(toolbarComponent: Array): void { + toolbarComponent.forEach(toolbarComponent => { + this.addToolbarItem(toolbarComponent); + }); + } + + addToolbarItem(toolbarComponent: sqlops.ToolbarComponent): void { + let itemImpl = this.convertToItemConfig(toolbarComponent); + this._component.addItem(toolbarComponent.component as ComponentWrapper, itemImpl.config); + } +} + class InternalItemConfig { constructor(private _component: ComponentWrapper, public config: any) { }