diff --git a/extensions/mssql/package.json b/extensions/mssql/package.json index de1129b243..faeba3d57c 100644 --- a/extensions/mssql/package.json +++ b/extensions/mssql/package.json @@ -658,7 +658,7 @@ } }, "dependencies": { - "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.1.7", + "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.1.8.2", "opener": "^1.4.3", "service-downloader": "github:anthonydresser/service-downloader#0.1.2", "vscode-extension-telemetry": "^0.0.15" diff --git a/extensions/mssql/src/config.json b/extensions/mssql/src/config.json index 9c779665b9..fb4dd8244b 100644 --- a/extensions/mssql/src/config.json +++ b/extensions/mssql/src/config.json @@ -1,6 +1,6 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", - "version": "1.4.0-alpha.35", + "version": "1.4.0-alpha.44", "downloadFileNames": { "Windows_86": "win-x86-netcoreapp2.1.zip", "Windows_64": "win-x64-netcoreapp2.1.zip", diff --git a/samples/sqlservices/src/controllers/mainController.ts b/samples/sqlservices/src/controllers/mainController.ts index f836ffa032..fd6073f67c 100644 --- a/samples/sqlservices/src/controllers/mainController.ts +++ b/samples/sqlservices/src/controllers/mainController.ts @@ -82,7 +82,8 @@ export default class MainController implements vscode.Disposable { tab1.registerContent(async (view) => { let inputBox = view.modelBuilder.inputBox() .withProperties({ - //width: 300 + multiline: true, + height: 100 }).component(); let inputBoxWrapper = view.modelBuilder.loadingComponent().withItem(inputBox).component(); inputBoxWrapper.loading = false; diff --git a/src/sql/base/browser/ui/button/button.ts b/src/sql/base/browser/ui/button/button.ts index 320d798770..7766563865 100644 --- a/src/sql/base/browser/ui/button/button.ts +++ b/src/sql/base/browser/ui/button/button.ts @@ -33,4 +33,12 @@ export class Button extends vsButton { public set title(value: string) { this.$el.title(value); } + + public setHeight(value: string) { + this.$el.style('height', value); + } + + public setWidth(value: string) { + this.$el.style('width', value); + } } \ No newline at end of file diff --git a/src/sql/base/browser/ui/inputBox/inputBox.ts b/src/sql/base/browser/ui/inputBox/inputBox.ts index e13df70934..dd139a151e 100644 --- a/src/sql/base/browser/ui/inputBox/inputBox.ts +++ b/src/sql/base/browser/ui/inputBox/inputBox.ts @@ -32,6 +32,7 @@ export class InputBox extends vsInputBox { private _onLoseFocus = this._register(new Emitter()); public onLoseFocus: Event = this._onLoseFocus.event; + private _isTextAreaInput: boolean; constructor(container: HTMLElement, contextViewProvider: IContextViewProvider, options?: IInputOptions) { super(container, contextViewProvider, options); @@ -48,6 +49,10 @@ export class InputBox extends vsInputBox { self._onLoseFocus.fire({ value: self.value, hasChanged: self._lastLoseFocusValue !== self.value }); self._lastLoseFocusValue = self.value; }); + + if (options && options.type === 'textarea') { + this._isTextAreaInput = true; + } } public style(styles: IInputBoxStyles): void { @@ -67,6 +72,20 @@ export class InputBox extends vsInputBox { this.applyStyles(); } + public set rows(value: number) { + this.inputElement.setAttribute('rows', value.toString()); + } + + public set columns(value: number) { + this.inputElement.setAttribute('cols', value.toString()); + } + + public layout(): void { + if (!this._isTextAreaInput) { + super.layout(); + } + } + public disable(): void { super.disable(); this.inputBackground = this.disabledInputBackground; @@ -75,6 +94,12 @@ export class InputBox extends vsInputBox { this.applyStyles(); } + public setHeight(value: string) { + if (this._isTextAreaInput) { + this.inputElement.style.height = value; + } + } + public isEnabled(): boolean { return !this.inputElement.hasAttribute('disabled'); } diff --git a/src/sql/base/browser/ui/selectBox/selectBox.ts b/src/sql/base/browser/ui/selectBox/selectBox.ts index 39a2f20bcb..fbc3af902f 100644 --- a/src/sql/base/browser/ui/selectBox/selectBox.ts +++ b/src/sql/base/browser/ui/selectBox/selectBox.ts @@ -115,8 +115,7 @@ export class SelectBox extends vsSelectBox { } public enable(): void { - //@SQLTODO - //this.selectElement.disabled = false; + this.selectElement.disabled = false; this.selectBackground = this.enabledSelectBackground; this.selectForeground = this.enabledSelectForeground; this.selectBorder = this.enabledSelectBorder; @@ -124,8 +123,7 @@ export class SelectBox extends vsSelectBox { } public disable(): void { - //@SQLTODO - //this.selectElement.disabled = true; + this.selectElement.disabled = true; this.selectBackground = this.disabledSelectBackground; this.selectForeground = this.disabledSelectForeground; this.selectBorder = this.disabledSelectBorder; diff --git a/src/sql/common/theme/styler.ts b/src/sql/common/theme/styler.ts index bccc45d40f..df2b8e936f 100644 --- a/src/sql/common/theme/styler.ts +++ b/src/sql/common/theme/styler.ts @@ -72,6 +72,7 @@ export function attachInputBoxStyler(widget: IThemable, themeService: IThemeServ export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeService, style?: { selectBackground?: cr.ColorIdentifier, + selectListBackground?: cr.ColorIdentifier, selectForeground?: cr.ColorIdentifier, selectBorder?: cr.ColorIdentifier, disabledSelectBackground?: cr.ColorIdentifier, @@ -81,10 +82,17 @@ export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeSer inputValidationWarningBorder?: cr.ColorIdentifier, inputValidationWarningBackground?: cr.ColorIdentifier, inputValidationErrorBorder?: cr.ColorIdentifier, - inputValidationErrorBackground?: cr.ColorIdentifier + inputValidationErrorBackground?: cr.ColorIdentifier, + focusBorder?: cr.ColorIdentifier, + listFocusBackground?: cr.ColorIdentifier, + listFocusForeground?: cr.ColorIdentifier, + listFocusOutline?: cr.ColorIdentifier, + listHoverBackground?: cr.ColorIdentifier, + listHoverForeground?: cr.ColorIdentifier }): IDisposable { return attachStyler(themeService, { selectBackground: (style && style.selectBackground) || cr.selectBackground, + selectListBackground: (style && style.selectListBackground) || cr.selectListBackground, selectForeground: (style && style.selectForeground) || cr.selectForeground, selectBorder: (style && style.selectBorder) || cr.selectBorder, disabledSelectBackground: (style && style.disabledSelectBackground) || sqlcolors.disabledInputBackground, @@ -94,7 +102,14 @@ export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeSer inputValidationWarningBorder: (style && style.inputValidationWarningBorder) || cr.inputValidationWarningBorder, inputValidationWarningBackground: (style && style.inputValidationWarningBackground) || cr.inputValidationWarningBackground, inputValidationErrorBorder: (style && style.inputValidationErrorBorder) || cr.inputValidationErrorBorder, - inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || cr.inputValidationErrorBackground + inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || cr.inputValidationErrorBackground, + focusBorder: (style && style.focusBorder) || cr.focusBorder, + listFocusBackground: (style && style.listFocusBackground) || cr.listFocusBackground, + listFocusForeground: (style && style.listFocusForeground) || cr.listFocusForeground, + listFocusOutline: (style && style.listFocusOutline) || cr.activeContrastBorder, + listHoverBackground: (style && style.listHoverBackground) || cr.listHoverBackground, + listHoverForeground: (style && style.listHoverForeground) || cr.listHoverForeground, + listHoverOutline: (style && style.listFocusOutline) || cr.activeContrastBorder }, widget); } diff --git a/src/sql/parts/insights/browser/insightsDialogView.ts b/src/sql/parts/insights/browser/insightsDialogView.ts index 897d5ef522..ccb776140a 100644 --- a/src/sql/parts/insights/browser/insightsDialogView.ts +++ b/src/sql/parts/insights/browser/insightsDialogView.ts @@ -168,13 +168,16 @@ export class InsightsDialogView extends Modal { this._splitView = new SplitView(container); + const itemsHeaderTitle = nls.localize("insights.dialog.items", "Items"); + const itemsDetailHeaderTitle = nls.localize("insights.dialog.itemDetails", "Item Details"); + this._topTableData = new TableDataView(); this._bottomTableData = new TableDataView(); - let topTableView = new TableCollapsibleView(nls.localize("insights.dialog.items", "Items"), { sizing: ViewSizing.Flexible, ariaHeaderLabel: 'title' }, this._topTableData, this._topColumns, { forceFitColumns: true }); + let topTableView = new TableCollapsibleView(itemsHeaderTitle, { sizing: ViewSizing.Flexible, ariaHeaderLabel: itemsHeaderTitle }, this._topTableData, this._topColumns, { forceFitColumns: true }); this._topTable = topTableView.table; topTableView.addContainerClass('insights'); this._topTable.setSelectionModel(new RowSelectionModel()); - let bottomTableView = new TableCollapsibleView(nls.localize("insights.dialog.itemDetails", "Item Details"), { sizing: ViewSizing.Flexible, ariaHeaderLabel: 'title' }, this._bottomTableData, this._bottomColumns, { forceFitColumns: true }); + let bottomTableView = new TableCollapsibleView(itemsDetailHeaderTitle, { sizing: ViewSizing.Flexible, ariaHeaderLabel: itemsDetailHeaderTitle }, this._bottomTableData, this._bottomColumns, { forceFitColumns: true }); this._bottomTable = bottomTableView.table; this._bottomTable.setSelectionModel(new RowSelectionModel()); diff --git a/src/sql/parts/modelComponents/button.component.ts b/src/sql/parts/modelComponents/button.component.ts index 1c0213e36a..b32b075662 100644 --- a/src/sql/parts/modelComponents/button.component.ts +++ b/src/sql/parts/modelComponents/button.component.ts @@ -15,7 +15,7 @@ import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } fro import { attachButtonStyler } from 'sql/common/theme/styler'; import { Button } from 'sql/base/browser/ui/button/button'; -import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; +import { SIDE_BAR_BACKGROUND, SIDE_BAR_TITLE_FOREGROUND } from 'vs/workbench/common/theme'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { attachListStyler } from 'vs/platform/theme/common/styler'; import URI from 'vs/base/common/uri'; @@ -55,13 +55,11 @@ export default class ButtonComponent extends ComponentBase implements IComponent ngAfterViewInit(): void { if (this._inputContainer) { - - this._button = new Button(this._inputContainer.nativeElement); this._register(this._button); this._register(attachButtonStyler(this._button, this.themeService, { - buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND + buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND, buttonForeground: SIDE_BAR_TITLE_FOREGROUND })); this._register(this._button.onDidClick(e => { this._onEventEmitter.fire({ @@ -94,6 +92,12 @@ export default class ButtonComponent extends ComponentBase implements IComponent super.setProperties(properties); this._button.enabled = this.enabled; this._button.label = this.label; + if (this.width) { + this._button.setWidth(this.width.toString()); + } + if (this.height) { + this._button.setWidth(this.height.toString()); + } this.updateIcon(); } diff --git a/src/sql/parts/modelComponents/checkbox.component.ts b/src/sql/parts/modelComponents/checkbox.component.ts index dce4381fca..c0f894b065 100644 --- a/src/sql/parts/modelComponents/checkbox.component.ts +++ b/src/sql/parts/modelComponents/checkbox.component.ts @@ -50,7 +50,7 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone this._register(this._input); this._register(this._input.onChange(e => { - this.value = this._input.checked; + this.checked = this._input.checked; this._onEventEmitter.fire({ eventType: ComponentEventType.onDidChange, args: e @@ -88,10 +88,10 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone // CSS-bound properties public get checked(): boolean { - return this.getPropertyOrDefault((props) => props.value, false); + return this.getPropertyOrDefault((props) => props.checked, false); } - public set value(newValue: boolean) { + public set checked(newValue: boolean) { this.setPropertyFromUI((properties, value) => { properties.checked = value; }, newValue); } diff --git a/src/sql/parts/modelComponents/componentBase.ts b/src/sql/parts/modelComponents/componentBase.ts index 3c6ecad832..fa8d2a46db 100644 --- a/src/sql/parts/modelComponents/componentBase.ts +++ b/src/sql/parts/modelComponents/componentBase.ts @@ -12,7 +12,7 @@ import { import * as types from 'vs/base/common/types'; import { IComponent, IComponentDescriptor, IModelStore, IComponentEventArgs, ComponentEventType } from 'sql/parts/modelComponents/interfaces'; -import { FlexLayout, FlexItemLayout } from 'sqlops'; +import * as sqlops from 'sqlops'; import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost.directive'; import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service'; import { Event, Emitter } from 'vs/base/common/event'; @@ -112,7 +112,36 @@ export abstract class ComponentBase extends Disposable implements IComponent, On this.setProperties(properties); } + public get height(): number | string { + return this.getPropertyOrDefault((props) => props.height, undefined); + } + + public set height(newValue: number | string) { + this.setPropertyFromUI((props, value) => props.height = value, newValue); + } + + public get width(): number | string { + return this.getPropertyOrDefault((props) => props.width, undefined); + } + + public set width(newValue: number | string) { + this.setPropertyFromUI((props, value) => props.width = value, newValue); + } + + protected convertSizeToNumber(size: number | string): number { + if (size && typeof (size) === 'string') { + if (size.toLowerCase().endsWith('px')) { + return +size.replace('px', ''); + } + return 0; + } + return +size; + } + protected convertSize(size: number | string): string { + if (types.isUndefinedOrNull(size)) { + return ''; + } let convertedSize: string = size ? size.toString() : '100%'; if (!convertedSize.toLowerCase().endsWith('px') && !convertedSize.toLowerCase().endsWith('%')) { convertedSize = convertedSize + 'px'; diff --git a/src/sql/parts/modelComponents/dropdown.component.ts b/src/sql/parts/modelComponents/dropdown.component.ts index 478b9f234c..4665a0ddda 100644 --- a/src/sql/parts/modelComponents/dropdown.component.ts +++ b/src/sql/parts/modelComponents/dropdown.component.ts @@ -69,7 +69,7 @@ export default class DropDownComponent extends ComponentBase implements ICompone this._register(attachEditableDropdownStyler(this._editableDropdown, this.themeService)); this._register(this._editableDropdown.onValueChange(e => { if (this.editable) { - this.value = this._editableDropdown.value; + this.setSelectedValue(this._editableDropdown.value); this._onEventEmitter.fire({ eventType: ComponentEventType.onDidChange, args: e @@ -78,14 +78,14 @@ export default class DropDownComponent extends ComponentBase implements ICompone })); } if (this._dropDownContainer) { - this._selectBox = new SelectBox(this.values || [], this.value, this.contextViewService, this._dropDownContainer.nativeElement); + this._selectBox = new SelectBox(this.getValues(), this.getSelectedValue(), this.contextViewService, this._dropDownContainer.nativeElement); this._selectBox.render(this._dropDownContainer.nativeElement); this._register(this._selectBox); this._register(attachSelectBoxStyler(this._selectBox, this.themeService)); this._register(this._selectBox.onDidSelect(e => { if (!this.editable) { - this.value = this._selectBox.value; + this.setSelectedValue(this._selectBox.value); this._onEventEmitter.fire({ eventType: ComponentEventType.onDidChange, args: e @@ -113,14 +113,14 @@ export default class DropDownComponent extends ComponentBase implements ICompone public setProperties(properties: { [key: string]: any; }): void { super.setProperties(properties); if (this.editable) { - this._editableDropdown.values = this.values ? this.values : []; + this._editableDropdown.values = this.getValues(); if (this.value) { - this._editableDropdown.value = this.value; + this._editableDropdown.value = this.getSelectedValue(); } this._editableDropdown.enabled = this.enabled; } else { - this._selectBox.setOptions(this.values || []); - this._selectBox.selectWithOptionName(this.value); + this._selectBox.setOptions(this.getValues()); + this._selectBox.selectWithOptionName(this.getSelectedValue()); if (this.enabled) { this._selectBox.enable(); } else { @@ -129,6 +129,39 @@ export default class DropDownComponent extends ComponentBase implements ICompone } } + private getValues(): string[] { + if (this.values && this.values.length > 0) { + if (!this.valuesHaveDisplayName()) { + return this.values as string[]; + } else { + return (this.values).map(v => v.displayName); + } + } + return []; + } + + private valuesHaveDisplayName(): boolean { + return typeof (this.values[0]) !== 'string'; + } + + private getSelectedValue(): string { + if (this.values && this.valuesHaveDisplayName()) { + let valueCategory = (this.values).find(v => v.name === this.value); + return valueCategory && valueCategory.displayName; + } else { + return this.value; + } + } + + private setSelectedValue(newValue: string): void { + if (this.values && this.valuesHaveDisplayName()) { + let valueCategory = (this.values).find(v => v.displayName === newValue); + this.value = valueCategory && valueCategory.name; + } else { + this.value = newValue; + } + } + // CSS-bound properties private get value(): string { @@ -139,11 +172,11 @@ export default class DropDownComponent extends ComponentBase implements ICompone return this.getPropertyOrDefault((props) => props.editable, false); } - public getEditableDisplay() : string { + public getEditableDisplay(): string { return this.editable ? '' : 'none'; } - public getNotEditableDisplay() : string { + public getNotEditableDisplay(): string { return !this.editable ? '' : 'none'; } @@ -151,12 +184,12 @@ export default class DropDownComponent extends ComponentBase implements ICompone this.setPropertyFromUI(this.setValueProperties, newValue); } - private get values(): string[] { - return this.getPropertyOrDefault((props) => props.values, undefined); + private get values(): string[] | sqlops.CategoryValue[] { + return this.getPropertyOrDefault((props) => props.values, undefined); } - private set values(newValue: string[]) { - this.setPropertyFromUI(this.setValuesProperties, newValue); + private set values(newValue: string[] | sqlops.CategoryValue[]) { + this.setPropertyFromUI(this.setValuesProperties, newValue); } private setValueProperties(properties: sqlops.DropDownProperties, value: string): void { diff --git a/src/sql/parts/modelComponents/flexContainer.component.ts b/src/sql/parts/modelComponents/flexContainer.component.ts index cd8f2d43c9..78c1c5a92b 100644 --- a/src/sql/parts/modelComponents/flexContainer.component.ts +++ b/src/sql/parts/modelComponents/flexContainer.component.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./flexContainer'; -import { Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver, +import { + Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver, ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList, } from '@angular/core'; @@ -18,13 +19,13 @@ import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentW import types = require('vs/base/common/types'); class FlexItem { - constructor(public descriptor: IComponentDescriptor, public config: FlexItemLayout) {} + constructor(public descriptor: IComponentDescriptor, public config: FlexItemLayout) { } } @Component({ template: `
+ [style.alignItems]="alignItems" [style.alignContent]="alignContent" [style.height]="height" [style.width]="width">
@@ -40,6 +41,7 @@ export default class FlexContainer extends ContainerBase impleme private _alignItems: string; private _alignContent: string; private _height: string; + private _width: string; constructor(@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) { super(changeRef); @@ -58,18 +60,14 @@ export default class FlexContainer extends ContainerBase impleme /// IComponent implementation - public setLayout (layout: FlexLayout): void { + public setLayout(layout: FlexLayout): void { this._flexFlow = layout.flexFlow ? layout.flexFlow : ''; this._justifyContent = layout.justifyContent ? layout.justifyContent : ''; this._alignItems = layout.alignItems ? layout.alignItems : ''; this._alignContent = layout.alignContent ? layout.alignContent : ''; - if (types.isUndefinedOrNull(layout.height)) { - this._height = ''; - } else if (types.isNumber(layout.height)) { - this._height = layout.height + 'px'; - } else { - this._height = layout.height; - } + this._height = this.convertSize(layout.height); + this._width = this.convertSize(layout.width); + this.layout(); } @@ -90,6 +88,10 @@ export default class FlexContainer extends ContainerBase impleme return this._height; } + public get width(): string { + return this._width; + } + public get alignContent(): string { return this._alignContent; } diff --git a/src/sql/parts/modelComponents/formContainer.component.ts b/src/sql/parts/modelComponents/formContainer.component.ts index b6e4cc9011..5afddcb365 100644 --- a/src/sql/parts/modelComponents/formContainer.component.ts +++ b/src/sql/parts/modelComponents/formContainer.component.ts @@ -35,10 +35,10 @@ class FormItem { @Component({ template: ` -
+
-
- +
+
{{getItemTitle(item)}}
@@ -69,7 +69,6 @@ class FormItem {
-
@@ -113,7 +112,11 @@ export default class FormContainer extends ContainerBase impleme } private getFormWidth(): string { - return this._formLayout && this._formLayout.width ? +this._formLayout.width + 'px' : '100%'; + return this.convertSize(this._formLayout && this._formLayout.width); + } + + private getFormHeight(): string { + return this.convertSize(this._formLayout && this._formLayout.height); } private getComponentWidth(item: FormItem): string { diff --git a/src/sql/parts/modelComponents/inputbox.component.ts b/src/sql/parts/modelComponents/inputbox.component.ts index a881731edd..4506ecb235 100644 --- a/src/sql/parts/modelComponents/inputbox.component.ts +++ b/src/sql/parts/modelComponents/inputbox.component.ts @@ -20,19 +20,23 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { Event, Emitter } from 'vs/base/common/event'; import * as nls from 'vs/nls'; +import { TextAreaInput } from 'vs/editor/browser/controller/textAreaInput'; @Component({ selector: 'modelview-inputBox', template: ` -
+
+
` }) export default class InputBoxComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit { @Input() descriptor: IComponentDescriptor; @Input() modelStore: IModelStore; private _input: InputBox; + private _textAreaInput: InputBox; @ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef; + @ViewChild('textarea', { read: ElementRef }) private _textareaContainer: ElementRef; constructor( @Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef, @Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService, @@ -43,47 +47,71 @@ export default class InputBoxComponent extends ComponentBase implements ICompone ngOnInit(): void { this.baseInit(); - } ngAfterViewInit(): void { - if (this._inputContainer) { - let inputOptions: IInputOptions = { - placeholder: '', - ariaLabel: '', - validationOptions: { - validation: () => { - if (this.valid) { - return undefined; - } else { - return { - content: this._input.inputElement.validationMessage || nls.localize('invalidValueError', 'Invalid value'), - type: MessageType.ERROR - }; - } + let inputOptions: IInputOptions = { + placeholder: '', + ariaLabel: '', + validationOptions: { + validation: () => { + if (this.valid) { + return undefined; + } else { + return { + content: this.inputElement.inputElement.validationMessage || nls.localize('invalidValueError', 'Invalid value'), + type: MessageType.ERROR + }; } - }, - useDefaultValidation: true - }; - + } + }, + useDefaultValidation: true + }; + if (this._inputContainer) { this._input = new InputBox(this._inputContainer.nativeElement, this.contextViewService, inputOptions); - this._validations.push(() => !this._input.inputElement.validationMessage); + this.registerInput(this._input, () => !this.multiline); - this._register(this._input); - this._register(attachInputBoxStyler(this._input, this.themeService)); - this._register(this._input.onDidChange(e => { - this.value = this._input.value; - this._onEventEmitter.fire({ - eventType: ComponentEventType.onDidChange, - args: e - }); + } + if (this._textareaContainer) { + let textAreaInputOptions = Object.assign({}, inputOptions, { flexibleHeight: true, type: 'textarea' }); + this._textAreaInput = new InputBox(this._textareaContainer.nativeElement, this.contextViewService, textAreaInputOptions); + this.registerInput(this._textAreaInput, () => this.multiline); + } + } + + private get inputElement(): InputBox { + return this.multiline ? this._textAreaInput : this._input; + } + + private registerInput(input: InputBox, checkOption: () => boolean): void { + if (input) { + this._validations.push(() => !input.inputElement.validationMessage); + + this._register(input); + this._register(attachInputBoxStyler(input, this.themeService)); + this._register(input.onDidChange(e => { + if (checkOption()) { + this.value = input.value; + this._onEventEmitter.fire({ + eventType: ComponentEventType.onDidChange, + args: e + }); + } })); } } + public getInputBoxDisplay(): string { + return !this.multiline ? '' : 'none'; + } + + public getTextAreaDisplay(): string { + return this.multiline ? '' : 'none'; + } + public validate(): Thenable { return super.validate().then(valid => { - this._input.validate(); + this.inputElement.validate(); return valid; }); } @@ -96,6 +124,16 @@ export default class InputBoxComponent extends ComponentBase implements ICompone public layout(): void { this._changeRef.detectChanges(); + this.layoutInputBox(); + } + + private layoutInputBox(): void { + if (this.width) { + this.inputElement.width = this.convertSizeToNumber(this.width); + } + if (this.height) { + this.inputElement.setHeight(this.convertSize(this.height)); + } } public setLayout(layout: any): void { @@ -105,21 +143,41 @@ export default class InputBoxComponent extends ComponentBase implements ICompone public setProperties(properties: { [key: string]: any; }): void { super.setProperties(properties); - this._input.inputElement.type = this.inputType; - if (this.inputType === 'number') { - this._input.inputElement.step = 'any'; - } - this._input.value = this.value; - this._input.setAriaLabel(this.ariaLabel); - this._input.setPlaceHolder(this.placeHolder); - this._input.setEnabled(this.enabled); - if (this.width) { - this._input.width = this.width; - } - this._input.inputElement.required = this.required; + this.setInputProperties(this.inputElement); this.validate(); } + private setInputProperties(input: InputBox): void { + if (!this.multiline) { + input.inputElement.type = this.inputType; + if (this.inputType === 'number') { + input.inputElement.step = 'any'; + if (this.min) { + input.inputElement.min = this.min.toString(); + } + if (this.max) { + input.inputElement.max = this.max.toString(); + } + } + } + input.value = this.value; + input.setAriaLabel(this.ariaLabel); + input.setPlaceHolder(this.placeHolder); + input.setEnabled(this.enabled); + this.layoutInputBox(); + if (this.multiline) { + if (this.rows) { + this.inputElement.rows = this.rows; + } + if (this.columns) { + this.inputElement.columns = this.columns; + } + } + + + input.inputElement.required = this.required; + } + // CSS-bound properties public get value(): string { @@ -146,20 +204,36 @@ export default class InputBoxComponent extends ComponentBase implements ICompone this.setPropertyFromUI((props, value) => props.placeHolder = value, newValue); } - public get height(): number { - return this.getPropertyOrDefault((props) => props.height, undefined); + public set columns(newValue: number) { + this.setPropertyFromUI((props, value) => props.columns = value, newValue); } - public set height(newValue: number) { - this.setPropertyFromUI((props, value) => props.height = value, newValue); + public get rows(): number { + return this.getPropertyOrDefault((props) => props.rows, undefined); } - public get width(): number { - return this.getPropertyOrDefault((props) => props.width, undefined); + public get columns(): number { + return this.getPropertyOrDefault((props) => props.columns, undefined); } - public set width(newValue: number) { - this.setPropertyFromUI((props, value) => props.width = value, newValue); + public set rows(newValue: number) { + this.setPropertyFromUI((props, value) => props.rows = value, newValue); + } + + public get min(): number { + return this.getPropertyOrDefault((props) => props.min, undefined); + } + + public set min(newValue: number) { + this.setPropertyFromUI((props, value) => props.min = value, newValue); + } + + public get max(): number { + return this.getPropertyOrDefault((props) => props.max, undefined); + } + + public set max(newValue: number) { + this.setPropertyFromUI((props, value) => props.max = value, newValue); } public get inputType(): string { @@ -170,6 +244,14 @@ export default class InputBoxComponent extends ComponentBase implements ICompone this.setPropertyFromUI((props, value) => props.inputType = value, newValue); } + public get multiline(): boolean { + return this.getPropertyOrDefault((props) => props.multiline, false); + } + + public set multiline(newValue: boolean) { + this.setPropertyFromUI((props, value) => props.multiline = value, newValue); + } + public get required(): boolean { return this.getPropertyOrDefault((props) => props.required, false); } diff --git a/src/sql/parts/modelComponents/listbox.component.ts b/src/sql/parts/modelComponents/listbox.component.ts index b4cfbed36e..81db438b09 100644 --- a/src/sql/parts/modelComponents/listbox.component.ts +++ b/src/sql/parts/modelComponents/listbox.component.ts @@ -109,20 +109,4 @@ export default class ListBoxComponent extends ComponentBase implements IComponen private set selectedRow(newValue: number) { this.setPropertyFromUI((props, value) => props.selectedRow = value, newValue); } - - public get height(): number { - return this.getPropertyOrDefault((props) => props.height, undefined); - } - - public set height(newValue: number) { - this.setPropertyFromUI((props, value) => props.height = value, newValue); - } - - public get width(): number { - return this.getPropertyOrDefault((props) => props.width, undefined); - } - - public set width(newValue: number) { - this.setPropertyFromUI((props, value) => props.width = value, newValue); - } } diff --git a/src/sql/parts/modelComponents/modelComponentWrapper.component.ts b/src/sql/parts/modelComponents/modelComponentWrapper.component.ts index eecfc1ab9d..df0cc07b9a 100644 --- a/src/sql/parts/modelComponents/modelComponentWrapper.component.ts +++ b/src/sql/parts/modelComponents/modelComponentWrapper.component.ts @@ -25,10 +25,18 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { memoize } from 'vs/base/common/decorators'; import { generateUuid } from 'vs/base/common/uuid'; +import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService'; +import { Event, Emitter } from 'vs/base/common/event'; import * as nls from 'vs/nls'; const componentRegistry = Registry.as(Extensions.ComponentContribution); +export interface ModelComponentParams extends IBootstrapParams { + + onLayoutRequested: Event; + modelViewId: string; +} + @Component({ selector: 'model-component-wrapper', template: ` @@ -46,6 +54,7 @@ export class ModelComponentWrapper extends AngularDisposable implements OnInit { } private _componentInstance: IComponent; + private _modelViewId: string; @ViewChild(ComponentHostDirective) componentHost: ComponentHostDirective; @@ -54,9 +63,18 @@ export class ModelComponentWrapper extends AngularDisposable implements OnInit { @Inject(forwardRef(() => ElementRef)) private _ref: ElementRef, @Inject(forwardRef(() => ChangeDetectorRef)) private _changeref: ChangeDetectorRef, @Inject(forwardRef(() => Injector)) private _injector: Injector, - @Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService + @Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService, + @Inject(IBootstrapParams) private _params: ModelComponentParams ) { super(); + if (_params && _params.onLayoutRequested) { + this._modelViewId = _params.modelViewId; + _params.onLayoutRequested(modelViewId => { + if (modelViewId === this._modelViewId) { + this.layout(); + } + }); + } } ngOnInit() { diff --git a/src/sql/parts/modelComponents/modelViewContent.component.ts b/src/sql/parts/modelComponents/modelViewContent.component.ts index 8fd10a7d5a..12a10f2e1e 100644 --- a/src/sql/parts/modelComponents/modelViewContent.component.ts +++ b/src/sql/parts/modelComponents/modelViewContent.component.ts @@ -62,6 +62,7 @@ export class ModelViewContent extends ViewBase implements OnInit, IModelView { } public layout(): void { + this.changeRef.detectChanges(); } public get id(): string { diff --git a/src/sql/parts/modelComponents/table.component.ts b/src/sql/parts/modelComponents/table.component.ts index 3299488095..b38b5c8f28 100644 --- a/src/sql/parts/modelComponents/table.component.ts +++ b/src/sql/parts/modelComponents/table.component.ts @@ -127,13 +127,19 @@ export default class TableComponent extends ComponentBase implements IComponent, /// IComponent implementation public layout(): void { - this._table.layout(new Dimension( - this.width ? this.width : getContentWidth(this._inputContainer.nativeElement), - this.height ? this.height : getContentHeight(this._inputContainer.nativeElement))); + this.layoutTable(); this._changeRef.detectChanges(); } + private layoutTable(): void { + let width: number = this.convertSizeToNumber(this.width); + let height: number = this.convertSizeToNumber(this.height); + this._table.layout(new Dimension( + width && width > 0 ? width : getContentWidth(this._inputContainer.nativeElement), + height && height > 0 ? height : getContentHeight(this._inputContainer.nativeElement))); + } + public setLayout(): void { // TODO allow configuring the look and feel this.layout(); @@ -149,10 +155,8 @@ export default class TableComponent extends ComponentBase implements IComponent, if (this.selectedRows) { this._table.setSelectedRows(this.selectedRows); } - this._table.layout(new Dimension( - this.width ? this.width : getContentWidth(this._inputContainer.nativeElement), - this.height ? this.height : getContentHeight(this._inputContainer.nativeElement))); + this.layoutTable(); this.validate(); } @@ -181,20 +185,4 @@ export default class TableComponent extends ComponentBase implements IComponent, public set selectedRows(newValue: number[]) { this.setPropertyFromUI((props, value) => props.selectedRows = value, newValue); } - - public get height(): number { - return this.getPropertyOrDefault((props) => props.height, undefined); - } - - public set height(newValue: number) { - this.setPropertyFromUI((props, value) => props.height = value, newValue); - } - - public get width(): number { - return this.getPropertyOrDefault((props) => props.width, undefined); - } - - public set width(newValue: number) { - this.setPropertyFromUI((props, value) => props.width = value, newValue); - } } diff --git a/src/sql/parts/modelComponents/viewBase.ts b/src/sql/parts/modelComponents/viewBase.ts index 8a9a16ec49..a00349e4f9 100644 --- a/src/sql/parts/modelComponents/viewBase.ts +++ b/src/sql/parts/modelComponents/viewBase.ts @@ -40,7 +40,6 @@ export abstract class ViewBase extends AngularDisposable implements IModelView { abstract serverInfo: sqlops.ServerInfo; private _onEventEmitter = new Emitter(); - initializeModel(rootComponent: IComponentShape, validationCallback: (componentId: string) => Thenable): void { let descriptor = this.defineComponent(rootComponent); this.rootDescriptor = descriptor; @@ -50,6 +49,10 @@ export abstract class ViewBase extends AngularDisposable implements IModelView { } private defineComponent(component: IComponentShape): IComponentDescriptor { + let existingDescriptor = this.modelStore.getComponentDescriptor(component.id); + if (existingDescriptor) { + return existingDescriptor; + } let typeId = componentRegistry.getIdForTypeMapping(component.type); if (!typeId) { // failure case diff --git a/src/sql/parts/profiler/contrib/profiler.contribution.ts b/src/sql/parts/profiler/contrib/profiler.contribution.ts index ddf89f5301..c77b21d962 100644 --- a/src/sql/parts/profiler/contrib/profiler.contribution.ts +++ b/src/sql/parts/profiler/contrib/profiler.contribution.ts @@ -92,33 +92,6 @@ const profilerSessionTemplateSchema: IJSONSchema = { } ] } - }, - { - name: 'TSQL' - }, - { - name: 'Blank' - }, - { - name: 'SP_Counts' - }, - { - name: 'TQL_Duration' - }, - { - name: 'TSQL_Grouped' - }, - { - name: 'TSQL_Locks' - }, - { - name: 'TSQL_Replay' - }, - { - name: 'TSQL_SPs' - }, - { - name: 'Tuning' } ] }; diff --git a/src/sql/parts/profiler/contrib/profilerActions.ts b/src/sql/parts/profiler/contrib/profilerActions.ts index 9a196411a2..406e867470 100644 --- a/src/sql/parts/profiler/contrib/profilerActions.ts +++ b/src/sql/parts/profiler/contrib/profilerActions.ts @@ -57,7 +57,7 @@ export class ProfilerConnect extends Action { public set connected(value: boolean) { this._connected = value; this._setClass(value ? 'disconnect' : 'connect'); - this._setLabel(value ? nls.localize('profilerAction.disconnect', 'Disconnected') : nls.localize('profilerAction.connect', "Connect")); + this._setLabel(value ? nls.localize('profilerAction.disconnect', 'Disconnect') : nls.localize('profilerAction.connect', "Connect")); } public get connected(): boolean { @@ -78,17 +78,19 @@ export class ProfilerStart extends Action { public run(input: ProfilerInput): TPromise { this.enabled = false; + input.data.clear(); return TPromise.wrap(this._profilerService.startSession(input.id).then(() => { input.state.change({ isRunning: true, isStopped: false, isPaused: false }); return true; })); } - } export class ProfilerPause extends Action { public static ID = 'profiler.pause'; - public static LABEL = nls.localize('pause', "Pause"); + public static LABEL = nls.localize('profiler.capture', "Pause Capture"); + + private _paused: boolean = false; constructor( id: string, label: string, @@ -98,12 +100,22 @@ export class ProfilerPause extends Action { } public run(input: ProfilerInput): TPromise { - this.enabled = false; return TPromise.wrap(this._profilerService.pauseSession(input.id).then(() => { - input.state.change({ isPaused: true, isStopped: false, isRunning: false }); + this.paused = !this._paused; + input.state.change({ isPaused: this.paused, isStopped: false, isRunning: !this.paused }); return true; })); } + + public set paused(value: boolean) { + this._paused = value; + this._setClass(value ? 'start' : 'stop'); + this._setLabel(value ? nls.localize('profilerAction.resumeCapture', "Resume Capture") : nls.localize('profilerAction.pauseCapture', "Pause Capture")); + } + + public get paused(): boolean { + return this._paused; + } } export class ProfilerStop extends Action { diff --git a/src/sql/parts/profiler/editor/profilerEditor.ts b/src/sql/parts/profiler/editor/profilerEditor.ts index 148f217b26..5324ee712b 100644 --- a/src/sql/parts/profiler/editor/profilerEditor.ts +++ b/src/sql/parts/profiler/editor/profilerEditor.ts @@ -202,15 +202,15 @@ export class ProfilerEditor extends BaseEditor { this._register(attachSelectBoxStyler(this._sessionTemplateSelector, this.themeService)); this._actionBar.setContent([ - { action: this._startAction }, - { action: this._pauseAction }, - { action: this._stopAction }, { action: this._connectAction }, { element: Taskbar.createTaskbarSeparator() }, - { action: this._autoscrollAction }, - { action: this._instantiationService.createInstance(Actions.ProfilerClear, Actions.ProfilerClear.ID, Actions.ProfilerClear.LABEL) }, + { action: this._startAction }, + { action: this._stopAction }, { element: dropdownContainer }, - { action: this._instantiationService.createInstance(Actions.ProfilerEditColumns, Actions.ProfilerEditColumns.ID, Actions.ProfilerEditColumns.LABEL) } + { element: Taskbar.createTaskbarSeparator() }, + { action: this._pauseAction }, + { action: this._autoscrollAction }, + { action: this._instantiationService.createInstance(Actions.ProfilerClear, Actions.ProfilerClear.ID, Actions.ProfilerClear.LABEL) } ]); } @@ -228,7 +228,9 @@ export class ProfilerEditor extends BaseEditor { if (data) { this._modelService.updateModel(this._editorModel, data['TextData']); this._detailTableData.clear(); - this._detailTableData.push(Object.keys(data).map(key => { + this._detailTableData.push(Object.keys(data).filter(key => { + return data[key] !== ' '; + }).map(key => { return { label: key, value: data[key] @@ -397,16 +399,14 @@ export class ProfilerEditor extends BaseEditor { return; } - if (e.isRunning) { - this._startAction.enabled = !this.input.state.isRunning; + if (e.isPaused){ + this._pauseAction.paused = this.input.state.isPaused; } if (e.isStopped || e.isRunning) { - this._stopAction.enabled = !this.input.state.isStopped && this.input.state.isRunning; - } - - if (e.isPaused || e.isRunning) { - this._pauseAction.enabled = !this.input.state.isPaused && this.input.state.isRunning; + this._startAction.enabled = !this.input.state.isRunning && !this.input.state.isPaused; + this._stopAction.enabled = !this.input.state.isStopped && (this.input.state.isRunning || this.input.state.isPaused); + this._pauseAction.enabled = !this.input.state.isStopped && (this.input.state.isRunning || this.input.state.isPaused); } } diff --git a/src/sql/parts/profiler/editor/profilerInput.ts b/src/sql/parts/profiler/editor/profilerInput.ts index d9df54032a..2e42de003d 100644 --- a/src/sql/parts/profiler/editor/profilerInput.ts +++ b/src/sql/parts/profiler/editor/profilerInput.ts @@ -129,7 +129,6 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { let data = {}; data['EventClass'] = e.name; data['StartTime'] = e.timestamp; - data['EndTime'] = e.timestamp; const columns = [ 'TextData', 'ApplicationName', @@ -156,12 +155,14 @@ export class ProfilerInput extends EditorInput implements IProfilerSession { columnNameMap['cpu_time'] = 'CPU'; columnNameMap['duration'] = 'Duration'; columnNameMap['logical_reads'] = 'Reads'; + columnNameMap['event_sequence'] = 'EventSequence'; + columnNameMap['client_pid'] = 'ClientProcessID'; + columnNameMap['writes'] = 'Writes'; - for (let idx = 0; idx < columns.length; ++idx) { - let columnName = columns[idx]; - data[columnName] = ''; - } - + // Using ' ' instead of '' fixed the error where clicking through events + // with empty text fields causes future text panes to be highlighted. + // This is a temporary fix, and should be changed before the July release + data['TextData'] = ' '; for (let key in e.values) { let columnName = columnNameMap[key]; if (columnName) { diff --git a/src/sql/platform/dialog/dialogContainer.component.ts b/src/sql/platform/dialog/dialogContainer.component.ts index 68716c2130..5abd0f0ea6 100644 --- a/src/sql/platform/dialog/dialogContainer.component.ts +++ b/src/sql/platform/dialog/dialogContainer.component.ts @@ -15,6 +15,7 @@ import { ComponentEventType } from '../../parts/modelComponents/interfaces'; export interface DialogComponentParams extends IBootstrapParams { modelViewId: string; validityChangedCallback: (valid: boolean) => void; + onLayoutRequested: Event; } @Component({ @@ -35,6 +36,11 @@ export class DialogContainer implements AfterContentInit { @Inject(forwardRef(() => ElementRef)) private _el: ElementRef, @Inject(IBootstrapParams) private _params: DialogComponentParams) { this.modelViewId = this._params.modelViewId; + this._params.onLayoutRequested(e => { + if (this.modelViewId === e) { + this.layout(); + } + }); } ngAfterContentInit(): void { diff --git a/src/sql/platform/dialog/dialogPane.ts b/src/sql/platform/dialog/dialogPane.ts index 5fb52a2006..d4dc349ee6 100644 --- a/src/sql/platform/dialog/dialogPane.ts +++ b/src/sql/platform/dialog/dialogPane.ts @@ -21,6 +21,7 @@ import { Builder } from 'vs/base/browser/builder'; import { IThemable } from 'vs/platform/theme/common/styler'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { Emitter } from 'vs/base/common/event'; export class DialogPane extends Disposable implements IThemable { private _tabbedPanel: TabbedPanel; @@ -34,6 +35,9 @@ export class DialogPane extends Disposable implements IThemable { private _tabBar: HTMLElement; private _tabs: HTMLElement[]; private _tabContent: HTMLElement[]; + private _selectedTabIndex: number = 0; //TODO: can be an option + private _onTabChange = new Emitter(); + private _selectedTabContent: string; constructor( private _title: string, @@ -55,10 +59,16 @@ export class DialogPane extends Disposable implements IThemable { } else { this._tabbedPanel = new TabbedPanel(this._body); this._content.forEach((tab, tabIndex) => { + if (this._selectedTabIndex === tabIndex) { + this._selectedTabContent = tab.content; + } let tabContainer = document.createElement('div'); tabContainer.style.display = 'none'; this._body.appendChild(tabContainer); this.initializeModelViewContainer(tabContainer, tab.content, tab); + this._tabbedPanel.onTabChange(e => { + this._onTabChange.fire(tab.content); + }); this._tabbedPanel.pushTab({ title: tab.title, identifier: 'dialogPane.' + this._title + '.' + tabIndex, @@ -70,7 +80,7 @@ export class DialogPane extends Disposable implements IThemable { container.appendChild(tabContainer); tabContainer.style.display = 'block'; }, - layout: (dimension) => { } + layout: (dimension) => { this.getTabDimension(); } } as IPanelView } as IPanelTab); }); @@ -80,9 +90,14 @@ export class DialogPane extends Disposable implements IThemable { return this._body; } + private getTabDimension(): DOM.Dimension { + return new DOM.Dimension(DOM.getContentWidth(this._body), DOM.getContentHeight(this._body)) + } + public layout(): void { if (this._tabbedPanel) { this._tabbedPanel.layout(new DOM.Dimension(DOM.getContentWidth(this._body), DOM.getContentHeight(this._body))); + this._onTabChange.fire(this._selectedTabContent); } } @@ -101,10 +116,13 @@ export class DialogPane extends Disposable implements IThemable { if (tab) { tab.notifyValidityChanged(valid); } - } + }, + onLayoutRequested: this._onTabChange.event } as DialogComponentParams, undefined, - (moduleRef) => this._moduleRefs.push(moduleRef)); + (moduleRef) => { + return this._moduleRefs.push(moduleRef); + }); } public show(): void { diff --git a/src/sql/platform/dialog/media/dialogModal.css b/src/sql/platform/dialog/media/dialogModal.css index 155d4802fc..54c1578089 100644 --- a/src/sql/platform/dialog/media/dialogModal.css +++ b/src/sql/platform/dialog/media/dialogModal.css @@ -29,4 +29,4 @@ .footer-button.dialogModal-hidden { margin: 0; -} +} \ No newline at end of file diff --git a/src/sql/sqlops.proposed.d.ts b/src/sql/sqlops.proposed.d.ts index f5f6ba998b..0887e7c40f 100644 --- a/src/sql/sqlops.proposed.d.ts +++ b/src/sql/sqlops.proposed.d.ts @@ -207,7 +207,15 @@ declare module 'sqlops' { */ alignContent?: string; + /** + * Container Height + */ height?: number | string; + + /** + * Container Width + */ + width?: number | string; } export interface FlexItemLayout { @@ -228,7 +236,8 @@ declare module 'sqlops' { } export interface FormLayout { - width?: number; + width?: number | string; + height?: number | string; } export interface GroupLayout { @@ -294,21 +303,29 @@ declare module 'sqlops' { export type InputBoxInputType = 'color' | 'date' | 'datetime-local' | 'email' | 'month' | 'number' | 'password' | 'range' | 'search' | 'text' | 'time' | 'url' | 'week'; - export interface InputBoxProperties { + export interface ComponentProperties { + height: number | string; + width: number | string; + } + + export interface InputBoxProperties extends ComponentProperties { value?: string; ariaLabel?: string; placeHolder?: string; - height: number; - width: number; inputType?: InputBoxInputType; required?: boolean; + multiline?: boolean; + rows?: number; + columns?: number; + min?: number; + max?: number; } export interface TableColumn { value: string } - export interface TableComponentProperties { + export interface TableComponentProperties extends ComponentProperties { data: any[][]; columns: string[] | TableColumn[]; selectedRows?: number[]; @@ -336,9 +353,9 @@ declare module 'sqlops' { value?: string; } - export interface DropDownProperties { + export interface DropDownProperties extends ComponentProperties { value?: string; - values?: string[]; + values?: string[] | CategoryValue[]; editable?: boolean; } @@ -347,7 +364,7 @@ declare module 'sqlops' { categoryValues: CategoryValue[]; valueType: DeclarativeDataType; isReadOnly: boolean; - width: number|string; + width: number | string; } export interface DeclarativeTableProperties { @@ -366,7 +383,7 @@ declare module 'sqlops' { html?: string; } - export interface ButtonProperties { + export interface ButtonProperties extends ComponentProperties { label?: string; iconPath?: string | vscode.Uri | { light: string | vscode.Uri; dark: string | vscode.Uri }; } @@ -402,7 +419,7 @@ declare module 'sqlops' { export interface DropDownComponent extends Component, DropDownProperties { value: string; - values: string[]; + values: string[] | CategoryValue[]; onValueChanged: vscode.Event; } diff --git a/src/sql/workbench/api/node/extHostDataProtocol.ts b/src/sql/workbench/api/node/extHostDataProtocol.ts index c58d01e64d..ae7d85132c 100644 --- a/src/sql/workbench/api/node/extHostDataProtocol.ts +++ b/src/sql/workbench/api/node/extHostDataProtocol.ts @@ -503,6 +503,14 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { return this._resolveProvider(handle).stopSession(sessionId); } + /** + * Pause a profiler session + */ + public $pauseSession(handle: number, sessionId: string): Thenable { + return this._resolveProvider(handle).pauseSession(sessionId); + } + + /** * Profiler session events available notification */ diff --git a/src/sql/workbench/api/node/extHostModelView.ts b/src/sql/workbench/api/node/extHostModelView.ts index 319b248a8d..3695c3fa96 100644 --- a/src/sql/workbench/api/node/extHostModelView.ts +++ b/src/sql/workbench/api/node/extHostModelView.ts @@ -342,7 +342,6 @@ class InternalItemConfig { } } - class ComponentWrapper implements sqlops.Component { public properties: { [key: string]: any } = {}; public layout: any; @@ -385,6 +384,22 @@ class ComponentWrapper implements sqlops.Component { this.setProperty('enabled', value); } + public get height(): number | string { + return this.properties['height']; + } + + public set height(v: number | string) { + this.setProperty('height', v); + } + + public get width(): number | string { + return this.properties['width']; + } + + public set width(v: number | string) { + this.setProperty('width', v); + } + public toComponentShape(): IComponentShape { return { id: this.id, @@ -553,18 +568,39 @@ class InputBoxWrapper extends ComponentWrapper implements sqlops.InputBoxCompone this.setProperty('placeHolder', v); } - public get height(): number { - return this.properties['height']; + public get rows(): number { + return this.properties['rows']; } - public set height(v: number) { - this.setProperty('height', v); + public set rows(v: number) { + this.setProperty('rows', v); } - public get width(): number { - return this.properties['width']; + public get min(): number { + return this.properties['min']; } - public set width(v: number) { - this.setProperty('width', v); + public set min(v: number) { + this.setProperty('min', v); + } + + public get max(): number { + return this.properties['max']; + } + public set max(v: number) { + this.setProperty('max', v); + } + + public get columns(): number { + return this.properties['columns']; + } + public set columns(v: number) { + this.setProperty('columns', v); + } + + public get multiline(): boolean { + return this.properties['multiline']; + } + public set multiline(v: boolean) { + this.setProperty('multiline', v); } public get inputType(): sqlops.InputBoxInputType { @@ -742,10 +778,10 @@ class DropDownWrapper extends ComponentWrapper implements sqlops.DropDownCompone this.setProperty('value', v); } - public get values(): string[] { + public get values(): string[] | sqlops.CategoryValue[] { return this.properties['values']; } - public set values(v: string[]) { + public set values(v: string[] | sqlops.CategoryValue[]) { this.setProperty('values', v); } diff --git a/src/sql/workbench/api/node/mainThreadDataProtocol.ts b/src/sql/workbench/api/node/mainThreadDataProtocol.ts index de360a5b65..8de3337a90 100644 --- a/src/sql/workbench/api/node/mainThreadDataProtocol.ts +++ b/src/sql/workbench/api/node/mainThreadDataProtocol.ts @@ -296,7 +296,7 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape { return self._proxy.$stopSession(handle, sessionId); }, pauseSession(sessionId: string): Thenable { - return TPromise.as(true); + return self._proxy.$pauseSession(handle, sessionId); }, connectSession(sessionId: string): Thenable { return TPromise.as(true); diff --git a/src/sql/workbench/api/node/sqlExtHost.protocol.ts b/src/sql/workbench/api/node/sqlExtHost.protocol.ts index a623f7d21e..dbacbd14f2 100644 --- a/src/sql/workbench/api/node/sqlExtHost.protocol.ts +++ b/src/sql/workbench/api/node/sqlExtHost.protocol.ts @@ -313,6 +313,11 @@ export abstract class ExtHostDataProtocolShape { */ $stopSession(handle: number, sessionId: string): Thenable { throw ni(); } + /** + * Pause a profiler session + */ + $pauseSession(handle: number, sessionId: string): Thenable { throw ni(); } + /** * Get Agent Job list