diff --git a/package.json b/package.json index 8b18027a..d5dcdf63 100644 --- a/package.json +++ b/package.json @@ -589,52 +589,42 @@ }, { "category": "MongoDB (vCore)", - "command": "mongoClusters.cmd.hello", - "title": "Dev: Say Hello!" - }, - { - "category": "MongoDB (vCore)", - "command": "mongoClusters.cmd.webview", - "title": "Dev: Show WebView" - }, - { - "category": "MongoDB (vCore)", - "command": "mongoClusters.cmd.dropCollection", + "command": "command.mongoClusters.dropCollection", "title": "Drop Collection..." }, { "category": "MongoDB (vCore)", - "command": "mongoClusters.cmd.dropDatabase", + "command": "command.mongoClusters.dropDatabase", "title": "Drop Database..." }, { "category": "MongoDB (vCore)", - "command": "mongoClusters.cmd.createCollection", + "command": "command.mongoClusters.createCollection", "title": "Create Collection..." }, { "category": "MongoDB (vCore)", - "command": "mongoClusters.cmd.createDatabase", + "command": "command.mongoClusters.createDatabase", "title": "Create Database..." }, { "category": "MongoDB (vCore)", - "command": "mongoClusters.cmd.importDocuments", + "command": "command.mongoClusters.importDocuments", "title": "Import Documents into Collection..." }, { "category": "MongoDB (vCore)", - "command": "mongoClusters.cmd.exportDocuments", + "command": "command.mongoClusters.exportDocuments", "title": "Export Documents from Collection..." }, { "category": "MongoDB (vCore)", - "command": "mongoClusters.cmd.launchShell", + "command": "command.mongoClusters.launchShell", "title": "Launch Shell" }, { "category": "MongoDB (vCore)", - "command": "mongoClusters.cmd.removeWorkspaceConnection", + "command": "command.mongoClusters.removeWorkspaceConnection", "title": "Remove Connection..." } ], @@ -1135,38 +1125,38 @@ "group": "1@1" }, { - "command": "mongoClusters.cmd.dropCollection", + "command": "command.mongoClusters.dropCollection", "when": "vscodeDatabases.mongoClustersSupportEnabled && viewItem == mongoClusters.item.collection" }, { - "command": "mongoClusters.cmd.dropDatabase", + "command": "command.mongoClusters.dropDatabase", "when": "vscodeDatabases.mongoClustersSupportEnabled && viewItem == mongoClusters.item.database" }, { - "command": "mongoClusters.cmd.removeWorkspaceConnection", + "command": "command.mongoClusters.removeWorkspaceConnection", "when": "vscodeDatabases.mongoClustersSupportEnabled && view == azureWorkspace && viewItem == mongoClusters.item.mongoCluster" }, { - "command": "mongoClusters.cmd.createCollection", + "command": "command.mongoClusters.createCollection", "when": "vscodeDatabases.mongoClustersSupportEnabled && viewItem == mongoClusters.item.database" }, { - "command": "mongoClusters.cmd.createDatabase", + "command": "command.mongoClusters.createDatabase", "when": "vscodeDatabases.mongoClustersSupportEnabled && viewItem =~ /mongoClusters.item.mongoCluster/i", "group": "1@1" }, { - "command": "mongoClusters.cmd.importDocuments", + "command": "command.mongoClusters.importDocuments", "when": "vscodeDatabases.mongoClustersSupportEnabled && viewItem == mongoClusters.item.collection", "group": "1@1" }, { - "command": "mongoClusters.cmd.exportDocuments", + "command": "command.mongoClusters.exportDocuments", "when": "vscodeDatabases.mongoClustersSupportEnabled && viewItem == mongoClusters.item.collection", "group": "1@2" }, { - "command": "mongoClusters.cmd.launchShell", + "command": "command.mongoClusters.launchShell", "when": "vscodeDatabases.mongoClustersSupportEnabled && viewItem =~ /mongoClusters.item.(mongoCluster|database|collection)/i", "group": "2@1" } @@ -1213,14 +1203,6 @@ { "command": "postgreSQL.executeQuery", "when": "editorLangId == 'postgres'" - }, - { - "command": "mongoClusters.cmd.hello", - "when": "vscodeDatabases.mongoClustersSupportEnabled" - }, - { - "command": "mongoClusters.cmd.webview", - "when": "vscodeDatabases.mongoClustersSupportEnabled" } ] }, diff --git a/src/AzureDBExperiences.ts b/src/AzureDBExperiences.ts index ed0904d7..454e2bdf 100644 --- a/src/AzureDBExperiences.ts +++ b/src/AzureDBExperiences.ts @@ -9,6 +9,7 @@ import { nonNullProp } from './utils/nonNull'; export enum API { MongoDB = 'MongoDB', + MongoClusters = 'MongoClusters', Graph = 'Graph', Table = 'Table', Core = 'Core', // Now called NoSQL diff --git a/src/docdb/tree/DocDBAccountTreeItemBase.ts b/src/docdb/tree/DocDBAccountTreeItemBase.ts index cae40324..3c80426c 100644 --- a/src/docdb/tree/DocDBAccountTreeItemBase.ts +++ b/src/docdb/tree/DocDBAccountTreeItemBase.ts @@ -13,11 +13,14 @@ import { type Resource, } from '@azure/cosmos'; import { + callWithTelemetryAndErrorHandling, type AzExtParentTreeItem, type AzExtTreeItem, + type IActionContext, type ICreateChildImplContext, } from '@microsoft/vscode-azext-utils'; import type * as vscode from 'vscode'; +import { API } from '../../AzureDBExperiences'; import { type IDeleteWizardContext } from '../../commands/deleteDatabaseAccount/IDeleteWizardContext'; import { deleteCosmosDBAccount } from '../../commands/deleteDatabaseAccount/deleteCosmosDBAccount'; import { getThemeAgnosticIconPath, SERVERLESS_CAPABILITY_NAME } from '../../constants'; @@ -98,31 +101,55 @@ export abstract class DocDBAccountTreeItemBase extends DocDBTreeItemBase { - if (this.root.isEmulator) { - const unableToReachEmulatorMessage: string = - "Unable to reach emulator. Please ensure it is started and connected to the port specified by the 'cosmosDB.emulator.port' setting, then try again."; - return await rejectOnTimeout( - 2000, - () => super.loadMoreChildrenImpl(clearCache), - unableToReachEmulatorMessage, - ); - } else { - try { - return await super.loadMoreChildrenImpl(clearCache); - } catch (e) { - if (e instanceof Error && isRbacException(e) && !this.hasShownRbacNotification) { - this.hasShownRbacNotification = true; - const principalId = (await getSignedInPrincipalIdForAccountEndpoint(this.root.endpoint)) ?? ''; - // chedck if the principal ID matches the one that is signed in, otherwise this might be a security problem, hence show the error message - if (e.message.includes(`[${principalId}]`) && (await ensureRbacPermission(this, principalId))) { + const result = await callWithTelemetryAndErrorHandling( + 'getChildren', + async (context: IActionContext): Promise => { + context.telemetry.properties.parentContext = this.contextValue; + + // move this to a shared file, currently it's defined in DocDBAccountTreeItem so I can't reference it here + if (this.contextValue.includes('cosmosDBDocumentServer')) { + context.telemetry.properties.experience = API.Core; + // same issue as above + } else if (this.contextValue.includes('cosmosDBGraphAccount')) { + context.telemetry.properties.experience = API.Graph; + // same issue as above + } else if (this.contextValue.includes('cosmosDBTableAccount')) { + context.telemetry.properties.experience = API.Table; + } + + if (this.root.isEmulator) { + const unableToReachEmulatorMessage: string = + "Unable to reach emulator. Please ensure it is started and connected to the port specified by the 'cosmosDB.emulator.port' setting, then try again."; + return await rejectOnTimeout( + 2000, + () => super.loadMoreChildrenImpl(clearCache), + unableToReachEmulatorMessage, + ); + } else { + try { return await super.loadMoreChildrenImpl(clearCache); - } else { - void showRbacPermissionError(this.fullId, principalId); + } catch (e) { + if (e instanceof Error && isRbacException(e) && !this.hasShownRbacNotification) { + this.hasShownRbacNotification = true; + const principalId = + (await getSignedInPrincipalIdForAccountEndpoint(this.root.endpoint)) ?? ''; + // chedck if the principal ID matches the one that is signed in, otherwise this might be a security problem, hence show the error message + if ( + e.message.includes(`[${principalId}]`) && + (await ensureRbacPermission(this, principalId)) + ) { + return await super.loadMoreChildrenImpl(clearCache); + } else { + void showRbacPermissionError(this.fullId, principalId); + } + } + throw e; // rethrowing tells the resources extension to show the exception message in the tree } } - throw e; // rethrowing tells the resources extension to show the exception message in the tree - } - } + }, + ); + + return result ?? []; } public async deleteTreeItemImpl(context: IDeleteWizardContext): Promise { diff --git a/src/mongo/tree/MongoAccountTreeItem.ts b/src/mongo/tree/MongoAccountTreeItem.ts index c3804112..ba45b9a3 100644 --- a/src/mongo/tree/MongoAccountTreeItem.ts +++ b/src/mongo/tree/MongoAccountTreeItem.ts @@ -7,12 +7,15 @@ import { type DatabaseAccountGetResults } from '@azure/arm-cosmosdb/src/models'; import { appendExtensionUserAgent, AzExtParentTreeItem, + callWithTelemetryAndErrorHandling, parseError, type AzExtTreeItem, + type IActionContext, type ICreateChildImplContext, } from '@microsoft/vscode-azext-utils'; import { type MongoClient } from 'mongodb'; import type * as vscode from 'vscode'; +import { API } from '../../AzureDBExperiences'; import { deleteCosmosDBAccount } from '../../commands/deleteDatabaseAccount/deleteCosmosDBAccount'; import { type IDeleteWizardContext } from '../../commands/deleteDatabaseAccount/IDeleteWizardContext'; import { getThemeAgnosticIconPath, Links, testDb } from '../../constants'; @@ -63,56 +66,70 @@ export class MongoAccountTreeItem extends AzExtParentTreeItem { } public async loadMoreChildrenImpl(_clearCache: boolean): Promise { - let mongoClient: MongoClient | undefined; - try { - let databases: IDatabaseInfo[]; - - if (!this.connectionString) { - throw new Error('Missing connection string'); - } - - // Azure MongoDB accounts need to have the name passed in for private endpoints - mongoClient = await connectToMongoClient( - this.connectionString, - this.databaseAccount ? nonNullProp(this.databaseAccount, 'name') : appendExtensionUserAgent(), - ); - - const databaseInConnectionString = getDatabaseNameFromConnectionString(this.connectionString); - if (databaseInConnectionString && !this.root.isEmulator) { - // emulator violates the connection string format - // If the database is in the connection string, that's all we connect to (we might not even have permissions to list databases) - databases = [ - { - name: databaseInConnectionString, - empty: false, - }, - ]; - } else { - // https://mongodb.github.io/node-mongodb-native/3.1/api/index.html - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const result: { databases: IDatabaseInfo[] } = await mongoClient.db(testDb).admin().listDatabases(); - databases = result.databases; - } - return databases - .filter( - (database: IDatabaseInfo) => - !(database.name && database.name.toLowerCase() === 'admin' && database.empty), - ) // Filter out the 'admin' database if it's empty - .map( - (database) => new MongoDatabaseTreeItem(this, nonNullProp(database, 'name'), this.connectionString), - ); - } catch (error) { - const message = parseError(error).message; - if (this.root?.isEmulator && message.includes('ECONNREFUSED')) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - error.message = `Unable to reach emulator. See ${Links.LocalConnectionDebuggingTips} for debugging tips.\n${message}`; - } - throw error; - } finally { - if (mongoClient) { - void mongoClient.close(); - } - } + const result = await callWithTelemetryAndErrorHandling( + 'getChildren', + async (context: IActionContext): Promise => { + context.telemetry.properties.experience = API.MongoDB; + context.telemetry.properties.parentContext = this.contextValue; + + let mongoClient: MongoClient | undefined; + try { + let databases: IDatabaseInfo[]; + + if (!this.connectionString) { + throw new Error('Missing connection string'); + } + + // Azure MongoDB accounts need to have the name passed in for private endpoints + mongoClient = await connectToMongoClient( + this.connectionString, + this.databaseAccount ? nonNullProp(this.databaseAccount, 'name') : appendExtensionUserAgent(), + ); + + const databaseInConnectionString = getDatabaseNameFromConnectionString(this.connectionString); + if (databaseInConnectionString && !this.root.isEmulator) { + // emulator violates the connection string format + // If the database is in the connection string, that's all we connect to (we might not even have permissions to list databases) + databases = [ + { + name: databaseInConnectionString, + empty: false, + }, + ]; + } else { + // https://mongodb.github.io/node-mongodb-native/3.1/api/index.html + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const result: { databases: IDatabaseInfo[] } = await mongoClient + .db(testDb) + .admin() + .listDatabases(); + databases = result.databases; + } + return databases + .filter( + (database: IDatabaseInfo) => + !(database.name && database.name.toLowerCase() === 'admin' && database.empty), + ) // Filter out the 'admin' database if it's empty + .map( + (database) => + new MongoDatabaseTreeItem(this, nonNullProp(database, 'name'), this.connectionString), + ); + } catch (error) { + const message = parseError(error).message; + if (this.root?.isEmulator && message.includes('ECONNREFUSED')) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + error.message = `Unable to reach emulator. See ${Links.LocalConnectionDebuggingTips} for debugging tips.\n${message}`; + } + throw error; + } finally { + if (mongoClient) { + void mongoClient.close(); + } + } + }, + ); + + return result ?? []; } public async createChildImpl(context: ICreateChildImplContext): Promise { diff --git a/src/mongoClusters/MongoClustersExtension.ts b/src/mongoClusters/MongoClustersExtension.ts index 6b22a56d..d67cb186 100644 --- a/src/mongoClusters/MongoClustersExtension.ts +++ b/src/mongoClusters/MongoClustersExtension.ts @@ -43,85 +43,77 @@ export class MongoClustersExtension implements vscode.Disposable { } async activate(): Promise { - await callWithTelemetryAndErrorHandling('mongoClusters.activate', async (activateContext: IActionContext) => { - activateContext.telemetry.properties.isActivationEvent = 'true'; + await callWithTelemetryAndErrorHandling( + 'cosmosDB.mongoClusters.activate', + async (activateContext: IActionContext) => { + activateContext.telemetry.properties.isActivationEvent = 'true'; - const isMongoClustersEnabled: boolean = isMongoClustersSupportenabled() ?? false; + const isMongoClustersEnabled: boolean = isMongoClustersSupportenabled() ?? false; - activateContext.telemetry.properties.mongoClustersEnabled = isMongoClustersEnabled.toString(); + activateContext.telemetry.properties.mongoClustersEnabled = isMongoClustersEnabled.toString(); - // allows to show/hide commands in the package.json file - vscode.commands.executeCommand( - 'setContext', - 'vscodeDatabases.mongoClustersSupportEnabled', - isMongoClustersEnabled, - ); + // allows to show/hide commands in the package.json file + vscode.commands.executeCommand( + 'setContext', + 'vscodeDatabases.mongoClustersSupportEnabled', + isMongoClustersEnabled, + ); - if (!isMongoClustersEnabled) { - return; - } + if (!isMongoClustersEnabled) { + return; + } - // // // MongoClusters / MongoDB (vCore) support is enabled // // // + // // // MongoClusters / MongoDB (vCore) support is enabled // // // - ext.mongoClustersBranchDataProvider = new MongoClustersBranchDataProvider(); - ext.rgApiV2.resources.registerAzureResourceBranchDataProvider( - AzExtResourceType.MongoClusters, - ext.mongoClustersBranchDataProvider, - ); + ext.mongoClustersBranchDataProvider = new MongoClustersBranchDataProvider(); + ext.rgApiV2.resources.registerAzureResourceBranchDataProvider( + AzExtResourceType.MongoClusters, + ext.mongoClustersBranchDataProvider, + ); - ext.workspaceDataProvider = new SharedWorkspaceResourceProvider(); - ext.rgApiV2.resources.registerWorkspaceResourceProvider(ext.workspaceDataProvider); + ext.workspaceDataProvider = new SharedWorkspaceResourceProvider(); + ext.rgApiV2.resources.registerWorkspaceResourceProvider(ext.workspaceDataProvider); - ext.mongoClustersWorkspaceBranchDataProvider = new MongoClustersWorkspaceBranchDataProvider(); - ext.rgApiV2.resources.registerWorkspaceResourceBranchDataProvider( - WorkspaceResourceType.MongoClusters, - ext.mongoClustersWorkspaceBranchDataProvider, - ); + ext.mongoClustersWorkspaceBranchDataProvider = new MongoClustersWorkspaceBranchDataProvider(); + ext.rgApiV2.resources.registerWorkspaceResourceBranchDataProvider( + WorkspaceResourceType.MongoClusters, + ext.mongoClustersWorkspaceBranchDataProvider, + ); - // using registerCommand instead of vscode.commands.registerCommand for better telemetry: - // https://github.com/microsoft/vscode-azuretools/tree/main/utils#telemetry-and-error-handling - registerCommand('mongoClusters.cmd.hello', this.commandSayHello); + // using registerCommand instead of vscode.commands.registerCommand for better telemetry: + // https://github.com/microsoft/vscode-azuretools/tree/main/utils#telemetry-and-error-handling - registerCommand('mongoClusters.internal.containerView.open', openCollectionView); - registerCommand('mongoClusters.internal.documentView.open', openDocumentView); + registerCommand('command.internal.mongoClusters.containerView.open', openCollectionView); + registerCommand('command.internal.mongoClusters.documentView.open', openDocumentView); - registerCommandWithTreeNodeUnwrapping('mongoClusters.cmd.launchShell', launchShell); + registerCommand('command.internal.mongoClusters.importDocuments', mongoClustersImportDocuments); + registerCommand('command.internal.mongoClusters.exportDocuments', mongoClustersExportQueryResults); - registerCommandWithTreeNodeUnwrapping('mongoClusters.cmd.dropCollection', dropCollection); - registerCommandWithTreeNodeUnwrapping('mongoClusters.cmd.dropDatabase', dropDatabase); + registerCommandWithTreeNodeUnwrapping('command.mongoClusters.launchShell', launchShell); - registerCommandWithTreeNodeUnwrapping('mongoClusters.cmd.createCollection', createCollection); - registerCommandWithTreeNodeUnwrapping('mongoClusters.cmd.createDatabase', createDatabase); + registerCommandWithTreeNodeUnwrapping('command.mongoClusters.dropCollection', dropCollection); + registerCommandWithTreeNodeUnwrapping('command.mongoClusters.dropDatabase', dropDatabase); - registerCommandWithTreeNodeUnwrapping('mongoClusters.cmd.importDocuments', mongoClustersImportDocuments); - registerCommandWithTreeNodeUnwrapping( - 'mongoClusters.cmd.exportDocuments', - mongoClustersExportEntireCollection, - ); + registerCommandWithTreeNodeUnwrapping('command.mongoClusters.createCollection', createCollection); + registerCommandWithTreeNodeUnwrapping('command.mongoClusters.createDatabase', createDatabase); - registerCommand('mongoClusters.internal.importDocuments', mongoClustersImportDocuments); - registerCommand('mongoClusters.internal.exportDocuments', mongoClustersExportQueryResults); + registerCommandWithTreeNodeUnwrapping( + 'command.mongoClusters.importDocuments', + mongoClustersImportDocuments, + ); + registerCommandWithTreeNodeUnwrapping( + 'command.mongoClusters.exportDocuments', + mongoClustersExportEntireCollection, + ); - registerCommand('mongoClusters.cmd.addWorkspaceConnection', addWorkspaceConnection); - registerCommandWithTreeNodeUnwrapping( - 'mongoClusters.cmd.removeWorkspaceConnection', - removeWorkspaceConnection, - ); + registerCommand('command.mongoClusters.addWorkspaceConnection', addWorkspaceConnection); + registerCommandWithTreeNodeUnwrapping( + 'command.mongoClusters.removeWorkspaceConnection', + removeWorkspaceConnection, + ); - ext.outputChannel.appendLine(`mongoClusters: activated.`); - }); - } - - // commands - - commandSayHello = (): void => { - console.log(`Hello there here!!!`); - void vscode.window.showInformationMessage('Saying hello here!'); - - void vscode.window.showWarningMessage( - `Are you sure?`, - { modal: true, detail: "You are about to:\n\ndelete 5 documents.\n\nThis action can't be undone." }, - 'Delete', + ext.outputChannel.appendLine(`MongoDB Clusters: activated.`); + }, ); - }; + } } diff --git a/src/mongoClusters/commands/addWorkspaceConnection.ts b/src/mongoClusters/commands/addWorkspaceConnection.ts index 83da3d89..ba14aeb0 100644 --- a/src/mongoClusters/commands/addWorkspaceConnection.ts +++ b/src/mongoClusters/commands/addWorkspaceConnection.ts @@ -3,12 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { - AzureWizard, - callWithTelemetryAndErrorHandling, - UserCancelledError, - type IActionContext, -} from '@microsoft/vscode-azext-utils'; +import { AzureWizard, UserCancelledError, type IActionContext } from '@microsoft/vscode-azext-utils'; import ConnectionString from 'mongodb-connection-string-url'; import * as vscode from 'vscode'; import { API } from '../../AzureDBExperiences'; @@ -29,25 +24,20 @@ export async function addWorkspaceConnection(context: IActionContext): Promise { - context.errorHandling.rethrow = true; - context.errorHandling.suppressDisplay = true; - try { - await wizard.prompt(); - } catch (error) { - if (error instanceof UserCancelledError) { - // The user cancelled the wizard - wizardContext.aborted = true; - return; - } else { - throw error; - } - } - }, - ); + context.errorHandling.rethrow = true; + context.errorHandling.suppressDisplay = true; + + try { + await wizard.prompt(); + } catch (error) { + if (error instanceof UserCancelledError) { + // The user cancelled the wizard + wizardContext.aborted = true; + return; + } else { + throw error; + } + } if (wizardContext.aborted) { return; diff --git a/src/mongoClusters/tree/CollectionItem.ts b/src/mongoClusters/tree/CollectionItem.ts index 8067ee56..c059dd0a 100644 --- a/src/mongoClusters/tree/CollectionItem.ts +++ b/src/mongoClusters/tree/CollectionItem.ts @@ -33,7 +33,7 @@ export class CollectionItem { contextValue: 'mongoClusters.item.documents', id: `${this.id}/documents`, label: 'Documents', - commandId: 'mongoClusters.internal.containerView.open', + commandId: 'command.internal.mongoClusters.containerView.open', commandArgs: [ { id: this.id, diff --git a/src/mongoClusters/tree/DatabaseItem.ts b/src/mongoClusters/tree/DatabaseItem.ts index cb1d556d..4d391f5c 100644 --- a/src/mongoClusters/tree/DatabaseItem.ts +++ b/src/mongoClusters/tree/DatabaseItem.ts @@ -34,7 +34,7 @@ export class DatabaseItem { id: `${this.id}/no-databases`, label: 'Create collection...', iconPath: new vscode.ThemeIcon('plus'), - commandId: 'mongoClusters.cmd.createCollection', + commandId: 'command.mongoClusters.createCollection', commandArgs: [this], }), ]; diff --git a/src/mongoClusters/tree/IndexItem.ts b/src/mongoClusters/tree/IndexItem.ts index 828d11e4..b42fb5f7 100644 --- a/src/mongoClusters/tree/IndexItem.ts +++ b/src/mongoClusters/tree/IndexItem.ts @@ -38,6 +38,7 @@ export class IndexItem { getTreeItem(): TreeItem { return { id: this.id, + contextValue: 'mongoClusters.item.index', label: this.indexInfo.name, iconPath: new ThemeIcon('combine'), // TODO: create our onw icon here, this one's shape can change collapsibleState: TreeItemCollapsibleState.Collapsed, diff --git a/src/mongoClusters/tree/IndexesItem.ts b/src/mongoClusters/tree/IndexesItem.ts index 96a1046f..deb059f8 100644 --- a/src/mongoClusters/tree/IndexesItem.ts +++ b/src/mongoClusters/tree/IndexesItem.ts @@ -31,6 +31,7 @@ export class IndexesItem { getTreeItem(): TreeItem { return { id: this.id, + contextValue: 'mongoClusters.item.indexes', label: 'Indexes', iconPath: new ThemeIcon('combine'), // TODO: create our onw icon here, this one's shape can change collapsibleState: TreeItemCollapsibleState.Collapsed, diff --git a/src/mongoClusters/tree/MongoClusterItemBase.ts b/src/mongoClusters/tree/MongoClusterItemBase.ts index 0f8a42c9..5b2b9668 100644 --- a/src/mongoClusters/tree/MongoClusterItemBase.ts +++ b/src/mongoClusters/tree/MongoClusterItemBase.ts @@ -3,12 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { - callWithTelemetryAndErrorHandling, - createGenericElement, - type IActionContext, - type TreeElementBase, -} from '@microsoft/vscode-azext-utils'; +import { createGenericElement, type IActionContext, type TreeElementBase } from '@microsoft/vscode-azext-utils'; import { type TreeItem } from 'vscode'; import * as vscode from 'vscode'; @@ -38,7 +33,7 @@ export abstract class MongoClusterItemBase implements TreeElementBase { * @param context The action context. * @returns An instance of MongoClustersClient if successful; otherwise, null. */ - protected abstract authenticateAndConnect(context: IActionContext): Promise; + protected abstract authenticateAndConnect(): Promise; /** * Authenticates and connects to the cluster to list all available databases. @@ -54,66 +49,52 @@ export abstract class MongoClusterItemBase implements TreeElementBase { * @returns A list of databases in the cluster or a single element to create a new database. */ async getChildren(): Promise { - const result = await callWithTelemetryAndErrorHandling( - 'mongoClusterItem.getChildren', - async (context: IActionContext) => { - // Error handling setup - context.errorHandling.suppressDisplay = false; - context.errorHandling.rethrow = true; - context.valuesToMask.push(this.id, this.mongoCluster.name); - - ext.outputChannel.appendLine( - `MongoDB Clusters: Loading cluster details for "${this.mongoCluster.name}"`, - ); - - let mongoClustersClient: MongoClustersClient | null; - - // Check if credentials are cached, and return the cached client if available - if (CredentialCache.hasCredentials(this.id)) { - ext.outputChannel.appendLine( - `MongoDB Clusters: Reusing active connection for "${this.mongoCluster.name}".`, - ); - mongoClustersClient = await MongoClustersClient.getClient(this.id); - } else { - // Call to the abstract method to authenticate and connect to the cluster - mongoClustersClient = await this.authenticateAndConnect(context); - } - - // If authentication failed, return the error element - if (!mongoClustersClient) { - return [ - createGenericElement({ - contextValue: 'error', - id: `${this.id}/error`, - label: 'Failed to authenticate (click to retry)', - iconPath: new vscode.ThemeIcon('error'), - commandId: 'azureResourceGroups.refreshTree', - }), - ]; - } - - // List the databases - return mongoClustersClient.listDatabases().then((databases: DatabaseItemModel[]) => { - if (databases.length === 0) { - return [ - createGenericElement({ - contextValue: 'mongoClusters.item.no-databases', - id: `${this.id}/no-databases`, - label: 'Create database...', - iconPath: new vscode.ThemeIcon('plus'), - commandId: 'mongoClusters.cmd.createDatabase', - commandArgs: [this], - }), - ]; - } - - // Map the databases to DatabaseItem elements - return databases.map((database) => new DatabaseItem(this.mongoCluster, database)); - }); - }, - ); - - return result ?? []; + ext.outputChannel.appendLine(`MongoDB Clusters: Loading cluster details for "${this.mongoCluster.name}"`); + + let mongoClustersClient: MongoClustersClient | null; + + // Check if credentials are cached, and return the cached client if available + if (CredentialCache.hasCredentials(this.id)) { + ext.outputChannel.appendLine( + `MongoDB Clusters: Reusing active connection for "${this.mongoCluster.name}".`, + ); + mongoClustersClient = await MongoClustersClient.getClient(this.id); + } else { + // Call to the abstract method to authenticate and connect to the cluster + mongoClustersClient = await this.authenticateAndConnect(); + } + + // If authentication failed, return the error element + if (!mongoClustersClient) { + return [ + createGenericElement({ + contextValue: 'error', + id: `${this.id}/error`, + label: 'Failed to authenticate (click to retry)', + iconPath: new vscode.ThemeIcon('error'), + commandId: 'azureResourceGroups.refreshTree', + }), + ]; + } + + // List the databases + return mongoClustersClient.listDatabases().then((databases: DatabaseItemModel[]) => { + if (databases.length === 0) { + return [ + createGenericElement({ + contextValue: 'mongoClusters.item.no-databases', + id: `${this.id}/no-databases`, + label: 'Create database...', + iconPath: new vscode.ThemeIcon('plus'), + commandId: 'command.mongoClusters.createDatabase', + commandArgs: [this], + }), + ]; + } + + // Map the databases to DatabaseItem elements + return databases.map((database) => new DatabaseItem(this.mongoCluster, database)); + }); } /** diff --git a/src/mongoClusters/tree/MongoClusterResourceItem.ts b/src/mongoClusters/tree/MongoClusterResourceItem.ts index c80618c4..09bbfec9 100644 --- a/src/mongoClusters/tree/MongoClusterResourceItem.ts +++ b/src/mongoClusters/tree/MongoClusterResourceItem.ts @@ -40,80 +40,89 @@ export class MongoClusterResourceItem extends MongoClusterItemBase { * @param context The action context. * @returns An instance of MongoClustersClient if successful; otherwise, null. */ - protected async authenticateAndConnect(context: IActionContext): Promise { - ext.outputChannel.appendLine( - `MongoDB Clusters: Attempting to authenticate with "${this.mongoCluster.name}"...`, - ); - - // Create a client to interact with the MongoDB vCore management API and read the cluster details - const managementClient = await createMongoClustersManagementClient(context, this.subscription); - const clusterInformation = await managementClient.mongoClusters.get( - this.mongoCluster.resourceGroup as string, - this.mongoCluster.name, - ); - - const clusterConnectionString = nonNullValue(clusterInformation.connectionString); - - context.valuesToMask.push(clusterConnectionString); - - // Fetch non-admin users using the extracted method - const clusterNonAdminUsers = await this.fetchNonAdminUsersFromAzure(managementClient, clusterInformation); - - const wizardContext: AuthenticateWizardContext = { - ...context, - adminUserName: clusterInformation.administratorLogin, - otherUserNames: clusterNonAdminUsers, - resourceName: this.mongoCluster.name, - }; - - // Prompt the user for credentials - const credentialsProvided = await this.promptForCredentials(wizardContext); + protected async authenticateAndConnect(): Promise { + const result = await callWithTelemetryAndErrorHandling( + 'cosmosDB.mongoClusters.authenticate', + async (context: IActionContext) => { + ext.outputChannel.appendLine( + `MongoDB Clusters: Attempting to authenticate with "${this.mongoCluster.name}"...`, + ); + + // Create a client to interact with the MongoDB vCore management API and read the cluster details + const managementClient = await createMongoClustersManagementClient(context, this.subscription); + const clusterInformation = await managementClient.mongoClusters.get( + this.mongoCluster.resourceGroup as string, + this.mongoCluster.name, + ); + + const clusterConnectionString = nonNullValue(clusterInformation.connectionString); + + context.valuesToMask.push(clusterConnectionString); + + // Fetch non-admin users using the extracted method + const clusterNonAdminUsers = await this.fetchNonAdminUsersFromAzure( + managementClient, + clusterInformation, + ); + + const wizardContext: AuthenticateWizardContext = { + ...context, + adminUserName: clusterInformation.administratorLogin, + otherUserNames: clusterNonAdminUsers, + resourceName: this.mongoCluster.name, + }; + + // Prompt the user for credentials + const credentialsProvided = await this.promptForCredentials(wizardContext); + + // If the wizard was aborted or failed, return null + if (!credentialsProvided) { + return null; + } - // If the wizard was aborted or failed, return null - if (!credentialsProvided) { - return null; - } + context.valuesToMask.push(nonNullProp(wizardContext, 'password')); - context.valuesToMask.push(nonNullProp(wizardContext, 'password')); + // Cache the credentials + CredentialCache.setCredentials( + this.id, + nonNullValue(clusterConnectionString), + nonNullProp(wizardContext, 'selectedUserName'), + nonNullProp(wizardContext, 'password'), + ); - // Cache the credentials - CredentialCache.setCredentials( - this.id, - nonNullValue(clusterConnectionString), - nonNullProp(wizardContext, 'selectedUserName'), - nonNullProp(wizardContext, 'password'), - ); + ext.outputChannel.append( + `MongoDB Clusters: Connecting to the cluster as "${wizardContext.selectedUserName}"... `, + ); - ext.outputChannel.append( - `MongoDB Clusters: Connecting to the cluster as "${wizardContext.selectedUserName}"... `, - ); + // Attempt to create the client with the provided credentials + let mongoClustersClient: MongoClustersClient; + try { + mongoClustersClient = await MongoClustersClient.getClient(this.id).catch((error: Error) => { + ext.outputChannel.appendLine(`Error: ${error.message}`); - // Attempt to create the client with the provided credentials - let mongoClustersClient: MongoClustersClient; - try { - mongoClustersClient = await MongoClustersClient.getClient(this.id).catch((error: Error) => { - ext.outputChannel.appendLine('failed.'); - ext.outputChannel.appendLine(`Error: ${error.message}`); + void vscode.window.showErrorMessage(`Failed to connect: ${error.message}`); - void vscode.window.showErrorMessage(`Failed to connect: ${error.message}`); + throw error; + }); + } catch (error) { + console.log(error); + // If connection fails, remove cached credentials + await MongoClustersClient.deleteClient(this.id); + CredentialCache.deleteCredentials(this.id); - throw error; - }); - } catch (error) { - console.log(error); - // If connection fails, remove cached credentials - await MongoClustersClient.deleteClient(this.id); - CredentialCache.deleteCredentials(this.id); + // Return null to indicate failure + return null; + } - // Return null to indicate failure - return null; - } + ext.outputChannel.appendLine( + `MongoDB Clusters: Connected to "${this.mongoCluster.name}" as "${wizardContext.selectedUserName}".`, + ); - ext.outputChannel.appendLine( - `MongoDB Clusters: Connected to "${this.mongoCluster.name}" as "${wizardContext.selectedUserName}".`, + return mongoClustersClient; + }, ); - return mongoClustersClient; + return result ?? null; } /** @@ -130,20 +139,14 @@ export class MongoClusterResourceItem extends MongoClusterItemBase { }); // Prompt the user for credentials - await callWithTelemetryAndErrorHandling( - 'mongoClusterItem.authenticate.promptForCredentials', - async (_context: IActionContext) => { - _context.errorHandling.rethrow = true; - _context.errorHandling.suppressDisplay = false; - try { - await wizard.prompt(); // This will prompt the user; results are stored in wizardContext - } catch (error) { - if (error instanceof UserCancelledError) { - wizardContext.aborted = true; - } - } - }, - ); + + try { + await wizard.prompt(); // This will prompt the user; results are stored in wizardContext + } catch (error) { + if (error instanceof UserCancelledError) { + wizardContext.aborted = true; + } + } // Return true if the wizard completed successfully; false otherwise return !wizardContext.aborted; diff --git a/src/mongoClusters/tree/MongoClustersBranchDataProvider.ts b/src/mongoClusters/tree/MongoClustersBranchDataProvider.ts index 6b271b05..2d91a768 100644 --- a/src/mongoClusters/tree/MongoClustersBranchDataProvider.ts +++ b/src/mongoClusters/tree/MongoClustersBranchDataProvider.ts @@ -13,6 +13,7 @@ import { type ResourceModelBase, } from '@microsoft/vscode-azureresources-api'; import * as vscode from 'vscode'; +import { API } from '../../AzureDBExperiences'; import { ext } from '../../extensionVariables'; import { createMongoClustersManagementClient } from '../../utils/azureClients'; import { type MongoClusterModel } from './MongoClusterModel'; @@ -49,13 +50,18 @@ export class MongoClustersBranchDataProvider /** * getChildren is called for every element in the tree when expanding, the element being expanded is being passed as an argument */ - return (await element.getChildren?.())?.map((child) => { - if (child.id) { - return ext.state.wrapItemInStateHandling(child as TreeElementBase & { id: string }, () => - this.refresh(child), - ); - } - return child; + return await callWithTelemetryAndErrorHandling('getChildren', async (context: IActionContext) => { + context.telemetry.properties.experience = API.MongoClusters; + context.telemetry.properties.parentContext = (await element.getTreeItem()).contextValue ?? 'unknown'; + + return (await element.getChildren?.())?.map((child) => { + if (child.id) { + return ext.state.wrapItemInStateHandling(child as TreeElementBase & { id: string }, () => + this.refresh(child), + ); + } + return child; + }); }); } @@ -65,12 +71,14 @@ export class MongoClustersBranchDataProvider */ const resourceItem = await callWithTelemetryAndErrorHandling( - 'mongoCluster.getResourceItem', + 'resolveResource', // disabling require-await, the async aspect is in there, but uses the .then pattern // eslint-disable-next-line @typescript-eslint/require-await - async (_context: IActionContext) => { + async (context: IActionContext) => { + context.telemetry.properties.experience = API.MongoClusters; + if (this.detailsCacheUpdateRequested) { - void this.updateResourceCache(_context, element.subscription, 1000 * 60 * 5).then(() => { + void this.updateResourceCache(context, element.subscription, 1000 * 60 * 5).then(() => { /** * Instances of MongoClusterItem were stored in the itemsToUpdateInfo map, * so that when the cache is updated, the items can be refreshed. @@ -118,9 +126,11 @@ export class MongoClustersBranchDataProvider cacheDuration: number, ): Promise { return callWithTelemetryAndErrorHandling( - 'mongoClusters.getResourceItem.cacheUpdate', + 'resolveResource.updatingResourceCache', async (context: IActionContext) => { try { + context.telemetry.properties.experience = API.MongoClusters; + this.detailsCacheUpdateRequested = false; setTimeout(() => { diff --git a/src/mongoClusters/tree/workspace/MongoClusterWorkspaceItem.ts b/src/mongoClusters/tree/workspace/MongoClusterWorkspaceItem.ts index 58cd78bc..8b368ac7 100644 --- a/src/mongoClusters/tree/workspace/MongoClusterWorkspaceItem.ts +++ b/src/mongoClusters/tree/workspace/MongoClusterWorkspaceItem.ts @@ -35,70 +35,82 @@ export class MongoClusterWorkspaceItem extends MongoClusterItemBase { * @param context The action context. * @returns An instance of MongoClustersClient if successful; otherwise, null. */ - protected async authenticateAndConnect(context: IActionContext): Promise { - ext.outputChannel.appendLine(`MongoDB Clusters: Attempting to authenticate with ${this.mongoCluster.name}`); + protected async authenticateAndConnect(): Promise { + const result = await callWithTelemetryAndErrorHandling( + 'cosmosDB.mongoClusters.authenticate', + async (context: IActionContext) => { + context.telemetry.properties.view = 'workspace'; - let mongoClustersClient: MongoClustersClient; + ext.outputChannel.appendLine( + `MongoDB Clusters: Attempting to authenticate with ${this.mongoCluster.name}`, + ); - const connectionString = new ConnectionString(nonNullValue(this.mongoCluster.connectionString)); + let mongoClustersClient: MongoClustersClient; - let username: string | undefined = connectionString.username; - let password: string | undefined = connectionString.password; + const connectionString = new ConnectionString(nonNullValue(this.mongoCluster.connectionString)); - if (!username || username.length === 0 || !password || password.length === 0) { - const wizardContext: AuthenticateWizardContext = { - ...context, - adminUserName: undefined, - otherUserNames: [], - resourceName: this.mongoCluster.name, + let username: string | undefined = connectionString.username; + let password: string | undefined = connectionString.password; - // preconfigure the username in case it's provided connection string - selectedUserName: username, - // we'll always ask for the password - }; + if (!username || username.length === 0 || !password || password.length === 0) { + const wizardContext: AuthenticateWizardContext = { + ...context, + adminUserName: undefined, + otherUserNames: [], + resourceName: this.mongoCluster.name, - // Prompt the user for credentials using the extracted method - const credentialsProvided = await this.promptForCredentials(wizardContext); + // preconfigure the username in case it's provided connection string + selectedUserName: username, + // we'll always ask for the password + }; - // If the wizard was aborted or failed, return null - if (!credentialsProvided) { - return null; - } + // Prompt the user for credentials using the extracted method + const credentialsProvided = await this.promptForCredentials(wizardContext); - context.valuesToMask.push(nonNullProp(wizardContext, 'password')); + // If the wizard was aborted or failed, return null + if (!credentialsProvided) { + return null; + } - username = nonNullProp(wizardContext, 'selectedUserName'); - password = nonNullProp(wizardContext, 'password'); - } + context.valuesToMask.push(nonNullProp(wizardContext, 'password')); - ext.outputChannel.append(`MongoDB Clusters: Connecting to the cluster as "${username}"... `); + username = nonNullProp(wizardContext, 'selectedUserName'); + password = nonNullProp(wizardContext, 'password'); + } - // Cache the credentials - CredentialCache.setCredentials(this.id, connectionString.toString(), username, password); + ext.outputChannel.append(`MongoDB Clusters: Connecting to the cluster as "${username}"... `); - // Attempt to create the client with the provided credentials - try { - mongoClustersClient = await MongoClustersClient.getClient(this.id).catch((error: Error) => { - ext.outputChannel.appendLine('failed.'); - ext.outputChannel.appendLine(`Error: ${error.message}`); + // Cache the credentials + CredentialCache.setCredentials(this.id, connectionString.toString(), username, password); - void vscode.window.showErrorMessage(`Failed to connect: ${error.message}`); + // Attempt to create the client with the provided credentials + try { + mongoClustersClient = await MongoClustersClient.getClient(this.id).catch((error: Error) => { + ext.outputChannel.appendLine('failed.'); + ext.outputChannel.appendLine(`Error: ${error.message}`); - throw error; - }); - } catch (error) { - console.log(error); - // If connection fails, remove cached credentials - await MongoClustersClient.deleteClient(this.id); - CredentialCache.deleteCredentials(this.id); + void vscode.window.showErrorMessage(`Failed to connect: ${error.message}`); - // Return null to indicate failure - return null; - } + throw error; + }); + } catch (error) { + console.log(error); + // If connection fails, remove cached credentials + await MongoClustersClient.deleteClient(this.id); + CredentialCache.deleteCredentials(this.id); - ext.outputChannel.appendLine(`MongoDB Clusters: Connected to "${this.mongoCluster.name}" as "${username}"`); + // Return null to indicate failure + return null; + } - return mongoClustersClient; + ext.outputChannel.appendLine( + `MongoDB Clusters: Connected to "${this.mongoCluster.name}" as "${username}"`, + ); + + return mongoClustersClient; + }, + ); + return result ?? null; } /** @@ -115,10 +127,12 @@ export class MongoClusterWorkspaceItem extends MongoClusterItemBase { // Prompt the user for credentials await callWithTelemetryAndErrorHandling( - 'mongoClusterItem.authenticate.promptForCredentials', - async (_context: IActionContext) => { - _context.errorHandling.rethrow = true; - _context.errorHandling.suppressDisplay = false; + 'cosmosDB.mongoClusters.authenticate.promptForCredentials', + async (context: IActionContext) => { + context.telemetry.properties.view = 'workspace'; + + context.errorHandling.rethrow = true; + context.errorHandling.suppressDisplay = false; try { await wizard.prompt(); // This will prompt the user; results are stored in wizardContext } catch (error) { diff --git a/src/mongoClusters/tree/workspace/MongoClustersWorkbenchBranchDataProvider.ts b/src/mongoClusters/tree/workspace/MongoClustersWorkbenchBranchDataProvider.ts index 995634e5..39634e06 100644 --- a/src/mongoClusters/tree/workspace/MongoClustersWorkbenchBranchDataProvider.ts +++ b/src/mongoClusters/tree/workspace/MongoClustersWorkbenchBranchDataProvider.ts @@ -3,10 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { type TreeElementBase } from '@microsoft/vscode-azext-utils'; +import { + callWithTelemetryAndErrorHandling, + type IActionContext, + type TreeElementBase, +} from '@microsoft/vscode-azext-utils'; import { type WorkspaceResourceBranchDataProvider } from '@microsoft/vscode-azureresources-api'; import * as vscode from 'vscode'; import { type TreeItem } from 'vscode'; +import { API } from '../../../AzureDBExperiences'; import { ext } from '../../../extensionVariables'; import { MongoDBAccountsWorkspaceItem } from './MongoDBAccountsWorkspaceItem'; @@ -27,13 +32,19 @@ export class MongoClustersWorkspaceBranchDataProvider } async getChildren(element: TreeElementBase): Promise { - return (await element.getChildren?.())?.map((child) => { - if (child.id) { - return ext.state.wrapItemInStateHandling(child as TreeElementBase & { id: string }, () => - this.refresh(child), - ); - } - return child; + return await callWithTelemetryAndErrorHandling('getChildren', async (context: IActionContext) => { + context.telemetry.properties.experience = API.MongoClusters; + context.telemetry.properties.view = 'workspace'; + context.telemetry.properties.parentContext = (await element.getTreeItem()).contextValue ?? 'unknown'; + + return (await element.getChildren?.())?.map((child) => { + if (child.id) { + return ext.state.wrapItemInStateHandling(child as TreeElementBase & { id: string }, () => + this.refresh(child), + ); + } + return child; + }); }); } diff --git a/src/mongoClusters/tree/workspace/MongoDBAccountsWorkspaceItem.ts b/src/mongoClusters/tree/workspace/MongoDBAccountsWorkspaceItem.ts index 04b4658a..e29c3776 100644 --- a/src/mongoClusters/tree/workspace/MongoDBAccountsWorkspaceItem.ts +++ b/src/mongoClusters/tree/workspace/MongoDBAccountsWorkspaceItem.ts @@ -14,7 +14,7 @@ export class MongoDBAccountsWorkspaceItem implements TreeElementBase { id: string; constructor() { - this.id = `vscode.cosmosdb.workspace.mongoclusters.mongodbaccounts`; + this.id = `vscode.cosmosdb.workspace.mongoclusters.accounts`; } async getChildren(): Promise { @@ -34,7 +34,7 @@ export class MongoDBAccountsWorkspaceItem implements TreeElementBase { id: this.id + '/newConnection', label: 'New Connection...', iconPath: new ThemeIcon('plus'), - commandId: 'mongoClusters.cmd.addWorkspaceConnection', + commandId: 'command.mongoClusters.addWorkspaceConnection', }), ]; } @@ -42,7 +42,7 @@ export class MongoDBAccountsWorkspaceItem implements TreeElementBase { getTreeItem(): TreeItem { return { id: this.id, - contextValue: 'vscode.cosmosdb.workspace.mongoclusters.mongodbaccounts', + contextValue: 'vscode.cosmosdb.workspace.mongoclusters.accounts', label: 'MongoDB Cluster Accounts', iconPath: new ThemeIcon('link'), collapsibleState: TreeItemCollapsibleState.Collapsed, diff --git a/src/mongoClusters/wizards/addWorkspaceConnection/ConnectionStringStep.ts b/src/mongoClusters/wizards/addWorkspaceConnection/ConnectionStringStep.ts index 165e21bb..1fb5ab13 100644 --- a/src/mongoClusters/wizards/addWorkspaceConnection/ConnectionStringStep.ts +++ b/src/mongoClusters/wizards/addWorkspaceConnection/ConnectionStringStep.ts @@ -35,8 +35,7 @@ export class ConnectionStringStep extends AzureWizardPromptStep { try { - const parsedCS = new ConnectionString(connectionString); - console.log(parsedCS); + new ConnectionString(connectionString); } catch (error) { if (error instanceof Error && error.name === 'MongoParseError') { return error.message; diff --git a/src/webviews/mongoClusters/collectionView/collectionViewRouter.ts b/src/webviews/mongoClusters/collectionView/collectionViewRouter.ts index cdf8297d..3caf48f2 100644 --- a/src/webviews/mongoClusters/collectionView/collectionViewRouter.ts +++ b/src/webviews/mongoClusters/collectionView/collectionViewRouter.ts @@ -113,7 +113,7 @@ export const collectionsViewRouter = router({ .mutation(({ ctx }) => { const myCtx = ctx as RouterContext; - vscode.commands.executeCommand('mongoClusters.internal.documentView.open', { + vscode.commands.executeCommand('command.internal.mongoClusters.documentView.open', { sessionId: myCtx.sessionId, databaseName: myCtx.databaseName, collectionName: myCtx.collectionName, @@ -127,7 +127,7 @@ export const collectionsViewRouter = router({ .mutation(({ input, ctx }) => { const myCtx = ctx as RouterContext; - vscode.commands.executeCommand('mongoClusters.internal.documentView.open', { + vscode.commands.executeCommand('command.internal.mongoClusters.documentView.open', { sessionId: myCtx.sessionId, databaseName: myCtx.databaseName, collectionName: myCtx.collectionName, @@ -142,7 +142,7 @@ export const collectionsViewRouter = router({ .mutation(({ input, ctx }) => { const myCtx = ctx as RouterContext; - vscode.commands.executeCommand('mongoClusters.internal.documentView.open', { + vscode.commands.executeCommand('command.internal.mongoClusters.documentView.open', { sessionId: myCtx.sessionId, databaseName: myCtx.databaseName, collectionName: myCtx.collectionName, @@ -187,7 +187,7 @@ export const collectionsViewRouter = router({ const myCtx = ctx as RouterContext; vscode.commands.executeCommand( - 'mongoClusters.internal.exportDocuments', + 'command.internal.mongoClusters.exportDocuments', myCtx.collectionTreeItem, input.query, ); @@ -195,6 +195,6 @@ export const collectionsViewRouter = router({ importDocuments: publicProcedure.query(async ({ ctx }) => { const myCtx = ctx as RouterContext; - vscode.commands.executeCommand('mongoClusters.internal.importDocuments', myCtx.collectionTreeItem); + vscode.commands.executeCommand('command.internal.mongoClusters.importDocuments', myCtx.collectionTreeItem); }), });