[open-ils-commits] [GIT] Evergreen ILS branch master updated. 30dcf71b98f4b48fb1e05c7d3c74afa3b31a0ebc

Evergreen Git git at git.evergreen-ils.org
Thu Aug 13 11:33:52 EDT 2020


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  30dcf71b98f4b48fb1e05c7d3c74afa3b31a0ebc (commit)
       via  5ac17c3524ebcecfc5e0e34b27cc629121b03c32 (commit)
       via  4215f83cac3f91949e2c3efa7edb059d9f91dfc5 (commit)
       via  c1b2e9b7606fdb04c626cbeb308508530694962a (commit)
       via  0c3e75b56a9d95b5fbfdb71ce2b00a7a7fb55cdf (commit)
       via  47ff5359de4d44e0117ec3bce342b8815c0b4159 (commit)
       via  627bf1cdc8073fc293a9c73d370831ef1a8166cb (commit)
       via  8509f6a858b634a278ab594448ab4c194300ba31 (commit)
       via  0e540a02e5add2d918590f7c92b2e8d8dd2dc1f4 (commit)
       via  d89523ea11ae3f1fdd4ae09a3e1909187ec40d21 (commit)
       via  04b5c10020f13af008654bc8e631962fc437024f (commit)
      from  aab2df83096e5f4890e021be2e8cfefc8a49854c (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 30dcf71b98f4b48fb1e05c7d3c74afa3b31a0ebc
Author: Galen Charlton <gmc at equinoxinitiative.org>
Date:   Thu Aug 13 11:32:57 2020 -0400

    tidying of Pg/upgrade scripts
    
    - remove executable flag
    - add .sql extension to a recent one
    
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/sql/Pg/upgrade/1014.metarecord_constituents_search_result_page_should_use_standard_search_code.sql b/Open-ILS/src/sql/Pg/upgrade/1014.metarecord_constituents_search_result_page_should_use_standard_search_code.sql
old mode 100755
new mode 100644
diff --git a/Open-ILS/src/sql/Pg/upgrade/1015.function.lp1573734_include-transcendent_bibs_in_unapi_mmr.sql b/Open-ILS/src/sql/Pg/upgrade/1015.function.lp1573734_include-transcendent_bibs_in_unapi_mmr.sql
old mode 100755
new mode 100644
diff --git a/Open-ILS/src/sql/Pg/upgrade/1199.lp1849736_at_email_self_register.sql b/Open-ILS/src/sql/Pg/upgrade/1199.lp1849736_at_email_self_register.sql
old mode 100755
new mode 100644
diff --git a/Open-ILS/src/sql/Pg/upgrade/1203.hpprox-best-hold-sort-order b/Open-ILS/src/sql/Pg/upgrade/1203.hpprox-best-hold-sort-order.sql
old mode 100755
new mode 100644
similarity index 100%
rename from Open-ILS/src/sql/Pg/upgrade/1203.hpprox-best-hold-sort-order
rename to Open-ILS/src/sql/Pg/upgrade/1203.hpprox-best-hold-sort-order.sql
diff --git a/Open-ILS/src/sql/Pg/upgrade/1206.function.distinct-regen_copy_map.sql b/Open-ILS/src/sql/Pg/upgrade/1206.function.distinct-regen_copy_map.sql
old mode 100755
new mode 100644

commit 5ac17c3524ebcecfc5e0e34b27cc629121b03c32
Author: Galen Charlton <gmc at equinoxinitiative.org>
Date:   Thu Aug 13 11:30:58 2020 -0400

    LP#1869898: stamp DB update
    
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index 02bab54b56..f5091efeb5 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -92,7 +92,7 @@ CREATE TRIGGER no_overlapping_deps
     BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
     FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
 
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('1211', :eg_version); -- Dyrcona/rhamby/gmcharlt
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('1212', :eg_version); -- berick/sandbergja/gmcharlt
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.ang-cat-default.sql b/Open-ILS/src/sql/Pg/upgrade/1212.data.ang-cat-default.sql
similarity index 82%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.data.ang-cat-default.sql
rename to Open-ILS/src/sql/Pg/upgrade/1212.data.ang-cat-default.sql
index 96f44657a9..c25e7adfb3 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.ang-cat-default.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/1212.data.ang-cat-default.sql
@@ -1,7 +1,7 @@
 
 BEGIN;
 
--- SELECT evergreen.upgrade_deps_block_check('TODO', :eg_version);
+SELECT evergreen.upgrade_deps_block_check('1212', :eg_version); -- berick/sandbergja/gmcharlt
 
 DELETE FROM actor.org_unit_setting
     WHERE name = 'ui.staff.angular_catalog.enabled';

commit 4215f83cac3f91949e2c3efa7edb059d9f91dfc5
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu Jul 30 15:29:08 2020 -0400

    LP1889685 Staff catalog record CN browse retains search
    
    Using the Shelf Browse tab on the record detail page in the Angular
    staff catalog no longer clobbers the active search, allowing the search
    navigation buttons (Next, Previous, etc.) to continue working.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse/results.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse/results.component.ts
index 9c0dab3dcf..b9e2076083 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse/results.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse/results.component.ts
@@ -48,6 +48,13 @@ export class CnBrowseResultsComponent implements OnInit, OnDestroy {
     ngOnInit() {
         this.searchContext = this.staffCat.searchContext;
 
+        if (this.bibSummary) {
+            // Avoid clobbering the active search when browsing in
+            // the context of a specific record.
+            this.searchContext =
+                this.staffCat.cloneContext(this.searchContext);
+        }
+
         for (let idx = 0; idx < this.rowCount; idx++) {
             this.rowIndexList.push(idx);
         }

commit c1b2e9b7606fdb04c626cbeb308508530694962a
Author: Bill Erickson <berickxx at gmail.com>
Date:   Fri Jul 31 10:54:28 2020 -0400

    LP1889694 Staff catalog record summary API
    
    Replaces a number of result page and record detail page API calls with a
    bespoke API specifically created to return the data required for display
    bib and metabib record summary information in the catalog.
    
    Specifically, a single streaming API this replaces the following:
    
    * fleshed record retrieval
    ** including record display fields and attributes processing.
    * copy count retrieval
    * hold count retrieval
    
    The end result is 22 API calls per results page replaced with 2.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/eg2/src/app/share/catalog/bib-record.service.ts b/Open-ILS/src/eg2/src/app/share/catalog/bib-record.service.ts
index d29c4bdef8..7510fe0d0b 100644
--- a/Open-ILS/src/eg2/src/app/share/catalog/bib-record.service.ts
+++ b/Open-ILS/src/eg2/src/app/share/catalog/bib-record.service.ts
@@ -33,7 +33,7 @@ export class BibRecordSummary {
     net: NetService;
     displayHighlights: {[name: string]: string | string[]} = {};
 
-    constructor(record: IdlObject, orgId: number, orgDepth: number) {
+    constructor(record: IdlObject, orgId: number, orgDepth?: number) {
         this.id = Number(record.id());
         this.record = record;
         this.orgId = orgId;
@@ -44,63 +44,6 @@ export class BibRecordSummary {
         this.metabibRecords = [];
     }
 
-    ingest() {
-        this.compileDisplayFields();
-        this.compileRecordAttrs();
-
-        // Normalize some data for JS consistency
-        this.record.creator(Number(this.record.creator()));
-        this.record.editor(Number(this.record.editor()));
-    }
-
-    compileDisplayFields() {
-        this.record.flat_display_entries().forEach(entry => {
-            if (entry.multi() === 't') {
-                if (this.display[entry.name()]) {
-                    this.display[entry.name()].push(entry.value());
-                } else {
-                    this.display[entry.name()] = [entry.value()];
-                }
-            } else {
-                this.display[entry.name()] = entry.value();
-            }
-        });
-    }
-
-    compileRecordAttrs() {
-        // Any attr can be multi-valued.
-        this.record.mattrs().forEach(attr => {
-            if (this.attributes[attr.attr()]) {
-                // Avoid dupes
-                if (this.attributes[attr.attr()].indexOf(attr.value()) < 0) {
-                    this.attributes[attr.attr()].push(attr.value());
-                }
-            } else {
-                this.attributes[attr.attr()] = [attr.value()];
-            }
-        });
-    }
-
-    // Get -> Set -> Return bib hold count
-    getHoldCount(): Promise<number> {
-
-        if (Number.isInteger(this.holdCount)) {
-            return Promise.resolve(this.holdCount);
-        }
-
-        let method = 'open-ils.circ.bre.holds.count';
-        let target = this.id;
-
-        if (this.metabibId) {
-            method = 'open-ils.circ.mmr.holds.count';
-            target = this.metabibId;
-        }
-
-        return this.net.request(
-            'open-ils.circ', method, target
-        ).toPromise().then(count => this.holdCount = count);
-    }
-
     // Get -> Set -> Return bib-level call number
     getBibCallNumber(): Promise<string> {
 
@@ -141,194 +84,53 @@ export class BibRecordService {
         this.userCache = {};
     }
 
-    // Avoid fetching the MARC blob by specifying which fields on the
-    // bre to select.  Note that fleshed fields are implicitly selected.
-    fetchableBreFields(): string[] {
-        return this.idl.classes.bre.fields
-            .filter(f => !f.virtual && f.name !== 'marc')
-            .map(f => f.name);
+    getBibSummary(id: number,
+        orgId?: number, isStaff?: boolean): Observable<BibRecordSummary> {
+        return this.getBibSummaries([id], orgId, isStaff);
     }
 
-    // Note when multiple IDs are provided, responses are emitted in order
-    // of receipt, not necessarily in the requested ID order.
-    getBibSummary(bibIds: number | number[],
-        orgId?: number, orgDepth?: number): Observable<BibRecordSummary> {
+    getBibSummaries(bibIds: number[],
+        orgId?: number, isStaff?: boolean): Observable<BibRecordSummary> {
 
-        const ids = [].concat(bibIds);
+        if (bibIds.length === 0) { return from([]); }
+        if (!orgId) { orgId = this.org.root().id(); }
 
-        if (ids.length === 0) {
-            return from([]);
-        }
+        let method = 'open-ils.search.biblio.record.catalog_summary';
+        if (isStaff) { method += '.staff'; }
 
-        return this.pcrud.search('bre', {id: ids},
-            {   flesh: 1,
-                flesh_fields: {bre: ['flat_display_entries', 'mattrs']},
-                select: {bre : this.fetchableBreFields()}
-            },
-            {anonymous: true} // skip unneccesary auth
-        ).pipe(mergeMap(bib => {
-            const summary = new BibRecordSummary(bib, orgId, orgDepth);
+        return this.net.request('open-ils.search', method, orgId, bibIds)
+        .pipe(map(bibSummary => {
+            const summary = new BibRecordSummary(bibSummary.record, orgId);
             summary.net = this.net; // inject
-            summary.ingest();
-            return this.getHoldingsSummary(bib.id(), orgId, orgDepth)
-            .then(holdingsSummary => {
-                summary.holdingsSummary = holdingsSummary;
-                return summary;
-            });
+            summary.display = bibSummary.display;
+            summary.attributes = bibSummary.attributes;
+            summary.holdCount = bibSummary.hold_count;
+            summary.holdingsSummary = bibSummary.copy_counts;
+            return summary;
         }));
     }
 
-    // A Metabib Summary is a BibRecordSummary with the lead record as
-    // its core bib record plus attributes (e.g. formats) from related
-    // records.
-    getMetabibSummary(metabibIds: number | number[],
-        orgId?: number, orgDepth?: number): Observable<BibRecordSummary> {
-
-        const ids = [].concat(metabibIds);
-
-        if (ids.length === 0) {
-            return from([]);
-        }
-
-        return this.pcrud.search('mmr', {id: ids},
-            {flesh: 1, flesh_fields: {mmr: ['source_maps']}},
-            {anonymous: true}
-        ).pipe(mergeMap(mmr => this.compileMetabib(mmr, orgId, orgDepth)));
-    }
-
-    // 'metabib' must have its "source_maps" field fleshed.
-    // Get bib summaries for all related bib records so we can
-    // extract data that must be appended to the master record summary.
-    compileMetabib(metabib: IdlObject,
-        orgId?: number, orgDepth?: number): Observable<BibRecordSummary> {
-
-        // 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(m => m.source())
-            .filter(id => id !== metabib.master_record());
+    getMetabibSummaries(metabibIds: number[],
+        orgId?: number, isStaff?: boolean): Observable<BibRecordSummary> {
 
-        let observer;
-        const observable = new Observable<BibRecordSummary>(o => observer = o);
+        if (metabibIds.length === 0) { return from([]); }
+        if (!orgId) { orgId = this.org.root().id(); }
 
-        // 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 = Number(metabib.id());
-            summary.metabibRecords =
-                metabib.source_maps().map(m => Number(m.source()));
+        let method = 'open-ils.search.biblio.metabib.catalog_summary';
+        if (isStaff) { method += '.staff'; }
 
-            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 => {
-                    summary.holdingsSummary = holdingsSummary;
-                    observer.next(summary);
-                    observer.complete();
-                });
-            });
-        });
-
-        return observable;
-    }
-
-    // Flesh the creator and editor fields.
-    // Handling this separately lets us pull from the cache and
-    // avoids the requirement that the main bib query use a staff
-    // (VIEW_USER) auth token.
-    fleshBibUsers(records: IdlObject[]): Promise<void> {
-
-        const search = [];
-
-        records.forEach(rec => {
-            ['creator', 'editor'].forEach(field => {
-                const id = rec[field]();
-                if (Number.isInteger(id)) {
-                    if (this.userCache[id]) {
-                        rec[field](this.userCache[id]);
-                    } else if (!search.includes(id)) {
-                        search.push(id);
-                    }
-                }
-            });
-        });
-
-        if (search.length === 0) {
-            return Promise.resolve();
-        }
-
-        return this.pcrud.search('au', {id: search})
-        .pipe(map(user => {
-            this.userCache[user.id()] = user;
-            records.forEach(rec => {
-                if (user.id() === rec.creator()) {
-                    rec.creator(user);
-                }
-                if (user.id() === rec.editor()) {
-                    rec.editor(user);
-                }
-            });
-        })).toPromise();
-    }
-
-    getHoldingsSummary(recordId: number,
-        orgId: number, orgDepth: number, isMetarecord?: boolean): Promise<any> {
-
-        const holdingsSummary = [];
-
-        return this.unapi.getAsXmlDocument({
-            target: isMetarecord ? 'mmr' : 'bre',
-            id: recordId,
-            extras: '{holdings_xml}',
-            format: 'holdings_xml',
-            orgId: orgId,
-            depth: orgDepth
-        }).then(xmlDoc => {
-
-            // namespace resolver
-            const resolver: any = (prefix: string): string => {
-                return NAMESPACE_MAPS[prefix] || null;
-            };
-
-            // Extract the holdings data from the unapi xml doc
-            const result = xmlDoc.evaluate(HOLDINGS_XPATH,
-                xmlDoc, resolver, XPathResult.ANY_TYPE, null);
-
-            let node;
-            while (node = result.iterateNext()) {
-                const counts = {type : node.getAttribute('type')};
-                ['depth', 'org_unit', 'transcendant',
-                    'available', 'count', 'unshadow'].forEach(field => {
-                    counts[field] = Number(node.getAttribute(field));
-                });
-                holdingsSummary.push(counts);
-            }
-
-            return holdingsSummary;
-        });
+        return this.net.request('open-ils.search', method, orgId, metabibIds)
+        .pipe(map(metabibSummary => {
+            const summary = new BibRecordSummary(metabibSummary.record, orgId);
+            summary.net = this.net; // inject
+            summary.metabibId = Number(metabibSummary.metabib_id);
+            summary.metabibRecords = metabibSummary.metabib_records;
+            summary.display = metabibSummary.display;
+            summary.attributes = metabibSummary.attributes;
+            summary.holdCount = metabibSummary.hold_count;
+            summary.holdingsSummary = metabibSummary.copy_counts;
+            return summary;
+        }));
     }
 }
 
diff --git a/Open-ILS/src/eg2/src/app/share/catalog/catalog.service.ts b/Open-ILS/src/eg2/src/app/share/catalog/catalog.service.ts
index c80d0b2683..805a0bb589 100644
--- a/Open-ILS/src/eg2/src/app/share/catalog/catalog.service.ts
+++ b/Open-ILS/src/eg2/src/app/share/catalog/catalog.service.ts
@@ -190,11 +190,11 @@ export class CatalogService {
         let observable: Observable<BibRecordSummary>;
 
         if (isMeta) {
-            observable = this.bibService.getMetabibSummary(
-                ctx.currentResultIds(), ctx.searchOrg.id(), depth);
+            observable = this.bibService.getMetabibSummaries(
+                ctx.currentResultIds(), ctx.searchOrg.id(), ctx.isStaff);
         } else {
-            observable = this.bibService.getBibSummary(
-                ctx.currentResultIds(), ctx.searchOrg.id(), depth);
+            observable = this.bibService.getBibSummaries(
+                ctx.currentResultIds(), ctx.searchOrg.id(), ctx.isStaff);
         }
 
         return observable.pipe(map(summary => {
@@ -239,9 +239,9 @@ export class CatalogService {
             // them to bib IDs for highlighting.
             ids = ctx.currentResultIds();
             if (ctx.termSearch.groupByMetarecord) {
-                ids = ids.map(mrId =>
-                    ctx.result.records.filter(r => mrId === r.metabibId)[0].id
-                );
+                // The 4th slot in the result ID reports the master record
+                // for the metarecord in question.  Sometimes it's null?
+                ids = ctx.result.ids.map(id => id[4]).filter(id => id !== null);
             }
         }
 
diff --git a/Open-ILS/src/eg2/src/app/staff/cat/vandelay/queued-record-matches.component.ts b/Open-ILS/src/eg2/src/app/staff/cat/vandelay/queued-record-matches.component.ts
index dfbee692ef..10060e05af 100644
--- a/Open-ILS/src/eg2/src/app/staff/cat/vandelay/queued-record-matches.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/cat/vandelay/queued-record-matches.component.ts
@@ -118,28 +118,24 @@ export class QueuedRecordMatchesComponent implements OnInit {
                 });
 
                 const bibSummaries: {[id: number]: BibRecordSummary} = {};
-                this.bib.getBibSummary(recIds).subscribe(
+                this.bib.getBibSummaries(recIds).subscribe(
                     summary => bibSummaries[summary.id] = summary,
                     err => {},
                     ()  => {
-                        this.bib.fleshBibUsers(
-                            Object.values(bibSummaries).map(sum => sum.record)
-                        ).then(() => {
-                            matches.forEach(match => {
-                                const row = {
-                                    id: match.id(),
-                                    eg_record: match.eg_record(),
-                                    bre_quality: match.quality(),
-                                    vqbr_quality: this.queuedRecord.quality(),
-                                    match_score: match.match_score(),
-                                    bib_summary: bibSummaries[match.eg_record()]
-                                };
-
-                                observer.next(row);
-                            });
-
-                            observer.complete();
+                        matches.forEach(match => {
+                            const row = {
+                                id: match.id(),
+                                eg_record: match.eg_record(),
+                                bre_quality: match.quality(),
+                                vqbr_quality: this.queuedRecord.quality(),
+                                match_score: match.match_score(),
+                                bib_summary: bibSummaries[match.eg_record()]
+                            };
+
+                            observer.next(row);
                         });
+
+                        observer.complete();
                     }
                 );
             });
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse/results.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse/results.component.ts
index 464f443a1f..9c0dab3dcf 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse/results.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse/results.component.ts
@@ -119,9 +119,9 @@ export class CnBrowseResultsComponent implements OnInit, OnDestroy {
         };
 
         const bres: IdlObject[] = [];
-        this.bib.getBibSummary(
+        this.bib.getBibSummaries(
             bibIds.filter(distinct),
-            this.searchContext.searchOrg.id(), depth
+            this.searchContext.searchOrg.id(), this.searchContext.isStaff
         ).subscribe(
             summary => {
                 // Response order not guaranteed.  Match the summary
@@ -134,10 +134,6 @@ export class CnBrowseResultsComponent implements OnInit, OnDestroy {
 
                 // Use _ since result is an 'acn' object.
                 bibResults.forEach(r => r._bibSummary = summary);
-            },
-            err => {},
-            ()  => {
-                this.bib.fleshBibUsers(bres);
             }
         );
     }
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.ts
index e68e01791d..fc7ba54ea1 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.ts
@@ -156,7 +156,6 @@ export class RecordComponent implements OnInit {
         .then(summary => {
             this.summary =
                 this.staffCat.currentDetailRecordSummary = summary;
-            this.bib.fleshBibUsers([summary.record]);
         });
     }
 
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.html
index 65209a0b4f..8d839e19b2 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.html
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.html
@@ -132,15 +132,13 @@
       <div class="col-lg-2">
         <div class="row" [ngClass]="{'pt-2':copyIndex > 0}" 
           *ngFor="let copyCount of summary.holdingsSummary; let copyIdx = index">
-          <div class="w-100" *ngIf="copyCount.type == 'staff'">
-            <div class="float-left text-left w-50">
-              <span class="pr-1">
-              {{copyCount.available}} / {{copyCount.count}} items
-              </span>
-            </div>
-            <div class="float-left w-50">
-              @ {{orgName(copyCount.org_unit)}}
-            </div>
+          <div class="float-left text-left w-50">
+            <span class="pr-1">
+            {{copyCount.available}} / {{copyCount.count}} items
+            </span>
+          </div>
+          <div class="float-left w-50">
+            @ {{orgName(copyCount.org_unit)}}
           </div>
         </div>
       </div>
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.ts
index 8cb7f03c6c..664d36661e 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.ts
@@ -43,7 +43,6 @@ export class ResultRecordComponent implements OnInit, OnDestroy {
 
     ngOnInit() {
         this.searchContext = this.staffCat.searchContext;
-        this.summary.getHoldCount();
         this.isRecordSelected = this.basket.hasRecordId(this.summary.id);
 
         // Watch for basket changes caused by other components
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 41804cc62c..515a376dd9 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
@@ -65,12 +65,10 @@
       </div>
       <div
         [ngClass]="{'col-lg-10': !searchContext.basket, 'col-lg-12': searchContext.basket}">
-        <div *ngIf="shouldStartRendering()">
-          <div *ngFor="let summary of searchContext.result.records; let idx = index">
-            <div *ngIf="summary">
-              <eg-catalog-result-record [summary]="summary" [index]="idx">
-              </eg-catalog-result-record>
-            </div>
+        <div *ngFor="let summary of searchContext.result.records; let idx = index">
+          <div *ngIf="summary">
+            <eg-catalog-result-record [summary]="summary" [index]="idx">
+            </eg-catalog-result-record>
           </div>
         </div>
       </div>
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 50ed7914e4..edcb381044 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
@@ -100,39 +100,11 @@ export class ResultsComponent implements OnInit, OnDestroy {
             this.cat.search(this.searchContext)
             .then(ok => {
                 this.cat.fetchFacets(this.searchContext);
-                this.cat.fetchBibSummaries(this.searchContext)
-                .then(ok2 => this.fleshSearchResults());
+                this.cat.fetchBibSummaries(this.searchContext);
             });
         }
     }
 
-    // Records file into place randomly as the server returns data.
-    // To reduce page display shuffling, avoid showing the list of
-    // records until the first few are ready to render.
-    shouldStartRendering(): boolean {
-
-        if (this.searchHasResults()) {
-            const pageCount = this.searchContext.currentResultIds().length;
-            switch (pageCount) {
-                case 1:
-                    return this.searchContext.result.records[0];
-                default:
-                    return this.searchContext.result.records[0]
-                        && this.searchContext.result.records[1];
-            }
-        }
-
-        return false;
-    }
-
-    fleshSearchResults(): void {
-        const records = this.searchContext.result.records;
-        if (!records || records.length === 0) { return; }
-
-        // Flesh the creator / editor fields with the user object.
-        this.bib.fleshBibUsers(records.map(r => r.record));
-    }
-
     searchIsDone(): boolean {
         return this.searchContext.searchState === CatalogSearchState.COMPLETE;
     }
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html
index 920b008074..d4ca900377 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html
@@ -130,7 +130,7 @@
                 </div>
                 <div class="checkbox pl-3">
                   <label>
-                    <input type="checkbox" [(ngModel)]="context.termSearch.global"/>
+                    <input type="checkbox" [(ngModel)]="context.global"/>
                     <span class="pl-1" i18n>Results from All Libraries</span>
                   </label>
                 </div>
diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts b/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts
index 39b8944d3a..84719fd3d5 100644
--- a/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts
@@ -66,7 +66,6 @@ export class BibSummaryComponent implements OnInit {
         this.bib.getBibSummary(this.recordId).toPromise()
         .then(summary => {
             summary.getBibCallNumber();
-            this.bib.fleshBibUsers([summary.record]);
             this.summary = summary;
         });
     }
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
index 159ecd78b9..b07440e65a 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm
@@ -13,9 +13,6 @@ use Encode;
 
 use OpenSRF::Utils::Logger qw/:logger/;
 
-
-use OpenSRF::Utils::JSON;
-
 use Time::HiRes qw(time sleep);
 use OpenSRF::EX qw(:try);
 use Digest::MD5 qw(md5_hex);
@@ -2744,5 +2741,158 @@ sub mk_copy_query {
 }
 
 
+__PACKAGE__->register_method(
+    method    => 'catalog_record_summary',
+    api_name  => 'open-ils.search.biblio.record.catalog_summary',
+    stream    => 1,
+    max_bundle_count => 1,
+    signature => {
+        desc   => 'Stream of record data suitable for catalog display',
+        params => [
+            {desc => 'Context org unit ID', type => 'number'},
+            {desc => 'Array of Record IDs', type => 'array'}
+        ],
+        return => { 
+            desc => q/
+                Stream of record summary objects including id, record,
+                hold_count, copy_counts, display (metabib display
+                fields), attributes (metabib record attrs), plus
+                metabib_id and metabib_records for the metabib variant.
+            /
+        }
+    }
+);
+__PACKAGE__->register_method(
+    method    => 'catalog_record_summary',
+    api_name  => 'open-ils.search.biblio.record.catalog_summary.staff',
+    stream    => 1,
+    max_bundle_count => 1,
+    signature => q/see open-ils.search.biblio.record.catalog_summary/
+);
+__PACKAGE__->register_method(
+    method    => 'catalog_record_summary',
+    api_name  => 'open-ils.search.biblio.metabib.catalog_summary',
+    stream    => 1,
+    max_bundle_count => 1,
+    signature => q/see open-ils.search.biblio.record.catalog_summary/
+);
+
+__PACKAGE__->register_method(
+    method    => 'catalog_record_summary',
+    api_name  => 'open-ils.search.biblio.metabib.catalog_summary.staff',
+    stream    => 1,
+    max_bundle_count => 1,
+    signature => q/see open-ils.search.biblio.record.catalog_summary/
+);
+
+
+sub catalog_record_summary {
+    my ($self, $client, $org_id, $record_ids) = @_;
+    my $e = new_editor();
+
+    my $is_meta = ($self->api_name =~ /metabib/);
+    my $is_staff = ($self->api_name =~ /staff/);
+
+    my $holds_method = $is_meta ? 
+        'open-ils.circ.mmr.holds.count' : 
+        'open-ils.circ.bre.holds.count';
+
+    my $copy_method = $is_meta ? 
+        'open-ils.search.biblio.metarecord.copy_count':
+        'open-ils.search.biblio.record.copy_count';
+
+    $copy_method .= '.staff' if $is_staff;
+
+    $copy_method = $self->method_lookup($copy_method); # local method
+
+    for my $rec_id (@$record_ids) {
+
+        my $response = $is_meta ? 
+            get_one_metarecord_summary($e, $rec_id) :
+            get_one_record_summary($e, $rec_id);
+
+        ($response->{copy_counts}) = $copy_method->run($org_id, $rec_id);
+
+        $response->{hold_count} = 
+            $U->simplereq('open-ils.circ', $holds_method, $rec_id);
+
+        $client->respond($response);
+    }
+
+    return undef;
+}
+
+# Start with a bib summary and augment the data with additional
+# metarecord content.
+sub get_one_metarecord_summary {
+    my ($e, $rec_id) = @_;
+
+    my $meta = $e->retrieve_metabib_metarecord($rec_id) or return {};
+    my $maps = $e->search_metabib_metarecord_source_map({metarecord => $rec_id});
+
+    my $bre_id = $meta->master_record; 
+
+    my $response = get_one_record_summary($e, $bre_id);
+
+    $response->{metabib_id} = $rec_id;
+    $response->{metabib_records} = [map {$_->source} @$maps];
+
+    my @other_bibs = map {$_->source} grep {$_->source != $bre_id} @$maps;
+
+    # Augment the record attributes with those of all of the records
+    # linked to this metarecord.
+    if (@other_bibs) {
+        my $attrs = $e->search_metabib_record_attr_flat({id => \@other_bibs});
+
+        my $attributes = $response->{attributes};
+
+        for my $attr (@$attrs) {
+            $attributes->{$attr->attr} = [] unless $attributes->{$attr->attr};
+            push(@{$attributes->{$attr->attr}}, $attr->value) # avoid dupes
+                unless grep {$_ eq $attr->value} @{$attributes->{$attr->attr}};
+        }
+    }
+
+    return $response;
+}
+
+sub get_one_record_summary {
+    my ($e, $rec_id) = @_;
+
+    my $bre = $e->retrieve_biblio_record_entry([$rec_id, {
+        flesh => 1,
+        flesh_fields => {
+            bre => [qw/compressed_display_entries mattrs creator editor/]
+        }
+    }]) or return {};
+
+    # Compressed display fields are pachaged as JSON
+    my $display = {};
+    $display->{$_->name} = OpenSRF::Utils::JSON->JSON2perl($_->value)
+        foreach @{$bre->compressed_display_entries};
+
+    # Create an object of 'mraf' attributes.
+    # Any attribute can be multi so dedupe and array-ify all of them.
+    my $attributes = {};
+    for my $attr (@{$bre->mattrs}) {
+        $attributes->{$attr->attr} = {} unless $attributes->{$attr->attr};
+        $attributes->{$attr->attr}->{$attr->value} = 1; # avoid dupes
+    }
+    $attributes->{$_} = [keys %{$attributes->{$_}}] for keys %$attributes;
+
+    # clear bulk
+    $bre->clear_marc;
+    $bre->clear_mattrs;
+    $bre->clear_compressed_display_entries;
+
+    return {
+        id => $rec_id,
+        record => $bre,
+        display => $display,
+        attributes => $attributes
+    };
+}
+
+
 1;
 

commit 0c3e75b56a9d95b5fbfdb71ce2b00a7a7fb55cdf
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu Aug 6 13:58:14 2020 -0400

    LP1869898 Remove staffcat AOUS; activate holds template
    
    Remove the org unit setting for enabling access to the Angular staff
    catalog, since it is now the default catalog.
    
    Activate the stock holds-for-bib print template, which is used by the
    staff catalog holds-for-record grid.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index 5856dabfe0..18086b3704 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -20025,25 +20025,6 @@ VALUES (
     )
 );
 
--- NOTE: This setting should be removed once the Angular catalog
--- becomes the default.
-INSERT into config.org_unit_setting_type 
-    (name, datatype, grp, label, description)
-VALUES ( 
-    'ui.staff.angular_catalog.enabled', 'bool', 'gui',
-    oils_i18n_gettext(
-        'ui.staff.angular_catalog.enabled',
-        'GUI: Enable Experimental Angular Staff Catalog',
-        'coust', 'label'
-    ),
-    oils_i18n_gettext(
-        'ui.staff.angular_catalog.enabled',
-        'Display an entry point in the browser client for the ' ||
-        'experimental Angular staff catalog.',
-        'coust', 'description'
-    )
-);
-
 INSERT INTO config.org_unit_setting_type
     (name, label, description, grp, datatype)
     VALUES (
@@ -20230,7 +20211,7 @@ $TEMPLATE$
 INSERT INTO config.print_template 
     (id, name, locale, active, owner, label, template) 
 VALUES (
-    2, 'holds_for_bib', 'en-US', FALSE,
+    2, 'holds_for_bib', 'en-US', TRUE,
     (SELECT id FROM actor.org_unit WHERE parent_ou IS NULL),
     oils_i18n_gettext(2, 'Holds for Bib Record', 'cpt', 'label'),
 $TEMPLATE$
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.ang-cat-default.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.ang-cat-default.sql
new file mode 100644
index 0000000000..96f44657a9
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.ang-cat-default.sql
@@ -0,0 +1,18 @@
+
+BEGIN;
+
+-- SELECT evergreen.upgrade_deps_block_check('TODO', :eg_version);
+
+DELETE FROM actor.org_unit_setting
+    WHERE name = 'ui.staff.angular_catalog.enabled';
+
+DELETE FROM config.org_unit_setting_type_log 
+    WHERE field_name = 'ui.staff.angular_catalog.enabled';
+
+DELETE FROM config.org_unit_setting_type
+    WHERE name = 'ui.staff.angular_catalog.enabled';
+
+-- activate the stock hold-for-bib server print template
+UPDATE config.print_template SET active = TRUE WHERE name = 'holds_for_bib';
+
+COMMIT;

commit 47ff5359de4d44e0117ec3bce342b8815c0b4159
Author: Bill Erickson <berickxx at gmail.com>
Date:   Wed Aug 5 10:43:05 2020 -0400

    LP1869898 Ang cat copy table responds to broadcasts
    
    Angular staff catalog copy table responds to broadcasts of modified
    holdings.  When holdings for the current record have changed, the table
    data is refreshed.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/copies.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/record/copies.component.ts
index bfc2b03107..9e288ee61d 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/record/copies.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/record/copies.component.ts
@@ -7,6 +7,7 @@ import {Pager} from '@eg/share/util/pager';
 import {OrgService} from '@eg/core/org.service';
 import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
 import {GridComponent} from '@eg/share/grid/grid.component';
+import {BroadcastService} from '@eg/share/util/broadcast.service';
 
 @Component({
   selector: 'eg-catalog-copies',
@@ -35,6 +36,7 @@ export class CopiesComponent implements OnInit {
         private net: NetService,
         private org: OrgService,
         private staffCat: StaffCatalogService,
+        private broadcaster: BroadcastService
     ) {
         this.gridDataSource = new GridDataSource();
     }
@@ -61,10 +63,12 @@ export class CopiesComponent implements OnInit {
             holdable: row => this.copyContext.holdable(row),
             barcode: row => row.barcode
         };
-    }
 
-    collectData() {
-        if (!this.recId) { return; }
+        this.broadcaster.listen('eg.holdings.update').subscribe(data => {
+            if (data && data.records && data.records.includes(this.recId)) {
+                this.copyGrid.reload();
+            }
+        });
     }
 
     orgName(orgId: number): string {

commit 627bf1cdc8073fc293a9c73d370831ef1a8166cb
Author: Jane Sandberg <sandbej at linnbenton.edu>
Date:   Tue Aug 4 14:50:13 2020 -0700

    LP1869898: Banner no longer calls the staff catalog experimental
    
    Signed-off-by: Jane Sandberg <sandbej at linnbenton.edu>
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/browse.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/browse.component.html
index 00a3f92911..3468e1add5 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/browse.component.html
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/browse.component.html
@@ -1,4 +1,4 @@
-<eg-staff-banner bannerText="Staff Catalog (Experimental)" i18n-bannerText>
+<eg-staff-banner bannerText="Staff Catalog" i18n-bannerText>
 </eg-staff-banner>
 
 <eg-catalog-search-form #searchForm></eg-catalog-search-form>
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.html
index 53c4622d85..79d5073c41 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.html
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.html
@@ -1,4 +1,4 @@
-<eg-staff-banner bannerText="Staff Catalog (Experimental)" i18n-bannerText>
+<eg-staff-banner bannerText="Staff Catalog" i18n-bannerText>
 </eg-staff-banner>
 
 <ng-container *ngIf="holdForUser()">
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse.component.html
index eca35ca0f0..3757aae9ce 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse.component.html
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/cnbrowse.component.html
@@ -1,4 +1,4 @@
-<eg-staff-banner bannerText="Staff Catalog (Experimental)" i18n-bannerText>
+<eg-staff-banner bannerText="Staff Catalog" i18n-bannerText>
 </eg-staff-banner>
 
 <eg-catalog-search-form #searchForm></eg-catalog-search-form>

commit 8509f6a858b634a278ab594448ab4c194300ba31
Author: Bill Erickson <berickxx at gmail.com>
Date:   Fri Jun 19 16:50:18 2020 -0400

    LP1869898 Holdings responds to broadcasted changes
    
    Adds a new service for interracting with BroadcastChannel's.
    Teaches the holdings grid to refresh data if a broadcast is received for
    related holdings updates.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Jane Sandberg <sandbej at linnbenton.edu>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/eg2/src/app/share/util/broadcast.service.ts b/Open-ILS/src/eg2/src/app/share/util/broadcast.service.ts
new file mode 100644
index 0000000000..ccbb573a66
--- /dev/null
+++ b/Open-ILS/src/eg2/src/app/share/util/broadcast.service.ts
@@ -0,0 +1,69 @@
+/**
+ * Create and consume BroadcastChannel broadcasts
+ */
+import {Injectable, EventEmitter} from '@angular/core';
+import {empty} from 'rxjs';
+
+interface BroadcastSub {
+    channel: any; // BroadcastChannel
+    emitter: EventEmitter<any>;
+}
+
+ at Injectable()
+export class BroadcastService {
+
+    subscriptions: {[key: string]: BroadcastSub} = {};
+
+    noOpEmitter = new EventEmitter<any>();
+
+    listen(key: string): EventEmitter<any> {
+        if (typeof BroadcastChannel === 'undefined') {
+            return this.noOpEmitter;
+        }
+
+        if (this.subscriptions[key]) {
+            return this.subscriptions[key].emitter;
+        }
+
+        const emitter = new EventEmitter<any>();
+        const channel = new BroadcastChannel(key);
+
+        channel.onmessage = (e) => {
+            console.debug('Broadcast received', e.data);
+            emitter.emit(e.data);
+        };
+
+        this.subscriptions[key] = {
+            channel: channel,
+            emitter: emitter
+        };
+
+        return emitter;
+    }
+
+    broadcast(key: string, value: any) {
+        if (typeof BroadcastChannel === 'undefined') { return; }
+
+        if (this.subscriptions[key]) {
+            this.subscriptions[key].channel.postMessage(value);
+
+        } else {
+
+            // One time use channel
+            const channel = new BroadcastChannel(key);
+            channel.postMessage(value);
+            channel.close();
+        }
+    }
+
+    close(key: string) {
+        if (typeof BroadcastChannel === 'undefined') { return; }
+
+        if (this.subscriptions[key]) {
+            this.subscriptions[key].channel.close();
+            this.subscriptions[key].emitter.complete();
+            delete this.subscriptions[key];
+        }
+    }
+}
+
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts
index 7a064a5468..ed31980213 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts
@@ -38,6 +38,7 @@ import {TransferItemsComponent
 import {TransferHoldingsComponent
     } from '@eg/staff/share/holdings/transfer-holdings.component';
 import {AlertDialogComponent} from '@eg/share/dialog/alert.component';
+import {BroadcastService} from '@eg/share/util/broadcast.service';
 
 
 // The holdings grid models a single HoldingsTree, composed of HoldingsTreeNodes
@@ -170,6 +171,7 @@ export class HoldingsMaintenanceComponent implements OnInit {
         private store: ServerStoreService,
         private localStore: StoreService,
         private holdings: HoldingsService,
+        private broadcaster: BroadcastService,
         private anonCache: AnonCacheService
     ) {
         // Set some sane defaults before settings are loaded.
@@ -230,6 +232,13 @@ export class HoldingsMaintenanceComponent implements OnInit {
     ngOnInit() {
         this.initDone = true;
 
+        this.broadcaster.listen('eg.holdings.update').subscribe(data => {
+            if (data && data.records && data.records.includes(this.recordId)) {
+                this.refreshHoldings = true;
+                this.holdingsGrid.reload();
+            }
+        });
+
         // These are pre-cached via the catalog resolver.
         const settings = this.store.getItemBatchCached([
             'cat.holdings_show_empty_org',
diff --git a/Open-ILS/src/eg2/src/app/staff/common.module.ts b/Open-ILS/src/eg2/src/app/staff/common.module.ts
index 5b9645e2ed..a2f54cf7ba 100644
--- a/Open-ILS/src/eg2/src/app/staff/common.module.ts
+++ b/Open-ILS/src/eg2/src/app/staff/common.module.ts
@@ -17,6 +17,7 @@ import {DatetimeValidatorDirective} from '@eg/share/validators/datetime_validato
 import {MultiSelectComponent} from '@eg/share/multi-select/multi-select.component';
 import {NotBeforeMomentValidatorDirective} from '@eg/share/validators/not_before_moment_validator.directive';
 import {PatronBarcodeValidatorDirective} from '@eg/share/validators/patron_barcode_validator.directive';
+import {BroadcastService} from '@eg/share/util/broadcast.service';
 
 /**
  * Imports the EG common modules and adds modules common to all staff UI's.
@@ -69,7 +70,8 @@ export class StaffCommonModule {
             ngModule: StaffCommonModule,
             providers: [ // Export staff-wide services
                 AccessKeyService,
-                AudioService
+                AudioService,
+                BroadcastService
             ]
         };
     }

commit 0e540a02e5add2d918590f7c92b2e8d8dd2dc1f4
Author: Bill Erickson <berickxx at gmail.com>
Date:   Mon Jun 8 14:57:37 2020 -0400

    LP1869898 Angular staff cat place hold from patron
    
    The place hold button in the patron holds list now takes staff to the
    Angular catalog for holds placement.  A banner is displayed along the
    top of the catalog to indicate which patron the hold is for and to
    provide a link back to the patron's holds list.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Jane Sandberg <sandbej at linnbenton.edu>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.html
index af1d6040c7..53c4622d85 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.html
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.html
@@ -1,5 +1,23 @@
 <eg-staff-banner bannerText="Staff Catalog (Experimental)" i18n-bannerText>
 </eg-staff-banner>
+
+<ng-container *ngIf="holdForUser()">
+  <div class="row border border-info mb-2 pt-1 pb-1">
+    <div class="col-lg-10 offset-lg-1 d-flex justify-content-center">
+      <span class="mt-2" i18n>
+        Placing hold for patron 
+        <a href="/eg/staff/circ/patron/{{holdForUser().id()}}/holds">
+          {{holdForUser().family_name()}}, {{holdForUser().first_given_name()}}
+        </a>.
+      </span>
+    </div>
+    <div class="col-lg-1">
+      <button class="btn btn-info btn-sm" 
+        (click)="clearHoldPatron()" i18n>Clear</button>
+    </div>
+  </div>
+</ng-container>
+
 <!-- search form sits atop every catalog page -->
 <eg-catalog-search-form></eg-catalog-search-form>
 
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.ts
index f9fcf6dc8f..5ce37128a0 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/catalog.component.ts
@@ -1,4 +1,5 @@
 import {Component, OnInit} from '@angular/core';
+import {IdlObject} from '@eg/core/idl.service';
 import {StaffCatalogService} from './catalog.service';
 import {BasketService} from '@eg/share/catalog/basket.service';
 
@@ -18,5 +19,16 @@ export class CatalogComponent implements OnInit {
         // reset and updated as needed to apply new search parameters.
         this.staffCat.createContext();
     }
+
+    // Returns the 'au' object for the patron who we are
+    // trying to place a hold for.
+    holdForUser(): IdlObject {
+        return this.staffCat.holdForUser;
+    }
+
+    clearHoldPatron() {
+        this.staffCat.holdForUser = null;
+        this.staffCat.holdForBarcode = null;
+    }
 }
 
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/catalog.service.ts b/Open-ILS/src/eg2/src/app/staff/catalog/catalog.service.ts
index e46c1b4a1a..95912a4285 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/catalog.service.ts
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/catalog.service.ts
@@ -6,6 +6,7 @@ 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';
+import {PatronService} from '@eg/staff/share/patron/patron.service';
 
 /**
  * Shared bits needed by the staff version of the catalog.
@@ -27,6 +28,11 @@ export class StaffCatalogService {
     // Default search tab
     defaultTab: string;
 
+    // Patron barcode we hope to place a hold for.
+    holdForBarcode: string;
+    // User object for above barcode.
+    holdForUser: IdlObject;
+
     // Cache the currently selected detail record (i.g. catalog/record/123)
     // summary so the record detail component can avoid duplicate fetches
     // during record tab navigation.
@@ -37,6 +43,7 @@ export class StaffCatalogService {
         private route: ActivatedRoute,
         private org: OrgService,
         private cat: CatalogService,
+        private patron: PatronService,
         private catUrl: CatalogUrlService
     ) { }
 
@@ -48,6 +55,13 @@ export class StaffCatalogService {
         this.searchContext =
             this.catUrl.fromUrlParams(this.route.snapshot.queryParamMap);
 
+        this.holdForBarcode = this.route.snapshot.queryParams['holdForBarcode'];
+
+        if (this.holdForBarcode) {
+            this.patron.getByBarcode(this.holdForBarcode)
+            .then(user => this.holdForUser = user);
+        }
+
         this.searchContext.org = this.org; // service, not searchOrg
         this.searchContext.isStaff = true;
         this.applySearchDefaults();
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts
index c1640b0b81..687783e37a 100644
--- a/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts
@@ -13,6 +13,7 @@ import {StaffCatalogService} from '../catalog.service';
 import {HoldsService, HoldRequest,
     HoldRequestTarget} from '@eg/staff/share/holds/holds.service';
 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
+import {PatronService} from '@eg/staff/share/patron/patron.service';
 import {PatronSearchDialogComponent
   } from '@eg/staff/share/patron/search-dialog.component';
 
@@ -81,6 +82,7 @@ export class HoldComponent implements OnInit {
         private cat: CatalogService,
         private staffCat: StaffCatalogService,
         private holds: HoldsService,
+        private patron: PatronService,
         private perm: PermService
     ) {
         this.holdContexts = [];
@@ -93,6 +95,11 @@ export class HoldComponent implements OnInit {
         this.holdTargets = this.route.snapshot.queryParams['target'];
         this.holdFor = this.route.snapshot.queryParams['holdFor'] || 'patron';
 
+        if (this.staffCat.holdForBarcode) {
+            this.holdFor = 'patron';
+            this.userBarcode = this.staffCat.holdForBarcode;
+        }
+
         if (!Array.isArray(this.holdTargets)) {
             this.holdTargets = [this.holdTargets];
         }
@@ -107,7 +114,7 @@ export class HoldComponent implements OnInit {
             return ctx;
         });
 
-        if (this.holdFor === 'staff') {
+        if (this.holdFor === 'staff' || this.userBarcode) {
             this.holdForChanged();
         }
 
@@ -245,25 +252,18 @@ export class HoldComponent implements OnInit {
 
         this.user = null;
         this.currentUserBarcode = this.userBarcode;
+        this.getUser();
+    }
 
-        this.net.request(
-            'open-ils.actor',
-            'open-ils.actor.get_barcodes',
-            this.auth.token(), this.auth.user().ws_ou(),
-            'actor', this.userBarcode
-        ).subscribe(barcodes => {
-
-            // Use the first successful barcode response.
-            // TODO: What happens when there are multiple responses?
-            // Use for-loop for early exit since we have async
-            // action within the loop.
-            for (let i = 0; i < barcodes.length; i++) {
-                const bc = barcodes[i];
-                if (!this.evt.parse(bc)) {
-                    this.getUser(bc.id);
-                    break;
-                }
-            }
+    getUser(id?: number) {
+        const flesh = {flesh: 1, flesh_fields: {au: ['settings']}};
+
+        const promise = id ? this.patron.getById(id, flesh) :
+            this.patron.getByBarcode(this.userBarcode);
+
+        promise.then(user => {
+            this.user = user;
+            this.applyUserSettings();
         });
     }
 
@@ -274,14 +274,6 @@ export class HoldComponent implements OnInit {
         this.pickupLib = this.requestor.ws_ou();
     }
 
-    getUser(id: number) {
-        this.pcrud.retrieve('au', id, {flesh: 1, flesh_fields: {au: ['settings']}})
-        .subscribe(user => {
-            this.user = user;
-            this.applyUserSettings();
-        });
-    }
-
     applyUserSettings() {
         if (!this.user || !this.user.settings()) { return; }
 
diff --git a/Open-ILS/src/eg2/src/app/staff/share/patron/patron.service.ts b/Open-ILS/src/eg2/src/app/staff/share/patron/patron.service.ts
index 12fd1e137b..e50fbb2422 100644
--- a/Open-ILS/src/eg2/src/app/staff/share/patron/patron.service.ts
+++ b/Open-ILS/src/eg2/src/app/staff/share/patron/patron.service.ts
@@ -1,5 +1,8 @@
 import {Injectable} from '@angular/core';
+import {IdlObject} from '@eg/core/idl.service';
 import {NetService} from '@eg/core/net.service';
+import {EventService} from '@eg/core/event.service';
+import {PcrudService} from '@eg/core/pcrud.service';
 import {AuthService} from '@eg/core/auth.service';
 import {Observable} from 'rxjs';
 
@@ -8,6 +11,8 @@ import {Observable} from 'rxjs';
 export class PatronService {
     constructor(
         private net: NetService,
+        private evt: EventService,
+        private pcrud: PcrudService,
         private auth: AuthService
     ) {}
 
@@ -19,5 +24,28 @@ export class PatronService {
            'actor', barcode.trim());
     }
 
+    getByBarcode(barcode: string, pcrudOps?: any): Promise<IdlObject> {
+        return this.bcSearch(barcode).toPromise()
+        .then(barcodes => {
+
+            // Use the first successful barcode response.
+            // TODO: What happens when there are multiple responses?
+            // Use for-loop for early exit since we have async
+            // action within the loop.
+            for (let i = 0; i < barcodes.length; i++) {
+                const bc = barcodes[i];
+                if (!this.evt.parse(bc)) {
+                    return this.getById(bc.id);
+                }
+            }
+
+            return null;
+        });
+    }
+
+    getById(id: number, pcrudOps?: any): Promise<IdlObject> {
+        return this.pcrud.retrieve('au', id, pcrudOps).toPromise();
+    }
+
 }
 
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_holds.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_holds.tt2
index 5ccd762a76..a5499acbbf 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_holds.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_holds.tt2
@@ -32,7 +32,9 @@
 
 <!-- catalog view for holds placement -->
 
+<!-- Replaced with Angular catalog link
 <div ng-if="placing_hold">
   <eg-embed-frame url="catalog_url" handlers="handlers" 
     onchange="handle_page"></eg-embed-frame>
 </div>
+-->
diff --git a/Open-ILS/web/js/ui/default/staff/circ/patron/holds.js b/Open-ILS/web/js/ui/default/staff/circ/patron/holds.js
index c3ce75be85..798ff73d7d 100644
--- a/Open-ILS/web/js/ui/default/staff/circ/patron/holds.js
+++ b/Open-ILS/web/js/ui/default/staff/circ/patron/holds.js
@@ -145,7 +145,10 @@ function($scope,  $q,  $routeParams,  egCore,  egUser,  patronSvc,
     }
 
     $scope.place_hold = function() {
-        $location.path($location.path() + '/create');
+        $window.location.href = '/eg2/staff/catalog?holdForBarcode=' + 
+            encodeURIComponent(patronSvc.current.card().barcode());
+
+        //$location.path($location.path() + '/create');
     }
 
     // when the detail hold is fetched (and updated), update the bib

commit d89523ea11ae3f1fdd4ae09a3e1909187ec40d21
Author: Bill Erickson <berickxx at gmail.com>
Date:   Tue Mar 31 11:01:57 2020 -0400

    LP1869898 Angular staff cat release notes
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Jane Sandberg <sandbej at linnbenton.edu>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/docs/RELEASE_NOTES_NEXT/Client/ang-staff-default.adoc b/docs/RELEASE_NOTES_NEXT/Client/ang-staff-default.adoc
new file mode 100644
index 0000000000..4664079189
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/Client/ang-staff-default.adoc
@@ -0,0 +1,17 @@
+New Angular Staff Catalog Default
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The experimental Angular staff catalog has been promoted to operate as the
+default catalog in the browser staff client.  It will be used for all 
+catalog entry points, except for the menu entries for the traditiaional
+catalog and any links within the traditional catalog.
+
+Menu Changes
+++++++++++++
+
+* Search => 'Search The Catalog' now searches to new catalog.
+* Cataloging => 'Search The Catalog' now searches to new catalog.
+* Cataloging => 'Search The Catalog (Traditional)' searches the traditional 
+  TPAC-style catalog.
+* Staff client splash page => 'Search the catalog' inline form uses the 
+  new catalog.
+

commit 04b5c10020f13af008654bc8e631962fc437024f
Author: Bill Erickson <berickxx at gmail.com>
Date:   Fri Mar 27 13:17:38 2020 -0400

    LP1869898 Make Angular staff catalog default
    
    Modifies Angular and AngJS templates and AngJS code to use the new
    Angular staff catalog as the default catalog for new catalog searches,
    record detail links, etc.
    
    The traditional client is left unmodified and remains accessible from
    the navigation menus.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Jane Sandberg <sandbej at linnbenton.edu>
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>

diff --git a/Open-ILS/src/eg2/src/app/staff/cat/vandelay/queue.component.html b/Open-ILS/src/eg2/src/app/staff/cat/vandelay/queue.component.html
index b3b39a8a16..480e5548ea 100644
--- a/Open-ILS/src/eg2/src/app/staff/cat/vandelay/queue.component.html
+++ b/Open-ILS/src/eg2/src/app/staff/cat/vandelay/queue.component.html
@@ -114,10 +114,9 @@
   <a *ngIf="queueType=='bib'" routerLink="/staff/catalog/record/{{row.imported_as}}">
     {{row.imported_as}}
   </a>
-  <a *ngIf="queueType=='auth'" href="/eg/staff/cat/catalog/authority/{{row.imported_as}}/marc_edit">
+  <a *ngIf="queueType=='auth'" routerLink="/staff/cat/authority/edit/{{row.imported_as}}">
     {{row.imported_as}}
   </a>
-
 </ng-template>
 
 
diff --git a/Open-ILS/src/eg2/src/app/staff/nav.component.html b/Open-ILS/src/eg2/src/app/staff/nav.component.html
index b6641b4b44..735c77a13b 100644
--- a/Open-ILS/src/eg2/src/app/staff/nav.component.html
+++ b/Open-ILS/src/eg2/src/app/staff/nav.component.html
@@ -27,7 +27,7 @@
             <span class="material-icons">assignment</span>
             <span i18n>Search for Items by Barcode</span>
           </a>
-          <a href="/eg/staff/cat/catalog/index" class="dropdown-item"
+          <a class="dropdown-item" routerLink="/staff/catalog"
             egAccessKey keyCtx="navbar" i18n-keySpec i18n-keyDesc
             keySpec="f3" keyDesc="Catalog">
             <span class="material-icons">search</span>
@@ -150,17 +150,15 @@
         </a>
         <div class="dropdown-menu" ngbDropdownMenu>
 
-          <a href="/eg/staff/cat/catalog/index" class="dropdown-item"
+          <a class="dropdown-item" routerLink="/staff/catalog/search"
             egAccessKey keyCtx="navbar"i18n-keySpec i18n-keyDesc
             keySpec="f3" keyDesc="Catalog">
             <span class="material-icons">search</span>
             <span i18n>Search the Catalog</span>
           </a>
-          <a *ngIf="showAngularCatalog"
-            class="dropdown-item"
-            routerLink="/staff/catalog/search">
+          <a href="/eg/staff/cat/catalog/index" class="dropdown-item">
             <span class="material-icons">search</span>
-            <span i18n>Staff Catalog (Experimental)</span>
+            <span i18n>Search the Catalog (Traditional)</span>
           </a>
           <a class="dropdown-item" href="/eg/staff/cat/item/search"
             egAccessKey keyCtx="navbar" i18n-keySpec i18n-keyDesc
diff --git a/Open-ILS/src/eg2/src/app/staff/nav.component.ts b/Open-ILS/src/eg2/src/app/staff/nav.component.ts
index 5627f762ba..6825464e55 100644
--- a/Open-ILS/src/eg2/src/app/staff/nav.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/nav.component.ts
@@ -104,11 +104,10 @@ export class StaffNavComponent implements OnInit, OnDestroy {
         this.printer.reprintLast();
     }
 
-    // TODO: Point to Angular catalog when the time comes
     retrieveLastRecord() {
         const recId = this.store.getLocalItem('eg.cat.last_record_retrieved');
         if (recId) {
-            window.location.href = '/eg/staff/cat/catalog/record/' + recId;
+            this.router.navigate(['/staff/catalog/record/' + recId]);
         }
     }
 }
diff --git a/Open-ILS/src/eg2/src/app/staff/splash.component.ts b/Open-ILS/src/eg2/src/app/staff/splash.component.ts
index af6b647dfa..6756b6519c 100644
--- a/Open-ILS/src/eg2/src/app/staff/splash.component.ts
+++ b/Open-ILS/src/eg2/src/app/staff/splash.component.ts
@@ -23,17 +23,10 @@ export class StaffSplashComponent implements OnInit {
     searchCatalog(): void {
         if (!this.catSearchQuery) { return; }
 
-        /* Route to angular6 catalog
         this.router.navigate(
             ['/staff/catalog/search'],
             {queryParams: {query : this.catSearchQuery}}
         );
-        */
-
-        // Route to AngularJS / TPAC catalog
-        window.location.href =
-            '/eg/staff/cat/catalog/results?query=' +
-            encodeURIComponent(this.catSearchQuery);
     }
 }
 
diff --git a/Open-ILS/src/templates/staff/cat/bucket/copy/t_pending.tt2 b/Open-ILS/src/templates/staff/cat/bucket/copy/t_pending.tt2
index 431d2d4d46..043cffc467 100644
--- a/Open-ILS/src/templates/staff/cat/bucket/copy/t_pending.tt2
+++ b/Open-ILS/src/templates/staff/cat/bucket/copy/t_pending.tt2
@@ -54,7 +54,7 @@
 
   <eg-grid-field label="[% l('Title') %]"
     path="call_number.record.simple_record.title" visible>
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item['call_number.record.id']}}">
+    <a href="/eg2/staff/catalog/record/{{item['call_number.record.id']}}">
       {{item['call_number.record.simple_record.title']}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/cat/bucket/copy/t_view.tt2 b/Open-ILS/src/templates/staff/cat/bucket/copy/t_view.tt2
index 98bf38b80b..29dc8a31c5 100644
--- a/Open-ILS/src/templates/staff/cat/bucket/copy/t_view.tt2
+++ b/Open-ILS/src/templates/staff/cat/bucket/copy/t_view.tt2
@@ -44,7 +44,7 @@
 
   <eg-grid-field label="[% l('Title') %]"
     path="call_number.record.simple_record.title" visible>
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item['call_number.record.id']}}">
+    <a href="/eg2/staff/catalog/record/{{item['call_number.record.id']}}">
       {{item['call_number.record.simple_record.title']}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/cat/bucket/record/t_pending.tt2 b/Open-ILS/src/templates/staff/cat/bucket/record/t_pending.tt2
index b313db9815..f636a09231 100644
--- a/Open-ILS/src/templates/staff/cat/bucket/record/t_pending.tt2
+++ b/Open-ILS/src/templates/staff/cat/bucket/record/t_pending.tt2
@@ -18,7 +18,7 @@
     handler="resetPendingList"></eg-grid-action>
 
   <eg-grid-field label="[% l('Title') %]" path="title">
-    <a target="_blank" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.id}}">
+    <a target="_blank" href="/eg2/staff/catalog/record/{{item.id}}">
     {{item.title}} <span ng-show="item.id" class="glyphicon glyphicon-new-window"></span>
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/cat/bucket/record/t_search.tt2 b/Open-ILS/src/templates/staff/cat/bucket/record/t_search.tt2
index c5cfc342d9..651b3618d4 100644
--- a/Open-ILS/src/templates/staff/cat/bucket/record/t_search.tt2
+++ b/Open-ILS/src/templates/staff/cat/bucket/record/t_search.tt2
@@ -44,7 +44,7 @@
     handler="addToBucket"></eg-grid-action>
 
   <eg-grid-field label="[% l('Title') %]" path="title">
-    <a target="_blank" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.id}}">
+    <a target="_blank" href="/eg2/staff/catalog/record/{{item.id}}">
     {{item.title}} <span ng-show="item.id" class="glyphicon glyphicon-new-window"></span>
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/cat/bucket/record/t_view.tt2 b/Open-ILS/src/templates/staff/cat/bucket/record/t_view.tt2
index a30697c6e5..26cd353bb2 100644
--- a/Open-ILS/src/templates/staff/cat/bucket/record/t_view.tt2
+++ b/Open-ILS/src/templates/staff/cat/bucket/record/t_view.tt2
@@ -35,7 +35,7 @@
   <eg-grid-field path="id" required hidden></eg-grid-field>
 
   <eg-grid-field label="[% l('Title') %]" path="title">
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.id}}">
+    <a href="/eg2/staff/catalog/record/{{item.id}}">
       {{item.title}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/cat/item/t_list.tt2 b/Open-ILS/src/templates/staff/cat/item/t_list.tt2
index fc9ce492a0..6d6e08cde9 100644
--- a/Open-ILS/src/templates/staff/cat/item/t_list.tt2
+++ b/Open-ILS/src/templates/staff/cat/item/t_list.tt2
@@ -93,7 +93,7 @@
         {{item['dummy_title']}}
     </span>
     <span ng-hide="item['call_number.record.id'] == -1">
-        <a target="_blank" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item['call_number.record.id']}}">
+        <a target="_blank" href="/eg2/staff/catalog/record/{{item['call_number.record.id']}}">
           {{item['call_number.record.simple_record.title']}} <span ng-show="item['call_number.record.id']" class="glyphicon glyphicon-new-window"></span>
         </a>
     </span>
diff --git a/Open-ILS/src/templates/staff/cat/share/t_record_summary.tt2 b/Open-ILS/src/templates/staff/cat/share/t_record_summary.tt2
index c98b087034..ce4af2e8e1 100644
--- a/Open-ILS/src/templates/staff/cat/share/t_record_summary.tt2
+++ b/Open-ILS/src/templates/staff/cat/share/t_record_summary.tt2
@@ -7,8 +7,7 @@
         </span>
     </div>
     <div ng-if="!noMarcLink" class="flex-cell">
-      <a target="_self" 
-        href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.id()}}/marc_html">
+      <a href="/eg2/staff/catalog/record/{{record.id()}}/marc_html">
         (MARC)
       </a>
     </div>
@@ -30,7 +29,7 @@
   </div>
 </div>
 <div ng-if="record.merged_to()" class="row alert alert-warning">
-  <a href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.merged_to()}}">
+  <a href="/eg2/staff/catalog/record/{{record.merged_to()}}">
     [% l('Record merged to #[_1] on [_2]', 
          '{{record.merged_to()}}',
          '{{record.merge_date() | date:$root.egDateAndTimeFormat}}') 
@@ -41,8 +40,7 @@
   <div class="flex-row">
     <div class="flex-cell strong-text">[% l('Title:') %]</div>
     <div class="flex-cell flex-2">
-      <a target="_self" 
-        href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.id()}}">
+      <a href="/eg2/staff/catalog/record/{{record.id()}}">
         {{rec_display.title}}
       </a>
     </div>
@@ -64,8 +62,7 @@
   <div class="flex-row">
     <div class="flex-cell strong-text">[% l('Title:') %]</div>
     <div class="flex-cell flex-2">
-      <a target="_self" 
-        href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.id()}}">
+      <a href="/eg2/staff/catalog/record/{{record.id()}}">
         {{rec_display.title}}
       </a>
     </div>
diff --git a/Open-ILS/src/templates/staff/cat/share/t_record_summary_slim.tt2 b/Open-ILS/src/templates/staff/cat/share/t_record_summary_slim.tt2
index 7095c5dee6..10719aa2b6 100644
--- a/Open-ILS/src/templates/staff/cat/share/t_record_summary_slim.tt2
+++ b/Open-ILS/src/templates/staff/cat/share/t_record_summary_slim.tt2
@@ -7,8 +7,7 @@
         </span>
     </div>
     <div ng-if="!noMarcLink" class="flex-cell flex-2">
-      <a target="_self" 
-        href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.id()}}/marc_html">
+      <a href="/eg2/staff/catalog/record/{{record.id()}}/marc_html">
         (MARC)
       </a>
     </div>
@@ -27,7 +26,7 @@
   </div>
 </div>
 <div ng-if="record.merged_to()" class="row alert alert-warning">
-  <a href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.merged_to()}}">
+  <a href="/eg2/staff/catalog/record/{{record.merged_to()}}">
     [% l('Record merged to #[_1] on [_2]', 
          '{{record.merged_to()}}',
          '{{record.merge_date() | date:$root.egDateAndTimeFormat}}') 
@@ -38,8 +37,7 @@
   <div class="flex-row">
     <div class="flex-cell strong-text">[% l('Title:') %]</div>
     <div class="flex-cell flex-3">
-      <a target="_self" 
-        href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.id()}}">
+      <a href="/eg2/staff/catalog/record/{{record.id()}}">
         {{rec_display.title}}
       </a>
     </div>
@@ -64,8 +62,7 @@
   <div class="flex-row">
     <div class="flex-cell strong-text">[% l('Title:') %]</div>
     <div class="flex-cell flex-3">
-      <a target="_self" 
-        href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.id()}}">
+      <a href="/eg2/staff/catalog/record/{{record.id()}}">
         {{rec_display.title}}
       </a>
     </div>
diff --git a/Open-ILS/src/templates/staff/circ/checkin/t_checkin_table.tt2 b/Open-ILS/src/templates/staff/circ/checkin/t_checkin_table.tt2
index 5a27145747..19b1d3358e 100644
--- a/Open-ILS/src/templates/staff/circ/checkin/t_checkin_table.tt2
+++ b/Open-ILS/src/templates/staff/circ/checkin/t_checkin_table.tt2
@@ -96,7 +96,7 @@
     path='circ.xact_start'></eg-grid-field>
 
   <eg-grid-field label="[% l('Title') %]" path="title">
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.record.doc_id()}}">
+    <a href="/eg2/staff/catalog/record/{{item.record.doc_id()}}">
       {{item.title}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/circ/holds/t_pull_list.tt2 b/Open-ILS/src/templates/staff/circ/holds/t_pull_list.tt2
index 2348f992cd..eda5f059ef 100644
--- a/Open-ILS/src/templates/staff/circ/holds/t_pull_list.tt2
+++ b/Open-ILS/src/templates/staff/circ/holds/t_pull_list.tt2
@@ -94,8 +94,7 @@
   <eg-grid-field name="title" 
     path="current_copy.call_number.record.simple_record.title" 
     label="[% l('Title') %]">
-    <a target="_self" 
-      href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.record_id}}">
+    <a href="/eg2/staff/catalog/record/{{item.record_id}}">
       {{item.title}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/circ/holds/t_shelf_list.tt2 b/Open-ILS/src/templates/staff/circ/holds/t_shelf_list.tt2
index 22a6e39d75..bbd8679a17 100644
--- a/Open-ILS/src/templates/staff/circ/holds/t_shelf_list.tt2
+++ b/Open-ILS/src/templates/staff/circ/holds/t_shelf_list.tt2
@@ -76,7 +76,7 @@
   <eg-grid-field label="[% l('Post-Clear') %]" path='post_clear'></eg-grid-field>
 
   <eg-grid-field label="[% l('Title') %]" path='hold.title'>
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.hold.record_id}}">
+    <a href="/eg2/staff/catalog/record/{{item.hold.record_id}}">
       {{item.hold.title}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_bill_history_payments.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_bill_history_payments.tt2
index 5c31297d9b..e21a3019ad 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_bill_history_payments.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_bill_history_payments.tt2
@@ -21,7 +21,7 @@
     <eg-grid-field path="payment_type" label="Payment Type"></eg-grid-field>
     <eg-grid-field label="[% l('Title') %]" name="title" 
       path="xact.circulation.target_copy.call_number.record.simple_record.title">
-      <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.record_id}}">{{item.title}}</a>
+      <a href="/eg2/staff/catalog/record/{{item.record_id}}">{{item.title}}</a>
     </eg-grid-field>
 
     <!-- needed for bib link -->
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_bill_history_xacts.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_bill_history_xacts.tt2
index 4be0ef08b6..f08b03414d 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_bill_history_xacts.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_bill_history_xacts.tt2
@@ -25,7 +25,7 @@
 
     <eg-grid-field label="[% l('Title') %]" name="title" 
       path="circulation.target_copy.call_number.record.simple_record.title">
-      <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.record_id}}">{{item.title}}</a>
+      <a href="/eg2/staff/catalog/record/{{item.record_id}}">{{item.title}}</a>
     </eg-grid-field>
 
     <!-- needed for bib link -->
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_bills_list.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_bills_list.tt2
index d622db6c47..ccd7320571 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_bills_list.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_bills_list.tt2
@@ -74,7 +74,7 @@
 
   <eg-grid-field label="[% l('Title') %]" name="title"
     path='circulation.target_copy.call_number.record.simple_record.title'>
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.record_id}}">{{item.title}}</a>
+    <a href="/eg2/staff/catalog/record/{{item.record_id}}">{{item.title}}</a>
   </eg-grid-field>
   <!-- fetch the record ID so we can link to it.  hide it by default -->
   <eg-grid-field path="circulation.target_copy.call_number.record.id" 
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_checkout.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_checkout.tt2
index 7cbe4927c7..8744e0f7d8 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_checkout.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_checkout.tt2
@@ -136,7 +136,7 @@
     path='circ.renewal_remaining'></eg-grid-field>
 
   <eg-grid-field label="[% l('Title') %]" path="title">
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.acn.record()}}">
+    <a href="/eg2/staff/catalog/record/{{item.acn.record()}}">
       {{item.title}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_holds_list.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_holds_list.tt2
index 961ad03fc6..d2e8d576ad 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_holds_list.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_holds_list.tt2
@@ -66,7 +66,7 @@
   <eg-grid-field label="[% l('Pickup Library') %]" path='hold.pickup_lib.shortname'></eg-grid-field>
 
   <eg-grid-field label="[% l('Title') %]" path='mvr.title'>
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.mvr.doc_id()}}">
+    <a href="/eg2/staff/catalog/record/{{item.mvr.doc_id()}}">
       {{item.mvr.title()}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_items_out.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_items_out.tt2
index 37235ed5c0..83f8ece7cd 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_items_out.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_items_out.tt2
@@ -97,7 +97,7 @@
   <eg-grid-field label="[% l('Renewals Remaining') %]" path='renewal_remaining'></eg-grid-field>
   <eg-grid-field label="[% l('Fines Stopped') %]" path='stop_fines'></eg-grid-field>
   <eg-grid-field label="[% l('Title') %]" path="target_copy.call_number.record.wide_display_entry.title" name="title">
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item.target_copy().call_number().record().id()}}">
+    <a href="/eg2/staff/catalog/record/{{item.target_copy().call_number().record().id()}}">
       {{item.target_copy().call_number().record().wide_display_entry().title()}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_xact_details.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_xact_details.tt2
index 4d5ff59486..b08cdff7d4 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_xact_details.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_xact_details.tt2
@@ -10,7 +10,7 @@
   <div class="col-md-2">{{xact.summary().total_owed() | currency}}</div>
   <div class="col-md-2 strong-text">[% l('Title') %]</div>
   <div class="col-md-2">
-    <a ng-if="title_id" target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{title_id}}">{{title}}</a>
+    <a ng-if="title_id" href="/eg2/staff/catalog/record/{{title_id}}">{{title}}</a>
     <span ng-if="!title_id">{{title}}</span>
   </div>
 </div>
diff --git a/Open-ILS/src/templates/staff/circ/renew/t_renew.tt2 b/Open-ILS/src/templates/staff/circ/renew/t_renew.tt2
index 0a2caad72a..6447ecce20 100644
--- a/Open-ILS/src/templates/staff/circ/renew/t_renew.tt2
+++ b/Open-ILS/src/templates/staff/circ/renew/t_renew.tt2
@@ -121,7 +121,7 @@
     path='circ.renewal_remaining'></eg-grid-field>
 
   <eg-grid-field label="[% l('Title') %]" path="title">
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{record.doc_id()}}">
+    <a href="/eg2/staff/catalog/record/{{record.doc_id()}}">
       {{item.title}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/circ/transits/t_list.tt2 b/Open-ILS/src/templates/staff/circ/transits/t_list.tt2
index d15120021e..0719ed909a 100644
--- a/Open-ILS/src/templates/staff/circ/transits/t_list.tt2
+++ b/Open-ILS/src/templates/staff/circ/transits/t_list.tt2
@@ -57,7 +57,7 @@
   <eg-grid-field path='target_copy.call_number.label' hidden required sortable></eg-grid-field>
   <eg-grid-field label="[% l('CN Suffix') %]" path="target_copy.call_number.suffix.label"></eg-grid-field>
   <eg-grid-field path='target_copy.call_number.record.simple_record.title' label="[% l('Title') %]" sortable>
-    <a target="_self" href="[% ctx.base_path %]/staff/cat/catalog/record/{{item['target_copy.call_number.record.simple_record.id']}}">
+    <a href="/eg2/staff/catalog/record/{{item['target_copy.call_number.record.simple_record.id']}}">
       {{item['target_copy.call_number.record.simple_record.title']}}
     </a>
   </eg-grid-field>
diff --git a/Open-ILS/src/templates/staff/navbar.tt2 b/Open-ILS/src/templates/staff/navbar.tt2
index 35e542332c..73053ddd1c 100644
--- a/Open-ILS/src/templates/staff/navbar.tt2
+++ b/Open-ILS/src/templates/staff/navbar.tt2
@@ -51,9 +51,9 @@
             </a>
           </li>
           <li>
-            <a href="./cat/catalog/index" target="_self"
+            <a href="/eg2/staff/catalog/search"
               eg-accesskey="[% l('f3') %]" 
-              eg-accesskey-desc="[% l('OPAC') %]">
+              eg-accesskey-desc="[% l('Catalog') %]">
               <span class="glyphicon glyphicon-search"></span>
               <span>[% l('Search the Catalog') %]</span>
             </a>
@@ -245,19 +245,16 @@
         <a href uib-dropdown-toggle>[% l('Cataloging') %]<b class="caret"></b>
         </a>
         <ul uib-dropdown-menu>
-          <li>
-            <a href="./cat/catalog/index" target="_self">
+          <li> 
+            <a href="/eg2/staff/catalog/search">
               <span class="glyphicon glyphicon-search"></span>
-              [% l('Search the Catalog') %]
+              <span>[% l('Search the Catalog') %]</span>
             </a>
           </li>
-          <!--
-            Link to experimental Angular staff catalog.
-          -->
-          <li ng-if="showAngularCatalog">
-            <a href="/eg2/staff/catalog/search">
+          <li>
+            <a href="./cat/catalog/index" target="_self">
               <span class="glyphicon glyphicon-search"></span>
-              <span>[% l('Staff Catalog (Experimental)') %]</span>
+              [% l('Search the Catalog (Traditional)') %]
             </a>
           </li>
           <li>
diff --git a/Open-ILS/src/templates/staff/serials/t_link_mfhd.tt2 b/Open-ILS/src/templates/staff/serials/t_link_mfhd.tt2
index 03820d284c..6ca1e40773 100644
--- a/Open-ILS/src/templates/staff/serials/t_link_mfhd.tt2
+++ b/Open-ILS/src/templates/staff/serials/t_link_mfhd.tt2
@@ -7,7 +7,7 @@
     <div class="modal-body">
         <div ng-repeat="legacy in legacies">
             <div uib-tooltip="[% l('Record ID [_1]', '{{legacy.mvr.doc_id}}') %]" tooltip-placement="left">
-                <a target="_blank" href="/eg/staff/cat/catalog/record/{{legacy.mvr.doc_id}}">{{legacy.mvr.title}}</a>
+                <a href="/eg2/staff/catalog/record/{{legacy.mvr.doc_id}}">{{legacy.mvr.title}}</a>
             </div>
             <div>
                 {{legacy.mvr.physical_description}}
diff --git a/Open-ILS/web/js/ui/default/staff/app.js b/Open-ILS/web/js/ui/default/staff/app.js
index 672104676a..58afd0664d 100644
--- a/Open-ILS/web/js/ui/default/staff/app.js
+++ b/Open-ILS/web/js/ui/default/staff/app.js
@@ -166,7 +166,7 @@ function($routeProvider , $locationProvider) {
         if (!$scope.cat_query) return;
         if ($event && $event.keyCode != 13) return; // input ng-keypress
         $window.location.href = 
-            '/eg/staff/cat/catalog/results?query=' + 
+            '/eg2/staff/catalog/search?query=' +
             encodeURIComponent($scope.cat_query);
     }
 }])
diff --git a/Open-ILS/web/js/ui/default/staff/cat/bucket/record/app.js b/Open-ILS/web/js/ui/default/staff/cat/bucket/record/app.js
index cdaaaa147b..cd9b9326d4 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/bucket/record/app.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/bucket/record/app.js
@@ -747,7 +747,7 @@ function($scope,  $q , $routeParams,  bucketSvc,  egCore,  $window,
                     args.lead_id,
                     args.records.map(function(val) { return val.id; })
                 ).then(function() {
-                    $window.open(egCore.env.basePath + 'cat/catalog/record/' + args.lead_id);
+                    $window.open('/eg2/staff/catalog/record/' + args.lead_id);
                 });
             });
         });
@@ -757,9 +757,7 @@ function($scope,  $q , $routeParams,  bucketSvc,  egCore,  $window,
         // TODO: probably want to set a limit on the number of
         //       new tabs one could choose to open at once
         angular.forEach(records, function(rec) {
-            var url = egCore.env.basePath +
-                      'cat/catalog/record/' +
-                      rec.id;
+            var url = '/eg2/staff/catalog/record/' + rec.id;
             $timeout(function() { $window.open(url, '_blank') });
         });
     }
diff --git a/Open-ILS/web/js/ui/default/staff/cat/item/app.js b/Open-ILS/web/js/ui/default/staff/cat/item/app.js
index a07ee45107..c419a72e19 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/item/app.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/item/app.js
@@ -91,7 +91,7 @@ function($scope , $q , $window , $location , $timeout , egCore , egNet , egGridD
     }
 
     $scope.show_in_catalog = function() {
-        window.open('/eg/staff/cat/catalog/record/' + $scope.args.recordId + '/catalog', '_blank');
+        window.open('/eg2/staff/catalog/record/' + $scope.args.recordId, '_blank');
     }
 
     $scope.print_labels = function() {
@@ -169,7 +169,7 @@ function($scope , $q , $window , $location , $timeout , egCore , egNet , egGridD
     }
 
     $scope.show_record_holds = function() {
-        window.open('/eg/staff/cat/catalog/record/' + $scope.args.recordId + '/holds', '_blank');
+        window.open('/eg2/staff/catalog/record/' + $scope.args.recordId + '/holds', '_blank');
     }
 
     $scope.add_item_alerts = function() {
@@ -656,7 +656,7 @@ function($scope , $q , $window , $location , $timeout , egCore , egNet , egGridD
 
     $scope.showBibHolds = function () {
         angular.forEach(gatherSelectedRecordIds(), function (r) {
-            var url = egCore.env.basePath + 'cat/catalog/record/' + r + '/holds';
+            var url = '/eg2/staff/catalog/record/' + r + '/holds';
             $timeout(function() { $window.open(url, '_blank') });
         });
     }
diff --git a/Open-ILS/web/js/ui/default/staff/cat/z3950/app.js b/Open-ILS/web/js/ui/default/staff/cat/z3950/app.js
index 94d68040e7..e2c363c4c3 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/z3950/app.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/z3950/app.js
@@ -185,8 +185,7 @@ function($scope , $q , $location , $timeout , $window,  egCore , egGridDataProvi
     $scope.showInCatalog = function() {
         var items = $scope.gridControls.selectedItems();
         // relying on cant_showInCatalog to protect us
-        var url = egCore.env.basePath +
-                  'cat/catalog/record/' + items[0].tcn();
+        var url = '/eg2/staff/catalog/record/' + items[0].tcn();
         $timeout(function() { $window.open(url, '_blank') });        
     };
     $scope.cant_showInCatalog = function() {
@@ -268,7 +267,7 @@ function($scope , $q , $location , $timeout , $window,  egCore , egGridDataProvi
                         egCore.strings.GO_TO_RECORD,
                         egCore.strings.GO_BACK
                     ).result.then(function() {
-                        $window.open(egCore.env.basePath + 'cat/catalog/record/' + result.id());
+                        $window.open('/eg2/staff/catalog/record/' + result.id());
                     });
                 }
             }
@@ -322,7 +321,7 @@ function($scope , $q , $location , $timeout , $window,  egCore , egGridDataProvi
             }]
         }).result.then(function () {
             if (recId) {
-                $window.location.href = egCore.env.basePath + 'cat/catalog/record/' + recId;
+                $window.location.href = '/eg2/staff/catalog/record/' + recId;
             }
         });
     }
@@ -472,7 +471,7 @@ function($scope , $q , $location , $timeout , $window,  egCore , egGridDataProvi
                     $scope.local_overlay_target = 0;
                     egCore.hatch.removeLocalItem('eg.cat.marked_overlay_record');
                     console.debug('overlay complete, target removed');
-                    $window.open(egCore.env.basePath + 'cat/catalog/record/' + overlay_target);
+                    $window.open('/eg2/staff/catalog/record/' + overlay_target);
                 }
             );            
         });
diff --git a/Open-ILS/web/js/ui/default/staff/circ/checkin/app.js b/Open-ILS/web/js/ui/default/staff/circ/checkin/app.js
index 82bd4c8764..eb360c9ff7 100644
--- a/Open-ILS/web/js/ui/default/staff/circ/checkin/app.js
+++ b/Open-ILS/web/js/ui/default/staff/circ/checkin/app.js
@@ -380,7 +380,7 @@ function($scope , $q , $window , $location , $timeout , egCore , checkinSvc , eg
             recordIds.push(i.acn.record());
         });
         angular.forEach(recordIds, function (r) {
-            var url = egCore.env.basePath + 'cat/catalog/record/' + r + '/holds';
+            var url = '/eg2/staff/catalog/record/' + r + '/holds';
             $timeout(function() { $window.open(url, '_blank') });
         });
     }
diff --git a/Open-ILS/web/js/ui/default/staff/circ/services/holds.js b/Open-ILS/web/js/ui/default/staff/circ/services/holds.js
index 0ae837aef7..251ceb216e 100644
--- a/Open-ILS/web/js/ui/default/staff/circ/services/holds.js
+++ b/Open-ILS/web/js/ui/default/staff/circ/services/holds.js
@@ -668,10 +668,7 @@ function($window , $location , $timeout , egCore , egHolds , egCirc) {
     service.show_holds_for_title = function(items) {
         var focus = items.length == 1;
         angular.forEach(items, function(item) {
-            var url = egCore.env.basePath +
-                      'cat/catalog/record/' +
-                      item.mvr.doc_id() +
-                      '/holds';
+            var url = '/eg2/staff/catalog/record/' + item.mvr.doc_id() + '/holds';
             $timeout(function() { var x = $window.open(url, '_blank'); if (focus) x.focus() });
         });
     }
@@ -679,10 +676,7 @@ function($window , $location , $timeout , egCore , egHolds , egCirc) {
     service.show_holds_for_title_wide = function(items) {
         var focus = items.length == 1;
         angular.forEach(items, function(item) {
-            var url = egCore.env.basePath +
-                      'cat/catalog/record/' +
-                      item.hold.record_id +
-                      '/holds';
+            var url = '/eg2/staff/catalog/record/' + item.hold.record_id + '/holds';
             $timeout(function() { var x = $window.open(url, '_blank'); if (focus) x.focus() });
         });
     }
diff --git a/Open-ILS/web/js/ui/default/staff/circ/services/item.js b/Open-ILS/web/js/ui/default/staff/circ/services/item.js
index 8150f18ea5..d7c43efd0f 100644
--- a/Open-ILS/web/js/ui/default/staff/circ/services/item.js
+++ b/Open-ILS/web/js/ui/default/staff/circ/services/item.js
@@ -998,7 +998,7 @@ function(egCore , egOrg , egCirc , $uibModal , $q , $timeout , $window , ngToast
 
     service.show_in_catalog = function(copy_list){
         angular.forEach(copy_list, function(copy){
-            window.open('/eg/staff/cat/catalog/record/'+copy['call_number.record.id']+'/catalog', '_blank')
+            window.open('/eg2/staff/catalog/record/'+copy['call_number.record.id'], '_blank')
         });
     }
 
diff --git a/Open-ILS/web/js/ui/default/staff/services/navbar.js b/Open-ILS/web/js/ui/default/staff/services/navbar.js
index a00e26a55c..755dcbba6f 100644
--- a/Open-ILS/web/js/ui/default/staff/services/navbar.js
+++ b/Open-ILS/web/js/ui/default/staff/services/navbar.js
@@ -18,6 +18,14 @@ angular.module('egCoreMod')
                 }
 
                 function navTo(path) {
+
+                    if (path.match(/^\/eg2\//)) {
+                        // Hotkey for /eg2/ page.  Go directly to the
+                        // provided URL.
+                        $window.location.href = path;
+                        return;
+                    }
+
                     path = path.replace(/^\.\//,'');
                     $window.location.href = egCore.env.basePath + path;
                 }       
@@ -55,8 +63,8 @@ angular.module('egCoreMod')
                 $scope.retrieveLastRecord = function() {
                     var last_record = egCore.hatch.getLocalItem("eg.cat.last_record_retrieved");
                     if (last_record) {
-                        $window.location.href =
-                            egCore.env.basePath + 'cat/catalog/record/' + last_record;
+                        $window.location.href = 
+                            '/eg2/staff/catalog/record/' + last_record;
                     }
                 }
 

-----------------------------------------------------------------------

Summary of changes:
 .../src/app/share/catalog/bib-record.service.ts    | 270 +++------------------
 .../eg2/src/app/share/catalog/catalog.service.ts   |  14 +-
 .../eg2/src/app/share/util/broadcast.service.ts    |  69 ++++++
 .../app/staff/cat/vandelay/queue.component.html    |   3 +-
 .../vandelay/queued-record-matches.component.ts    |  32 ++-
 .../src/app/staff/catalog/browse.component.html    |   2 +-
 .../src/app/staff/catalog/catalog.component.html   |  20 +-
 .../eg2/src/app/staff/catalog/catalog.component.ts |  12 +
 .../eg2/src/app/staff/catalog/catalog.service.ts   |  14 ++
 .../src/app/staff/catalog/cnbrowse.component.html  |   2 +-
 .../staff/catalog/cnbrowse/results.component.ts    |  15 +-
 .../src/app/staff/catalog/hold/hold.component.ts   |  46 ++--
 .../app/staff/catalog/record/copies.component.ts   |  10 +-
 .../app/staff/catalog/record/holdings.component.ts |   9 +
 .../app/staff/catalog/record/record.component.ts   |   1 -
 .../app/staff/catalog/result/record.component.html |  16 +-
 .../app/staff/catalog/result/record.component.ts   |   1 -
 .../staff/catalog/result/results.component.html    |  10 +-
 .../app/staff/catalog/result/results.component.ts  |  30 +--
 .../app/staff/catalog/search-form.component.html   |   2 +-
 Open-ILS/src/eg2/src/app/staff/common.module.ts    |   4 +-
 Open-ILS/src/eg2/src/app/staff/nav.component.html  |  10 +-
 Open-ILS/src/eg2/src/app/staff/nav.component.ts    |   3 +-
 .../share/bib-summary/bib-summary.component.ts     |   1 -
 .../src/app/staff/share/patron/patron.service.ts   |  28 +++
 Open-ILS/src/eg2/src/app/staff/splash.component.ts |   7 -
 .../lib/OpenILS/Application/Search/Biblio.pm       | 156 +++++++++++-
 Open-ILS/src/sql/Pg/002.schema.config.sql          |   2 +-
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       |  21 +-
 ...result_page_should_use_standard_search_code.sql |   0
 ...3734_include-transcendent_bibs_in_unapi_mmr.sql |   0
 .../1199.lp1849736_at_email_self_register.sql      |   0
 ...-order => 1203.hpprox-best-hold-sort-order.sql} |   0
 .../1206.function.distinct-regen_copy_map.sql      |   0
 .../sql/Pg/upgrade/1212.data.ang-cat-default.sql   |  18 ++
 .../templates/staff/cat/bucket/copy/t_pending.tt2  |   2 +-
 .../src/templates/staff/cat/bucket/copy/t_view.tt2 |   2 +-
 .../staff/cat/bucket/record/t_pending.tt2          |   2 +-
 .../templates/staff/cat/bucket/record/t_search.tt2 |   2 +-
 .../templates/staff/cat/bucket/record/t_view.tt2   |   2 +-
 Open-ILS/src/templates/staff/cat/item/t_list.tt2   |   2 +-
 .../templates/staff/cat/share/t_record_summary.tt2 |  11 +-
 .../staff/cat/share/t_record_summary_slim.tt2      |  11 +-
 .../staff/circ/checkin/t_checkin_table.tt2         |   2 +-
 .../src/templates/staff/circ/holds/t_pull_list.tt2 |   3 +-
 .../templates/staff/circ/holds/t_shelf_list.tt2    |   2 +-
 .../staff/circ/patron/t_bill_history_payments.tt2  |   2 +-
 .../staff/circ/patron/t_bill_history_xacts.tt2     |   2 +-
 .../templates/staff/circ/patron/t_bills_list.tt2   |   2 +-
 .../src/templates/staff/circ/patron/t_checkout.tt2 |   2 +-
 .../src/templates/staff/circ/patron/t_holds.tt2    |   2 +
 .../templates/staff/circ/patron/t_holds_list.tt2   |   2 +-
 .../templates/staff/circ/patron/t_items_out.tt2    |   2 +-
 .../templates/staff/circ/patron/t_xact_details.tt2 |   2 +-
 .../src/templates/staff/circ/renew/t_renew.tt2     |   2 +-
 .../src/templates/staff/circ/transits/t_list.tt2   |   2 +-
 Open-ILS/src/templates/staff/navbar.tt2            |  19 +-
 .../src/templates/staff/serials/t_link_mfhd.tt2    |   2 +-
 Open-ILS/web/js/ui/default/staff/app.js            |   2 +-
 .../js/ui/default/staff/cat/bucket/record/app.js   |   6 +-
 Open-ILS/web/js/ui/default/staff/cat/item/app.js   |   6 +-
 Open-ILS/web/js/ui/default/staff/cat/z3950/app.js  |   9 +-
 .../web/js/ui/default/staff/circ/checkin/app.js    |   2 +-
 .../web/js/ui/default/staff/circ/patron/holds.js   |   5 +-
 .../web/js/ui/default/staff/circ/services/holds.js |  10 +-
 .../web/js/ui/default/staff/circ/services/item.js  |   2 +-
 .../web/js/ui/default/staff/services/navbar.js     |  12 +-
 .../Client/ang-staff-default.adoc                  |  17 ++
 68 files changed, 522 insertions(+), 459 deletions(-)
 create mode 100644 Open-ILS/src/eg2/src/app/share/util/broadcast.service.ts
 mode change 100755 => 100644 Open-ILS/src/sql/Pg/upgrade/1014.metarecord_constituents_search_result_page_should_use_standard_search_code.sql
 mode change 100755 => 100644 Open-ILS/src/sql/Pg/upgrade/1015.function.lp1573734_include-transcendent_bibs_in_unapi_mmr.sql
 mode change 100755 => 100644 Open-ILS/src/sql/Pg/upgrade/1199.lp1849736_at_email_self_register.sql
 rename Open-ILS/src/sql/Pg/upgrade/{1203.hpprox-best-hold-sort-order => 1203.hpprox-best-hold-sort-order.sql} (100%)
 mode change 100755 => 100644
 mode change 100755 => 100644 Open-ILS/src/sql/Pg/upgrade/1206.function.distinct-regen_copy_map.sql
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/1212.data.ang-cat-default.sql
 create mode 100644 docs/RELEASE_NOTES_NEXT/Client/ang-staff-default.adoc


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list