diff --git a/src/sql/parts/modelComponents/componentBase.ts b/src/sql/parts/modelComponents/componentBase.ts index 8a11a771bc..ff44630a8e 100644 --- a/src/sql/parts/modelComponents/componentBase.ts +++ b/src/sql/parts/modelComponents/componentBase.ts @@ -130,11 +130,13 @@ export abstract class ComponentBase extends Disposable implements IComponent, On this.setPropertyFromUI((props, value) => props.width = value, newValue); } - protected convertSizeToNumber(size: number | string): number { + public convertSizeToNumber(size: number | string): number { if (size && typeof (size) === 'string') { if (size.toLowerCase().endsWith('px')) { return +size.replace('px', ''); } + + } else if (!size) { return 0; } return +size; @@ -148,7 +150,7 @@ export abstract class ComponentBase extends Disposable implements IComponent, On return this.height ? this.convertSize(this.height) : ''; } - protected convertSize(size: number | string, defaultValue?: string): string { + public convertSize(size: number | string, defaultValue?: string): string { defaultValue = defaultValue || ''; if (types.isUndefinedOrNull(size)) { return defaultValue; diff --git a/src/sql/parts/modelComponents/dropdown.component.ts b/src/sql/parts/modelComponents/dropdown.component.ts index ead4629c33..1a96f3d834 100644 --- a/src/sql/parts/modelComponents/dropdown.component.ts +++ b/src/sql/parts/modelComponents/dropdown.component.ts @@ -187,7 +187,7 @@ export default class DropDownComponent extends ComponentBase implements ICompone } private get values(): string[] | sqlops.CategoryValue[] { - return this.getPropertyOrDefault((props) => props.values, undefined); + return this.getPropertyOrDefault((props) => props.values, []); } private set values(newValue: string[] | sqlops.CategoryValue[]) { diff --git a/src/sql/parts/modelComponents/inputbox.component.ts b/src/sql/parts/modelComponents/inputbox.component.ts index d77438229b..f2d8cc015a 100644 --- a/src/sql/parts/modelComponents/inputbox.component.ts +++ b/src/sql/parts/modelComponents/inputbox.component.ts @@ -20,6 +20,9 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import * as nls from 'vs/nls'; import { inputBackground, inputBorder } from 'vs/platform/theme/common/colorRegistry'; +import * as DomUtils from 'vs/base/browser/dom'; +import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { KeyCode } from 'vs/base/common/keyCodes'; @Component({ selector: 'modelview-inputBox', @@ -73,11 +76,31 @@ export default class InputBoxComponent extends ComponentBase implements ICompone if (this._textareaContainer) { let textAreaInputOptions = Object.assign({}, inputOptions, { flexibleHeight: true, type: 'textarea' }); this._textAreaInput = new InputBox(this._textareaContainer.nativeElement, this.contextViewService, textAreaInputOptions); + this.onkeydown(this._textAreaInput.inputElement, (e: StandardKeyboardEvent) => { + if (this.tryHandleKeyEvent(e)) { + e.stopPropagation(); + } + // Else assume that keybinding service handles routing this to a command + }); + this.registerInput(this._textAreaInput, () => this.multiline); } this.inputElement.hideErrors = true; } + private onkeydown(domNode: HTMLElement, listener: (e: IKeyboardEvent) => void): void { + this._register(DomUtils.addDisposableListener(domNode, DomUtils.EventType.KEY_DOWN, (e: KeyboardEvent) => listener(new StandardKeyboardEvent(e)))); + } + + private tryHandleKeyEvent(e: StandardKeyboardEvent): boolean { + let handled: boolean = false; + + if (this.multiline && e.keyCode === KeyCode.Enter) { + handled = true; + } + return handled; + } + private get inputElement(): InputBox { return this.multiline ? this._textAreaInput : this._input; } diff --git a/src/sql/parts/modelComponents/table.component.ts b/src/sql/parts/modelComponents/table.component.ts index 2ca84d66f9..ad77eede26 100644 --- a/src/sql/parts/modelComponents/table.component.ts +++ b/src/sql/parts/modelComponents/table.component.ts @@ -74,15 +74,21 @@ export default class TableComponent extends ComponentBase implements IComponent, } } - transformData(rows: string[][], columns: any[]): { [key: string]: string }[] { - return rows.map(row => { - let object: { [key: string]: string } = {}; - row.forEach((val, index) => { - let columnName: string = (columns[index].value) ? columns[index].value : columns[index]; - object[columnName] = val; + public static transformData(rows: string[][], columns: any[]): { [key: string]: string }[] { + if (rows && columns) { + return rows.map(row => { + let object: { [key: string]: string } = {}; + if (row.forEach) { + row.forEach((val, index) => { + let columnName: string = (columns[index].value) ? columns[index].value : columns[index]; + object[columnName] = val; + }); + } + return object; }); - return object; - }); + } else { + return []; + } } ngAfterViewInit(): void { @@ -147,7 +153,7 @@ export default class TableComponent extends ComponentBase implements IComponent, public setProperties(properties: { [key: string]: any; }): void { super.setProperties(properties); this._tableData.clear(); - this._tableData.push(this.transformData(this.data, this.columns)); + this._tableData.push(TableComponent.transformData(this.data, this.columns)); this._tableColumns = this.transformColumns(this.columns); this._table.columns = this._tableColumns; this._table.setData(this._tableData); diff --git a/src/sqltest/parts/modelComponents/componentBase.test.ts b/src/sqltest/parts/modelComponents/componentBase.test.ts index e13e9b5737..6ed7c8e773 100644 --- a/src/sqltest/parts/modelComponents/componentBase.test.ts +++ b/src/sqltest/parts/modelComponents/componentBase.test.ts @@ -49,7 +49,7 @@ class TestContainer extends ContainerBase { } } -suite('ComponentBase Validation Tests', () => { +suite('ComponentBase Tests', () => { let testComponent: TestComponent; let testContainer: TestContainer; let modelStore: IModelStore; @@ -129,4 +129,51 @@ suite('ComponentBase Validation Tests', () => { testContainer.addToContainer(testComponent.descriptor, undefined); testComponent.validate(); }); + + test('Component convert size should add px', done => { + let expected = '100px'; + let actual = testComponent.convertSize(100); + assert.equal(expected, actual); + + actual = testComponent.convertSize('100px'); + assert.equal(expected, actual); + + expected = '100%'; + actual = testComponent.convertSize('100%'); + assert.equal(expected, actual); + done(); + }); + + test('Component convert size should keep value if ends with %', done => { + let expected = '100%'; + let actual = testComponent.convertSize('100%'); + assert.equal(expected, actual); + done(); + }); + + test('Component convert size should return the default value given undefined value %', done => { + let expected = '200'; + let actual = testComponent.convertSize(undefined, '200'); + assert.equal(expected, actual); + done(); + }); + + test('Component convert to number should return size without px', done => { + let expected = 200; + let actual = testComponent.convertSizeToNumber('200px'); + assert.equal(expected, actual); + + actual = testComponent.convertSizeToNumber('200'); + assert.equal(expected, actual); + done(); + }); + + test('Component convert to number should return 0 given undefined', done => { + let expected = 0; + let actual = testComponent.convertSizeToNumber(undefined); + assert.equal(expected, actual); + + done(); + }); + }); \ No newline at end of file diff --git a/src/sqltest/parts/modelComponents/table.component.test.ts b/src/sqltest/parts/modelComponents/table.component.test.ts new file mode 100644 index 0000000000..e211f2c46a --- /dev/null +++ b/src/sqltest/parts/modelComponents/table.component.test.ts @@ -0,0 +1,77 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import TableComponent from 'sql/parts/modelComponents/table.component'; + +'use strict'; + + +suite('TableComponent Tests', () => { + + setup(() => { + }); + + test('Table transformData should convert data and columns successfully given valid inputs', () => { + let data = [ + ['1', '2', '2'], + ['4', '5', '6'] + ]; + let columns = ['c1', 'c2', 'c3']; + let actual: { [key: string]: string }[] = TableComponent.transformData(data, columns); + let expected: { [key: string]: string }[] = [ + { + 'c1': '1', + 'c2': '2', + 'c3': '2' + }, + { + 'c1': '4', + 'c2': '5', + 'c3': '6' + } + ]; + assert.deepEqual(actual, expected); + }); + + test('Table transformData should return empty array given undefined rows', () => { + let data = undefined; + let columns = ['c1', 'c2', 'c3']; + let actual: { [key: string]: string }[] = TableComponent.transformData(data, columns); + let expected: { [key: string]: string }[] = []; + assert.deepEqual(actual, expected); + }); + + test('Table transformData should return empty array given undefined columns', () => { + let data = [ + ['1', '2', '2'], + ['4', '5', '6'] + ]; + let columns; + let actual: { [key: string]: string }[] = TableComponent.transformData(data, columns); + let expected: { [key: string]: string }[] = []; + assert.deepEqual(actual, expected); + }); + + test('Table transformData should return array matched with columns given rows with missing column', () => { + let data = [ + ['1', '2'], + ['4', '5'] + ]; + let columns = ['c1', 'c2', 'c3']; + let actual: { [key: string]: string }[] = TableComponent.transformData(data, columns); + let expected: { [key: string]: string }[] = [ + { + 'c1': '1', + 'c2': '2' + }, + { + 'c1': '4', + 'c2': '5' + } + ]; + assert.deepEqual(actual, expected); + }); +}); \ No newline at end of file