LP1823041 Angular dialogs resolve on dismiss/cancel
authorBill Erickson <berickxx@gmail.com>
Wed, 3 Apr 2019 16:14:52 +0000 (12:14 -0400)
committerBill Erickson <berickxx@gmail.com>
Wed, 3 Apr 2019 16:19:11 +0000 (12:19 -0400)
Angular dialogs now only result in a promise rejection when an
unexpected error occurs.  Dismissing a dialog via Esc, Cancel button,
cross-click, body-click, etc. no longer result in a rejection.  In these
situations, the response value will be set to 'null' and a new boolean
field 'dismissed' on the dialog object will be set to true.

For the current code, this primarily affects confirm dialogs, which
previously rejected the dialog promise when the user selected the "do
not confirm" option.

Additionally, this commits add typescript support for "es2018.promise"
which allows us to start using Promise.finally() handlers.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/dialog/dialog.component.ts
Open-ILS/src/eg2/src/app/staff/admin/workstation/workstations/workstations.component.ts
Open-ILS/src/eg2/src/app/staff/cat/vandelay/match-set-list.component.ts
Open-ILS/src/eg2/src/app/staff/cat/vandelay/queue.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.ts
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts
Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.ts
Open-ILS/src/eg2/tsconfig.json

index b7531a2..08ee743 100644 (file)
@@ -7,13 +7,6 @@ import {NgbModal, NgbModalRef, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap
  * at the root of the template (see ConfirmDialogComponent).
  */
 
-export interface DialogRejectionResponse {
-    // Did the user simply close the dialog without performing an action.
-    dismissed?: boolean;
-    // Relays error, etc. messages from the dialog handler to the caller.
-    message?: string;
-}
-
 @Component({
     selector: 'eg-dialog',
     template: '<ng-template></ng-template>'
@@ -32,6 +25,11 @@ export class DialogComponent implements OnInit {
     // called in the overridding method.
     onOpen$ = new EventEmitter<any>();
 
+    // null if the dialog has never been opened.
+    // true if the most recent instance was dismissed by the user,
+    // false otherwise.
+    dismissed: boolean = null;
+
     // The modalRef allows direct control of the modal instance.
     private modalRef: NgbModalRef = null;
 
@@ -44,10 +42,10 @@ export class DialogComponent implements OnInit {
     open(options?: NgbModalOptions): Promise<any> {
 
         if (this.modalRef !== null) {
-            console.warn('Dismissing existing dialog');
-            this.dismiss();
+            this.dismiss(new Error('Dialog was replaced'));
         }
 
+        this.dismissed = null;
         this.modalRef = this.modalService.open(this.dialogContent, options);
 
         if (this.onOpen$) {
@@ -58,7 +56,9 @@ export class DialogComponent implements OnInit {
         return new Promise( (resolve, reject) => {
 
             this.modalRef.result.then(
+
                 (result) => {
+                    this.dismissed = false;
                     resolve(result);
                     this.modalRef = null;
                 },
@@ -67,21 +67,20 @@ export class DialogComponent implements OnInit {
                     // NgbModal creates some result values for us, which
                     // are outside of our control.  Other dismissal
                     // reasons are agreed upon by implementing subclasses.
-                    console.debug('dialog closed with ' + result);
-
-                    const dismissed = (
+                    this.dismissed = (
                            result === 0 // body click
                         || result === 1 // Esc key
                         || result === 'canceled' // Cancel button
                         || result === 'cross_click' // modal top-right X
                     );
 
-                    const rejection: DialogRejectionResponse = {
-                        dismissed: dismissed,
-                        message: result
-                    };
+                    if (this.dismissed) {
+                        resolve(null);
+                    } else {
+                        console.error('Dialog rejection occurred', result);
+                        reject(result);
+                    }
 
-                    reject(rejection);
                     this.modalRef = null;
                 }
             );
index a5c72e2..f162723 100644 (file)
@@ -121,16 +121,14 @@ export class WorkstationsComponent implements OnInit {
 
     private handleCollision(): Promise<number> {
         return new Promise((resolve, reject) => {
-            this.wsExistsDialog.open()
-            .then(
-                confirmed => {
+            this.wsExistsDialog.open().then(override => {
+                if (override) {
                     this.registerWorkstationApi(true).then(
                         wsId => resolve(wsId),
                         notOk => reject(notOk)
                     );
-                },
-                dismissed => reject(dismissed)
-            );
+                }
+            });
         });
     }
 
index 0afc01d..208d8aa 100644 (file)
@@ -41,10 +41,8 @@ export class MatchSetListComponent implements AfterViewInit {
 
         this.createNew = () => {
             this.editDialog.mode = 'create';
-            this.editDialog.open({size: 'lg'}).then(
-                ok => this.grid.reload(),
-                err => {}
-            );
+            this.editDialog.open({size: 'lg'})
+                .then(ok => this.grid.reload());
         };
 
         this.deleteSelected = (matchSets: IdlObject[]) => {
@@ -62,10 +60,8 @@ export class MatchSetListComponent implements AfterViewInit {
             (matchSet: IdlObject) => {
                 this.editDialog.mode = 'update';
                 this.editDialog.recId = matchSet.id();
-                this.editDialog.open({size: 'lg'}).then(
-                    ok => this.grid.reload(),
-                    err => {}
-                );
+                this.editDialog.open({size: 'lg'})
+                    .then(ok => this.grid.reload());
             }
         );
     }
index fbc62ba..89ab6c4 100644 (file)
@@ -218,35 +218,26 @@ export class QueueComponent implements OnInit, AfterViewInit {
     }
 
     deleteQueue() {
-        this.confirmDelDlg.open().then(
-            yes => {
-                this.progressDlg.open();
-                return this.net.request(
-                    'open-ils.vandelay',
-                    `open-ils.vandelay.${this.qtypeShort()}_queue.delete`,
-                    this.auth.token(), this.queueId
-                ).toPromise();
-            },
-            no => {
-                this.progressDlg.close();
-                return Promise.reject('delete failed');
-            }
-        ).then(
-            resp => {
-                this.progressDlg.close();
-                const e = this.evt.parse(resp);
-                if (e) {
-                    console.error(e);
-                    alert(e);
-                } else {
+
+        this.confirmDelDlg.open().then(confirmed => {
+            if (!confirmed) { return; }
+
+            this.progressDlg.open();
+            this.net.request(
+                'open-ils.vandelay',
+                `open-ils.vandelay.${this.qtypeShort()}_queue.delete`,
+                this.auth.token(), this.queueId
+            ).toPromise().then(
+                resp => {
+                    const e = this.evt.parse(resp);
+                    if (e) { return new Error(e.toString()); }
+
                     // Jump back to the main queue page.
                     this.router.navigate(['/staff/cat/vandelay/queue']);
-                }
-            },
-            err => {
-                this.progressDlg.close();
-            }
-        );
+                },
+                err => console.error('queue deletion failed!', err)
+            ).finally(() => this.progressDlg.close());
+        });
     }
 
     exportNonImported() {
index 3ab8e8f..2264f24 100644 (file)
@@ -81,10 +81,7 @@ export class PartsComponent implements OnInit {
             (part: IdlObject) => {
                 this.editDialog.mode = 'update';
                 this.editDialog.recId = part.id();
-                this.editDialog.open().then(
-                    ok => this.partsGrid.reload(),
-                    err => {}
-                );
+                this.editDialog.open().then(ok => this.partsGrid.reload());
             }
         );
 
@@ -95,10 +92,7 @@ export class PartsComponent implements OnInit {
             this.editDialog.record = part;
 
             this.editDialog.mode = 'create';
-            this.editDialog.open().then(
-                ok => this.partsGrid.reload(),
-                err => {}
-            );
+            this.editDialog.open().then(ok => this.partsGrid.reload());
         };
 
         this.deleteSelected = (parts: IdlObject[]) => {
@@ -113,10 +107,7 @@ export class PartsComponent implements OnInit {
         this.mergeSelected = (parts: IdlObject[]) => {
             if (parts.length < 2) { return; }
             this.mergeDialog.parts = parts;
-            this.mergeDialog.open().then(
-                ok => this.partsGrid.reload(),
-                err => console.debug('Dialog dismissed')
-            );
+            this.mergeDialog.open().then(ok => this.partsGrid.reload());
         };
     }
 }
index 9b058cd..e109d97 100644 (file)
@@ -137,16 +137,13 @@ export class SandboxComponent implements OnInit {
     }
 
     openEditor() {
-        this.fmRecordEditor.open({size: 'lg'}).then(
-            ok => { console.debug(ok); },
-            err => {
-                if (err && err.dismissed) {
-                    console.debug('dialog was dismissed');
-                } else {
-                    console.error(err);
-                }
+        this.fmRecordEditor.open({size: 'lg'}).then(ok => {
+            if (this.fmRecordEditor.dismissed) {
+                console.debug('fm editor dialog dismissed');
+            } else {
+                console.debug(ok);
             }
-        );
+        });
     }
 
     btGridRowClassCallback(row: any): string {
index 125d3a0..c934df3 100644 (file)
@@ -180,15 +180,17 @@ export class AdminPageComponent implements OnInit {
             this.editDialog.record = null;
             this.editDialog.open({size: this.dialogSize}).then(
                 ok => {
-                    this.createString.current()
-                        .then(str => this.toast.success(str));
-                    this.grid.reload();
+                    if (this.editDialog.dismissed) {
+                        console.debug('create action was dismissed');
+                    } else {
+                        this.createString.current()
+                            .then(str => this.toast.success(str));
+                        this.grid.reload();
+                    }
                 },
                 rejection => {
-                    if (!rejection.dismissed) {
-                        this.createErrString.current()
-                            .then(str => this.toast.danger(str));
-                    }
+                    this.createErrString.current()
+                        .then(str => this.toast.danger(str));
                 }
             );
         };
@@ -330,15 +332,17 @@ export class AdminPageComponent implements OnInit {
         this.editDialog.recId = idlThing[this.pkeyField]();
         return this.editDialog.open({size: this.dialogSize}).then(
             ok => {
-                this.successString.current()
-                    .then(str => this.toast.success(str));
-                this.grid.reload();
+                if (this.editDialog.dismissed) {
+                    console.debug('Edit dialog dismissed');
+                } else {
+                    this.successString.current()
+                        .then(str => this.toast.success(str));
+                    this.grid.reload();
+                }
             },
             rejection => {
-                if (!rejection.dismissed) {
-                    this.updateFailedString.current()
-                        .then(str => this.toast.danger(str));
-                }
+                this.updateFailedString.current()
+                    .then(str => this.toast.danger(str));
             }
         );
     }
index 14a504d..157d6e6 100644 (file)
@@ -18,7 +18,8 @@
     ],
     "lib": [
       "es2017",
-      "dom"
+      "dom",
+      "es2018.promise"
     ]
   }
 }