diff --git a/samples/connection-sharing-sample/.vscode/launch.json b/samples/connection-sharing-sample/.vscode/launch.json index 8416e338bc..41d625c597 100644 --- a/samples/connection-sharing-sample/.vscode/launch.json +++ b/samples/connection-sharing-sample/.vscode/launch.json @@ -14,8 +14,7 @@ "--extensionDevelopmentPath=${workspaceFolder}/../../", "--disable-extensions" ], - "outFiles": ["${workspaceFolder}/dist/**/*.js"], - "preLaunchTask": "${defaultBuildTask}" + "outFiles": ["${workspaceFolder}/dist/**/*.js"] } ] } diff --git a/samples/connection-sharing-sample/.vscode/tasks.json b/samples/connection-sharing-sample/.vscode/tasks.json index 96763900f1..683b03da96 100644 --- a/samples/connection-sharing-sample/.vscode/tasks.json +++ b/samples/connection-sharing-sample/.vscode/tasks.json @@ -18,7 +18,6 @@ "type": "npm", "script": "watch:esbuild", "group": "build", - "problemMatcher": "$esbuild-watch", "isBackground": true, "label": "npm: watch:esbuild", "presentation": { diff --git a/samples/connection-sharing-sample/package.json b/samples/connection-sharing-sample/package.json index 0d8161fa8c..12ef3922b8 100644 --- a/samples/connection-sharing-sample/package.json +++ b/samples/connection-sharing-sample/package.json @@ -33,8 +33,27 @@ "command": "connection-sharing-sample.requestApproval", "title": "Request Approval for Connection Sharing", "category": "ConnSharing" + }, + { + "command": "connection-sharing-sample.customObjectExplorerDatabaseCommand", + "title": "Custom Object Explorer Database Command", + "category": "ConnSharing" } - ] + ], + "menus": { + "view/item/context": [ + { + "command": "connection-sharing-sample.customObjectExplorerDatabaseCommand", + "when": "view === objectExplorer && viewItem =~ /\\btype=(Database|Server)\\b.*\\bsubType=(Database)\\b/" + } + ], + "commandPalette": [ + { + "command": "connection-sharing-sample.customObjectExplorerDatabaseCommand", + "when": "false" + } + ] + } }, "scripts": { "vscode:prepublish": "npm run package", diff --git a/samples/connection-sharing-sample/src/extension.ts b/samples/connection-sharing-sample/src/extension.ts index eedd22ae43..e3a2eab81b 100644 --- a/samples/connection-sharing-sample/src/extension.ts +++ b/samples/connection-sharing-sample/src/extension.ts @@ -5,6 +5,36 @@ import * as mssql from "vscode-mssql"; const EXTENSION_ID = "ms-mssql.connection-sharing-sample"; const MSSQL_EXTENSION_ID = "ms-mssql.mssql"; +export async function getConnectionSharingServiceApi(): Promise< + mssql.IConnectionSharingService | undefined +> { + console.log("--- Starting Connection Sharing Demo (Direct API Approach) ---"); + + const mssqlExtension = vscode.extensions.getExtension(MSSQL_EXTENSION_ID); + if (!mssqlExtension) { + vscode.window.showErrorMessage( + "MSSQL extension is not installed. Please install it first.", + ); + return; + } + + await mssqlExtension.activate(); + + const mssqlExtensionApi = mssqlExtension.exports as mssql.IExtension; + if (!mssqlExtensionApi) { + vscode.window.showErrorMessage("Unable to access MSSQL extension API"); + return; + } + + const connectionSharingService = + mssqlExtensionApi.connectionSharing as mssql.IConnectionSharingService; + if (!connectionSharingService) { + vscode.window.showErrorMessage("Connection sharing service is not available"); + return; + } + return connectionSharingService; +} + export function activate(extensionContext: vscode.ExtensionContext) { console.log("Connection Sharing Sample extension is now active!"); @@ -40,6 +70,29 @@ export function registerCommands(extensionContext: vscode.ExtensionContext) { requestConnectionSharingPermissions, ), ); + + /** + * Example of registering a command that receives a tree node with a connection profile + * and generates a connection string from it. + */ + extensionContext.subscriptions.push( + vscode.commands.registerCommand( + "connection-sharing-sample.customObjectExplorerDatabaseCommand", + async (treeNode) => { + const connectionProfile = treeNode.connectionProfile; + const connectionSharingService = await getConnectionSharingServiceApi(); + if (!connectionSharingService) { + return; + } + const connectionString = await connectionSharingService.getConnectionString( + EXTENSION_ID, + connectionProfile.id, + ); + console.log(`Generated connection string: ${connectionString}`); + vscode.window.showInformationMessage(`Connection string generated`); + }, + ), + ); } async function connectionSharingWithCommands() { @@ -58,6 +111,22 @@ async function connectionSharingWithCommands() { console.log(`Active connection ID: ${activeConnectionId}`); + // New feature: Get the connection string for the active connection + const connectionString = (await vscode.commands.executeCommand( + "mssql.connectionSharing.getConnectionString", + EXTENSION_ID, + activeConnectionId, + )) as string; + + if (connectionString) { + console.log(`Connection string: ${connectionString}`); + vscode.window.showInformationMessage( + `Retrieved connection string for connection ${activeConnectionId}`, + ); + } else { + console.log("Unable to retrieve connection string"); + } + // New feature: Get the active database name using command approach const activeDatabase = (await vscode.commands.executeCommand( "mssql.connectionSharing.getActiveDatabase", @@ -127,28 +196,8 @@ async function connectionSharingWithCommands() { async function connectionSharingWithApis() { try { - console.log("--- Starting Connection Sharing Demo (Direct API Approach) ---"); - - const mssqlExtension = vscode.extensions.getExtension(MSSQL_EXTENSION_ID); - if (!mssqlExtension) { - vscode.window.showErrorMessage( - "MSSQL extension is not installed. Please install it first.", - ); - return; - } - - await mssqlExtension.activate(); - - const mssqlExtensionApi = mssqlExtension.exports as any; - if (!mssqlExtensionApi) { - vscode.window.showErrorMessage("Unable to access MSSQL extension API"); - return; - } - - const connectionSharingService = - mssqlExtensionApi.connectionSharing as mssql.IConnectionSharingService; + const connectionSharingService = await getConnectionSharingServiceApi(); if (!connectionSharingService) { - vscode.window.showErrorMessage("Connection sharing service is not available"); return; } @@ -161,6 +210,20 @@ async function connectionSharingWithApis() { console.log(`Retrieved connection ID: ${activeConnectionId}`); + // New feature: Get the connection string for the active connection + const connectionString = await connectionSharingService.getConnectionString( + EXTENSION_ID, + activeConnectionId, + ); + if (connectionString) { + console.log(`Connection string: ${connectionString}`); + vscode.window.showInformationMessage( + `Retrieved connection string for connection ${activeConnectionId}`, + ); + } else { + console.log("Unable to retrieve connection string"); + } + // New feature: Get the active database name const activeDatabase = await connectionSharingService.getActiveDatabase(EXTENSION_ID); if (activeDatabase) { diff --git a/src/connectionSharing/connectionSharingService.ts b/src/connectionSharing/connectionSharingService.ts index 9c1a4eddd0..3a3c264dd2 100644 --- a/src/connectionSharing/connectionSharingService.ts +++ b/src/connectionSharing/connectionSharingService.ts @@ -165,6 +165,14 @@ export class ConnectionSharingService implements mssql.IConnectionSharingService }, ), ); + + this._context.subscriptions.push( + vscode.commands.registerCommand( + "mssql.connectionSharing.getConnectionString", + (extensionId: string, connectionId: string) => + this.getConnectionString(extensionId, connectionId), + ), + ); } private async getStoredExtensionPermissions(): Promise { @@ -594,4 +602,40 @@ export class ConnectionSharingService implements mssql.IConnectionSharingService ); return newApproval; } + + public async getConnectionString( + extensionId: string, + connectionId: string, + ): Promise { + await this.validateExtensionPermission(extensionId); + + const connections = + await this._connectionManager.connectionStore.connectionConfig.getConnections(false); + const targetConnection = connections.find((conn) => conn.id === connectionId); + + if (!targetConnection) { + this._logger.error( + `Connection with ID "${connectionId}" not found for extension "${extensionId}".`, + ); + throw new ConnectionSharingError( + ConnectionSharingErrorCode.CONNECTION_NOT_FOUND, + LocalizedConstants.ConnectionSharing.connectionNotFoundError(connectionId), + extensionId, + connectionId, + ); + } + + // Use ConnectionManager's getConnectionString method + const connectionDetails = this._connectionManager.createConnectionDetails(targetConnection); + const connectionString = await this._connectionManager.getConnectionString( + connectionDetails, + true, // includePassword + false, // do not include appName + ); + + this._logger.info( + `Retrieved connection string for connection ID "${connectionId}" for extension "${extensionId}".`, + ); + return connectionString; + } } diff --git a/src/extension.ts b/src/extension.ts index d72ea414de..387b62d25c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -122,7 +122,7 @@ export async function activate(context: vscode.ExtensionContext): Promise { return controller.connectionManager.getServerInfo(connectionInfo); }, - connectionSharing: { + connectionSharing: { getActiveEditorConnectionId: (extensionId: string) => { return controller.connectionSharingService.getActiveEditorConnectionId(extensionId); }, @@ -166,7 +166,13 @@ export async function activate(context: vscode.ExtensionContext): Promise => { + return controller.connectionSharingService.getConnectionString( + extensionId, + connectionId, + ); + }, + } as vscodeMssql.IConnectionSharingService, }; } diff --git a/typings/globals/index.d.ts b/typings/globals/index.d.ts new file mode 100644 index 0000000000..f956d5ec2c --- /dev/null +++ b/typings/globals/index.d.ts @@ -0,0 +1,2 @@ +// Type definitions stub for globals directory +export {}; diff --git a/typings/vscode-mssql.d.ts b/typings/vscode-mssql.d.ts index 5ed5951525..eb6f40595f 100644 --- a/typings/vscode-mssql.d.ts +++ b/typings/vscode-mssql.d.ts @@ -2587,5 +2587,12 @@ declare module "vscode-mssql" { operation: ScriptOperation, scriptingObject: IScriptingObject, ): Promise; + /** + * Get the connection string for a specific connection ID. + * @param extensionId The ID of the extension. + * @param connectionId The ID of the connection. + * @returns The connection string if the connection is found, or undefined if the connection is not found. + */ + getConnectionString(extensionId: string, connectionId: string): Promise; } }