diff --git a/src/sql/base/browser/ui/editableDropdown/dropdownTree.ts b/src/sql/base/browser/ui/editableDropdown/dropdownTree.ts index 06017c8f5a..f1666dbba5 100644 --- a/src/sql/base/browser/ui/editableDropdown/dropdownTree.ts +++ b/src/sql/base/browser/ui/editableDropdown/dropdownTree.ts @@ -36,7 +36,7 @@ export class DropdownRenderer implements tree.IRenderer { public renderTemplate(tree: tree.ITree, templateId: string, container: HTMLElement) { const row = $('div.list-row').style('height', '22px').style('padding-left', '5px').getHTMLElement(); DOM.append(container, row); - const label = $('span.label').style('margin', 'auto').getHTMLElement(); + const label = $('span.label').style('margin', 'auto').style('vertical-align', 'middle').getHTMLElement(); DOM.append(row, label); return { label }; @@ -91,7 +91,7 @@ export class DropdownFilter extends TreeDefaults.DefaultFilter { public filterString: string; public isVisible(tree: tree.ITree, element: Resource): boolean { - return element.value.includes(this.filterString); + return element.value.toLowerCase().includes(this.filterString.toLowerCase()); } } diff --git a/src/sql/parts/connection/connectionDialog/connectionController.ts b/src/sql/parts/connection/connectionDialog/connectionController.ts index 566de37170..f0e6737168 100644 --- a/src/sql/parts/connection/connectionDialog/connectionController.ts +++ b/src/sql/parts/connection/connectionDialog/connectionController.ts @@ -26,6 +26,8 @@ export class ConnectionController implements IConnectionComponentController { private _model: IConnectionProfile; private _providerOptions: data.ConnectionOption[]; private _providerName: string; + /* key: uri, value : list of databases */ + private _databaseCache = new Map(); constructor(container: HTMLElement, connectionManagementService: IConnectionManagementService, @@ -43,11 +45,50 @@ export class ConnectionController implements IConnectionComponentController { onSetConnectButton: (enable: boolean) => this._callback.onSetConnectButton(enable), onCreateNewServerGroup: () => this.onCreateNewServerGroup(), onAdvancedProperties: () => this.handleOnAdvancedProperties(), - onSetAzureTimeOut: () => this.handleonSetAzureTimeOut() + onSetAzureTimeOut: () => this.handleonSetAzureTimeOut(), + onFetchDatabases: (serverName: string, authenticationType: string, userName?: string, password?: string) => this.onFetchDatabases( + serverName, authenticationType, userName, password).then(result => { + return result; + }) }, providerName); this._providerName = providerName; } + private onFetchDatabases(serverName: string, authenticationType: string, userName?: string, password?: string): Promise { + let tempProfile = this._model; + tempProfile.serverName = serverName; + tempProfile.authenticationType = authenticationType; + tempProfile.userName = userName; + tempProfile.password = password; + let uri = this._connectionManagementService.getConnectionId(tempProfile); + return new Promise((resolve, reject) => { + if (this._databaseCache.has(uri)) { + let cachedDatabases : string[] = this._databaseCache.get(uri); + if (cachedDatabases !== null) { + resolve(cachedDatabases); + } else { + reject(); + } + } else { + this._connectionManagementService.connect(tempProfile, uri).then(connResult => { + if (connResult && connResult.connected) { + this._connectionManagementService.listDatabases(uri).then(result => { + if (result && result.databaseNames) { + this._databaseCache.set(uri, result.databaseNames); + resolve(result.databaseNames); + } else { + this._databaseCache.set(uri, null); + reject(); + } + }) + } else { + reject(connResult.errorMessage); + } + }); + } + }); + } + private onCreateNewServerGroup(): void { this._connectionManagementService.showCreateServerGroupDialog({ onAddGroup: (groupName) => this._connectionWidget.updateServerGroup(this.getAllServerGroups(), groupName), diff --git a/src/sql/parts/connection/connectionDialog/connectionDialogService.ts b/src/sql/parts/connection/connectionDialog/connectionDialogService.ts index f4e9f0ebc2..afadbd7101 100644 --- a/src/sql/parts/connection/connectionDialog/connectionDialogService.ts +++ b/src/sql/parts/connection/connectionDialog/connectionDialogService.ts @@ -43,6 +43,7 @@ export interface IConnectionComponentCallbacks { onCreateNewServerGroup?: () => void; onAdvancedProperties?: () => void; onSetAzureTimeOut?: () => void; + onFetchDatabases?: (serverName: string, authenticationType: string, userName?: string, password?: string) => Promise; } export interface IConnectionComponentController { diff --git a/src/sql/parts/connection/connectionDialog/connectionWidget.ts b/src/sql/parts/connection/connectionDialog/connectionWidget.ts index 384963bd3e..fadecb1efa 100644 --- a/src/sql/parts/connection/connectionDialog/connectionWidget.ts +++ b/src/sql/parts/connection/connectionDialog/connectionWidget.ts @@ -21,12 +21,13 @@ import * as Constants from 'sql/parts/connection/common/constants'; import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import * as styler from 'vs/platform/theme/common/styler'; -import { attachInputBoxStyler, attachButtonStyler } from 'sql/common/theme/styler'; +import { attachInputBoxStyler, attachButtonStyler, attachEditableDropdownStyler } from 'sql/common/theme/styler'; import * as DOM from 'vs/base/browser/dom'; import data = require('data'); import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { localize } from 'vs/nls'; import { OS, OperatingSystem } from 'vs/base/common/platform'; +import { Dropdown } from 'sql/base/browser/ui/editableDropdown/dropdown'; export class ConnectionWidget { private _builder: Builder; @@ -34,7 +35,7 @@ export class ConnectionWidget { private _previousGroupOption: string; private _serverGroupOptions: IConnectionProfileGroup[]; private _serverNameInputBox: InputBox; - private _databaseNameInputBox: InputBox; + private _databaseNameInputBox: Dropdown; private _userNameInputBox: InputBox; private _passwordInputBox: InputBox; private _password: string; @@ -51,6 +52,8 @@ export class ConnectionWidget { [Constants.mssqlProviderName]: [new AuthenticationType(Constants.integrated, false), new AuthenticationType(Constants.sqlLogin, true)] }; private _saveProfile: boolean; + private _defaultDatabaseName: string = localize('defaultDatabaseOption', ''); + private _loadingDatabaseName: string = localize('loadingDatabaseOption', 'Loading...'); public DefaultServerGroup: IConnectionProfileGroup = { id: '', name: localize('defaultServerGroup', ''), @@ -151,11 +154,12 @@ export class ConnectionWidget { let databaseOption = this._optionsMaps[ConnectionOptionSpecialType.databaseName]; let databaseNameBuilder = DialogHelper.appendRow(this._tableContainer, databaseOption.displayName, 'connection-label', 'connection-input'); - this._databaseNameInputBox = new InputBox(databaseNameBuilder.getHTMLElement(), this._contextViewService, { - validationOptions: { - validation: (value: string) => (!value && databaseOption.isRequired) ? ({ type: MessageType.ERROR, content: databaseOption.displayName + errorMessage }) : null - }, - placeholder: (databaseOption.defaultValue || '') + + this._databaseNameInputBox = new Dropdown(databaseNameBuilder.getHTMLElement(), this._contextViewService, this._themeService, { + values: [this._defaultDatabaseName, this._loadingDatabaseName], + strictSelection : false, + placeholder: this._defaultDatabaseName, + maxHeight: 125 }); let serverGroupLabel = localize('serverGroup', 'Server group'); @@ -208,7 +212,7 @@ export class ConnectionWidget { private registerListeners(): void { // Theme styler this._toDispose.push(attachInputBoxStyler(this._serverNameInputBox, this._themeService)); - this._toDispose.push(attachInputBoxStyler(this._databaseNameInputBox, this._themeService)); + this._toDispose.push(attachEditableDropdownStyler(this._databaseNameInputBox, this._themeService)); this._toDispose.push(attachInputBoxStyler(this._userNameInputBox, this._themeService)); this._toDispose.push(attachInputBoxStyler(this._passwordInputBox, this._themeService)); this._toDispose.push(styler.attachSelectBoxStyler(this._serverGroupSelectBox, this._themeService)); @@ -238,6 +242,31 @@ export class ConnectionWidget { this._toDispose.push(this._passwordInputBox.onDidChange(passwordInput => { this._password = passwordInput; })); + + this._toDispose.push(this._databaseNameInputBox.onFocus(() => { + if (this.serverName) { + this._databaseNameInputBox.values = [this._loadingDatabaseName]; + this._callbacks.onFetchDatabases(this.serverName, this.authenticationType, this.userName, this._password).then(databases => { + if (databases) { + this._databaseNameInputBox.values = databases; + } else { + this._databaseNameInputBox.values = [this._defaultDatabaseName]; + } + }).catch(() => { + this._databaseNameInputBox.values = [this._defaultDatabaseName]; + }); + } else { + this._databaseNameInputBox.values = [this._defaultDatabaseName]; + } + })); + + this._toDispose.push(this._databaseNameInputBox.onValueChange(s => { + if (s === this._defaultDatabaseName || s === this._loadingDatabaseName) { + this._databaseNameInputBox.value = ''; + } else { + this._databaseNameInputBox.value = s; + } + })); } private onGroupSelected(selectedGroup: string) { @@ -393,7 +422,7 @@ export class ConnectionWidget { this._serverGroupSelectBox.disable(); this._serverNameInputBox.disable(); - this._databaseNameInputBox.disable(); + this._databaseNameInputBox.enabled = false; this._userNameInputBox.disable(); this._passwordInputBox.disable(); this._rememberPasswordCheckBox.enabled = false; @@ -407,7 +436,7 @@ export class ConnectionWidget { this._serverGroupSelectBox.enable(); this._serverNameInputBox.enable(); - this._databaseNameInputBox.enable(); + this._databaseNameInputBox.enabled = true; let currentAuthType: AuthenticationType = undefined; if (this._authTypeSelectBox) { this._authTypeSelectBox.enable(); @@ -462,11 +491,7 @@ export class ConnectionWidget { this._passwordInputBox.focus(); isFocused = true; } - let validateDatabaseName = this._databaseNameInputBox.validate(); - if (!validateDatabaseName && !isFocused) { - this._databaseNameInputBox.focus(); - } - return validateServerName && validateUserName && validatePassword && validateDatabaseName; + return validateServerName && validateUserName && validatePassword; } public connect(model: IConnectionProfile): boolean {