From ecfcb92a89476c8a23e04055ae437a46837cad8e Mon Sep 17 00:00:00 2001 From: Aditya Bist Date: Wed, 3 Jul 2019 16:03:09 -0700 Subject: [PATCH] Data explorer/context menu initial (#6264) * fixed context for data explorer * added more files * initial servers and database context menu actions finished * added all actions for servers and databases with correct conditions * added nodetype and nodelabel for subtype actions * added nodeinfo logic to oe shim * fixed context for cms * added all scripting actions to data explorer * review comments * fix import * fix correct context key * removed unused import * separate PR for commands and menus added * rename mssql context menu nodes * remove command id constants --- .../database/databaseTreeDataProvider.ts | 5 +- .../databaseServerTreeDataProvider.ts | 5 +- .../cmsResource/tree/cmsResourceTreeNode.ts | 1 + .../tree/registeredServerTreeNode.ts | 1 + src/sql/azdata.proposed.d.ts | 6 + .../workbench/api/common/sqlExtHostTypes.ts | 5 + .../api/node/extHostConnectionManagement.ts | 4 +- .../workbench/api/node/sqlExtHost.api.impl.ts | 3 +- .../browser/parts/views/customView.ts | 1 - src/sql/workbench/common/views.ts | 2 + .../browser/dataExplorerViewlet.ts | 1 + .../dataExplorer/common/mssqlNodeContext.ts | 159 ++++++++++++++++++ .../parts/dataExplorer/common/nodeContext.ts | 14 +- .../nodeActions.contribution.ts | 48 ++++-- .../electron-browser/nodeCommands.ts | 8 +- .../parts/notebook/notebookActions.ts | 1 - .../browser/objectExplorerActions.ts | 3 +- .../common/objectExplorerViewTreeShim.ts | 42 ++++- .../workbench/api/common/extHostTreeViews.ts | 3 +- 19 files changed, 276 insertions(+), 36 deletions(-) create mode 100644 src/sql/workbench/parts/dataExplorer/common/mssqlNodeContext.ts diff --git a/extensions/azurecore/src/azureResource/providers/database/databaseTreeDataProvider.ts b/extensions/azurecore/src/azureResource/providers/database/databaseTreeDataProvider.ts index 2a6d9bad70..19cb954a72 100644 --- a/extensions/azurecore/src/azureResource/providers/database/databaseTreeDataProvider.ts +++ b/extensions/azurecore/src/azureResource/providers/database/databaseTreeDataProvider.ts @@ -5,7 +5,7 @@ 'use strict'; -import { AzureResource } from 'azdata'; +import { AzureResource, ExtensionNodeType } from 'azdata'; import { TreeItem, TreeItemCollapsibleState, ExtensionContext } from 'vscode'; import { TokenCredentials } from 'ms-rest'; import * as nls from 'vscode-nls'; @@ -72,7 +72,8 @@ export class AzureResourceDatabaseTreeDataProvider implements azureResource.IAzu saveProfile: false, options: {} }, - childProvider: 'MSSQL' + childProvider: 'MSSQL', + type: ExtensionNodeType.Database } }); } diff --git a/extensions/azurecore/src/azureResource/providers/databaseServer/databaseServerTreeDataProvider.ts b/extensions/azurecore/src/azureResource/providers/databaseServer/databaseServerTreeDataProvider.ts index f7e61b2303..804491cec9 100644 --- a/extensions/azurecore/src/azureResource/providers/databaseServer/databaseServerTreeDataProvider.ts +++ b/extensions/azurecore/src/azureResource/providers/databaseServer/databaseServerTreeDataProvider.ts @@ -5,7 +5,7 @@ 'use strict'; -import { AzureResource } from 'azdata'; +import { AzureResource, ExtensionNodeType } from 'azdata'; import { TreeItem, TreeItemCollapsibleState, ExtensionContext } from 'vscode'; import { TokenCredentials } from 'ms-rest'; import * as nls from 'vscode-nls'; @@ -72,7 +72,8 @@ export class AzureResourceDatabaseServerTreeDataProvider implements azureResourc saveProfile: false, options: {} }, - childProvider: 'MSSQL' + childProvider: 'MSSQL', + type: ExtensionNodeType.Server } }); } diff --git a/extensions/cms/src/cmsResource/tree/cmsResourceTreeNode.ts b/extensions/cms/src/cmsResource/tree/cmsResourceTreeNode.ts index b1c15e0546..a95ca1025f 100644 --- a/extensions/cms/src/cmsResource/tree/cmsResourceTreeNode.ts +++ b/extensions/cms/src/cmsResource/tree/cmsResourceTreeNode.ts @@ -95,6 +95,7 @@ export class CmsResourceTreeNode extends CmsResourceTreeNodeBase { item.contextValue = CmsResourceItemType.cmsNodeContainer; item.id = this._id; item.tooltip = this.description; + item.type = azdata.ExtensionNodeType.Server; item.iconPath = { dark: this.appContext.extensionContext.asAbsolutePath('resources/light/centralmanagement_server.svg'), light: this.appContext.extensionContext.asAbsolutePath('resources/light/centralmanagement_server.svg') diff --git a/extensions/cms/src/cmsResource/tree/registeredServerTreeNode.ts b/extensions/cms/src/cmsResource/tree/registeredServerTreeNode.ts index 2acf5842b1..2082049b93 100644 --- a/extensions/cms/src/cmsResource/tree/registeredServerTreeNode.ts +++ b/extensions/cms/src/cmsResource/tree/registeredServerTreeNode.ts @@ -55,6 +55,7 @@ export class RegisteredServerTreeNode extends CmsResourceTreeNodeBase { collapsibleState: TreeItemCollapsibleState.Collapsed, label: this.name ? this.name : this.serverName, childProvider: 'MSSQL', + type: azdata.ExtensionNodeType.Server, iconPath: { dark: this.appContext.extensionContext.asAbsolutePath('resources/light/regserverserver.svg'), light: this.appContext.extensionContext.asAbsolutePath('resources/light/regserverserver.svg') diff --git a/src/sql/azdata.proposed.d.ts b/src/sql/azdata.proposed.d.ts index 857618b07b..347d780014 100644 --- a/src/sql/azdata.proposed.d.ts +++ b/src/sql/azdata.proposed.d.ts @@ -2632,9 +2632,15 @@ declare module 'azdata' { serverInfo: ServerInfo; } + export enum ExtensionNodeType { + Server = 'Server', + Database = 'Database' + } + export class TreeItem extends vscode.TreeItem { payload?: IConnectionProfile; childProvider?: string; + type?: ExtensionNodeType; } export namespace tasks { diff --git a/src/sql/workbench/api/common/sqlExtHostTypes.ts b/src/sql/workbench/api/common/sqlExtHostTypes.ts index e98c589091..cd632d112a 100644 --- a/src/sql/workbench/api/common/sqlExtHostTypes.ts +++ b/src/sql/workbench/api/common/sqlExtHostTypes.ts @@ -191,6 +191,11 @@ export enum StepCompletionAction { GoToStep = 4 } +export enum ExtensionNodeType { + Server = 'Server', + Database = 'Database' +} + export interface IComponentShape { type: ModelComponentTypes; id: string; diff --git a/src/sql/workbench/api/node/extHostConnectionManagement.ts b/src/sql/workbench/api/node/extHostConnectionManagement.ts index df39064353..f074147be1 100644 --- a/src/sql/workbench/api/node/extHostConnectionManagement.ts +++ b/src/sql/workbench/api/node/extHostConnectionManagement.ts @@ -21,7 +21,9 @@ export class ExtHostConnectionManagement extends ExtHostConnectionManagementShap public $getCurrentConnection(): Thenable { let connection: any = this._proxy.$getCurrentConnection(); connection.then((conn) => { - conn.providerId = conn.providerName; + if (conn && conn.providerId) { + conn.providerId = conn.providerName; + } }); return connection; } diff --git a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts index 2e9a4532a2..6c161c516b 100644 --- a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts +++ b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts @@ -552,7 +552,8 @@ export function createApiFactory( ColumnType: sqlExtHostTypes.ColumnType, ActionOnCellCheckboxCheck: sqlExtHostTypes.ActionOnCellCheckboxCheck, StepCompletionAction: sqlExtHostTypes.StepCompletionAction, - AgentSubSystem: sqlExtHostTypes.AgentSubSystem + AgentSubSystem: sqlExtHostTypes.AgentSubSystem, + ExtensionNodeType: sqlExtHostTypes.ExtensionNodeType }; }, diff --git a/src/sql/workbench/browser/parts/views/customView.ts b/src/sql/workbench/browser/parts/views/customView.ts index 3fc97e8fe6..d2fbe1af35 100644 --- a/src/sql/workbench/browser/parts/views/customView.ts +++ b/src/sql/workbench/browser/parts/views/customView.ts @@ -43,7 +43,6 @@ import { dirname } from 'vs/base/common/resources'; import { ITreeItem, ITreeView } from 'sql/workbench/common/views'; import { IOEShimService } from 'sql/workbench/parts/objectExplorer/common/objectExplorerViewTreeShim'; -import { equalsIgnoreCase } from 'vs/base/common/strings'; import { NodeContextKey } from 'sql/workbench/parts/dataExplorer/common/nodeContext'; import { fillInActionBarActions, fillInContextMenuActions, ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { mssqlProviderName } from 'sql/platform/connection/common/constants'; diff --git a/src/sql/workbench/common/views.ts b/src/sql/workbench/common/views.ts index fea7fac3f8..af3d83c8f9 100644 --- a/src/sql/workbench/common/views.ts +++ b/src/sql/workbench/common/views.ts @@ -5,6 +5,7 @@ import { ITreeViewDataProvider, ITreeItem as vsITreeItem, IViewDescriptor, ITreeView as vsITreeView } from 'vs/workbench/common/views'; import { IConnectionProfile } from 'azdata'; +import { ExtensionNodeType } from 'sql/workbench/api/common/sqlExtHostTypes'; export interface ITreeComponentItem extends vsITreeItem { checked?: boolean; @@ -22,6 +23,7 @@ export interface ITreeItem extends vsITreeItem { childProvider?: string; payload?: IConnectionProfile; // its possible we will want this to be more generic sqlIcon?: string; + type?: ExtensionNodeType; } export interface ITreeView extends vsITreeView { diff --git a/src/sql/workbench/parts/dataExplorer/browser/dataExplorerViewlet.ts b/src/sql/workbench/parts/dataExplorer/browser/dataExplorerViewlet.ts index 590f691be5..569717aa85 100644 --- a/src/sql/workbench/parts/dataExplorer/browser/dataExplorerViewlet.ts +++ b/src/sql/workbench/parts/dataExplorer/browser/dataExplorerViewlet.ts @@ -112,6 +112,7 @@ export class DataExplorerViewlet extends ViewContainerViewlet { actions.push(...group[1]); } }); + menu.dispose(); return actions; } diff --git a/src/sql/workbench/parts/dataExplorer/common/mssqlNodeContext.ts b/src/sql/workbench/parts/dataExplorer/common/mssqlNodeContext.ts new file mode 100644 index 0000000000..939671b554 --- /dev/null +++ b/src/sql/workbench/parts/dataExplorer/common/mssqlNodeContext.ts @@ -0,0 +1,159 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as os from 'os'; +import { INodeContextValue } from 'sql/workbench/parts/dataExplorer/common/nodeContext'; +import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; +import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; +import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; +import { mssqlProviderName } from 'sql/platform/connection/common/constants'; +import { NodeType } from 'sql/workbench/parts/objectExplorer/common/nodeType'; +import { ExtensionNodeType } from 'sql/workbench/api/common/sqlExtHostTypes'; + +export class MssqlNodeContext extends Disposable { + + static readonly canSelect = new Set([NodeType.Table, NodeType.View]); + static readonly canEditData = new Set([NodeType.Table]); + static readonly canCreateOrDelete = new Set([NodeType.AggregateFunction, NodeType.PartitionFunction, NodeType.ScalarValuedFunction, + NodeType.Schema, NodeType.StoredProcedure, NodeType.Table, NodeType.TableValuedFunction, + NodeType.User, NodeType.UserDefinedTableType, NodeType.View]); + static readonly canExecute = new Set([NodeType.StoredProcedure]); + static readonly canAlter = new Set([NodeType.AggregateFunction, NodeType.PartitionFunction, NodeType.ScalarValuedFunction, + NodeType.StoredProcedure, NodeType.TableValuedFunction, NodeType.View]); + + // General node context keys + static NodeProvider = new RawContextKey('nodeProvider', undefined); + static IsDatabaseOrServer = new RawContextKey('isDatabaseOrServer', false); + static IsWindows = new RawContextKey('isWindows', os.platform() === 'win32'); + static IsCloud = new RawContextKey('isCloud', false); + static NodeType = new RawContextKey('nodeType', undefined); + static NodeLabel = new RawContextKey('nodeLabel', undefined); + + // Scripting context keys + static CanScriptAsSelect = new RawContextKey('canScriptAsSelect', false); + static CanEditData = new RawContextKey('canEditData', false); + static CanScriptAsCreateOrDelete = new RawContextKey('canScriptAsCreateOeDelete', false); + static CanScriptAsExecute = new RawContextKey('canScriptAsExecute', false); + static CanScriptAsAlter = new RawContextKey('canScriptAsAlter', false); + + private nodeProviderKey: IContextKey; + private isCloudKey: IContextKey; + private nodeTypeKey: IContextKey; + private nodeLabelKey: IContextKey; + private isDatabaseOrServerKey: IContextKey; + + private canScriptAsSelectKey: IContextKey; + private canEditDataKey: IContextKey; + private canScriptAsCreateOrDeleteKey: IContextKey; + private canScriptAsExecuteKey: IContextKey; + private canScriptAsAlterKey: IContextKey; + + constructor( + private nodeContextValue: INodeContextValue, + @IContextKeyService private contextKeyService: IContextKeyService, + @IConnectionManagementService private connectionManagementService: IConnectionManagementService, + @ICapabilitiesService private capabilitiesService: ICapabilitiesService + ) { + super(); + this.bindContextKeys(); + + // Set additional node context keys + if (this.nodeContextValue.node) { + const node = this.nodeContextValue.node; + if (node.payload) { + this.setNodeProvider(); + this.setIsCloud(); + if (node.type) { + this.setIsDatabaseOrServer(); + this.nodeTypeKey.set(node.type); + } else if (node.contextValue && node.providerHandle === mssqlProviderName) { + this.setIsDatabaseOrServer(); + this.setScriptingContextKeys(); + this.nodeTypeKey.set(node.contextValue); + } + } + if (node.label) { + this.nodeLabelKey.set(node.label.label); + } + } + } + + private bindContextKeys(): void { + this.isCloudKey = MssqlNodeContext.IsCloud.bindTo(this.contextKeyService); + this.nodeTypeKey = MssqlNodeContext.NodeType.bindTo(this.contextKeyService); + this.nodeLabelKey = MssqlNodeContext.NodeLabel.bindTo(this.contextKeyService); + this.isDatabaseOrServerKey = MssqlNodeContext.IsDatabaseOrServer.bindTo(this.contextKeyService); + this.canScriptAsSelectKey = MssqlNodeContext.CanScriptAsSelect.bindTo(this.contextKeyService); + this.canEditDataKey = MssqlNodeContext.CanEditData.bindTo(this.contextKeyService); + this.canScriptAsCreateOrDeleteKey = MssqlNodeContext.CanScriptAsCreateOrDelete.bindTo(this.contextKeyService); + this.canScriptAsExecuteKey = MssqlNodeContext.CanScriptAsExecute.bindTo(this.contextKeyService); + this.canScriptAsAlterKey = MssqlNodeContext.CanScriptAsAlter.bindTo(this.contextKeyService); + this.nodeProviderKey = MssqlNodeContext.NodeProvider.bindTo(this.contextKeyService); + } + + /** + * Helper function to get the node provider + */ + private setNodeProvider(): void { + if (this.nodeContextValue.node.payload.providerName) { + this.nodeProviderKey.set(this.nodeContextValue.node.payload.providerName); + } else if (this.nodeContextValue.node.childProvider) { + this.nodeProviderKey.set(this.nodeContextValue.node.childProvider); + } + } + + /** + * Helper function to tell whether a connected node is cloud or not + */ + private setIsCloud(): void { + const profile = new ConnectionProfile(this.capabilitiesService, + this.nodeContextValue.node.payload); + const connection = this.connectionManagementService.findExistingConnection(profile); + if (connection) { + const serverInfo = this.connectionManagementService.getServerInfo(connection.id); + if (serverInfo.isCloud) { + this.isCloudKey.set(true); + } + } + } + + /** + * Helper function to tell whether a connected node is a database or a + * server or not. Added this key because this is easier to write than + * writing an OR statement in ContextKeyExpr + */ + private setIsDatabaseOrServer(): void { + const isDatabaseOrServer = (this.nodeContextValue.node.contextValue === NodeType.Server || + this.nodeContextValue.node.contextValue === NodeType.Database || + this.nodeContextValue.node.type === ExtensionNodeType.Server || + this.nodeContextValue.node.type === ExtensionNodeType.Database); + this.isDatabaseOrServerKey.set(isDatabaseOrServer); + } + + /** + * Helper function to get the correct context from node for showing + * scripting context menu actions + */ + private setScriptingContextKeys(): void { + const nodeType = this.nodeContextValue.node.contextValue; + if (MssqlNodeContext.canCreateOrDelete.has(nodeType)) { + this.canScriptAsCreateOrDeleteKey.set(true); + } + if (MssqlNodeContext.canEditData.has(nodeType)) { + this.canEditDataKey.set(true); + } + if (MssqlNodeContext.canAlter.has(nodeType)) { + this.canScriptAsAlterKey.set(true); + } + if (MssqlNodeContext.canExecute.has(nodeType)) { + this.canScriptAsExecuteKey.set(true); + } + if (MssqlNodeContext.canSelect.has(nodeType)) { + this.canScriptAsSelectKey.set(true); + } + } +} diff --git a/src/sql/workbench/parts/dataExplorer/common/nodeContext.ts b/src/sql/workbench/parts/dataExplorer/common/nodeContext.ts index a444e45f48..6c2ca11378 100644 --- a/src/sql/workbench/parts/dataExplorer/common/nodeContext.ts +++ b/src/sql/workbench/parts/dataExplorer/common/nodeContext.ts @@ -9,6 +9,9 @@ import { ITreeItem } from 'sql/workbench/common/views'; import { Disposable } from 'vs/base/common/lifecycle'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IQueryManagementService } from 'sql/platform/query/common/queryManagement'; +import { MssqlNodeContext } from 'sql/workbench/parts/dataExplorer/common/mssqlNodeContext'; +import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; +import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; export interface INodeContextValue { node: ITreeItem; @@ -30,10 +33,14 @@ export class NodeContextKey extends Disposable implements IContextKey; private readonly _nodeContextKey: IContextKey; + private _nodeContextUtils: MssqlNodeContext; + constructor( - @IContextKeyService contextKeyService: IContextKeyService, + @IContextKeyService private contextKeyService: IContextKeyService, @IOEShimService private oeService: IOEShimService, - @IQueryManagementService queryManagementService: IQueryManagementService + @IQueryManagementService queryManagementService: IQueryManagementService, + @IConnectionManagementService private connectionManagementService: IConnectionManagementService, + @ICapabilitiesService private capabilitiesService: ICapabilitiesService ) { super(); @@ -62,6 +69,8 @@ export class NodeContextKey extends Disposable implements IContextKey { @@ -35,6 +36,7 @@ CommandsRegistry.registerCommand({ } }); +// New Query CommandsRegistry.registerCommand({ id: NEW_QUERY_COMMAND_ID, handler: (accessor, args: TreeViewItemHandleArg) => { @@ -58,6 +60,7 @@ CommandsRegistry.registerCommand({ } }); +// Manage CommandsRegistry.registerCommand({ id: MANAGE_COMMAND_ID, handler: (accessor, args: TreeViewItemHandleArg) => { @@ -79,6 +82,7 @@ CommandsRegistry.registerCommand({ } }); +// Refresh CommandsRegistry.registerCommand({ id: REFRESH_COMMAND_ID, handler: (accessor, args: TreeViewItemHandleArg) => { @@ -94,4 +98,4 @@ CommandsRegistry.registerCommand({ } return Promise.resolve(true); } -}); +}); \ No newline at end of file diff --git a/src/sql/workbench/parts/notebook/notebookActions.ts b/src/sql/workbench/parts/notebook/notebookActions.ts index 42f316056b..6625d449f4 100644 --- a/src/sql/workbench/parts/notebook/notebookActions.ts +++ b/src/sql/workbench/parts/notebook/notebookActions.ts @@ -558,7 +558,6 @@ export class NewNotebookAction extends Action { run(context?: azdata.ConnectedContext): Promise { return this.commandService.executeCommand(NewNotebookAction.INTERNAL_NEW_NOTEBOOK_CMD_ID, context); - } } \ No newline at end of file diff --git a/src/sql/workbench/parts/objectExplorer/browser/objectExplorerActions.ts b/src/sql/workbench/parts/objectExplorer/browser/objectExplorerActions.ts index 4161dac35c..cdb4b1df17 100644 --- a/src/sql/workbench/parts/objectExplorer/browser/objectExplorerActions.ts +++ b/src/sql/workbench/parts/objectExplorer/browser/objectExplorerActions.ts @@ -60,7 +60,6 @@ export class OEAction extends ExecuteCommandAction { public async run(actionContext: any): Promise { this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler); - let profile: IConnectionProfile; if (actionContext instanceof ObjectExplorerActionsContext) { if (actionContext.isConnectionNode) { @@ -240,7 +239,7 @@ export class OEScriptCreateAction extends ScriptCreateAction { @IScriptingService protected _scriptingService: IScriptingService, @IObjectExplorerService private _objectExplorerService: IObjectExplorerService, @IInstantiationService private _instantiationService: IInstantiationService, - @IErrorMessageService protected _errorMessageService: IErrorMessageService + @IErrorMessageService protected _errorMessageService: IErrorMessageService, ) { super(id, label, _queryEditorService, _connectionManagementService, _scriptingService, _errorMessageService); } diff --git a/src/sql/workbench/parts/objectExplorer/common/objectExplorerViewTreeShim.ts b/src/sql/workbench/parts/objectExplorer/common/objectExplorerViewTreeShim.ts index a558375731..7b45c742ea 100644 --- a/src/sql/workbench/parts/objectExplorer/common/objectExplorerViewTreeShim.ts +++ b/src/sql/workbench/parts/objectExplorer/common/objectExplorerViewTreeShim.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Deferred } from 'sql/base/common/promise'; +import * as azdata from 'azdata'; import { TreeNode } from 'sql/workbench/parts/objectExplorer/common/treeNode'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import { ConnectionType, IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; @@ -17,6 +17,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { TreeItemCollapsibleState } from 'vs/workbench/common/views'; import { localize } from 'vs/nls'; +import { NodeType } from 'sql/workbench/parts/objectExplorer/common/nodeType'; export const SERVICE_ID = 'oeShimService'; export const IOEShimService = createDecorator(SERVICE_ID); @@ -27,6 +28,7 @@ export interface IOEShimService { disconnectNode(viewId: string, node: ITreeItem): Promise; providerExists(providerId: string): boolean; isNodeConnected(viewId: string, node: ITreeItem): boolean; + getNodeInfoForTreeItem(treeItem: ITreeItem): azdata.NodeInfo; } export class OEShimService extends Disposable implements IOEShimService { @@ -34,6 +36,7 @@ export class OEShimService extends Disposable implements IOEShimService { private sessionMap = new Map(); private nodeHandleMap = new Map(); + private nodeInfoMap = new Map(); constructor( @IObjectExplorerService private oe: IObjectExplorerService, @@ -140,8 +143,8 @@ export class OEShimService extends Disposable implements IOEShimService { private treeNodeToITreeItem(viewId: string, node: TreeNode, parentNode: ITreeItem): ITreeItem { let handle = generateUuid(); - let nodePath = node.nodePath; let icon: string = ''; + let nodePath = node.nodePath; if (node.iconType) { icon = (typeof node.iconType === 'string') ? node.iconType : node.iconType.id; } else { @@ -154,6 +157,31 @@ export class OEShimService extends Disposable implements IOEShimService { } } icon = icon.toLowerCase(); + // Change the database if the node has a different database + // than its parent + let databaseChanged = false; + let updatedPayload: azdata.IConnectionProfile | any = {}; + if (node.nodeTypeId === NodeType.Database) { + const database = node.getDatabaseName(); + if (database) { + databaseChanged = true; + updatedPayload = Object.assign(updatedPayload, parentNode.payload); + updatedPayload.databaseName = node.getDatabaseName(); + } + } + const nodeInfo: azdata.NodeInfo = { + nodePath: nodePath, + nodeType: node.nodeTypeId, + nodeSubType: node.nodeSubType, + nodeStatus: node.nodeStatus, + label: node.label, + isLeaf: node.isAlwaysLeaf, + metadata: node.metadata, + errorMessage: node.errorStateMessage, + iconType: icon, + childProvider: node.childProvider || parentNode.childProvider, + payload: node.payload || (databaseChanged ? updatedPayload : parentNode.payload) + }; let newTreeItem: ITreeItem = { parentHandle: node.parent.id, handle, @@ -163,11 +191,12 @@ export class OEShimService extends Disposable implements IOEShimService { }, childProvider: node.childProvider || parentNode.childProvider, providerHandle: parentNode.childProvider, - payload: node.payload || parentNode.payload, + payload: node.payload || (databaseChanged ? updatedPayload : parentNode.payload), contextValue: node.nodeTypeId, sqlIcon: icon }; this.nodeHandleMap.set(generateNodeMapKey(viewId, newTreeItem), nodePath); + this.nodeInfoMap.set(newTreeItem, nodeInfo); return newTreeItem; } @@ -178,6 +207,13 @@ export class OEShimService extends Disposable implements IOEShimService { public isNodeConnected(viewId: string, node: ITreeItem): boolean { return this.sessionMap.has(generateSessionMapKey(viewId, node)); } + + public getNodeInfoForTreeItem(treeItem: ITreeItem): azdata.NodeInfo { + if (this.nodeInfoMap.has(treeItem)) { + return this.nodeInfoMap.get(treeItem); + } + return undefined; + } } function generateSessionMapKey(viewId: string, node: ITreeItem): number { diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index b11f50f8eb..f53b92757e 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -483,7 +483,8 @@ export class ExtHostTreeView extends Disposable { collapsibleState: isUndefinedOrNull(extensionTreeItem.collapsibleState) ? TreeItemCollapsibleState.None : extensionTreeItem.collapsibleState, // {{SQL CARBON EDIT}} payload: extensionTreeItem.payload, - childProvider: extensionTreeItem.childProvider + childProvider: extensionTreeItem.childProvider, + type: extensionTreeItem.type }; return item;