mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-24 17:23:05 -05:00
Added error handling service for providers (#21627)
* added prototype errorHandlerService * added initial contracts * Added WIP client sent request function * added WIP signature for handleOtherError to resourceProviderService * made some small fixes * removed unnecessary resourceProviderId * added updates to contracts and resourceProvider * moved error codes to azdata proposed * added connection type instead of profile * added WIP handleOtherError code * added fix for send * added WIP change password function in resource provider * added work in progress error handling thread * added errorHandler interface * added result error check * renamed errorHandling namespace to diagnostics * WIP rename of errorhandler * light cleanup * Bump json5 from 2.1.3 to 2.2.3 in /extensions/machine-learning (#21514) Bumps [json5](https://github.com/json5/json5) from 2.1.3 to 2.2.3. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v2.1.3...v2.2.3) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Stops second invocation of createNewSession while expanding OE tree items on disconnected servers (#21437) * Debounces second invocation while expanding OE tree items * Minor clean up * Adjusts debounce time * Adding temp trace comments * Adds missing semicolon * Removes debouncer to stop 2nd newSession calls * Removes temp trace comments * Updates comment Co-authored-by: Alan Ren <alanren@microsoft.com> * Bump json5 from 2.1.3 to 2.2.3 in /extensions/admin-tool-ext-win (#21546) Bumps [json5](https://github.com/json5/json5) from 2.1.3 to 2.2.3. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v2.1.3...v2.2.3) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Fix resource endpoints to end with slash (#21540) * Bump json5 from 2.1.3 to 2.2.3 in /extensions/azcli (#21543) Bumps [json5](https://github.com/json5/json5) from 2.1.3 to 2.2.3. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v2.1.3...v2.2.3) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump json5 from 2.1.3 to 2.2.3 in /extensions/arc (#21544) Bumps [json5](https://github.com/json5/json5) from 2.1.3 to 2.2.3. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v2.1.3...v2.2.3) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * renamed diagnostics service slightly * registered service * added work in progress diagnostics implementation * small changes * added new diagnostics exe * Changes for Diagnostics Service (#21583) Co-authored-by: Cheena Malhotra <cmalhotra@microsoft.com> * WIP provider changes * added changes for errorDiagnosticsService * removed stuff from mssql. * made fix to connectionManagementService * added error catch * added small changes * more small changes made * added small changes to handleOtherError * moved changePassword to CMS * added testErrorDiagnosticsService * Added provider-based handling for change password/generic error handling. (#21662) * WIP rework for error connection change * added connectionProfileDuringError * added working password reset * added comments * consolidated connection profile conversion * added additionalObjects parameter. * removed unnecessary error profile grab * added comments * added changes to parameters and comments * added changes and params * added handleConnectionErrorParam * added more changes * added async * added params and more * added many fixes * added updated documentation * added WIP password change dialog with await * added error handling * added comment * added options as parameters * cleaned up parameters * added async * added check fixes * Added username to title * added server name to dialog * Added dialog changes * Revert "Added dialog changes" This reverts commit c2bdcd16f4a0dffdc643ef9cae1c1a20642ac512. * Revert "added server name to dialog" This reverts commit dbd22e80461b5a068643f0c2d6728adce4010978. * Revert "Added username to title" This reverts commit 6d936b4d5f97f9345f8ec2fdbbcf6b52df18820a. * Revert "added check fixes" This reverts commit f58081a5af3276766e2042b4d671455b18add9a7. * Revert "added async" This reverts commit dd1198e26ec7542ec51add0628f588361d674299. * Revert "cleaned up parameters" This reverts commit 51135c9f9db452104697483779d8df15b6430717. * Revert "added options as parameters" This reverts commit b167804a2410558bbe60042e017ae2c77af7697f. * Revert "added comment" This reverts commit 0ad37326a3e025e88f715e3f2547be6825597a8d. * Revert "added error handling" This reverts commit 69340980d2c84056a2bcf126ea77f4b5ed4cddf3. * Revert "added WIP password change dialog with await" This reverts commit 9e43113e07b10421b39575f6c7dd14287662b90d. * added a fix to check * added fixes * added back in change password changes * added in comment * added suggested changes * removed param colons * Update extensions/mssql/src/errorDiagnostics/errorDiagnosticsProvider.ts Co-authored-by: Charles Gagnon <chgagnon@microsoft.com> * Update src/sql/azdata.proposed.d.ts Co-authored-by: Charles Gagnon <chgagnon@microsoft.com> * fixed conversion and provider dialog * altered comments * Update src/sql/platform/connection/common/utils.ts Co-authored-by: Charles Gagnon <chgagnon@microsoft.com> * renamed Id * Update src/sql/platform/connection/common/utils.ts Co-authored-by: Charles Gagnon <chgagnon@microsoft.com> * Improvements for Change password dialog + logs added (#21794) * Improvements for Change password dialog + logs added * Include server * fixed tab space * added comment --------- Co-authored-by: Alex Ma <alma1@microsoft.com> * Update src/sql/azdata.proposed.d.ts Co-authored-by: Charles Gagnon <chgagnon@microsoft.com> * added fix to id to extHostErrorDiagnostics --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Lewis Sanchez <87730006+lewis-sanchez@users.noreply.github.com> Co-authored-by: Alan Ren <alanren@microsoft.com> Co-authored-by: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com> Co-authored-by: Cheena Malhotra <cmalhotra@microsoft.com> Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
This commit is contained in:
@@ -30,7 +30,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { CmsConnectionController } from 'sql/workbench/services/connection/browser/cmsConnectionController';
|
||||
import { PasswordChangeDialog } from 'sql/workbench/services/connection/browser/passwordChangeDialog';
|
||||
import { entries } from 'sql/base/common/collections';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
@@ -284,9 +283,6 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
} else if (connectionResult && connectionResult.errorHandled) {
|
||||
this._connectionDialog.resetConnection();
|
||||
this._logService.debug(`ConnectionDialogService: Error handled and connection reset - Error: ${connectionResult.errorMessage}`);
|
||||
} else if (connection.providerName === Constants.mssqlProviderName && connectionResult.errorCode === Constants.sqlPasswordErrorCode) {
|
||||
this._connectionDialog.resetConnection();
|
||||
this.launchChangePasswordDialog(connection, params);
|
||||
} else {
|
||||
this._connectionDialog.resetConnection();
|
||||
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack, connectionResult.errorCode);
|
||||
@@ -507,11 +503,6 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
recentConnections.forEach(conn => conn.dispose());
|
||||
}
|
||||
|
||||
public launchChangePasswordDialog(profile: IConnectionProfile, params: INewConnectionParams): void {
|
||||
let dialog = this._instantiationService.createInstance(PasswordChangeDialog);
|
||||
dialog.open(profile, params);
|
||||
}
|
||||
|
||||
|
||||
private showErrorDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, errorCode?: number): void {
|
||||
// Kerberos errors are currently very hard to understand, so adding handling of these to solve the common scenario
|
||||
|
||||
@@ -55,6 +55,8 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b
|
||||
import { ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { VIEWLET_ID as ExtensionsViewletID } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IErrorDiagnosticsService } from 'sql/workbench/services/diagnostics/common/errorDiagnosticsService';
|
||||
import { PasswordChangeDialog } from 'sql/workbench/services/connection/browser/passwordChangeDialog';
|
||||
|
||||
export class ConnectionManagementService extends Disposable implements IConnectionManagementService {
|
||||
|
||||
@@ -94,6 +96,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
@IQuickInputService private _quickInputService: IQuickInputService,
|
||||
@INotificationService private _notificationService: INotificationService,
|
||||
@IResourceProviderService private _resourceProviderService: IResourceProviderService,
|
||||
@IErrorDiagnosticsService private _errorDiagnosticsService: IErrorDiagnosticsService,
|
||||
@IAngularEventingService private _angularEventing: IAngularEventingService,
|
||||
@IAccountManagementService private _accountManagementService: IAccountManagementService,
|
||||
@ILogService private _logService: ILogService,
|
||||
@@ -430,7 +433,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
/**
|
||||
* Changes password of the connection profile's user.
|
||||
*/
|
||||
public changePassword(connection: interfaces.IConnectionProfile, uri: string, newPassword: string):
|
||||
public async changePassword(connection: interfaces.IConnectionProfile, uri: string, newPassword: string):
|
||||
Promise<azdata.PasswordChangeResult> {
|
||||
return this.sendChangePasswordRequest(connection, uri, newPassword);
|
||||
}
|
||||
@@ -552,20 +555,32 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
});
|
||||
}
|
||||
|
||||
private handleConnectionError(connection: interfaces.IConnectionProfile, uri: string, options: IConnectionCompletionOptions, callbacks: IConnectionCallbacks, connectionResult: IConnectionResult) {
|
||||
private async handleConnectionError(connection: interfaces.IConnectionProfile, uri: string, options: IConnectionCompletionOptions, callbacks: IConnectionCallbacks, connectionResult: IConnectionResult) {
|
||||
let connectionNotAcceptedError = nls.localize('connectionNotAcceptedError', "Connection Not Accepted");
|
||||
if (options.showFirewallRuleOnError && connectionResult.errorCode) {
|
||||
return this.handleFirewallRuleError(connection, connectionResult).then(success => {
|
||||
if (success) {
|
||||
options.showFirewallRuleOnError = false;
|
||||
let firewallRuleErrorHandled = await this.handleFirewallRuleError(connection, connectionResult);
|
||||
if (firewallRuleErrorHandled) {
|
||||
options.showFirewallRuleOnError = false;
|
||||
return this.connectWithOptions(connection, uri, options, callbacks);
|
||||
}
|
||||
else {
|
||||
let connectionErrorHandled = await this._errorDiagnosticsService.tryHandleConnectionError(connectionResult.errorCode, connectionResult.errorMessage, connection.providerName, connection);
|
||||
if (connectionErrorHandled.handled) {
|
||||
connectionResult.errorHandled = true;
|
||||
if (connectionErrorHandled.options) {
|
||||
//copy over altered connection options from the result if provided.
|
||||
connection.options = connectionErrorHandled.options;
|
||||
}
|
||||
return this.connectWithOptions(connection, uri, options, callbacks);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Error not handled by any registered providers so fail the connection
|
||||
if (callbacks.onConnectReject) {
|
||||
callbacks.onConnectReject(connectionNotAcceptedError);
|
||||
}
|
||||
return connectionResult;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (callbacks.onConnectReject) {
|
||||
callbacks.onConnectReject(connectionNotAcceptedError);
|
||||
@@ -585,6 +600,12 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
});
|
||||
}
|
||||
|
||||
public async openChangePasswordDialog(profile: interfaces.IConnectionProfile): Promise<string | undefined> {
|
||||
let dialog = this._instantiationService.createInstance(PasswordChangeDialog);
|
||||
let result = await dialog.open(profile);
|
||||
return result;
|
||||
}
|
||||
|
||||
private doActionsAfterConnectionComplete(uri: string, options: IConnectionCompletionOptions): void {
|
||||
let connectionManagementInfo = this._connectionStatusManager.findConnection(uri);
|
||||
if (!connectionManagementInfo) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
.change-password-dialog {
|
||||
width: 100%;
|
||||
padding: 30px;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
@@ -15,8 +15,9 @@
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.change-password-dialog .component-label {
|
||||
vertical-align: middle;
|
||||
.change-password-dialog .component-label-bold {
|
||||
font-weight: 600;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.change-password-dialog .components-grid {
|
||||
@@ -25,7 +26,7 @@
|
||||
grid-template-columns: max-content 1fr;
|
||||
grid-template-rows: max-content;
|
||||
grid-gap: 10px;
|
||||
padding: 5px;
|
||||
padding: 30px 0px 10px;
|
||||
align-content: start;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { Modal } from 'sql/workbench/browser/modal/modal';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { attachInputBoxStyler } from 'sql/platform/theme/common/styler';
|
||||
import { INewConnectionParams } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
@@ -19,7 +18,6 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
|
||||
@@ -27,12 +25,11 @@ import { attachModalDialogStyler } from 'sql/workbench/common/styler';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfiguration';
|
||||
|
||||
const dialogWidth: string = '300px'; // Width is set manually here as there is no default width for normal dialogs.
|
||||
const dialogWidth: string = '500px'; // Width is set manually here as there is no default width for normal dialogs.
|
||||
const okText: string = localize('passwordChangeDialog.ok', "OK");
|
||||
const cancelText: string = localize('passwordChangeDialog.cancel', "Cancel");
|
||||
const dialogTitle: string = localize('passwordChangeDialog.title', "Change Password");
|
||||
const newPasswordText: string = localize('passwordChangeDialog.newPassword', 'New password:');
|
||||
const confirmPasswordText: string = localize('passwordChangeDialog.confirmPassword', 'Confirm password:');
|
||||
const newPasswordText: string = localize('passwordChangeDialog.newPassword', "New password:");
|
||||
const confirmPasswordText: string = localize('passwordChangeDialog.confirmPassword', "Confirm password:");
|
||||
const passwordChangeLoadText: string = localize('passwordChangeDialog.connecting', "Connecting");
|
||||
const errorHeader: string = localize('passwordChangeDialog.errorHeader', "Failure when attempting to change password");
|
||||
const errorPasswordMismatchErrorMessage = localize('passwordChangeDialog.errorPasswordMismatchErrorMessage', "Passwords entered do not match");
|
||||
@@ -42,8 +39,8 @@ export class PasswordChangeDialog extends Modal {
|
||||
|
||||
private _okButton?: Button;
|
||||
private _cancelButton?: Button;
|
||||
private _promiseResolver: (value: string) => void;
|
||||
private _profile: IConnectionProfile;
|
||||
private _params: INewConnectionParams;
|
||||
private _uri: string;
|
||||
private _passwordValueText: InputBox;
|
||||
private _confirmValueText: InputBox;
|
||||
@@ -53,7 +50,6 @@ export class PasswordChangeDialog extends Modal {
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@IConnectionManagementService private readonly connectionManagementService: IConnectionManagementService,
|
||||
@IErrorMessageService private readonly errorMessageService: IErrorMessageService,
|
||||
@IConnectionDialogService private readonly connectionDialogService: IConnectionDialogService,
|
||||
@ILayoutService layoutService: ILayoutService,
|
||||
@IAdsTelemetryService telemetryService: IAdsTelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@@ -64,31 +60,43 @@ export class PasswordChangeDialog extends Modal {
|
||||
super('', '', telemetryService, layoutService, clipboardService, themeService, logService, textResourcePropertiesService, contextKeyService, { hasSpinner: true, spinnerTitle: passwordChangeLoadText, dialogStyle: 'normal', width: dialogWidth, dialogPosition: 'left' });
|
||||
}
|
||||
|
||||
public open(profile: IConnectionProfile, params: INewConnectionParams) {
|
||||
public open(profile: IConnectionProfile): Promise<string> {
|
||||
if (this._profile) {
|
||||
// If already in the middle of a password change, reject an incoming open.
|
||||
let message = localize('passwordChangeDialog.passwordChangeInProgress', "Password change already in progress")
|
||||
this.errorMessageService.showDialog(Severity.Error, errorHeader, message);
|
||||
return Promise.reject(new Error(message));
|
||||
}
|
||||
this._profile = profile;
|
||||
this._params = params;
|
||||
this._uri = this.connectionManagementService.getConnectionUri(profile);
|
||||
this.render();
|
||||
this.show();
|
||||
this._okButton!.focus();
|
||||
const promise = new Promise<string | undefined>((resolve) => {
|
||||
this._promiseResolver = resolve;
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
public override dispose(): void {
|
||||
|
||||
}
|
||||
public override dispose(): void { }
|
||||
|
||||
public override render() {
|
||||
super.render();
|
||||
this.title = dialogTitle;
|
||||
this.title = localize('passwordChangeDialog.title', 'Change Password');
|
||||
this._register(attachModalDialogStyler(this, this._themeService));
|
||||
this._okButton = this.addFooterButton(okText, () => this.handleOkButtonClick());
|
||||
this._cancelButton = this.addFooterButton(cancelText, () => this.hide('cancel'), 'right', true);
|
||||
this._okButton = this.addFooterButton(okText, async () => { await this.handleOkButtonClick(); });
|
||||
this._cancelButton = this.addFooterButton(cancelText, () => { this.handleCancelButtonClick(); }, 'right', true);
|
||||
this._register(attachButtonStyler(this._okButton, this._themeService));
|
||||
this._register(attachButtonStyler(this._cancelButton, this._themeService));
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
const body = container.appendChild(DOM.$('.change-password-dialog'));
|
||||
body.appendChild(DOM.$('span.component-label-bold')).innerText = localize('passwordChangeDialog.Message1',
|
||||
`Password must be changed for '{0}' to continue logging into '{1}'.`, this._profile?.userName, this._profile?.serverName);
|
||||
body.appendChild(DOM.$('span.component-label')).innerText = localize('passwordChangeDialog.Message2',
|
||||
`Please enter a new password below:`);
|
||||
|
||||
const contentElement = body.appendChild(DOM.$('.properties-content.components-grid'));
|
||||
contentElement.appendChild(DOM.$('')).appendChild(DOM.$('span.component-label')).innerText = newPasswordText;
|
||||
const passwordInputContainer = contentElement.appendChild(DOM.$(''));
|
||||
@@ -107,42 +115,50 @@ export class PasswordChangeDialog extends Modal {
|
||||
|
||||
/* espace key */
|
||||
protected override onClose() {
|
||||
this.hide('close');
|
||||
this.handleCancelButtonClick();
|
||||
}
|
||||
|
||||
/* enter key */
|
||||
protected override onAccept() {
|
||||
this.handleOkButtonClick();
|
||||
protected override async onAccept() {
|
||||
await this.handleOkButtonClick();
|
||||
}
|
||||
|
||||
private handleOkButtonClick(): void {
|
||||
private async handleOkButtonClick(): Promise<void> {
|
||||
this._okButton.enabled = false;
|
||||
this._cancelButton.enabled = false;
|
||||
this.spinner = true;
|
||||
this.changePasswordFunction(this._profile, this._params, this._uri, this._passwordValueText.value, this._confirmValueText.value).then(
|
||||
() => {
|
||||
this.hide('ok'); /* password changed successfully */
|
||||
},
|
||||
() => {
|
||||
this._okButton.enabled = true; /* ignore, user must try again */
|
||||
this._cancelButton.enabled = true;
|
||||
this.spinner = false;
|
||||
}
|
||||
);
|
||||
try {
|
||||
let result = await this.changePasswordFunction(this._profile, this._uri, this._passwordValueText.value, this._confirmValueText.value);
|
||||
this.hide('ok'); /* password changed successfully */
|
||||
this._promiseResolver(result);
|
||||
}
|
||||
catch {
|
||||
// Error encountered, keep the dialog open and reset dialog back to previous state.
|
||||
this._okButton.enabled = true; /* ignore, user must try again */
|
||||
this._cancelButton.enabled = true;
|
||||
this.spinner = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async changePasswordFunction(connection: IConnectionProfile, params: INewConnectionParams, uri: string, oldPassword: string, newPassword: string): Promise<void> {
|
||||
private handleCancelButtonClick(): void {
|
||||
this.hide('cancel');
|
||||
this._promiseResolver(undefined);
|
||||
}
|
||||
|
||||
private async changePasswordFunction(connection: IConnectionProfile, uri: string, oldPassword: string, newPassword: string): Promise<string> {
|
||||
// Verify passwords match before changing the password.
|
||||
if (oldPassword !== newPassword) {
|
||||
this.errorMessageService.showDialog(Severity.Error, errorHeader, errorPasswordMismatchErrorMessage + '\n\n' + errorPasswordMismatchRecoveryInstructions);
|
||||
return Promise.reject(new Error(errorPasswordMismatchErrorMessage));
|
||||
}
|
||||
|
||||
let passwordChangeResult = await this.connectionManagementService.changePassword(connection, uri, newPassword);
|
||||
if (!passwordChangeResult.result) {
|
||||
this.errorMessageService.showDialog(Severity.Error, errorHeader, passwordChangeResult.errorMessage);
|
||||
return Promise.reject(new Error(passwordChangeResult.errorMessage));
|
||||
}
|
||||
connection.options['password'] = newPassword;
|
||||
await this.connectionDialogService.callDefaultOnConnect(connection, params);
|
||||
|
||||
return newPassword;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { TestCapabilitiesService } from 'sql/platform/capabilities/test/common/testCapabilitiesService';
|
||||
import { TestConnectionProvider } from 'sql/platform/connection/test/common/testConnectionProvider';
|
||||
import { TestResourceProvider } from 'sql/workbench/services/resourceProvider/test/common/testResourceProviderService';
|
||||
import { TestErrorDiagnosticsService } from 'sql/workbench/services/connection/test/common/testErrorDiagnosticsService';
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
|
||||
@@ -52,6 +53,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
||||
let workspaceConfigurationServiceMock: TypeMoq.Mock<TestConfigurationService>;
|
||||
let resourceProviderStubMock: TypeMoq.Mock<TestResourceProvider>;
|
||||
let accountManagementService: TypeMoq.Mock<TestAccountManagementService>;
|
||||
let errorDiagnosticsService: TestErrorDiagnosticsService;
|
||||
|
||||
let none: void;
|
||||
|
||||
@@ -99,6 +101,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
||||
let resourceProviderStub = new TestResourceProvider();
|
||||
resourceProviderStubMock = TypeMoq.Mock.ofInstance(resourceProviderStub);
|
||||
accountManagementService = TypeMoq.Mock.ofType(TestAccountManagementService);
|
||||
errorDiagnosticsService = new TestErrorDiagnosticsService();
|
||||
let root = new ConnectionProfileGroup(ConnectionProfileGroup.RootGroupName, undefined, ConnectionProfileGroup.RootGroupName, undefined, undefined);
|
||||
root.connections = [ConnectionProfile.fromIConnectionProfile(capabilitiesService, connectionProfile)];
|
||||
|
||||
@@ -181,6 +184,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
||||
undefined, // IQuickInputService
|
||||
new TestNotificationService(),
|
||||
resourceProviderStubMock.object,
|
||||
errorDiagnosticsService,
|
||||
undefined, // IAngularEventingService
|
||||
accountManagementService.object,
|
||||
testLogService, // ILogService
|
||||
@@ -1574,7 +1578,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
||||
const testInstantiationService = new TestInstantiationService();
|
||||
testInstantiationService.stub(IStorageService, new TestStorageService());
|
||||
testInstantiationService.stubCreateInstance(ConnectionStore, connectionStoreMock.object);
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, errorDiagnosticsService, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
assert.strictEqual(profile.password, '', 'Profile should not have password initially');
|
||||
assert.strictEqual(profile.options['password'], '', 'Profile options should not have password initially');
|
||||
// Check for invalid profile id
|
||||
@@ -1604,7 +1608,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
||||
testInstantiationService.stub(IStorageService, new TestStorageService());
|
||||
testInstantiationService.stubCreateInstance(ConnectionStore, connectionStoreMock.object);
|
||||
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, errorDiagnosticsService, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
assert.strictEqual(profile.password, '', 'Profile should not have password initially');
|
||||
assert.strictEqual(profile.options['password'], '', 'Profile options should not have password initially');
|
||||
let credentials = await connectionManagementService.getConnectionCredentials(profile.id);
|
||||
@@ -1924,7 +1928,7 @@ suite('SQL ConnectionManagementService tests', () => {
|
||||
createInstanceStub.withArgs(ConnectionStore).returns(connectionStoreMock.object);
|
||||
createInstanceStub.withArgs(ConnectionStatusManager).returns(connectionStatusManagerMock.object);
|
||||
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, errorDiagnosticsService, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
|
||||
// dupe connections have been seeded the numbers below already reflected the de-duped results
|
||||
|
||||
@@ -1957,7 +1961,7 @@ test('isRecent should evaluate whether a profile was recently connected or not',
|
||||
});
|
||||
let profile1 = createConnectionProfile('1');
|
||||
let profile2 = createConnectionProfile('2');
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, new TestErrorDiagnosticsService(), undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
assert(connectionManagementService.isRecent(profile1));
|
||||
assert(!connectionManagementService.isRecent(profile2));
|
||||
});
|
||||
@@ -1975,7 +1979,7 @@ test('clearRecentConnection and ConnectionsList should call connectionStore func
|
||||
testInstantiationService.stub(IStorageService, new TestStorageService());
|
||||
sinon.stub(testInstantiationService, 'createInstance').withArgs(ConnectionStore).returns(connectionStoreMock.object);
|
||||
let profile1 = createConnectionProfile('1');
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, new TestErrorDiagnosticsService(), undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
connectionManagementService.clearRecentConnection(profile1);
|
||||
assert(called);
|
||||
called = false;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { IErrorDiagnosticsService } from 'sql/workbench/services/diagnostics/common/errorDiagnosticsService';
|
||||
|
||||
export class TestErrorDiagnosticsService implements IErrorDiagnosticsService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
registerDiagnosticsProvider(providerId: string, errorDiagnostics: azdata.diagnostics.ErrorDiagnosticsProvider): void {
|
||||
}
|
||||
|
||||
unregisterDiagnosticsProvider(ProviderId: string): void {
|
||||
}
|
||||
|
||||
tryHandleConnectionError(errorCode: number, errorMessage: string, providerId: string, connection: azdata.IConnectionProfile): Promise<azdata.diagnostics.ConnectionDiagnosticsResult> {
|
||||
return Promise.resolve({ handled: false });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IErrorDiagnosticsService } from 'sql/workbench/services/diagnostics/common/errorDiagnosticsService';
|
||||
import * as azdata from 'azdata';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import * as Utils from 'sql/platform/connection/common/utils';
|
||||
import * as interfaces from 'sql/platform/connection/common/interfaces';
|
||||
|
||||
export class ErrorDiagnosticsService implements IErrorDiagnosticsService {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
private _providers: { [handle: string]: azdata.diagnostics.ErrorDiagnosticsProvider; } = Object.create(null);
|
||||
|
||||
constructor(
|
||||
@ILogService private readonly _logService: ILogService
|
||||
) { }
|
||||
|
||||
public async tryHandleConnectionError(errorCode: number, errorMessage: string, providerId: string, connection: interfaces.IConnectionProfile): Promise<azdata.diagnostics.ConnectionDiagnosticsResult> {
|
||||
let result = { handled: false };
|
||||
let provider = this._providers[providerId]
|
||||
if (provider) {
|
||||
result = await provider.handleConnectionError(errorCode, errorMessage, Utils.convertToRpcConnectionProfile(connection));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a diagnostic provider object for a provider
|
||||
* Note: only ONE diagnostic provider object can be assigned to a specific provider at a time.
|
||||
* @param providerId the id of the provider to register.
|
||||
* @param errorDiagnostics the actual diagnostics provider object to register under the id.
|
||||
*/
|
||||
public registerDiagnosticsProvider(providerId: string, errorDiagnostics: azdata.diagnostics.ErrorDiagnosticsProvider): void {
|
||||
if (this._providers[providerId]) {
|
||||
this._logService.error('Provider ' + providerId + ' was already registered, cannot register again.')
|
||||
}
|
||||
else {
|
||||
this._providers[providerId] = errorDiagnostics;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a diagnostics provider object for a provider
|
||||
* @param providerId the id of the provider to unregister.
|
||||
*/
|
||||
public unregisterDiagnosticsProvider(providerId: string): void {
|
||||
delete this._providers[providerId];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export const SERVICE_ID = 'errorDiagnosticsService';
|
||||
export const IErrorDiagnosticsService = createDecorator<IErrorDiagnosticsService>(SERVICE_ID);
|
||||
|
||||
export interface IErrorDiagnosticsService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Register a diagnostics provider object for a provider
|
||||
* Note: only ONE diagnostic provider object can be assigned to a specific provider at a time.
|
||||
* @param providerId the id of the provider to be registered.
|
||||
* @param errorDiagnostics the actual diagnostics provider object to be registered under the id.
|
||||
*/
|
||||
registerDiagnosticsProvider(providerId: string, errorDiagnostics: azdata.diagnostics.ErrorDiagnosticsProvider): void;
|
||||
|
||||
/**
|
||||
* Unregister a diagnostics provider object for a provider
|
||||
* @param providerId the id of the provider to be unregistered.
|
||||
*/
|
||||
unregisterDiagnosticsProvider(ProviderId: string): void;
|
||||
|
||||
/**
|
||||
* Checks connection error with given parameters
|
||||
* @param errorCode Error code indicating the error problem.
|
||||
* @param errorMessage Error message that describes the problem in detail.
|
||||
* @param providerId Identifies what provider the error comes from.
|
||||
* @param connection Connection profile that is utilized for connection
|
||||
* @returns a Promise containing a ConnectionDiagnosticsResult object (with handling status and altered options)
|
||||
*/
|
||||
tryHandleConnectionError(errorCode: number, errorMessage: string, providerId: string, connection: azdata.IConnectionProfile): Promise<azdata.diagnostics.ConnectionDiagnosticsResult>;
|
||||
}
|
||||
Reference in New Issue
Block a user