CMS Extension - 2 (#4908)

* first set of changes to experiment the registration of cms related apis

* Adding cms service entry to workbench

* Adding basic functionality for add remove reg servers and group

* Returning relative path as part of RegServerResult as string

* initial extension

* cleaned building with connecting to server

* get list of registered servers

* progress with registered servers tree

* cms base node with server selection

* removed unused services

* replaced azure stuff with cms

* removed cmsResourceService

* list servers progress

* Removing the cms apis from core. Having mssql extension expose them for cms extension

* create server working fine

* initial expansion and nodes

* Propogating the backend name changes to apis

* initial cms extension working

* cached connection needs change in api

* connect without dashboard in proposed

* Fixing some missing sqlops references

* add registered server bug found

* added refresh context menu option

* added payload

* server description not disabled after reject connection

* added more context actions and action icons

* added empty resource and error when same name server is added

* fixed connection issues with cms and normal connections

* added initial tests

* added cms icons

* removed azure readme

* test script revert

* fix build tests

* added more cms tests

* fixed test script

* fixed silent error when expanding servers

* added more cms tests

* removed cmsdialog from api

* cms dialog without object

* fixed theming issues

* initial connection dialog done

* can make connections

* PM asks for strings and icons

* removed search

* removed unused code and fixed 1 test

* fix connection management tests

* changed icons

* format file

* fixed hygiene

* initial cr comments

* refactored cms connection dialog

* fixed bug when switching dialogs

* localized connection provider options

* fixed cms provider name

* code review comments

* localized options in cms and mssql

* localized more options
This commit is contained in:
Aditya Bist
2019-04-29 15:16:59 -07:00
committed by GitHub
parent cbf3ca726f
commit 39772c2dbe
60 changed files with 4595 additions and 156 deletions

View File

@@ -37,13 +37,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
export class ConnectionWidget {
private _container: HTMLElement;
private _serverGroupSelectBox: SelectBox;
private _previousGroupOption: string;
private _serverGroupOptions: IConnectionProfileGroup[];
private _connectionNameInputBox: InputBox;
private _serverNameInputBox: InputBox;
private _databaseNameInputBox: Dropdown;
private _userNameInputBox: InputBox;
private _passwordInputBox: InputBox;
private _password: string;
@@ -55,22 +51,26 @@ export class ConnectionWidget {
private readonly _azureProviderId = 'azurePublicCloud';
private _azureTenantId: string;
private _azureAccountList: azdata.Account[];
private _advancedButton: Button;
private _callbacks: IConnectionComponentCallbacks;
private _authTypeSelectBox: SelectBox;
private _toDispose: lifecycle.IDisposable[];
private _optionsMaps: { [optionType: number]: azdata.ConnectionOption };
private _tableContainer: HTMLElement;
private _focusedBeforeHandleOnConnection: HTMLElement;
private _providerName: string;
private _authTypeMap: { [providerName: string]: AuthenticationType[] } = {
[Constants.mssqlProviderName]: [AuthenticationType.SqlLogin, AuthenticationType.Integrated, AuthenticationType.AzureMFA]
};
private _saveProfile: boolean;
private _databaseDropdownExpanded: boolean = false;
private _defaultDatabaseName: string = localize('defaultDatabaseOption', '<Default>');
private _loadingDatabaseName: string = localize('loadingDatabaseOption', 'Loading...');
private _serverGroupDisplayString: string = localize('serverGroup', 'Server group');
protected _container: HTMLElement;
protected _serverGroupSelectBox: SelectBox;
protected _authTypeSelectBox: SelectBox;
protected _toDispose: lifecycle.IDisposable[];
protected _optionsMaps: { [optionType: number]: azdata.ConnectionOption };
protected _tableContainer: HTMLElement;
protected _providerName: string;
protected _authTypeMap: { [providerName: string]: AuthenticationType[] } = {
[Constants.mssqlProviderName]: [AuthenticationType.SqlLogin, AuthenticationType.Integrated, AuthenticationType.AzureMFA]
};
protected _connectionNameInputBox: InputBox;
protected _databaseNameInputBox: Dropdown;
protected _advancedButton: Button;
public DefaultServerGroup: IConnectionProfileGroup = {
id: '',
name: localize('defaultServerGroup', '<Default>'),
@@ -96,8 +96,8 @@ export class ConnectionWidget {
constructor(options: azdata.ConnectionOption[],
callbacks: IConnectionComponentCallbacks,
providerName: string,
@IThemeService private _themeService: IThemeService,
@IContextViewService private _contextViewService: IContextViewService,
@IThemeService protected _themeService: IThemeService,
@IContextViewService protected _contextViewService: IContextViewService,
@ILayoutService private _layoutService: ILayoutService,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
@@ -125,13 +125,13 @@ export class ConnectionWidget {
this._providerName = providerName;
}
public createConnectionWidget(container: HTMLElement): void {
public createConnectionWidget(container: HTMLElement, authTypeChanged: boolean = false): void {
this._serverGroupOptions = [this.DefaultServerGroup];
this._serverGroupSelectBox = new SelectBox(this._serverGroupOptions.map(g => g.name), this.DefaultServerGroup.name, this._contextViewService, undefined, { ariaLabel: this._serverGroupDisplayString });
this._previousGroupOption = this._serverGroupSelectBox.value;
this._container = DOM.append(container, DOM.$('div.connection-table'));
this._tableContainer = DOM.append(this._container, DOM.$('table.connection-table-content'));
this.fillInConnectionForm();
this.fillInConnectionForm(authTypeChanged);
this.registerListeners();
if (this._authTypeSelectBox) {
this.onAuthTypeSelected(this._authTypeSelectBox.value);
@@ -142,7 +142,7 @@ export class ConnectionWidget {
});
}
private _handleClipboard(): void {
protected _handleClipboard(): void {
if (this._configurationService.getValue<boolean>('connection.parseClipboardForConnectionString')) {
let paste = this._clipboardService.readText();
this._connectionManagementService.buildConnectionInfo(paste, this._providerName).then(e => {
@@ -157,7 +157,37 @@ export class ConnectionWidget {
}
}
private fillInConnectionForm(): void {
protected fillInConnectionForm(authTypeChanged: boolean = false): void {
// Server Name
this.addServerNameOption();
// Authentication type
this.addAuthenticationTypeOption(authTypeChanged);
// Login Options
this.addLoginOptions();
// Database
this.addDatabaseOption();
// Server Group
this.addServerGroupOption();
// Connection Name
this.addConnectionNameOptions();
// Advanced Options
this.addAdvancedOptions();
}
protected addAuthenticationTypeOption(authTypeChanged: boolean = false): void {
if (this._optionsMaps[ConnectionOptionSpecialType.authType]) {
let authType = DialogHelper.appendRow(this._tableContainer, this._optionsMaps[ConnectionOptionSpecialType.authType].displayName, 'connection-label', 'connection-input');
DialogHelper.appendInputSelectBox(authType, this._authTypeSelectBox);
}
}
protected addServerNameOption(): void {
// Server name
let serverNameOption = this._optionsMaps[ConnectionOptionSpecialType.serverName];
let serverName = DialogHelper.appendRow(this._tableContainer, serverNameOption.displayName, 'connection-label', 'connection-input');
@@ -174,13 +204,9 @@ export class ConnectionWidget {
},
ariaLabel: serverNameOption.displayName
});
}
// Authentication type
if (this._optionsMaps[ConnectionOptionSpecialType.authType]) {
let authType = DialogHelper.appendRow(this._tableContainer, this._optionsMaps[ConnectionOptionSpecialType.authType].displayName, 'connection-label', 'connection-input');
DialogHelper.appendInputSelectBox(authType, this._authTypeSelectBox);
}
protected addLoginOptions(): void {
// Username
let self = this;
let userNameOption = this._optionsMaps[ConnectionOptionSpecialType.userName];
@@ -211,35 +237,46 @@ export class ConnectionWidget {
this._refreshCredentialsLink = DOM.append(refreshCredentials, DOM.$('a'));
this._refreshCredentialsLink.href = '#';
this._refreshCredentialsLink.innerText = localize('connectionWidget.refreshAzureCredentials', 'Refresh account credentials');
// Azure tenant picker
let tenantLabel = localize('connection.azureTenantDropdownLabel', 'Azure AD tenant');
let tenantDropdown = DialogHelper.appendRow(this._tableContainer, tenantLabel, 'connection-label', 'connection-input', ['azure-account-row', 'azure-tenant-row']);
this._azureTenantDropdown = new SelectBox([], undefined, this._contextViewService, tenantDropdown, { ariaLabel: tenantLabel });
DialogHelper.appendInputSelectBox(tenantDropdown, this._azureTenantDropdown);
}
private addDatabaseOption(): void {
// Database
let databaseOption = this._optionsMaps[ConnectionOptionSpecialType.databaseName];
let databaseName = DialogHelper.appendRow(this._tableContainer, databaseOption.displayName, 'connection-label', 'connection-input');
this._databaseNameInputBox = new Dropdown(databaseName, this._contextViewService, this._layoutService, {
values: [this._defaultDatabaseName, this._loadingDatabaseName],
strictSelection: false,
placeholder: this._defaultDatabaseName,
maxHeight: 125,
ariaLabel: databaseOption.displayName,
actionLabel: localize('connectionWidget.toggleDatabaseNameDropdown', 'Select Database Toggle Dropdown')
});
if (databaseOption) {
let databaseName = DialogHelper.appendRow(this._tableContainer, databaseOption.displayName, 'connection-label', 'connection-input');
this._databaseNameInputBox = new Dropdown(databaseName, this._contextViewService, this._layoutService, {
values: [this._defaultDatabaseName, this._loadingDatabaseName],
strictSelection: false,
placeholder: this._defaultDatabaseName,
maxHeight: 125,
ariaLabel: databaseOption.displayName,
actionLabel: localize('connectionWidget.toggleDatabaseNameDropdown', 'Select Database Toggle Dropdown')
});
}
}
private addServerGroupOption(): void {
// Server group
let serverGroup = DialogHelper.appendRow(this._tableContainer, this._serverGroupDisplayString, 'connection-label', 'connection-input');
DialogHelper.appendInputSelectBox(serverGroup, this._serverGroupSelectBox);
if (this._serverGroupSelectBox) {
let serverGroup = DialogHelper.appendRow(this._tableContainer, this._serverGroupDisplayString, 'connection-label', 'connection-input');
DialogHelper.appendInputSelectBox(serverGroup, this._serverGroupSelectBox);
}
}
protected addConnectionNameOptions(): void {
// Connection name
let connectionNameOption = this._optionsMaps[ConnectionOptionSpecialType.connectionName];
connectionNameOption.displayName = localize('connectionName', 'Name (optional)');
let connectionNameBuilder = DialogHelper.appendRow(this._tableContainer, connectionNameOption.displayName, 'connection-label', 'connection-input');
this._connectionNameInputBox = new InputBox(connectionNameBuilder, this._contextViewService, { ariaLabel: connectionNameOption.displayName });
}
protected addAdvancedOptions(): void {
let AdvancedLabel = localize('advanced', 'Advanced...');
this._advancedButton = this.createAdvancedButton(this._tableContainer, AdvancedLabel);
}
@@ -254,7 +291,7 @@ export class ConnectionWidget {
return false;
}
private createAdvancedButton(container: HTMLElement, title: string): Button {
protected createAdvancedButton(container: HTMLElement, title: string): Button {
let rowContainer = DOM.append(container, DOM.$('tr'));
DOM.append(rowContainer, DOM.$('td'));
let cellContainer = DOM.append(rowContainer, DOM.$('td'));
@@ -276,17 +313,49 @@ export class ConnectionWidget {
return new Checkbox(checkboxContainer, { label, checked: isChecked, ariaLabel: label });
}
private registerListeners(): void {
protected registerListeners(): void {
// Theme styler
this._toDispose.push(styler.attachInputBoxStyler(this._serverNameInputBox, this._themeService));
this._toDispose.push(styler.attachEditableDropdownStyler(this._databaseNameInputBox, this._themeService));
this._toDispose.push(styler.attachInputBoxStyler(this._connectionNameInputBox, this._themeService));
this._toDispose.push(styler.attachInputBoxStyler(this._userNameInputBox, this._themeService));
this._toDispose.push(styler.attachInputBoxStyler(this._passwordInputBox, this._themeService));
this._toDispose.push(styler.attachSelectBoxStyler(this._serverGroupSelectBox, this._themeService));
this._toDispose.push(styler.attachButtonStyler(this._advancedButton, this._themeService));
this._toDispose.push(styler.attachCheckboxStyler(this._rememberPasswordCheckBox, this._themeService));
this._toDispose.push(styler.attachSelectBoxStyler(this._azureAccountDropdown, this._themeService));
if (this._serverGroupSelectBox) {
this._toDispose.push(styler.attachSelectBoxStyler(this._serverGroupSelectBox, this._themeService));
this._toDispose.push(this._serverGroupSelectBox.onDidSelect(selectedGroup => {
this.onGroupSelected(selectedGroup.selected);
}));
}
if (this._databaseNameInputBox) {
this._toDispose.push(styler.attachEditableDropdownStyler(this._databaseNameInputBox, this._themeService));
this._toDispose.push(this._databaseNameInputBox.onFocus(() => {
this._databaseDropdownExpanded = true;
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.sort((a, b) => a.localeCompare(b));
} 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;
}
}));
}
if (this._authTypeSelectBox) {
// Theme styler
@@ -321,10 +390,6 @@ export class ConnectionWidget {
}));
}
this._toDispose.push(this._serverGroupSelectBox.onDidSelect(selectedGroup => {
this.onGroupSelected(selectedGroup.selected);
}));
this._toDispose.push(this._serverNameInputBox.onDidChange(serverName => {
this.serverNameChanged(serverName);
}));
@@ -336,33 +401,6 @@ export class ConnectionWidget {
this._toDispose.push(this._passwordInputBox.onDidChange(passwordInput => {
this._password = passwordInput;
}));
this._toDispose.push(this._databaseNameInputBox.onFocus(() => {
this._databaseDropdownExpanded = true;
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.sort((a, b) => a.localeCompare(b));
} 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) {
@@ -376,7 +414,7 @@ export class ConnectionWidget {
}
private setConnectButton(): void {
let showUsernameAndPassword: boolean = true;
let showUsernameAndPassword: boolean;
if (this.authType) {
showUsernameAndPassword = this.authType === AuthenticationType.SqlLogin;
}
@@ -384,7 +422,7 @@ export class ConnectionWidget {
this._callbacks.onSetConnectButton(!!this.serverName);
}
private onAuthTypeSelected(selectedAuthType: string) {
protected onAuthTypeSelected(selectedAuthType: string) {
let currentAuthType = this.getMatchingAuthType(selectedAuthType);
if (currentAuthType !== AuthenticationType.SqlLogin) {
this._userNameInputBox.disable();
@@ -504,16 +542,20 @@ export class ConnectionWidget {
}
public focusOnServerGroup() {
this._serverGroupSelectBox.focus();
if (this._serverGroupSelectBox) {
this._serverGroupSelectBox.focus();
}
}
public updateServerGroup(connectionGroups: IConnectionProfileGroup[], groupName?: string) {
this._serverGroupOptions = connectionGroups;
this._serverGroupOptions.push(this._addNewServerGroup);
this._serverGroupSelectBox.setOptions(this._serverGroupOptions.map(g => g.name));
if (groupName) {
this._serverGroupSelectBox.selectWithOptionName(groupName);
this._previousGroupOption = this._serverGroupSelectBox.value;
if (this._serverGroupSelectBox) {
this._serverGroupOptions = connectionGroups;
this._serverGroupOptions.push(this._addNewServerGroup);
this._serverGroupSelectBox.setOptions(this._serverGroupOptions.map(g => g.name));
if (groupName) {
this._serverGroupSelectBox.selectWithOptionName(groupName);
this._previousGroupOption = this._serverGroupSelectBox.value;
}
}
}
@@ -541,13 +583,15 @@ export class ConnectionWidget {
public fillInConnectionInputs(connectionInfo: IConnectionProfile) {
if (connectionInfo) {
this._serverNameInputBox.value = this.getModelValue(connectionInfo.serverName);
this._databaseNameInputBox.value = this.getModelValue(connectionInfo.databaseName);
this._connectionNameInputBox.value = this.getModelValue(connectionInfo.connectionName);
this._userNameInputBox.value = this.getModelValue(connectionInfo.userName);
this._passwordInputBox.value = connectionInfo.password ? Constants.passwordChars : '';
this._password = this.getModelValue(connectionInfo.password);
this._saveProfile = connectionInfo.saveProfile;
this._azureTenantId = connectionInfo.azureTenantId;
if (this._databaseNameInputBox) {
this._databaseNameInputBox.value = this.getModelValue(connectionInfo.databaseName);
}
let groupName: string;
if (this._saveProfile) {
if (!connectionInfo.groupFullName) {
@@ -558,8 +602,10 @@ export class ConnectionWidget {
} else {
groupName = this.NoneServerGroup.name;
}
this._serverGroupSelectBox.selectWithOptionName(groupName);
this._previousGroupOption = this._serverGroupSelectBox.value;
if (this._serverGroupSelectBox) {
this._serverGroupSelectBox.selectWithOptionName(groupName);
this._previousGroupOption = this._serverGroupSelectBox.value;
}
// To handle the empty password case
if (this.getModelValue(connectionInfo.password) === '') {
@@ -604,7 +650,7 @@ export class ConnectionWidget {
}
}
private getAuthTypeDisplayName(authTypeName: string) {
protected getAuthTypeDisplayName(authTypeName: string) {
let displayName: string;
let authTypeOption = this._optionsMaps[ConnectionOptionSpecialType.authType];
@@ -632,14 +678,17 @@ export class ConnectionWidget {
public handleOnConnecting(): void {
this._focusedBeforeHandleOnConnection = <HTMLElement>document.activeElement;
this._advancedButton.enabled = false;
this._serverGroupSelectBox.disable();
this._serverNameInputBox.disable();
this._databaseNameInputBox.enabled = false;
this._userNameInputBox.disable();
this._passwordInputBox.disable();
this._connectionNameInputBox.disable();
this._rememberPasswordCheckBox.enabled = false;
if (this._serverGroupSelectBox) {
this._serverGroupSelectBox.disable();
}
if (this._databaseNameInputBox) {
this._databaseNameInputBox.enabled = false;
}
if (this._authTypeSelectBox) {
this._authTypeSelectBox.disable();
}
@@ -647,11 +696,9 @@ export class ConnectionWidget {
public handleResetConnection(): void {
this._advancedButton.enabled = true;
this._serverGroupSelectBox.enable();
this._serverNameInputBox.enable();
this._connectionNameInputBox.enable();
this._databaseNameInputBox.enabled = true;
let currentAuthType: AuthenticationType = undefined;
if (this._authTypeSelectBox) {
this._authTypeSelectBox.enable();
@@ -667,6 +714,14 @@ export class ConnectionWidget {
if (this._focusedBeforeHandleOnConnection) {
this._focusedBeforeHandleOnConnection.focus();
}
if (this._serverGroupSelectBox) {
this._serverGroupSelectBox.enable();
}
if (this._databaseNameInputBox) {
this._databaseNameInputBox.enabled = true;
}
}
public get connectionName(): string {
@@ -678,7 +733,7 @@ export class ConnectionWidget {
}
public get databaseName(): string {
return this._databaseNameInputBox.value;
return this._databaseNameInputBox ? this._databaseNameInputBox.value : undefined;
}
public get userName(): string {
@@ -742,24 +797,26 @@ export class ConnectionWidget {
public connect(model: IConnectionProfile): boolean {
let validInputs = this.validateInputs();
if (validInputs) {
model.connectionName = this.connectionName;
model.serverName = this.serverName;
model.databaseName = this.databaseName;
model.userName = this.userName;
model.password = this.password;
model.authenticationType = this.authenticationType;
model.savePassword = this._rememberPasswordCheckBox.checked;
if (this._serverGroupSelectBox.value === this.DefaultServerGroup.name) {
model.groupFullName = '';
model.saveProfile = true;
model.groupId = this.findGroupId(model.groupFullName);
} else if (this._serverGroupSelectBox.value === this.NoneServerGroup.name) {
model.groupFullName = '';
model.saveProfile = false;
} else if (this._serverGroupSelectBox.value !== this._addNewServerGroup.name) {
model.groupFullName = this._serverGroupSelectBox.value;
model.saveProfile = true;
model.groupId = this.findGroupId(model.groupFullName);
model.connectionName = this.connectionName;
model.databaseName = this.databaseName;
if (this._serverGroupSelectBox) {
if (this._serverGroupSelectBox.value === this.DefaultServerGroup.name) {
model.groupFullName = '';
model.saveProfile = true;
model.groupId = this.findGroupId(model.groupFullName);
} else if (this._serverGroupSelectBox.value === this.NoneServerGroup.name) {
model.groupFullName = '';
model.saveProfile = false;
} else if (this._serverGroupSelectBox.value !== this._addNewServerGroup.name) {
model.groupFullName = this._serverGroupSelectBox.value;
model.saveProfile = true;
model.groupId = this.findGroupId(model.groupFullName);
}
}
if (this.authType === AuthenticationType.AzureMFA) {
model.azureTenantId = this._azureTenantId;
@@ -814,7 +871,7 @@ export class ConnectionWidget {
}
}
enum AuthenticationType {
export enum AuthenticationType {
SqlLogin = 'SqlLogin',
Integrated = 'Integrated',
AzureMFA = 'AzureMFA'