diff --git a/src/sql/workbench/api/browser/mainThreadModelViewDialog.ts b/src/sql/workbench/api/browser/mainThreadModelViewDialog.ts index 3372f78435..c6dafc4b3d 100644 --- a/src/sql/workbench/api/browser/mainThreadModelViewDialog.ts +++ b/src/sql/workbench/api/browser/mainThreadModelViewDialog.ts @@ -83,7 +83,7 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape public $setDialogDetails(handle: number, details: IModelViewDialogDetails): Thenable { let dialog = this._dialogs.get(handle); if (!dialog) { - dialog = new Dialog(details.title); + dialog = new Dialog(details.title, details.width); let okButton = this.getButton(details.okButton); let cancelButton = this.getButton(details.cancelButton); dialog.okButton = okButton; @@ -91,10 +91,11 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape dialog.onValidityChanged(valid => this._proxy.$onPanelValidityChanged(handle, valid)); dialog.registerCloseValidator(() => this.validateDialogClose(handle)); this._dialogs.set(handle, dialog); + } else { + dialog.title = details.title; + dialog.width = details.width; } - dialog.title = details.title; - dialog.width = details.width; if (details.content && typeof details.content !== 'string') { dialog.content = details.content.map(tabHandle => this.getTab(tabHandle)); } else { @@ -165,13 +166,13 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape public $setWizardDetails(handle: number, details: IModelViewWizardDetails): Thenable { let wizard = this._wizards.get(handle); if (!wizard) { - wizard = new Wizard(details.title); + wizard = new Wizard(details.title, + this.getButton(details.doneButton), + this.getButton(details.cancelButton), + this.getButton(details.nextButton), + this.getButton(details.backButton), + this.getButton(details.generateScriptButton)); wizard.width = details.width; - wizard.backButton = this.getButton(details.backButton); - wizard.cancelButton = this.getButton(details.cancelButton); - wizard.generateScriptButton = this.getButton(details.generateScriptButton); - wizard.doneButton = this.getButton(details.doneButton); - wizard.nextButton = this.getButton(details.nextButton); wizard.onPageChanged(info => this._proxy.$onWizardPageChanged(handle, info)); wizard.onPageAdded(() => this.handleWizardPageAddedOrRemoved(handle)); wizard.onPageRemoved(() => this.handleWizardPageAddedOrRemoved(handle)); diff --git a/src/sql/workbench/services/dialog/browser/dialog.module.ts b/src/sql/workbench/services/dialog/browser/dialog.module.ts index e82f25f430..b374844dab 100644 --- a/src/sql/workbench/services/dialog/browser/dialog.module.ts +++ b/src/sql/workbench/services/dialog/browser/dialog.module.ts @@ -26,11 +26,10 @@ import { InputBox } from 'sql/platform/browser/inputbox/inputBox.component'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; import { IBootstrapParams, ISelector } from 'sql/workbench/services/bootstrap/common/bootstrapParams'; -import { startsWith } from 'vs/base/common/strings'; import { PanelModule } from 'sql/base/browser/ui/panel/panel.module'; import { PropertiesContainerModule } from 'sql/base/browser/ui/propertiesContainer/propertiesContainer.module'; -export const DialogModule = (params, selector: string, instantiationService: IInstantiationService): any => { +export const DialogModule = (params: IBootstrapParams, selector: string, instantiationService: IInstantiationService): any => { /* Model-backed components */ let extensionComponents = Registry.as(Extensions.ComponentContribution).getAllCtors(); @@ -73,7 +72,7 @@ export const DialogModule = (params, selector: string, instantiationService: IIn } ngDoBootstrap(appRef: ApplicationRef) { - let componentClass = startsWith(this.selector, WizardNavigation.SELECTOR) ? WizardNavigation : DialogContainer; + let componentClass = this.selector.startsWith(WizardNavigation.SELECTOR) ? WizardNavigation : DialogContainer; const factoryWrapper: any = this._resolver.resolveComponentFactory(componentClass); factoryWrapper.factory.selector = this.selector; appRef.bootstrap(factoryWrapper); diff --git a/src/sql/workbench/services/dialog/browser/dialogContainer.component.ts b/src/sql/workbench/services/dialog/browser/dialogContainer.component.ts index 35dd452092..6fec7cf53a 100644 --- a/src/sql/workbench/services/dialog/browser/dialogContainer.component.ts +++ b/src/sql/workbench/services/dialog/browser/dialogContainer.component.ts @@ -48,7 +48,7 @@ export class DialogContainer implements AfterViewInit { public _dialogPane: DialogPane; public modelViewId: string; - @ViewChild(ModelViewContent) private _modelViewContent: ModelViewContent; + @ViewChild(ModelViewContent) private _modelViewContent!: ModelViewContent; constructor( @Inject(forwardRef(() => ElementRef)) private _el: ElementRef, @Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef, diff --git a/src/sql/workbench/services/dialog/browser/dialogPane.ts b/src/sql/workbench/services/dialog/browser/dialogPane.ts index d7c8286570..4be4a3b140 100644 --- a/src/sql/workbench/services/dialog/browser/dialogPane.ts +++ b/src/sql/workbench/services/dialog/browser/dialogPane.ts @@ -24,16 +24,16 @@ import { attachTabbedPanelStyler } from 'sql/workbench/common/styler'; import { localize } from 'vs/nls'; export class DialogPane extends Disposable implements IThemable { - private _tabbedPanel: TabbedPanel; + private _tabbedPanel: TabbedPanel | undefined; private _moduleRefs: NgModuleRef<{}>[] = []; // Validation private _modelViewValidityMap = new Map(); - private _body: HTMLElement; + private _body!: HTMLElement; private _selectedTabIndex: number = 0; //TODO: can be an option private _onLayoutChange = new Emitter(); - private _selectedTabContent: string; + private _selectedTabContent: string = ''; public pageNumber?: number; constructor( @@ -68,11 +68,11 @@ export class DialogPane extends Disposable implements IThemable { tabContainer.style.display = 'none'; this._body.appendChild(tabContainer); this.initializeModelViewContainer(tabContainer, tab.content, tab); - this._tabbedPanel.onTabChange(e => { - tabContainer.style.height = (this.getTabDimension().height - this._tabbedPanel.headersize) + 'px'; + this._tabbedPanel!.onTabChange(e => { + tabContainer.style.height = (this.getTabDimension().height - this._tabbedPanel!.headersize) + 'px'; this._onLayoutChange.fire({ modelViewId: tab.content }); }); - this._tabbedPanel.pushTab({ + this._tabbedPanel!.pushTab({ title: tab.title, identifier: 'dialogPane.' + this.title + '.' + tabIndex, view: { @@ -130,7 +130,7 @@ export class DialogPane extends Disposable implements IThemable { dialogPane: this } as DialogComponentParams, undefined, - (moduleRef) => { + (moduleRef: NgModuleRef<{}>) => { return this._moduleRefs.push(moduleRef); }); } @@ -155,8 +155,8 @@ export class DialogPane extends Disposable implements IThemable { * Called by the theme registry on theme change to style the component */ public style(styles: IModalDialogStyles): void { - this._body.style.backgroundColor = styles.dialogBodyBackground ? styles.dialogBodyBackground.toString() : undefined; - this._body.style.color = styles.dialogForeground ? styles.dialogForeground.toString() : undefined; + this._body.style.backgroundColor = styles.dialogBodyBackground ? styles.dialogBodyBackground.toString() : ''; + this._body.style.color = styles.dialogForeground ? styles.dialogForeground.toString() : ''; } private _setValidity(modelViewId: string, valid: boolean) { diff --git a/src/sql/workbench/services/dialog/browser/wizardModal.ts b/src/sql/workbench/services/dialog/browser/wizardModal.ts index 9b3382d2d7..e83e4b50c8 100644 --- a/src/sql/workbench/services/dialog/browser/wizardModal.ts +++ b/src/sql/workbench/services/dialog/browser/wizardModal.ts @@ -74,12 +74,10 @@ export class WizardModal extends Modal { attachButtonStyler(this.backButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND }); } - if (this._wizard.customButtons) { - this._wizard.customButtons.forEach(button => { - let buttonElement = this.addDialogButton(button); - this.updateButtonElement(buttonElement, button); - }); - } + this._wizard.customButtons.forEach(button => { + let buttonElement = this.addDialogButton(button); + this.updateButtonElement(buttonElement, button); + }); this._previousButton = this.addDialogButton(this._wizard.backButton, () => this.showPage(this._wizard.currentPage - 1)); this._nextButton = this.addDialogButton(this._wizard.nextButton, () => this.showPage(this._wizard.currentPage + 1, true, true), true, true); diff --git a/src/sql/workbench/services/dialog/browser/wizardNavigation.component.ts b/src/sql/workbench/services/dialog/browser/wizardNavigation.component.ts index 64553065ef..a5905dfd34 100644 --- a/src/sql/workbench/services/dialog/browser/wizardNavigation.component.ts +++ b/src/sql/workbench/services/dialog/browser/wizardNavigation.component.ts @@ -12,8 +12,8 @@ import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { IBootstrapParams } from 'sql/workbench/services/bootstrap/common/bootstrapParams'; export class WizardNavigationParams implements IBootstrapParams { - wizard: Wizard; - navigationHandler: (index: number) => void; + wizard!: Wizard; + navigationHandler!: (index: number) => void; } @Component({ @@ -39,7 +39,7 @@ export class WizardNavigation implements AfterViewInit { private _onResize = new Emitter(); public readonly onResize: Event = this._onResize.event; - @ViewChild('container', { read: ElementRef }) private _container: ElementRef; + @ViewChild('container', { read: ElementRef }) private _container!: ElementRef; constructor( @Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef, @Inject(IBootstrapParams) private _params: WizardNavigationParams, @@ -77,6 +77,9 @@ export class WizardNavigation implements AfterViewInit { private style(): void { let theme = this._themeService.getColorTheme(); let navigationBackgroundColor = theme.getColor(SIDE_BAR_BACKGROUND); + if (!navigationBackgroundColor) { + return; + } if (theme.type === 'light') { navigationBackgroundColor = navigationBackgroundColor.lighten(0.03); } else if (theme.type === 'dark') { diff --git a/src/sql/workbench/services/dialog/common/dialogTypes.ts b/src/sql/workbench/services/dialog/common/dialogTypes.ts index c675c2d7f9..52c4530bb5 100644 --- a/src/sql/workbench/services/dialog/common/dialogTypes.ts +++ b/src/sql/workbench/services/dialog/common/dialogTypes.ts @@ -26,7 +26,7 @@ export class ModelViewPane { } export class DialogTab extends ModelViewPane { - public content: string; + public content: string = ''; constructor(public title: string, content?: string) { super(); @@ -36,37 +36,38 @@ export class DialogTab extends ModelViewPane { } } +export type CloseValidator = () => boolean | Thenable; + export class Dialog extends ModelViewPane { private static readonly DONE_BUTTON_LABEL = localize('dialogModalDoneButtonLabel', "Done"); private static readonly CANCEL_BUTTON_LABEL = localize('dialogModalCancelButtonLabel', "Cancel"); - public content: string | DialogTab[]; - public width: DialogWidth; + public content: string | DialogTab[] = ''; public okButton: DialogButton = new DialogButton(Dialog.DONE_BUTTON_LABEL, true); public cancelButton: DialogButton = new DialogButton(Dialog.CANCEL_BUTTON_LABEL, true); - public customButtons: DialogButton[]; - private _onMessageChange = new Emitter(); + public customButtons: DialogButton[] = []; + private _onMessageChange = new Emitter(); public readonly onMessageChange = this._onMessageChange.event; - private _message: DialogMessage; - private _closeValidator: () => boolean | Thenable; + private _message: DialogMessage | undefined; + private _closeValidator: CloseValidator | undefined; - constructor(public title: string, content?: string | DialogTab[]) { + constructor(public title: string, public width: DialogWidth, content?: string | DialogTab[]) { super(); if (content) { this.content = content; } } - public get message(): DialogMessage { + public get message(): DialogMessage | undefined { return this._message; } - public set message(value: DialogMessage) { + public set message(value: DialogMessage | undefined) { this._message = value; this._onMessageChange.fire(this._message); } - public registerCloseValidator(validator: () => boolean | Thenable): void { + public registerCloseValidator(validator: CloseValidator): void { this._closeValidator = validator; } @@ -83,7 +84,7 @@ export class DialogButton implements azdata.window.Button { private _label: string; private _enabled: boolean; private _hidden: boolean; - private _focused: boolean; + private _focused: boolean | undefined; private _position?: azdata.window.DialogButtonPosition; private _onClick: Emitter = new Emitter(); public readonly onClick: Event = this._onClick.event; @@ -123,11 +124,11 @@ export class DialogButton implements azdata.window.Button { this._onUpdate.fire(); } - public get focused(): boolean { + public get focused(): boolean | undefined { return this._focused; } - public set focused(focused: boolean) { + public set focused(focused: boolean | undefined) { this._focused = focused; this._onUpdate.fire(); } @@ -150,9 +151,9 @@ export class DialogButton implements azdata.window.Button { } export class WizardPage extends DialogTab { - public customButtons: DialogButton[]; - private _enabled: boolean; - private _description: string; + public customButtons: DialogButton[] = []; + private _enabled: boolean = false; + private _description: string | undefined; private _onUpdate: Emitter = new Emitter(); public readonly onUpdate: Event = this._onUpdate.event; @@ -169,39 +170,41 @@ export class WizardPage extends DialogTab { this._onUpdate.fire(); } - public get description(): string { + public get description(): string | undefined { return this._description; } - public set description(description: string) { + public set description(description: string | undefined) { this._description = description; this._onUpdate.fire(); } } +export type NavigationValidator = (pageChangeInfo: azdata.window.WizardPageChangeInfo) => boolean | Thenable; + export class Wizard { - public pages: WizardPage[]; - public nextButton: DialogButton; - public backButton: DialogButton; - public generateScriptButton: DialogButton; - public doneButton: DialogButton; - public cancelButton: DialogButton; - public customButtons: DialogButton[]; - private _currentPage: number; + public pages: WizardPage[] = []; + public customButtons: DialogButton[] = []; + private _currentPage: number = -1; private _pageChangedEmitter = new Emitter(); public readonly onPageChanged = this._pageChangedEmitter.event; private _pageAddedEmitter = new Emitter(); public readonly onPageAdded = this._pageAddedEmitter.event; private _pageRemovedEmitter = new Emitter(); public readonly onPageRemoved = this._pageRemovedEmitter.event; - private _navigationValidator: (pageChangeInfo: azdata.window.WizardPageChangeInfo) => boolean | Thenable; - private _onMessageChange = new Emitter(); + private _navigationValidator: NavigationValidator | undefined; + private _onMessageChange = new Emitter(); public readonly onMessageChange = this._onMessageChange.event; - private _message: DialogMessage; - public displayPageTitles: boolean; - public width: DialogWidth; + private _message: DialogMessage | undefined; + public displayPageTitles: boolean = false; + public width: DialogWidth | undefined; - constructor(public title: string) { } + constructor(public title: string, + public doneButton: DialogButton, + public cancelButton: DialogButton, + public nextButton: DialogButton, + public backButton: DialogButton, + public generateScriptButton: DialogButton) { } public get currentPage(): number { return this._currentPage; @@ -253,7 +256,7 @@ export class Wizard { this._pageRemovedEmitter.fire(removedPage); } - public registerNavigationValidator(validator: (pageChangeInfo: azdata.window.WizardPageChangeInfo) => boolean | Thenable): void { + public registerNavigationValidator(validator: NavigationValidator): void { this._navigationValidator = validator; } @@ -268,11 +271,11 @@ export class Wizard { } } - public get message(): DialogMessage { + public get message(): DialogMessage | undefined { return this._message; } - public set message(value: DialogMessage) { + public set message(value: DialogMessage | undefined) { this._message = value; this._onMessageChange.fire(this._message); } diff --git a/src/sql/workbench/services/dialog/test/electron-browser/dialogPane.test.ts b/src/sql/workbench/services/dialog/test/electron-browser/dialogPane.test.ts index 712b7b2474..fc21661c52 100644 --- a/src/sql/workbench/services/dialog/test/electron-browser/dialogPane.test.ts +++ b/src/sql/workbench/services/dialog/test/electron-browser/dialogPane.test.ts @@ -27,7 +27,7 @@ suite('Dialog Pane Tests', () => { } setup(() => { - dialog = new Dialog('test_dialog'); + dialog = new Dialog('test_dialog', 'narrow'); container = document.createElement('div'); bootstrapSave = bootstrapAngular; });