initial mono parts UI for catalog
authorBill Erickson <berickxx@gmail.com>
Thu, 29 Nov 2018 22:54:20 +0000 (17:54 -0500)
committerBill Erickson <berickxx@gmail.com>
Fri, 30 Nov 2018 16:34:20 +0000 (11:34 -0500)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/catalog.module.ts
Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.html
Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.html
Open-ILS/src/eg2/src/app/staff/share/hold.service.ts

index 5f7a65a..d079f6a 100644 (file)
@@ -177,9 +177,12 @@ export class FmRecordEditorComponent
             });
         }
 
-        // create a new record from scratch
+        // create a new record from scratch or from a stub record
+        // provided by the caller.
         this.pkeyIsEditable = !('pkey_sequence' in this.idlDef);
-        this.record = this.idl.create(this.idlClass);
+        if (!this.record) {
+            this.record = this.idl.create(this.idlClass);
+        }
         return this.getFieldList();
     }
 
index 87cda49..3289e60 100644 (file)
@@ -17,6 +17,7 @@ import {HoldingsService} from '@eg/staff/share/holdings.service';
 import {BasketActionsComponent} from './basket-actions.component';
 import {HoldComponent} from './hold/hold.component';
 import {HoldService} from '@eg/staff/share/hold.service';
+import {PartsComponent} from './record/parts.component';
 
 @NgModule({
   declarations: [
@@ -31,7 +32,8 @@ import {HoldService} from '@eg/staff/share/hold.service';
     RecordPaginationComponent,
     RecordActionsComponent,
     BasketActionsComponent,
-    HoldComponent
+    HoldComponent,
+    PartsComponent
   ],
   imports: [
     StaffCommonModule,
index 7b6cae8..c4afcf5 100644 (file)
   <span class="font-italic" i18n>ANY</span>
 </ng-template>
 
+<!--
+    TODO: add a section per hold context for metarecord holds
+    listing the possible formats and languages.
+
+    TODO: add a secion per hold context for T holds providing a 
+    link to the metarecord hold equivalent (AKA "Advanced Hold 
+    Options") for each record that has selectable filters (and
+    only when metarecord holds are enabled).
+-->
+
 <div class="hold-records-list common-form striped-even">
 
   <div class="row mt-2 ml-1 mr-1 font-weight-bold">
index 5c59508..a8c9fcb 100644 (file)
@@ -287,6 +287,12 @@ export class HoldComponent implements OnInit {
     iconFormatLabel(code: string): string {
         return this.cat.iconFormatLabel(code);
     }
+
+    hasMetaFilters(ctx: HoldContext): boolean {
+        return ctx.holdMeta.metarecord_filters && (
+            ctx.holdMeta.metarecord_filters.langs.length > 1 ||
+            ctx.holdMeta.metarecord_filters.formats.length > 1); 
+    }
 }
 
 
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.html
new file mode 100644 (file)
index 0000000..caa28b9
--- /dev/null
@@ -0,0 +1,20 @@
+
+<div class="mt-3">
+
+  <eg-grid #partsGrid idlClass="bmp" [dataSource]="gridDataSource"
+      [sortable]="true" persistKey="catalog.record.parts"
+      showFields="id,label" class="mt-3">
+    <eg-grid-toolbar-button [disabled]="!permissions.CREATE_MONOGRAPH_PART"
+      label="New Monograph Part" i18n-label [action]="createNew">
+    </eg-grid-toolbar-button>
+    <eg-grid-toolbar-action label="Merge Selected" i18n-label [action]="mergeSelected">
+    </eg-grid-toolbar-action>
+    <eg-grid-toolbar-action label="Delete Selected" i18n-label [action]="deleteSelected">
+    </eg-grid-toolbar-action>
+  </eg-grid>
+  
+  <eg-fm-record-editor #editDialog idlClass="bmp"     
+    hiddenFields="record,label_sortkey,deleted">
+  </eg-fm-record-editor>
+
+</div>
diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/record/parts.component.ts
new file mode 100644 (file)
index 0000000..4df2c37
--- /dev/null
@@ -0,0 +1,118 @@
+import {Component, OnInit, Input, ViewChild} from '@angular/core';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {Pager} from '@eg/share/util/pager';
+import {OrgService} from '@eg/core/org.service';
+import {PermService} from '@eg/core/perm.service';
+import {GridDataSource} from '@eg/share/grid/grid';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
+
+@Component({
+  selector: 'eg-catalog-record-parts',
+  templateUrl: 'parts.component.html'
+})
+export class PartsComponent implements OnInit {
+
+    recId: number;
+    gridDataSource: GridDataSource;
+    initDone: boolean;
+    @ViewChild('partsGrid') partsGrid: GridComponent;
+    @ViewChild('editDialog') editDialog: FmRecordEditorComponent;
+
+    canCreate: boolean;
+    canDelete: boolean;
+    createNew: () => void;
+    deleteSelected: (rows: IdlObject[]) => void;
+    mergeSelected: (rows: IdlObject[]) => void;
+    permissions: {[name: string]: boolean};
+
+    @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.partsGrid.reload();
+        }
+    }
+
+    constructor(
+        private idl: IdlService,
+        private org: OrgService,
+        private pcrud: PcrudService,
+        private perm: PermService
+    ) {
+        this.permissions = {};
+        this.gridDataSource = new GridDataSource();
+    }
+
+    ngOnInit() {
+        this.initDone = true;
+
+        // Load edit perms
+        this.perm.hasWorkPermHere([
+            'CREATE_MONOGRAPH_PART',
+            'UPDATE_MONOGRAPH_PART',
+            'DELETE_MONOGRAPH_PART'
+        ]).then(perms => this.permissions = perms);
+
+        this.gridDataSource.getRows = (pager: Pager, sort: any[]) => {
+            const orderBy: any = {};
+
+            if (sort.length) { // Sort provided by grid.
+                orderBy.bmp = sort[0].name + ' ' + sort[0].dir;
+            } else {
+                orderBy.bmp = 'label';
+            }
+
+            const searchOps = {
+                offset: pager.offset,
+                limit: pager.limit,
+                order_by: orderBy
+            };
+
+            return this.pcrud.search('bmp', 
+                {record: this.recId, deleted: 'f'}, searchOps);
+        };
+
+        this.partsGrid.onRowActivate.subscribe(
+            (part: IdlObject) => {
+                this.editDialog.mode = 'update';
+                this.editDialog.recId = part.id();
+                this.editDialog.open().then(
+                    ok => this.partsGrid.reload(),
+                    err => {}
+                );
+            }
+        );
+
+        this.createNew = () => {
+
+            const part = this.idl.create('bmp');
+            part.record(this.recId);
+            this.editDialog.record = part;
+
+            this.editDialog.mode = 'create';
+            this.editDialog.open().then(
+                ok => this.partsGrid.reload(),
+                err => {}
+            );
+        };
+
+        this.deleteSelected = (parts: IdlObject[]) => {
+            parts.forEach(part => part.isdeleted(true));
+            this.pcrud.autoApply(parts).subscribe(
+                val => console.debug('deleted: ' + val),
+                err => {},
+                ()  => this.partsGrid.reload()
+            );
+        };
+
+        this.mergeSelected = (parts: IdlObject[]) => this.mergeParts(parts);
+    }
+
+    mergeParts(parts: IdlObject[]) {
+        console.log('merging parts for rec', parts, this.recId);
+    }
+}
+
index cefd1ff..96c733e 100644 (file)
       </ngb-tab>
       <ngb-tab title="View Holds" i18n-title id="holds">
       </ngb-tab>
+      <ngb-tab title="Monograph Parts" i18n-title id="parts">
+        <ng-template ngbTabContent>
+          <eg-catalog-record-parts [recordId]="recordId">
+          </eg-catalog-record-parts>
+        </ng-template>
+      </ngb-tab>
     </ngb-tabset>
   </div>
 </div>
index 7f4b216..0bbfd63 100644 (file)
@@ -42,7 +42,8 @@ export interface HoldRequest {
 // available for each hold type / target.  E.g. a TITLE hold will
 // not have a value for 'volume', but a COPY hold will, since all
 // copies have volumes.  Every HoldRequestTarget will have a bibId and
-// bibSummary.
+// bibSummary.  Some values come directly from the API call, others
+// applied locally.
 export interface HoldRequestTarget {
     target: number;
     metarecord?: IdlObject;
@@ -130,6 +131,7 @@ export class HoldService {
         ).pipe(mergeMap(meta => {
             const target: HoldRequestTarget = meta;
             target.bibId = target.bibrecord.id();
+
             return this.bib.getBibSummary(target.bibId)
             .pipe(map(sum => {
                 target.bibSummary = sum;