From 2e8162e07d6d02e654043d79466dc4c451769757 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Wed, 3 Apr 2019 15:59:56 -0400 Subject: [PATCH] LP1823041 Angular dialogs return observables Dialog.open() now returns an observable to the caller. This allows dialogs to pass 0 or more success events, error events, and close events each as descrete actions to the caller. Existing dialogs are updated to expect an Observable response to .open(). Signed-off-by: Bill Erickson --- .../share/accesskey/accesskey-info.component.html | 3 +- .../src/app/share/dialog/confirm.component.html | 7 +- .../eg2/src/app/share/dialog/dialog.component.ts | 112 +++++++++++++-------- .../src/app/share/dialog/progress.component.html | 2 +- .../eg2/src/app/share/dialog/prompt.component.html | 5 +- .../app/share/fm-editor/fm-editor.component.html | 10 +- .../src/app/share/fm-editor/fm-editor.component.ts | 14 +-- .../share/grid/grid-column-config.component.html | 3 +- .../workstations/workstations.component.ts | 2 +- .../staff/cat/vandelay/match-set-list.component.ts | 4 +- .../src/app/staff/cat/vandelay/queue.component.ts | 2 +- .../record/part-merge-dialog.component.html | 5 +- .../app/staff/catalog/record/parts.component.ts | 7 +- .../eg2/src/app/staff/sandbox/sandbox.component.ts | 12 +-- .../staff/share/admin-page/admin-page.component.ts | 40 ++++---- .../buckets/record-bucket-dialog.component.html | 3 +- .../staff/share/op-change/op-change.component.html | 5 +- .../staff/share/translate/translate.component.html | 5 +- 18 files changed, 129 insertions(+), 112 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/share/accesskey/accesskey-info.component.html b/Open-ILS/src/eg2/src/app/share/accesskey/accesskey-info.component.html index 82ed72a4b0..ae584cec40 100644 --- a/Open-ILS/src/eg2/src/app/share/accesskey/accesskey-info.component.html +++ b/Open-ILS/src/eg2/src/app/share/accesskey/accesskey-info.component.html @@ -2,8 +2,7 @@ diff --git a/Open-ILS/src/eg2/src/app/share/dialog/confirm.component.html b/Open-ILS/src/eg2/src/app/share/dialog/confirm.component.html index 21766cac09..3db73cc8e0 100644 --- a/Open-ILS/src/eg2/src/app/share/dialog/confirm.component.html +++ b/Open-ILS/src/eg2/src/app/share/dialog/confirm.component.html @@ -2,16 +2,15 @@ diff --git a/Open-ILS/src/eg2/src/app/share/dialog/dialog.component.ts b/Open-ILS/src/eg2/src/app/share/dialog/dialog.component.ts index 08ee743607..79a5c8605d 100644 --- a/Open-ILS/src/eg2/src/app/share/dialog/dialog.component.ts +++ b/Open-ILS/src/eg2/src/app/share/dialog/dialog.component.ts @@ -1,10 +1,30 @@ import {Component, Input, OnInit, ViewChild, TemplateRef, EventEmitter} from '@angular/core'; +import {Observable, Observer} from 'rxjs'; import {NgbModal, NgbModalRef, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap'; /** * Dialog base class. Handles the ngbModal logic. * Sub-classed component templates must have a #dialogContent selector * at the root of the template (see ConfirmDialogComponent). + * + * Dialogs interact with the caller via Observable. + * + * dialog.open().subscribe( + * value => handleValue(value), + * error => handleError(error), + * () => console.debug('dialog closed') + * ); + * + * It is up to the dialog implementer to decide what values to + * pass to the caller via the dialog.respond(data) and/or + * dialog.close(data) methods. + * + * dialog.close(...) closes the modal window and completes the + * observable, unless an error was previously passed, in which + * case the observable is already complete. + * + * dialog.close() with no data closes the dialog without passing + * any values to the caller. */ @Component({ @@ -25,10 +45,8 @@ export class DialogComponent implements OnInit { // called in the overridding method. onOpen$ = new EventEmitter(); - // null if the dialog has never been opened. - // true if the most recent instance was dismissed by the user, - // false otherwise. - dismissed: boolean = null; + // How we relay responses to the caller. + observer: Observer; // The modalRef allows direct control of the modal instance. private modalRef: NgbModalRef = null; @@ -39,13 +57,13 @@ export class DialogComponent implements OnInit { this.onOpen$ = new EventEmitter(); } - open(options?: NgbModalOptions): Promise { + open(options?: NgbModalOptions): Observable { if (this.modalRef !== null) { - this.dismiss(new Error('Dialog was replaced')); + this.error('Dialog was replaced!'); + this.finalize(); } - this.dismissed = null; this.modalRef = this.modalService.open(this.dialogContent, options); if (this.onOpen$) { @@ -53,50 +71,62 @@ export class DialogComponent implements OnInit { setTimeout(() => this.onOpen$.emit(true)); } - return new Promise( (resolve, reject) => { + return new Observable(observer => { + this.observer = observer; this.modalRef.result.then( - - (result) => { - this.dismissed = false; - resolve(result); - this.modalRef = null; - }, - - (result) => { - // NgbModal creates some result values for us, which - // are outside of our control. Other dismissal - // reasons are agreed upon by implementing subclasses. - this.dismissed = ( - result === 0 // body click - || result === 1 // Esc key - || result === 'canceled' // Cancel button - || result === 'cross_click' // modal top-right X - ); - - if (this.dismissed) { - resolve(null); - } else { - console.error('Dialog rejection occurred', result); - reject(result); - } - - this.modalRef = null; - } + // Results are relayed to the caller via our observer. + // Our Observer is marked complete via this.close(). + // Nothing to do here. + result => {}, + + // Modal was dismissed via UI control which + // bypasses call to this.close() + dismissed => this.finalize() ); }); } - close(reason?: any): void { - if (this.modalRef) { - this.modalRef.close(reason); + // Send a response to the caller without closing the dialog. + respond(value: any) { + if (this.observer && value !== undefined) { + this.observer.next(value); + } + } + + // Sends error event to the caller and closes the dialog. + // Once an error is sent, our observable is complete and + // cannot be used again to send any messages. + error(value: any, close?: boolean) { + if (this.observer) { + console.error('Dialog produced error', value); + this.observer.error(value); + this.observer = null; } + if (this.modalRef) { this.modalRef.close(); } + this.finalize(); + } + + // Close the dialog, optionally with a value to relay to the caller. + // Calling close() with no value simply dismisses the dialog. + close(value?: any) { + this.respond(value); + if (this.modalRef) { this.modalRef.close(); } + this.finalize(); + } + + dismiss() { + console.warn('Dialog.dismiss() is deprecated. Use close() instead'); + this.close(); } - dismiss(reason?: any): void { - if (this.modalRef) { - this.modalRef.dismiss(reason); + // Clean up after closing the dialog. + finalize() { + if (this.observer) { // null if this.error() called + this.observer.complete(); + this.observer = null; } + this.modalRef = null; } } diff --git a/Open-ILS/src/eg2/src/app/share/dialog/progress.component.html b/Open-ILS/src/eg2/src/app/share/dialog/progress.component.html index 78ca3d0c95..c1fdf20c0f 100644 --- a/Open-ILS/src/eg2/src/app/share/dialog/progress.component.html +++ b/Open-ILS/src/eg2/src/app/share/dialog/progress.component.html @@ -3,7 +3,7 @@ diff --git a/Open-ILS/src/eg2/src/app/share/dialog/prompt.component.html b/Open-ILS/src/eg2/src/app/share/dialog/prompt.component.html index 1d7936b176..17a6b50726 100644 --- a/Open-ILS/src/eg2/src/app/share/dialog/prompt.component.html +++ b/Open-ILS/src/eg2/src/app/share/dialog/prompt.component.html @@ -2,8 +2,7 @@ @@ -17,6 +16,6 @@ + (click)="close()" i18n>Cancel diff --git a/Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.html b/Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.html index aad65d15d6..2a6884186d 100644 --- a/Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.html +++ b/Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.html @@ -2,13 +2,18 @@ diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.ts index 2264f24e4d..2f59374084 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.ts @@ -81,7 +81,8 @@ export class PartsComponent implements OnInit { (part: IdlObject) => { this.editDialog.mode = 'update'; this.editDialog.recId = part.id(); - this.editDialog.open().then(ok => this.partsGrid.reload()); + this.editDialog.open() + .subscribe(ok => this.partsGrid.reload()); } ); @@ -92,7 +93,7 @@ export class PartsComponent implements OnInit { this.editDialog.record = part; this.editDialog.mode = 'create'; - this.editDialog.open().then(ok => this.partsGrid.reload()); + this.editDialog.open().subscribe(ok => this.partsGrid.reload()); }; this.deleteSelected = (parts: IdlObject[]) => { @@ -107,7 +108,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()); + this.mergeDialog.open().subscribe(ok => this.partsGrid.reload()); }; } } diff --git a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts index e109d97a2b..9579e9577e 100644 --- a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts @@ -137,13 +137,11 @@ export class SandboxComponent implements OnInit { } openEditor() { - this.fmRecordEditor.open({size: 'lg'}).then(ok => { - if (this.fmRecordEditor.dismissed) { - console.debug('fm editor dialog dismissed'); - } else { - console.debug(ok); - } - }); + this.fmRecordEditor.open({size: 'lg'}).subscribe( + pcrudResult => console.debug('Record editor performed action'), + err => console.error(err), + () => console.debug('Dialog closed') + ); } btGridRowClassCallback(row: any): string { diff --git a/Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.ts b/Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.ts index c934df39d0..ad509c8316 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.ts @@ -178,17 +178,13 @@ export class AdminPageComponent implements OnInit { // create action does not try to modify an existing record. this.editDialog.recId = null; this.editDialog.record = null; - this.editDialog.open({size: this.dialogSize}).then( - ok => { - if (this.editDialog.dismissed) { - console.debug('create action was dismissed'); - } else { - this.createString.current() - .then(str => this.toast.success(str)); - this.grid.reload(); - } + this.editDialog.open({size: this.dialogSize}).subscribe( + result => { + this.createString.current() + .then(str => this.toast.success(str)); + this.grid.reload(); }, - rejection => { + error => { this.createErrString.current() .then(str => this.toast.danger(str)); } @@ -327,24 +323,24 @@ export class AdminPageComponent implements OnInit { return this.contextOrg && this.contextOrg.children().length === 0; } - showEditDialog(idlThing: IdlObject) { + showEditDialog(idlThing: IdlObject): Promise { this.editDialog.mode = 'update'; this.editDialog.recId = idlThing[this.pkeyField](); - return this.editDialog.open({size: this.dialogSize}).then( - ok => { - if (this.editDialog.dismissed) { - console.debug('Edit dialog dismissed'); - } else { + return new Promise((resolve, reject) => { + this.editDialog.open({size: this.dialogSize}).subscribe( + result => { this.successString.current() .then(str => this.toast.success(str)); this.grid.reload(); + resolve(result); + }, + error => { + this.updateFailedString.current() + .then(str => this.toast.danger(str)); + reject(error); } - }, - rejection => { - this.updateFailedString.current() - .then(str => this.toast.danger(str)); - } - ); + ); + }); } } diff --git a/Open-ILS/src/eg2/src/app/staff/share/buckets/record-bucket-dialog.component.html b/Open-ILS/src/eg2/src/app/staff/share/buckets/record-bucket-dialog.component.html index a2c88b8e34..27eea66130 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/buckets/record-bucket-dialog.component.html +++ b/Open-ILS/src/eg2/src/app/staff/share/buckets/record-bucket-dialog.component.html @@ -10,8 +10,7 @@ Add Records from queue #{{qId}} to Bucket diff --git a/Open-ILS/src/eg2/src/app/staff/share/op-change/op-change.component.html b/Open-ILS/src/eg2/src/app/staff/share/op-change/op-change.component.html index e5a6f493b5..d472202999 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/op-change/op-change.component.html +++ b/Open-ILS/src/eg2/src/app/staff/share/op-change/op-change.component.html @@ -2,8 +2,7 @@ @@ -60,6 +59,6 @@ diff --git a/Open-ILS/src/eg2/src/app/staff/share/translate/translate.component.html b/Open-ILS/src/eg2/src/app/staff/share/translate/translate.component.html index 7aa59b46c3..61b9cb4f90 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/translate/translate.component.html +++ b/Open-ILS/src/eg2/src/app/staff/share/translate/translate.component.html @@ -4,8 +4,7 @@ {{idlClassDef.label}} @@ -58,6 +57,6 @@ - + -- 2.11.0