diff --git a/src/sql/platform/accounts/browser/accountListRenderer.ts b/src/sql/platform/accounts/browser/accountListRenderer.ts index f82bf763f9..c4d8465db0 100644 --- a/src/sql/platform/accounts/browser/accountListRenderer.ts +++ b/src/sql/platform/accounts/browser/accountListRenderer.ts @@ -33,26 +33,29 @@ export class AccountListDelegate implements IListVirtualDelegate } } -export interface AccountListTemplate { +export interface AccountPickerListTemplate { root: HTMLElement; icon: HTMLElement; badgeContent: HTMLElement; contextualDisplayName: HTMLElement; label: HTMLElement; displayName: HTMLElement; - content?: HTMLElement; - actions?: ActionBar; } -export class AccountPickerListRenderer implements IListRenderer { +export interface AccountListTemplate extends AccountPickerListTemplate { + content: HTMLElement; + actions: ActionBar; +} + +export class AccountPickerListRenderer implements IListRenderer { public static TEMPLATE_ID = 'accountListRenderer'; public get templateId(): string { return AccountPickerListRenderer.TEMPLATE_ID; } - public renderTemplate(container: HTMLElement): AccountListTemplate { - const tableTemplate: AccountListTemplate = Object.create(null); + public renderTemplate(container: HTMLElement): AccountPickerListTemplate { + const tableTemplate: AccountPickerListTemplate = Object.create(null); const badge = DOM.$('div.badge'); tableTemplate.root = DOM.append(container, DOM.$('div.list-row.account-picker-list')); tableTemplate.icon = DOM.append(tableTemplate.root, DOM.$('div.icon')); @@ -64,7 +67,7 @@ export class AccountPickerListRenderer implements IListRenderer; public get addAccountStartEvent(): Event { return this._addAccountStartEmitter.event; } - private _onAccountSelectionChangeEvent: Emitter; - public get onAccountSelectionChangeEvent(): Event { return this._onAccountSelectionChangeEvent.event; } + private _onAccountSelectionChangeEvent: Emitter; + public get onAccountSelectionChangeEvent(): Event { return this._onAccountSelectionChangeEvent.event; } constructor( private _providerId: string, @@ -145,7 +145,7 @@ export class AccountPicker extends Disposable { } // PRIVATE HELPERS ///////////////////////////////////////////////////// - private onAccountSelectionChange(account: azdata.Account) { + private onAccountSelectionChange(account: azdata.Account | undefined) { this.viewModel.selectedAccount = account; if (account && account.isStale) { this._refreshAccountAction.account = account; @@ -157,7 +157,7 @@ export class AccountPicker extends Disposable { this._onAccountSelectionChangeEvent.fire(account); } - private renderLabel(container: HTMLElement): IDisposable { + private renderLabel(container: HTMLElement): IDisposable | null { if (container.hasChildNodes()) { for (let i = 0; i < container.childNodes.length; i++) { container.removeChild(container.childNodes.item(i)); @@ -189,7 +189,7 @@ export class AccountPicker extends Disposable { const row = DOM.append(container, DOM.$('div.no-account-container')); row.innerText = AddAccountAction.LABEL + '...'; } - return undefined; + return null; } private updateAccountList(accounts: azdata.Account[]): void { @@ -197,7 +197,7 @@ export class AccountPicker extends Disposable { const selectedElements = this._accountList.getSelectedElements(); // find selected index - let selectedIndex: number; + let selectedIndex: number | undefined; if (selectedElements.length > 0 && accounts.length > 0) { selectedIndex = accounts.findIndex((account) => { return (account.key.accountId === selectedElements[0].key.accountId); diff --git a/src/sql/platform/accounts/browser/accountPickerService.ts b/src/sql/platform/accounts/browser/accountPickerService.ts index cc18130b23..ea9fe0103b 100644 --- a/src/sql/platform/accounts/browser/accountPickerService.ts +++ b/src/sql/platform/accounts/browser/accountPickerService.ts @@ -25,8 +25,8 @@ export class AccountPickerService implements IAccountPickerService { private _addAccountStartEmitter: Emitter; public get addAccountStartEvent(): Event { return this._addAccountStartEmitter.event; } - private _onAccountSelectionChangeEvent: Emitter; - public get onAccountSelectionChangeEvent(): Event { return this._onAccountSelectionChangeEvent.event; } + private _onAccountSelectionChangeEvent: Emitter; + public get onAccountSelectionChangeEvent(): Event { return this._onAccountSelectionChangeEvent.event; } constructor( @IInstantiationService private _instantiationService: IInstantiationService @@ -41,7 +41,7 @@ export class AccountPickerService implements IAccountPickerService { /** * Get selected account */ - public get selectedAccount(): azdata.Account { + public get selectedAccount(): azdata.Account | undefined { return this._accountPicker.viewModel.selectedAccount; } diff --git a/src/sql/platform/accounts/browser/autoOAuthDialogController.ts b/src/sql/platform/accounts/browser/autoOAuthDialogController.ts index ebc0c084da..a963edbfeb 100644 --- a/src/sql/platform/accounts/browser/autoOAuthDialogController.ts +++ b/src/sql/platform/accounts/browser/autoOAuthDialogController.ts @@ -14,7 +14,7 @@ import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMess export class AutoOAuthDialogController { // MEMBER VARIABLES //////////////////////////////////////////////////// private _autoOAuthDialog: AutoOAuthDialog; - private _providerId: string; + private _providerId?: string; private _userCode: string; private _uri: string; @@ -22,15 +22,13 @@ export class AutoOAuthDialogController { @IInstantiationService private _instantiationService: IInstantiationService, @IAccountManagementService private _accountManagementService: IAccountManagementService, @IErrorMessageService private _errorMessageService: IErrorMessageService - ) { - this._providerId = null; - } + ) { } /** * Open auto OAuth dialog */ public openAutoOAuthDialog(providerId: string, title: string, message: string, userCode: string, uri: string): Thenable { - if (this._providerId !== null) { + if (this._providerId !== undefined) { // If a oauth flyout is already open, return an error const errorMessage = localize('oauthFlyoutIsAlreadyOpen', "Cannot start auto OAuth. An auto OAuth is already in progress."); this._errorMessageService.showDialog(Severity.Error, '', errorMessage); @@ -60,16 +58,16 @@ export class AutoOAuthDialogController { */ public closeAutoOAuthDialog(): void { this._autoOAuthDialog.close(); - this._providerId = null; + this._providerId = undefined; } // PRIVATE HELPERS ///////////////////////////////////////////////////// private handleOnCancel(): void { - this._accountManagementService.cancelAutoOAuthDeviceCode(this._providerId); + this._accountManagementService.cancelAutoOAuthDeviceCode(this._providerId!); // this should be always true } private handleOnClose(): void { - this._providerId = null; + this._providerId = undefined; } private handleOnAddAccount(): void { diff --git a/src/sql/platform/accounts/browser/firewallRuleDialog.ts b/src/sql/platform/accounts/browser/firewallRuleDialog.ts index 76266a0aeb..8a7cfca923 100644 --- a/src/sql/platform/accounts/browser/firewallRuleDialog.ts +++ b/src/sql/platform/accounts/browser/firewallRuleDialog.ts @@ -278,7 +278,7 @@ export class FirewallRuleDialog extends Modal { } } - public onAccountSelectionChange(account: azdata.Account): void { + public onAccountSelectionChange(account: azdata.Account | undefined): void { this.viewModel.selectedAccount = account; if (account && !account.isStale) { this._createButton.enabled = true; diff --git a/src/sql/platform/accounts/browser/firewallRuleDialogController.ts b/src/sql/platform/accounts/browser/firewallRuleDialogController.ts index 31cd5af08a..bc0ecf3a7c 100644 --- a/src/sql/platform/accounts/browser/firewallRuleDialogController.ts +++ b/src/sql/platform/accounts/browser/firewallRuleDialogController.ts @@ -57,31 +57,28 @@ export class FirewallRuleDialogController { this._errorMessageService.showDialog(Severity.Error, this._addAccountErrorTitle, message); } - private handleOnCreateFirewallRule(): void { + private async handleOnCreateFirewallRule(): Promise { const resourceProviderId = this._resourceProviderId; - - this._accountManagementService.getSecurityToken(this._firewallRuleDialog.viewModel.selectedAccount, AzureResource.ResourceManagement).then(tokenMappings => { - let firewallRuleInfo: azdata.FirewallRuleInfo = { + try { + const securityTokenMappings = await this._accountManagementService.getSecurityToken(this._firewallRuleDialog.viewModel.selectedAccount!, AzureResource.ResourceManagement); + const firewallRuleInfo: azdata.FirewallRuleInfo = { startIpAddress: this._firewallRuleDialog.viewModel.isIPAddressSelected ? this._firewallRuleDialog.viewModel.defaultIPAddress : this._firewallRuleDialog.viewModel.fromSubnetIPRange, endIpAddress: this._firewallRuleDialog.viewModel.isIPAddressSelected ? this._firewallRuleDialog.viewModel.defaultIPAddress : this._firewallRuleDialog.viewModel.toSubnetIPRange, serverName: this._connection.serverName, - securityTokenMappings: tokenMappings + securityTokenMappings }; - this._resourceProviderService.createFirewallRule(this._firewallRuleDialog.viewModel.selectedAccount, firewallRuleInfo, resourceProviderId).then(createFirewallRuleResponse => { - if (createFirewallRuleResponse.result) { - this._firewallRuleDialog.close(); - this._deferredPromise.resolve(true); - } else { - this._errorMessageService.showDialog(Severity.Error, this._firewallRuleErrorTitle, createFirewallRuleResponse.errorMessage); - } - this._firewallRuleDialog.onServiceComplete(); - }, error => { - this.showError(error); - }); - }, error => { - this.showError(error); - }); + const response = await this._resourceProviderService.createFirewallRule(this._firewallRuleDialog.viewModel.selectedAccount!, firewallRuleInfo, resourceProviderId); + if (response.result) { + this._firewallRuleDialog.close(); + this._deferredPromise.resolve(true); + } else { + this._errorMessageService.showDialog(Severity.Error, this._firewallRuleErrorTitle, response.errorMessage); + } + this._firewallRuleDialog.onServiceComplete(); + } catch (e) { + this.showError(e); + } } private showError(error: any): void { diff --git a/src/sql/platform/accounts/common/accountPicker.ts b/src/sql/platform/accounts/common/accountPicker.ts index 160fce0727..2e4e52ba1c 100644 --- a/src/sql/platform/accounts/common/accountPicker.ts +++ b/src/sql/platform/accounts/common/accountPicker.ts @@ -15,6 +15,6 @@ export interface IAccountPickerService { addAccountCompleteEvent: Event; addAccountErrorEvent: Event; addAccountStartEvent: Event; - onAccountSelectionChangeEvent: Event; - selectedAccount: azdata.Account; + onAccountSelectionChangeEvent: Event; + selectedAccount: azdata.Account | undefined; } diff --git a/src/sql/platform/accounts/common/accountPickerViewModel.ts b/src/sql/platform/accounts/common/accountPickerViewModel.ts index a61177b54d..0ed5936a4f 100644 --- a/src/sql/platform/accounts/common/accountPickerViewModel.ts +++ b/src/sql/platform/accounts/common/accountPickerViewModel.ts @@ -17,7 +17,7 @@ export class AccountPickerViewModel { private _updateAccountListEmitter: Emitter; public get updateAccountListEvent(): Event { return this._updateAccountListEmitter.event; } - public selectedAccount: azdata.Account; + public selectedAccount: azdata.Account | undefined; constructor( private _providerId: string, diff --git a/src/sql/platform/accounts/common/accountStore.ts b/src/sql/platform/accounts/common/accountStore.ts index 9e7b2aeedf..953b117886 100644 --- a/src/sql/platform/accounts/common/accountStore.ts +++ b/src/sql/platform/accounts/common/accountStore.ts @@ -89,7 +89,7 @@ export default class AccountStore implements IAccountStore { activeOperation = activeOperation.then(op); // Add a catch at the end to make sure we can continue after any errors - activeOperation = activeOperation.then(null, (err) => { + activeOperation = activeOperation.then(undefined, (err) => { // TODO: Log the error }); @@ -107,7 +107,7 @@ export default class AccountStore implements IAccountStore { accountAdded: false, accountModified: false, accountRemoved: false, - changedAccount: null, + changedAccount: undefined, updatedAccounts: accounts }; } @@ -135,7 +135,7 @@ export default class AccountStore implements IAccountStore { accountAdded: false, accountModified: false, accountRemoved: match >= 0, - changedAccount: null, + changedAccount: undefined, updatedAccounts: accounts }; } @@ -149,7 +149,7 @@ export default class AccountStore implements IAccountStore { accountAdded: false, accountModified: false, accountRemoved: false, - changedAccount: null, + changedAccount: undefined, updatedAccounts: accounts }; } diff --git a/src/sql/platform/accounts/common/eventTypes.ts b/src/sql/platform/accounts/common/eventTypes.ts index 2736a8fc29..02c66342b9 100644 --- a/src/sql/platform/accounts/common/eventTypes.ts +++ b/src/sql/platform/accounts/common/eventTypes.ts @@ -22,7 +22,7 @@ export interface AccountAdditionResult { /** * The account that was added/updated (with any updates applied) */ - changedAccount: azdata.Account; + changedAccount: azdata.Account | undefined; } /** diff --git a/src/sql/platform/accounts/common/firewallRuleViewModel.ts b/src/sql/platform/accounts/common/firewallRuleViewModel.ts index 9fdd40ab2d..68afa61b22 100644 --- a/src/sql/platform/accounts/common/firewallRuleViewModel.ts +++ b/src/sql/platform/accounts/common/firewallRuleViewModel.ts @@ -10,7 +10,7 @@ import * as azdata from 'azdata'; */ export class FirewallRuleViewModel { public isIPAddressSelected: boolean; - public selectedAccount: azdata.Account; + public selectedAccount: azdata.Account | undefined; private _defaultIPAddress: string; private _defaultFromSubnetIPRange: string; diff --git a/src/sql/platform/accounts/test/browser/accountDialogController.test.ts b/src/sql/platform/accounts/test/browser/accountDialogController.test.ts index 3af867243f..d31568634e 100644 --- a/src/sql/platform/accounts/test/browser/accountDialogController.test.ts +++ b/src/sql/platform/accounts/test/browser/accountDialogController.test.ts @@ -20,7 +20,7 @@ suite('Account Management Dialog Controller Tests', () => { test('Open Account Dialog - Dialog Doesn\'t Exist', () => { // Setup: Create instance of the controller let instantiationService = createInstantiationService(); - let controller = new AccountDialogController(instantiationService, undefined); + let controller = new AccountDialogController(instantiationService, undefined!); assert.strictEqual(controller.accountDialog, undefined); // If: I open the account dialog when one hasn't been opened @@ -34,7 +34,7 @@ suite('Account Management Dialog Controller Tests', () => { test('Open Account Dialog - Dialog Exists', () => { // Setup: Create instance of the controller with an account dialog already loaded let instantiationService = createInstantiationService(); - let controller = new AccountDialogController(instantiationService, undefined); + let controller = new AccountDialogController(instantiationService, undefined!); controller.openAccountDialog(); let accountDialog = controller.accountDialog; @@ -86,7 +86,7 @@ function createInstantiationService(addAccountFailureEmitter?: Emitter): .returns(() => undefined); // Create a mock account dialog - let accountDialog = new AccountDialog(null, null, instantiationService.object, null, null, null, null, new MockContextKeyService(), null, undefined, undefined); + let accountDialog = new AccountDialog(undefined!, undefined!, instantiationService.object, undefined!, undefined!, undefined!, undefined!, new MockContextKeyService(), undefined!, undefined!, undefined!); let mockAccountDialog = TypeMoq.Mock.ofInstance(accountDialog); mockAccountDialog.setup(x => x.onAddAccountErrorEvent) .returns(() => { return addAccountFailureEmitter ? addAccountFailureEmitter.event : mockEvent.event; }); diff --git a/src/sql/platform/accounts/test/browser/accountPickerService.test.ts b/src/sql/platform/accounts/test/browser/accountPickerService.test.ts index 2290cf6763..44c79da6fc 100644 --- a/src/sql/platform/accounts/test/browser/accountPickerService.test.ts +++ b/src/sql/platform/accounts/test/browser/accountPickerService.test.ts @@ -13,6 +13,7 @@ import { AccountPickerService } from 'sql/platform/accounts/browser/accountPicke import { AccountPickerViewModel } from 'sql/platform/accounts/common/accountPickerViewModel'; import { TestAccountManagementService } from 'sql/platform/accounts/test/common/testAccountManagementService'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; +import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; // SUITE STATE ///////////////////////////////////////////////////////////// let mockAddAccountCompleteEmitter: Emitter; @@ -98,7 +99,8 @@ function createInstantiationService(): InstantiationService { .returns(() => mockAccountViewModel.object); // Create a mock account picker - let accountPicker = new AccountPicker(null, null, instantiationService.object, null); + + let accountPicker = new AccountPicker('provider', new TestThemeService(), instantiationService.object, undefined!); let mockAccountDialog = TypeMoq.Mock.ofInstance(accountPicker); mockAccountDialog.setup(x => x.addAccountCompleteEvent) diff --git a/src/sql/platform/accounts/test/browser/autoOAuthDialogController.test.ts b/src/sql/platform/accounts/test/browser/autoOAuthDialogController.test.ts index f4036f52ec..ca71d09fb5 100644 --- a/src/sql/platform/accounts/test/browser/autoOAuthDialogController.test.ts +++ b/src/sql/platform/accounts/test/browser/autoOAuthDialogController.test.ts @@ -37,7 +37,7 @@ suite('auto OAuth dialog controller tests', () => { mockOnCloseEvent = new Emitter(); // Create a mock auto OAuth dialog - let autoOAuthDialog = new AutoOAuthDialog(null, null, null, null, new MockContextKeyService(), null, undefined, undefined); + let autoOAuthDialog = new AutoOAuthDialog(undefined!, undefined!, undefined!, undefined!, new MockContextKeyService(), undefined!, undefined!, undefined!); mockAutoOAuthDialog = TypeMoq.Mock.ofInstance(autoOAuthDialog); mockAutoOAuthDialog.setup(x => x.onCancel).returns(() => mockOnCancelEvent.event); diff --git a/src/sql/platform/accounts/test/browser/firewallRuleDialogController.test.ts b/src/sql/platform/accounts/test/browser/firewallRuleDialogController.test.ts index e2c8887666..be08d35571 100644 --- a/src/sql/platform/accounts/test/browser/firewallRuleDialogController.test.ts +++ b/src/sql/platform/accounts/test/browser/firewallRuleDialogController.test.ts @@ -5,7 +5,7 @@ import * as azdata from 'azdata'; import * as TypeMoq from 'typemoq'; -import { Emitter } from 'vs/base/common/event'; +import { Emitter, Event } from 'vs/base/common/event'; import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { FirewallRuleDialog } from 'sql/platform/accounts/browser/firewallRuleDialog'; import { FirewallRuleViewModel } from 'sql/platform/accounts/common/firewallRuleViewModel'; @@ -60,7 +60,7 @@ suite('Firewall rule dialog controller tests', () => { .returns(() => mockFirewallRuleViewModel.object); // Create a mock account picker - let firewallRuleDialog = new FirewallRuleDialog(null, null, null, instantiationService.object, null, null, new MockContextKeyService(), null, null, undefined, undefined); + let firewallRuleDialog = new FirewallRuleDialog(undefined!, undefined!, undefined!, instantiationService.object, undefined!, undefined!, new MockContextKeyService(), undefined!, undefined!, undefined!, undefined!); mockFirewallRuleDialog = TypeMoq.Mock.ofInstance(firewallRuleDialog); let mockEvent = new Emitter(); @@ -87,12 +87,12 @@ suite('Firewall rule dialog controller tests', () => { savePassword: true, groupFullName: 'g2/g2-2', groupId: 'group id', - getOptionsKey: undefined, - matches: undefined, + getOptionsKey: () => '', + matches: () => false, providerName: mssqlProviderName, options: {}, saveProfile: true, - id: undefined + id: '' }; }); @@ -103,7 +103,7 @@ suite('Firewall rule dialog controller tests', () => { mockErrorMessageService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())); // ... Create instance of the controller with an opened dialog - let controller = new FirewallRuleDialogController(instantiationService.object, null, null, mockErrorMessageService.object); + let controller = new FirewallRuleDialogController(instantiationService.object, undefined!, undefined!, mockErrorMessageService.object); controller.openFirewallRuleDialog(connectionProfile, IPAddress, 'resourceID'); // If: The firewall rule dialog reports a failure @@ -114,7 +114,7 @@ suite('Firewall rule dialog controller tests', () => { mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); }); - test('create firewall rule success', (done) => { + test('create firewall rule success', async () => { let deferredPromise = new Deferred(); mockFirewallRuleDialog.setup(x => x.onServiceComplete()) @@ -129,24 +129,22 @@ suite('Firewall rule dialog controller tests', () => { let mockResourceProvider = getMockResourceProvider(true, { result: true, errorMessage: '' }); // ... Create instance of the controller with an opened dialog - let controller = new FirewallRuleDialogController(instantiationService.object, mockResourceProvider.object, mockAccountManagementService.object, null); + let controller = new FirewallRuleDialogController(instantiationService.object, mockResourceProvider.object, mockAccountManagementService.object, undefined!); controller.openFirewallRuleDialog(connectionProfile, IPAddress, 'resourceID'); // If: The firewall rule dialog's create firewall rule get fired mockOnCreateFirewallRule.fire(); // Then: it should get security token from account management service and call create firewall rule in resource provider - deferredPromise.promise.then(() => { - mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); - mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); - mockFirewallRuleDialog.verify(x => x.close(), TypeMoq.Times.once()); - mockFirewallRuleDialog.verify(x => x.onServiceComplete(), TypeMoq.Times.once()); - done(); - }); + await deferredPromise; + mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); + mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); + mockFirewallRuleDialog.verify(x => x.close(), TypeMoq.Times.once()); + mockFirewallRuleDialog.verify(x => x.onServiceComplete(), TypeMoq.Times.once()); }); - test('create firewall rule fails during getSecurity', (done) => { - let deferredPromise = new Deferred(); + test('create firewall rule fails during getSecurity', async () => { + let deferredPromise = new Deferred<{}>(); // ... Create a mock instance of the error message service let mockErrorMessageService = getMockErrorMessageService(deferredPromise); @@ -165,16 +163,14 @@ suite('Firewall rule dialog controller tests', () => { mockOnCreateFirewallRule.fire(); // Then: it should get security token from account management service and an error dialog should have been opened - deferredPromise.promise.then(() => { - mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); - mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); - mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.never()); - done(); - }); + await deferredPromise; + mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); + mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); + mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.never()); }); - test('create firewall rule fails during createFirewallRule in ResourceProvider - result is false', (done) => { - let deferredPromise = new Deferred(); + test('create firewall rule fails during createFirewallRule in ResourceProvider - result is false', async () => { + let deferredPromise = new Deferred<{}>(); // ... Create a mock instance of the error message service let mockErrorMessageService = getMockErrorMessageService(deferredPromise); @@ -193,16 +189,15 @@ suite('Firewall rule dialog controller tests', () => { mockOnCreateFirewallRule.fire(); // Then: it should get security token from account management service and an error dialog should have been opened - deferredPromise.promise.then(() => { - mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); - mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); - mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); - done(); - }); + await deferredPromise; + + mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); + mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); + mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); }); - test('create firewall rule fails during createFirewallRule in ResourceProvider - reject promise', (done) => { - let deferredPromise = new Deferred(); + test('create firewall rule fails during createFirewallRule in ResourceProvider - reject promise', async () => { + let deferredPromise = new Deferred<{}>(); // ... Create a mock instance of the error message service let mockErrorMessageService = getMockErrorMessageService(deferredPromise); @@ -221,12 +216,10 @@ suite('Firewall rule dialog controller tests', () => { mockOnCreateFirewallRule.fire(); // Then: it should get security token from account management service and an error dialog should have been opened - deferredPromise.promise.then(() => { - mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); - mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); - mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); - done(); - }); + await deferredPromise; + mockAccountManagementService.verify(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); + mockResourceProvider.verify(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); + mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); }); }); @@ -234,7 +227,7 @@ function getMockAccountManagementService(resolveSecurityToken: boolean): TypeMoq let accountManagementTestService = new TestAccountManagementService(); let mockAccountManagementService = TypeMoq.Mock.ofInstance(accountManagementTestService); mockAccountManagementService.setup(x => x.getSecurityToken(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(() => resolveSecurityToken ? Promise.resolve({}) : Promise.reject(null).then()); + .returns(() => resolveSecurityToken ? Promise.resolve({}) : Promise.reject(null)); return mockAccountManagementService; } @@ -242,7 +235,7 @@ function getMockResourceProvider(resolveCreateFirewallRule: boolean, response?: let resourceProviderStub = new TestResourceProvider(); let mockResourceProvider = TypeMoq.Mock.ofInstance(resourceProviderStub); mockResourceProvider.setup(x => x.createFirewallRule(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(() => resolveCreateFirewallRule ? Promise.resolve(response) : Promise.reject(null).then()); + .returns(() => resolveCreateFirewallRule ? Promise.resolve(response) : Promise.reject(null)); return mockResourceProvider; } diff --git a/src/sql/platform/accounts/test/common/accountStore.test.ts b/src/sql/platform/accounts/test/common/accountStore.test.ts index c7df765a6c..c016198e8b 100644 --- a/src/sql/platform/accounts/test/common/accountStore.test.ts +++ b/src/sql/platform/accounts/test/common/accountStore.test.ts @@ -21,7 +21,7 @@ suite('Account Store Tests', () => { // ... I should have gotten back a result indicating the account was added assert.ok(result.accountAdded); assert.ok(!result.accountModified); - assertAccountEqual(result.changedAccount, account1); + assertAccountEqual(result.changedAccount!, account1); // ... The memento should have been initialized and account added assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY])); @@ -47,7 +47,7 @@ suite('Account Store Tests', () => { // ... I should have gotten back a result indicating the account was added assert.ok(result.accountAdded); assert.ok(!result.accountModified); - assertAccountEqual(result.changedAccount, account1); + assertAccountEqual(result.changedAccount!, account1); // ... The memento should have the account added assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY])); @@ -77,7 +77,7 @@ suite('Account Store Tests', () => { // ... I should have gotten back a result indicating the account was updated assert.ok(result.accountModified); assert.ok(!result.accountAdded); - assertAccountEqual(result.changedAccount, param); + assertAccountEqual(result.changedAccount!, param); // ... The memento should have been initialized and account updated assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY])); diff --git a/src/sql/platform/accounts/test/common/testAccountManagementService.ts b/src/sql/platform/accounts/test/common/testAccountManagementService.ts index 8a7489f5c4..498c891b6d 100644 --- a/src/sql/platform/accounts/test/common/testAccountManagementService.ts +++ b/src/sql/platform/accounts/test/common/testAccountManagementService.ts @@ -11,20 +11,20 @@ import { AccountProviderAddedEventParams, UpdateAccountListEventParams } from 's export class TestAccountManagementService implements IAccountManagementService { _serviceBrand: any; - public get addAccountProviderEvent(): Event { return () => { return undefined; }; } - public get removeAccountProviderEvent(): Event { return () => { return undefined; }; } - public get updateAccountListEvent(): Event { return () => { return undefined; }; } + public get addAccountProviderEvent(): Event { return Event.None; } + public get removeAccountProviderEvent(): Event { return Event.None; } + public get updateAccountListEvent(): Event { return Event.None; } accountUpdated(account: azdata.Account): Thenable { - return undefined; + return Promise.resolve(); } addAccount(providerId: string): Thenable { - return undefined; + return Promise.resolve(); } beginAutoOAuthDeviceCode(title: string, message: string, userCode: string, uri: string): Thenable { - return undefined; + return Promise.resolve(); } cancelAutoOAuthDeviceCode(providerId: string): void { @@ -40,27 +40,27 @@ export class TestAccountManagementService implements IAccountManagementService { } getAccountProviderMetadata(): Thenable { - return undefined; + return Promise.resolve([]); } getAccountsForProvider(providerId: string): Thenable { - return undefined; + return Promise.resolve([]); } getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Thenable<{}> { - return undefined; + return Promise.resolve([]); } removeAccount(accountKey: azdata.AccountKey): Thenable { - return undefined; + throw new Error('Method not implemented'); } refreshAccount(account: azdata.Account): Thenable { - return undefined; + throw new Error('Method not implemented'); } openAccountListDialog(): Promise { - return undefined; + return Promise.resolve(); } registerProvider(providerMetadata: azdata.AccountProviderMetadata, provider: azdata.AccountProvider): void { @@ -94,7 +94,7 @@ export class AccountProviderStub implements azdata.AccountProvider { } prompt(): Thenable { - return Promise.resolve(undefined); + throw new Error('Method not implemented'); } refresh(account: azdata.Account): Thenable { diff --git a/src/sql/workbench/api/common/sqlExtHostTypes.ts b/src/sql/workbench/api/common/sqlExtHostTypes.ts index 104607f396..299a5403f8 100644 --- a/src/sql/workbench/api/common/sqlExtHostTypes.ts +++ b/src/sql/workbench/api/common/sqlExtHostTypes.ts @@ -581,8 +581,7 @@ export class ConnectionProfile { options: { [name: string]: any }; static createFrom(options: any[]): ConnectionProfile { - // create from options - return undefined; + throw new Error('Method not implemented'); } } diff --git a/src/sql/workbench/browser/modal/modal.ts b/src/sql/workbench/browser/modal/modal.ts index f9e10b6546..8d7f7633b9 100644 --- a/src/sql/workbench/browser/modal/modal.ts +++ b/src/sql/workbench/browser/modal/modal.ts @@ -43,6 +43,10 @@ export interface IModalDialogStyles { dialogBorder?: Color; dialogHeaderAndFooterBackground?: Color; dialogBodyBackground?: Color; + footerBackgroundColor?: Color; + footerBorderTopWidth?: Color; + footerBorderTopStyle?: Color; + footerBorderTopColor?: Color; } export interface IModalOptions { @@ -55,14 +59,6 @@ export interface IModalOptions { hasSpinner?: boolean; } -// Needed for angular component dialogs to style modal footer -export class ModalFooterStyle { - public static backgroundColor; - public static borderTopWidth; - public static borderTopStyle; - public static borderTopColor; -} - const defaultOptions: IModalOptions = { isFlyout: true, isWide: false, @@ -93,10 +89,10 @@ export abstract class Modal extends Disposable implements IThemable { private _lastFocusableElement: HTMLElement; private _focusedElementBeforeOpen: HTMLElement; - private _dialogForeground: Color; - private _dialogBorder: Color; - private _dialogHeaderAndFooterBackground: Color; - private _dialogBodyBackground: Color; + private _dialogForeground?: Color; + private _dialogBorder?: Color; + private _dialogHeaderAndFooterBackground?: Color; + private _dialogBodyBackground?: Color; private _modalDialog: HTMLElement; private _modalHeaderSection: HTMLElement; @@ -336,12 +332,12 @@ export abstract class Modal extends Disposable implements IThemable { * Shows the modal and attaches key listeners */ protected show() { - this._modalShowingContext.get().push(this._staticKey); + this._modalShowingContext.get()!.push(this._staticKey); DOM.append(this.layoutService.container, this._bodyContainer); this.setFocusableElements(); this._keydownListener = DOM.addDisposableListener(document, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { - let context = this._modalShowingContext.get(); + let context = this._modalShowingContext.get()!; if (context[context.length - 1] === this._staticKey) { let event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.Enter)) { @@ -372,7 +368,7 @@ export abstract class Modal extends Disposable implements IThemable { * Hides the modal and removes key listeners */ protected hide() { - this._modalShowingContext.get().pop(); + this._modalShowingContext.get()!.pop(); this._bodyContainer.remove(); if (this._focusedElementBeforeOpen) { this._focusedElementBeforeOpen.focus(); @@ -438,7 +434,7 @@ export abstract class Modal extends Disposable implements IThemable { * @param level Severity level of the message * @param description Description of the message */ - protected setError(message: string, level: MessageLevel = MessageLevel.Error, description: string = '') { + protected setError(message: string | undefined, level: MessageLevel = MessageLevel.Error, description: string = '') { if (this._modalOptions.hasErrors) { this._messageSummaryText = message ? message : ''; this._messageDetailText = description ? description : ''; @@ -461,8 +457,8 @@ export abstract class Modal extends Disposable implements IThemable { this._messageIcon.title = severityText; this._messageSeverity.innerText = severityText; - this._messageSummary.innerText = message; - this._messageSummary.title = message; + this._messageSummary.innerText = message!; + this._messageSummary.title = message!; this._messageDetail.innerText = description; } DOM.hide(this._messageDetail); @@ -491,7 +487,7 @@ export abstract class Modal extends Disposable implements IThemable { /** * Return background color of header and footer */ - protected get headerAndFooterBackground(): string { + protected get headerAndFooterBackground(): string | null { return this._dialogHeaderAndFooterBackground ? this._dialogHeaderAndFooterBackground.toString() : null; } @@ -533,10 +529,8 @@ export abstract class Modal extends Disposable implements IThemable { const border = this._dialogBorder ? this._dialogBorder.toString() : null; const headerAndFooterBackground = this._dialogHeaderAndFooterBackground ? this._dialogHeaderAndFooterBackground.toString() : null; const bodyBackground = this._dialogBodyBackground ? this._dialogBodyBackground.toString() : null; - ModalFooterStyle.backgroundColor = headerAndFooterBackground; - ModalFooterStyle.borderTopWidth = border ? '1px' : null; - ModalFooterStyle.borderTopStyle = border ? 'solid' : null; - ModalFooterStyle.borderTopColor = border; + const footerBorderTopWidth = border ? '1px' : null; + const footerBorderTopStyle = border ? 'solid' : null; if (this._closeButtonInHeader) { this._closeButtonInHeader.style.color = foreground; @@ -567,10 +561,10 @@ export abstract class Modal extends Disposable implements IThemable { } if (this._modalFooterSection) { - this._modalFooterSection.style.backgroundColor = ModalFooterStyle.backgroundColor; - this._modalFooterSection.style.borderTopWidth = ModalFooterStyle.borderTopWidth; - this._modalFooterSection.style.borderTopStyle = ModalFooterStyle.borderTopStyle; - this._modalFooterSection.style.borderTopColor = ModalFooterStyle.borderTopColor; + this._modalFooterSection.style.backgroundColor = headerAndFooterBackground; + this._modalFooterSection.style.borderTopWidth = footerBorderTopWidth; + this._modalFooterSection.style.borderTopStyle = footerBorderTopStyle; + this._modalFooterSection.style.borderTopColor = border; } } diff --git a/src/sql/workbench/parts/backup/browser/backup.component.ts b/src/sql/workbench/parts/backup/browser/backup.component.ts index 4461f64120..f5b171fe34 100644 --- a/src/sql/workbench/parts/backup/browser/backup.component.ts +++ b/src/sql/workbench/parts/backup/browser/backup.component.ts @@ -10,7 +10,6 @@ import { Button } from 'sql/base/browser/ui/button/button'; import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox'; import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox'; import { ListBox } from 'sql/base/browser/ui/listBox/listBox'; -import { ModalFooterStyle } from 'sql/workbench/browser/modal/modal'; import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox'; import { attachButtonStyler, attachListBoxStyler, attachInputBoxStyler, attachSelectBoxStyler, attachCheckboxStyler } from 'sql/platform/theme/common/styler'; import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; @@ -20,6 +19,7 @@ import * as FileValidationConstants from 'sql/workbench/services/fileBrowser/com import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; import { IFileBrowserDialogController } from 'sql/workbench/services/fileBrowser/common/fileBrowserDialogController'; import { IBackupUiService } from 'sql/workbench/services/backup/common/backupUiService'; +import * as cr from 'vs/platform/theme/common/colorRegistry'; import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; import * as lifecycle from 'vs/base/common/lifecycle'; @@ -32,6 +32,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; import { KeyCode } from 'vs/base/common/keyCodes'; +import { ITheme } from 'vs/platform/theme/common/themeService'; export const BACKUP_SELECTOR: string = 'backup-component'; @@ -350,7 +351,7 @@ export class BackupComponent { this.mediaDescriptionBox.disable(); this.registerListeners(); - this.updateTheme(); + this.updateTheme(this.themeService.getTheme()); } ngAfterViewInit() { @@ -549,17 +550,21 @@ export class BackupComponent { this.backupRetainDaysChanged(days); })); - this._toDispose.push(this.themeService.onDidColorThemeChange(e => this.updateTheme())); + this._toDispose.push(this.themeService.onDidColorThemeChange(e => this.updateTheme(e))); } // Update theming that is specific to backup dialog - private updateTheme(): void { + private updateTheme(theme: ITheme): void { // set modal footer style let footerHtmlElement: HTMLElement = this.modalFooterElement.nativeElement; - footerHtmlElement.style.backgroundColor = ModalFooterStyle.backgroundColor; - footerHtmlElement.style.borderTopWidth = ModalFooterStyle.borderTopWidth; - footerHtmlElement.style.borderTopStyle = ModalFooterStyle.borderTopStyle; - footerHtmlElement.style.borderTopColor = ModalFooterStyle.borderTopColor; + const backgroundColor = theme.getColor(cr.foreground); + const border = theme.getColor(cr.contrastBorder) ? theme.getColor(cr.contrastBorder).toString() : null; + const footerBorderTopWidth = border ? '1px' : null; + const footerBorderTopStyle = border ? 'solid' : null; + footerHtmlElement.style.backgroundColor = backgroundColor ? backgroundColor.toString() : null; + footerHtmlElement.style.borderTopWidth = footerBorderTopWidth; + footerHtmlElement.style.borderTopStyle = footerBorderTopStyle; + footerHtmlElement.style.borderTopColor = border; } private addButtonClickHandler(button: Button, handler: () => void) { diff --git a/src/sql/workbench/services/resourceProvider/test/common/testResourceProviderService.ts b/src/sql/workbench/services/resourceProvider/test/common/testResourceProviderService.ts index a38fc7d48e..fad46b1073 100644 --- a/src/sql/workbench/services/resourceProvider/test/common/testResourceProviderService.ts +++ b/src/sql/workbench/services/resourceProvider/test/common/testResourceProviderService.ts @@ -10,23 +10,23 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; export class TestResourceProvider implements IResourceProviderService { _serviceBrand: any; - registerProvider(providerId: string, provider: azdata.ResourceProvider) { + registerProvider(providerId: string, provider: azdata.ResourceProvider): void { } - unregisterProvider(ProviderId: string) { + unregisterProvider(ProviderId: string): void { } createFirewallRule(selectedAccount: azdata.Account, firewallruleInfo: azdata.FirewallRuleInfo, resourceProviderId: string): Promise { - return undefined; + throw new Error('Method not implemented'); } handleFirewallRule(errorCode: number, errorMessage: string, connectionTypeId: string): Promise { - return undefined; + throw new Error('Method not implemented'); } showFirewallRuleDialog(connection: IConnectionProfile, ipAddress: string, resourceProviderId: string): Promise { - return undefined; + return Promise.resolve(true); } -} \ No newline at end of file +} diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 547e24ef50..2d070f4a8c 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -18,6 +18,7 @@ "./sql/base/**/*.ts", "./sql/editor/**/*.ts", "./sql/platform/angularEventing/**/*.ts", + "./sql/platform/accounts/**/*.ts", "./sql/platform/clipboard/**/*.ts", "./sql/platform/credentials/**/*.ts", "./sql/platform/theme/**/*.ts",