Fix #4089 Linked account cancel (#5347)

VSCode serialization changed rejection handling to only serialize errors, which caused things to break
- Changed to return either account info or a cancel message in the resolve
- Rewrote to use promises. Tracking how to return canceled through 4+ thenables was way trickier than just using a promise
- Updated unit tests to handle new scenario
- Tested integration tests, realized they a) didn't run and b) didn't passed. 
  - Added vscode dev dependency to fix run issue
  - Fixed tests to account for behavior changes in tree state.
This commit is contained in:
Kevin Cunnane
2019-05-06 09:13:03 -07:00
committed by GitHub
parent b9d985b663
commit 022761aa4b
11 changed files with 1130 additions and 145 deletions

View File

@@ -36,11 +36,11 @@ export class ExtHostAccountManagement extends ExtHostAccountManagementShape {
return this._withProvider(handle, (provider: azdata.AccountProvider) => provider.initialize(restoredAccounts));
}
public $prompt(handle: number): Thenable<azdata.Account> {
public $prompt(handle: number): Thenable<azdata.Account | azdata.PromptFailedResult> {
return this._withProvider(handle, (provider: azdata.AccountProvider) => provider.prompt());
}
public $refresh(handle: number, account: azdata.Account): Thenable<azdata.Account> {
public $refresh(handle: number, account: azdata.Account): Thenable<azdata.Account | azdata.PromptFailedResult> {
return this._withProvider(handle, (provider: azdata.AccountProvider) => provider.refresh(account));
}

View File

@@ -81,10 +81,10 @@ export class MainThreadAccountManagement implements MainThreadAccountManagementS
initialize(restoredAccounts: azdata.Account[]): Thenable<azdata.Account[]> {
return self._proxy.$initialize(handle, restoredAccounts);
},
prompt(): Thenable<azdata.Account> {
prompt(): Thenable<azdata.Account | azdata.PromptFailedResult> {
return self._proxy.$prompt(handle);
},
refresh(account: azdata.Account): Thenable<azdata.Account> {
refresh(account: azdata.Account): Thenable<azdata.Account | azdata.PromptFailedResult> {
return self._proxy.$refresh(handle, account);
}
};

View File

@@ -30,8 +30,8 @@ export abstract class ExtHostAccountManagementShape {
$clear(handle: number, accountKey: azdata.AccountKey): Thenable<void> { throw ni(); }
$getSecurityToken(account: azdata.Account, resource?: azdata.AzureResource): Thenable<{}> { throw ni(); }
$initialize(handle: number, restoredAccounts: azdata.Account[]): Thenable<azdata.Account[]> { throw ni(); }
$prompt(handle: number): Thenable<azdata.Account> { throw ni(); }
$refresh(handle: number, account: azdata.Account): Thenable<azdata.Account> { throw ni(); }
$prompt(handle: number): Thenable<azdata.Account | azdata.PromptFailedResult> { throw ni(); }
$refresh(handle: number, account: azdata.Account): Thenable<azdata.Account | azdata.PromptFailedResult> { throw ni(); }
$accountsChanged(handle: number, accounts: azdata.Account[]): Thenable<void> { throw ni(); }
}

View File

@@ -21,6 +21,7 @@ import { AccountListStatusbarItem } from 'sql/platform/accounts/browser/accountL
import { AccountProviderAddedEventParams, UpdateAccountListEventParams } from 'sql/platform/accounts/common/eventTypes';
import { IAccountManagementService } from 'sql/platform/accounts/common/interfaces';
import { Deferred } from 'sql/base/common/promise';
import { localize } from 'vs/nls';
export class AccountManagementService implements IAccountManagementService {
// CONSTANTS ///////////////////////////////////////////////////////////
@@ -127,30 +128,29 @@ export class AccountManagementService implements IAccountManagementService {
public addAccount(providerId: string): Thenable<void> {
let self = this;
return this.doWithProvider(providerId, (provider) => {
return provider.provider.prompt()
.then(account => self._accountStore.addOrUpdate(account))
.then(result => {
if (result.accountAdded) {
// Add the account to the list
provider.accounts.push(result.changedAccount);
}
if (result.accountModified) {
self.spliceModifiedAccount(provider, result.changedAccount);
}
return this.doWithProvider(providerId, async (provider) => {
let account = await provider.provider.prompt();
if (self.isCanceledResult(account)) {
return;
}
self.fireAccountListUpdate(provider, result.accountAdded);
})
.then(null, err => {
// On error, check to see if the error is because the user cancelled. If so, just ignore
if (err && 'userCancelledSignIn' in err) {
return Promise.resolve();
}
return Promise.reject(err);
});
let result = await self._accountStore.addOrUpdate(account);
if (result.accountAdded) {
// Add the account to the list
provider.accounts.push(result.changedAccount);
}
if (result.accountModified) {
self.spliceModifiedAccount(provider, result.changedAccount);
}
self.fireAccountListUpdate(provider, result.accountAdded);
});
}
private isCanceledResult(result: azdata.Account | azdata.PromptFailedResult): result is azdata.PromptFailedResult {
return (<azdata.PromptFailedResult>result).canceled;
}
/**
* Asks the requested provider to refresh an account
* @param account account to refresh
@@ -159,27 +159,32 @@ export class AccountManagementService implements IAccountManagementService {
public refreshAccount(account: azdata.Account): Thenable<azdata.Account> {
let self = this;
return this.doWithProvider(account.key.providerId, (provider) => {
return provider.provider.refresh(account)
.then(account => self._accountStore.addOrUpdate(account))
.then(result => {
if (result.accountAdded) {
// Add the account to the list
provider.accounts.push(result.changedAccount);
}
if (result.accountModified) {
// Find the updated account and splice the updated on in
let indexToRemove: number = provider.accounts.findIndex(account => {
return account.key.accountId === result.changedAccount.key.accountId;
});
if (indexToRemove >= 0) {
provider.accounts.splice(indexToRemove, 1, result.changedAccount);
}
}
return this.doWithProvider(account.key.providerId, async (provider) => {
let refreshedAccount = await provider.provider.refresh(account);
if (self.isCanceledResult(refreshedAccount)) {
// Pattern here is to throw if this fails. Handled upstream.
throw new Error(localize('refreshFailed', 'Refresh account was canceled by the user'));
} else {
account = refreshedAccount;
}
self.fireAccountListUpdate(provider, result.accountAdded);
return result.changedAccount;
let result = await self._accountStore.addOrUpdate(account);
if (result.accountAdded) {
// Add the account to the list
provider.accounts.push(result.changedAccount);
}
if (result.accountModified) {
// Find the updated account and splice the updated on in
let indexToRemove: number = provider.accounts.findIndex(account => {
return account.key.accountId === result.changedAccount.key.accountId;
});
if (indexToRemove >= 0) {
provider.accounts.splice(indexToRemove, 1, result.changedAccount);
}
}
self.fireAccountListUpdate(provider, result.accountAdded);
return result.changedAccount;
});
}