LP#1626157 op-change; toast wip
authorBill Erickson <berickxx@gmail.com>
Tue, 24 Apr 2018 16:00:07 +0000 (12:00 -0400)
committerBill Erickson <berickxx@gmail.com>
Tue, 24 Apr 2018 16:00:07 +0000 (12:00 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
15 files changed:
Open-ILS/src/eg2/src/app/core/auth.service.ts
Open-ILS/src/eg2/src/app/share/README
Open-ILS/src/eg2/src/app/share/dialog/dialog.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/catalog.module.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.ts
Open-ILS/src/eg2/src/app/staff/common.module.ts
Open-ILS/src/eg2/src/app/staff/nav.component.html
Open-ILS/src/eg2/src/app/staff/nav.component.ts
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts
Open-ILS/src/eg2/src/app/staff/share/bib-summary.component.html [deleted file]
Open-ILS/src/eg2/src/app/staff/share/bib-summary.component.ts [deleted file]
Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/staff.component.html

index 7557da2..9bd05dc 100644 (file)
@@ -47,7 +47,7 @@ export class EgAuthService {
     // opChangeUser refers to the user that has been superseded during
     // an op-change event.  opChangeUser resumes its status as the 
     // activeUser once the op-change cycle has completed.
-    private opChangeUser: EgAuthUser;
+    private opChangeUser: EgAuthUser = null;
 
     workstationState: EgAuthWsState = EgAuthWsState.PENDING;
 
@@ -70,6 +70,10 @@ export class EgAuthService {
             new BroadcastChannel('eg.auth') : {};
     }
 
+    // Returns true if we are currently in op-change mode.
+    opChangeIsActive(): boolean {
+        return this.opChangeUser !== null;
+    }
 
     // - Accessor functions always refer to the active user.
 
index 9da6f8a..8bd93d7 100644 (file)
@@ -1,5 +1,6 @@
 Shared Angular services, components, directives, and associated classes.  
 
-These items are NOT automatically imported to the base module.   Import
-as needed.
+These items are NOT automatically imported to the base module, though some
+may already be imported by intermediate modules (e.g. EgStaffCommonModule).   
+Import as needed.
 
index 0b2cbbc..1f979fc 100644 (file)
@@ -1,4 +1,4 @@
-import {Component, Input, ViewChild, TemplateRef} from '@angular/core';
+import {Component, Input, OnInit, ViewChild, TemplateRef, EventEmitter} from '@angular/core';
 import {NgbModal, NgbModalRef, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
 
 /** 
@@ -11,7 +11,7 @@ import {NgbModal, NgbModalRef, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap
     selector: 'eg-dialog',
     template: '<ng-template></ng-template>'
 })
-export class EgDialogComponent {
+export class EgDialogComponent implements OnInit {
 
     // Assume all dialogs support a title attribute.
     @Input() public dialogTitle: string;
@@ -20,11 +20,20 @@ export class EgDialogComponent {
     @ViewChild('dialogContent') 
     private dialogContent: TemplateRef<any>;
 
+    // Emitted after open() is called on the ngbModal.
+    // Note when overriding open(), this will not fire unless also 
+    // called in the overridding method.
+    onOpen$ = new EventEmitter<any>();
+
     // The modalRef allows direct control of the modal instance.
     private modalRef: NgbModalRef = null;
 
     constructor(private modalService: NgbModal) {}
 
+    ngOnInit() {
+        this.onOpen$ = new EventEmitter<any>();
+    }
+
     open(options?: NgbModalOptions): Promise<any> {
 
         if (this.modalRef !== null) {
@@ -33,6 +42,12 @@ export class EgDialogComponent {
         }
 
         this.modalRef = this.modalService.open(this.dialogContent, options);
+
+        if (this.onOpen$) {
+            // Let the digest cycle complete
+            setTimeout(() => this.onOpen$.emit(true));
+        }
+
         return new Promise( (resolve, reject) => {
 
             this.modalRef.result.then(
index 4bb63fd..635eec1 100644 (file)
@@ -9,7 +9,7 @@ import {SearchFormComponent} from './search-form.component';
 import {ResultsComponent} from './result/results.component';
 import {RecordComponent} from './record/record.component';
 import {CopiesComponent} from './record/copies.component';
-import {EgBibSummaryComponent} from '../share/bib-summary.component';
+import {EgBibSummaryComponent} from '@eg/staff/share/bib-summary/bib-summary.component';
 import {ResultPaginationComponent} from './result/pagination.component';
 import {ResultFacetsComponent} from './result/facets.component';
 import {ResultRecordComponent} from './result/record.component';
index 7df0e4a..ec9a302 100644 (file)
@@ -6,7 +6,7 @@ import {CatalogSearchContext, CatalogSearchState}
   from '@eg/share/catalog/search-context';
 import {EgCatalogService} from '@eg/share/catalog/catalog.service';
 import {StaffCatalogService} from '../catalog.service';
-import {EgBibSummaryComponent} from '../../share/bib-summary.component';
+import {EgBibSummaryComponent} from '@eg/staff/share/bib-summary/bib-summary.component';
 
 @Component({
   selector: 'eg-catalog-record',
index c8aeb1d..5f47962 100644 (file)
@@ -9,6 +9,9 @@ import {EgProgressDialogComponent} from '@eg/share/dialog/progress.component';
 import {EgAccessKeyDirective} from '@eg/share/accesskey/accesskey.directive';
 import {EgAccessKeyService} from '@eg/share/accesskey/accesskey.service';
 import {EgAccessKeyInfoComponent} from '@eg/share/accesskey/accesskey-info.component';
+import {EgOpChangeComponent} from '@eg/staff/share/op-change/op-change.component';
+import {EgToastService} from '@eg/share/toast/toast.service';
+import {EgToastComponent} from '@eg/share/toast/toast.component';
 
 /**
  * Imports the EG common modules and adds modules common to all staff UI's.
@@ -23,7 +26,9 @@ import {EgAccessKeyInfoComponent} from '@eg/share/accesskey/accesskey-info.compo
     EgPromptDialogComponent,
     EgProgressDialogComponent,
     EgAccessKeyDirective,
-    EgAccessKeyInfoComponent
+    EgAccessKeyInfoComponent,
+    EgToastComponent,
+    EgOpChangeComponent
   ],
   imports: [
     EgCommonModule
@@ -37,7 +42,9 @@ import {EgAccessKeyInfoComponent} from '@eg/share/accesskey/accesskey-info.compo
     EgPromptDialogComponent,
     EgProgressDialogComponent,
     EgAccessKeyDirective,
-    EgAccessKeyInfoComponent
+    EgAccessKeyInfoComponent,
+    EgToastComponent,
+    EgOpChangeComponent
   ]
 })
 
@@ -45,11 +52,11 @@ export class EgStaffCommonModule {
     static forRoot(): ModuleWithProviders {
         return {
             ngModule: EgStaffCommonModule,
-            providers: [
-                EgAccessKeyService
-                /* placeholder for exporting staff-wide services */
+            providers: [ // Export staff-wide services
+                EgAccessKeyService,
+                EgToastService
             ]
         };
     }
-
 }
+
index 8ca7cce..a56fd16 100644 (file)
           <i class="material-icons">list</i>
         </a>
         <div class="dropdown-menu" ngbDropdownMenu>
+          <eg-op-change #navOpChange></eg-op-change>
+          <a class="dropdown-item" *ngIf="!opChangeActive()" 
+            (click)="navOpChange.open()">
+            <span class="material-icons">transform</span>
+            <span i18n>Change Operator</span>
+          </a>
+          <a *ngIf="opChangeActive()" class="dropdown-item" 
+            (click)="restoreOperator()">
+            <span class="material-icons">transform</span>
+            <span i18n>Restore Operator</span>
+          </a>
           <a class="dropdown-item" (click)="logout()">
             <span class="material-icons">lock_outline</span>
             <span i18n>Logout</span>
index 32577ad..1e4053f 100644 (file)
@@ -25,6 +25,23 @@ export class EgStaffNavComponent implements OnInit {
         }
     }
 
+    opChangeActive(): boolean {
+        return this.auth.opChangeIsActive();
+    }
+
+    restoreOperator() { 
+        this.auth.undoOpChange().then(
+            ok => {
+                console.log('OP change undo succeeded');
+            },
+
+            err => {
+                console.warn('OP change undo auth expired');
+                this.router.navigate(['/staff/login']);
+            }
+        );
+    }
+
     // Broadcast to all tabs that we're logging out.
     // Redirect to the login page, which performs the remaining 
     // logout duties.
index a0579b6..1b55f39 100644 (file)
@@ -37,3 +37,6 @@
 </div>
 <!-- /Progress Dialog Experiments ----------------------------- -->
 
+<!-- eg toast -->
+<button class="btn btn-info" (click)="testToast()">Test Toast Message</button>
+
index 8e3c725..dae9e12 100644 (file)
@@ -1,5 +1,6 @@
 import {Component, OnInit, ViewChild} from '@angular/core';
 import {EgProgressDialogComponent} from '@eg/share/dialog/progress.component';
+import {EgToastService} from '@eg/share/toast/toast.service';
 
 @Component({
   templateUrl: 'sandbox.component.html'
@@ -9,7 +10,9 @@ export class EgSandboxComponent implements OnInit {
     @ViewChild('progressDialog')
     private progressDialog: EgProgressDialogComponent;
 
-    constructor() {}
+    constructor(
+        private toast: EgToastService
+    ) {}
 
     ngOnInit() {
     }
@@ -23,5 +26,9 @@ export class EgSandboxComponent implements OnInit {
         setTimeout(() => this.progressDialog.update({value: 95}), 4000);
         setTimeout(() => this.progressDialog.close(), 5000);
     }
+
+    testToast() {
+        this.toast.success('HELLO TOAST TEST');
+    }
 }
 
diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-summary.component.html b/Open-ILS/src/eg2/src/app/staff/share/bib-summary.component.html
deleted file mode 100644 (file)
index 6626608..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-
-<div class='eg-bib-summary card tight-card w-100' *ngIf="summary">
-  <div class="card-header d-flex">
-    <div class="font-weight-bold">
-      Record Summary
-    </div>
-    <div class="flex-1"></div>
-    <div>
-      <a class="with-material-icon no-href text-primary" 
-        title="Show More" i18n-title
-        *ngIf="!expandDisplay" (click)="expandDisplay=true">
-        <span class="material-icons">expand_more</span>
-      </a>
-      <a class="with-material-icon no-href text-primary" 
-        title="Show Less" i18n-title
-        *ngIf="expandDisplay" (click)="expandDisplay=false">
-        <span class="material-icons">expand_less</span>
-      </a>
-    </div>
-  </div>
-  <div class="card-body">
-    <ul class="list-group list-group-flush">
-      <li class="list-group-item">
-        <div class="d-flex">
-          <div class="flex-1 font-weight-bold" i18n>Title:</div>
-          <div class="flex-3">{{summary.title}}</div>
-          <div class="flex-1 font-weight-bold pl-1" i18n>Edition:</div>
-          <div class="flex-1">{{summary.edition}}</div>
-          <div class="flex-1 font-weight-bold" i18n>TCN:</div>
-          <div class="flex-1">{{summary.tcn_value}}</div>
-          <div class="flex-1 font-weight-bold pl-1" i18n>Created By:</div>
-          <div class="flex-1" *ngIf="summary.creator.usrname">
-            {{summary.creator.usrname()}}
-          </div>
-        </div>
-      </li>
-      <li class="list-group-item" *ngIf="expandDisplay">
-        <div class="d-flex">
-          <div class="flex-1 font-weight-bold" i18n>Author:</div>
-          <div class="flex-3">{{summary.author}}</div>
-          <div class="flex-1 font-weight-bold pl-1" i18n>Pubdate:</div>
-          <div class="flex-1">{{summary.pubdate}}</div>
-          <div class="flex-1 font-weight-bold" i18n>Database ID:</div>
-          <div class="flex-1">{{summary.id}}</div>
-          <div class="flex-1 font-weight-bold pl-1" i18n>Last Edited By:</div>
-          <div class="flex-1" *ngIf="summary.editor.usrname">
-            {{summary.editor.usrname()}}
-          </div>
-        </div>
-      </li>
-      <li class="list-group-item" *ngIf="expandDisplay">
-        <div class="d-flex">
-          <div class="flex-1 font-weight-bold" i18n>Bib Call #:</div>
-          <div class="flex-3">{{summary.callNumber}}</div>
-          <div class="flex-1 font-weight-bold" i18n>Record Owner:</div>
-          <div class="flex-1">TODO</div>
-          <div class="flex-1 font-weight-bold pl-1" i18n>Created On:</div>
-          <div class="flex-1">{{summary.create_date | date:'shortDate'}}</div>
-          <div class="flex-1 font-weight-bold pl-1" i18n>Last Edited On:</div>
-          <div class="flex-1">{{summary.edit_date | date:'shortDate'}}</div>
-        </div>
-      </li>
-    </ul>
-  </div>
-</div>
-
diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-summary.component.ts b/Open-ILS/src/eg2/src/app/staff/share/bib-summary.component.ts
deleted file mode 100644 (file)
index c672add..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-import {Component, OnInit, Input} from '@angular/core';
-import {EgNetService} from '@eg/core/net.service';
-import {EgPcrudService} from '@eg/core/pcrud.service';
-import {EgCatalogService} from '@eg/share/catalog/catalog.service';
-
-@Component({
-  selector: 'eg-bib-summary',
-  templateUrl: 'bib-summary.component.html'
-})
-export class EgBibSummaryComponent implements OnInit {
-
-    initDone: boolean = false;
-
-    // If provided, the record will be fetched by the component.
-    @Input() recordId: number;
-
-    // Otherwise, we'll use the provided bib summary object.
-    summary: any;
-    @Input() set bibSummary(s: any) {
-        this.summary = s;
-        if (this.initDone) this.fetchBibCallNumber();
-    }
-
-    expandDisplay: boolean = true;
-
-    constructor(
-        private cat: EgCatalogService,
-        private net: EgNetService,
-        private pcrud: EgPcrudService
-    ) {}
-
-    ngOnInit() { 
-        this.initDone = true;
-        if (this.summary) {
-            this.fetchBibCallNumber();
-        } else {
-            if (this.recordId) this.loadSummary();
-        }
-    }
-
-    loadSummary(): void {
-        this.cat.getBibSummary(this.recordId).then(summary => { 
-            this.summary = summary;
-            this.fetchBibCallNumber();
-            
-            // Flesh the user data
-            this.pcrud.search('au', {id: [summary.creator, summary.editor]})
-            .subscribe(user => {
-                if (user.id() == summary.creator)
-                    summary.creator = user;
-                if (user.id() == summary.editor)
-                    summary.editor = user;
-            })
-        });
-    }
-
-    fetchBibCallNumber(): void {
-        if (!this.summary || this.summary.callNumber) return;
-
-        // TODO labelClass = cat.default_classification_scheme YAOUS
-        let labelClass = 1;
-
-        this.net.request(
-            'open-ils.cat',
-            'open-ils.cat.biblio.record.marc_cn.retrieve',
-            this.summary.id, labelClass
-        ).subscribe(cnArray => {
-            if (cnArray && cnArray.length > 0) {
-                let key1 = Object.keys(cnArray[0])[0];
-                this.summary.callNumber = cnArray[0][key1];
-            }
-        });
-    }
-}
-
-
diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.html b/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.html
new file mode 100644 (file)
index 0000000..6626608
--- /dev/null
@@ -0,0 +1,66 @@
+
+<div class='eg-bib-summary card tight-card w-100' *ngIf="summary">
+  <div class="card-header d-flex">
+    <div class="font-weight-bold">
+      Record Summary
+    </div>
+    <div class="flex-1"></div>
+    <div>
+      <a class="with-material-icon no-href text-primary" 
+        title="Show More" i18n-title
+        *ngIf="!expandDisplay" (click)="expandDisplay=true">
+        <span class="material-icons">expand_more</span>
+      </a>
+      <a class="with-material-icon no-href text-primary" 
+        title="Show Less" i18n-title
+        *ngIf="expandDisplay" (click)="expandDisplay=false">
+        <span class="material-icons">expand_less</span>
+      </a>
+    </div>
+  </div>
+  <div class="card-body">
+    <ul class="list-group list-group-flush">
+      <li class="list-group-item">
+        <div class="d-flex">
+          <div class="flex-1 font-weight-bold" i18n>Title:</div>
+          <div class="flex-3">{{summary.title}}</div>
+          <div class="flex-1 font-weight-bold pl-1" i18n>Edition:</div>
+          <div class="flex-1">{{summary.edition}}</div>
+          <div class="flex-1 font-weight-bold" i18n>TCN:</div>
+          <div class="flex-1">{{summary.tcn_value}}</div>
+          <div class="flex-1 font-weight-bold pl-1" i18n>Created By:</div>
+          <div class="flex-1" *ngIf="summary.creator.usrname">
+            {{summary.creator.usrname()}}
+          </div>
+        </div>
+      </li>
+      <li class="list-group-item" *ngIf="expandDisplay">
+        <div class="d-flex">
+          <div class="flex-1 font-weight-bold" i18n>Author:</div>
+          <div class="flex-3">{{summary.author}}</div>
+          <div class="flex-1 font-weight-bold pl-1" i18n>Pubdate:</div>
+          <div class="flex-1">{{summary.pubdate}}</div>
+          <div class="flex-1 font-weight-bold" i18n>Database ID:</div>
+          <div class="flex-1">{{summary.id}}</div>
+          <div class="flex-1 font-weight-bold pl-1" i18n>Last Edited By:</div>
+          <div class="flex-1" *ngIf="summary.editor.usrname">
+            {{summary.editor.usrname()}}
+          </div>
+        </div>
+      </li>
+      <li class="list-group-item" *ngIf="expandDisplay">
+        <div class="d-flex">
+          <div class="flex-1 font-weight-bold" i18n>Bib Call #:</div>
+          <div class="flex-3">{{summary.callNumber}}</div>
+          <div class="flex-1 font-weight-bold" i18n>Record Owner:</div>
+          <div class="flex-1">TODO</div>
+          <div class="flex-1 font-weight-bold pl-1" i18n>Created On:</div>
+          <div class="flex-1">{{summary.create_date | date:'shortDate'}}</div>
+          <div class="flex-1 font-weight-bold pl-1" i18n>Last Edited On:</div>
+          <div class="flex-1">{{summary.edit_date | date:'shortDate'}}</div>
+        </div>
+      </li>
+    </ul>
+  </div>
+</div>
+
diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts b/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts
new file mode 100644 (file)
index 0000000..c672add
--- /dev/null
@@ -0,0 +1,76 @@
+import {Component, OnInit, Input} from '@angular/core';
+import {EgNetService} from '@eg/core/net.service';
+import {EgPcrudService} from '@eg/core/pcrud.service';
+import {EgCatalogService} from '@eg/share/catalog/catalog.service';
+
+@Component({
+  selector: 'eg-bib-summary',
+  templateUrl: 'bib-summary.component.html'
+})
+export class EgBibSummaryComponent implements OnInit {
+
+    initDone: boolean = false;
+
+    // If provided, the record will be fetched by the component.
+    @Input() recordId: number;
+
+    // Otherwise, we'll use the provided bib summary object.
+    summary: any;
+    @Input() set bibSummary(s: any) {
+        this.summary = s;
+        if (this.initDone) this.fetchBibCallNumber();
+    }
+
+    expandDisplay: boolean = true;
+
+    constructor(
+        private cat: EgCatalogService,
+        private net: EgNetService,
+        private pcrud: EgPcrudService
+    ) {}
+
+    ngOnInit() { 
+        this.initDone = true;
+        if (this.summary) {
+            this.fetchBibCallNumber();
+        } else {
+            if (this.recordId) this.loadSummary();
+        }
+    }
+
+    loadSummary(): void {
+        this.cat.getBibSummary(this.recordId).then(summary => { 
+            this.summary = summary;
+            this.fetchBibCallNumber();
+            
+            // Flesh the user data
+            this.pcrud.search('au', {id: [summary.creator, summary.editor]})
+            .subscribe(user => {
+                if (user.id() == summary.creator)
+                    summary.creator = user;
+                if (user.id() == summary.editor)
+                    summary.editor = user;
+            })
+        });
+    }
+
+    fetchBibCallNumber(): void {
+        if (!this.summary || this.summary.callNumber) return;
+
+        // TODO labelClass = cat.default_classification_scheme YAOUS
+        let labelClass = 1;
+
+        this.net.request(
+            'open-ils.cat',
+            'open-ils.cat.biblio.record.marc_cn.retrieve',
+            this.summary.id, labelClass
+        ).subscribe(cnArray => {
+            if (cnArray && cnArray.length > 0) {
+                let key1 = Object.keys(cnArray[0])[0];
+                this.summary.callNumber = cnArray[0][key1];
+            }
+        });
+    }
+}
+
+
index ac17f7a..2a2539c 100644 (file)
@@ -14,4 +14,6 @@
     (click)="egAccessKeyInfo.open()">
 </a>
 
+<!-- global toast alerts -->
+<eg-toast></eg-toast>