Add CW MARS Angular customizations
authorJason Stephenson <jason@sigio.com>
Tue, 23 May 2023 17:22:43 +0000 (13:22 -0400)
committerJason Stephenson <jason@sigio.com>
Tue, 23 May 2023 17:22:43 +0000 (13:22 -0400)
Signed-off-by: Jason Stephenson <jason@sigio.com>
Open-ILS/src/eg2/src/app/share/catalog/bib-record.service.ts
Open-ILS/src/eg2/src/app/share/catalog/search-context.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.html
Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html
Open-ILS/src/eg2/src/app/staff/common.module.ts
Open-ILS/src/eg2/src/app/staff/share/bib-staff-view/bib-staff-view.component.css [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/share/bib-staff-view/bib-staff-view.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/share/bib-staff-view/bib-staff-view.component.ts [new file with mode: 0644]

index a4dd0b0..954906c 100644 (file)
@@ -37,6 +37,9 @@ export class BibRecordSummary {
     id: number; // == record.id() for convenience
     metabibId: number; // If present, this is a metabib summary
     metabibRecords: number[]; // all constituent bib records
+    staffViewMetabibId: number; // to supplement a record summary
+    staffViewMetabibRecords: number[]; // to supplement a record summary
+    staffViewMetabibAttributes: any; // to supplement a record summary
     orgId: number;
     orgDepth: number;
     record: IdlObject;
@@ -128,6 +131,9 @@ export class BibRecordService {
         .pipe(map(bibSummary => {
             const summary = new BibRecordSummary(bibSummary.record, orgId);
             summary.net = this.net; // inject
+            summary.staffViewMetabibId = Number(bibSummary.staff_view_metabib_id);
+            summary.staffViewMetabibRecords = bibSummary.staff_view_metabib_records;
+            summary.staffViewMetabibAttributes = bibSummary.staff_view_metabib_attributes;
             summary.display = bibSummary.display;
             summary.attributes = bibSummary.attributes;
             summary.holdCount = bibSummary.hold_count;
index 7ee7ab1..53d6763 100644 (file)
@@ -417,7 +417,7 @@ export class CatalogSearchContext {
      */
     reset(): void {
         this.pager.offset = 0;
-        this.sort = '';
+        this.sort = 'poprel';
         this.showBasket = false;
         this.result = new CatalogSearchResults();
         this.resultIds = [];
index 7dea673..106f8c9 100644 (file)
     </div>
     <ngb-tabset #recordTabs [activeId]="recordTab" 
       (tabChange)="beforeTabChange($event)">
+      <ngb-tab title="Staff View" i18n-title id="staff_view">
+        <ng-template ngbTabContent>
+            <eg-bib-staff-view [recordId]="recordId" [bibSummary]="summaryForDisplay()">
+            </eg-bib-staff-view>
+        </ng-template>
+      </ngb-tab>
       <ngb-tab title="Item Table" i18n-title id="item_table">
         <ng-template ngbTabContent>
           <eg-catalog-copies [recordId]="recordId"></eg-catalog-copies>
     </ngb-tabset>
   </div>
 </div>
-
-
index 80e6e19..8d58d2c 100644 (file)
@@ -9,6 +9,7 @@ import {CatalogService} from '@eg/share/catalog/catalog.service';
 import {BibRecordService, BibRecordSummary} from '@eg/share/catalog/bib-record.service';
 import {StaffCatalogService} from '../catalog.service';
 import {BibSummaryComponent} from '@eg/staff/share/bib-summary/bib-summary.component';
+import {BibStaffViewComponent} from '@eg/staff/share/bib-staff-view/bib-staff-view.component';
 import {StoreService} from '@eg/core/store.service';
 import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
 import {MarcEditorComponent} from '@eg/staff/share/marc-edit/editor.component';
@@ -154,7 +155,7 @@ export class RecordComponent implements OnInit {
         this.bib.getBibSummary(
             this.recordId,
             this.searchContext.searchOrg.id(),
-            this.searchContext.searchOrg.ou_type().depth()).toPromise()
+            this.searchContext.isStaff).toPromise()
         .then(summary => {
             this.summary =
                 this.staffCat.currentDetailRecordSummary = summary;
index e08dd8c..912734d 100644 (file)
@@ -64,7 +64,9 @@
                 <option i18n value='keyword'>Keyword</option>
                 <option i18n value='title'>Title</option>
                 <option i18n value='jtitle'>Journal Title</option>
+                <option i18n value='title|uniform'>Uniform Title</option>
                 <option i18n value='author'>Author</option>
+                <option i18n value='identifier|publisher'>Publisher</option>
                 <option i18n value='subject'>Subject</option>
                 <option i18n value='series'>Series</option>
                 <option i18n value='bookplate'
                   <option i18n value="identifier|isbn">ISBN</option>
                   <option i18n value="identifier|upc">UPC</option>
                   <option i18n value="identifier|issn">ISSN</option>
+                  <option i18n value="identifier|scn">OCLC</option>
+                  <option i18n value="identifier|music_number">Music Number</option>
                   <option i18n value="identifier|lccn">LCCN</option>
                   <option i18n value="identifier|tcn">TCN</option>
                   <option i18n value="item_barcode">Item Barcode</option>
+                  <option i18n value="identifier|gov_doc_number">Government Document Number</option>
                 </select>
                 <label for="ident-value" class="ml-2" i18n>Value</label>
                 <input name="ident-value" id='ident-query-input' 
index 3dcd8cc..853576f 100644 (file)
@@ -12,6 +12,7 @@ import {OpChangeComponent} from '@eg/staff/share/op-change/op-change.component';
 import {TitleComponent} from '@eg/share/title/title.component';
 import {BucketDialogComponent} from '@eg/staff/share/buckets/bucket-dialog.component';
 import {BibSummaryComponent} from '@eg/staff/share/bib-summary/bib-summary.component';
+import {BibStaffViewComponent} from '@eg/staff/share/bib-staff-view/bib-staff-view.component';
 import {EgHelpPopoverComponent} from '@eg/share/eg-help-popover/eg-help-popover.component';
 import {DatetimeValidatorDirective} from '@eg/share/validators/datetime_validator.directive';
 import {MultiSelectComponent} from '@eg/share/multi-select/multi-select.component';
@@ -38,6 +39,7 @@ import {ItemLocationSelectModule} from '@eg/share/item-location-select/item-loca
     OpChangeComponent,
     BucketDialogComponent,
     BibSummaryComponent,
+    BibStaffViewComponent,
     EgHelpPopoverComponent,
     DatetimeValidatorDirective,
     MultiSelectComponent,
@@ -65,6 +67,7 @@ import {ItemLocationSelectModule} from '@eg/share/item-location-select/item-loca
     OpChangeComponent,
     BucketDialogComponent,
     BibSummaryComponent,
+    BibStaffViewComponent,
     EgHelpPopoverComponent,
     DatetimeValidatorDirective,
     MultiSelectComponent,
diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-staff-view/bib-staff-view.component.css b/Open-ILS/src/eg2/src/app/staff/share/bib-staff-view/bib-staff-view.component.css
new file mode 100644 (file)
index 0000000..95777f6
--- /dev/null
@@ -0,0 +1,22 @@
+.eg-bib-staff-view {
+    padding-top: 0.5rem;
+}
+
+.eg-bib-staff-view .row {
+    margin-bottom: 0.5rem;
+}
+
+.eg-bib-staff-view > .row:first-child {
+    margin-left: 0;
+}
+
+.eg-bib-staff-view .bib-details ul {
+    margin-bottom: 0;
+    padding-left: 0;
+}
+
+.eg-bib-staff-view .bib-details li {
+    border: 0;
+    list-style: none;
+    padding: .25rem .25rem 0 0;
+}
diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-staff-view/bib-staff-view.component.html b/Open-ILS/src/eg2/src/app/staff/share/bib-staff-view/bib-staff-view.component.html
new file mode 100644 (file)
index 0000000..e69032d
--- /dev/null
@@ -0,0 +1,280 @@
+<div class='eg-bib-staff-view w-100' *ngIf="summary">
+    <div class="row"><!-- "table" -->
+
+        <!-- 1st column -->
+        <div class="col-md-4">
+
+            <!-- Col 1, Title Row -->
+            <div class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Title:</div>
+                <div class="col-sm-8 bib-details">
+                    <a *ngIf="summary.display.title" href="/eg2/staff/catalog/search?query={{summary.display.title}}&fieldClass=title&joinOp=&matchOp=contains&dateOp=is">
+                        {{summary.display.title}}
+                    </a>
+                </div>
+            </div><!-- end of Col 1, Title Row -->
+
+            <!-- Col 1, Series Title Row -->
+            <div *ngIf="summary.display.series_title" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Series Title:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _series of summary.display.series_title">
+                            <a href="/eg2/staff/catalog/search?query={{_series}}&fieldClass=series&joinOp=&matchOp=contains&dateOp=is">
+                                {{_series}}
+                            </a>
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end Col 1, Series Title Row-->
+
+            <!-- Col 1, Author Row -->
+            <div class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Author:</div>
+                <div class="col-sm-8 bib-details">
+                    <a *ngIf="summary.display.author" href="/eg2/staff/catalog/search?query={{summary.display.author}}&fieldClass=author&joinOp=&matchOp=contains&dateOp=is">
+                        {{summary.display.author}}
+                    </a>
+                </div>
+            </div><!-- end Col 1, Author Row -->
+
+            <!-- Col 1, Performer Row -->
+            <div *ngIf="summary.display.performers" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Performer:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _performer of summary.display.performers">
+                            {{_performer}}
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 1, Performer Row -->
+
+            <!-- Col 1, Edition Row -->
+            <div *ngIf="summary.display.edition" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Edition:</div>
+                <div class="col-sm-8 bib-details">
+                    {{summary.display.edition}}
+                </div>
+            </div><!-- end of Col 1, Edition Row -->
+
+            <!-- Col 1, Publisher Row -->
+            <div *ngIf="summary.display.publisher" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Publisher:</div>
+                <div class="col-sm-8 bib-details">
+                    {{summary.display.publisher}}
+                </div>
+            </div><!-- end of Col 1, Publisher Row -->
+
+            <!-- Col 1, Production Credit Row -->
+            <div *ngIf="summary.display.production_credits" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Production Credit:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _credit of summary.display.production_credits">
+                            {{_credit}}
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 1, Production Credit Row -->
+
+            <!-- Col 1, Type of Resource Row -->
+            <div *ngIf="summary.display.type_of_resource" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Type of Resource:</div>
+                <div class="col-sm-8 bib-details">
+                    {{summary.display.type_of_resource}}
+                </div>
+            </div><!-- end of Col 1, Type of Resource Row -->
+
+            <!-- Col 1, Physical Description Row -->
+            <div *ngIf="summary.display.physical_description" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Physical Description:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _desc of summary.display.physical_description">
+                            {{_desc}}
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 1, Physical Description Row -->
+
+            <!-- Col 1, ISBN Row -->
+            <div *ngIf="summary.display.isbn" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>ISBN:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _isbn of summary.display.isbn">
+                            <a href="/eg2/staff/catalog/search?identQuery={{_isbn}}&identQueryType=identifier%7Cisbn">
+                                {{_isbn}}
+                            </a>
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 1, ISBN Row -->
+
+            <!-- Col 1, ISSN Row -->
+            <div *ngIf="summary.display.issn" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>ISSN:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _issn of summary.display.issn">
+                            <a href="/eg2/staff/catalog/search?identQuery={{_issn}}&identQueryType=identifier%7Cissn">
+                                {{_issn}}
+                            </a>
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 1, ISSN Row -->
+
+            <!-- Col 1, UPC Row -->
+            <div *ngIf="summary.display.upc" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>UPC:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _upc of summary.display.upc">
+                            <a href="/eg2/staff/catalog/search?identQuery={{_upc}}&identQueryType=identifier%7Cupc">
+                                {{_upc}}
+                            </a>
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 1, UPC Row -->
+
+        </div><!-- 1st column -->
+
+        <!-- 2nd column -->
+        <div class="col-md-4">
+
+            <!-- Col 2, Abstract Row -->
+            <div *ngIf="summary.display.abstract" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Summary:</div>
+                <div class="col-sm-8 bib-details">
+                    {{summary.display.abstract}}
+                </div>
+            </div><!-- end of Col 2, Abstract Row -->
+
+            <!-- Col 2, General Note Row -->
+            <div *ngIf="summary.display.general_note" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>General Note:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _note of summary.display.general_note">
+                            {{_note}}
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 2, General Note Row -->
+
+            <!-- Col 2, Bibliography Row -->
+            <div *ngIf="summary.display.bibliography" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Bibliography:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _bibliography of summary.display.bibliography">
+                            {{_bibliography}}
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 2, Bibliography Row -->
+
+            <!-- Col 2, TOC Row -->
+            <div *ngIf="summary.display.toc" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Table of Contents:</div>
+                <div class="col-sm-8 bib-details">
+                    {{summary.display.toc}}
+                </div>
+            </div><!-- end of Col 2, TOC Row -->
+
+            <!-- Col 2, Thesis Row -->
+            <div *ngIf="summary.display.thesis" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Thesis:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _thesis of summary.display.thesis">
+                            {{_thesis}}
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 2, Thesis Row -->
+
+        </div><!-- 2nd column -->
+
+        <div class="col-md-4"><!-- 3rd column -->
+
+            <!-- Col 3, Hold and Copy Counts Row -->
+            <div class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Hold and Copy Counts:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li><span i18n>{{summary.holdCount}} hold requests</span></li>
+                        <li *ngFor="let _count of summary.holdingsSummary">
+                            <span i18n>{{_count.available}} of {{_count.count}} copies available at {{orgName(_count.org_unit)}}.</span>
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 3, Hold and Copy Counts Row -->
+
+
+            <!-- Col 3, Subject Row -->
+            <div *ngIf="summary.display.subject" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Subject:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _subj of summary.display.subject">
+                            <a href="/eg2/staff/catalog/search?query={{_subj}}&fieldClass=subject&joinOp=&matchOp=contains&dateOp=is">
+                                {{_subj}}
+                            </a>
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 3, Subject Row -->
+
+            <!-- Col 3, Genre Row -->
+            <div *ngIf="summary.display.genre" class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Genre:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <li *ngFor="let _genre of summary.display.genre">
+                            <a href="/eg2/staff/catalog/search?query={{'subject:identifier|genre[' + _genre + ']'}}">
+                                {{_genre}}
+                            </a>
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 3, Genre Row -->
+
+            <!-- Col 3, Formats and Editions Row -->
+            <div class="row">
+                <div class="col-sm-4 font-weight-bold bib-details-title" i18n>Formats and Editions:</div>
+                <div class="col-sm-8 bib-details">
+                    <ul>
+                        <ng-container *ngIf="summary.staffViewMetabibAttributes.icon_format">
+                            <li *ngFor="let _x of summary.staffViewMetabibAttributes.icon_format | keyvalue">
+                                <a href="/eg2/staff/catalog/search?query=from_metarecord({{summary.staffViewMetabibId}}) icon_format({{_x.key}})">
+                                    {{_x.value.label}}
+                                </a>
+                                    {{_x.value.count}}
+                            </li>
+                        </ng-container>
+                        <ng-container *ngIf="summary.staffViewMetabibAttributes.item_lang">
+                            <li *ngFor="let _x of summary.staffViewMetabibAttributes.item_lang | keyvalue">
+                                <a href="/eg2/staff/catalog/search?query=from_metarecord({{summary.staffViewMetabibId}}) item_lang({{_x.key}})">
+                                    {{_x.value.label}}
+                                </a>
+                                    {{_x.value.count}}
+                            </li>
+                        </ng-container>
+                        <li>
+                            <a href="/eg2/staff/catalog/search?query=from_metarecord({{summary.staffViewMetabibId}})">
+                                <span i18n>View all Formats and Editions</span>
+                            </a>
+                            <span> {{summary.staffViewMetabibRecords.length}}</span>
+                        </li>
+                    </ul>
+                </div>
+            </div><!-- end of Col 3, Formats and Editions Row -->
+
+        </div><!-- 3rd column -->
+
+    </div><!-- "table" -->
+</div>
diff --git a/Open-ILS/src/eg2/src/app/staff/share/bib-staff-view/bib-staff-view.component.ts b/Open-ILS/src/eg2/src/app/staff/share/bib-staff-view/bib-staff-view.component.ts
new file mode 100644 (file)
index 0000000..f3991ed
--- /dev/null
@@ -0,0 +1,95 @@
+import {Component, OnInit, Input} from '@angular/core';
+import {OrgService} from '@eg/core/org.service';
+import {BibRecordService, BibRecordSummary
+    } from '@eg/share/catalog/bib-record.service';
+import {ServerStoreService} from '@eg/core/server-store.service';
+import {CatalogService} from '@eg/share/catalog/catalog.service';
+import {StaffCatalogService} from '@eg/staff/catalog/catalog.service';
+
+@Component({
+  selector: 'eg-bib-staff-view',
+  templateUrl: 'bib-staff-view.component.html',
+  styleUrls: ['bib-staff-view.component.css']
+})
+export class BibStaffViewComponent implements OnInit {
+
+    recId: number;
+    initDone = false;
+
+    // True / false if the display is vertically expanded
+    private _exp: boolean;
+    set expand(e: boolean) {
+        this._exp = e;
+        if (this.initDone) {
+            this.saveExpandState();
+        }
+    }
+    get expand(): boolean { return this._exp; }
+
+    @Input() set recordId(id: number) {
+        this.recId = id;
+        // Only force new data collection when recordId()
+        // is invoked after ngInit() has already run.
+        if (this.initDone) {
+            this.loadSummary();
+        }
+    }
+
+    // Otherwise, we'll use the provided bib summary object.
+    summary: BibRecordSummary;
+    @Input() set bibSummary(s: any) {
+        this.summary = s;
+        if (this.initDone && this.summary) {
+            this.summary.getBibCallNumber();
+        }
+    }
+
+    constructor(
+        private bib: BibRecordService,
+        private org: OrgService,
+        private store: ServerStoreService,
+        private cat: CatalogService,
+        private staffCat: StaffCatalogService
+    ) {}
+
+    ngOnInit() {
+
+        this.store.getItem('eg.cat.record.staff-view.collapse')
+        .then(value => this.expand = !value)
+        .then(_ => this.cat.fetchCcvms())
+        .then(_ => {
+            if (this.recId) {
+                // ignore any existing this.summary, always refetch
+                return this.loadSummary();
+            }
+        }).then(_ => this.initDone = true);
+    }
+
+    saveExpandState() {
+        this.store.setItem('eg.cat.record.staff-view.collapse', !this.expand);
+    }
+
+    loadSummary(): Promise<any> {
+        return this.bib.getBibSummary(
+            this.recId,
+            this.staffCat.searchContext.searchOrg.id(),
+            true // isStaff
+        ).toPromise()
+        .then(summary => {
+            this.summary = summary;
+            return summary.getBibCallNumber();
+        });
+    }
+
+    orgName(orgId: number): string {
+        if (orgId) {
+            return this.org.get(orgId).shortname();
+        }
+    }
+
+    iconFormatLabel(code: string): string {
+        return this.cat.iconFormatLabel(code);
+    }
+}
+
+