Add more to strict nulls (#11871)

* add more to strict nulls

* maintain error handling properly

* fix lint
This commit is contained in:
Anthony Dresser
2020-08-19 18:38:34 -07:00
committed by GitHub
parent 69a96a7d5d
commit 9327624930
22 changed files with 393 additions and 369 deletions

View File

@@ -83,44 +83,44 @@ const tabbableElementsQuerySelector = 'a[href], area[href], input:not([disabled]
export abstract class Modal extends Disposable implements IThemable {
protected _useDefaultMessageBoxLocation: boolean = true;
protected _messageElement: HTMLElement;
protected _messageElement?: HTMLElement;
protected _modalOptions: IModalOptions;
protected readonly disposableStore = this._register(new DisposableStore());
private _detailsButtonContainer: HTMLElement;
private _messageIcon: HTMLElement;
private _messageSeverity: HTMLElement;
private _messageSummary: HTMLElement;
private _messageBody: HTMLElement;
private _messageDetail: HTMLElement;
private _toggleMessageDetailButton: Button;
private _copyMessageButton: Button;
private _closeMessageButton: Button;
private _messageSummaryText: string;
private _messageDetailText: string;
private _detailsButtonContainer?: HTMLElement;
private _messageIcon?: HTMLElement;
private _messageSeverity?: HTMLElement;
private _messageSummary?: HTMLElement;
private _messageBody?: HTMLElement;
private _messageDetail?: HTMLElement;
private _toggleMessageDetailButton?: Button;
private _copyMessageButton?: Button;
private _closeMessageButton?: Button;
private _messageSummaryText?: string;
private _messageDetailText?: string;
private _spinnerElement: HTMLElement;
private _firstTabbableElement: HTMLElement; // The first element in the dialog the user could tab to
private _lastTabbableElement: HTMLElement; // The last element in the dialog the user could tab to
private _focusedElementBeforeOpen: HTMLElement;
private _spinnerElement?: HTMLElement;
private _firstTabbableElement?: HTMLElement; // The first element in the dialog the user could tab to
private _lastTabbableElement?: HTMLElement; // The last element in the dialog the user could tab to
private _focusedElementBeforeOpen?: HTMLElement;
private _dialogForeground?: Color;
private _dialogBorder?: Color;
private _dialogHeaderAndFooterBackground?: Color;
private _dialogBodyBackground?: Color;
private _modalDialog: HTMLElement;
private _modalContent: HTMLElement;
private _modalHeaderSection: HTMLElement;
private _modalBodySection: HTMLElement;
private _modalFooterSection: HTMLElement;
private _closeButtonInHeader: HTMLElement;
private _bodyContainer: HTMLElement;
private _modalTitle: HTMLElement;
private _modalTitleIcon: HTMLElement;
private _leftFooter: HTMLElement;
private _rightFooter: HTMLElement;
private _footerButtons: Button[];
private _backButton: Button;
private _modalDialog?: HTMLElement;
private _modalContent?: HTMLElement;
private _modalHeaderSection?: HTMLElement;
private _modalBodySection?: HTMLElement;
private _modalFooterSection?: HTMLElement;
private _closeButtonInHeader?: HTMLElement;
private _bodyContainer?: HTMLElement;
private _modalTitle?: HTMLElement;
private _modalTitleIcon?: HTMLElement;
private _leftFooter?: HTMLElement;
private _rightFooter?: HTMLElement;
private _footerButtons: Button[] = [];
private _backButton?: Button;
private _modalShowingContext: IContextKey<Array<string>>;
private readonly _staticKey: string;
@@ -128,7 +128,7 @@ export abstract class Modal extends Disposable implements IThemable {
/**
* Get the back button, only available after render and if the hasBackButton option is true
*/
protected get backButton(): Button {
protected get backButton(): Button | undefined {
return this._backButton;
}
@@ -139,7 +139,7 @@ export abstract class Modal extends Disposable implements IThemable {
* (hyoshi - 10/2/2017 tracked by https://github.com/Microsoft/carbon/issues/1836)
*/
public setWide(isWide: boolean): void {
DOM.toggleClass(this._bodyContainer, 'wide', isWide);
DOM.toggleClass(this._bodyContainer!, 'wide', isWide);
}
/**
@@ -165,7 +165,6 @@ export abstract class Modal extends Disposable implements IThemable {
mixin(this._modalOptions, defaultOptions, false);
this._staticKey = generateUuid();
this._modalShowingContext = MODAL_SHOWING_CONTEXT.bindTo(_contextKeyService);
this._footerButtons = [];
}
/**
@@ -248,7 +247,7 @@ export abstract class Modal extends Disposable implements IThemable {
this._modalFooterSection = DOM.append(this._modalContent, DOM.$('.modal-footer'));
if (this._modalOptions.hasSpinner) {
this._spinnerElement = DOM.append(this._modalFooterSection, DOM.$('.codicon.in-progress'));
this._spinnerElement.setAttribute('title', this._modalOptions.spinnerTitle);
this._spinnerElement.setAttribute('title', this._modalOptions.spinnerTitle ?? '');
DOM.hide(this._spinnerElement);
}
this._leftFooter = DOM.append(this._modalFooterSection, DOM.$('.left-footer'));
@@ -294,42 +293,42 @@ export abstract class Modal extends Disposable implements IThemable {
private getTextForClipboard(): string {
const eol = this.textResourcePropertiesService.getEOL(URI.from({ scheme: Schemas.untitled }));
return this._messageDetailText === '' ? this._messageSummaryText : `${this._messageSummaryText}${eol}========================${eol}${this._messageDetailText}`;
return this._messageDetailText === '' ? this._messageSummaryText! : `${this._messageSummaryText}${eol}========================${eol}${this._messageDetailText}`;
}
private updateExpandMessageState() {
this._messageSummary.style.cursor = this.shouldShowExpandMessageButton ? 'pointer' : 'default';
DOM.removeClass(this._messageSummary, MESSAGE_EXPANDED_MODE_CLASS);
this._messageSummary!.style.cursor = this.shouldShowExpandMessageButton ? 'pointer' : 'default';
DOM.removeClass(this._messageSummary!, MESSAGE_EXPANDED_MODE_CLASS);
if (this.shouldShowExpandMessageButton) {
DOM.append(this._detailsButtonContainer, this._toggleMessageDetailButton.element);
DOM.append(this._detailsButtonContainer!, this._toggleMessageDetailButton!.element);
} else {
DOM.removeNode(this._toggleMessageDetailButton.element);
DOM.removeNode(this._toggleMessageDetailButton!.element);
}
}
private toggleMessageDetail() {
const isExpanded = DOM.hasClass(this._messageSummary, MESSAGE_EXPANDED_MODE_CLASS);
DOM.toggleClass(this._messageSummary, MESSAGE_EXPANDED_MODE_CLASS, !isExpanded);
this._toggleMessageDetailButton.label = isExpanded ? SHOW_DETAILS_TEXT : localize('hideMessageDetails', "Hide Details");
const isExpanded = DOM.hasClass(this._messageSummary!, MESSAGE_EXPANDED_MODE_CLASS);
DOM.toggleClass(this._messageSummary!, MESSAGE_EXPANDED_MODE_CLASS, !isExpanded);
this._toggleMessageDetailButton!.label = isExpanded ? SHOW_DETAILS_TEXT : localize('hideMessageDetails', "Hide Details");
if (this._messageDetailText) {
if (isExpanded) {
DOM.removeNode(this._messageDetail);
DOM.removeNode(this._messageDetail!);
} else {
DOM.append(this._messageBody, this._messageDetail);
DOM.append(this._messageBody!, this._messageDetail!);
}
}
}
private get shouldShowExpandMessageButton(): boolean {
return this._messageDetailText !== '' || this._messageSummary.scrollWidth > this._messageSummary.offsetWidth;
return this._messageDetailText !== '' || this._messageSummary!.scrollWidth > this._messageSummary!.offsetWidth;
}
/**
* Figures out the first and last elements which the user can tab to in the dialog
*/
public setFirstLastTabbableElement() {
const tabbableElements = this._bodyContainer.querySelectorAll(tabbableElementsQuerySelector);
const tabbableElements = this._bodyContainer!.querySelectorAll(tabbableElementsQuerySelector);
if (tabbableElements && tabbableElements.length > 0) {
this._firstTabbableElement = <HTMLElement>tabbableElements[0];
this._lastTabbableElement = <HTMLElement>tabbableElements[tabbableElements.length - 1];
@@ -344,7 +343,7 @@ export abstract class Modal extends Disposable implements IThemable {
// This ensures that we are setting the focus on a useful element in the form when possible.
const focusableElements = this._modalBodySection ?
this._modalBodySection.querySelectorAll(tabbableElementsQuerySelector) :
this._bodyContainer.querySelectorAll(tabbableElementsQuerySelector);
this._bodyContainer!.querySelectorAll(tabbableElementsQuerySelector);
if (focusableElements && focusableElements.length > 0) {
(<HTMLElement>focusableElements[0]).focus();
@@ -357,7 +356,7 @@ export abstract class Modal extends Disposable implements IThemable {
protected show() {
this._focusedElementBeforeOpen = <HTMLElement>document.activeElement;
this._modalShowingContext.get()!.push(this._staticKey);
DOM.append(this.layoutService.container, this._bodyContainer);
DOM.append(this.layoutService.container, this._bodyContainer!);
this.setInitialFocusedElement();
this.disposableStore.add(DOM.addDisposableListener(document, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {
@@ -376,10 +375,10 @@ export abstract class Modal extends Disposable implements IThemable {
}
}));
this.disposableStore.add(DOM.addDisposableListener(window, DOM.EventType.RESIZE, (e: Event) => {
this.layout(DOM.getTotalHeight(this._modalBodySection));
this.layout(DOM.getTotalHeight(this._modalBodySection!));
}));
this.layout(DOM.getTotalHeight(this._modalBodySection));
this.layout(DOM.getTotalHeight(this._modalBodySection!));
this._telemetryService.createActionEvent(TelemetryKeys.TelemetryView.Shell, TelemetryKeys.ModalDialogOpened)
.withAdditionalProperties({ name: this._name })
.send();
@@ -395,7 +394,7 @@ export abstract class Modal extends Disposable implements IThemable {
*/
protected hide() {
this._modalShowingContext.get()!.pop();
this._bodyContainer.remove();
this._bodyContainer!.remove();
this.disposableStore.clear();
this._telemetryService.createActionEvent(TelemetryKeys.TelemetryView.Shell, TelemetryKeys.ModalDialogClosed)
.withAdditionalProperties({ name: this._name })
@@ -420,9 +419,9 @@ export abstract class Modal extends Disposable implements IThemable {
button.label = label;
button.onDidClick(() => onSelect()); // @todo this should be registered to dispose but that brakes some dialogs
if (orientation === 'left') {
DOM.append(this._leftFooter, footerButton);
DOM.append(this._leftFooter!, footerButton);
} else {
DOM.append(this._rightFooter, footerButton);
DOM.append(this._rightFooter!, footerButton);
}
this._footerButtons.push(button);
return button;
@@ -433,7 +432,7 @@ export abstract class Modal extends Disposable implements IThemable {
* @param label Label to show on the button
* @param onSelect The callback to call when the button is selected
*/
protected findFooterButton(label: string): Button {
protected findFooterButton(label: string): Button | undefined {
return find(this._footerButtons, e => {
try {
return e && e.element.innerText === label;
@@ -482,17 +481,17 @@ export abstract class Modal extends Disposable implements IThemable {
severityText = WARNING_ALT_TEXT;
}
levelClasses.forEach(level => {
DOM.toggleClass(this._messageIcon, level, selectedLevel === level);
DOM.toggleClass(this._messageElement, level, selectedLevel === level);
DOM.toggleClass(this._messageIcon!, level, selectedLevel === level);
DOM.toggleClass(this._messageElement!, level, selectedLevel === level);
});
this._messageIcon.title = severityText;
this._messageSeverity.innerText = severityText;
this._messageSummary.innerText = message!;
this._messageSummary.title = message!;
this._messageDetail.innerText = description;
this._messageIcon!.title = severityText;
this._messageSeverity!.innerText = severityText;
this._messageSummary!.innerText = message!;
this._messageSummary!.title = message!;
this._messageDetail!.innerText = description;
}
DOM.removeNode(this._messageDetail);
DOM.removeNode(this._messageDetail!);
this.messagesElementVisible = !!this._messageSummaryText;
this.updateExpandMessageState();
}
@@ -501,12 +500,12 @@ export abstract class Modal extends Disposable implements IThemable {
protected set messagesElementVisible(visible: boolean) {
if (visible) {
if (this._useDefaultMessageBoxLocation) {
DOM.prepend(this._modalContent, (this._messageElement));
DOM.prepend(this._modalContent!, this._messageElement!);
}
} else {
DOM.removeNode(this._messageElement);
DOM.removeNode(this._messageElement!);
// Set the focus to first focus element if the focus is not within the dialog
if (!DOM.isAncestor(document.activeElement, this._bodyContainer)) {
if (!DOM.isAncestor(document.activeElement, this._bodyContainer!)) {
this.setInitialFocusedElement();
}
}
@@ -518,12 +517,12 @@ export abstract class Modal extends Disposable implements IThemable {
public set spinner(show: boolean) {
if (this._modalOptions.hasSpinner) {
if (show) {
DOM.show(this._spinnerElement);
DOM.show(this._spinnerElement!);
if (this._modalOptions.spinnerTitle) {
alert(this._modalOptions.spinnerTitle);
}
} else {
DOM.hide(this._spinnerElement);
DOM.hide(this._spinnerElement!);
}
}
}
@@ -573,34 +572,34 @@ export abstract class Modal extends Disposable implements IThemable {
}
private applyStyles(): void {
const foreground = this._dialogForeground ? this._dialogForeground.toString() : null;
const border = this._dialogBorder ? this._dialogBorder.toString() : null;
const headerAndFooterBackground = this._dialogHeaderAndFooterBackground ? this._dialogHeaderAndFooterBackground.toString() : null;
const bodyBackground = this._dialogBodyBackground ? this._dialogBodyBackground.toString() : null;
const footerBorderTopWidth = border ? '1px' : null;
const footerBorderTopStyle = border ? 'solid' : null;
const foreground = this._dialogForeground ? this._dialogForeground.toString() : '';
const border = this._dialogBorder ? this._dialogBorder.toString() : '';
const headerAndFooterBackground = this._dialogHeaderAndFooterBackground ? this._dialogHeaderAndFooterBackground.toString() : '';
const bodyBackground = this._dialogBodyBackground ? this._dialogBodyBackground.toString() : '';
const footerBorderTopWidth = border ? '1px' : '';
const footerBorderTopStyle = border ? 'solid' : '';
if (this._closeButtonInHeader) {
this._closeButtonInHeader.style.color = foreground;
}
if (this._modalDialog) {
this._modalDialog.style.color = foreground;
this._modalDialog.style.borderWidth = border ? '1px' : null;
this._modalDialog.style.borderStyle = border ? 'solid' : null;
this._modalDialog.style.borderWidth = border ? '1px' : '';
this._modalDialog.style.borderStyle = border ? 'solid' : '';
this._modalDialog.style.borderColor = border;
}
if (this._modalHeaderSection) {
this._modalHeaderSection.style.backgroundColor = headerAndFooterBackground;
this._modalHeaderSection.style.borderBottomWidth = border ? '1px' : null;
this._modalHeaderSection.style.borderBottomStyle = border ? 'solid' : null;
this._modalHeaderSection.style.borderBottomWidth = border ? '1px' : '';
this._modalHeaderSection.style.borderBottomStyle = border ? 'solid' : '';
this._modalHeaderSection.style.borderBottomColor = border;
}
if (this._messageElement) {
this._messageElement.style.backgroundColor = headerAndFooterBackground;
this._messageElement.style.borderBottomWidth = border ? '1px' : null;
this._messageElement.style.borderBottomStyle = border ? 'solid' : null;
this._messageElement.style.borderBottomWidth = border ? '1px' : '';
this._messageElement.style.borderBottomStyle = border ? 'solid' : '';
this._messageElement.style.borderBottomColor = border;
}

View File

@@ -60,9 +60,9 @@ export const ACCOUNT_VIEW_CONTAINER = Registry.as<IViewContainersRegistry>(ViewC
}, ViewContainerLocation.Dialog);
class AccountPanel extends ViewPane {
public index: number;
private accountList: List<azdata.Account>;
private tenantList: List<Tenant>;
public index?: number;
private accountList?: List<azdata.Account>;
private tenantList?: List<Tenant>;
constructor(
@@ -93,24 +93,24 @@ class AccountPanel extends ViewPane {
}
public get length(): number {
return this.accountList.length;
return this.accountList!.length;
}
public focus() {
this.accountList.domFocus();
this.accountList!.domFocus();
}
public updateAccounts(accounts: azdata.Account[]) {
this.accountList.splice(0, this.accountList.length, accounts);
this.accountList!.splice(0, this.accountList!.length, accounts);
}
public setSelection(indexes: number[]) {
this.accountList.setSelection(indexes);
this.updateTenants(this.accountList.getSelection[0]);
this.accountList!.setSelection(indexes);
this.updateTenants(this.accountList!.getSelectedElements()[0]);
}
private updateTenants(account: azdata.Account) {
this.tenantList.splice(0, this.tenantList.length, account?.properties?.tenants ?? []);
this.tenantList!.splice(0, this.tenantList!.length, account.properties?.tenants ?? []);
}
public getActions(): IAction[] {
@@ -134,12 +134,12 @@ export class AccountDialog extends Modal {
// MEMBER VARIABLES ////////////////////////////////////////////////////
private _providerViewsMap = new Map<string, IProviderViewUiComponent>();
private _closeButton: Button;
private _addAccountButton: Button;
private _splitView: SplitView;
private _container: HTMLElement;
private _splitViewContainer: HTMLElement;
private _noaccountViewContainer: HTMLElement;
private _closeButton?: Button;
private _addAccountButton?: Button;
private _splitView?: SplitView;
private _container?: HTMLElement;
private _splitViewContainer?: HTMLElement;
private _noaccountViewContainer?: HTMLElement;
// EVENTING ////////////////////////////////////////////////////////////
private _onAddAccountErrorEmitter: Emitter<string>;
@@ -199,8 +199,8 @@ export class AccountDialog extends Modal {
}
// MODAL OVERRIDE METHODS //////////////////////////////////////////////
protected layout(height?: number): void {
this._splitView.layout(DOM.getContentHeight(this._container));
protected layout(_height?: number): void {
this._splitView!.layout(DOM.getContentHeight(this._container!));
}
public render() {
@@ -230,7 +230,7 @@ export class AccountDialog extends Modal {
this._register(this._addAccountButton.onDidClick(async () => {
const vals = Iterable.consume(this._providerViewsMap.values())[0];
let pickedValue: string;
let pickedValue: string | undefined;
if (vals.length === 0) {
this._notificationService.error(localize('accountDialog.noCloudsRegistered', "You have no clouds enabled. Go to Settings -> Search Azure Account Configuration -> Enable at least one cloud"));
return;
@@ -262,8 +262,8 @@ export class AccountDialog extends Modal {
private registerListeners(): void {
// Theme styler
this._register(attachButtonStyler(this._closeButton, this._themeService));
this._register(attachButtonStyler(this._addAccountButton, this._themeService));
this._register(attachButtonStyler(this._closeButton!, this._themeService));
this._register(attachButtonStyler(this._addAccountButton!, this._themeService));
}
/* Overwrite escape key behavior */
@@ -292,14 +292,14 @@ export class AccountDialog extends Modal {
}
private showNoAccountContainer() {
this._splitViewContainer.hidden = true;
this._noaccountViewContainer.hidden = false;
this._addAccountButton.focus();
this._splitViewContainer!.hidden = true;
this._noaccountViewContainer!.hidden = false;
this._addAccountButton!.focus();
}
private showSplitView() {
this._splitViewContainer.hidden = false;
this._noaccountViewContainer.hidden = true;
this._splitViewContainer!.hidden = false;
this._noaccountViewContainer!.hidden = true;
if (Iterable.consume(this._providerViewsMap.values()).length > 0) {
const firstView = this._providerViewsMap.values().next().value;
if (firstView instanceof AccountPanel) {
@@ -373,19 +373,19 @@ export class AccountDialog extends Modal {
attachPanelStyler(providerView, this._themeService);
const insertIndex = this._splitView.length;
const insertIndex = this._splitView!.length;
providerView.render();
// Append the list view to the split view
this._splitView.addView(providerView, Sizing.Distribute, insertIndex);
this._splitView!.addView(providerView, Sizing.Distribute, insertIndex);
providerView.index = insertIndex;
this._splitView.layout(DOM.getContentHeight(this._container));
this._splitView!.layout(DOM.getContentHeight(this._container!));
// Set the initial items of the list
providerView.updateAccounts(newProvider.initialAccounts);
if (newProvider.initialAccounts.length > 0 && this._splitViewContainer.hidden) {
if (newProvider.initialAccounts.length > 0 && this._splitViewContainer!.hidden) {
this.showSplitView();
}
@@ -403,8 +403,8 @@ export class AccountDialog extends Modal {
}
// Remove the list view from the split view
this._splitView.removeView(providerView.view.index);
this._splitView.layout(DOM.getContentHeight(this._container));
this._splitView!.removeView(providerView.view.index!);
this._splitView!.layout(DOM.getContentHeight(this._container!));
// Remove the list view from our internal map
this._providerViewsMap.delete(removedProvider.id);
@@ -418,11 +418,11 @@ export class AccountDialog extends Modal {
}
providerMapping.view.updateAccounts(args.accountList);
if (args.accountList.length > 0 && this._splitViewContainer.hidden) {
if (args.accountList.length > 0 && this._splitViewContainer!.hidden) {
this.showSplitView();
}
if (this.isEmptyLinkedAccount() && this._noaccountViewContainer.hidden) {
if (this.isEmptyLinkedAccount() && this._noaccountViewContainer!.hidden) {
this.showNoAccountContainer();
}

View File

@@ -14,8 +14,8 @@ export class AccountDialogController {
// MEMBER VARIABLES ////////////////////////////////////////////////////
private _addAccountErrorTitle = localize('accountDialog.addAccountErrorTitle', "Error adding account");
private _accountDialog: AccountDialog;
public get accountDialog(): AccountDialog { return this._accountDialog; }
private _accountDialog?: AccountDialog;
public get accountDialog(): AccountDialog | undefined { return this._accountDialog; }
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,

View File

@@ -35,9 +35,9 @@ export class AccountManagementService implements IAccountManagementService {
public _providers: { [id: string]: AccountProviderWithMetadata } = {};
public _serviceBrand: undefined;
private _accountStore: AccountStore;
private _accountDialogController: AccountDialogController;
private _autoOAuthDialogController: AutoOAuthDialogController;
private _mementoContext: Memento;
private _accountDialogController?: AccountDialogController;
private _autoOAuthDialogController?: AutoOAuthDialogController;
private _mementoContext?: Memento;
// EVENT EMITTERS //////////////////////////////////////////////////////
private _addAccountProviderEmitter: Emitter<AccountProviderAddedEventParams>;
@@ -57,7 +57,7 @@ export class AccountManagementService implements IAccountManagementService {
@IClipboardService private _clipboardService: IClipboardService,
@IOpenerService private _openerService: IOpenerService,
@ILogService private readonly _logService: ILogService,
@INotificationService private readonly _notificationService,
@INotificationService private readonly _notificationService: INotificationService
) {
// Create the account store
if (!this._mementoObj) {
@@ -88,7 +88,7 @@ export class AccountManagementService implements IAccountManagementService {
* account's properties have been updated (usually when the account goes stale).
* @param updatedAccount Account with the updated properties
*/
public accountUpdated(updatedAccount: azdata.Account): Thenable<void> {
public accountUpdated(updatedAccount: azdata.Account): Promise<void> {
let self = this;
// 1) Update the account in the store
@@ -119,7 +119,7 @@ export class AccountManagementService implements IAccountManagementService {
* @param providerId ID of the provider to ask to prompt for an account
* @return Promise to return an account
*/
public addAccount(providerId: string): Thenable<void> {
public addAccount(providerId: string): Promise<void> {
const closeAction: Action = new Action('closeAddingAccount', localize('accountManagementService.close', "Close"), undefined, true);
const loginNotification: INotification = {
@@ -166,7 +166,7 @@ export class AccountManagementService implements IAccountManagementService {
* @param account account to refresh
* @return Promise to return an account
*/
public refreshAccount(account: azdata.Account): Thenable<azdata.Account> {
public refreshAccount(account: azdata.Account): Promise<azdata.Account> {
let self = this;
return this.doWithProvider(account.key.providerId, async (provider) => {
@@ -181,20 +181,20 @@ export class AccountManagementService implements IAccountManagementService {
let result = await self._accountStore.addOrUpdate(account);
if (result.accountAdded) {
// Add the account to the list
provider.accounts.push(result.changedAccount);
provider.accounts.push(result.changedAccount!);
}
if (result.accountModified) {
// Find the updated account and splice the updated on in
let indexToRemove: number = firstIndex(provider.accounts, account => {
return account.key.accountId === result.changedAccount.key.accountId;
return account.key.accountId === result.changedAccount!.key.accountId;
});
if (indexToRemove >= 0) {
provider.accounts.splice(indexToRemove, 1, result.changedAccount);
provider.accounts.splice(indexToRemove, 1, result.changedAccount!);
}
}
self.fireAccountListUpdate(provider, result.accountAdded);
return result.changedAccount;
return result.changedAccount!;
});
}
@@ -202,7 +202,7 @@ export class AccountManagementService implements IAccountManagementService {
* Retrieves metadata of all providers that have been registered
* @returns Registered account providers
*/
public getAccountProviderMetadata(): Thenable<azdata.AccountProviderMetadata[]> {
public getAccountProviderMetadata(): Promise<azdata.AccountProviderMetadata[]> {
return Promise.resolve(values(this._providers).map(provider => provider.metadata));
}
@@ -211,7 +211,7 @@ export class AccountManagementService implements IAccountManagementService {
* @param providerId ID of the provider the returned accounts belong to
* @returns Promise to return a list of accounts
*/
public getAccountsForProvider(providerId: string): Thenable<azdata.Account[]> {
public getAccountsForProvider(providerId: string): Promise<azdata.Account[]> {
let self = this;
// 1) Get the accounts from the store
@@ -228,7 +228,7 @@ export class AccountManagementService implements IAccountManagementService {
/**
* Retrieves all the accounts registered with ADS.
*/
public getAccounts(): Thenable<azdata.Account[]> {
public getAccounts(): Promise<azdata.Account[]> {
return this._accountStore.getAllAccounts();
}
@@ -238,9 +238,9 @@ export class AccountManagementService implements IAccountManagementService {
* @param resource The resource to get the security token for
* @return Promise to return the security token
*/
public getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Thenable<{}> {
public getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Promise<{} | undefined> {
return this.doWithProvider(account.key.providerId, provider => {
return provider.provider.getSecurityToken(account, resource);
return Promise.resolve(provider.provider.getSecurityToken(account, resource));
});
}
@@ -251,9 +251,9 @@ export class AccountManagementService implements IAccountManagementService {
* @param resource The resource to get the security token for
* @return Promise to return the security token
*/
public getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Thenable<{ token: string }> {
public getAccountSecurityToken(account: azdata.Account, tenant: string, resource: azdata.AzureResource): Promise<{ token: string } | undefined> {
return this.doWithProvider(account.key.providerId, provider => {
return provider.provider.getAccountSecurityToken(account, tenant, resource);
return Promise.resolve(provider.provider.getAccountSecurityToken(account, tenant, resource));
});
}
@@ -263,7 +263,7 @@ export class AccountManagementService implements IAccountManagementService {
* @returns Promise with result of account removal, true if account was
* removed, false otherwise.
*/
public removeAccount(accountKey: azdata.AccountKey): Thenable<boolean> {
public removeAccount(accountKey: azdata.AccountKey): Promise<boolean> {
// Step 1) Remove the account
// Step 2) Clear the sensitive data from the provider (regardless of whether the account was removed)
@@ -316,7 +316,7 @@ export class AccountManagementService implements IAccountManagementService {
* Opens the account list dialog
* @return Promise that finishes when the account list dialog closes
*/
public openAccountListDialog(): Thenable<void> {
public openAccountListDialog(): Promise<void> {
let self = this;
return new Promise((resolve, reject) => {
@@ -326,7 +326,7 @@ export class AccountManagementService implements IAccountManagementService {
self._accountDialogController = self._instantiationService.createInstance(AccountDialogController);
}
self._accountDialogController.openAccountDialog();
self._accountDialogController.accountDialog.onCloseEvent(resolve);
self._accountDialogController.accountDialog!.onCloseEvent(resolve);
} catch (e) {
reject(e);
}
@@ -337,7 +337,7 @@ export class AccountManagementService implements IAccountManagementService {
* Begin auto OAuth device code open add account dialog
* @return Promise that finishes when the account list dialog opens
*/
public beginAutoOAuthDeviceCode(providerId: string, title: string, message: string, userCode: string, uri: string): Thenable<void> {
public beginAutoOAuthDeviceCode(providerId: string, title: string, message: string, userCode: string, uri: string): Promise<void> {
let self = this;
return this.doWithProvider(providerId, provider => {
@@ -356,9 +356,9 @@ export class AccountManagementService implements IAccountManagementService {
* Called from the UI when a user cancels the auto OAuth dialog
*/
public cancelAutoOAuthDeviceCode(providerId: string): void {
this.doWithProvider(providerId, provider => provider.provider.autoOAuthCancelled())
void this.doWithProvider(providerId, provider => Promise.resolve(provider.provider.autoOAuthCancelled()))
.then( // Swallow errors
null,
undefined,
err => { this._logService.warn(`Error when cancelling auto OAuth: ${err}`); }
)
.then(() => this.autoOAuthDialogController.closeAutoOAuthDialog());
@@ -408,7 +408,7 @@ export class AccountManagementService implements IAccountManagementService {
* @param providerMetadata Metadata of the provider that is being registered
* @param provider References to the methods of the provider
*/
public registerProvider(providerMetadata: azdata.AccountProviderMetadata, provider: azdata.AccountProvider): Thenable<void> {
public registerProvider(providerMetadata: azdata.AccountProviderMetadata, provider: azdata.AccountProvider): Promise<void> {
return this._registerProvider(providerMetadata, provider);
}
@@ -432,7 +432,7 @@ export class AccountManagementService implements IAccountManagementService {
// TODO: Support for orphaned accounts (accounts with no provider)
// PRIVATE HELPERS /////////////////////////////////////////////////////
private doWithProvider<T>(providerId: string, op: (provider: AccountProviderWithMetadata) => Thenable<T>): Thenable<T> {
private doWithProvider<T>(providerId: string, op: (provider: AccountProviderWithMetadata) => Promise<T>): Promise<T> {
let provider = this._providers[providerId];
if (!provider) {
// If the provider doesn't already exist wait until it gets registered

View File

@@ -30,18 +30,18 @@ import { Tenant, TenantListDelegate, TenantPickerListRenderer } from 'sql/workbe
export class AccountPicker extends Disposable {
public static ACCOUNTPICKERLIST_HEIGHT = 47;
public viewModel: AccountPickerViewModel;
private _accountList: List<azdata.Account>;
private _rootContainer: HTMLElement;
private _accountList?: List<azdata.Account>;
private _rootContainer?: HTMLElement;
private _accountContainer: HTMLElement;
private _refreshContainer: HTMLElement;
private _accountListContainer: HTMLElement;
private _dropdown: DropdownList;
private _tenantContainer: HTMLElement;
private _tenantListContainer: HTMLElement;
private _tenantList: List<Tenant>;
private _tenantDropdown: DropdownList;
private _refreshAccountAction: RefreshAccountAction;
private _accountContainer?: HTMLElement;
private _refreshContainer?: HTMLElement;
private _accountListContainer?: HTMLElement;
private _dropdown?: DropdownList;
private _tenantContainer?: HTMLElement;
private _tenantListContainer?: HTMLElement;
private _tenantList?: List<Tenant>;
private _tenantDropdown?: DropdownList;
private _refreshAccountAction?: RefreshAccountAction;
// EVENTING ////////////////////////////////////////////////////////////
private _addAccountCompleteEmitter: Emitter<void>;
@@ -71,7 +71,7 @@ export class AccountPicker extends Disposable {
this._addAccountCompleteEmitter = new Emitter<void>();
this._addAccountErrorEmitter = new Emitter<string>();
this._addAccountStartEmitter = new Emitter<void>();
this._onAccountSelectionChangeEvent = new Emitter<azdata.Account>();
this._onAccountSelectionChangeEvent = new Emitter<azdata.Account | undefined>();
this._onTenantSelectionChangeEvent = new Emitter<string | undefined>();
// Create the view model, wire up the events, and initialize with baseline data
@@ -88,7 +88,7 @@ export class AccountPicker extends Disposable {
* Render account picker
*/
public render(rootContainer: HTMLElement): void {
DOM.append(rootContainer, this._rootContainer);
DOM.append(rootContainer, this._rootContainer!);
}
// PUBLIC METHODS //////////////////////////////////////////////////////
@@ -156,14 +156,14 @@ export class AccountPicker extends Disposable {
this._register(this._accountList.onDidChangeSelection((e: IListEvent<azdata.Account>) => {
if (e.elements.length === 1) {
this._dropdown.renderLabel();
this._dropdown!.renderLabel();
this.onAccountSelectionChange(e.elements[0]);
}
}));
this._register(this._tenantList.onDidChangeSelection((e: IListEvent<Tenant>) => {
if (e.elements.length === 1) {
this._tenantDropdown.renderLabel();
this._tenantDropdown!.renderLabel();
this.onTenantSelectionChange(e.elements[0].id);
}
}));
@@ -214,16 +214,16 @@ export class AccountPicker extends Disposable {
private onAccountSelectionChange(account: azdata.Account | undefined) {
this.viewModel.selectedAccount = account;
if (account && account.isStale) {
this._refreshAccountAction.account = account;
DOM.show(this._refreshContainer);
} else {
DOM.hide(this._refreshContainer);
this._refreshAccountAction!.account = account;
DOM.show(this._refreshContainer!);
} else if (account) {
DOM.hide(this._refreshContainer!);
if (account.properties.tenants?.length > 1) {
DOM.show(this._tenantContainer);
DOM.show(this._tenantContainer!);
this.updateTenantList(account);
} else {
DOM.hide(this._tenantContainer);
DOM.hide(this._tenantContainer!);
}
this.onTenantSelectionChange(account?.properties?.tenants[0]?.id);
}
@@ -243,7 +243,7 @@ export class AccountPicker extends Disposable {
}
}
const selectedAccounts = this._accountList.getSelectedElements();
const selectedAccounts = this._accountList!.getSelectedElements();
const account = selectedAccounts ? selectedAccounts[0] : undefined;
if (account) {
const badge = DOM.$('div.badge');
@@ -278,7 +278,7 @@ export class AccountPicker extends Disposable {
}
}
const selectedTenants = this._tenantList.getSelectedElements();
const selectedTenants = this._tenantList!.getSelectedElements();
const tenant = selectedTenants ? selectedTenants[0] : undefined;
if (tenant) {
const row = DOM.append(container, DOM.$('div.selected-tenant-container'));
@@ -291,15 +291,15 @@ export class AccountPicker extends Disposable {
}
private updateTenantList(account: azdata.Account): void {
this._tenantList.splice(0, this._tenantList.length, account?.properties?.tenants ?? []);
this._tenantList.setSelection([0]);
this._tenantDropdown.renderLabel();
this._tenantList.layout(this._tenantList.contentHeight);
this._tenantList!.splice(0, this._tenantList!.length, account?.properties?.tenants ?? []);
this._tenantList!.setSelection([0]);
this._tenantDropdown!.renderLabel();
this._tenantList!.layout(this._tenantList!.contentHeight);
}
private updateAccountList(accounts: azdata.Account[]): void {
// keep the selection to the current one
const selectedElements = this._accountList.getSelectedElements();
const selectedElements = this._accountList!.getSelectedElements();
// find selected index
let selectedIndex: number | undefined;
@@ -310,21 +310,21 @@ export class AccountPicker extends Disposable {
}
// Replace the existing list with the new one
this._accountList.splice(0, this._accountList.length, accounts);
this._accountList!.splice(0, this._accountList!.length, accounts);
if (this._accountList.length > 0) {
if (this._accountList!.length > 0) {
if (selectedIndex && selectedIndex !== -1) {
this._accountList.setSelection([selectedIndex]);
this._accountList!.setSelection([selectedIndex]);
} else {
this._accountList.setSelection([0]);
this._accountList!.setSelection([0]);
}
} else {
// if the account is empty, re-render dropdown label
this.onAccountSelectionChange(undefined);
this._dropdown.renderLabel();
this._dropdown!.renderLabel();
}
this._accountList.layout(this._accountList.contentHeight);
this._accountList!.layout(this._accountList!.contentHeight);
}
/**
@@ -333,9 +333,8 @@ export class AccountPicker extends Disposable {
private updateTheme(theme: IColorTheme): void {
const linkColor = theme.getColor(buttonBackground);
const link = linkColor ? linkColor.toString() : null;
this._refreshContainer.style.color = link;
if (this._refreshContainer) {
this._refreshContainer.style.color = link;
this._refreshContainer.style.color = link ?? '';
}
}
}

View File

@@ -13,7 +13,7 @@ import { AccountPicker } from 'sql/workbench/services/accountManagement/browser/
export class AccountPickerService implements IAccountPickerService {
_serviceBrand: undefined;
private _accountPicker: AccountPicker;
private _accountPicker?: AccountPicker;
// EVENTING ////////////////////////////////////////////////////////////
private _addAccountCompleteEmitter: Emitter<void>;
@@ -38,7 +38,7 @@ export class AccountPickerService implements IAccountPickerService {
this._addAccountCompleteEmitter = new Emitter<void>();
this._addAccountErrorEmitter = new Emitter<string>();
this._addAccountStartEmitter = new Emitter<void>();
this._onAccountSelectionChangeEvent = new Emitter<azdata.Account>();
this._onAccountSelectionChangeEvent = new Emitter<azdata.Account | undefined>();
this._onTenantSelectionChangeEvent = new Emitter<string | undefined>();
}
@@ -46,7 +46,11 @@ export class AccountPickerService implements IAccountPickerService {
* Get selected account
*/
public get selectedAccount(): azdata.Account | undefined {
return this._accountPicker.viewModel.selectedAccount;
if (this._accountPicker) {
return this._accountPicker.viewModel.selectedAccount;
} else {
return undefined;
}
}
/**

View File

@@ -27,11 +27,11 @@ import { attachModalDialogStyler } from 'sql/workbench/common/styler';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
export class AutoOAuthDialog extends Modal {
private _copyAndOpenButton: Button;
private _closeButton: Button;
private _userCodeInputBox: InputBox;
private _websiteInputBox: InputBox;
private _descriptionElement: HTMLElement;
private _copyAndOpenButton?: Button;
private _closeButton?: Button;
private _userCodeInputBox?: InputBox;
private _websiteInputBox?: InputBox;
private _descriptionElement?: HTMLElement;
// EVENTING ////////////////////////////////////////////////////////////
private _onHandleAddAccount = new Emitter<void>();
@@ -75,14 +75,14 @@ export class AutoOAuthDialog extends Modal {
public render() {
super.render();
attachModalDialogStyler(this, this._themeService);
this.backButton.onDidClick(() => this.cancel());
this._register(attachButtonStyler(this.backButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND }));
this.backButton!.onDidClick(() => this.cancel());
this._register(attachButtonStyler(this.backButton!, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND }));
this._copyAndOpenButton = this.addFooterButton(localize('copyAndOpen', "Copy & Open"), () => this.addAccount());
this._closeButton = this.addFooterButton(localize('oauthDialog.cancel', "Cancel"), () => this.cancel());
this.registerListeners();
this._userCodeInputBox.disable();
this._websiteInputBox.disable();
this._userCodeInputBox!.disable();
this._websiteInputBox!.disable();
}
protected layout(height?: number): void {
@@ -110,10 +110,10 @@ export class AutoOAuthDialog extends Modal {
private registerListeners(): void {
// Theme styler
this._register(attachButtonStyler(this._copyAndOpenButton, this._themeService));
this._register(attachButtonStyler(this._closeButton, this._themeService));
this._register(attachInputBoxStyler(this._userCodeInputBox, this._themeService));
this._register(attachInputBoxStyler(this._websiteInputBox, this._themeService));
this._register(attachButtonStyler(this._copyAndOpenButton!, this._themeService));
this._register(attachButtonStyler(this._closeButton!, this._themeService));
this._register(attachInputBoxStyler(this._userCodeInputBox!, this._themeService));
this._register(attachInputBoxStyler(this._websiteInputBox!, this._themeService));
}
@@ -128,8 +128,8 @@ export class AutoOAuthDialog extends Modal {
}
private addAccount() {
if (this._copyAndOpenButton.enabled) {
this._copyAndOpenButton.enabled = false;
if (this._copyAndOpenButton!.enabled) {
this._copyAndOpenButton!.enabled = false;
this.spinner = true;
this._onHandleAddAccount.fire();
}
@@ -140,7 +140,7 @@ export class AutoOAuthDialog extends Modal {
}
public close() {
this._copyAndOpenButton.enabled = true;
this._copyAndOpenButton!.enabled = true;
this._onCloseEvent.fire();
this.spinner = false;
this.hide();
@@ -149,10 +149,10 @@ export class AutoOAuthDialog extends Modal {
public open(title: string, message: string, userCode: string, uri: string) {
// Update dialog
this.title = title;
this._descriptionElement.innerText = message;
this._userCodeInputBox.value = userCode;
this._websiteInputBox.value = uri;
this._descriptionElement!.innerText = message;
this._userCodeInputBox!.value = userCode;
this._websiteInputBox!.value = uri;
this.show();
this._copyAndOpenButton.focus();
this._copyAndOpenButton!.focus();
}
}

View File

@@ -13,10 +13,10 @@ import { IErrorMessageService } from 'sql/platform/errorMessage/common/errorMess
export class AutoOAuthDialogController {
// MEMBER VARIABLES ////////////////////////////////////////////////////
private _autoOAuthDialog: AutoOAuthDialog;
private _autoOAuthDialog?: AutoOAuthDialog;
private _providerId?: string;
private _userCode: string;
private _uri: string;
private _userCode?: string;
private _uri?: string;
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,
@@ -27,7 +27,7 @@ export class AutoOAuthDialogController {
/**
* Open auto OAuth dialog
*/
public openAutoOAuthDialog(providerId: string, title: string, message: string, userCode: string, uri: string): Thenable<void> {
public openAutoOAuthDialog(providerId: string, title: string, message: string, userCode: string, uri: string): Promise<void> {
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.");
@@ -57,7 +57,9 @@ export class AutoOAuthDialogController {
* Close auto OAuth dialog
*/
public closeAutoOAuthDialog(): void {
this._autoOAuthDialog.close();
if (this._autoOAuthDialog) {
this._autoOAuthDialog.close();
}
this._providerId = undefined;
}
@@ -71,6 +73,10 @@ export class AutoOAuthDialogController {
}
private handleOnAddAccount(): void {
this._accountManagementService.copyUserCodeAndOpenBrowser(this._userCode, this._uri);
if (this._userCode && this._uri) {
this._accountManagementService.copyUserCodeAndOpenBrowser(this._userCode, this._uri);
} else {
throw new Error('Missing user code and uri');
}
}
}

View File

@@ -118,10 +118,11 @@ suite('Account Management Service Tests:', () => {
state.mockAccountStore.verify(x => x.addOrUpdate(TypeMoq.It.isAny()), TypeMoq.Times.once());
// ... The account list was updated
state.eventVerifierUpdate.assertFiredWithVerify((params: UpdateAccountListEventParams) => {
assert.equal(params.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(params.accountList));
assert.equal(params.accountList.length, 1);
state.eventVerifierUpdate.assertFiredWithVerify((params: UpdateAccountListEventParams | undefined) => {
assert.ok(params);
assert.equal(params!.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(params!.accountList));
assert.equal(params!.accountList.length, 1);
});
});
});
@@ -157,10 +158,11 @@ suite('Account Management Service Tests:', () => {
// ... The account list change should have been fired
state.eventVerifierUpdate.assertFiredWithVerify(param => {
assert.equal(param.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(param.accountList));
assert.equal(param.accountList.length, 1);
assert.equal(param.accountList[0], account);
assert.ok(param);
assert.equal(param!.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(param!.accountList));
assert.equal(param!.accountList.length, 1);
assert.equal(param!.accountList[0], account);
});
});
});
@@ -196,10 +198,11 @@ suite('Account Management Service Tests:', () => {
// ... The account list change should have been fired
state.eventVerifierUpdate.assertFiredWithVerify(param => {
assert.equal(param.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(param.accountList));
assert.equal(param.accountList.length, 1);
assert.equal(param.accountList[0], account);
assert.ok(param);
assert.equal(param!.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(param!.accountList));
assert.equal(param!.accountList.length, 1);
assert.equal(param!.accountList[0], account);
});
});
});
@@ -246,7 +249,7 @@ suite('Account Management Service Tests:', () => {
let state = getTestState();
state.accountManagementService._providers[noAccountProvider.id] = {
accounts: [],
provider: null, // Doesn't matter
provider: undefined!, // Doesn't matter
metadata: noAccountProvider
};
@@ -290,7 +293,7 @@ suite('Account Management Service Tests:', () => {
let ams = getTestState().accountManagementService;
ams._providers[noAccountProvider.id] = {
accounts: [],
provider: null, // Doesn't matter
provider: undefined!, // Doesn't matter
metadata: noAccountProvider
};
@@ -308,7 +311,7 @@ suite('Account Management Service Tests:', () => {
let ams = getTestState().accountManagementService;
ams._providers[hasAccountProvider.id] = {
accounts: [account],
provider: null, // Doesn't matter
provider: undefined!, // Doesn't matter
metadata: hasAccountProvider
};
@@ -350,10 +353,11 @@ suite('Account Management Service Tests:', () => {
mockProvider.verify(x => x.clear(TypeMoq.It.isValue(account.key)), TypeMoq.Times.once());
// ... The updated account list event should have fired
state.eventVerifierUpdate.assertFiredWithVerify((params: UpdateAccountListEventParams) => {
assert.equal(params.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(params.accountList));
assert.equal(params.accountList.length, 0);
state.eventVerifierUpdate.assertFiredWithVerify((params: UpdateAccountListEventParams | undefined) => {
assert.ok(params);
assert.equal(params!.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(params!.accountList));
assert.equal(params!.accountList.length, 0);
});
});
});
@@ -404,7 +408,7 @@ suite('Account Management Service Tests:', () => {
mockDialogController.setup(x => x.openAccountDialog());
mockDialogController.setup(x => x.accountDialog).returns(() => <AccountDialog>mockAccountDialog);
let mockAccountDialogCloseEvent = new Emitter<void>();
mockAccountDialog['onCloseEvent'] = mockAccountDialogCloseEvent.event;
(mockAccountDialog as any).onCloseEvent = mockAccountDialogCloseEvent.event;
setTimeout(() => {
mockAccountDialogCloseEvent.fire();
}, 1000);
@@ -434,7 +438,7 @@ suite('Account Management Service Tests:', () => {
mockDialogController.setup(x => x.openAccountDialog());
mockDialogController.setup(x => x.accountDialog).returns(() => <AccountDialog>mockAccountDialog);
let mockAccountDialogCloseEvent = new Emitter<void>();
mockAccountDialog['onCloseEvent'] = mockAccountDialogCloseEvent.event;
(mockAccountDialog as any).onCloseEvent = mockAccountDialogCloseEvent.event;
setTimeout(() => {
mockAccountDialogCloseEvent.fire();
}, 1000);
@@ -468,7 +472,7 @@ suite('Account Management Service Tests:', () => {
// ... Create ams, account store that will accept account add/update
let mocks = getTestState();
mocks.mockAccountStore.setup(x => x.addOrUpdate(TypeMoq.It.isAny()))
.returns(() => Promise.resolve(undefined));
.returns(() => Promise.resolve(undefined!));
// ... Create mock account provider
let mockProvider = getMockAccountProvider();
@@ -484,10 +488,11 @@ suite('Account Management Service Tests:', () => {
mockProvider.verify(x => x.initialize(TypeMoq.It.isAny()), TypeMoq.Times.once());
// ... The provider added event should have fired
mocks.eventVerifierProviderAdded.assertFiredWithVerify((param: AccountProviderAddedEventParams) => {
assert.equal(param.addedProvider, noAccountProvider);
assert.ok(Array.isArray(param.initialAccounts));
assert.equal(param.initialAccounts.length, 0);
mocks.eventVerifierProviderAdded.assertFiredWithVerify((param: AccountProviderAddedEventParams | undefined) => {
assert.ok(param);
assert.equal(param!.addedProvider, noAccountProvider);
assert.ok(Array.isArray(param!.initialAccounts));
assert.equal(param!.initialAccounts.length, 0);
});
});
});
@@ -530,7 +535,7 @@ function getTestState(): AccountManagementState {
const testNotificationService = new TestNotificationService();
// Create the account management service
let ams = new AccountManagementService(mockMemento, mockInstantiationService.object, new TestStorageService(), null, null, undefined, testNotificationService);
let ams = new AccountManagementService(mockMemento, mockInstantiationService.object, new TestStorageService(), undefined!, undefined!, undefined!, testNotificationService);
// Wire up event handlers
let evUpdate = new EventVerifierSingle<UpdateAccountListEventParams>();

View File

@@ -79,7 +79,7 @@ suite('Account picker service tests', () => {
properties: [],
isStale: false
};
let evOnAccountSelectionChangeEvent = new EventVerifierSingle<azdata.Account>();
let evOnAccountSelectionChangeEvent = new EventVerifierSingle<azdata.Account | undefined>();
service.onAccountSelectionChangeEvent(evOnAccountSelectionChangeEvent.eventHandler);
mockOnAccountSelectionChangeEvent.fire(account);
evOnAccountSelectionChangeEvent.assertFired(account);

View File

@@ -13,15 +13,17 @@ const languageRegistry = Registry.as<ILanguageAssociationRegistry>(ILanguageAsso
export function doHandleUpgrade(editor?: EditorInput): EditorInput | undefined {
if (editor instanceof UntitledTextEditorInput || editor instanceof FileEditorInput) {
let language: string;
let language: string | undefined;
if (editor instanceof UntitledTextEditorInput) {
language = editor.getMode();
} else {
editor.getPreferredMode();
language = editor.getPreferredMode();
}
const association = languageRegistry.getAssociationForLanguage(language);
if (association && association.syncConvertinput) {
return association.syncConvertinput(editor);
if (language) {
const association = languageRegistry.getAssociationForLanguage(language);
if (association && association.syncConvertinput) {
return association.syncConvertinput(editor);
}
}
}
return editor;

View File

@@ -25,8 +25,8 @@ type ILanguageAssociationSignature<Services extends BrandedService[]> = new (...
export interface ILanguageAssociationRegistry {
registerLanguageAssociation<Services extends BrandedService[]>(languages: string[], contribution: ILanguageAssociationSignature<Services>, isDefault?: boolean): IDisposable;
getAssociationForLanguage(language: string): ILanguageAssociation;
readonly defaultAssociation: [string, ILanguageAssociation];
getAssociationForLanguage(language: string): ILanguageAssociation | undefined;
readonly defaultAssociation: [string, ILanguageAssociation] | undefined;
/**
* Starts the registry by providing the required services.

View File

@@ -41,7 +41,7 @@ export interface IQueryManagementService {
registerRunner(runner: QueryRunner, uri: string): void;
cancelQuery(ownerUri: string): Promise<QueryCancelResult>;
runQuery(ownerUri: string, range: IRange, runOptions?: ExecutionPlanOptions): Promise<void>;
runQuery(ownerUri: string, range?: IRange, runOptions?: ExecutionPlanOptions): Promise<void>;
runQueryStatement(ownerUri: string, line: number, column: number): Promise<void>;
runQueryString(ownerUri: string, queryString: string): Promise<void>;
runQueryAndReturn(ownerUri: string, queryString: string): Promise<azdata.SimpleExecuteResult>;
@@ -79,7 +79,7 @@ export interface IQueryManagementService {
*/
export interface IQueryRequestHandler {
cancelQuery(ownerUri: string): Promise<azdata.QueryCancelResult>;
runQuery(ownerUri: string, selection: azdata.ISelectionData, runOptions?: ExecutionPlanOptions): Promise<void>;
runQuery(ownerUri: string, selection?: azdata.ISelectionData, runOptions?: ExecutionPlanOptions): Promise<void>;
runQueryStatement(ownerUri: string, line: number, column: number): Promise<void>;
runQueryString(ownerUri: string, queryString: string): Promise<void>;
runQueryAndReturn(ownerUri: string, queryString: string): Promise<azdata.SimpleExecuteResult>;

View File

@@ -254,6 +254,7 @@ export class QueryModelService implements IQueryModelService {
text: strings.format(nls.localize('runQueryBatchStartLine', "Line {0}"), b.range.startLineNumber)
};
}
info.range!.push(b.range);
}
let message = {
message: messageText,
@@ -263,7 +264,6 @@ export class QueryModelService implements IQueryModelService {
link: link
};
this._fireQueryEvent(uri, 'message', message);
info.range!.push(b.range);
});
queryRunner.onMessage(m => {
this._fireQueryEvent(uri, 'message', m);

View File

@@ -138,7 +138,9 @@ export default class QueryRunner extends Disposable {
*/
public runQuery(input: IRange | undefined, runOptions?: ExecutionPlanOptions): Promise<void>;
public runQuery(input: string | IRange | undefined, runOptions?: ExecutionPlanOptions): Promise<void> {
if (types.isString(input) || types.isUndefined(input)) {
if (types.isString(input)) {
return this.doRunQuery(input, false, runOptions);
} else if (types.isUndefined(input)) {
return this.doRunQuery(input, false, runOptions);
} else {
return this.doRunQuery(input, false, runOptions);
@@ -157,8 +159,9 @@ export default class QueryRunner extends Disposable {
* Implementation that runs the query with the provided query
* @param input Query string to execute
*/
private doRunQuery(input: string, runCurrentStatement: boolean, runOptions?: ExecutionPlanOptions): Promise<void>;
private doRunQuery(input: IRange | undefined, runCurrentStatement: boolean, runOptions?: ExecutionPlanOptions): Promise<void>;
private doRunQuery(input: string, runCurrentStatement: false, runOptions?: ExecutionPlanOptions): Promise<void>;
private doRunQuery(input: IRange | undefined, runCurrentStatement: false, runOptions?: ExecutionPlanOptions): Promise<void>;
private doRunQuery(input: IRange, runCurrentStatement: true, runOptions?: ExecutionPlanOptions): Promise<void>;
private doRunQuery(input: string | IRange | undefined, runCurrentStatement: boolean, runOptions?: ExecutionPlanOptions): Promise<void> {
if (this.isExecuting) {
return Promise.resolve();
@@ -181,7 +184,7 @@ export default class QueryRunner extends Disposable {
// Send the request to execute the query
return runCurrentStatement
? this.queryManagementService.runQueryStatement(this.uri, input.startLineNumber, input.startColumn).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e))
? this.queryManagementService.runQueryStatement(this.uri, input!.startLineNumber, input!.startColumn).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e))
: this.queryManagementService.runQuery(this.uri, input, runOptions).then(() => this.handleSuccessRunQueryResult(), e => this.handleFailureRunQueryResult(e));
} else {
// Update internal state to show that we're executing the query
@@ -232,7 +235,9 @@ export default class QueryRunner extends Disposable {
this._batchSets.map(batch => {
if (batch.range) {
batch.range = new Range(batch.range.startLineNumber + this._resultLineOffset, batch.range.startColumn + this._resultColumnOffset, batch.range.endLineNumber + this._resultLineOffset, batch.range.endColumn + this._resultColumnOffset);
const columnOffset = (this._resultColumnOffset ?? 0);
const lineOffest = (this._resultLineOffset ?? 0);
batch.range = new Range(batch.range.startLineNumber + lineOffest, batch.range.startColumn + columnOffset, batch.range.endLineNumber + lineOffest, batch.range.endColumn + columnOffset);
}
});
@@ -256,7 +261,9 @@ export default class QueryRunner extends Disposable {
public handleBatchStart(batch: BatchStartSummary): void {
// Recalculate the start and end lines, relative to the result line offset
if (batch.range) {
batch.range = new Range(batch.range.startLineNumber + this._resultLineOffset, batch.range.startColumn + this._resultColumnOffset, batch.range.endLineNumber + this._resultLineOffset, batch.range.endColumn + this._resultColumnOffset);
const columnOffset = (this._resultColumnOffset ?? 0);
const lineOffest = (this._resultLineOffset ?? 0);
batch.range = new Range(batch.range.startLineNumber + lineOffest, batch.range.startColumn + columnOffset, batch.range.endLineNumber + lineOffest, batch.range.endColumn + columnOffset);
}
// Store the batch
@@ -305,6 +312,7 @@ export default class QueryRunner extends Disposable {
batchSet = <BatchSummary>{
id: 0,
range: undefined,
executionStart: Date.now().toString(),
hasError: false,
resultSetSummaries: []
};