mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Fixing async server tree error handling and removing timeout. (#22955)
* Fixing async server tree issues and removing timeout * removing empty results for connection errors * Fixing error message fetching * Update src/sql/workbench/services/objectExplorer/browser/asyncServerTreeDataSource.ts Co-authored-by: Charles Gagnon <chgagnon@microsoft.com> --------- Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
This commit is contained in:
@@ -41,7 +41,6 @@ const serverGroupConfig: IConfigurationNode = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NODE_EXPANSION_CONFIG = 'serverTree.nodeExpansionTimeout';
|
|
||||||
export const USE_ASYNC_SERVER_TREE_CONFIG = 'serverTree.useAsyncServerTree';
|
export const USE_ASYNC_SERVER_TREE_CONFIG = 'serverTree.useAsyncServerTree';
|
||||||
const serverTreeConfig: IConfigurationNode = {
|
const serverTreeConfig: IConfigurationNode = {
|
||||||
'id': 'serverTree',
|
'id': 'serverTree',
|
||||||
@@ -52,12 +51,6 @@ const serverTreeConfig: IConfigurationNode = {
|
|||||||
'type': 'boolean',
|
'type': 'boolean',
|
||||||
'default': true,
|
'default': true,
|
||||||
'description': localize('serverTree.useAsyncServerTree', "Use the new async server tree for the Servers view and Connection Dialog with support for new features such as dynamic node filtering. Requires a restart to take effect.")
|
'description': localize('serverTree.useAsyncServerTree', "Use the new async server tree for the Servers view and Connection Dialog with support for new features such as dynamic node filtering. Requires a restart to take effect.")
|
||||||
},
|
|
||||||
'serverTree.nodeExpansionTimeout': {
|
|
||||||
'type': 'number',
|
|
||||||
'default': '45',
|
|
||||||
'description': localize('serverTree.nodeExpansionTimeout', "The timeout in seconds for expanding a node in the Servers view"),
|
|
||||||
'minimum': 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -151,3 +151,10 @@ export class AsyncServerTree extends WorkbenchAsyncDataTree<ConnectionProfileGro
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ServerTreeElement = ConnectionProfile | ConnectionProfileGroup | TreeNode;
|
export type ServerTreeElement = ConnectionProfile | ConnectionProfileGroup | TreeNode;
|
||||||
|
|
||||||
|
|
||||||
|
export class ConnectionError extends Error {
|
||||||
|
constructor(message: string, public connection: ConnectionProfile) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ import { IConnectionManagementService } from 'sql/platform/connection/common/con
|
|||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
|
import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMessageService';
|
||||||
import { IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
import { IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||||
import { ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
import { ConnectionError, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
import { getErrorMessage } from 'vs/base/common/errors';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the DataSource(that returns a parent/children of an element) for the server tree
|
* Implements the DataSource(that returns a parent/children of an element) for the server tree
|
||||||
@@ -51,18 +52,16 @@ export class AsyncServerTreeDataSource implements IAsyncDataSource<ConnectionPro
|
|||||||
} else if (element instanceof ConnectionProfileGroup) {
|
} else if (element instanceof ConnectionProfileGroup) {
|
||||||
return element.getChildren();
|
return element.getChildren();
|
||||||
} else if (element instanceof TreeNode) {
|
} else if (element instanceof TreeNode) {
|
||||||
if (element.children) {
|
return await this._objectExplorerService.resolveTreeNodeChildren(element.getSession()!, element);
|
||||||
return element.children;
|
|
||||||
} else {
|
|
||||||
return await this._objectExplorerService.resolveTreeNodeChildren(element.getSession()!, element);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
const errorMessage = getErrorMessage(err);
|
||||||
if (element instanceof TreeNode) {
|
if (element instanceof TreeNode) {
|
||||||
element.errorStateMessage = err.message ?? err;
|
element.errorStateMessage = errorMessage;
|
||||||
}
|
}
|
||||||
if (err.message) {
|
// In case of connection profile, we won't show the error here and let the connection service handle it.
|
||||||
this.showError(err.message);
|
if (errorMessage && !(err instanceof ConnectionError)) {
|
||||||
|
this.showError(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw err;
|
throw err;
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ import { ITree } from 'sql/base/parts/tree/browser/tree';
|
|||||||
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
||||||
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
||||||
import { ObjectExplorerRequestStatus } from 'sql/workbench/services/objectExplorer/browser/treeSelectionHandler';
|
import { ObjectExplorerRequestStatus } from 'sql/workbench/services/objectExplorer/browser/treeSelectionHandler';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
|
||||||
import { NODE_EXPANSION_CONFIG } from 'sql/workbench/contrib/objectExplorer/common/serverGroup.contribution';
|
|
||||||
|
|
||||||
export const SERVICE_ID = 'ObjectExplorerService';
|
export const SERVICE_ID = 'ObjectExplorerService';
|
||||||
|
|
||||||
@@ -190,8 +187,6 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
|||||||
@IAdsTelemetryService private _telemetryService: IAdsTelemetryService,
|
@IAdsTelemetryService private _telemetryService: IAdsTelemetryService,
|
||||||
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
|
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
|
||||||
@ILogService private logService: ILogService,
|
@ILogService private logService: ILogService,
|
||||||
@IConfigurationService private _configurationService: IConfigurationService,
|
|
||||||
@INotificationService private _notificationService: INotificationService
|
|
||||||
) {
|
) {
|
||||||
this._onUpdateObjectExplorerNodes = new Emitter<ObjectExplorerNodeEventArgs>();
|
this._onUpdateObjectExplorerNodes = new Emitter<ObjectExplorerNodeEventArgs>();
|
||||||
this._activeObjectExplorerNodes = {};
|
this._activeObjectExplorerNodes = {};
|
||||||
@@ -298,27 +293,8 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
|||||||
this._connectionsWaitingForSession.delete(connection.id);
|
this._connectionsWaitingForSession.delete(connection.id);
|
||||||
}
|
}
|
||||||
createNewSessionListener.dispose();
|
createNewSessionListener.dispose();
|
||||||
clearTimeout(timeoutHandle);
|
|
||||||
}
|
}
|
||||||
const onTimeout = () => {
|
|
||||||
if (!this._sessions[sessionId]) {
|
|
||||||
this.logService.error(`Timed out waiting for session ${sessionId} to be created.
|
|
||||||
This has probably happened because OE service did not recieve a response for createNewSession from the provider.`);
|
|
||||||
reject(new Error(
|
|
||||||
nls.localize('objectExplorerMissingSession',
|
|
||||||
'Timed out waiting for session {0} to be created. This has probably happened because OE service did not recieve a response for createNewSession from the provider.', sessionId)));
|
|
||||||
} else {
|
|
||||||
this.logService.error(`Timeout waiting for session ${sessionId} to be created for connection "${connection.title}".
|
|
||||||
This has probably happened because OE service did not recieve a response for createNewSession from the provider for connection."${connection.title}`);
|
|
||||||
reject(new Error(nls.localize(
|
|
||||||
'objectExplorerMissingConnectionForSession',
|
|
||||||
'Timeout waiting for session {0} to be created for connection "{1}". This has probably happened because OE service did not recieve a response for createNewSession from the provider for connection "{1}"', sessionId, connection.title
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
const timeoutHandle = setTimeout(onTimeout, this.getObjectExplorerTimeout() * 1000);
|
|
||||||
const createNewSessionListener = this._onCreateNewSession.event((response) => {
|
const createNewSessionListener = this._onCreateNewSession.event((response) => {
|
||||||
checkSessionAndConnection();
|
checkSessionAndConnection();
|
||||||
});
|
});
|
||||||
@@ -510,7 +486,6 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
|||||||
const resolveExpansion = () => {
|
const resolveExpansion = () => {
|
||||||
resolve(self.mergeResults(allProviders, resultMap, node.nodePath));
|
resolve(self.mergeResults(allProviders, resultMap, node.nodePath));
|
||||||
// Have to delete it after get all responses otherwise couldn't find session for not the first response
|
// Have to delete it after get all responses otherwise couldn't find session for not the first response
|
||||||
clearTimeout(expansionTimeout);
|
|
||||||
if (newRequest) {
|
if (newRequest) {
|
||||||
delete self._sessions[session.sessionId!].nodes[node.nodePath];
|
delete self._sessions[session.sessionId!].nodes[node.nodePath];
|
||||||
this.logService.trace(`Deleted node ${node.nodePath} from session ${session.sessionId}`);
|
this.logService.trace(`Deleted node ${node.nodePath} from session ${session.sessionId}`);
|
||||||
@@ -529,19 +504,6 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const expansionTimeout = setTimeout(() => {
|
|
||||||
/**
|
|
||||||
* If we don't get a response back from all the providers in specified expansion timeout seconds then we assume
|
|
||||||
* it's not going to respond and resolve the promise with the results we have so far
|
|
||||||
*/
|
|
||||||
if (resultMap.size !== allProviders.length) {
|
|
||||||
const missingProviders = allProviders.filter(p => !resultMap.has(p.providerId));
|
|
||||||
this.logService.warn(`${session.sessionId}: Node expansion timed out for node ${node.nodePath} for providers ${missingProviders.map(p => p.providerId).join(', ')}`);
|
|
||||||
this._notificationService.error(nls.localize('nodeExpansionTimeout', "Node expansion timed out for node {0} for providers {1}", node.nodePath, missingProviders.map(p => p.providerId).join(', ')));
|
|
||||||
}
|
|
||||||
resolveExpansion();
|
|
||||||
}, this.getObjectExplorerTimeout() * 1000);
|
|
||||||
|
|
||||||
self._sessions[session.sessionId!].nodes[node.nodePath].expandEmitter.event((expandResult: NodeExpandInfoWithProviderId) => {
|
self._sessions[session.sessionId!].nodes[node.nodePath].expandEmitter.event((expandResult: NodeExpandInfoWithProviderId) => {
|
||||||
if (expandResult && expandResult.providerId) {
|
if (expandResult && expandResult.providerId) {
|
||||||
this.logService.trace(`${session.sessionId}: Received expand result for node ${node.nodePath} from provider ${expandResult.providerId}`);
|
this.logService.trace(`${session.sessionId}: Received expand result for node ${node.nodePath} from provider ${expandResult.providerId}`);
|
||||||
@@ -600,8 +562,12 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private mergeResults(allProviders: azdata.ObjectExplorerProviderBase[], resultMap: Map<string, azdata.ObjectExplorerExpandInfo>, nodePath: string): azdata.ObjectExplorerExpandInfo | undefined {
|
private mergeResults(allProviders: azdata.ObjectExplorerProviderBase[], resultMap: Map<string, azdata.ObjectExplorerExpandInfo>, nodePath: string): azdata.ObjectExplorerExpandInfo {
|
||||||
let finalResult: azdata.ObjectExplorerExpandInfo | undefined = undefined;
|
let finalResult: azdata.ObjectExplorerExpandInfo | undefined = {
|
||||||
|
sessionId: undefined,
|
||||||
|
nodePath: nodePath,
|
||||||
|
nodes: []
|
||||||
|
};
|
||||||
let allNodes: azdata.NodeInfo[] = [];
|
let allNodes: azdata.NodeInfo[] = [];
|
||||||
let errorNode: azdata.NodeInfo = {
|
let errorNode: azdata.NodeInfo = {
|
||||||
nodePath: nodePath,
|
nodePath: nodePath,
|
||||||
@@ -620,12 +586,14 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
|||||||
if (resultMap.has(provider.providerId)) {
|
if (resultMap.has(provider.providerId)) {
|
||||||
let result = resultMap.get(provider.providerId);
|
let result = resultMap.get(provider.providerId);
|
||||||
if (result) {
|
if (result) {
|
||||||
|
|
||||||
if (!result.errorMessage) {
|
if (!result.errorMessage) {
|
||||||
finalResult = result;
|
finalResult = result;
|
||||||
if (result.nodes !== undefined && result.nodes) {
|
if (result.nodes !== undefined && result.nodes) {
|
||||||
allNodes = allNodes.concat(result.nodes);
|
allNodes = allNodes.concat(result.nodes);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
finalResult.sessionId = result.sessionId;
|
||||||
errorMessages.push(result.errorMessage);
|
errorMessages.push(result.errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -639,8 +607,11 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
|||||||
errorNode.errorMessage = errorMessages.join('\n');
|
errorNode.errorMessage = errorMessages.join('\n');
|
||||||
errorNode.label = errorNode.errorMessage;
|
errorNode.label = errorNode.errorMessage;
|
||||||
allNodes = [errorNode].concat(allNodes);
|
allNodes = [errorNode].concat(allNodes);
|
||||||
|
this._onUpdateObjectExplorerNodes.fire({
|
||||||
|
connection: undefined,
|
||||||
|
errorMessage: errorNode.errorMessage
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
finalResult.nodes = allNodes;
|
finalResult.nodes = allNodes;
|
||||||
}
|
}
|
||||||
return finalResult;
|
return finalResult;
|
||||||
@@ -1049,13 +1020,6 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
|||||||
return currentNode;
|
return currentNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* returns object explorer timeout in seconds.
|
|
||||||
*/
|
|
||||||
public getObjectExplorerTimeout(): number {
|
|
||||||
return this._configurationService.getValue<number>(NODE_EXPANSION_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
private getTreeNodeCacheKey(node: azdata.NodeInfo | TreeNode): string {
|
private getTreeNodeCacheKey(node: azdata.NodeInfo | TreeNode): string {
|
||||||
return node.nodePath;
|
return node.nodePath;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,9 @@ import { NodeType } from 'sql/workbench/services/objectExplorer/common/nodeType'
|
|||||||
|
|
||||||
import { TreeNode } from 'sql/workbench/services/objectExplorer/common/treeNode';
|
import { TreeNode } from 'sql/workbench/services/objectExplorer/common/treeNode';
|
||||||
import { Disposable, isDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, isDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { getErrorMessage, onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
import { AsyncServerTree, ConnectionError as AsyncTreeConnectionError, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
||||||
import { ObjectExplorerRequestStatus } from 'sql/workbench/services/objectExplorer/browser/treeSelectionHandler';
|
import { ObjectExplorerRequestStatus } from 'sql/workbench/services/objectExplorer/browser/treeSelectionHandler';
|
||||||
import * as nls from 'vs/nls';
|
|
||||||
import { NODE_EXPANSION_CONFIG } from 'sql/workbench/contrib/objectExplorer/common/serverGroup.contribution';
|
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
|
||||||
export interface IExpandableTree extends ITree {
|
export interface IExpandableTree extends ITree {
|
||||||
@@ -184,52 +182,58 @@ export class TreeUpdateUtils {
|
|||||||
options: IConnectionCompletionOptions,
|
options: IConnectionCompletionOptions,
|
||||||
connectionManagementService: IConnectionManagementService,
|
connectionManagementService: IConnectionManagementService,
|
||||||
tree: AsyncServerTree | ITree | undefined): 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)) {
|
|
||||||
return undefined;
|
|
||||||
|
|
||||||
// else if we aren't connected or connecting then try to connect
|
try {
|
||||||
} else {
|
if (!connectionManagementService.isProfileConnected(connection)) {
|
||||||
let callbacks: IConnectionCallbacks | undefined;
|
// don't try to reconnect if currently connecting
|
||||||
if (tree instanceof AsyncServerTree) {
|
if (connectionManagementService.isProfileConnecting(connection)) {
|
||||||
callbacks = {
|
return 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
|
|
||||||
tree.addTraits('loading', [connection]);
|
|
||||||
let rejectOrCancelCallback = () => {
|
|
||||||
tree.collapse(connection);
|
|
||||||
tree.removeTraits('loading', [connection]);
|
|
||||||
};
|
|
||||||
callbacks = {
|
|
||||||
onConnectStart: () => { },
|
|
||||||
onConnectReject: rejectOrCancelCallback,
|
|
||||||
onConnectSuccess: () => tree.removeTraits('loading', [connection]),
|
|
||||||
onDisconnect: () => { },
|
|
||||||
onConnectCanceled: rejectOrCancelCallback,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await connectionManagementService.connect(connection, undefined, options, callbacks);
|
// else if we aren't connected or connecting then try to connect
|
||||||
if (result.connected) {
|
|
||||||
let existingConnection = connectionManagementService.findExistingConnection(connection);
|
|
||||||
return existingConnection;
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(result.errorMessage);
|
let callbacks: IConnectionCallbacks | undefined;
|
||||||
|
if (tree instanceof AsyncServerTree) {
|
||||||
|
callbacks = {
|
||||||
|
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
|
||||||
|
tree.addTraits('loading', [connection]);
|
||||||
|
let rejectOrCancelCallback = () => {
|
||||||
|
tree.collapse(connection);
|
||||||
|
tree.removeTraits('loading', [connection]);
|
||||||
|
};
|
||||||
|
callbacks = {
|
||||||
|
onConnectStart: () => { },
|
||||||
|
onConnectReject: rejectOrCancelCallback,
|
||||||
|
onConnectSuccess: () => tree.removeTraits('loading', [connection]),
|
||||||
|
onDisconnect: () => { },
|
||||||
|
onConnectCanceled: rejectOrCancelCallback,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await connectionManagementService.connect(connection, undefined, options, callbacks);
|
||||||
|
if (result.connected) {
|
||||||
|
let existingConnection = connectionManagementService.findExistingConnection(connection);
|
||||||
|
return existingConnection;
|
||||||
|
} else {
|
||||||
|
throw new Error(result.errorMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let existingConnection = connectionManagementService.findExistingConnection(connection);
|
||||||
|
if (options && options.showDashboard) {
|
||||||
|
await connectionManagementService.showDashboard(connection);
|
||||||
|
}
|
||||||
|
return existingConnection;
|
||||||
}
|
}
|
||||||
} else {
|
} catch (e) {
|
||||||
let existingConnection = connectionManagementService.findExistingConnection(connection);
|
// Since the connection dialog handles connection errors, we don't need to do anything here
|
||||||
if (options && options.showDashboard) {
|
throw new AsyncTreeConnectionError(getErrorMessage(e), connection);
|
||||||
await connectionManagementService.showDashboard(connection);
|
|
||||||
}
|
|
||||||
return existingConnection;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,6 +253,7 @@ export class TreeUpdateUtils {
|
|||||||
objectExplorerService: IObjectExplorerService,
|
objectExplorerService: IObjectExplorerService,
|
||||||
tree: AsyncServerTree | ITree | undefined,
|
tree: AsyncServerTree | ITree | undefined,
|
||||||
requestStatus?: ObjectExplorerRequestStatus | undefined): Promise<boolean> {
|
requestStatus?: ObjectExplorerRequestStatus | undefined): Promise<boolean> {
|
||||||
|
|
||||||
const connectedConnection = await TreeUpdateUtils.connectIfNotConnected(connection, options, connectionManagementService, tree);
|
const connectedConnection = await TreeUpdateUtils.connectIfNotConnected(connection, options, connectionManagementService, tree);
|
||||||
if (connectedConnection) {
|
if (connectedConnection) {
|
||||||
// append group ID and original display name to build unique OE session ID
|
// append group ID and original display name to build unique OE session ID
|
||||||
@@ -305,28 +310,18 @@ export class TreeUpdateUtils {
|
|||||||
return rootNode.children ?? [];
|
return rootNode.children ?? [];
|
||||||
} else {
|
} else {
|
||||||
const options: IConnectionCompletionOptions = {
|
const options: IConnectionCompletionOptions = {
|
||||||
|
params: undefined,
|
||||||
saveTheConnection: true,
|
saveTheConnection: true,
|
||||||
showConnectionDialogOnError: true,
|
showConnectionDialogOnError: true,
|
||||||
showFirewallRuleOnError: true,
|
showFirewallRuleOnError: true,
|
||||||
showDashboard: false
|
showDashboard: false
|
||||||
};
|
};
|
||||||
const expansionTimeoutValueSec = configurationService.getValue<number>(NODE_EXPANSION_CONFIG);
|
|
||||||
// Need to wait for the OE service to update its nodes in order to resolve the children
|
// Need to wait for the OE service to update its nodes in order to resolve the children
|
||||||
const nodesUpdatedPromise = new Promise<void>((resolve, reject) => {
|
const nodesUpdatedPromise = new Promise<void>((resolve, reject) => {
|
||||||
// Clean up timeout and listener
|
// Clean up timeout and listener
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
clearTimeout(nodeUpdateTimer);
|
|
||||||
nodesUpdatedListener.dispose();
|
nodesUpdatedListener.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the node update takes too long, reject the promise
|
|
||||||
const nodeUpdateTimeout = () => {
|
|
||||||
cleanup();
|
|
||||||
reject(new Error(nls.localize('objectExplorerTimeout', "Object Explorer expansion timed out for '{0}'", connection.databaseName)));
|
|
||||||
}
|
|
||||||
const nodeUpdateTimer = setTimeout(nodeUpdateTimeout, expansionTimeoutValueSec * 1000);
|
|
||||||
|
|
||||||
|
|
||||||
const nodesUpdatedListener = objectExplorerService.onUpdateObjectExplorerNodes(e => {
|
const nodesUpdatedListener = objectExplorerService.onUpdateObjectExplorerNodes(e => {
|
||||||
if (e.connection && e.connection.id === connection.id) {
|
if (e.connection && e.connection.id === connection.id) {
|
||||||
if (e.errorMessage) {
|
if (e.errorMessage) {
|
||||||
|
|||||||
@@ -288,9 +288,7 @@ suite('SQL Object Explorer Service tests', () => {
|
|||||||
connectionManagementService.object,
|
connectionManagementService.object,
|
||||||
new NullAdsTelemetryService(),
|
new NullAdsTelemetryService(),
|
||||||
capabilitiesService,
|
capabilitiesService,
|
||||||
logService,
|
logService);
|
||||||
configurationService.object,
|
|
||||||
notificationService.object);
|
|
||||||
|
|
||||||
objectExplorerService.registerProvider(mssqlProviderName, sqlOEProvider.object);
|
objectExplorerService.registerProvider(mssqlProviderName, sqlOEProvider.object);
|
||||||
sqlOEProvider.setup(x => x.createNewSession(TypeMoq.It.is<azdata.ConnectionInfo>(x => x.options['serverName'] === connection.serverName))).returns(() => new Promise<any>((resolve) => {
|
sqlOEProvider.setup(x => x.createNewSession(TypeMoq.It.is<azdata.ConnectionInfo>(x => x.options['serverName'] === connection.serverName))).returns(() => new Promise<any>((resolve) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user