diff --git a/src/sql/azdata.d.ts b/src/sql/azdata.d.ts index b1e850b445..8f2034cce5 100644 --- a/src/sql/azdata.d.ts +++ b/src/sql/azdata.d.ts @@ -297,10 +297,10 @@ declare module 'azdata' { nodePath: string; nodeType: string; nodeSubType: string; - nodeStatus: string; + nodeStatus?: string; label: string; isLeaf: boolean; - metadata: ObjectMetadata; + metadata?: ObjectMetadata; errorMessage: string; /** * Optional iconType for the object in the tree. Currently this only supports @@ -320,7 +320,7 @@ declare module 'azdata' { } export interface IConnectionProfile extends ConnectionInfo { - connectionName: string; + connectionName?: string; serverName: string; databaseName: string; userName: string; @@ -427,11 +427,11 @@ declare module 'azdata' { /** * The major version of the instance. */ - serverMajorVersion: number; + serverMajorVersion?: number; /** * The minor version of the instance. */ - serverMinorVersion: number; + serverMinorVersion?: number; /** * The build of the instance. */ @@ -1231,7 +1231,7 @@ declare module 'azdata' { sessionId: string; nodePath: string; nodes: NodeInfo[]; - errorMessage: string; + errorMessage?: string; } export interface ExpandNodeInfo { @@ -1249,7 +1249,7 @@ declare module 'azdata' { } export interface ObjectExplorerCloseSessionInfo { - sessionId: string; + sessionId?: string; } export interface ObjectExplorerCloseSessionResponse { @@ -4130,7 +4130,7 @@ declare module 'azdata' { * Note that the connection is not guaranteed to be in a connected * state on click. */ - connectionProfile: IConnectionProfile; + connectionProfile?: IConnectionProfile; } /** @@ -4149,7 +4149,7 @@ declare module 'azdata' { * Node info for objects below a specific connection. This * may be null for a Connection-level object */ - nodeInfo: NodeInfo; + nodeInfo?: NodeInfo; } /** diff --git a/src/sql/platform/connection/common/connectionManagement.ts b/src/sql/platform/connection/common/connectionManagement.ts index dfae757d86..24d254cfc7 100644 --- a/src/sql/platform/connection/common/connectionManagement.ts +++ b/src/sql/platform/connection/common/connectionManagement.ts @@ -51,7 +51,7 @@ export interface IConnectionCompletionOptions { /** * Parameters to be used if connecting from an editor */ - params: INewConnectionParams; + params?: INewConnectionParams; /** * Open the connection dialog if connection fails @@ -107,12 +107,12 @@ export interface IConnectionManagementService { /** * Opens the connection dialog to create new connection */ - showConnectionDialog(params?: INewConnectionParams, options?: IConnectionCompletionOptions, model?: IConnectionProfile, connectionResult?: IConnectionResult): Promise; + showConnectionDialog(params?: INewConnectionParams, options?: IConnectionCompletionOptions, model?: Partial, connectionResult?: IConnectionResult): Promise; /** * Load the password and opens a new connection */ - connect(connection: IConnectionProfile, uri: string, options?: IConnectionCompletionOptions, callbacks?: IConnectionCallbacks): Promise; + connect(connection: IConnectionProfile, uri?: string, options?: IConnectionCompletionOptions, callbacks?: IConnectionCallbacks): Promise; /** * Opens a new connection and save the profile in settings @@ -183,7 +183,7 @@ export interface IConnectionManagementService { isRecent(connectionProfile: ConnectionProfile): boolean; - isConnected(fileUri: string, connectionProfile?: ConnectionProfile): boolean; + isConnected(fileUri?: string, connectionProfile?: ConnectionProfile): boolean; disconnectEditor(owner: IConnectableInput, force?: boolean): Promise; diff --git a/src/sql/platform/connection/common/connectionProfile.ts b/src/sql/platform/connection/common/connectionProfile.ts index 8f41947ecc..55664c29a4 100644 --- a/src/sql/platform/connection/common/connectionProfile.ts +++ b/src/sql/platform/connection/common/connectionProfile.ts @@ -33,7 +33,7 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa public constructor( capabilitiesService: ICapabilitiesService, - model: string | azdata.IConnectionProfile) { + model: string | azdata.IConnectionProfile | undefined) { super(capabilitiesService, model); if (model && !isString(model)) { this.groupId = model.groupId; diff --git a/src/sql/platform/connection/common/connectionProfileGroup.ts b/src/sql/platform/connection/common/connectionProfileGroup.ts index d7b0c7cfc3..7948aefc07 100644 --- a/src/sql/platform/connection/common/connectionProfileGroup.ts +++ b/src/sql/platform/connection/common/connectionProfileGroup.ts @@ -18,7 +18,7 @@ export interface INewConnectionProfileGroup { } export interface IConnectionProfileGroup extends INewConnectionProfileGroup { - id: string; + id?: string; } export class ConnectionProfileGroup extends Disposable implements IConnectionProfileGroup { @@ -30,8 +30,8 @@ export class ConnectionProfileGroup extends Disposable implements IConnectionPro public readonly isRoot: boolean = false; public constructor( public name: string, - public parent: ConnectionProfileGroup | undefined, - public id: string, + public parent?: ConnectionProfileGroup, + public id?: string, public color?: string, public description?: string ) { diff --git a/src/sql/platform/connection/common/connectionStore.ts b/src/sql/platform/connection/common/connectionStore.ts index 9e4645a567..b1de5f9106 100644 --- a/src/sql/platform/connection/common/connectionStore.ts +++ b/src/sql/platform/connection/common/connectionStore.ts @@ -289,7 +289,7 @@ export class ConnectionStore { if (children) { children.map(group => { let connectionGroup = new ConnectionProfileGroup(group.name, parent, group.id, group.color, group.description); - this.addGroupFullNameToMap(group.id, connectionGroup.fullName); + this.addGroupFullNameToMap(group.id!, connectionGroup.fullName); if (connections) { let connectionsForGroup = connections.filter(conn => conn.groupId === connectionGroup.id); let conns: ConnectionProfile[] = []; diff --git a/src/sql/platform/connection/common/providerConnectionInfo.ts b/src/sql/platform/connection/common/providerConnectionInfo.ts index 163e8f7bc6..535ad656b1 100644 --- a/src/sql/platform/connection/common/providerConnectionInfo.ts +++ b/src/sql/platform/connection/common/providerConnectionInfo.ts @@ -27,7 +27,7 @@ export class ProviderConnectionInfo extends Disposable implements azdata.Connect public constructor( protected capabilitiesService: ICapabilitiesService, - model: string | azdata.IConnectionProfile + model: string | azdata.IConnectionProfile | undefined ) { super(); // we can't really do a whole lot if we don't have a provider @@ -61,7 +61,7 @@ export class ProviderConnectionInfo extends Disposable implements azdata.Connect */ private updateSpecialValueType(typeName: SettableProperty, model: azdata.IConnectionProfile): void { if (!this[typeName]) { - this[typeName] = model[typeName]; + this[typeName] = model[typeName]!; } } diff --git a/src/sql/platform/connection/test/common/connectionProfile.test.ts b/src/sql/platform/connection/test/common/connectionProfile.test.ts index 6f2b621e7e..ec534858eb 100644 --- a/src/sql/platform/connection/test/common/connectionProfile.test.ts +++ b/src/sql/platform/connection/test/common/connectionProfile.test.ts @@ -136,7 +136,7 @@ suite('SQL ConnectionProfileInfo tests', () => { test('set properties should set the values correctly', () => { let conn = new ConnectionProfile(capabilitiesService, undefined!); assert.equal(conn.serverName, undefined); - conn.connectionName = connectionProfile.connectionName; + conn.connectionName = connectionProfile.connectionName!; conn.serverName = connectionProfile.serverName; conn.databaseName = connectionProfile.databaseName; conn.authenticationType = connectionProfile.authenticationType; diff --git a/src/sql/platform/connection/test/common/providerConnectionInfo.test.ts b/src/sql/platform/connection/test/common/providerConnectionInfo.test.ts index e0b385e0ea..dff79df6ce 100644 --- a/src/sql/platform/connection/test/common/providerConnectionInfo.test.ts +++ b/src/sql/platform/connection/test/common/providerConnectionInfo.test.ts @@ -139,7 +139,7 @@ suite('SQL ProviderConnectionInfo tests', () => { test('set properties should set the values correctly', () => { let conn = new ProviderConnectionInfo(capabilitiesService, mssqlProviderName); assert.equal(conn.serverName, undefined); - conn.connectionName = connectionProfile.connectionName; + conn.connectionName = connectionProfile.connectionName!; conn.serverName = connectionProfile.serverName; conn.databaseName = connectionProfile.databaseName; conn.authenticationType = connectionProfile.authenticationType; diff --git a/src/sql/workbench/api/browser/mainThreadObjectExplorer.ts b/src/sql/workbench/api/browser/mainThreadObjectExplorer.ts index 3e53d9206c..7d0ef85e8f 100644 --- a/src/sql/workbench/api/browser/mainThreadObjectExplorer.ts +++ b/src/sql/workbench/api/browser/mainThreadObjectExplorer.ts @@ -49,7 +49,7 @@ export class MainThreadObjectExplorer extends Disposable implements MainThreadOb return this._objectExplorerService.getTreeNode(connectionId, nodePath).then(treeNode => treeNode.getChildren().then(children => children.map(node => node.toNodeInfo()))); } - public $isExpanded(connectionId: string, nodePath: string): Thenable { + public $isExpanded(connectionId: string, nodePath: string): Thenable { return this._objectExplorerService.getTreeNode(connectionId, nodePath).then(treeNode => treeNode.isExpanded()); } diff --git a/src/sql/workbench/contrib/azure/browser/azure.contribution.ts b/src/sql/workbench/contrib/azure/browser/azure.contribution.ts index 09d6ed11b3..33b74fa5a6 100644 --- a/src/sql/workbench/contrib/azure/browser/azure.contribution.ts +++ b/src/sql/workbench/contrib/azure/browser/azure.contribution.ts @@ -23,9 +23,12 @@ MenuRegistry.appendMenuItem(MenuId.DataExplorerContext, { CommandsRegistry.registerCommand({ id: openInAzureDECommandId, - handler: (accessor, args: TreeViewItemHandleArg) => { + handler: async (accessor, args: TreeViewItemHandleArg) => { const commandService = accessor.get(ICommandService); - return commandService.executeCommand('azure.resource.openInAzurePortal', args.$treeItem.payload); + const payload = args.$treeItem?.payload; + if (payload) { + commandService.executeCommand('azure.resource.openInAzurePortal', payload); + } } }); diff --git a/src/sql/workbench/contrib/objectExplorer/browser/serverTreeView.ts b/src/sql/workbench/contrib/objectExplorer/browser/serverTreeView.ts index 23e6496ca8..4b1af93209 100644 --- a/src/sql/workbench/contrib/objectExplorer/browser/serverTreeView.ts +++ b/src/sql/workbench/contrib/objectExplorer/browser/serverTreeView.ts @@ -570,7 +570,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView { /** * Set whether the given element is expanded or collapsed */ - public async setExpandedState(element: ServerTreeElement, expandedState: TreeItemCollapsibleState): Promise { + public async setExpandedState(element: ServerTreeElement, expandedState?: TreeItemCollapsibleState): Promise { if (expandedState === TreeItemCollapsibleState.Collapsed) { return this._tree.collapse(element); } else if (expandedState === TreeItemCollapsibleState.Expanded) { @@ -588,7 +588,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView { /** * Select the given element in the tree and clear any other selections */ - public async setSelected(element: ServerTreeElement, selected: boolean, clearOtherSelections: boolean): Promise { + public async setSelected(element: ServerTreeElement, selected?: boolean, clearOtherSelections?: boolean): Promise { if (clearOtherSelections || (selected && clearOtherSelections !== false)) { if (this._tree instanceof AsyncServerTree) { this._tree.setSelection([]); diff --git a/src/sql/workbench/services/connection/browser/connectionManagementService.ts b/src/sql/workbench/services/connection/browser/connectionManagementService.ts index ffcbc465b0..534f145cea 100644 --- a/src/sql/workbench/services/connection/browser/connectionManagementService.ts +++ b/src/sql/workbench/services/connection/browser/connectionManagementService.ts @@ -213,7 +213,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti * @param params Include the uri, type of connection * @param model the existing connection profile to create a new one from */ - public showConnectionDialog(params?: INewConnectionParams, options?: IConnectionCompletionOptions, model?: interfaces.IConnectionProfile, connectionResult?: IConnectionResult): Promise { + public showConnectionDialog(params?: INewConnectionParams, options?: IConnectionCompletionOptions, model?: Partial, connectionResult?: IConnectionResult): Promise { if (!params) { params = { connectionType: ConnectionType.default }; } diff --git a/src/sql/workbench/services/connection/common/connectionDialogService.ts b/src/sql/workbench/services/connection/common/connectionDialogService.ts index 04253123cf..373002ef75 100644 --- a/src/sql/workbench/services/connection/common/connectionDialogService.ts +++ b/src/sql/workbench/services/connection/common/connectionDialogService.ts @@ -13,7 +13,7 @@ export interface IConnectionDialogService { /** * Opens the connection dialog and returns the promise for successfully opening the dialog */ - showDialog(connectionManagementService: IConnectionManagementService, params: INewConnectionParams, model: IConnectionProfile, connectionResult?: IConnectionResult, connectionOptions?: IConnectionCompletionOptions): Promise; + showDialog(connectionManagementService: IConnectionManagementService, params: INewConnectionParams, model: Partial, connectionResult?: IConnectionResult, connectionOptions?: IConnectionCompletionOptions): Promise; /** * Opens the connection dialog and returns the promise when connection is made diff --git a/src/sql/workbench/services/connection/common/serverInfoContextKey.ts b/src/sql/workbench/services/connection/common/serverInfoContextKey.ts index 6c0b28eacc..3100c7b40c 100644 --- a/src/sql/workbench/services/connection/common/serverInfoContextKey.ts +++ b/src/sql/workbench/services/connection/common/serverInfoContextKey.ts @@ -33,8 +33,10 @@ export class ServerInfoContextKey implements IContextKey { set(value: ServerInfo) { this._serverInfo.set(value); - let majorVersion = value && value.serverMajorVersion; - this._serverMajorVersion.set(majorVersion && `${majorVersion}`); + let majorVersion = value.serverMajorVersion; + if (majorVersion) { + this._serverMajorVersion.set(`${majorVersion}`); + } this._isCloud.set(value && value.isCloud); this._isBigDataCluster.set(value && value.options && value.options['isBigDataCluster']); let engineEditionId = value && value.engineEditionId; @@ -48,7 +50,7 @@ export class ServerInfoContextKey implements IContextKey { this._engineEdition.reset(); } - public get(): ServerInfo { + public get(): ServerInfo | undefined { return this._serverInfo.get(); } } diff --git a/src/sql/workbench/services/objectExplorer/browser/connectionTreeAction.ts b/src/sql/workbench/services/objectExplorer/browser/connectionTreeAction.ts index 3624cf97ba..2571ec4a46 100644 --- a/src/sql/workbench/services/objectExplorer/browser/connectionTreeAction.ts +++ b/src/sql/workbench/services/objectExplorer/browser/connectionTreeAction.ts @@ -43,7 +43,7 @@ export class RefreshAction extends Action { super(id, label); } public async run(): Promise { - let treeNode: TreeNode; + let treeNode: TreeNode | undefined = undefined; if (this.element instanceof ConnectionProfile) { let connection: ConnectionProfile = this.element; if (this._connectionManagementService.isConnected(undefined, connection)) { @@ -60,7 +60,10 @@ export class RefreshAction extends Action { if (treeNode) { try { try { - await this._objectExplorerService.refreshTreeNode(treeNode.getSession(), treeNode); + const session = treeNode.getSession(); + if (session) { + await this._objectExplorerService.refreshTreeNode(session, treeNode); + } } catch (error) { this.showError(error); return true; @@ -160,7 +163,8 @@ export class AddServerAction extends Action { } public async run(element: ConnectionProfileGroup): Promise { - let connection: IConnectionProfile = element === undefined ? undefined : { + // Not sure how to fix this.... + let connection: Partial | undefined = element === undefined ? undefined : { connectionName: undefined, serverName: undefined, databaseName: undefined, @@ -175,8 +179,8 @@ export class AddServerAction extends Action { providerName: '', options: {}, saveProfile: true, - id: element.id - }; + id: element.id! + } as Partial; await this._connectionManagementService.showConnectionDialog(undefined, undefined, connection); return true; } @@ -236,7 +240,7 @@ export class ActiveConnectionsFilterAction extends Action { private static enabledClass = 'active-connections-action'; private static disabledClass = 'icon server-page'; private static showAllConnectionsLabel = localize('showAllConnections', "Show All Connections"); - private _isSet: boolean; + private _isSet: boolean = false; public static readonly ACTIVE = 'active'; public get isSet(): boolean { return this._isSet; @@ -342,7 +346,7 @@ export class DeleteConnectionAction extends Action { } if (element instanceof ConnectionProfile) { - let parent: ConnectionProfileGroup = element.parent; + let parent: ConnectionProfileGroup | undefined = element.parent; if (parent && parent.id === UNSAVED_GROUP_ID) { this.enabled = false; } diff --git a/src/sql/workbench/services/objectExplorer/browser/mssqlNodeContext.ts b/src/sql/workbench/services/objectExplorer/browser/mssqlNodeContext.ts index 639817250d..a807be6dc9 100644 --- a/src/sql/workbench/services/objectExplorer/browser/mssqlNodeContext.ts +++ b/src/sql/workbench/services/objectExplorer/browser/mssqlNodeContext.ts @@ -48,19 +48,19 @@ export class MssqlNodeContext extends Disposable { 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 engineEditionKey: IContextKey; - private canOpenInAzurePortal: IContextKey; + private nodeProviderKey!: IContextKey; + private isCloudKey!: IContextKey; + private nodeTypeKey!: IContextKey; + private nodeLabelKey!: IContextKey; + private isDatabaseOrServerKey!: IContextKey; + private engineEditionKey!: IContextKey; + private canOpenInAzurePortal!: IContextKey; - private canScriptAsSelectKey: IContextKey; - private canEditDataKey: IContextKey; - private canScriptAsCreateOrDeleteKey: IContextKey; - private canScriptAsExecuteKey: IContextKey; - private canScriptAsAlterKey: IContextKey; + private canScriptAsSelectKey!: IContextKey; + private canEditDataKey!: IContextKey; + private canScriptAsCreateOrDeleteKey!: IContextKey; + private canScriptAsExecuteKey!: IContextKey; + private canScriptAsAlterKey!: IContextKey; constructor( private nodeContextValue: INodeContextValue, @@ -113,9 +113,9 @@ export class MssqlNodeContext extends Disposable { * Helper function to get the node provider */ private setNodeProvider(): void { - if (this.nodeContextValue.node.payload.providerName) { + if (this?.nodeContextValue?.node?.payload?.providerName) { this.nodeProviderKey.set(this.nodeContextValue.node.payload.providerName); - } else if (this.nodeContextValue.node.childProvider) { + } else if (this.nodeContextValue?.node?.childProvider) { this.nodeProviderKey.set(this.nodeContextValue.node.childProvider); } } @@ -124,7 +124,7 @@ export class MssqlNodeContext extends Disposable { * Helper function to tell whether a connected node is cloud or not */ private setIsCloud(): void { - let serverInfo: azdata.ServerInfo = this.getServerInfo(); + let serverInfo = this.getServerInfo(); if (serverInfo && serverInfo.isCloud) { this.isCloudKey.set(true); } @@ -145,7 +145,7 @@ export class MssqlNodeContext extends Disposable { */ private setEngineEdition(): void { - let serverInfo: azdata.ServerInfo = this.getServerInfo(); + let serverInfo = this.getServerInfo(); if (serverInfo && serverInfo.engineEditionId) { this.engineEditionKey.set(serverInfo.engineEditionId); } @@ -183,6 +183,9 @@ export class MssqlNodeContext extends Disposable { */ private setScriptingContextKeys(): void { const nodeType = this.nodeContextValue.node.contextValue; + if (!nodeType) { + return; + } if (MssqlNodeContext.canCreateOrDelete.has(nodeType)) { this.canScriptAsCreateOrDeleteKey.set(true); } diff --git a/src/sql/workbench/services/objectExplorer/browser/objectExplorerActions.ts b/src/sql/workbench/services/objectExplorer/browser/objectExplorerActions.ts index 2443b690ec..58d4d3dd34 100644 --- a/src/sql/workbench/services/objectExplorer/browser/objectExplorerActions.ts +++ b/src/sql/workbench/services/objectExplorer/browser/objectExplorerActions.ts @@ -17,21 +17,20 @@ import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilit import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; export class ObjectExplorerActionsContext implements azdata.ObjectExplorerContext { - public connectionProfile: azdata.IConnectionProfile; - public nodeInfo: azdata.NodeInfo; + public connectionProfile?: azdata.IConnectionProfile; + public nodeInfo?: azdata.NodeInfo; public isConnectionNode: boolean = false; } -export async function getTreeNode(context: ObjectExplorerActionsContext, objectExplorerService: IObjectExplorerService): Promise { +export async function getTreeNode(context: ObjectExplorerActionsContext, objectExplorerService: IObjectExplorerService): Promise { if (context.isConnectionNode) { return Promise.resolve(undefined); } - return await objectExplorerService.getTreeNode(context.connectionProfile.id, context.nodeInfo.nodePath); + return await objectExplorerService.getTreeNode(context?.connectionProfile?.id, context?.nodeInfo?.nodePath); } export class OEAction extends ExecuteCommandAction { - private _treeSelectionHandler: TreeSelectionHandler; constructor( id: string, label: string, @@ -44,23 +43,27 @@ export class OEAction extends ExecuteCommandAction { } public async run(actionContext: any): Promise { - this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler); + const treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler); - let profile: IConnectionProfile; + let profile: IConnectionProfile | undefined = undefined; if (actionContext instanceof ObjectExplorerActionsContext) { if (actionContext.isConnectionNode) { profile = new ConnectionProfile(this._capabilitiesService, actionContext.connectionProfile); } else { // Get the "correct" version from the tree let treeNode = await getTreeNode(actionContext, this._objectExplorerService); - profile = TreeUpdateUtils.getConnectionProfile(treeNode); + if (treeNode) { + profile = TreeUpdateUtils.getConnectionProfile(treeNode); + } } } - this._treeSelectionHandler.onTreeActionStateChange(true); - - return super.run(profile).then(() => { - this._treeSelectionHandler.onTreeActionStateChange(false); - return true; - }); + treeSelectionHandler.onTreeActionStateChange(true); + if (profile) { + return super.run(profile).then(() => { + treeSelectionHandler.onTreeActionStateChange(false); + return true; + }); + } + return false; } } diff --git a/src/sql/workbench/services/objectExplorer/browser/objectExplorerService.ts b/src/sql/workbench/services/objectExplorer/browser/objectExplorerService.ts index 557c4c8161..7df2f5e8d7 100644 --- a/src/sql/workbench/services/objectExplorer/browser/objectExplorerService.ts +++ b/src/sql/workbench/services/objectExplorer/browser/objectExplorerService.ts @@ -42,10 +42,10 @@ export interface IServerTreeView { isFocused(): boolean; refreshElement(node: TreeNode): Promise; readonly treeActionProvider: ServerTreeActionProvider; - isExpanded(node: ServerTreeElement): boolean; + isExpanded(node?: ServerTreeElement): boolean; reveal(node: ServerTreeElement): Promise; - setExpandedState(node: ServerTreeElement, state: TreeItemCollapsibleState): Promise; - setSelected(node: ServerTreeElement, selected: boolean, clearOtherSelections: boolean): Promise; + setExpandedState(node: ServerTreeElement, state?: TreeItemCollapsibleState): Promise; + setSelected(node: ServerTreeElement, selected?: boolean, clearOtherSelections?: boolean): Promise; refreshTree(): Promise; readonly activeConnectionsFilterAction: IAction; renderBody(container: HTMLElement): Promise; @@ -57,11 +57,11 @@ export interface IObjectExplorerService { createNewSession(providerId: string, connection: ConnectionProfile): Promise; - closeSession(providerId: string, session: azdata.ObjectExplorerSession): Promise; + closeSession(providerId: string, session: azdata.ObjectExplorerSession): Promise; expandNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise; - refreshNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise; + refreshNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise; resolveTreeNodeChildren(session: azdata.ObjectExplorerSession, parentTree: TreeNode): Promise; @@ -90,21 +90,21 @@ export interface IObjectExplorerService { registerServerTreeView(view: IServerTreeView): void; - getSelectedProfileAndDatabase(): { profile: ConnectionProfile, databaseName: string }; + getSelectedProfileAndDatabase(): { profile?: ConnectionProfile, databaseName?: string } | undefined; isFocused(): boolean; onSelectionOrFocusChange: Event; - getServerTreeView(): IServerTreeView; + getServerTreeView(): IServerTreeView | undefined; findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames?: string[]): Promise; getActiveConnectionNodes(): TreeNode[]; - getTreeNode(connectionId: string, nodePath: string): Promise; + getTreeNode(connectionId?: string, nodePath?: string): Promise; - refreshNodeInView(connectionId: string, nodePath: string): Promise; + refreshNodeInView(connectionId: string, nodePath: string): Promise; /** * For Testing purpose only. Get the context menu actions for an object explorer node. @@ -113,7 +113,7 @@ export interface IObjectExplorerService { getSessionConnectionProfile(sessionId: string): azdata.IConnectionProfile; - getSession(sessionId: string): azdata.ObjectExplorerSession; + getSession(sessionId: string): azdata.ObjectExplorerSession | undefined; providerRegistered(providerId: string): boolean; } @@ -130,7 +130,7 @@ interface NodeStatus { export interface ObjectExplorerNodeEventArgs { connection: IConnectionProfile; - errorMessage: string; + errorMessage?: string; } export interface NodeInfoWithConnection { @@ -161,7 +161,7 @@ export class ObjectExplorerService implements IObjectExplorerService { private _onUpdateObjectExplorerNodes: Emitter; - private _serverTreeView: IServerTreeView; + private _serverTreeView?: IServerTreeView; private _onSelectionOrFocusChange: Emitter; @@ -179,7 +179,7 @@ export class ObjectExplorerService implements IObjectExplorerService { this._onSelectionOrFocusChange = new Emitter(); } - public getSession(sessionId: string): azdata.ObjectExplorerSession { + public getSession(sessionId: string): azdata.ObjectExplorerSession | undefined { let session = this._sessions[sessionId]; if (!session) { return undefined; @@ -210,12 +210,16 @@ export class ObjectExplorerService implements IObjectExplorerService { } public async deleteObjectExplorerNode(connection: IConnectionProfile): Promise { - let connectionUri = connection.id; + let connectionUri = connection.id!; let nodeTree = this._activeObjectExplorerNodes[connectionUri]; if (nodeTree) { - await this.closeSession(connection.providerName, nodeTree.getSession()); + const session = nodeTree?.getSession(); + if (!session) { + return; + } + await this.closeSession(connection.providerName, session); delete this._activeObjectExplorerNodes[connectionUri]; - delete this._sessions[nodeTree.getSession().sessionId]; + delete this._sessions[session.sessionId]; } } @@ -255,14 +259,14 @@ export class ObjectExplorerService implements IObjectExplorerService { } private async handleSessionCreated(session: azdata.ObjectExplorerSession): Promise { - let connection: ConnectionProfile = undefined; - let errorMessage: string = undefined; + let connection: ConnectionProfile | undefined = undefined; + let errorMessage: string | undefined = undefined; if (this._sessions[session.sessionId]) { connection = this._sessions[session.sessionId].connection; try { if (session.success && session.rootNode) { - let server = this.toTreeNode(session.rootNode, null); + let server = this.toTreeNode(session.rootNode, undefined); server.connection = connection; server.session = session; this._activeObjectExplorerNodes[connection.id] = server; @@ -296,8 +300,8 @@ export class ObjectExplorerService implements IObjectExplorerService { let connection: ConnectionProfile = this._sessions[session.sessionId].connection; if (connection && this._connectionManagementService.isProfileConnected(connection)) { let uri: string = Utils.generateUri(connection); - if (this._serverTreeView.isObjectExplorerConnectionUri(uri)) { - this._serverTreeView.deleteObjectExplorerNodeAndRefreshTree(connection).then(() => { + if (this._serverTreeView?.isObjectExplorerConnectionUri(uri)) { + this._serverTreeView?.deleteObjectExplorerNodeAndRefreshTree(connection).then(() => { this.sendUpdateNodeEvent(connection, session.errorMessage); connection.isDisconnecting = true; this._connectionManagementService.disconnect(connection).then(() => { @@ -311,7 +315,7 @@ export class ObjectExplorerService implements IObjectExplorerService { } } - private sendUpdateNodeEvent(connection: ConnectionProfile, errorMessage: string = undefined) { + private sendUpdateNodeEvent(connection: ConnectionProfile, errorMessage?: string) { let eventArgs: ObjectExplorerNodeEventArgs = { connection: connection, errorMessage: errorMessage @@ -333,7 +337,7 @@ export class ObjectExplorerService implements IObjectExplorerService { } public getObjectExplorerNode(connection: IConnectionProfile): TreeNode | undefined { - return this._activeObjectExplorerNodes[connection.id]; + return this._activeObjectExplorerNodes[connection.id!]; } public async createNewSession(providerId: string, connection: ConnectionProfile): Promise { @@ -394,7 +398,7 @@ export class ObjectExplorerService implements IObjectExplorerService { let nodeProviders = this._nodeProviders[providerId]; if (nodeProviders) { - nodeProviders = nodeProviders.sort((a, b) => a.group.toLowerCase().localeCompare(b.group.toLowerCase())); + nodeProviders = nodeProviders.sort((a, b) => a.group!.toLowerCase().localeCompare(b.group!.toLowerCase())); allProviders.push(...nodeProviders); } @@ -443,8 +447,8 @@ export class ObjectExplorerService implements IObjectExplorerService { }); } - private mergeResults(allProviders: azdata.ObjectExplorerProviderBase[], resultMap: Map, nodePath: string): azdata.ObjectExplorerExpandInfo { - let finalResult: azdata.ObjectExplorerExpandInfo; + private mergeResults(allProviders: azdata.ObjectExplorerProviderBase[], resultMap: Map, nodePath: string): azdata.ObjectExplorerExpandInfo | undefined { + let finalResult: azdata.ObjectExplorerExpandInfo | undefined = undefined; let allNodes: azdata.NodeInfo[] = []; let errorNode: azdata.NodeInfo = { nodePath: nodePath, @@ -454,7 +458,7 @@ export class ObjectExplorerService implements IObjectExplorerService { isLeaf: true, nodeSubType: '', nodeStatus: '', - metadata: null + metadata: undefined }; let errorMessages: string[] = []; for (let provider of allProviders) { @@ -487,7 +491,7 @@ export class ObjectExplorerService implements IObjectExplorerService { return finalResult; } - public refreshNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise { + public refreshNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise { let provider = this._providers[providerId]; if (provider) { this._telemetryService.createActionEvent(TelemetryKeys.TelemetryView.Shell, TelemetryKeys.ObjectExplorerExpand) @@ -500,7 +504,7 @@ export class ObjectExplorerService implements IObjectExplorerService { return Promise.resolve(undefined); } - public closeSession(providerId: string, session: azdata.ObjectExplorerSession): Promise { + public closeSession(providerId: string, session: azdata.ObjectExplorerSession): Promise { // Complete any requests that are still open for the session let sessionStatus = this._sessions[session.sessionId]; if (sessionStatus && sessionStatus.nodes) { @@ -558,7 +562,7 @@ export class ObjectExplorerService implements IObjectExplorerService { return this.expandOrRefreshTreeNode(session, parentTree, true); } - private callExpandOrRefreshFromService(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string, refresh: boolean = false): Promise { + private callExpandOrRefreshFromService(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string, refresh: boolean = false): Promise { if (refresh) { return this.refreshNode(providerId, session, nodePath); } else { @@ -570,7 +574,11 @@ export class ObjectExplorerService implements IObjectExplorerService { session: azdata.ObjectExplorerSession, parentTree: TreeNode, refresh: boolean = false): Promise { - const expandResult = await this.callExpandOrRefreshFromService(parentTree.getConnectionProfile().providerName, session, parentTree.nodePath, refresh); + const providerName = parentTree.getConnectionProfile()?.providerName; + if (!providerName) { + throw new Error('Failed to expand node - no provider name'); + } + const expandResult = await this.callExpandOrRefreshFromService(providerName, session, parentTree.nodePath, refresh); if (expandResult && expandResult.nodes) { const children = expandResult.nodes.map(node => { return this.toTreeNode(node, parentTree); @@ -582,7 +590,7 @@ export class ObjectExplorerService implements IObjectExplorerService { } } - private toTreeNode(nodeInfo: azdata.NodeInfo, parent: TreeNode): TreeNode { + private toTreeNode(nodeInfo: azdata.NodeInfo, parent?: TreeNode): TreeNode { // Show the status for database nodes with a status field let isLeaf: boolean = nodeInfo.isLeaf; if (nodeInfo.nodeType === NodeType.Database) { @@ -599,10 +607,10 @@ export class ObjectExplorerService implements IObjectExplorerService { let node = new TreeNode(nodeInfo.nodeType, nodeInfo.label, isLeaf, nodeInfo.nodePath, nodeInfo.nodeSubType, nodeInfo.nodeStatus, parent, nodeInfo.metadata, nodeInfo.iconType, { - getChildren: treeNode => this.getChildren(treeNode), + getChildren: (treeNode?: TreeNode) => this.getChildren(treeNode), isExpanded: treeNode => this.isExpanded(treeNode), setNodeExpandedState: async (treeNode, expandedState) => await this.setNodeExpandedState(treeNode, expandedState), - setNodeSelected: (treeNode, selected, clearOtherSelections: boolean = undefined) => this.setNodeSelected(treeNode, selected, clearOtherSelections) + setNodeSelected: (treeNode, selected, clearOtherSelections?: boolean) => this.setNodeSelected(treeNode, selected, clearOtherSelections) }); node.childProvider = nodeInfo.childProvider; node.payload = nodeInfo.payload; @@ -621,7 +629,7 @@ export class ObjectExplorerService implements IObjectExplorerService { * Returns the connection profile corresponding to the current Object Explorer selection, * or undefined if there are multiple selections or no such connection */ - public getSelectedProfileAndDatabase(): { profile: ConnectionProfile, databaseName: string } { + public getSelectedProfileAndDatabase(): { profile?: ConnectionProfile, databaseName?: string } | undefined { if (!this._serverTreeView) { return undefined; } @@ -647,19 +655,19 @@ export class ObjectExplorerService implements IObjectExplorerService { * Returns a boolean indicating whether the Object Explorer tree has focus */ public isFocused(): boolean { - return this._serverTreeView.isFocused(); + return this._serverTreeView?.isFocused() ?? false; } public getServerTreeView() { return this._serverTreeView; } - public async findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames?: string[]): Promise { + public async findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames: string[] = []): Promise { let rootNode = this._activeObjectExplorerNodes[connectionId]; if (!rootNode) { return []; } - let sessionId = rootNode.session.sessionId; + let sessionId = rootNode?.session?.sessionId ?? ''; const response = await this._providers[this._sessions[sessionId].connection.providerName].findNodes({ type: type, name: name, @@ -680,20 +688,35 @@ export class ObjectExplorerService implements IObjectExplorerService { */ public async getNodeActions(connectionId: string, nodePath: string): Promise { const node = await this.getTreeNode(connectionId, nodePath); - const actions = this._serverTreeView.treeActionProvider.getActions(this._serverTreeView.tree, this.getTreeItem(node)); - return actions.filter(action => action.label).map(action => action.label); + if (!node || !this._serverTreeView?.tree) { + return []; + } + let treeItem = this.getTreeItem(node); + if (!treeItem) { + return []; + } + const actions = this._serverTreeView?.treeActionProvider.getActions(this._serverTreeView!.tree, treeItem); + return actions?.filter(action => action.label).map(action => action.label) ?? []; } - public async refreshNodeInView(connectionId: string, nodePath: string): Promise { + public async refreshNodeInView(connectionId: string, nodePath: string): Promise { // Get the tree node and call refresh from the provider let treeNode = await this.getTreeNode(connectionId, nodePath); - await this.refreshTreeNode(treeNode.getSession(), treeNode); - + if (!treeNode) { + return undefined; + } + const session = treeNode.getSession(); + if (session) { + await this.refreshTreeNode(session, treeNode); + } // Get the new tree node, refresh it in the view, and expand it if needed treeNode = await this.getTreeNode(connectionId, nodePath); - await this._serverTreeView.refreshElement(treeNode); - if (treeNode.children.length > 0) { - await treeNode.setExpandedState(TreeItemCollapsibleState.Expanded); + if (!treeNode) { + return undefined; + } + await this._serverTreeView?.refreshElement(treeNode); + if (treeNode?.children?.length ?? -1 > 0) { + await treeNode?.setExpandedState(TreeItemCollapsibleState.Expanded); } return treeNode; } @@ -702,31 +725,37 @@ export class ObjectExplorerService implements IObjectExplorerService { return this._sessions[sessionId].connection.toIConnectionProfile(); } - private async setNodeExpandedState(treeNode: TreeNode, expandedState: TreeItemCollapsibleState): Promise { + private async setNodeExpandedState(treeNode?: TreeNode, expandedState?: TreeItemCollapsibleState): Promise { treeNode = await this.getUpdatedTreeNode(treeNode); if (!treeNode) { - return Promise.resolve(); + return; } let expandNode = this.getTreeItem(treeNode); - if (expandedState === TreeItemCollapsibleState.Expanded) { - await this._serverTreeView.reveal(expandNode); + if (!expandNode) { + return; } - return this._serverTreeView.setExpandedState(expandNode, expandedState); + if (expandedState === TreeItemCollapsibleState.Expanded) { + await this._serverTreeView?.reveal(expandNode); + } + return this._serverTreeView?.setExpandedState(expandNode, expandedState); } - private async setNodeSelected(treeNode: TreeNode, selected: boolean, clearOtherSelections: boolean = undefined): Promise { + private async setNodeSelected(treeNode?: TreeNode, selected?: boolean, clearOtherSelections?: boolean): Promise { treeNode = await this.getUpdatedTreeNode(treeNode); if (!treeNode) { return Promise.resolve(); } let selectNode = this.getTreeItem(treeNode); - if (selected) { - await this._serverTreeView.reveal(selectNode); + if (!selectNode) { + return; } - return this._serverTreeView.setSelected(selectNode, selected, clearOtherSelections); + if (selected) { + await this._serverTreeView?.reveal(selectNode); + } + return this._serverTreeView?.setSelected(selectNode, selected, clearOtherSelections); } - private async getChildren(treeNode: TreeNode): Promise { + private async getChildren(treeNode?: TreeNode): Promise { treeNode = await this.getUpdatedTreeNode(treeNode); if (!treeNode) { return Promise.resolve([]); @@ -735,19 +764,25 @@ export class ObjectExplorerService implements IObjectExplorerService { return []; } if (!treeNode.children) { - await this.resolveTreeNodeChildren(treeNode.getSession(), treeNode); + const session = treeNode.getSession(); + if (session) { + await this.resolveTreeNodeChildren(session, treeNode); + } } - return treeNode.children; + return treeNode.children ?? []; } - private async isExpanded(treeNode: TreeNode): Promise { + private async isExpanded(treeNode?: TreeNode): Promise { + if (!treeNode) { + return false; + } treeNode = await this.getUpdatedTreeNode(treeNode); if (!treeNode) { return false; } do { let expandNode = this.getTreeItem(treeNode); - if (!this._serverTreeView.isExpanded(expandNode)) { + if (!this._serverTreeView?.isExpanded(expandNode)) { return false; } treeNode = treeNode.parent; @@ -756,16 +791,20 @@ export class ObjectExplorerService implements IObjectExplorerService { return true; } - private getTreeItem(treeNode: TreeNode): TreeNode | ConnectionProfile { - let rootNode = this._activeObjectExplorerNodes[treeNode.getConnectionProfile().id]; + private getTreeItem(treeNode: TreeNode): TreeNode | ConnectionProfile | undefined { + const idx = treeNode?.getConnectionProfile()?.id; + if (!idx) { + return undefined; + } + let rootNode = this._activeObjectExplorerNodes[idx]; if (treeNode === rootNode) { return treeNode.connection; } return treeNode; } - private async getUpdatedTreeNode(treeNode: TreeNode): Promise { - const newTreeNode = await this.getTreeNode(treeNode.getConnectionProfile().id, treeNode.nodePath); + private async getUpdatedTreeNode(treeNode?: TreeNode): Promise { + const newTreeNode = await this.getTreeNode(treeNode?.getConnectionProfile()?.id, treeNode?.nodePath); if (!newTreeNode) { // throw new Error(nls.localize('treeNodeNoLongerExists', "The given tree node no longer exists")); return undefined; @@ -773,7 +812,10 @@ export class ObjectExplorerService implements IObjectExplorerService { return newTreeNode; } - public async getTreeNode(connectionId: string, nodePath: string): Promise { + public async getTreeNode(connectionId?: string, nodePath?: string): Promise { + if (!connectionId) { + return undefined; + } let parentNode = this._activeObjectExplorerNodes[connectionId]; if (!parentNode) { return undefined; @@ -785,7 +827,10 @@ export class ObjectExplorerService implements IObjectExplorerService { while (currentNode.nodePath !== nodePath) { let nextNode = undefined; if (!currentNode.isAlwaysLeaf && !currentNode.children) { - await this.resolveTreeNodeChildren(currentNode.getSession(), currentNode); + const session = currentNode?.getSession(); + if (session) { + await this.resolveTreeNodeChildren(session, currentNode); + } } if (currentNode.children) { // Look at the next node in the path, which is the child object with the longest path where the desired path starts with the child path diff --git a/src/sql/workbench/services/objectExplorer/browser/serverTreeActionProvider.ts b/src/sql/workbench/services/objectExplorer/browser/serverTreeActionProvider.ts index c5a253b0cb..5e785ba9ca 100644 --- a/src/sql/workbench/services/objectExplorer/browser/serverTreeActionProvider.ts +++ b/src/sql/workbench/services/objectExplorer/browser/serverTreeActionProvider.ts @@ -52,11 +52,14 @@ export class ServerTreeActionProvider { return this.getConnectionProfileGroupActions(element); } if (element instanceof TreeNode) { - return this.getObjectExplorerNodeActions({ - tree: tree, - profile: element.getConnectionProfile(), - treeNode: element - }); + const profile = element.getConnectionProfile(); + if (profile) { + return this.getObjectExplorerNodeActions({ + tree: tree, + profile, + treeNode: element + }); + } } return []; } @@ -80,7 +83,7 @@ export class ServerTreeActionProvider { // Fill in all actions const builtIn = getDefaultActions(context); - const actions = []; + const actions: IAction[] = []; const options = { arg: undefined, shouldForwardArgs: true }; const groups = menu.getActions(options); let insertIndex: number | undefined = 0; @@ -88,7 +91,9 @@ export class ServerTreeActionProvider { if (v[0] === '0_query') { return true; } else { - insertIndex += v[1].length; + if (v[1].length) { + insertIndex! += v[1].length; + } return false; } }); @@ -99,7 +104,7 @@ export class ServerTreeActionProvider { if (!(actions[insertIndex] instanceof Separator) && builtIn.length > 0) { builtIn.unshift(new Separator()); } - actions.splice(insertIndex, 0, ...builtIn); + actions?.splice(insertIndex, 0, ...builtIn); } else { if (actions.length > 0 && builtIn.length > 0) { builtIn.push(new Separator()); @@ -168,13 +173,14 @@ export class ServerTreeActionProvider { private getBuiltInNodeActions(context: ObjectExplorerContext): IAction[] { let actions: IAction[] = []; let treeNode = context.treeNode; - if (TreeUpdateUtils.isDatabaseNode(treeNode)) { - if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) { - } else { - return actions; + if (treeNode) { + if (TreeUpdateUtils.isDatabaseNode(treeNode)) { + if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) { + } else { + return actions; + } } } - // Contribute refresh action for scriptable objects via contribution if (!this.isScriptableObject(context)) { actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, context.tree, context.treeNode || context.profile)); @@ -185,7 +191,7 @@ export class ServerTreeActionProvider { private isScriptableObject(context: ObjectExplorerContext): boolean { if (context.treeNode) { - if (find(NodeType.SCRIPTABLE_OBJECTS, x => x === context.treeNode.nodeTypeId)) { + if (find(NodeType.SCRIPTABLE_OBJECTS, x => x === context?.treeNode?.nodeTypeId)) { return true; } } diff --git a/src/sql/workbench/services/objectExplorer/browser/treeSelectionHandler.ts b/src/sql/workbench/services/objectExplorer/browser/treeSelectionHandler.ts index deb8a30a67..a38f961beb 100644 --- a/src/sql/workbench/services/objectExplorer/browser/treeSelectionHandler.ts +++ b/src/sql/workbench/services/objectExplorer/browser/treeSelectionHandler.ts @@ -16,7 +16,7 @@ import { AsyncServerTree } from 'sql/workbench/services/objectExplorer/browser/a export class TreeSelectionHandler { // progressRunner: IProgressRunner; - private _lastClicked: any[]; + private _lastClicked: any[] | undefined; private _clickTimer: any = undefined; private _otherTimer: any = undefined; @@ -100,7 +100,7 @@ export class TreeSelectionHandler { this.onTreeActionStateChange(true); } } else { - let connectionProfile: ConnectionProfile = undefined; + let connectionProfile: ConnectionProfile | undefined = undefined; let options: IConnectionCompletionOptions = { params: undefined, saveTheConnection: true, diff --git a/src/sql/workbench/services/objectExplorer/browser/treeUpdateUtils.ts b/src/sql/workbench/services/objectExplorer/browser/treeUpdateUtils.ts index 1f6ab57e84..1aadffea76 100644 --- a/src/sql/workbench/services/objectExplorer/browser/treeUpdateUtils.ts +++ b/src/sql/workbench/services/objectExplorer/browser/treeUpdateUtils.ts @@ -52,7 +52,7 @@ export class TreeUpdateUtils { let expandableTree: IExpandableTree = tree; let selectedElement: any; - let targetsToExpand: any[]; + let targetsToExpand: any[] = []; if (tree && !(tree instanceof AsyncServerTree)) { let selection = tree.getSelection(); if (selection && selection.length === 1) { @@ -61,7 +61,7 @@ export class TreeUpdateUtils { targetsToExpand = expandableTree.getExpandedElements(); } let groups; - let treeInput = new ConnectionProfileGroup('root', null, undefined); + let treeInput: ConnectionProfileGroup | undefined = new ConnectionProfileGroup('root', undefined, undefined); if (viewKey === 'recent') { groups = connectionManagementService.getRecentConnections(providers); treeInput.addConnections(groups); @@ -72,8 +72,9 @@ export class TreeUpdateUtils { treeInput = TreeUpdateUtils.getTreeInput(connectionManagementService, providers); } const previousTreeInput = tree.getInput(); - await tree.setInput(treeInput); - + if (treeInput) { + await tree.setInput(treeInput); + } if (previousTreeInput instanceof Disposable) { previousTreeInput.dispose(); } @@ -95,7 +96,9 @@ export class TreeUpdateUtils { public static async registeredServerUpdate(tree: ITree | AsyncServerTree, connectionManagementService: IConnectionManagementService, elementToSelect?: any): Promise { if (tree instanceof AsyncServerTree) { const treeInput = TreeUpdateUtils.getTreeInput(connectionManagementService); - await tree.setInput(treeInput); + if (treeInput) { + await tree.setInput(treeInput); + } tree.rerender(); } else { // convert to old VS Code tree interface with expandable methods @@ -155,7 +158,7 @@ export class TreeUpdateUtils { connection: ConnectionProfile, options: IConnectionCompletionOptions, connectionManagementService: IConnectionManagementService, - tree: AsyncServerTree | ITree): Promise { + tree: AsyncServerTree | ITree | undefined): Promise { if (!connectionManagementService.isProfileConnected(connection)) { // don't try to reconnect if currently connecting if (connectionManagementService.isProfileConnecting(connection)) { @@ -163,14 +166,14 @@ export class TreeUpdateUtils { // else if we aren't connected or connecting then try to connect } else { - let callbacks: IConnectionCallbacks = undefined; + let callbacks: IConnectionCallbacks | undefined; if (tree instanceof AsyncServerTree) { callbacks = { - onConnectStart: undefined, - onConnectReject: undefined, - onConnectSuccess: undefined, - onDisconnect: undefined, - onConnectCanceled: undefined, + onConnectStart: () => { }, + onConnectReject: () => { }, + onConnectSuccess: () => { }, + onDisconnect: () => { }, + onConnectCanceled: () => { }, }; } else if (tree) { // Show the spinner in OE by adding the 'loading' trait to the connection, and set up callbacks to hide the spinner @@ -180,10 +183,10 @@ export class TreeUpdateUtils { tree.removeTraits('loading', [connection]); }; callbacks = { - onConnectStart: undefined, + onConnectStart: () => { }, onConnectReject: rejectOrCancelCallback, onConnectSuccess: () => tree.removeTraits('loading', [connection]), - onDisconnect: undefined, + onDisconnect: () => { }, onConnectCanceled: rejectOrCancelCallback, }; } @@ -215,14 +218,14 @@ export class TreeUpdateUtils { * @param objectExplorerService Object explorer service instance */ public static async connectAndCreateOeSession(connection: ConnectionProfile, options: IConnectionCompletionOptions, - connectionManagementService: IConnectionManagementService, objectExplorerService: IObjectExplorerService, tree: AsyncServerTree | ITree): Promise { + connectionManagementService: IConnectionManagementService, objectExplorerService: IObjectExplorerService, tree: AsyncServerTree | ITree | undefined): Promise { const connectedConnection = await TreeUpdateUtils.connectIfNotConnected(connection, options, connectionManagementService, tree); if (connectedConnection) { // append group ID and original display name to build unique OE session ID connectedConnection.options['groupId'] = connection.groupId; connectedConnection.options['databaseDisplayName'] = connection.databaseName; - let rootNode: TreeNode = objectExplorerService.getObjectExplorerNode(connectedConnection); + let rootNode: TreeNode | undefined = objectExplorerService.getObjectExplorerNode(connectedConnection); if (!rootNode) { await objectExplorerService.updateObjectExplorerNodes(connectedConnection); return true; @@ -240,10 +243,11 @@ export class TreeUpdateUtils { return []; } else { let rootNode = objectExplorerService.getObjectExplorerNode(connection); - if (rootNode) { + const session = rootNode?.getSession(); + if (rootNode && session) { try { - await objectExplorerService.resolveTreeNodeChildren(rootNode.getSession(), rootNode); - return rootNode.children; + await objectExplorerService.resolveTreeNodeChildren(session, rootNode); + return rootNode.children ?? []; } catch (err) { onUnexpectedError(err); return []; @@ -260,9 +264,10 @@ export class TreeUpdateUtils { return []; } else { let rootNode = objectExplorerService.getObjectExplorerNode(connection); - if (rootNode) { - await objectExplorerService.resolveTreeNodeChildren(rootNode.getSession(), rootNode); - return rootNode.children; + const session = rootNode?.getSession(); + if (rootNode && session) { + await objectExplorerService.resolveTreeNodeChildren(session, rootNode); + return rootNode.children ?? []; } else { const options: IConnectionCompletionOptions = { params: undefined, @@ -284,9 +289,12 @@ export class TreeUpdateUtils { }); await TreeUpdateUtils.connectAndCreateOeSession(connection, options, connectionManagementService, objectExplorerService, undefined); await nodesUpdatedPromise; - let rootNode = objectExplorerService.getObjectExplorerNode(connection); - await objectExplorerService.resolveTreeNodeChildren(rootNode.getSession(), rootNode); - return rootNode.children; + let rootNode = objectExplorerService.getObjectExplorerNode(connection); // Major code change + const session = rootNode?.getSession(); + if (rootNode && session) { + await objectExplorerService.resolveTreeNodeChildren(session, rootNode); + } + return rootNode?.children ?? []; } } } @@ -295,10 +303,12 @@ export class TreeUpdateUtils { if (objectExplorerNode && objectExplorerNode.parent) { // if object explorer node's parent is root, return connection profile if (!objectExplorerNode.parent.parent) { - const connectionId = objectExplorerNode.getConnectionProfile().id; + const connectionId = objectExplorerNode.getConnectionProfile()?.id; // get connection profile from connection profile groups const root = TreeUpdateUtils.getTreeInput(connectionManagementService); - return ConnectionProfileGroup.getConnectionsInGroup(root).find(conn => connectionId === conn.id); + if (root) { + return ConnectionProfileGroup.getConnectionsInGroup(root).find(conn => connectionId === conn.id); + } } else { return objectExplorerNode.parent; } @@ -325,11 +335,11 @@ export class TreeUpdateUtils { /** * Get connection profile with the current database */ - public static getConnectionProfile(treeNode: TreeNode): ConnectionProfile { + public static getConnectionProfile(treeNode: TreeNode): ConnectionProfile | undefined { let connectionProfile = treeNode.getConnectionProfile(); let databaseName = treeNode.getDatabaseName(); - if (databaseName !== undefined && connectionProfile.databaseName !== databaseName) { - connectionProfile = connectionProfile.cloneWithDatabase(databaseName); + if (databaseName !== undefined && connectionProfile?.databaseName !== databaseName) { + connectionProfile = connectionProfile?.cloneWithDatabase(databaseName); } return connectionProfile; } diff --git a/src/sql/workbench/services/objectExplorer/common/treeNode.ts b/src/sql/workbench/services/objectExplorer/common/treeNode.ts index a249714c28..5a8683845c 100644 --- a/src/sql/workbench/services/objectExplorer/common/treeNode.ts +++ b/src/sql/workbench/services/objectExplorer/common/treeNode.ts @@ -17,7 +17,7 @@ export enum TreeItemCollapsibleState { } export interface ObjectExplorerCallbacks { - getChildren(treeNode: TreeNode): Thenable; + getChildren(treeNode?: TreeNode): Thenable; isExpanded(treeNode: TreeNode): Thenable; setNodeExpandedState(TreeNode: TreeNode, expandedState: TreeItemCollapsibleState): Thenable; setNodeSelected(TreeNode: TreeNode, selected: boolean, clearOtherSelections?: boolean): Thenable; @@ -27,7 +27,7 @@ export class TreeNode { /** * Informs who provides the children to a node, used by data explorer tree view api */ - public childProvider: string; + public childProvider?: string; /** * Holds the connection profile for nodes, used by data explorer tree view api */ @@ -56,12 +56,12 @@ export class TreeNode { * Message to show if this Node is in an error state. This indicates * that children could be retrieved */ - public errorStateMessage: string; + public errorStateMessage?: string; /** * Parent of this node */ - public parent: TreeNode; + public parent?: TreeNode; /** * Path identifying this node @@ -76,28 +76,28 @@ export class TreeNode { /** * Node Status */ - public nodeStatus: string; + public nodeStatus?: string; /** * Children of this node */ - public children: TreeNode[]; + public children?: TreeNode[]; - public connection: ConnectionProfile; + public connection?: ConnectionProfile; - public session: azdata.ObjectExplorerSession; + public session?: azdata.ObjectExplorerSession; - public metadata: azdata.ObjectMetadata; + public metadata?: azdata.ObjectMetadata; - public iconType: string | SqlThemeIcon; + public iconType?: string | SqlThemeIcon; - public iconPath: URI | { light: URI, dark: URI }; + public iconPath?: URI | { light: URI, dark: URI }; constructor(nodeTypeId: string, label: string, isAlwaysLeaf: boolean, nodePath: string, - nodeSubType: string, nodeStatus: string, parent: TreeNode, metadata: azdata.ObjectMetadata, - iconType: string | SqlThemeIcon, - private _objectExplorerCallbacks: ObjectExplorerCallbacks) { + nodeSubType: string, nodeStatus?: string, parent?: TreeNode, metadata?: azdata.ObjectMetadata, + iconType?: string | SqlThemeIcon, + private _objectExplorerCallbacks?: ObjectExplorerCallbacks) { this.nodeTypeId = nodeTypeId; this.label = label; this.isAlwaysLeaf = isAlwaysLeaf; @@ -109,7 +109,7 @@ export class TreeNode { this.nodeSubType = nodeSubType; this.nodeStatus = nodeStatus; } - public getConnectionProfile(): ConnectionProfile { + public getConnectionProfile(): ConnectionProfile | undefined { let currentNode: TreeNode = this; while (!currentNode.connection && currentNode.parent) { currentNode = currentNode.parent; @@ -117,7 +117,7 @@ export class TreeNode { return currentNode.connection; } - public getDatabaseName(): string { + public getDatabaseName(): string | undefined { if (this.connection) { return undefined; } @@ -127,12 +127,12 @@ export class TreeNode { } if (currentNode && currentNode.nodeTypeId === NodeType.Database) { - return currentNode.metadata ? currentNode.metadata.name : null; + return currentNode?.metadata?.name; } return undefined; } - public getSession(): azdata.ObjectExplorerSession { + public getSession(): azdata.ObjectExplorerSession | undefined { let currentNode: TreeNode = this; while (!currentNode.session && currentNode.parent) { currentNode = currentNode.parent; @@ -161,18 +161,18 @@ export class TreeNode { } public getChildren(): Thenable { - return this._objectExplorerCallbacks.getChildren(this); + return this._objectExplorerCallbacks?.getChildren(this) ?? Promise.resolve([]); } public isExpanded(): Thenable { - return this._objectExplorerCallbacks.isExpanded(this); + return this._objectExplorerCallbacks?.isExpanded(this) ?? Promise.resolve(false); } - public setExpandedState(expandedState: TreeItemCollapsibleState): Thenable { - return this._objectExplorerCallbacks.setNodeExpandedState(this, expandedState); + public setExpandedState(expandedState: TreeItemCollapsibleState): Thenable { + return this._objectExplorerCallbacks?.setNodeExpandedState(this, expandedState) ?? Promise.resolve(); } - public setSelected(selected: boolean, clearOtherSelections?: boolean): Thenable { - return this._objectExplorerCallbacks.setNodeSelected(this, selected, clearOtherSelections); + public setSelected(selected: boolean, clearOtherSelections?: boolean): Thenable { + return this._objectExplorerCallbacks?.setNodeSelected(this, selected, clearOtherSelections) ?? Promise.resolve(); } } diff --git a/src/sql/workbench/services/objectExplorer/common/treeNodeContextKey.ts b/src/sql/workbench/services/objectExplorer/common/treeNodeContextKey.ts index 053b1d7b41..27b3caab5d 100644 --- a/src/sql/workbench/services/objectExplorer/common/treeNodeContextKey.ts +++ b/src/sql/workbench/services/objectExplorer/common/treeNodeContextKey.ts @@ -34,7 +34,9 @@ export class TreeNodeContextKey implements IContextKey { this._treeNodeKey.set(value); this._nodeTypeKey.set(value && value.nodeTypeId); this._subTypeKey.set(value && value.nodeSubType); - this._statusKey.set(value && value.nodeStatus); + if (value.nodeStatus) { + this._statusKey.set(value && value.nodeStatus); + } this._nodeLabelKey.set(value && value.label); } @@ -46,7 +48,7 @@ export class TreeNodeContextKey implements IContextKey { this._nodeLabelKey.reset(); } - public get(): TreeNode { + public get(): TreeNode | undefined { return this._treeNodeKey.get(); } } diff --git a/src/tsconfig.vscode.json b/src/tsconfig.vscode.json index 3e267444df..8cc8c9b798 100644 --- a/src/tsconfig.vscode.json +++ b/src/tsconfig.vscode.json @@ -32,7 +32,6 @@ "./sql/workbench/api/common/**/*.ts", // 294 errors "./sql/workbench/browser/**/*.ts", // 3162 errors "./sql/workbench/contrib/assessment/**/*.ts", // 3164 errors - "./sql/workbench/contrib/azure/**/*.ts", // 118 errors "./sql/workbench/contrib/backup/**/*.ts", // 249 errors "./sql/workbench/contrib/charts/**/*.ts", // 3162 errors "./sql/workbench/contrib/commandLine/**/*.ts", // 3185 errors