mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-18 09:35:39 -05:00
handle unsupported connection provider (#20577)
* handle unknown connection provider * fix error
This commit is contained in:
@@ -141,6 +141,11 @@ export class MainThreadConnectionManagement extends Disposable implements MainTh
|
||||
}
|
||||
|
||||
public async $openConnectionDialog(providers: string[], initialConnectionProfile?: IConnectionProfile, connectionCompletionOptions?: azdata.IConnectionCompletionOptions): Promise<azdata.connection.Connection | undefined> {
|
||||
if (initialConnectionProfile?.providerName && this._capabilitiesService.providers[initialConnectionProfile.providerName] === undefined) {
|
||||
await this._connectionManagementService.handleUnsupportedProvider(initialConnectionProfile.providerName);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Here we default to ConnectionType.editor which saves the connecton in the connection store by default
|
||||
let connectionType = ConnectionType.editor;
|
||||
|
||||
|
||||
@@ -25,20 +25,25 @@ export const DE_MANAGE_COMMAND_ID = 'dataExplorer.manage';
|
||||
// Manage
|
||||
CommandsRegistry.registerCommand({
|
||||
id: DE_MANAGE_COMMAND_ID,
|
||||
handler: (accessor, args: TreeViewItemHandleArg) => {
|
||||
handler: async (accessor, args: TreeViewItemHandleArg) => {
|
||||
if (args.$treeItem) {
|
||||
const connectionService = accessor.get(IConnectionManagementService);
|
||||
const capabilitiesService = accessor.get(ICapabilitiesService);
|
||||
let options = {
|
||||
showDashboard: true,
|
||||
saveTheConnection: false,
|
||||
params: undefined,
|
||||
showConnectionDialogOnError: true,
|
||||
showFirewallRuleOnError: true
|
||||
};
|
||||
let profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
|
||||
let uri = generateUri(profile, 'dashboard');
|
||||
return connectionService.connect(new ConnectionProfile(capabilitiesService, args.$treeItem.payload), uri, options);
|
||||
const providerName = args.$treeItem?.payload?.providerName;
|
||||
if (providerName && capabilitiesService.providers[providerName] === undefined) {
|
||||
await connectionService.handleUnsupportedProvider(providerName);
|
||||
} else {
|
||||
let options = {
|
||||
showDashboard: true,
|
||||
saveTheConnection: false,
|
||||
params: undefined,
|
||||
showConnectionDialogOnError: true,
|
||||
showFirewallRuleOnError: true
|
||||
};
|
||||
let profile = new ConnectionProfile(capabilitiesService, args.$treeItem.payload);
|
||||
let uri = generateUri(profile, 'dashboard');
|
||||
return connectionService.connect(new ConnectionProfile(capabilitiesService, args.$treeItem.payload), uri, options);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
@@ -43,12 +43,8 @@ import { AsyncServerTree } from 'sql/workbench/services/objectExplorer/browser/a
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ConnectionBrowseTab } from 'sql/workbench/services/connection/browser/connectionBrowseTab';
|
||||
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
|
||||
import { ConnectionProviderAndExtensionMap, ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { VIEWLET_ID as ExtensionsViewletID } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
||||
import { ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
||||
export interface OnShowUIResponse {
|
||||
selectedProviderDisplayName: string;
|
||||
@@ -129,10 +125,7 @@ export class ConnectionDialogWidget extends Modal {
|
||||
@ILogService logService: ILogService,
|
||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService,
|
||||
@IConfigurationService private _configurationService: IConfigurationService,
|
||||
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
|
||||
@INotificationService private _notificationService: INotificationService,
|
||||
@IPaneCompositePartService private _paneCompositeService: IPaneCompositePartService,
|
||||
@ICommandService private _commandService: ICommandService
|
||||
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService
|
||||
) {
|
||||
super(
|
||||
localize('connection', "Connection"),
|
||||
@@ -227,7 +220,7 @@ export class ConnectionDialogWidget extends Modal {
|
||||
|
||||
this._register(this.browsePanel.view.onSelectedConnectionChanged(e => {
|
||||
this._connectionSource = e.source;
|
||||
this.onConnectionClick(e.connectionProfile, e.connect);
|
||||
this.onConnectionClick(e.connectionProfile, e.connect).catch(onUnexpectedError);
|
||||
}));
|
||||
|
||||
this._panel.pushTab(this.browsePanel);
|
||||
@@ -355,7 +348,7 @@ export class ConnectionDialogWidget extends Modal {
|
||||
if (element instanceof ConnectionProfile) {
|
||||
const isDoubleClick = origin === 'mouse' && (eventish as MouseEvent).detail === 2;
|
||||
this._connectionSource = 'recent';
|
||||
this.onConnectionClick(element, isDoubleClick);
|
||||
this.onConnectionClick(element, isDoubleClick).catch(onUnexpectedError);
|
||||
}
|
||||
};
|
||||
const actionProvider = this.instantiationService.createInstance(RecentConnectionActionsProvider);
|
||||
@@ -377,13 +370,13 @@ export class ConnectionDialogWidget extends Modal {
|
||||
this._recentConnectionTree.onMouseClick(e => {
|
||||
if (e.element instanceof ConnectionProfile) {
|
||||
this._connectionSource = 'recent';
|
||||
this.onConnectionClick(e.element, false);
|
||||
this.onConnectionClick(e.element, false).catch(onUnexpectedError);
|
||||
}
|
||||
});
|
||||
this._recentConnectionTree.onMouseDblClick(e => {
|
||||
if (e.element instanceof ConnectionProfile) {
|
||||
this._connectionSource = 'recent';
|
||||
this.onConnectionClick(e.element, true);
|
||||
this.onConnectionClick(e.element, true).catch(onUnexpectedError);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -399,9 +392,8 @@ export class ConnectionDialogWidget extends Modal {
|
||||
DOM.append(noRecentConnectionContainer, DOM.$('.no-recent-connections')).innerText = noRecentHistoryLabel;
|
||||
}
|
||||
|
||||
private onConnectionClick(element: IConnectionProfile, connect: boolean = false): void {
|
||||
const isProviderAvailable = this._capabilitiesService.providers[element.providerName] !== undefined;
|
||||
if (isProviderAvailable) {
|
||||
private async onConnectionClick(element: IConnectionProfile, connect: boolean = false): Promise<void> {
|
||||
if (this._capabilitiesService.providers[element.providerName] !== undefined) {
|
||||
if (connect) {
|
||||
this.connect(element);
|
||||
} else {
|
||||
@@ -409,27 +401,8 @@ export class ConnectionDialogWidget extends Modal {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const extensionId = ConnectionProviderAndExtensionMap.get(element.providerName);
|
||||
if (extensionId) {
|
||||
this._notificationService.prompt(Severity.Error,
|
||||
localize('connectionDialog.extensionNotInstalled', "The extension '{0}' is required in order to connect to this resource. Please install it and try again.", extensionId),
|
||||
[{
|
||||
label: localize('connectionDialog.viewExtension', "View Extension"),
|
||||
run: async () => {
|
||||
this.close();
|
||||
await this._commandService.executeCommand('extension.open', extensionId);
|
||||
}
|
||||
}]);
|
||||
} else {
|
||||
this._notificationService.prompt(Severity.Error,
|
||||
localize('connectionDialog.connectionProviderNotSupported', "The extension that supports provider type '{0}' is not currently installed. Please install it and try again.", element.providerName),
|
||||
[{
|
||||
label: localize('connectionDialog.viewExtensions', "View Extensions"),
|
||||
run: async () => {
|
||||
this.close();
|
||||
await this._paneCompositeService.openPaneComposite(ExtensionsViewletID, ViewContainerLocation.Sidebar);
|
||||
}
|
||||
}]);
|
||||
if (await this.connectionManagementService.handleUnsupportedProvider(element.providerName)) {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ConnectionStore } from 'sql/platform/connection/common/connectionStore'
|
||||
import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo';
|
||||
import * as Utils from 'sql/platform/connection/common/utils';
|
||||
import * as Constants from 'sql/platform/connection/common/constants';
|
||||
import { ICapabilitiesService, ConnectionProviderProperties, ProviderFeatures } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import { ICapabilitiesService, ConnectionProviderProperties, ProviderFeatures, ConnectionProviderAndExtensionMap } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import * as ConnectionContracts from 'sql/workbench/services/connection/browser/connection';
|
||||
import { ConnectionStatusManager } from 'sql/platform/connection/common/connectionStatusManager';
|
||||
import { DashboardInput } from 'sql/workbench/browser/editor/profiler/dashboardInput';
|
||||
@@ -51,6 +51,11 @@ import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { IQueryEditorConfiguration } from 'sql/platform/query/common/query';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { QueryEditorInput } from 'sql/workbench/common/editor/query/queryEditorInput';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
||||
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';
|
||||
|
||||
export class ConnectionManagementService extends Disposable implements IConnectionManagementService {
|
||||
|
||||
@@ -94,7 +99,10 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
@IAccountManagementService private _accountManagementService: IAccountManagementService,
|
||||
@ILogService private _logService: ILogService,
|
||||
@IStorageService private _storageService: IStorageService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IPaneCompositePartService private readonly _paneCompositePartService: IPaneCompositePartService,
|
||||
@IDialogService private readonly _dialogService: IDialogService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -981,7 +989,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
options: connection.options
|
||||
});
|
||||
|
||||
await this.extensionService.activateByEvent(`onConnect:${connection.providerName}`);
|
||||
await this._extensionService.activateByEvent(`onConnect:${connection.providerName}`);
|
||||
|
||||
return this._providers.get(connection.providerName).onReady.then((provider) => {
|
||||
provider.connect(uri, connectionInfo);
|
||||
@@ -1649,4 +1657,22 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
}
|
||||
return connections;
|
||||
}
|
||||
|
||||
async handleUnsupportedProvider(providerName: string): Promise<boolean> {
|
||||
const extensionId = ConnectionProviderAndExtensionMap.get(providerName);
|
||||
const message = extensionId ? nls.localize('connection.extensionNotInstalled', "The extension '{0}' is required in order to connect to this resource. Do you want to install it?", extensionId) :
|
||||
nls.localize('connectionDialog.connectionProviderNotSupported', "The extension that supports provider type '{0}' is not currently installed. Do you want to view the extensions?", providerName);
|
||||
const result = await this._dialogService.confirm({
|
||||
message: message,
|
||||
type: 'question'
|
||||
});
|
||||
if (result.confirmed) {
|
||||
if (extensionId) {
|
||||
await this._commandService.executeCommand('extension.open', extensionId);
|
||||
} else {
|
||||
await this._paneCompositePartService.openPaneComposite(ExtensionsViewletID, ViewContainerLocation.Sidebar);
|
||||
}
|
||||
}
|
||||
return result.confirmed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ suite('ConnectionDialogService tests', () => {
|
||||
}
|
||||
};
|
||||
});
|
||||
testConnectionDialog = new TestConnectionDialogWidget(providerDisplayNames, providerNameToDisplayMap['MSSQL'], providerNameToDisplayMap, testInstantiationService, mockConnectionManagementService.object, undefined, undefined, viewDescriptorService, new TestThemeService(), new TestLayoutService(), new NullAdsTelemetryService(), new MockContextKeyService(), undefined, new NullLogService(), new TestTextResourcePropertiesService(new TestConfigurationService), new TestConfigurationService(), new TestCapabilitiesService(), undefined, undefined, undefined);
|
||||
testConnectionDialog = new TestConnectionDialogWidget(providerDisplayNames, providerNameToDisplayMap['MSSQL'], providerNameToDisplayMap, testInstantiationService, mockConnectionManagementService.object, undefined, undefined, viewDescriptorService, new TestThemeService(), new TestLayoutService(), new NullAdsTelemetryService(), new MockContextKeyService(), undefined, new NullLogService(), new TestTextResourcePropertiesService(new TestConfigurationService), new TestConfigurationService(), new TestCapabilitiesService());
|
||||
testConnectionDialog.render();
|
||||
testConnectionDialog['renderBody'](DOM.createStyleSheet());
|
||||
(connectionDialogService as any)._connectionDialog = testConnectionDialog;
|
||||
|
||||
@@ -65,7 +65,7 @@ suite('ConnectionDialogWidget tests', () => {
|
||||
new TestCapabilitiesService());
|
||||
let providerDisplayNames = ['Mock SQL Server'];
|
||||
let providerNameToDisplayMap = { 'MSSQL': 'Mock SQL Server' };
|
||||
connectionDialogWidget = new TestConnectionDialogWidget(providerDisplayNames, providerNameToDisplayMap['MSSQL'], providerNameToDisplayMap, cmInstantiationService, mockConnectionManagementService.object, undefined, undefined, viewDescriptorService, new TestThemeService(), new TestLayoutService(), new NullAdsTelemetryService(), new MockContextKeyService(), undefined, new NullLogService(), new TestTextResourcePropertiesService(new TestConfigurationService()), new TestConfigurationService(), new TestCapabilitiesService(), undefined, undefined, undefined);
|
||||
connectionDialogWidget = new TestConnectionDialogWidget(providerDisplayNames, providerNameToDisplayMap['MSSQL'], providerNameToDisplayMap, cmInstantiationService, mockConnectionManagementService.object, undefined, undefined, viewDescriptorService, new TestThemeService(), new TestLayoutService(), new NullAdsTelemetryService(), new MockContextKeyService(), undefined, new NullLogService(), new TestTextResourcePropertiesService(new TestConfigurationService()), new TestConfigurationService(), new TestCapabilitiesService());
|
||||
element = DOM.createStyleSheet();
|
||||
connectionDialogWidget.render();
|
||||
connectionDialogWidget['renderBody'](element);
|
||||
|
||||
@@ -185,7 +185,10 @@ suite('SQL ConnectionManagementService tests', () => {
|
||||
accountManagementService.object,
|
||||
testLogService, // ILogService
|
||||
undefined, // IStorageService
|
||||
getBasicExtensionService()
|
||||
getBasicExtensionService(),
|
||||
undefined,
|
||||
undefined,
|
||||
undefined
|
||||
);
|
||||
return connectionManagementService;
|
||||
}
|
||||
@@ -1573,7 +1576,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());
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, 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
|
||||
@@ -1603,7 +1606,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());
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, 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);
|
||||
@@ -1848,7 +1851,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());
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
|
||||
// dupe connections have been seeded the numbers below already reflected the de-duped results
|
||||
|
||||
@@ -1881,7 +1884,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());
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
assert(connectionManagementService.isRecent(profile1));
|
||||
assert(!connectionManagementService.isRecent(profile2));
|
||||
});
|
||||
@@ -1899,7 +1902,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());
|
||||
const connectionManagementService = new ConnectionManagementService(undefined, testInstantiationService, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService(), undefined, undefined, undefined);
|
||||
connectionManagementService.clearRecentConnection(profile1);
|
||||
assert(called);
|
||||
called = false;
|
||||
|
||||
@@ -17,9 +17,6 @@ import { ITextResourcePropertiesService } from 'vs/editor/common/services/textRe
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
||||
|
||||
export class TestConnectionDialogWidget extends ConnectionDialogWidget {
|
||||
constructor(
|
||||
@@ -39,11 +36,8 @@ export class TestConnectionDialogWidget extends ConnectionDialogWidget {
|
||||
@ILogService logService: ILogService,
|
||||
@ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@ICapabilitiesService capabilitiesService: ICapabilitiesService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@IPaneCompositePartService paneCompositeService: IPaneCompositePartService,
|
||||
@ICommandService commandService: ICommandService
|
||||
@ICapabilitiesService capabilitiesService: ICapabilitiesService
|
||||
) {
|
||||
super(providerDisplayNameOptions, selectedProviderType, providerNameToDisplayNameMap, _instantiationService, _connectionManagementService, _contextMenuService, _contextViewService, themeService, layoutService, telemetryService, contextKeyService, clipboardService, logService, textResourcePropertiesService, configurationService, capabilitiesService, notificationService, paneCompositeService, commandService);
|
||||
super(providerDisplayNameOptions, selectedProviderType, providerNameToDisplayNameMap, _instantiationService, _connectionManagementService, _contextMenuService, _contextViewService, themeService, layoutService, telemetryService, contextKeyService, clipboardService, logService, textResourcePropertiesService, configurationService, capabilitiesService);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user