Refresh master with initial release/0.24 snapshot (#332)

* Initial port of release/0.24 source code

* Fix additional headers

* Fix a typo in launch.json
This commit is contained in:
Karl Burtram
2017-12-15 15:38:57 -08:00
committed by GitHub
parent 271b3a0b82
commit 6ad0df0e3e
7118 changed files with 107999 additions and 56466 deletions

View File

@@ -6,7 +6,7 @@
'use strict';
import { IConnectionManagementService, ConnectionOptionSpecialType } from 'sql/parts/connection/common/connectionManagement';
import { IConnectionComponentCallbacks, IConnectionComponentController, IConnectionResult } from 'sql/parts/connection/connectionDialog/connectionDialogService';
import { IConnectionComponentCallbacks, IConnectionComponentController, IConnectionValidateResult } from 'sql/parts/connection/connectionDialog/connectionDialogService';
import { ConnectionWidget } from 'sql/parts/connection/connectionDialog/connectionWidget';
import { AdvancedPropertiesController } from 'sql/parts/connection/connectionDialog/advancedPropertiesController';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
@@ -119,7 +119,7 @@ export class ConnectionController implements IConnectionComponentController {
this._connectionWidget.focusOnOpen();
}
public validateConnection(): IConnectionResult {
public validateConnection(): IConnectionValidateResult {
return { isValid: this._connectionWidget.connect(this._model), connection: this._model };
}

View File

@@ -7,7 +7,7 @@
import {
IConnectionDialogService, IConnectionManagementService, IErrorMessageService,
ConnectionType, INewConnectionParams, IConnectionCompletionOptions
ConnectionType, INewConnectionParams, IConnectionCompletionOptions, IConnectionResult
} from 'sql/parts/connection/common/connectionManagement';
import { ConnectionDialogWidget, OnShowUIResponse } from 'sql/parts/connection/connectionDialog/connectionDialogWidget';
import { ConnectionController } from 'sql/parts/connection/connectionDialog/connectionController';
@@ -24,10 +24,16 @@ import { IPartService } from 'vs/workbench/services/part/common/partService';
import { withElementById } from 'vs/base/browser/builder';
import { TPromise } from 'vs/base/common/winjs.base';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import * as platform from 'vs/base/common/platform';
import Severity from 'vs/base/common/severity';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { Action, IAction } from 'vs/base/common/actions';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import * as types from 'vs/base/common/types';
export interface IConnectionResult {
export interface IConnectionValidateResult {
isValid: boolean;
connection: IConnectionProfile;
}
@@ -42,7 +48,7 @@ export interface IConnectionComponentCallbacks {
export interface IConnectionComponentController {
showUiComponent(container: HTMLElement): void;
initDialog(model: IConnectionProfile): void;
validateConnection(): IConnectionResult;
validateConnection(): IConnectionValidateResult;
fillInConnectionInputs(connectionInfo: IConnectionProfile): void;
handleOnConnecting(): void;
handleResetConnection(): void;
@@ -65,14 +71,17 @@ export class ConnectionDialogService implements IConnectionDialogService {
private _providerTypes: string[];
private _currentProviderType: string = 'Microsoft SQL Server';
private _connecting: boolean = false;
private _connectionErrorTitle = localize('connectionError', 'Connection Error');
private _connectionErrorTitle = localize('connectionError', 'Connection error');
constructor(
@IPartService private _partService: IPartService,
@IInstantiationService private _instantiationService: IInstantiationService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
@IErrorMessageService private _errorMessageService: IErrorMessageService,
@IWorkspaceConfigurationService private _workspaceConfigurationService: IWorkspaceConfigurationService
@IWorkspaceConfigurationService private _workspaceConfigurationService: IWorkspaceConfigurationService,
@IWindowsService private _windowsService: IWindowsService,
@IClipboardService private _clipboardService: IClipboardService,
@ICommandService private _commandService: ICommandService
) {
this._capabilitiesMaps = {};
this._providerNameToDisplayNameMap = {};
@@ -172,13 +181,13 @@ export class ConnectionDialogService implements IConnectionDialogService {
} else if (connectionResult && connectionResult.errorHandled) {
this._connectionDialog.resetConnection();
} else {
this._errorMessageService.showDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage);
this._connectionDialog.resetConnection();
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack);
}
}).catch(err => {
this._connecting = false;
this._errorMessageService.showDialog(Severity.Error, this._connectionErrorTitle, err);
this._connectionDialog.resetConnection();
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, err);
});
}
@@ -277,7 +286,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
connectionManagementService: IConnectionManagementService,
params: INewConnectionParams,
model?: IConnectionProfile,
error?: string): Thenable<void> {
connectionResult?: IConnectionResult): Thenable<void> {
this._connectionManagementService = connectionManagementService;
this._params = params;
@@ -303,8 +312,8 @@ export class ConnectionDialogService implements IConnectionDialogService {
}
resolve(this.showDialogWithModel().then(() => {
if (error && error !== '') {
this._errorMessageService.showDialog(Severity.Error, this._connectionErrorTitle, error);
if (connectionResult && connectionResult.errorMessage) {
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack);
}
}));
}, err => reject(err));
@@ -333,6 +342,33 @@ export class ConnectionDialogService implements IConnectionDialogService {
}
private getCurrentProviderName(): string {
return 'MSSQL';
return Object.keys(this._providerNameToDisplayNameMap).find(providerName => {
return this._currentProviderType === this._providerNameToDisplayNameMap[providerName];
});
}
private showErrorDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string): void {
// Kerberos errors are currently very hard to understand, so adding handling of these to solve the common scenario
// note that ideally we would have an extensible service to handle errors by error code and provider, but for now
// this solves the most common "hard error" that we've noticed
const helpLink = 'https://aka.ms/sqlopskerberos';
let actions: IAction[] = [];
if (!platform.isWindows && types.isString(message) && message.toLowerCase().includes('kerberos') && message.toLowerCase().includes('kinit')) {
message = [
localize('kerberosErrorStart', "Connection failed due to Kerberos error."),
localize('kerberosHelpLink', "&nbsp;Help configuring Kerberos is available at ") + helpLink,
localize('kerberosKinit', "&nbsp;If you have previously connected you may need to re-run kinit.")
].join('<br/>');
actions.push(new Action('Kinit', 'Run kinit', null, true, () => {
this._connectionDialog.close();
this._clipboardService.writeText('kinit\r');
this._commandService.executeCommand('workbench.action.terminal.focus').then(resolve => {
return this._commandService.executeCommand('workbench.action.terminal.paste');
}).then(resolve => null, reject => null);
return null;
}));
}
this._errorMessageService.showDialog(severity, headerTitle, message, messageDetails, actions);
}
}

View File

@@ -4,7 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/connectionDialog';
import { attachModalDialogStyler } from 'sql/common/theme/styler';
import nls = require('vs/nls');
import { Button } from 'sql/base/browser/ui/button/button';
import { attachModalDialogStyler, attachButtonStyler } from 'sql/common/theme/styler';
import { TPromise } from 'vs/base/common/winjs.base';
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { Modal } from 'sql/base/browser/ui/modal/modal';
@@ -14,51 +17,37 @@ import { TreeCreationUtils } from 'sql/parts/registeredServer/viewlet/treeCreati
import { TreeUpdateUtils } from 'sql/parts/registeredServer/viewlet/treeUpdateUtils';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import * as styler from 'vs/platform/theme/common/styler';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { ITree } from 'vs/base/parts/tree/browser/tree';
import Event, { Emitter } from 'vs/base/common/event';
import { Builder, $ } from 'vs/base/browser/builder';
import { Button } from 'vs/base/browser/ui/button/button';
import { DefaultController, ICancelableEvent } from 'vs/base/parts/tree/browser/treeDefaults';
import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { ICancelableEvent } from 'vs/base/parts/tree/browser/treeDefaults';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import * as TelemetryKeys from 'sql/common/telemetryKeys';
import { localize } from 'vs/nls';
import * as DOM from 'vs/base/browser/dom';
import { ITree } from 'vs/base/parts/tree/browser/tree';
import { RecentConnectionTreeController, RecentConnectionActionsProvider } from 'sql/parts/connection/connectionDialog/recentConnectionTreeController';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IMessageService, IConfirmation } from 'vs/platform/message/common/message';
export interface OnShowUIResponse {
selectedProviderType: string;
container: HTMLElement;
}
class TreeController extends DefaultController {
constructor(private clickcb: (element: any, eventish: ICancelableEvent, origin: string) => void) {
super();
}
protected onLeftClick(tree: ITree, element: any, eventish: ICancelableEvent, origin: string = 'mouse'): boolean {
this.clickcb(element, eventish, origin);
return super.onLeftClick(tree, element, eventish, origin);
}
protected onEnter(tree: ITree, event: IKeyboardEvent): boolean {
super.onEnter(tree, event);
this.clickcb(tree.getSelection()[0], event, 'keyboard');
return true;
}
}
export class ConnectionDialogWidget extends Modal {
private _bodyBuilder: Builder;
private _recentConnectionBuilder: Builder;
private _noRecentConnectionBuilder: Builder;
private _dividerBuilder: Builder;
private _connectButton: Button;
private _closeButton: Button;
private _providerTypeSelectBox: SelectBox;
private _newConnectionParams: INewConnectionParams;
private _recentConnectionTree: ITree;
private $connectionUIContainer: Builder;
@@ -89,16 +78,20 @@ export class ConnectionDialogWidget extends Modal {
@IWorkbenchThemeService private _themeService: IWorkbenchThemeService,
@IPartService _partService: IPartService,
@ITelemetryService telemetryService: ITelemetryService,
@IContextKeyService contextKeyService: IContextKeyService
@IContextKeyService contextKeyService: IContextKeyService,
@IContextMenuService private _contextMenuService: IContextMenuService,
@IMessageService private _messageService: IMessageService
) {
super(localize('connection', 'Connection'), TelemetryKeys.Connection, _partService, telemetryService, contextKeyService, { hasSpinner: true, hasErrors: true });
}
protected renderBody(container: HTMLElement): void {
this._bodyBuilder = new Builder(container);
this._providerTypeSelectBox = new SelectBox(this.providerTypeOptions, this.selectedProviderType);
this._bodyBuilder.div({ class: 'connection-recent', id: 'recentConnection' }, (builder) => {
this._recentConnectionBuilder = new Builder(builder.getHTMLElement());
this._noRecentConnectionBuilder = new Builder(builder.getHTMLElement());
this.createRecentConnections();
this._recentConnectionBuilder.hide();
});
@@ -108,16 +101,10 @@ export class ConnectionDialogWidget extends Modal {
});
this._bodyBuilder.div({ class: 'connection-type' }, (modelTableContent) => {
// add SQL Server label to Connection Dialog until we support multiple connection providers
let sqlServerName = localize('microsoftSqlServer', "Microsoft SQL Server");
modelTableContent.div({ class: 'server-name-label' }, (nameLabel) => {
nameLabel.innerHtml(sqlServerName);
});
//let connectTypeLabel = localize('connectType', 'Connection type');
let connectTypeLabel = localize('connectType', 'Connection type');
modelTableContent.element('table', { class: 'connection-table-content' }, (tableContainer) => {
// DialogHelper.appendInputSelectBox(
// DialogHelper.appendRow(tableContainer, connectTypeLabel, 'connection-label', 'connection-input'), this._providerTypeSelectBox);
DialogHelper.appendInputSelectBox(
DialogHelper.appendRow(tableContainer, connectTypeLabel, 'connection-label', 'connection-input'), this._providerTypeSelectBox);
});
});
@@ -141,7 +128,7 @@ export class ConnectionDialogWidget extends Modal {
this._connectButton.enabled = false;
this._closeButton = this.addFooterButton(cancelLabel, () => this.cancel());
this.registerListeners();
this.onProviderTypeSelected('MSSQL');
this.onProviderTypeSelected(this._providerTypeSelectBox.value);
}
// Update theming that is specific to connection flyout body
@@ -156,9 +143,14 @@ export class ConnectionDialogWidget extends Modal {
}
private registerListeners(): void {
this._register(styler.attachButtonStyler(this._connectButton, this._themeService));
this._register(styler.attachButtonStyler(this._closeButton, this._themeService));
// Theme styler
this._register(styler.attachSelectBoxStyler(this._providerTypeSelectBox, this._themeService));
this._register(attachButtonStyler(this._connectButton, this._themeService));
this._register(attachButtonStyler(this._closeButton, this._themeService));
this._register(this._providerTypeSelectBox.onDidSelect(selectedProviderType => {
this.onProviderTypeSelected(selectedProviderType.selected);
}));
}
private onProviderTypeSelected(selectedProviderType: string) {
@@ -171,6 +163,7 @@ export class ConnectionDialogWidget extends Modal {
private connect(element?: IConnectionProfile): void {
if (this._connectButton.enabled) {
this._connectButton.enabled = false;
this._providerTypeSelectBox.disable();
this.showSpinner();
this._onConnect.fire(element);
}
@@ -198,13 +191,37 @@ export class ConnectionDialogWidget extends Modal {
this.hide();
}
private createRecentConnections() {
private clearRecentConnectionList(): TPromise<boolean> {
let confirm: IConfirmation = {
message: nls.localize('clearRecentConnectionMessage', 'Are you sure you want to delete all the connections from the list?'),
primaryButton: localize('yes', 'Yes'),
secondaryButton: localize('no', 'No'),
type: 'question'
};
return this._messageService.confirm(confirm).then(confirmation => {
if (!confirmation.confirmed) {
return TPromise.as(false);
} else {
this._connectionManagementService.clearRecentConnectionsList();
this.open(false);
return TPromise.as(true);
}
});
}
private createRecentConnectionList(): void {
this._recentConnectionBuilder.div({ class: 'connection-recent-content' }, (recentConnectionContainer) => {
let recentHistoryLabel = localize('recentHistory', 'Recent history');
recentConnectionContainer.div({ class: 'connection-history-label' }, (recentTitle) => {
recentTitle.innerHtml(recentHistoryLabel);
recentConnectionContainer.div({ class: 'recent-titles-container'}, (container) => {
container.div({ class: 'connection-history-label' }, (recentTitle) => {
recentTitle.innerHtml(recentHistoryLabel);
});
container.div({ class: 'search-action clear-search-results'}, (clearSearchIcon) => {
clearSearchIcon.on('click', () => this.clearRecentConnectionList());
});
});
recentConnectionContainer.div({ class: 'server-explorer-viewlet' }, (divContainer: Builder) => {
divContainer.div({ class: 'explorer-servers' }, (treeContainer: Builder) => {
let leftClick = (element: any, eventish: ICancelableEvent, origin: string) => {
@@ -212,9 +229,16 @@ export class ConnectionDialogWidget extends Modal {
if (element instanceof ConnectionProfile) {
this.onRecentConnectionClick({ payload: { origin: origin, originalEvent: eventish } }, element);
}
};
let controller = new TreeController(leftClick);
let actionProvider = this._instantiationService.createInstance(RecentConnectionActionsProvider, this._instantiationService, this._connectionManagementService,
this._messageService);
let controller = new RecentConnectionTreeController(leftClick, actionProvider, this._connectionManagementService, this._contextMenuService);
actionProvider.onRecentConnectionRemoved(() => {
this.open(this._connectionManagementService.getRecentConnections().length > 0);
});
controller.onRecentConnectionRemoved(() => {
this.open(this._connectionManagementService.getRecentConnections().length > 0);
})
this._recentConnectionTree = TreeCreationUtils.createConnectionTree(treeContainer.getHTMLElement(), this._instantiationService, controller);
// Theme styler
@@ -225,6 +249,20 @@ export class ConnectionDialogWidget extends Modal {
});
}
private createRecentConnections() {
this.createRecentConnectionList();
this._noRecentConnectionBuilder.div({ class: 'connection-recent-content' }, (noRecentConnectionContainer) => {
let recentHistoryLabel = localize('recentHistory', 'Recent history');
noRecentConnectionContainer.div({ class: 'connection-history-label' }, (recentTitle) => {
recentTitle.innerHtml(recentHistoryLabel);
});
let noRecentHistoryLabel = localize('noRecentConnections', 'No Recent Connections');
noRecentConnectionContainer.div({ class: 'no-recent-connections' }, (noRecentTitle) => {
noRecentTitle.innerHtml(noRecentHistoryLabel);
});
});
}
private onRecentConnectionClick(event: any, element: IConnectionProfile) {
let isMouseOrigin = event.payload && (event.payload.origin === 'mouse');
let isDoubleClick = isMouseOrigin && event.payload.originalEvent && event.payload.originalEvent.detail === 2;
@@ -244,14 +282,15 @@ export class ConnectionDialogWidget extends Modal {
public open(recentConnections: boolean) {
this.show();
if (recentConnections) {
this._noRecentConnectionBuilder.hide();
this._recentConnectionBuilder.show();
TreeUpdateUtils.structuralTreeUpdate(this._recentConnectionTree, 'recent', this._connectionManagementService);
// call layout with view height
this.layout();
} else {
this._recentConnectionBuilder.hide();
this._noRecentConnectionBuilder.show();
}
TreeUpdateUtils.structuralTreeUpdate(this._recentConnectionTree, 'recent', this._connectionManagementService);
// call layout with view height
this.layout();
this.initDialog();
}
@@ -284,6 +323,7 @@ export class ConnectionDialogWidget extends Modal {
public resetConnection(): void {
this.hideSpinner();
this._connectButton.enabled = true;
this._providerTypeSelectBox.enable();
this._onResetConnection.fire();
}
@@ -296,6 +336,7 @@ export class ConnectionDialogWidget extends Modal {
}
public updateProvider(displayName: string) {
this.onProviderTypeSelected('MSSQL');
this._providerTypeSelectBox.selectWithOptionName(displayName);
this.onProviderTypeSelected(displayName);
}
}

View File

@@ -7,10 +7,10 @@
import 'vs/css!./media/sqlConnection';
import { Builder, $ } from 'vs/base/browser/builder';
import { Button } from 'vs/base/browser/ui/button/button';
import { Button } from 'sql/base/browser/ui/button/button';
import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
import { Checkbox } from 'sql/base/browser/ui/checkbox/defaultCheckbox';
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox';
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
import * as DialogHelper from 'sql/base/browser/ui/modal/dialogHelper';
import { IConnectionComponentCallbacks } from 'sql/parts/connection/connectionDialog/connectionDialogService';
@@ -21,11 +21,12 @@ 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 } from 'sql/common/theme/styler';
import { attachInputBoxStyler, attachButtonStyler } 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';
export class ConnectionWidget {
private _builder: Builder;
@@ -36,6 +37,7 @@ export class ConnectionWidget {
private _databaseNameInputBox: InputBox;
private _userNameInputBox: InputBox;
private _passwordInputBox: InputBox;
private _password: string;
private _rememberPasswordCheckBox: Checkbox;
private _advancedButton: Button;
private _callbacks: IConnectionComponentCallbacks;
@@ -43,9 +45,10 @@ export class ConnectionWidget {
private _toDispose: lifecycle.IDisposable[];
private _optionsMaps: { [optionType: number]: data.ConnectionOption };
private _tableContainer: Builder;
private _focusedBeforeHandleOnConnection: HTMLElement;
private _providerName: string;
private _authTypeMap: { [providerName: string]: AuthenticationType[] } = {
[Constants.mssqlProviderName]: [new AuthenticationType('Integrated', false), new AuthenticationType('SqlLogin', true)]
[Constants.mssqlProviderName]: [new AuthenticationType(Constants.integrated, false), new AuthenticationType(Constants.sqlLogin, true)]
};
private _saveProfile: boolean;
public DefaultServerGroup: IConnectionProfileGroup = {
@@ -84,7 +87,14 @@ export class ConnectionWidget {
}
var authTypeOption = this._optionsMaps[ConnectionOptionSpecialType.authType];
this._authTypeSelectBox = authTypeOption ? new SelectBox(authTypeOption.categoryValues.map(c => c.displayName), authTypeOption.defaultValue) : undefined;
if(authTypeOption) {
if (OS === OperatingSystem.Windows) {
authTypeOption.defaultValue = this.getAuthTypeDisplayName(Constants.integrated);
} else {
authTypeOption.defaultValue = this.getAuthTypeDisplayName(Constants.sqlLogin);
}
this._authTypeSelectBox = new SelectBox(authTypeOption.categoryValues.map(c => c.displayName), authTypeOption.defaultValue);
}
this._providerName = providerName;
}
@@ -134,6 +144,7 @@ export class ConnectionWidget {
let passwordBuilder = DialogHelper.appendRow(this._tableContainer, passwordOption.displayName, 'connection-label', 'connection-input');
this._passwordInputBox = new InputBox(passwordBuilder.getHTMLElement(), this._contextViewService);
this._passwordInputBox.inputElement.type = 'password';
this._password = '';
let rememberPasswordLabel = localize('rememberPassword', 'Remember password');
this._rememberPasswordCheckBox = this.appendCheckbox(this._tableContainer, rememberPasswordLabel, 'connection-checkbox', 'connection-input', false);
@@ -201,13 +212,14 @@ export class ConnectionWidget {
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));
this._toDispose.push(styler.attachButtonStyler(this._advancedButton, this._themeService));
this._toDispose.push(attachButtonStyler(this._advancedButton, this._themeService));
if (this._authTypeSelectBox) {
// Theme styler
this._toDispose.push(styler.attachSelectBoxStyler(this._authTypeSelectBox, this._themeService));
this._toDispose.push(this._authTypeSelectBox.onDidSelect(selectedAuthType => {
this.onAuthTypeSelected(selectedAuthType.selected);
this.setConnectButton();
}));
}
@@ -218,6 +230,14 @@ export class ConnectionWidget {
this._toDispose.push(this._serverNameInputBox.onDidChange(serverName => {
this.serverNameChanged(serverName);
}));
this._toDispose.push(this._userNameInputBox.onDidChange(userName => {
this.setConnectButton();
}));
this._toDispose.push(this._passwordInputBox.onDidChange(passwordInput => {
this._password = passwordInput;
}));
}
private onGroupSelected(selectedGroup: string) {
@@ -230,6 +250,17 @@ export class ConnectionWidget {
}
}
private setConnectButton() : void {
let authDisplayName: string = this.getAuthTypeDisplayName(this.authenticationType);
let authType: AuthenticationType = this.getMatchingAuthType(authDisplayName);
let showUsernameAndPassword: boolean = true;
if(authType) {
showUsernameAndPassword = authType.showUsernameAndPassword;
}
showUsernameAndPassword ? this._callbacks.onSetConnectButton(!!this.serverName && !!this.userName) :
this._callbacks.onSetConnectButton(!!this.serverName);
}
private onAuthTypeSelected(selectedAuthType: string) {
let currentAuthType = this.getMatchingAuthType(selectedAuthType);
if (!currentAuthType.showUsernameAndPassword) {
@@ -239,6 +270,7 @@ export class ConnectionWidget {
this._passwordInputBox.hideMessage();
this._userNameInputBox.value = '';
this._passwordInputBox.value = '';
this._password = '';
this._rememberPasswordCheckBox.checked = false;
this._rememberPasswordCheckBox.enabled = false;
@@ -250,7 +282,7 @@ export class ConnectionWidget {
}
private serverNameChanged(serverName: string) {
this._callbacks.onSetConnectButton(!!serverName);
this.setConnectButton();
if (serverName.toLocaleLowerCase().includes('database.windows.net')) {
this._callbacks.onSetAzureTimeOut();
}
@@ -289,10 +321,10 @@ export class ConnectionWidget {
public fillInConnectionInputs(connectionInfo: IConnectionProfile) {
if (connectionInfo) {
this._serverNameInputBox.value = this.getModelValue(connectionInfo.serverName);
this._callbacks.onSetConnectButton(!!connectionInfo.serverName);
this._databaseNameInputBox.value = this.getModelValue(connectionInfo.databaseName);
this._userNameInputBox.value = this.getModelValue(connectionInfo.userName);
this._passwordInputBox.value = this.getModelValue(connectionInfo.password);
this._passwordInputBox.value = connectionInfo.password ? Constants.passwordChars : '';
this._password = this.getModelValue(connectionInfo.password);
this._saveProfile = connectionInfo.saveProfile;
let groupName: string;
if (this._saveProfile) {
@@ -321,18 +353,26 @@ export class ConnectionWidget {
if (this._authTypeSelectBox) {
this.onAuthTypeSelected(this._authTypeSelectBox.value);
}
// Disable connect button if -
// 1. Authentication type is SQL Login and no username is provided
// 2. No server name is provided
this.setConnectButton();
}
}
private getAuthTypeDisplayName(authTypeName: string) {
var displayName: string;
var authTypeOption = this._optionsMaps[ConnectionOptionSpecialType.authType];
authTypeOption.categoryValues.forEach(c => {
if (c.name === authTypeName) {
displayName = c.displayName;
}
});
if(authTypeOption) {
authTypeOption.categoryValues.forEach(c => {
if (c.name === authTypeName) {
displayName = c.displayName;
}
});
}
return displayName;
}
@@ -348,6 +388,7 @@ export class ConnectionWidget {
}
public handleOnConnecting(): void {
this._focusedBeforeHandleOnConnection = <HTMLElement>document.activeElement;
this._advancedButton.enabled = false;
this._serverGroupSelectBox.disable();
@@ -378,6 +419,10 @@ export class ConnectionWidget {
this._passwordInputBox.enable();
this._rememberPasswordCheckBox.enabled = true;
}
if (this._focusedBeforeHandleOnConnection) {
this._focusedBeforeHandleOnConnection.focus();
}
}
public get serverName(): string {
@@ -393,7 +438,7 @@ export class ConnectionWidget {
}
public get password(): string {
return this._passwordInputBox.value;
return this._password;
}
public get authenticationType(): string {
@@ -467,7 +512,8 @@ export class ConnectionWidget {
}
private getMatchingAuthType(displayName: string): AuthenticationType {
return this._authTypeMap[this._providerName].find(authType => this.getAuthTypeDisplayName(authType.name) === displayName);
const authType = this._authTypeMap[this._providerName];
return authType ? authType.find(authType => this.getAuthTypeDisplayName(authType.name) === displayName) : undefined;
}
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#1E1E1E" d="M4.222 0h-2.222v.479c-.526.648-.557 1.57-.043 2.269l.043.059v3.203l-.4.296-.053.053c-.353.352-.547.822-.547 1.321s.194.967.549 1.32c.134.134.288.236.451.322v6.678h14v-16h-11.778z"/><path fill="#E8E8E8" d="M10.798 7l-1.83-2h6.032v2h-4.202zm-2.292-6h-3.207l1.337 1.52 1.87-1.52zm-5.506 8.531v1.469h12v-2h-10.813l-.024.021c-.3.299-.716.479-1.163.51zm0 5.469h12v-2h-12v2zm3.323-8h.631l-.347-.266-.284.266zm8.677-4v-2h-3.289l-1.743 2h5.032z"/><path fill="#F48771" d="M7.246 4.6l2.856-3.277-.405-.002-3.176 2.581-2.607-2.962c-.336-.221-.786-.2-1.082.096-.308.306-.319.779-.069 1.12l2.83 2.444-3.339 2.466c-.339.338-.339.887 0 1.225.339.337.888.337 1.226 0l3.063-2.867 3.33 2.555h.466l-3.093-3.379z"/></svg>

After

Width:  |  Height:  |  Size: 787 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fff" d="M4.222 0h-2.222v.479c-.526.648-.557 1.57-.043 2.269l.043.059v3.203l-.4.296-.053.053c-.353.352-.547.822-.547 1.321s.194.967.549 1.32c.134.134.288.236.451.322v6.678h14v-16h-11.778z"/><path fill="#424242" d="M10.798 7l-1.83-2h6.032v2h-4.202zm-2.292-6h-3.207l1.337 1.52 1.87-1.52zm-5.506 8.531v1.469h12v-2h-10.813l-.024.021c-.3.299-.716.479-1.163.51zm0 5.469h12v-2h-12v2zm3.323-8h.631l-.347-.266-.284.266zm8.677-4v-2h-3.289l-1.743 2h5.032z"/><path fill="#A1260D" d="M7.246 4.6l2.856-3.277-.405-.002-3.176 2.581-2.607-2.962c-.336-.221-.786-.2-1.082.096-.308.306-.319.779-.069 1.12l2.83 2.444-3.339 2.466c-.339.338-.339.887 0 1.225.339.337.888.337 1.226 0l3.063-2.867 3.33 2.555h.466l-3.093-3.379z"/></svg>

After

Width:  |  Height:  |  Size: 784 B

View File

@@ -20,13 +20,22 @@
overflow-y: auto;
}
.connection-history-label {
font-size: 15px;
.no-recent-connections {
font-size: 12px;
text-align: left;
display: block;
padding-top: 5px;
}
.server-name-label {
.connection-history-label {
font-size: 15px;
margin-bottom: 15px;
display: inline;
text-align: left;
}
.recent-titles-container {
display: flex;
justify-content: space-between;
}
.connection-provider-info {
@@ -46,4 +55,17 @@
.connection-type {
margin: 15px;
overflow-y: hidden;
}
.search-action.clear-search-results {
background: url('clear-search-results.svg') center right no-repeat;
width: 10%;
cursor: pointer;
}
.vs-dark .search-action.clear-search-results,
.hc-black .search-action.clear-search-results {
background: url('clear-search-results-dark.svg') center right no-repeat;
width: 10%;
cursor: pointer;
}

View File

@@ -0,0 +1,142 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { DefaultController, ICancelableEvent } from 'vs/base/parts/tree/browser/treeDefaults';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ITree } from 'vs/base/parts/tree/browser/tree';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { ClearSingleRecentConnectionAction } from 'sql/parts/connection/common/connectionActions';
import { ContributableActionProvider } from 'vs/workbench/browser/actions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { IAction } from 'vs/base/common/actions';
import Event, { Emitter } from 'vs/base/common/event';
import { IMessageService } from 'vs/platform/message/common/message';
import mouse = require('vs/base/browser/mouseEvent');
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
export class RecentConnectionActionsProvider extends ContributableActionProvider {
private _onRecentConnectionRemoved = new Emitter<void>();
public onRecentConnectionRemoved: Event<void> = this._onRecentConnectionRemoved.event;
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@IMessageService private _messageService: IMessageService,
) {
super();
}
private getRecentConnectionActions(tree: ITree, element: any): IAction[] {
let actions: IAction[] = [];
let clearSingleConnectionAction = this._instantiationService.createInstance(ClearSingleRecentConnectionAction, ClearSingleRecentConnectionAction.ID,
ClearSingleRecentConnectionAction.LABEL,<IConnectionProfile>element);
clearSingleConnectionAction.onRecentConnectionRemoved(() => this._onRecentConnectionRemoved.fire());
actions.push(clearSingleConnectionAction);
return actions;
}
public hasActions(tree: ITree, element: any): boolean {
return element instanceof ConnectionProfile;
}
/**
* Return actions given an element in the tree
*/
public getActions(tree: ITree, element: any): TPromise<IAction[]> {
if (element instanceof ConnectionProfile) {
return TPromise.as(this.getRecentConnectionActions(tree, element));
}
return TPromise.as([]);
}
}
export class RecentConnectionsActionsContext {
public connectionProfile: ConnectionProfile;
public container: HTMLElement;
public tree: ITree;
}
export class RecentConnectionTreeController extends DefaultController {
private _onRecentConnectionRemoved = new Emitter<void>();
public onRecentConnectionRemoved: Event<void> = this._onRecentConnectionRemoved.event;
constructor(
private clickcb: (element: any, eventish: ICancelableEvent, origin: string) => void,
private actionProvider: RecentConnectionActionsProvider,
private _connectionManagementService: IConnectionManagementService,
@IContextMenuService private _contextMenuService: IContextMenuService
) {
super();
}
protected onLeftClick(tree: ITree, element: any, eventish: ICancelableEvent, origin: string = 'mouse'): boolean {
this.clickcb(element, eventish, origin);
return super.onLeftClick(tree, element, eventish, origin);
}
protected onEnter(tree: ITree, event: IKeyboardEvent): boolean {
super.onEnter(tree, event);
this.clickcb(tree.getSelection()[0], event, 'keyboard');
return true;
}
protected onRightClick(tree: ITree, element: any, eventish: ICancelableEvent, origin: string = 'mouse'): boolean {
this.clickcb(element, eventish, origin);
this.onContextMenu(tree, element, event);
return true;
}
public onMouseDown(tree: ITree, element: any, event: mouse.IMouseEvent, origin: string = 'mouse'): boolean {
if (event.leftButton || event.middleButton) {
return this.onLeftClick(tree, element, event, origin);
} else {
return this.onRightClick(tree, element, event);
}
}
public onKeyDown(tree: ITree, event: IKeyboardEvent): boolean {
if (event.keyCode === 20) {
let element = tree.getFocus();
if (element instanceof ConnectionProfile) {
this._connectionManagementService.clearRecentConnection(element);
this._onRecentConnectionRemoved.fire();
return true;
}
}
return super.onKeyDown(tree, event);
}
public onContextMenu(tree: ITree, element: any, event: any): boolean {
var actionContext: any;
if (element instanceof ConnectionProfile) {
actionContext = new RecentConnectionsActionsContext();
actionContext.container = event.target;
actionContext.connectionProfile = <ConnectionProfile>element;
actionContext.tree = tree;
} else {
actionContext = element;
}
let anchor = { x: event.x + 1, y: event.y };
this._contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => this.actionProvider.getActions(tree, element),
onHide: (wasCancelled?: boolean) => {
if (wasCancelled) {
tree.DOMFocus();
}
},
getActionsContext: () => (actionContext)
});
return true;
}
}