Stops second invocation of createNewSession while expanding OE tree items on disconnected servers (#21437)

* Debounces second invocation while expanding OE tree items

* Minor clean up

* Adjusts debounce time

* Adding temp trace comments

* Adds missing semicolon

* Removes debouncer to stop 2nd newSession calls

* Removes temp trace comments

* Updates comment

Co-authored-by: Alan Ren <alanren@microsoft.com>
This commit is contained in:
Lewis Sanchez
2023-01-06 16:10:19 -08:00
committed by GitHub
parent ad006cdb63
commit 8c8a7859a0
3 changed files with 30 additions and 12 deletions

View File

@@ -23,6 +23,7 @@ import { ServerTreeActionProvider } from 'sql/workbench/services/objectExplorer/
import { ITree } from 'sql/base/parts/tree/browser/tree';
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
import { ObjectExplorerRequestStatus } from 'sql/workbench/services/objectExplorer/browser/treeSelectionHandler';
export const SERVICE_ID = 'ObjectExplorerService';
@@ -87,7 +88,7 @@ export interface IObjectExplorerService {
getObjectExplorerNode(connection: IConnectionProfile): TreeNode | undefined;
updateObjectExplorerNodes(connectionProfile: IConnectionProfile): Promise<void>;
updateObjectExplorerNodes(connectionProfile: IConnectionProfile, requestStatus?: ObjectExplorerRequestStatus | undefined): Promise<void>;
deleteObjectExplorerNode(connection: IConnectionProfile): Promise<void>;
@@ -208,10 +209,10 @@ export class ObjectExplorerService implements IObjectExplorerService {
return this._onSelectionOrFocusChange.event;
}
public async updateObjectExplorerNodes(connection: IConnectionProfile): Promise<void> {
public async updateObjectExplorerNodes(connection: IConnectionProfile, requestStatus?: ObjectExplorerRequestStatus | undefined): Promise<void> {
const withPassword = await this._connectionManagementService.addSavedPassword(connection);
const connectionProfile = ConnectionProfile.fromIConnectionProfile(this._capabilitiesService, withPassword);
return this.updateNewObjectExplorerNode(connectionProfile);
return this.updateNewObjectExplorerNode(connectionProfile, requestStatus);
}
public async deleteObjectExplorerNode(connection: IConnectionProfile): Promise<void> {
@@ -327,12 +328,14 @@ export class ObjectExplorerService implements IObjectExplorerService {
this._onUpdateObjectExplorerNodes.fire(eventArgs);
}
private async updateNewObjectExplorerNode(connection: ConnectionProfile): Promise<void> {
private async updateNewObjectExplorerNode(connection: ConnectionProfile, requestStatus: ObjectExplorerRequestStatus | undefined): Promise<void> {
if (this._activeObjectExplorerNodes[connection.id]) {
this.sendUpdateNodeEvent(connection);
} else {
try {
await this.createNewSession(connection.providerName, connection);
if (!requestStatus) {
await this.createNewSession(connection.providerName, connection);
}
} catch (err) {
this.sendUpdateNodeEvent(connection, err);
throw err;
@@ -352,6 +355,7 @@ export class ObjectExplorerService implements IObjectExplorerService {
connection: connection,
nodes: {}
};
return result;
} else {
throw new Error(`Provider doesn't exist. id: ${providerId}`);

View File

@@ -15,12 +15,17 @@ import { AsyncServerTree } from 'sql/workbench/services/objectExplorer/browser/a
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
import { onUnexpectedError } from 'vs/base/common/errors';
export interface ObjectExplorerRequestStatus {
inProgress: boolean;
}
export class TreeSelectionHandler {
// progressRunner: IProgressRunner;
private _lastClicked: any[] | undefined;
private _clickTimer: any = undefined;
private _otherTimer: any = undefined;
private _requestStatus: ObjectExplorerRequestStatus | undefined = undefined;
// constructor(@IProgressService private _progressService: IProgressService) {
@@ -50,13 +55,13 @@ export class TreeSelectionHandler {
* Handle selection of tree element
*/
public onTreeSelect(event: any, tree: AsyncServerTree | ITree, connectionManagementService: IConnectionManagementService, objectExplorerService: IObjectExplorerService, capabilitiesService: ICapabilitiesService, connectionCompleteCallback: () => void) {
let sendSelectionEvent = ((event: any, selection: any, isDoubleClick: boolean, userInteraction: boolean) => {
let sendSelectionEvent = ((event: any, selection: any, isDoubleClick: boolean, userInteraction: boolean, requestStatus: ObjectExplorerRequestStatus | undefined = undefined) => {
// userInteraction: defensive - don't touch this something else is handling it.
if (userInteraction === true && this._lastClicked && this._lastClicked[0] === selection[0]) {
this._lastClicked = undefined;
}
if (!TreeUpdateUtils.isInDragAndDrop) {
this.handleTreeItemSelected(connectionManagementService, objectExplorerService, capabilitiesService, isDoubleClick, this.isKeyboardEvent(event), selection, tree, connectionCompleteCallback);
this.handleTreeItemSelected(connectionManagementService, objectExplorerService, capabilitiesService, isDoubleClick, this.isKeyboardEvent(event), selection, tree, connectionCompleteCallback, requestStatus);
}
});
@@ -82,12 +87,14 @@ export class TreeSelectionHandler {
this._lastClicked = selection;
this._clickTimer = setTimeout(() => {
// Sets request status object when timer is executed
this._requestStatus = { inProgress: true };
sendSelectionEvent(event, selection, false, true);
}, 400);
} else {
clearTimeout(this._otherTimer);
this._otherTimer = setTimeout(() => {
sendSelectionEvent(event, selection, false, false);
sendSelectionEvent(event, selection, false, false, this._requestStatus);
}, 400);
}
}
@@ -102,8 +109,9 @@ export class TreeSelectionHandler {
* @param selection
* @param tree
* @param connectionCompleteCallback A function that gets called after a connection is established due to the selection, if needed
* @param requestStatus Used to identify if a new session should be created or not to avoid creating back to back sessions
*/
private handleTreeItemSelected(connectionManagementService: IConnectionManagementService, objectExplorerService: IObjectExplorerService, capabilitiesService: ICapabilitiesService, isDoubleClick: boolean, isKeyboard: boolean, selection: any[], tree: AsyncServerTree | ITree, connectionCompleteCallback: () => void): void {
private handleTreeItemSelected(connectionManagementService: IConnectionManagementService, objectExplorerService: IObjectExplorerService, capabilitiesService: ICapabilitiesService, isDoubleClick: boolean, isKeyboard: boolean, selection: any[], tree: AsyncServerTree | ITree, connectionCompleteCallback: () => void, requestStatus: ObjectExplorerRequestStatus | undefined): void {
if (tree instanceof AsyncServerTree) {
if (selection && selection.length > 0 && (selection[0] instanceof ConnectionProfile)) {
if (!capabilitiesService.getCapabilities(selection[0].providerName)) {
@@ -131,7 +139,12 @@ export class TreeSelectionHandler {
if (connectionProfile) {
this.onTreeActionStateChange(true);
TreeUpdateUtils.connectAndCreateOeSession(connectionProfile, options, connectionManagementService, objectExplorerService, tree).then(sessionCreated => {
TreeUpdateUtils.connectAndCreateOeSession(connectionProfile, options, connectionManagementService, objectExplorerService, tree, requestStatus).then(sessionCreated => {
// Clears request status object that was created when the first timeout callback is executed.
if (this._requestStatus) {
this._requestStatus = undefined;
}
if (!sessionCreated) {
this.onTreeActionStateChange(false);
}

View File

@@ -14,6 +14,7 @@ import { TreeNode } from 'sql/workbench/services/objectExplorer/common/treeNode'
import { Disposable, isDisposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
import { ObjectExplorerRequestStatus } from 'sql/workbench/services/objectExplorer/browser/treeSelectionHandler';
export interface IExpandableTree extends ITree {
/**
@@ -222,7 +223,7 @@ export class TreeUpdateUtils {
* @param objectExplorerService Object explorer service instance
*/
public static async connectAndCreateOeSession(connection: ConnectionProfile, options: IConnectionCompletionOptions,
connectionManagementService: IConnectionManagementService, objectExplorerService: IObjectExplorerService, tree: AsyncServerTree | ITree | undefined): Promise<boolean> {
connectionManagementService: IConnectionManagementService, objectExplorerService: IObjectExplorerService, tree: AsyncServerTree | ITree | undefined, requestStatus?: ObjectExplorerRequestStatus | 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
@@ -231,7 +232,7 @@ export class TreeUpdateUtils {
let rootNode: TreeNode | undefined = objectExplorerService.getObjectExplorerNode(connectedConnection);
if (!rootNode) {
await objectExplorerService.updateObjectExplorerNodes(connectedConnection);
await objectExplorerService.updateObjectExplorerNodes(connectedConnection, requestStatus);
return true;
// The oe request is sent. an event will be raised when the session is created
} else {