strict null checks azure (#11928)

* strict null checks azure

* strict compilation

* Fix compilation issues

* Return empty arrays instead
This commit is contained in:
Amir Omidi
2020-08-25 18:12:47 -07:00
committed by GitHub
parent 8b52e7200c
commit 4659d727b7
24 changed files with 285 additions and 208 deletions

View File

@@ -43,7 +43,7 @@ export class RefreshAction extends Action {
super(id, label);
}
public async run(): Promise<boolean> {
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<boolean> {
let connection: IConnectionProfile = element === undefined ? undefined : {
// Not sure how to fix this....
let connection: Partial<IConnectionProfile> | 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<IConnectionProfile>;
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;
}

View File

@@ -48,19 +48,19 @@ export class MssqlNodeContext extends Disposable {
static CanScriptAsExecute = new RawContextKey<boolean>('canScriptAsExecute', false);
static CanScriptAsAlter = new RawContextKey<boolean>('canScriptAsAlter', false);
private nodeProviderKey: IContextKey<string>;
private isCloudKey: IContextKey<boolean>;
private nodeTypeKey: IContextKey<string>;
private nodeLabelKey: IContextKey<string>;
private isDatabaseOrServerKey: IContextKey<boolean>;
private engineEditionKey: IContextKey<number>;
private canOpenInAzurePortal: IContextKey<boolean>;
private nodeProviderKey!: IContextKey<string>;
private isCloudKey!: IContextKey<boolean>;
private nodeTypeKey!: IContextKey<string>;
private nodeLabelKey!: IContextKey<string>;
private isDatabaseOrServerKey!: IContextKey<boolean>;
private engineEditionKey!: IContextKey<number>;
private canOpenInAzurePortal!: IContextKey<boolean>;
private canScriptAsSelectKey: IContextKey<boolean>;
private canEditDataKey: IContextKey<boolean>;
private canScriptAsCreateOrDeleteKey: IContextKey<boolean>;
private canScriptAsExecuteKey: IContextKey<boolean>;
private canScriptAsAlterKey: IContextKey<boolean>;
private canScriptAsSelectKey!: IContextKey<boolean>;
private canEditDataKey!: IContextKey<boolean>;
private canScriptAsCreateOrDeleteKey!: IContextKey<boolean>;
private canScriptAsExecuteKey!: IContextKey<boolean>;
private canScriptAsAlterKey!: IContextKey<boolean>;
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);
}

View File

@@ -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<TreeNode> {
export async function getTreeNode(context: ObjectExplorerActionsContext, objectExplorerService: IObjectExplorerService): Promise<TreeNode | undefined> {
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<boolean> {
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;
}
}

View File

@@ -42,10 +42,10 @@ export interface IServerTreeView {
isFocused(): boolean;
refreshElement(node: TreeNode): Promise<void>;
readonly treeActionProvider: ServerTreeActionProvider;
isExpanded(node: ServerTreeElement): boolean;
isExpanded(node?: ServerTreeElement): boolean;
reveal(node: ServerTreeElement): Promise<void>;
setExpandedState(node: ServerTreeElement, state: TreeItemCollapsibleState): Promise<void>;
setSelected(node: ServerTreeElement, selected: boolean, clearOtherSelections: boolean): Promise<void>;
setExpandedState(node: ServerTreeElement, state?: TreeItemCollapsibleState): Promise<void>;
setSelected(node: ServerTreeElement, selected?: boolean, clearOtherSelections?: boolean): Promise<void>;
refreshTree(): Promise<void>;
readonly activeConnectionsFilterAction: IAction;
renderBody(container: HTMLElement): Promise<void>;
@@ -57,11 +57,11 @@ export interface IObjectExplorerService {
createNewSession(providerId: string, connection: ConnectionProfile): Promise<azdata.ObjectExplorerSessionResponse>;
closeSession(providerId: string, session: azdata.ObjectExplorerSession): Promise<azdata.ObjectExplorerCloseSessionResponse>;
closeSession(providerId: string, session: azdata.ObjectExplorerSession): Promise<azdata.ObjectExplorerCloseSessionResponse | undefined>;
expandNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise<azdata.ObjectExplorerExpandInfo>;
refreshNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise<azdata.ObjectExplorerExpandInfo>;
refreshNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise<azdata.ObjectExplorerExpandInfo | undefined>;
resolveTreeNodeChildren(session: azdata.ObjectExplorerSession, parentTree: TreeNode): Promise<TreeNode[]>;
@@ -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<void>;
getServerTreeView(): IServerTreeView;
getServerTreeView(): IServerTreeView | undefined;
findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames?: string[]): Promise<azdata.NodeInfo[]>;
getActiveConnectionNodes(): TreeNode[];
getTreeNode(connectionId: string, nodePath: string): Promise<TreeNode>;
getTreeNode(connectionId?: string, nodePath?: string): Promise<TreeNode | undefined>;
refreshNodeInView(connectionId: string, nodePath: string): Promise<TreeNode>;
refreshNodeInView(connectionId: string, nodePath: string): Promise<TreeNode | undefined>;
/**
* 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<ObjectExplorerNodeEventArgs>;
private _serverTreeView: IServerTreeView;
private _serverTreeView?: IServerTreeView;
private _onSelectionOrFocusChange: Emitter<void>;
@@ -179,7 +179,7 @@ export class ObjectExplorerService implements IObjectExplorerService {
this._onSelectionOrFocusChange = new Emitter<void>();
}
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<void> {
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<void> {
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: <IConnectionProfile>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<azdata.ObjectExplorerSessionResponse> {
@@ -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<string, azdata.ObjectExplorerExpandInfo>, nodePath: string): azdata.ObjectExplorerExpandInfo {
let finalResult: azdata.ObjectExplorerExpandInfo;
private mergeResults(allProviders: azdata.ObjectExplorerProviderBase[], resultMap: Map<string, azdata.ObjectExplorerExpandInfo>, 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<azdata.ObjectExplorerExpandInfo> {
public refreshNode(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string): Promise<azdata.ObjectExplorerExpandInfo | undefined> {
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<azdata.ObjectExplorerCloseSessionResponse> {
public closeSession(providerId: string, session: azdata.ObjectExplorerSession): Promise<azdata.ObjectExplorerCloseSessionResponse | undefined> {
// 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<azdata.ObjectExplorerExpandInfo> {
private callExpandOrRefreshFromService(providerId: string, session: azdata.ObjectExplorerSession, nodePath: string, refresh: boolean = false): Promise<azdata.ObjectExplorerExpandInfo | undefined> {
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<TreeNode[]> {
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<azdata.NodeInfo[]> {
public async findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames: string[] = []): Promise<azdata.NodeInfo[]> {
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<string[]> {
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<TreeNode> {
public async refreshNodeInView(connectionId: string, nodePath: string): Promise<TreeNode | undefined> {
// 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<void> {
private async setNodeExpandedState(treeNode?: TreeNode, expandedState?: TreeItemCollapsibleState): Promise<void> {
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<void> {
private async setNodeSelected(treeNode?: TreeNode, selected?: boolean, clearOtherSelections?: boolean): Promise<void> {
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<TreeNode[]> {
private async getChildren(treeNode?: TreeNode): Promise<TreeNode[]> {
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<boolean> {
private async isExpanded(treeNode?: TreeNode): Promise<boolean> {
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<TreeNode | undefined> {
const newTreeNode = await this.getTreeNode(treeNode.getConnectionProfile().id, treeNode.nodePath);
private async getUpdatedTreeNode(treeNode?: TreeNode): Promise<TreeNode | undefined> {
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<TreeNode> {
public async getTreeNode(connectionId?: string, nodePath?: string): Promise<TreeNode | undefined> {
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

View File

@@ -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;
}
}

View File

@@ -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,

View File

@@ -52,7 +52,7 @@ export class TreeUpdateUtils {
let expandableTree: IExpandableTree = <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<void> {
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<ConnectionProfile | undefined> {
tree: AsyncServerTree | ITree | undefined): Promise<ConnectionProfile | undefined> {
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<boolean> {
connectionManagementService: IConnectionManagementService, objectExplorerService: IObjectExplorerService, tree: AsyncServerTree | ITree | undefined): Promise<boolean> {
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;
}