diff --git a/extensions/mssql/package.json b/extensions/mssql/package.json index b07f8dc97e..d8a06b2a0e 100644 --- a/extensions/mssql/package.json +++ b/extensions/mssql/package.json @@ -658,7 +658,7 @@ } }, "dependencies": { - "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.0", + "dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.3", "opener": "^1.4.3", "service-downloader": "github:anthonydresser/service-downloader#0.1.4", "vscode-extension-telemetry": "^0.0.15" diff --git a/extensions/mssql/src/config.json b/extensions/mssql/src/config.json index 4784cc0323..9e8c155182 100644 --- a/extensions/mssql/src/config.json +++ b/extensions/mssql/src/config.json @@ -1,6 +1,6 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", - "version": "1.5.0-alpha.18", + "version": "1.5.0-alpha.19", "downloadFileNames": { "Windows_86": "win-x86-netcoreapp2.1.zip", "Windows_64": "win-x64-netcoreapp2.1.zip", diff --git a/extensions/mssql/yarn.lock b/extensions/mssql/yarn.lock index 1cfa9e4151..bc1127b389 100644 --- a/extensions/mssql/yarn.lock +++ b/extensions/mssql/yarn.lock @@ -49,9 +49,9 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.2.0": - version "0.2.0" - resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/c7a691c7fc5ad54a147090784a7f11efda301f4b" +"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.2.3": + version "0.2.3" + resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/4dd3c6ae27aa0aa10361336c19e15f183ea13c47" dependencies: vscode-languageclient "3.5.0" diff --git a/src/sql/parts/connection/common/connection.contribution.ts b/src/sql/parts/connection/common/connection.contribution.ts index d427998bd4..89bc79a5a6 100644 --- a/src/sql/parts/connection/common/connection.contribution.ts +++ b/src/sql/parts/connection/common/connection.contribution.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IExtensionGalleryService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; +import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/common/extensions'; import { IConfigurationRegistry, Extensions as ConfigExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; @@ -13,10 +13,9 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { DashboardEditor } from 'sql/parts/dashboard/dashboardEditor'; import { DashboardInput } from 'sql/parts/dashboard/dashboardInput'; import { AddServerGroupAction, AddServerAction } from 'sql/parts/objectExplorer/viewlet/connectionTreeAction'; -import { ClearRecentConnectionsAction } from 'sql/parts/connection/common/connectionActions'; +import { ClearRecentConnectionsAction, GetCurrentConnectionStringAction } from 'sql/parts/connection/common/connectionActions'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; -import { EditorDescriptor } from 'vs/workbench/browser/editor'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-browser/extensionTipsService'; import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; @@ -49,6 +48,7 @@ actionRegistry.registerWorkbenchAction( ), ClearRecentConnectionsAction.LABEL ); + actionRegistry.registerWorkbenchAction( new SyncActionDescriptor( AddServerGroupAction, @@ -67,6 +67,15 @@ actionRegistry.registerWorkbenchAction( AddServerAction.LABEL ); +actionRegistry.registerWorkbenchAction( + new SyncActionDescriptor( + GetCurrentConnectionStringAction, + GetCurrentConnectionStringAction.ID, + GetCurrentConnectionStringAction.LABEL + ), + GetCurrentConnectionStringAction.LABEL +); + let configurationRegistry = Registry.as(ConfigExtensions.Configuration); configurationRegistry.registerConfiguration({ 'id': 'connection', diff --git a/src/sql/parts/connection/common/connectionActions.ts b/src/sql/parts/connection/common/connectionActions.ts index cde70fc610..61a14470ec 100644 --- a/src/sql/parts/connection/common/connectionActions.ts +++ b/src/sql/parts/connection/common/connectionActions.ts @@ -13,6 +13,11 @@ import { IConnectionManagementService } from 'sql/parts/connection/common/connec import { INotificationService, INotificationActions } from 'vs/platform/notification/common/notification'; import Severity from 'vs/base/common/severity'; import { IDialogService, IConfirmation, IConfirmationResult } from 'vs/platform/dialogs/common/dialogs'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IObjectExplorerService } from '../../objectExplorer/common/objectExplorerService'; +import { QueryInput } from 'sql/parts/query/common/queryInput'; +import { EditDataInput } from 'sql/parts/editData/common/editDataInput'; +import { DashboardInput } from 'sql/parts/dashboard/dashboardInput'; /** * Workbench action to clear the recent connnections list @@ -126,4 +131,44 @@ export class ClearSingleRecentConnectionAction extends Action { this._onRecentConnectionRemoved.fire(); }); } -} \ No newline at end of file +} + +/** + * Action to retrieve the current connection string + */ +export class GetCurrentConnectionStringAction extends Action { + + public static ID = 'getCurrentConnectionStringAction'; + public static LABEL = nls.localize('connectionAction.GetCurrentConnectionString', "Get Current Connection String"); + + constructor( + id: string, + label: string, + @IConnectionManagementService private _connectionManagementService: IConnectionManagementService, + @IWorkbenchEditorService private _editorService: IWorkbenchEditorService, + @IObjectExplorerService private _objectExplorerService: IObjectExplorerService, + @INotificationService private readonly _notificationService: INotificationService + ) { + super(GetCurrentConnectionStringAction.ID, GetCurrentConnectionStringAction.LABEL); + this.enabled = true; + } + + public run(): TPromise { + return new TPromise((resolve, reject) => { + let activeInput = this._editorService.getActiveEditorInput(); + if (activeInput && (activeInput instanceof QueryInput || activeInput instanceof EditDataInput || activeInput instanceof DashboardInput) + && this._connectionManagementService.isConnected(activeInput.uri)) { + let includePassword = false; + this._connectionManagementService.getConnectionString(activeInput.uri, includePassword).then(result => { + let message = result + ? result + : nls.localize('connectionAction.connectionString', "Connection string not available"); + this._notificationService.info(message); + }); + } else { + let message = nls.localize('connectionAction.noConnection', "No active connection available"); + this._notificationService.info(message); + } + }); + } +} diff --git a/src/sql/parts/connection/common/connectionManagement.ts b/src/sql/parts/connection/common/connectionManagement.ts index 5f4e6561fd..575e1283bb 100644 --- a/src/sql/parts/connection/common/connectionManagement.ts +++ b/src/sql/parts/connection/common/connectionManagement.ts @@ -260,6 +260,11 @@ export interface IConnectionManagementService { * in the connection profile's options dictionary, or undefined if the profile is not connected */ getActiveConnectionCredentials(profileId: string): { [name: string]: string }; + + /** + * Get the connection string for the provided connection profile + */ + getConnectionString(ownerUri: string, includePassword: boolean): Thenable; } export const IConnectionDialogService = createDecorator('connectionDialogService'); diff --git a/src/sql/parts/connection/common/connectionManagementService.ts b/src/sql/parts/connection/common/connectionManagementService.ts index 35e8e684f4..60c01d3f76 100644 --- a/src/sql/parts/connection/common/connectionManagementService.ts +++ b/src/sql/parts/connection/common/connectionManagementService.ts @@ -1345,4 +1345,24 @@ export class ConnectionManagementService extends Disposable implements IConnecti credentials[passwordOption.name] = profile.options[passwordOption.name]; return credentials; } + + /** + * Get the connection string for the provided connection profile + */ + public getConnectionString(ownerUri: string, includePassword: boolean = false): Thenable { + if (!ownerUri) { + return Promise.resolve(undefined); + } + + let providerId = this.getProviderIdFromUri(ownerUri); + if (!providerId) { + return Promise.resolve(undefined); + } + + return this._providers.get(providerId).onReady.then(provider => { + return provider.getConnectionString(ownerUri, includePassword).then(connectionString => { + return connectionString; + }); + }); + } } diff --git a/src/sql/sqlops.d.ts b/src/sql/sqlops.d.ts index 5fcba5696a..1e8272459e 100644 --- a/src/sql/sqlops.d.ts +++ b/src/sql/sqlops.d.ts @@ -87,6 +87,11 @@ declare module 'sqlops' { */ export function getActiveConnections(): Thenable; + /** + * Get connection string + */ + export function getConnectionString(connectionId: string, includePassword: boolean): Thenable; + /** * Get the credentials for an active connection * @param {string} connectionId The id of the connection @@ -322,6 +327,8 @@ declare module 'sqlops' { rebuildIntelliSenseCache(connectionUri: string): Thenable; + getConnectionString(connectionUri: string, includePassword: boolean): Thenable ; + registerOnConnectionComplete(handler: (connSummary: ConnectionInfoSummary) => any): void; registerOnIntelliSenseCacheComplete(handler: (connectionUri: string) => any): void; diff --git a/src/sql/workbench/api/node/extHostConnectionManagement.ts b/src/sql/workbench/api/node/extHostConnectionManagement.ts index f56f00b351..2c8b674214 100644 --- a/src/sql/workbench/api/node/extHostConnectionManagement.ts +++ b/src/sql/workbench/api/node/extHostConnectionManagement.ts @@ -35,6 +35,10 @@ export class ExtHostConnectionManagement extends ExtHostConnectionManagementShap return this._proxy.$listDatabases(connectionId); } + public $getConnectionString(connectionId: string, includePassword: boolean): Thenable { + return this._proxy.$getConnectionString(connectionId, includePassword); + } + public $getUriForConnection(connectionId: string): Thenable { return this._proxy.$getUriForConnection(connectionId); } diff --git a/src/sql/workbench/api/node/extHostDataProtocol.ts b/src/sql/workbench/api/node/extHostDataProtocol.ts index 30b6898c6a..d98d143a47 100644 --- a/src/sql/workbench/api/node/extHostDataProtocol.ts +++ b/src/sql/workbench/api/node/extHostDataProtocol.ts @@ -181,6 +181,10 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { return this._resolveProvider(handle).listDatabases(connectionUri); } + $getConnectionString(handle: number, connectionUri: string, includePassword: boolean): Thenable { + return this._resolveProvider(handle).getConnectionString(connectionUri, includePassword); + } + $rebuildIntelliSenseCache(handle: number, connectionUri: string): Thenable { return this._resolveProvider(handle).rebuildIntelliSenseCache(connectionUri); } diff --git a/src/sql/workbench/api/node/mainThreadConnectionManagement.ts b/src/sql/workbench/api/node/mainThreadConnectionManagement.ts index 4b8f9b2fbc..65e1ca323d 100644 --- a/src/sql/workbench/api/node/mainThreadConnectionManagement.ts +++ b/src/sql/workbench/api/node/mainThreadConnectionManagement.ts @@ -56,6 +56,11 @@ export class MainThreadConnectionManagement implements MainThreadConnectionManag return result.databaseNames; } + public async $getConnectionString(connectionId: string, includePassword: boolean): Promise { + let connection = this._connectionManagementService.getActiveConnections().find(profile => profile.id === connectionId); + return await this._connectionManagementService.getConnectionString(connectionId, includePassword); + } + public $getUriForConnection(connectionId: string): Thenable { return Promise.resolve(this._connectionManagementService.getConnectionUriFromId(connectionId)); } diff --git a/src/sql/workbench/api/node/mainThreadDataProtocol.ts b/src/sql/workbench/api/node/mainThreadDataProtocol.ts index 047e552d6a..f1e741b657 100644 --- a/src/sql/workbench/api/node/mainThreadDataProtocol.ts +++ b/src/sql/workbench/api/node/mainThreadDataProtocol.ts @@ -88,6 +88,9 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape { listDatabases(connectionUri: string): Thenable { return self._proxy.$listDatabases(handle, connectionUri); }, + getConnectionString(connectionUri: string, includePassword: boolean): Thenable { + return self._proxy.$getConnectionString(handle, connectionUri, includePassword); + }, rebuildIntelliSenseCache(connectionUri: string): Thenable { return self._proxy.$rebuildIntelliSenseCache(handle, connectionUri); } diff --git a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts index ae67191252..7cb961e3bb 100644 --- a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts +++ b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts @@ -105,6 +105,9 @@ export function createApiFactory( listDatabases(connectionId: string): Thenable { return extHostConnectionManagement.$listDatabases(connectionId); }, + getConnectionString(connectionId: string, includePassword: boolean): Thenable { + return extHostConnectionManagement.$getConnectionString(connectionId, includePassword); + }, getUriForConnection(connectionId: string): Thenable { return extHostConnectionManagement.$getUriForConnection(connectionId); } diff --git a/src/sql/workbench/api/node/sqlExtHost.protocol.ts b/src/sql/workbench/api/node/sqlExtHost.protocol.ts index f3774ae0ee..75dbc37051 100644 --- a/src/sql/workbench/api/node/sqlExtHost.protocol.ts +++ b/src/sql/workbench/api/node/sqlExtHost.protocol.ts @@ -63,6 +63,13 @@ export abstract class ExtHostDataProtocolShape { */ $listDatabases(handle: number, connectionUri: string): Thenable { throw ni(); } + /** + * Get the connection string for the connection specified by connectionUri + * @param handle the handle to use when looking up a provider + * @param connectionUri URI identifying a connected resource + */ + $getConnectionString(handle: number, connectionUri: string, includePassword: boolean): Thenable { throw ni(); } + /** * Notifies all listeners on the Extension Host side that a language change occurred * for a dataprotocol language. The sub-flavor is the specific implementation used for query @@ -474,6 +481,7 @@ export interface MainThreadConnectionManagementShape extends IDisposable { $getCurrentConnection(): Thenable; $getCredentials(connectionId: string): Thenable<{ [name: string]: string }>; $listDatabases(connectionId: string): Thenable; + $getConnectionString(connectionId: string, includePassword: boolean): Thenable; $getUriForConnection(connectionId: string): Thenable; } diff --git a/src/sqltest/stubs/connectionManagementService.test.ts b/src/sqltest/stubs/connectionManagementService.test.ts index 40dc0c07cc..7dc72a9e1d 100644 --- a/src/sqltest/stubs/connectionManagementService.test.ts +++ b/src/sqltest/stubs/connectionManagementService.test.ts @@ -253,4 +253,8 @@ export class TestConnectionManagementService implements IConnectionManagementSer getActiveConnectionCredentials(profileId: string): { [name: string]: string } { return undefined; } + + getConnectionString(ownerUri: string): Thenable { + return undefined; + } } \ No newline at end of file diff --git a/src/sqltest/stubs/connectionProviderStub.ts b/src/sqltest/stubs/connectionProviderStub.ts index 4f2d99c7d2..19ad97033a 100644 --- a/src/sqltest/stubs/connectionProviderStub.ts +++ b/src/sqltest/stubs/connectionProviderStub.ts @@ -28,6 +28,10 @@ export class ConnectionProviderStub implements sqlops.ConnectionProvider { return undefined; } + getConnectionString(connectionUri: string): Thenable { + return undefined; + } + rebuildIntelliSenseCache(connectionUri: string): Thenable { return undefined; }