mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Add dialog close validation (#1704)
This commit is contained in:
@@ -120,11 +120,13 @@ export class DialogModal extends Modal {
|
|||||||
this.show();
|
this.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public done(): void {
|
public async done(): Promise<void> {
|
||||||
if (this._dialog.okButton.enabled) {
|
if (this._dialog.okButton.enabled) {
|
||||||
this._onDone.fire();
|
if (await this._dialog.validateClose()) {
|
||||||
this.dispose();
|
this._onDone.fire();
|
||||||
this.hide();
|
this.dispose();
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ export class Dialog extends ModelViewPane {
|
|||||||
private _onMessageChange = new Emitter<DialogMessage>();
|
private _onMessageChange = new Emitter<DialogMessage>();
|
||||||
public readonly onMessageChange = this._onMessageChange.event;
|
public readonly onMessageChange = this._onMessageChange.event;
|
||||||
private _message: DialogMessage;
|
private _message: DialogMessage;
|
||||||
|
private _closeValidator: () => boolean | Thenable<boolean>;
|
||||||
|
|
||||||
constructor(public title: string, content?: string | DialogTab[]) {
|
constructor(public title: string, content?: string | DialogTab[]) {
|
||||||
super();
|
super();
|
||||||
@@ -67,6 +68,18 @@ export class Dialog extends ModelViewPane {
|
|||||||
this._onMessageChange.fire(this._message);
|
this._onMessageChange.fire(this._message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public registerCloseValidator(validator: () => boolean | Thenable<boolean>): void {
|
||||||
|
this._closeValidator = validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public validateClose(): Thenable<boolean> {
|
||||||
|
if (this._closeValidator) {
|
||||||
|
return Promise.resolve(this._closeValidator());
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DialogButton implements sqlops.window.modelviewdialog.Button {
|
export class DialogButton implements sqlops.window.modelviewdialog.Button {
|
||||||
|
|||||||
9
src/sql/sqlops.proposed.d.ts
vendored
9
src/sql/sqlops.proposed.d.ts
vendored
@@ -660,6 +660,15 @@ declare module 'sqlops' {
|
|||||||
* undefined or the text is empty or undefined. The default level is error.
|
* undefined or the text is empty or undefined. The default level is error.
|
||||||
*/
|
*/
|
||||||
message: DialogMessage;
|
message: DialogMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a callback that will be called when the user tries to click done. Only
|
||||||
|
* one callback can be registered at once, so each registration call will clear
|
||||||
|
* the previous registration.
|
||||||
|
* @param validator The callback that gets executed when the user tries to click
|
||||||
|
* done. Return true to allow the dialog to close or false to block it from closing
|
||||||
|
*/
|
||||||
|
registerCloseValidator(validator: () => boolean | Thenable<boolean>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DialogTab extends ModelViewPanel {
|
export interface DialogTab extends ModelViewPanel {
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ class DialogImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdi
|
|||||||
public cancelButton: sqlops.window.modelviewdialog.Button;
|
public cancelButton: sqlops.window.modelviewdialog.Button;
|
||||||
public customButtons: sqlops.window.modelviewdialog.Button[];
|
public customButtons: sqlops.window.modelviewdialog.Button[];
|
||||||
private _message: sqlops.window.modelviewdialog.DialogMessage;
|
private _message: sqlops.window.modelviewdialog.DialogMessage;
|
||||||
|
private _closeValidator: () => boolean | Thenable<boolean>;
|
||||||
|
|
||||||
constructor(extHostModelViewDialog: ExtHostModelViewDialog,
|
constructor(extHostModelViewDialog: ExtHostModelViewDialog,
|
||||||
extHostModelView: ExtHostModelViewShape) {
|
extHostModelView: ExtHostModelViewShape) {
|
||||||
@@ -115,6 +116,18 @@ class DialogImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdi
|
|||||||
this._message = value;
|
this._message = value;
|
||||||
this._extHostModelViewDialog.updateDialogContent(this);
|
this._extHostModelViewDialog.updateDialogContent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public registerCloseValidator(validator: () => boolean | Thenable<boolean>): void {
|
||||||
|
this._closeValidator = validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public validateClose(): Thenable<boolean> {
|
||||||
|
if (this._closeValidator) {
|
||||||
|
return Promise.resolve(this._closeValidator());
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TabImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdialog.DialogTab {
|
class TabImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdialog.DialogTab {
|
||||||
@@ -374,6 +387,11 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
|
|||||||
return wizard.validateNavigation(info);
|
return wizard.validateNavigation(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public $validateDialogClose(handle: number): Thenable<boolean> {
|
||||||
|
let dialog = this._objectsByHandle.get(handle) as DialogImpl;
|
||||||
|
return dialog.validateClose();
|
||||||
|
}
|
||||||
|
|
||||||
public openDialog(dialog: sqlops.window.modelviewdialog.Dialog): void {
|
public openDialog(dialog: sqlops.window.modelviewdialog.Dialog): void {
|
||||||
let handle = this.getHandle(dialog);
|
let handle = this.getHandle(dialog);
|
||||||
this.updateDialogContent(dialog);
|
this.updateDialogContent(dialog);
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
|||||||
dialog.okButton = okButton;
|
dialog.okButton = okButton;
|
||||||
dialog.cancelButton = cancelButton;
|
dialog.cancelButton = cancelButton;
|
||||||
dialog.onValidityChanged(valid => this._proxy.$onPanelValidityChanged(handle, valid));
|
dialog.onValidityChanged(valid => this._proxy.$onPanelValidityChanged(handle, valid));
|
||||||
|
dialog.registerCloseValidator(() => this.validateDialogClose(handle));
|
||||||
this._dialogs.set(handle, dialog);
|
this._dialogs.set(handle, dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,4 +263,8 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
|||||||
private validateNavigation(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): Thenable<boolean> {
|
private validateNavigation(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): Thenable<boolean> {
|
||||||
return this._proxy.$validateNavigation(handle, info);
|
return this._proxy.$validateNavigation(handle, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private validateDialogClose(handle: number): Thenable<boolean> {
|
||||||
|
return this._proxy.$validateDialogClose(handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -563,6 +563,7 @@ export interface ExtHostModelViewDialogShape {
|
|||||||
$onWizardPageChanged(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): void;
|
$onWizardPageChanged(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): void;
|
||||||
$updateWizardPageInfo(handle: number, pageHandles: number[], currentPageIndex: number): void;
|
$updateWizardPageInfo(handle: number, pageHandles: number[], currentPageIndex: number): void;
|
||||||
$validateNavigation(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): Thenable<boolean>;
|
$validateNavigation(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): Thenable<boolean>;
|
||||||
|
$validateDialogClose(handle: number): Thenable<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MainThreadModelViewDialogShape extends IDisposable {
|
export interface MainThreadModelViewDialogShape extends IDisposable {
|
||||||
|
|||||||
@@ -307,4 +307,23 @@ suite('ExtHostModelViewDialog Tests', () => {
|
|||||||
// Then the main thread gets notified of the new details
|
// Then the main thread gets notified of the new details
|
||||||
mockProxy.verify(x => x.$setWizardDetails(It.isAny(), It.is(x => x.message === newMessage)), Times.once());
|
mockProxy.verify(x => x.$setWizardDetails(It.isAny(), It.is(x => x.message === newMessage)), Times.once());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Main thread can execute dialog close validation', () => {
|
||||||
|
// Set up the main thread mock to record the dialog handle
|
||||||
|
let dialogHandle: number;
|
||||||
|
mockProxy.setup(x => x.$setDialogDetails(It.isAny(), It.isAny())).callback((handle, details) => dialogHandle = handle);
|
||||||
|
|
||||||
|
// Create the dialog and add a validation that records that it has been called
|
||||||
|
let dialog = extHostModelViewDialog.createDialog('dialog_1');
|
||||||
|
extHostModelViewDialog.updateDialogContent(dialog);
|
||||||
|
let callCount = 0;
|
||||||
|
dialog.registerCloseValidator(() => {
|
||||||
|
callCount++;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// If I call the validation from the main thread then it should run
|
||||||
|
extHostModelViewDialog.$validateDialogClose(dialogHandle);
|
||||||
|
assert.equal(callCount, 1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -60,7 +60,8 @@ suite('MainThreadModelViewDialog Tests', () => {
|
|||||||
$onPanelValidityChanged: (handle, valid) => undefined,
|
$onPanelValidityChanged: (handle, valid) => undefined,
|
||||||
$onWizardPageChanged: (handle, info) => undefined,
|
$onWizardPageChanged: (handle, info) => undefined,
|
||||||
$updateWizardPageInfo: (wizardHandle, pageHandles, currentPageIndex) => undefined,
|
$updateWizardPageInfo: (wizardHandle, pageHandles, currentPageIndex) => undefined,
|
||||||
$validateNavigation: (handle, info) => undefined
|
$validateNavigation: (handle, info) => undefined,
|
||||||
|
$validateDialogClose: handle => undefined
|
||||||
});
|
});
|
||||||
let extHostContext = <IExtHostContext>{
|
let extHostContext = <IExtHostContext>{
|
||||||
getProxy: proxyType => mockExtHostModelViewDialog.object
|
getProxy: proxyType => mockExtHostModelViewDialog.object
|
||||||
@@ -347,4 +348,15 @@ suite('MainThreadModelViewDialog Tests', () => {
|
|||||||
assert.equal(newMessage, wizardDetails.message, 'New message was not included in the fired event');
|
assert.equal(newMessage, wizardDetails.message, 'New message was not included in the fired event');
|
||||||
assert.equal(openedWizard.message, wizardDetails.message, 'New message was not set on the wizard');
|
assert.equal(openedWizard.message, wizardDetails.message, 'New message was not set on the wizard');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Creating a dialog adds a close validation that calls the extension host', () => {
|
||||||
|
mockExtHostModelViewDialog.setup(x => x.$validateDialogClose(It.isAny()));
|
||||||
|
|
||||||
|
// If I call validateClose on the dialog that gets created
|
||||||
|
mainThreadModelViewDialog.$openDialog(dialogHandle);
|
||||||
|
openedDialog.validateClose();
|
||||||
|
|
||||||
|
// Then the call gets forwarded to the extension host
|
||||||
|
mockExtHostModelViewDialog.verify(x => x.$validateDialogClose(It.is(handle => handle === dialogHandle)), Times.once());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user