From: Bill Erickson Date: Tue, 17 Nov 2020 22:55:20 +0000 (-0500) Subject: LP1904788 Staff catalog browse results paging X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=b93e88dc7be7340348d393d77c01b64eab74dcb4;p=working%2FEvergreen.git LP1904788 Staff catalog browse results paging Adds the ability to step through browse headings directly from the heading record list page without having to return to the original browse search To test: 1. Navigate to the staff catalog and perform a Browse search. 2. Click on one of the headings and you'll be taken to the page which lists the bib records that use the selected heading. 3. Click the Previous Headings and Next Headings buttons to load the prev/next heading and its linked records. Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/browse/results.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/browse/results.component.ts index 3aeaf6b32c..3ae935a59f 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/browse/results.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/catalog/browse/results.component.ts @@ -119,9 +119,7 @@ export class BrowseResultsComponent implements OnInit, OnDestroy { searchByBrowseEntryParams(result) { const ctx = this.searchContext.clone(); - ctx.browseSearch.reset(); // we're done browsing - ctx.termSearch.hasBrowseEntry = - result.browse_entry + ',' + result.fields; + ctx.termSearch.hasBrowseEntry = result.browse_entry + ',' + result.fields; return this.catUrl.toUrlParams(ctx); } diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.html index 515a376dd9..0c04c9efaa 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.html +++ b/Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.html @@ -31,11 +31,13 @@
+
+
+

Results for browse entry "{{searchContext.termSearch.browseEntry.value()}}"

+
+
- -

Results for browse "{{searchContext.termSearch.browseEntry.value()}}"

-

Search Results ({{searchContext.result.count}})

@@ -52,11 +54,32 @@
-
-
- + + +
+ + + + + + +
-
+
+
+ +
+
+ + +
+
+ +
+
+
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.ts index edcb381044..a7cd2dcabb 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/catalog/result/results.component.ts @@ -1,6 +1,6 @@ import {Component, OnInit, OnDestroy, Input} from '@angular/core'; import {Observable, Subscription} from 'rxjs'; -import {map, switchMap, distinctUntilChanged} from 'rxjs/operators'; +import {tap, map, switchMap, distinctUntilChanged} from 'rxjs/operators'; import {ActivatedRoute, ParamMap} from '@angular/router'; import {CatalogService} from '@eg/share/catalog/catalog.service'; import {BibRecordService} from '@eg/share/catalog/bib-record.service'; @@ -28,6 +28,8 @@ export class ResultsComponent implements OnInit, OnDestroy { searchSub: Subscription; routeSub: Subscription; basketSub: Subscription; + browseResults: any[] = []; + browseLoading = false; constructor( private route: ActivatedRoute, @@ -62,12 +64,22 @@ export class ResultsComponent implements OnInit, OnDestroy { }); // After each completed search, update the record selector. - this.searchSub = this.cat.onSearchComplete.subscribe( - ctx => this.applyRecordSelection()); + this.searchSub = this.cat.onSearchComplete.subscribe(ctx => { + this.applyRecordSelection(); + }); // Watch for basket changes applied by other components. this.basketSub = this.basket.onChange.subscribe( () => this.applyRecordSelection()); + + + // Load browse data to support browse paging. + /* + if (this.searchContext.termSearch.hasBrowseEntry && + this.searchContext.browseSearch.value) { + this.fetchBrowseData().toPromise(); + } + */ } ngOnDestroy() { @@ -126,6 +138,106 @@ export class ResultsComponent implements OnInit, OnDestroy { this.basket.removeRecordIds(ids); } } + + // Grab a page of browse results + fetchBrowseData(prev?: boolean): Promise { + const ctx = this.searchContext.clone(); + ctx.termSearch.hasBrowseEntry = null; // avoid term search + + // Grab a few extras so we can last a bit longer before + // having to fetch more browse data. Could make this bigger. + ctx.pager.limit = 20; + + const results = []; + + return this.cat.browse(ctx) + .pipe(tap(result => results.push(result))) + .toPromise().then(_ => { + if (prev) { + this.browseResults = results.concat(this.browseResults); + } else { + this.browseResults = this.browseResults.concat(results); + } + }); + } + + // Find the browse entry for the next/prev page and navigate there + // if possible. Returns false if not enough data is available. + goToBrowsePage(prev?: boolean): boolean { + const ctx = this.searchContext; + + // See if we have enough info to direct to the selected page. + + const mbeId = Number( // for this page + this.searchContext.termSearch.hasBrowseEntry.split(',')[0]); + + let target, previous; + + this.browseResults.forEach(result => { + if (!result.browse_entry) { return; } // ignore pivot entries + + if (previous) { + if (prev) { + if (result.browse_entry === mbeId) { + target = previous; + } + } else { + if (previous.browse_entry === mbeId) { + target = result; + } + } + } + previous = result; + }); + + if (!target) { return false; } + + // Jump to the selected browse entry's page. + ctx.termSearch.hasBrowseEntry = target.browse_entry + ',' + target.fields; + ctx.pager.offset = 0; // this is a brand new search + this.staffCat.search(); + + return true; + } + + + // Navigate to next or previous browse entry page. + // take1: navigate without fetching data if possible + // take2: fetch data and navigate if possible. + // take3: data fetched in take2 contains data for this page, but + // not the requested page. This happens when the user navigates + // cold to a browse page boundary and the current page of data + // does not yet exist. + browseNav(prev?: boolean, take?: number) { + if (!take) { take = 1; } + + this.browseLoading = true; + + if (take > 3) { + // We tried our best, but could not find the requested + // browse data Could happen if we reach the end of the data set. + this.browseLoading = false; + return; + } + + if (this.goToBrowsePage(prev)) { + // Navigation successful + this.browseLoading = false; + return; + } + + // We need another page of browse data before we can direct + // the user to the requested page. + + const results = this.browseResults; + if (results.length > 0) { + this.searchContext.browseSearch.pivot = prev ? + results[0].pivot_point : + results[results.length - 1].pivot_point; + } + + this.fetchBrowseData(prev).then(_ => this.browseNav(prev, take + 1)); + } } diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.ts index 9dcca68570..2b4faadad3 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.ts @@ -93,7 +93,13 @@ export class SearchFormComponent implements OnInit, AfterViewInit { this.searchTab = 'marc'; } else if (this.context.identSearch.isSearchable()) { this.searchTab = 'ident'; - } else if (this.context.browseSearch.isSearchable()) { + + // Browse search may remain 'searchable' even though we + // are displaying bibs linked to a browse entry. + // This is so browse search paging can be added to + // the record list page. + } else if (this.context.browseSearch.isSearchable() + && !this.context.termSearch.hasBrowseEntry) { this.searchTab = 'browse'; } else if (this.context.termSearch.isSearchable()) { this.searchTab = 'term';