diff --git a/extensions/azurecore/src/azureResource/tree/accountTreeNode.ts b/extensions/azurecore/src/azureResource/tree/accountTreeNode.ts index aa9ba624a1..9534e4aa23 100644 --- a/extensions/azurecore/src/azureResource/tree/accountTreeNode.ts +++ b/extensions/azurecore/src/azureResource/tree/accountTreeNode.ts @@ -90,12 +90,9 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode } } catch (error) { if (error instanceof AzureResourceCredentialError) { - this.appContext.apiWrapper.showErrorMessage(error.message); - this.appContext.apiWrapper.executeCommand('azure.resource.signin'); - } else { - return [AzureResourceMessageTreeNode.create(AzureResourceErrorMessageUtil.getErrorMessage(error), this)]; } + return [AzureResourceMessageTreeNode.create(AzureResourceErrorMessageUtil.getErrorMessage(error), this)]; } } diff --git a/extensions/azurecore/src/azureResource/tree/treeProvider.ts b/extensions/azurecore/src/azureResource/tree/treeProvider.ts index 7e47191c39..a36365c41c 100644 --- a/extensions/azurecore/src/azureResource/tree/treeProvider.ts +++ b/extensions/azurecore/src/azureResource/tree/treeProvider.ts @@ -32,7 +32,7 @@ export class AzureResourceTreeProvider implements TreeDataProvider, IA return element.getChildren(true); } - if (!this.isSystemInitialized) { + if (!this.isSystemInitialized && !this._loadingTimer) { this._loadingTimer = setInterval(async () => { try { // Call sqlops.accounts.getAllAccounts() to determine whether the system has been initialized. diff --git a/extensions/azurecore/src/azureResource/utils.ts b/extensions/azurecore/src/azureResource/utils.ts index a3c7cedbc0..b907d58493 100644 --- a/extensions/azurecore/src/azureResource/utils.ts +++ b/extensions/azurecore/src/azureResource/utils.ts @@ -40,4 +40,57 @@ export function generateGuid(): string { let clockSequenceHi: string = hexValues[8 + (Math.random() * 4) | 0]; return oct.substr(0, 8) + '-' + oct.substr(9, 4) + '-4' + oct.substr(13, 3) + '-' + clockSequenceHi + oct.substr(16, 3) + '-' + oct.substr(19, 12); /* tslint:enable:no-bitwise */ +} + +export function equals(one: any, other: any): boolean { + if (one === other) { + return true; + } + if (one === null || one === undefined || other === null || other === undefined) { + return false; + } + if (typeof one !== typeof other) { + return false; + } + if (typeof one !== 'object') { + return false; + } + if ((Array.isArray(one)) !== (Array.isArray(other))) { + return false; + } + + let i: number; + let key: string; + + if (Array.isArray(one)) { + if (one.length !== other.length) { + return false; + } + for (i = 0; i < one.length; i++) { + if (!equals(one[i], other[i])) { + return false; + } + } + } else { + const oneKeys: string[] = []; + + for (key in one) { + oneKeys.push(key); + } + oneKeys.sort(); + const otherKeys: string[] = []; + for (key in other) { + otherKeys.push(key); + } + otherKeys.sort(); + if (!equals(oneKeys, otherKeys)) { + return false; + } + for (i = 0; i < oneKeys.length; i++) { + if (!equals(one[oneKeys[i]], other[oneKeys[i]])) { + return false; + } + } + } + return true; } \ No newline at end of file diff --git a/extensions/azurecore/src/controllers/azureResourceController.ts b/extensions/azurecore/src/controllers/azureResourceController.ts index 8778d29908..fb01d0f4db 100644 --- a/extensions/azurecore/src/controllers/azureResourceController.ts +++ b/extensions/azurecore/src/controllers/azureResourceController.ts @@ -25,6 +25,7 @@ import { AzureResourceTenantService } from '../azureResource/services/tenantServ import { registerAzureResourceDatabaseServerCommands } from '../azureResource/providers/databaseServer/commands'; import { registerAzureResourceDatabaseCommands } from '../azureResource/providers/database/commands'; +import { equals } from '../azureResource/utils'; export default class AzureResourceController extends ControllerBase { public activate(): Promise { @@ -37,7 +38,16 @@ export default class AzureResourceController extends ControllerBase { const azureResourceTree = new AzureResourceTreeProvider(this.appContext); this.extensionContext.subscriptions.push(this.apiWrapper.registerTreeDataProvider('azureResourceExplorer', azureResourceTree)); - this.appContext.getService(AzureResourceServiceNames.accountService).onDidChangeAccounts((e: DidChangeAccountsParams) => { azureResourceTree.notifyNodeChanged(undefined); }); + let previousAccounts = undefined; + this.appContext.getService(AzureResourceServiceNames.accountService).onDidChangeAccounts((e: DidChangeAccountsParams) => { + // the onDidChangeAccounts event will trigger in many cases where the accounts didn't actually change + // the notifyNodeChanged event triggers a refresh which triggers a getChildren which can trigger this callback + // this below check short-circuits the infinite callback loop + if (!equals(e.accounts, previousAccounts)) { + azureResourceTree.notifyNodeChanged(undefined); + } + previousAccounts = e.accounts; + }); registerAzureResourceCommands(this.appContext, azureResourceTree);