LP1806087 Group formats and editions (WIP)
authorBill Erickson <berickxx@gmail.com>
Tue, 18 Dec 2018 21:15:17 +0000 (16:15 -0500)
committerBill Erickson <berickxx@gmail.com>
Mon, 7 Jan 2019 14:58:44 +0000 (09:58 -0500)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/catalog/bib-record.service.ts
Open-ILS/src/eg2/src/app/share/catalog/catalog-url.service.ts
Open-ILS/src/eg2/src/app/share/catalog/catalog.service.ts
Open-ILS/src/eg2/src/app/share/catalog/search-context.ts
Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.html
Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.ts

index c29c33a..6b00e79 100644 (file)
@@ -3,6 +3,7 @@ import {Observable} from 'rxjs/Observable';
 import {mergeMap} from 'rxjs/operators/mergeMap';
 import {from} from 'rxjs/observable/from';
 import {map} from 'rxjs/operators/map';
+import {tap} from 'rxjs/operators/tap';
 import {OrgService} from '@eg/core/org.service';
 import {UnapiService} from '@eg/share/catalog/unapi.service';
 import {IdlService, IdlObject} from '@eg/core/idl.service';
@@ -204,47 +205,53 @@ export class BibRecordService {
     compileMetabib(metabib: IdlObject, 
         orgId?: number, orgDepth?: number): Observable<BibRecordSummary> {
 
-        const bibIds = metabib.source_maps().map(map => map.source());
+        // TODO: Create an API similar to the one that builds a combined
+        // mods blob for metarecords, except using display fields, etc.
+        // For now, this seems to get the job done.
+
+        // Non-master records
+        const relatedBibIds = metabib.source_maps()
+            .map(map => map.source())
+            .filter(id => id !== metabib.master_record());
+
         let observer;
-        const observable = 
-            new Observable<BibRecordSummary>(o => observer = o);
-
-        let master;
-        const summaries = [];
-
-        // NOTE if we only need to augment with 'mattrs' it would be
-        // faster to just grab those than to fetch the full bib-summary
-        // for related records.  Revisit.
-
-        this.getBibSummary(bibIds, orgId, orgDepth).subscribe(
-            sum => {
-                summaries.push(sum);
-                if (sum.id === Number(metabib.master_record())) {
-                    master = sum;
-                    master.metabibId = metabib.id();
-                }
-            },
-            err => {},
-            ()  => {
-                summaries.forEach(sum => {
-                    if (sum.id !== master.id) {
-                        master.record.mattrs(
-                            master.record.mattrs().concat(sum.record.mattrs()))
-                    }
-                });
+        const observable = new Observable<BibRecordSummary>(o => observer = o);
+
+        // NOTE: getBibSummary calls getHoldingsSummary against
+        // the bib record unnecessarily.  It's called again below.
+        // Reconsider this approach (see also note above about API).
+        this.getBibSummary(metabib.master_record(), orgId, orgDepth)
+        .subscribe(summary => {
+            summary.metabibId = metabib.id();
 
-                // Recompile attributes now that the data has been augmented
-                master.compileRecordAttrs();
+            let promise;
+
+            if (relatedBibIds.length > 0) {
+
+                // Grab data for MR bib summary augmentation
+                promise = this.pcrud.search('mraf', {id: relatedBibIds})
+                    .pipe(tap(attr => summary.record.mattrs().push(attr)))
+                    .toPromise();
+            } else {
+
+                // Metarecord has only one constituent bib.
+                promise = Promise.resolve();
+            }
+
+            promise.then(() => {
+
+                // Re-compile with augmented data
+                summary.compileRecordAttrs();
 
                 // Fetch holdings data for the metarecord
                 this.getHoldingsSummary(metabib.id(), orgId, orgDepth, true)
                 .then(holdingsSummary => {
-                    master.holdingsSummary = holdingsSummary;
-                    observer.next(master);
+                    summary.holdingsSummary = holdingsSummary;
+                    observer.next(summary);
                     observer.complete();
                 });
-            }
-        );
+            });
+        });
 
         return observable;
     }
index 1b85d71..cfec1d9 100644 (file)
@@ -80,8 +80,8 @@ export class CatalogUrlService {
             params.joinOp = [];
             params.matchOp = [];
 
-            ['format', 'available', 'hasBrowseEntry', 
-                'date1', 'date2', 'dateOp', 'isMetarecord']
+            ['format', 'available', 'hasBrowseEntry', 'date1', 
+                'date2', 'dateOp', 'isMetarecord', 'fromMetarecord']
             .forEach(field => {
                 if (ts[field]) {
                     params[field] = ts[field];
@@ -196,7 +196,8 @@ export class CatalogUrlService {
         } else if (params.has('query')) {
 
             // Scalars
-            ['format', 'available', 'date1', 'date2', 'dateOp', 'isMetarecord']
+            ['format', 'available', 'date1', 'date2', 
+                'dateOp', 'isMetarecord', 'fromMetarecord']
             .forEach(field => {
                 if (params.has(field)) {
                     ts[field] = params.get(field);
index b210103..c741acb 100644 (file)
@@ -122,7 +122,9 @@ export class CatalogService {
         console.debug(`search query: ${fullQuery}`);
 
         let method = 'open-ils.search.biblio.multiclass.query';
-        if (ctx.termSearch.isSearchable() && ctx.termSearch.isMetarecord) {
+        if (ctx.termSearch.isSearchable() 
+            && ctx.termSearch.isMetarecord
+            && !ctx.termSearch.fromMetarecord) {
             method = 'open-ils.search.metabib.multiclass.query';
         }
 
@@ -169,9 +171,12 @@ export class CatalogService {
             ctx.org.root().ou_type().depth() :
             ctx.searchOrg.ou_type().depth();
 
+        // Term search, looking for metarecords, but no 
+        // specific metarecord has been selected for display.
         const isMeta = (
             ctx.termSearch.isSearchable() && 
-            ctx.termSearch.isMetarecord
+            ctx.termSearch.isMetarecord &&
+            !ctx.termSearch.fromMetarecord
         );
 
         let observable: Observable<BibRecordSummary>;
index c4bb493..56ab527 100644 (file)
@@ -122,7 +122,13 @@ export class CatalogTermContext {
     ccvmFilters: {[ccvmCode: string]: string[]};
     facetFilters: FacetFilter[];
     copyLocations: string[]; // ID's, but treated as strings in the UI.
+
+    // True when searching for metarecords
     isMetarecord: boolean;
+
+    // Filter results by records which link to this metarecord ID.
+    fromMetarecord: number;
+
     hasBrowseEntry: string; // "entryId,fieldId"
     date1: number;
     date2: number;
@@ -140,6 +146,7 @@ export class CatalogTermContext {
         this.date1 = null;
         this.date2 = null;
         this.dateOp = 'is';
+        this.fromMetarecord = null;
 
         // Apply empty string values for each ccvm filter
         this.ccvmFilters = {};
@@ -150,6 +157,7 @@ export class CatalogTermContext {
         return (
             this.query[0] !== ''
             || this.hasBrowseEntry !== ''
+            || this.fromMetarecord !== null
         );
     }
 
@@ -416,6 +424,10 @@ export class CatalogSearchContext {
             str += ` has_browse_entry(${ts.hasBrowseEntry})`;
         }
 
+        if (ts.fromMetarecord) {
+            str += ` from_metarecord(${ts.fromMetarecord})`;
+        }
+
         if (ts.format) {
             str += ' format(' + ts.format + ')';
         }
index 928d1a1..ddfacc0 100644 (file)
@@ -32,7 +32,7 @@
             <div class="col-lg-12 font-weight-bold">
               <!-- nbsp allows the column to take shape when no value exists -->
               <a href="javascript:void(0)"
-                (click)="navigatToRecord(summary.id)">
+                (click)="navigatToRecord(summary)">
                 {{summary.display.title || '&nbsp;'}}
               </a>
             </div>
             <div class="float-right">
               <span>
                 <button (click)="placeHold()"
+                  [disabled]="summary.metabibId"
                   class="btn btn-sm btn-success label-with-material-icon small-text-1">
                   <span class="material-icons">check</span>
                   <span i18n>Place Hold</span>
index 5224c38..5e6d25b 100644 (file)
@@ -76,11 +76,17 @@ export class ResultRecordComponent implements OnInit, OnDestroy {
     /**
      * Propagate the search params along when navigating to each record.
      */
-    navigatToRecord(id: number) {
+    navigatToRecord(summary: BibRecordSummary) {
         const params = this.catUrl.toUrlParams(this.searchContext);
 
+        if (summary.metabibId) {
+            this.searchContext.termSearch.fromMetarecord = summary.metabibId;
+            this.staffCat.search();
+            return;
+        }
+
         this.router.navigate(
-          ['/staff/catalog/record/' + id], {queryParams: params});
+          ['/staff/catalog/record/' + summary.id], {queryParams: params});
     }
 
     toggleBasketEntry() {
index a558011..049b677 100644 (file)
@@ -193,6 +193,7 @@ export class SearchFormComponent implements OnInit, AfterViewInit {
                 this.context.browseSearch.reset();
                 this.context.identSearch.reset();
                 this.context.termSearch.hasBrowseEntry = '';
+                this.context.termSearch.fromMetarecord = null;
                 this.staffCat.search();
                 break;