From 3b74d7843f19b9ac3b6788782873fc71854c4c36 Mon Sep 17 00:00:00 2001 From: Alan Ren Date: Sun, 15 May 2022 13:52:28 -0700 Subject: [PATCH] show proper message when extension is not installed for a connection provider (#19377) * show extension not installed error * extension provider mapping * fix tests --- .../common/capabilitiesService.ts | 10 ++++ .../browser/connectionDialogWidget.ts | 46 ++++++++++++++++--- .../browser/connectionDialogService.test.ts | 2 +- .../browser/connectionDialogWidget.test.ts | 2 +- .../browser/testConnectionDialogWidget.ts | 10 +++- 5 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/sql/platform/capabilities/common/capabilitiesService.ts b/src/sql/platform/capabilities/common/capabilitiesService.ts index 0c7e0d0b8d..b6e5629471 100644 --- a/src/sql/platform/capabilities/common/capabilitiesService.ts +++ b/src/sql/platform/capabilities/common/capabilitiesService.ts @@ -20,6 +20,16 @@ export const clientCapabilities = { hostVersion: HOST_VERSION }; +/** + * The map containing the connection provider names and the owning extensions. + * This is to workaround the issue that we don't have the ability to store and query the information from extension gallery. + */ +export const ConnectionProviderAndExtensionMap = new Map([ + ['PGSQL', 'microsoft.azuredatastudio-postgresql'], + ['KUSTO', 'microsoft.kusto'], + ['LOGANALYTICS', 'microsoft.azuremonitor'] +]); + /** * The connection string options for connection provider. */ diff --git a/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts b/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts index c56b656add..b2ee6ec06b 100644 --- a/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts +++ b/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts @@ -43,7 +43,11 @@ 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 { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; +import { ConnectionProviderAndExtensionMap, ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { VIEWLET_ID as ExtensionsViewletID } from 'vs/workbench/contrib/extensions/common/extensions'; +import { ICommandService } from 'vs/platform/commands/common/commands'; export interface OnShowUIResponse { selectedProviderDisplayName: string; @@ -124,7 +128,10 @@ export class ConnectionDialogWidget extends Modal { @ILogService logService: ILogService, @ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService, @IConfigurationService private _configurationService: IConfigurationService, - @ICapabilitiesService private _capabilitiesService: ICapabilitiesService + @ICapabilitiesService private _capabilitiesService: ICapabilitiesService, + @INotificationService private _notificationService: INotificationService, + @IViewletService private _viewletService: IViewletService, + @ICommandService private _commandService: ICommandService ) { super( localize('connection', "Connection"), @@ -392,10 +399,37 @@ export class ConnectionDialogWidget extends Modal { } private onConnectionClick(element: IConnectionProfile, connect: boolean = false): void { - if (connect) { - this.connect(element); - } else { - this._onFillinConnectionInputs.fire(element); + const isProviderAvailable = this._capabilitiesService.providers[element.providerName] !== undefined; + if (isProviderAvailable) { + if (connect) { + this.connect(element); + } else { + this._onFillinConnectionInputs.fire(element); + } + } + 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._viewletService.openViewlet(ExtensionsViewletID, true); + } + }]); + } } } diff --git a/src/sql/workbench/services/connection/test/browser/connectionDialogService.test.ts b/src/sql/workbench/services/connection/test/browser/connectionDialogService.test.ts index b82c6b5d0d..5b449c3b8e 100644 --- a/src/sql/workbench/services/connection/test/browser/connectionDialogService.test.ts +++ b/src/sql/workbench/services/connection/test/browser/connectionDialogService.test.ts @@ -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()); + 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.render(); testConnectionDialog['renderBody'](DOM.createStyleSheet()); (connectionDialogService as any)._connectionDialog = testConnectionDialog; diff --git a/src/sql/workbench/services/connection/test/browser/connectionDialogWidget.test.ts b/src/sql/workbench/services/connection/test/browser/connectionDialogWidget.test.ts index a349e9c2ff..61bcba7ee5 100644 --- a/src/sql/workbench/services/connection/test/browser/connectionDialogWidget.test.ts +++ b/src/sql/workbench/services/connection/test/browser/connectionDialogWidget.test.ts @@ -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()); + 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); element = DOM.createStyleSheet(); connectionDialogWidget.render(); connectionDialogWidget['renderBody'](element); diff --git a/src/sql/workbench/services/connection/test/browser/testConnectionDialogWidget.ts b/src/sql/workbench/services/connection/test/browser/testConnectionDialogWidget.ts index 12baf8f416..8d9c67653f 100644 --- a/src/sql/workbench/services/connection/test/browser/testConnectionDialogWidget.ts +++ b/src/sql/workbench/services/connection/test/browser/testConnectionDialogWidget.ts @@ -17,6 +17,9 @@ 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 { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { ICommandService } from 'vs/platform/commands/common/commands'; export class TestConnectionDialogWidget extends ConnectionDialogWidget { constructor( @@ -36,8 +39,11 @@ export class TestConnectionDialogWidget extends ConnectionDialogWidget { @ILogService logService: ILogService, @ITextResourcePropertiesService textResourcePropertiesService: ITextResourcePropertiesService, @IConfigurationService configurationService: IConfigurationService, - @ICapabilitiesService capabilitiesService: ICapabilitiesService + @ICapabilitiesService capabilitiesService: ICapabilitiesService, + @INotificationService notificationService: INotificationService, + @IViewletService viewletService: IViewletService, + @ICommandService commandService: ICommandService ) { - super(providerDisplayNameOptions, selectedProviderType, providerNameToDisplayNameMap, _instantiationService, _connectionManagementService, _contextMenuService, _contextViewService, themeService, layoutService, telemetryService, contextKeyService, clipboardService, logService, textResourcePropertiesService, configurationService, capabilitiesService); + super(providerDisplayNameOptions, selectedProviderType, providerNameToDisplayNameMap, _instantiationService, _connectionManagementService, _contextMenuService, _contextViewService, themeService, layoutService, telemetryService, contextKeyService, clipboardService, logService, textResourcePropertiesService, configurationService, capabilitiesService, notificationService, viewletService, commandService); } }