LP1806087 Browse entry display/facets; holds improvements
authorBill Erickson <berickxx@gmail.com>
Thu, 27 Dec 2018 21:53:57 +0000 (16:53 -0500)
committerBill Erickson <berickxx@gmail.com>
Thu, 10 Jan 2019 17:24:18 +0000 (12:24 -0500)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/examples/fm_IDL.xml
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/hold/hold.component.html
Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.html
Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html
Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.ts

index e934ae6..d78bb92 100644 (file)
@@ -4120,6 +4120,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <links>
                        <link field="def_maps" reltype="has_many" key="entry" map="" class="mbedm"/>
                </links>
+               <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+                       <actions>
+                               <retrieve/>
+                       </actions>
+               </permacrud>
        </class>
        <class id="mbedm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="metabib::browse_entry_def_map" oils_persist:tablename="metabib.browse_entry_def_map" reporter:label="Combined Browse Entry Definition Map" oils_persist:readonly="true">
                <fields oils_persist:primary="id" oils_persist:sequence="metabib.browse_entry_def_map_id_seq">
index cfec1d9..0f07070 100644 (file)
@@ -81,7 +81,7 @@ export class CatalogUrlService {
             params.matchOp = [];
 
             ['format', 'available', 'hasBrowseEntry', 'date1', 
-                'date2', 'dateOp', 'isMetarecord', 'fromMetarecord']
+                'date2', 'dateOp', 'groupByMetarecord', 'fromMetarecord']
             .forEach(field => {
                 if (ts[field]) {
                     params[field] = ts[field];
@@ -187,17 +187,21 @@ export class CatalogUrlService {
 
         const ts = context.termSearch;
 
+        // browseEntry and query searches may be facet-limited
+        params.getAll('facets').forEach(blob => {
+            const facet = JSON.parse(blob);
+            ts.addFacet(new FacetFilter(facet.c, facet.n, facet.v));
+        });
+
         if (params.has('hasBrowseEntry')) {
 
-            // Browse entry display is (currently) a standalone filter.
-            // Other filters could be applied if needed.
             ts.hasBrowseEntry = params.get('hasBrowseEntry');
 
         } else if (params.has('query')) {
 
             // Scalars
             ['format', 'available', 'date1', 'date2', 
-                'dateOp', 'isMetarecord', 'fromMetarecord']
+                'dateOp', 'groupByMetarecord', 'fromMetarecord']
             .forEach(field => {
                 if (params.has(field)) {
                     ts[field] = params.get(field);
@@ -221,11 +225,6 @@ export class CatalogUrlService {
                 }
             });
 
-            params.getAll('facets').forEach(blob => {
-                const facet = JSON.parse(blob);
-                ts.addFacet(new FacetFilter(facet.c, facet.n, facet.v));
-            });
-
             if (params.get('copyLocations')) {
                 ts.copyLocations = params.get('copyLocations').split(/,/);
             }
index c741acb..86a014d 100644 (file)
@@ -53,7 +53,7 @@ export class CatalogService {
             ctx.identSearch.queryType === 'item_barcode') {
             return this.barcodeSearch(ctx);
         } else {
-            return this.querySearch(ctx);
+            return this.termSearch(ctx);
         }
     }
 
@@ -110,28 +110,33 @@ export class CatalogService {
         });
     }
 
-    querySearch(ctx: CatalogSearchContext): Promise<void> {
+    termSearch(ctx: CatalogSearchContext): Promise<void> {
+
+        let method = 'open-ils.search.biblio.multiclass.query';
         let fullQuery;
 
         if (ctx.identSearch.isSearchable()) {
             fullQuery = ctx.compileIdentSearchQuery();
+
         } else {
             fullQuery = ctx.compileTermSearchQuery();
-        }
 
-        console.debug(`search query: ${fullQuery}`);
+            if (ctx.termSearch.groupByMetarecord 
+                && !ctx.termSearch.fromMetarecord) {
+                method = 'open-ils.search.metabib.multiclass.query';
+            }
 
-        let method = 'open-ils.search.biblio.multiclass.query';
-        if (ctx.termSearch.isSearchable() 
-            && ctx.termSearch.isMetarecord
-            && !ctx.termSearch.fromMetarecord) {
-            method = 'open-ils.search.metabib.multiclass.query';
+            if (ctx.termSearch.hasBrowseEntry) {
+                this.fetchBrowseEntry(ctx);
+            }
         }
 
+        console.debug(`search query: ${fullQuery}`);
+
         if (ctx.isStaff) {
             method += '.staff';
         }
-
+        
         return new Promise((resolve, reject) => {
             this.net.request(
                 'open-ils.search', method, {
@@ -148,6 +153,19 @@ export class CatalogService {
 
     }
 
+    // When showing titles linked to a browse entry, fetch 
+    // the entry data as well so the UI can display it.
+    fetchBrowseEntry(ctx: CatalogSearchContext) {
+        const ts = ctx.termSearch;
+
+        const parts = ts.hasBrowseEntry.split(',');
+        const mbeId = parts[0];
+        const cmfId = parts[1];
+
+        this.pcrud.retrieve('mbe', mbeId)
+        .subscribe(mbe => ctx.termSearch.browseEntry = mbe);
+    }
+
     applyResultData(ctx: CatalogSearchContext, result: any): void {
         ctx.result = result;
         ctx.pager.resultCount = result.count;
@@ -175,7 +193,7 @@ export class CatalogService {
         // specific metarecord has been selected for display.
         const isMeta = (
             ctx.termSearch.isSearchable() && 
-            ctx.termSearch.isMetarecord &&
+            ctx.termSearch.groupByMetarecord &&
             !ctx.termSearch.fromMetarecord
         );
 
index 56ab527..11e5c89 100644 (file)
@@ -124,12 +124,13 @@ export class CatalogTermContext {
     copyLocations: string[]; // ID's, but treated as strings in the UI.
 
     // True when searching for metarecords
-    isMetarecord: boolean;
+    groupByMetarecord: boolean;
 
     // Filter results by records which link to this metarecord ID.
     fromMetarecord: number;
 
     hasBrowseEntry: string; // "entryId,fieldId"
+    browseEntry: IdlObject;
     date1: number;
     date2: number;
     dateOp: string; // before, after, between, is
index a0e4797..7ff4140 100644 (file)
   <div class="row mt-2">
     <div class="col-lg-3">
       <button class="btn btn-success" (click)="placeHolds()" 
-        [disabled]="!user" i18n>Place Hold(s)</button>
+        [disabled]="!user || placeHoldsClicked" i18n>Place Hold(s)</button>
     </div>
   </div>
 </form>
         </ng-container>
       </div>
       <div class="col-lg-2">
-        <ng-container *ngIf="!ctx.lastRequest">
+        <ng-container *ngIf="!ctx.lastRequest && !ctx.processing">
           <div class="alert alert-info" i18n>Hold Pending</div>
         </ng-container>
+        <ng-container *ngIf="ctx.processing">
+          <div class="alert alert-primary" i18n>Hold Processing...</div>
+        </ng-container>
         <ng-container *ngIf="ctx.lastRequest">
           <ng-container *ngIf="ctx.lastRequest.result.success">
             <div class="alert alert-success" i18n>Hold Succeeded</div>
index a8c9fcb..b7f341d 100644 (file)
@@ -22,6 +22,7 @@ class HoldContext {
     holdTarget: number;
     lastRequest: HoldRequest;
     canOverride?: boolean;
+    processing: boolean;
 }
 
 @Component({
@@ -52,6 +53,7 @@ export class HoldComponent implements OnInit {
     smsCarriers: ComboboxEntry[];
 
     smsEnabled: boolean;
+    placeHoldsClicked: boolean;
 
     constructor(
         private router: Router,
@@ -234,14 +236,21 @@ export class HoldComponent implements OnInit {
     placeHolds(idx?: number) {
         if (!idx) { idx = 0; }
         if (!this.holdTargets[idx]) { return; }
-        this.placeOneHold(this.holdTargets[idx])
-            .then(() => this.placeHolds(idx + 1));
+        this.placeHoldsClicked = true;
+
+        const target = this.holdTargets[idx];
+        const ctx = this.holdContexts.filter(
+            ctx => ctx.holdTarget === target)[0];
+
+        this.placeOneHold(ctx).then(() => this.placeHolds(idx + 1));
     }
 
-    placeOneHold(target: number, override?: boolean): Promise<any> {
+    placeOneHold(ctx: HoldContext, override?: boolean): Promise<any> {
+
+        ctx.processing = true;
 
         return this.holds.placeHold({
-            holdTarget: target,
+            holdTarget: ctx.holdTarget,
             holdType: this.holdType,
             recipient: this.user.id(),
             requestor: this.requestor.id(),
@@ -254,29 +263,33 @@ export class HoldComponent implements OnInit {
             thawDate: this.suspend ? this.activeDate : null,
             frozen: this.suspend
 
-        }).toPromise().then(request => {
-            console.log('hold returned: ', request);
-
-            const ctx = this.holdContexts.filter(
-                ctx => ctx.holdTarget === request.holdTarget)[0];
-            ctx.lastRequest = request;
-
-            // If this request failed and was not already an override,
-            // see of this user has permission to override.
-            if (!request.override && 
-                !request.result.success && request.result.evt) {
-
-                const txtcode = request.result.evt.textcode;
-                const perm = txtcode + '.override';
-
-                return this.perm.hasWorkPermHere(perm).then(
-                    permResult => ctx.canOverride = permResult[perm]);
+        }).toPromise().then(
+            request => {
+                console.log('hold returned: ', request);
+                ctx.lastRequest = request;
+                ctx.processing = false;
+    
+                // If this request failed and was not already an override,
+                // see of this user has permission to override.
+                if (!request.override && 
+                    !request.result.success && request.result.evt) {
+    
+                    const txtcode = request.result.evt.textcode;
+                    const perm = txtcode + '.override';
+    
+                    return this.perm.hasWorkPermHere(perm).then(
+                        permResult => ctx.canOverride = permResult[perm]);
+                }
+            },
+            error => {
+                ctx.processing = false;
+                console.error(error);
             }
-        });
+        );
     }
 
     override(ctx: HoldContext) {
-        this.placeOneHold(ctx.holdTarget, true);
+        this.placeOneHold(ctx, true);
     }
 
     canOverride(ctx: HoldContext): boolean {
index 3019b33..902e50b 100644 (file)
 <div id="staff-catalog-results-container" *ngIf="searchHasResults()">
   <div class="row">
     <div class="col-lg-2" *ngIf="!searchContext.basket">
-      <h3 i18n>Search Results ({{searchContext.result.count}})</h3>
+      <ng-container *ngIf="searchContext.termSearch.browseEntry">
+        <h3 i18n>Results for browse "{{searchContext.termSearch.browseEntry.value()}}"</h3>
+      </ng-container>
+      <ng-container *ngIf="!searchContext.termSearch.browseEntry">
+        <h3 i18n>Search Results ({{searchContext.result.count}})</h3>
+      </ng-container>
     </div>
     <div class="col-lg-2" *ngIf="searchContext.basket">
       <h3 i18n>Basket View</h3>
index 4327e8d..ee4abc5 100644 (file)
@@ -113,7 +113,7 @@ TODO focus search input
                 <div class="checkbox pl-3">
                   <label>
                     <input type="checkbox"
-                      [(ngModel)]="context.termSearch.isMetarecord"/>
+                      [(ngModel)]="context.termSearch.groupByMetarecord"/>
                     <span class="pl-1" i18n>Group Formats/Editions</span>
                   </label>
                 </div>
index d0216b7..711ff90 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.browseEntry = null;
                 this.context.termSearch.fromMetarecord = null;
                 this.context.termSearch.facetFilters = [];
                 this.staffCat.search();