LPXXX Angular Volcopy
authorBill Erickson <berickxx@gmail.com>
Fri, 5 Jun 2020 16:30:10 +0000 (12:30 -0400)
committerBill Erickson <berickxx@gmail.com>
Fri, 5 Jun 2020 16:30:10 +0000 (12:30 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/staff/cat/volcopy/vol-edit.component.css
Open-ILS/src/eg2/src/app/staff/cat/volcopy/vol-edit.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/vol-edit.component.ts
Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.component.ts
Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.ts

index bfbc3ef..c109cac 100644 (file)
@@ -1,4 +1,11 @@
 
 input[type="number"] {
-  width: 5em;
+  /* visually accomodates numbers in the hundreds */
+  width: 4.5em;
+}
+
+.vol-row {
+  background-color: rgba(0,0,0,.03);
+  border-top: 1px solid rgba(0,0,0,.125);
+  border-bottom: 1px solid rgba(0,0,0,.125);
 }
index 115aaf3..dbfcbea 100644 (file)
@@ -1,8 +1,64 @@
 
-<div class="row bg-info p-2">
-  <b>BATCH</b>
+<div class="row d-flex vol-row border border-info mb-2">
+  <div class="p-1" [ngStyle]="{flex: flexAt(1)}">
+  </div>
+  <div class="p-1" [ngStyle]="{flex: flexAt(2)}">
+  </div>
+  <div class="p-1" [ngStyle]="{flex: flexAt(3)}">
+    <label class="font-weight-bold" i18n>Classification</label>
+    <div>
+      <eg-combobox [smallFormControl]="true" [(ngModel)]="batchVolClass">
+        <eg-combobox-entry *ngFor="let cls of volClasses" 
+          [entryId]="cls.id()" [entryLabel]="cls.name()">
+        </eg-combobox-entry>
+      </eg-combobox>
+    </div>
+  </div>
+  <div class="p-1" [ngStyle]="{flex: flexAt(4)}">
+    <label class="font-weight-bold" i18n>Prefix</label>
+    <div>
+      <eg-combobox [smallFormControl]="true" [(ngModel)]="batchVolPrefix">
+        <eg-combobox-entry *ngFor="let pfx of volPrefixes" 
+          [entryId]="pfx.id()" [entryLabel]="pfx.label()">
+        </eg-combobox-entry>
+      </eg-combobox>
+    </div>
+  </div>
+  <div class="p-1" [ngStyle]="{flex: flexAt(5)}">
+    <label class="font-weight-bold" i18n>Call Number Label</label>
+    <div>
+      <eg-combobox [smallFormControl]="true" [(ngModel)]="batchVolLabel">
+        <eg-combobox-entry *ngFor="let label of recordVolLabels" [entryId]="label">
+        </eg-combobox-entry>
+      </eg-combobox>
+    </div>
+  </div>
+  <div class="p-1" [ngStyle]="{flex: flexAt(6)}">
+    <label class="font-weight-bold" i18n>Suffix</label>
+    <div>
+      <eg-combobox [smallFormControl]="true" [(ngModel)]="batchVolSuffix">
+        <eg-combobox-entry *ngFor="let sfx of volSuffixes" 
+          [entryId]="sfx.id()" [entryLabel]="sfx.label()">
+        </eg-combobox-entry>
+      </eg-combobox>
+    </div>
+  </div>
+  <div class="p-1" [ngStyle]="{flex: flexAt(7)}">
+    <label class="font-weight-bold" i18n>Batch</label>
+    <div>
+      <button class="btn btn-outline-dark label-with-material-icon" 
+        (click)="batchVolApply()">
+        <span i18n>Apply</span>
+        <span class="material-icons">arrow_downward</span>
+      </button>
+    </div>
+  </div>
+  <div class="p-1" [ngStyle]="{flex: flexAt(8)}"></div>
+  <div class="p-1" [ngStyle]="{flex: flexAt(9)}"></div>
+  <div class="p-1" [ngStyle]="{flex: flexAt(10)}"></div>
 </div>
 
+
 <div class="row d-flex mt-2 mb-2">
   <div class="p-1" [ngStyle]="{flex: flexAt(1)}">
     <label class="font-weight-bold" i18n>Owning Library</label>
@@ -40,7 +96,7 @@
 <ng-container *ngFor="let orgNode of context.orgNodes(); let orgIdx = index">
   <ng-container *ngFor="let volNode of orgNode.children; let volIdx = index">
     <ng-container *ngFor="let copyNode of volNode.children; let copyIdx = index">
-      <div class="row d-flex mt-1">
+      <div class="row d-flex mt-1" [ngClass]="{'vol-row': copyIdx == 0}">
         <div class="p-1" [ngStyle]="{flex: flexAt(1)}">
           <span *ngIf="copyIdx == 0">{{orgNode.target.shortname()}}</span>
         </div>
               [startId]="volNode.target.label_class()"
               [smallFormControl]="true"
               [required]="true" 
-              (onChange)="applyVolValue(volNode.target, 'label_class', $event)">
+              (onChange)="applyVolValue(volNode.target, 'label_class', $event ? $event.id : null)">
               <eg-combobox-entry *ngFor="let cls of volClasses" 
                 [entryId]="cls.id()" [entryLabel]="cls.name()">
               </eg-combobox-entry>
               [startId]="volNode.target.prefix()"
               [required]="true" 
               [smallFormControl]="true"
-              (onChange)="applyVolValue(volNode.target, 'prefix', $event)">
-              <eg-combobox-entry 
-                [entryId]="-1" 
-                entryLabel="<Unset>" i18n-entryLabel>
-              </eg-combobox-entry>
+              (onChange)="applyVolValue(volNode.target, 'prefix', $event ? $event.id : null)">
               <eg-combobox-entry *ngFor="let pfx of volPrefixes" 
                 [entryId]="pfx.id()" [entryLabel]="pfx.label()">
               </eg-combobox-entry>
               [startId]="volNode.target.suffix()"
               [required]="true" 
               [smallFormControl]="true"
-              (onChange)="applyVolValue(volNode.target, 'suffix', $event)">
-              <eg-combobox-entry 
-                [entryId]="-1" 
-                entryLabel="<Unset>" i18n-entryLabel>
-              </eg-combobox-entry>
+              (onChange)="applyVolValue(volNode.target, 'suffix', $event ? $event.id : null)">
               <eg-combobox-entry *ngFor="let sfx of volSuffixes" 
                 [entryId]="sfx.id()" [entryLabel]="sfx.label()">
               </eg-combobox-entry>
index 2d58cc7..1a01e01 100644 (file)
@@ -2,6 +2,7 @@ import {Component, OnInit, AfterViewInit, ViewChild, Input, Renderer2} from '@an
 import {Router, ActivatedRoute, ParamMap} from '@angular/router';
 import {IdlObject} from '@eg/core/idl.service';
 import {OrgService} from '@eg/core/org.service';
+import {NetService} from '@eg/core/net.service';
 import {PcrudService} from '@eg/core/pcrud.service';
 import {VolCopyContext, HoldingsTreeNode} from './volcopy';
 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
@@ -30,14 +31,22 @@ export class VolEditComponent implements OnInit {
     volSuffixes: IdlObject[] = null;
     bibParts: {[bibId: number]: IdlObject[]} = {};
 
+    batchVolClass: number = null;
+    batchVolPrefix: number = null;
+    batchVolSuffix: number = null;
+    batchVolLabel: string = null;
+    recordVolLabels: string[] = [];
+
     constructor(
         private pcrud: PcrudService,
+        private net: NetService,
         private holdings: HoldingsService
     ) {}
 
     ngOnInit() {
 
-        this.fetchBibParts();
+        this.fetchRecordVolLabels()
+        .then(_ => this.fetchBibParts());
 
         // TODO: Filter these to only show org-scoped values
         // plus any values otherwise needed for the current
@@ -54,6 +63,26 @@ export class VolEditComponent implements OnInit {
             this.volSuffixes = suffixes.filter(pfx => pfx.id() !== -1));
     }
 
+    fetchRecordVolLabels(): Promise<any> {
+        // NOTE: see https://bugs.launchpad.net/evergreen/+bug/1874897
+        // for more on MARC call numbers and classification scheme.
+
+        this.recordVolLabels = [];
+        const ids = this.context.getRecordIds();
+
+        // It only makes sense to fetch bib call numbers when we are
+        // working with exactly one record.
+        if (ids.length !== 1) { return Promise.resolve(); }
+
+        return this.net.request(
+            'open-ils.cat',
+            'open-ils.cat.biblio.record.marc_cn.retrieve', ids[0]
+        ).toPromise().then(res => {
+            this.recordVolLabels = Object.values(res)
+                .map(blob => Object.values(blob)[0]).sort();
+        });
+    }
+
     fetchBibParts() {
 
         this.context.orgNodes().forEach(orgNode => {
@@ -99,6 +128,12 @@ export class VolEditComponent implements OnInit {
     }
 
     applyVolValue(vol: IdlObject, key: string, value: any) {
+
+        if (value === null && (key === 'prefix' || key === 'suffix')) {
+            // -1 is the empty prefix/suffix value.
+            value = -1;
+        }
+
         if (vol[key]() !== value) {
             vol[key](value);
             vol.ischanged(true);
@@ -115,5 +150,8 @@ export class VolEditComponent implements OnInit {
     copyPartChanged(copyNode: HoldingsTreeNode, entry: ComboboxEntry) {
         // TODO
     }
+
+    batchVolApply() {
+    }
 }
 
index cb4c8dc..8a5999e 100644 (file)
@@ -72,7 +72,10 @@ export class VolCopyComponent implements OnInit {
 
     setRecordId() {
         if (!this.recordId) {
-            this.recordId = this.context.getRecordId();
+            const ids = this.context.getRecordIds();
+            if (ids.length === 1) {
+                this.recordId = ids[0];
+            }
         }
     }
 
index 0f1ad56..c73a6bd 100644 (file)
@@ -32,22 +32,15 @@ export class VolCopyContext {
         return this.holdings.root.children;
     }
 
-    // If the holdings in question all link to a single bib
-    // record, return the ID of said record.  Otherwise null.
-    getRecordId(): number {
-        let id = null;
-        let nope = false;
+    // Returns IDs for all bib records represented in our holdings tree.
+    getRecordIds(): number[] {
+        const idHash: {[id: number]: boolean} = {};
         this.orgNodes().forEach(orgNode => {
-            orgNode.children.forEach(volNode => {
-                if (id === null) {
-                    id = volNode.target.record();
-                } else if (id !== volNode.target.record()) {
-                    nope = true;
-                }
-            })
+            orgNode.children.forEach(
+                volNode => idHash[volNode.target.record()] = true)
         });
 
-        return nope ? null : id;
+        return Object.keys(idHash).map(id => Number(id));
     }
 
     // Adds an org unit node; unsorted.