LP1850546 Record detail shelf browse
authorBill Erickson <berickxx@gmail.com>
Mon, 6 Jan 2020 16:05:52 +0000 (11:05 -0500)
committerBill Erickson <berickxx@gmail.com>
Fri, 21 Feb 2020 16:44:38 +0000 (11:44 -0500)
Adds support for browsing call numbers directly from a record detail
page, similar to the TPAC's 'Shelf Browser' tab in its detail page.

Add support for jumping to a record detail page or a new author search
from each shelf browse entry.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Ruth Frasur <rfrasur@gmail.com>

Open-ILS/src/eg2/src/app/staff/catalog/catalog.service.ts
Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse/results.component.html
Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse/results.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.html
Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.ts

index 05f5881..e46c1b4 100644 (file)
@@ -5,6 +5,7 @@ import {OrgService} from '@eg/core/org.service';
 import {CatalogService} from '@eg/share/catalog/catalog.service';
 import {CatalogUrlService} from '@eg/share/catalog/catalog-url.service';
 import {CatalogSearchContext} from '@eg/share/catalog/search-context';
+import {BibRecordSummary} from '@eg/share/catalog/bib-record.service';
 
 /**
  * Shared bits needed by the staff version of the catalog.
@@ -122,6 +123,16 @@ export class StaffCatalogService {
         params.ridx = '' + this.routeIndex++; // see comments above
         this.router.navigate(['/staff/catalog/cnbrowse'], {queryParams: params});
     }
+
+    // Params to genreate a new author search based on a reset
+    // clone of the current page params.
+    getAuthorSearchParams(summary: BibRecordSummary): any {
+        const tmpContext = this.cloneContext(this.searchContext);
+        tmpContext.reset();
+        tmpContext.termSearch.fieldClass = ['author'];
+        tmpContext.termSearch.query = [summary.display.author];
+        return this.catUrl.toUrlParams(tmpContext);
+    }
 }
 
 
index 4aff584..4a3da08 100644 (file)
@@ -25,8 +25,9 @@
 <!-- header, pager, and list of records -->
 <div id="staff-catalog-browse-results-container" *ngIf="browseHasResults()">
 
-  <div class="row mb-2">
-    <div class="col-lg-3">
+  <div class="row mb-2 d-flex">
+    <div class="flex-1"></div>
+    <div>
       <button class="btn btn-primary" (click)="prevPage()">Back</button>
       <button class="btn btn-primary ml-3" (click)="nextPage()">Next</button>
     </div>
                 {{callNumber.suffix().label()}}
                 @ {{orgName(callNumber.owning_lib())}}
               </div>
-              <div>{{callNumber._bibSummary.display.title}}</div>
-              <div>{{callNumber._bibSummary.display.author}}</div>
+              <div>
+                <a queryParamsHandling="merge"
+                  routerLink="/staff/catalog/record/{{callNumber._bibSummary.id}}">
+                  {{callNumber._bibSummary.display.title}}
+                </a>
+              </div>
+              <div>
+                <a routerLink="/staff/catalog/search"
+                  [queryParams]="getAuthorSearchParams(callNumber._bibSummary)">
+                  {{callNumber._bibSummary.display.author}}
+                </a>
+              </div>
             </div>
             <div class="ml-2">
               <img src="/opac/extras/ac/jacket/small/r/{{callNumber._bibSummary.id}}"/>
     </div>
   </ng-container>
 
-
-  <div class="row mb-2">
-    <div class="col-lg-3">
+  <div class="row mb-2 d-flex">
+    <div class="flex-1"></div>
+    <div>
       <button class="btn btn-primary" (click)="prevPage()">Back</button>
       <button class="btn btn-primary ml-3" (click)="nextPage()">Next</button>
     </div>
   </div>
-
 </div>
 
 
index bddf40e..464f443 100644 (file)
@@ -2,6 +2,7 @@ import {Component, Input, OnInit, OnDestroy} from '@angular/core';
 import {ActivatedRoute, Router, ParamMap} from '@angular/router';
 import {Subscription} from 'rxjs';
 import {IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
 import {CatalogService} from '@eg/share/catalog/catalog.service';
 import {BibRecordService} from '@eg/share/catalog/bib-record.service';
 import {CatalogUrlService} from '@eg/share/catalog/catalog-url.service';
@@ -16,6 +17,9 @@ import {OrgService} from '@eg/core/org.service';
 })
 export class CnBrowseResultsComponent implements OnInit, OnDestroy {
 
+    // If set, this is a bib-focused browse
+    @Input() bibSummary: BibRecordSummary;
+
     @Input() rowCount = 5;
     rowIndexList: number[] = [];
 
@@ -23,13 +27,18 @@ export class CnBrowseResultsComponent implements OnInit, OnDestroy {
     colCount = 3;
 
     searchContext: CatalogSearchContext;
-    results: any[];
+    results: any[] = [];
     routeSub: Subscription;
 
+    // When browsing by a specific record, keep tabs on the initial
+    // browse call number.
+    browseCn: string;
+
     constructor(
         private router: Router,
         private route: ActivatedRoute,
         private org: OrgService,
+        private pcrud: PcrudService,
         private cat: CatalogService,
         private bib: BibRecordService,
         private catUrl: CatalogUrlService,
@@ -43,20 +52,53 @@ export class CnBrowseResultsComponent implements OnInit, OnDestroy {
             this.rowIndexList.push(idx);
         }
 
-        this.routeSub = this.route.queryParamMap.subscribe(
-            (params: ParamMap) => this.browseByUrl(params)
-        );
+        let promise = Promise.resolve();
+        if (this.bibSummary) {
+            promise = this.getBrowseCallnumber();
+        }
+
+        promise.then(_ => {
+            this.routeSub = this.route.queryParamMap.subscribe(
+                (params: ParamMap) => this.browseByUrl(params)
+            );
+        });
     }
 
     ngOnDestroy() {
         this.routeSub.unsubscribe();
     }
 
+    getBrowseCallnumber(): Promise<any> {
+        let org = this.searchContext.searchOrg.id();
+
+        if (this.searchContext.searchOrg.ou_type().can_have_vols() === 'f') {
+            // If the current search org unit cannot hold volumes, search
+            // across child org units.
+            org = this.org.descendants(this.searchContext.searchOrg, true);
+        }
+
+        return this.pcrud.search('acn',
+            {record: this.bibSummary.id, owning_lib: org},
+            {limit: 1}
+        ).toPromise().then(cn =>
+            this.browseCn = cn ? cn.label() : this.bibSummary.bibCallNumber
+        );
+    }
+
     browseByUrl(params: ParamMap): void {
         this.catUrl.applyUrlParams(this.searchContext, params);
+        this.getBrowseResults();
+    }
+
+    getBrowseResults() {
         const cbs = this.searchContext.cnBrowseSearch;
         cbs.limit = this.rowCount * this.colCount;
 
+        if (this.browseCn) {
+            // Override any call number browse URL parameters
+            cbs.value = this.browseCn;
+        }
+
         if (cbs.isSearchable()) {
             this.results = [];
             this.cat.cnBrowse(this.searchContext)
@@ -114,12 +156,23 @@ export class CnBrowseResultsComponent implements OnInit, OnDestroy {
 
     prevPage() {
         this.searchContext.cnBrowseSearch.offset--;
-        this.staffCat.cnBrowse();
+        if (this.bibSummary) {
+            // Browse without navigation
+            this.getBrowseResults();
+        } else {
+            this.staffCat.cnBrowse();
+        }
+
     }
 
     nextPage() {
         this.searchContext.cnBrowseSearch.offset++;
-        this.staffCat.cnBrowse();
+        if (this.bibSummary) {
+            // Browse without navigation
+            this.getBrowseResults();
+        } else {
+            this.staffCat.cnBrowse();
+        }
     }
 
     /**
@@ -145,6 +198,10 @@ export class CnBrowseResultsComponent implements OnInit, OnDestroy {
     orgName(orgId: number): string {
         return this.org.get(orgId).shortname();
     }
+
+    getAuthorSearchParams(summary: BibRecordSummary): any {
+        return this.staffCat.getAuthorSearchParams(summary);
+    }
 }
 
 
index b82dd74..a9330c3 100644 (file)
           </eg-catalog-record-conjoined>
         </ng-template>
       </ngb-tab>
+      <ngb-tab title="Shelf Browse" i18n-title id="cnbrowse">
+        <ng-template ngbTabContent>
+          <ng-container *ngIf="summary">
+            <div class="mt-2">
+              <eg-catalog-cn-browse-results [bibSummary]="summary">
+              </eg-catalog-cn-browse-results>
+            </div>
+          </ng-container>
+        </ng-template>
+      </ngb-tab>
       <ngb-tab title="Patron View" i18n-title id="catalog">
         <ng-template ngbTabContent>
           <eg-opac-record-detail [recordId]="recordId">
index b46e4ca..8cb7f03 100644 (file)
@@ -85,11 +85,7 @@ export class ResultRecordComponent implements OnInit, OnDestroy {
     // Params to genreate a new author search based on a reset
     // clone of the current page params.
     getAuthorSearchParams(summary: BibRecordSummary): any {
-        const tmpContext = this.staffCat.cloneContext(this.searchContext);
-        tmpContext.reset();
-        tmpContext.termSearch.fieldClass = ['author'];
-        tmpContext.termSearch.query = [summary.display.author];
-        return this.catUrl.toUrlParams(tmpContext);
+        return this.staffCat.getAuthorSearchParams(summary);
     }
 
     // Returns the URL parameters for the current page plus the