LP1849212: Improvements to the Simplified Marc Editor
authorJane Sandberg <sandbej@linnbenton.edu>
Wed, 26 Aug 2020 22:51:32 +0000 (15:51 -0700)
committerGalen Charlton <gmc@equinoxinitiative.org>
Mon, 14 Sep 2020 22:17:31 +0000 (18:17 -0400)
* Templates can now set multiple subfields for the same field
* Templates can now set indicator values
* Editor now allows user to choose a MARC Form and Type
* Improvements to the course associate brief record interface
to use these improvements

Signed-off-by: Jane Sandberg <sandbej@linnbenton.edu>
Signed-off-by: Michele Morgan <mmorgan@noblenet.org>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>

Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.html
Open-ILS/src/eg2/src/app/staff/share/course.service.ts
Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor-field.component.ts [deleted file]
Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor-field.directive.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor-subfield.directive.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor.component.html
Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor.component.ts
Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor.module.ts

index 73e5bdd..9d94b30 100644 (file)
                     placeholder="e.g. Required" class="flex-grow-1" />
                 </div>
               </div>
-              <eg-marc-simplified-editor (xmlRecordEvent)="associateBriefRecord($event)" buttonLabel="Add material" i18n-buttonLabel>
-                <eg-marc-simplified-editor-field tag="245" subfield="a"></eg-marc-simplified-editor-field>
-                <eg-marc-simplified-editor-field tag="856" subfield="u"></eg-marc-simplified-editor-field>
-                <eg-marc-simplified-editor-field tag="856" subfield="9" defaultValue="CONS"></eg-marc-simplified-editor-field>
-                <eg-marc-simplified-editor-field tag="990" subfield="a" i18n-defaultValue
-                  defaultValue="This record was created using the Course Materials Module -- please edit it there">
-                  </eg-marc-simplified-editor-field>
+              <eg-marc-simplified-editor (xmlRecordEvent)="associateBriefRecord($event)"
+              buttonLabel="Add material" i18n-buttonLabel defaultMarcForm="o">
+                <eg-marc-simplified-editor-field tag="245" ind1="0" ind2="0">
+                  <eg-marc-simplified-editor-subfield code="a"></eg-marc-simplified-editor-subfield>
+                </eg-marc-simplified-editor-field>
+                <eg-marc-simplified-editor-field tag="856" ind1="4" ind2="0">
+                  <eg-marc-simplified-editor-subfield code="u"></eg-marc-simplified-editor-subfield>
+                  <eg-marc-simplified-editor-subfield code="y"></eg-marc-simplified-editor-subfield>
+                  <eg-marc-simplified-editor-subfield code="9" [defaultValue]="currentCourse.owning_lib().shortname()"></eg-marc-simplified-editor-subfield>
+                </eg-marc-simplified-editor-field>
+                <eg-marc-simplified-editor-field tag="990">
+                  <eg-marc-simplified-editor-subfield code="a" i18n-defaultValue
+                    defaultValue="This record was created using the Course Materials Module -- please edit it there">
+                  </eg-marc-simplified-editor-subfield>
+                </eg-marc-simplified-editor-field>
               </eg-marc-simplified-editor>
             </ng-template>
           </li>
       </div>
 
       <div class="mt-3" [ngClass]="isDialog() ? 'col-md-12' : 'col-md-8'">
-        <eg-grid #materialsGrid [dataSource]="materialsDataSource" [useLocalSort]="true">
+        <eg-grid #materialsGrid [dataSource]="materialsDataSource" [useLocalSort]="true" [disablePaging]="true">
           <eg-grid-toolbar-action label="Remove Selected" i18n-label (onClick)="deleteSelectedMaterials($event)">
           </eg-grid-toolbar-action>
           <eg-grid-toolbar-action label="Edit Selected" i18n-label (onClick)="editSelectedMaterials($event)">
index bc7f707..7443a79 100644 (file)
@@ -30,10 +30,12 @@ export class CourseService {
     getCourses(course_ids?: Number[]): Promise<IdlObject[]> {
         if (!course_ids) {
             return this.pcrud.retrieveAll('acmc',
-                {}, {atomic: true}).toPromise();
+                {flesh: 1, flesh_fields: {'acmc': ['owning_lib']}},
+                {atomic: true}).toPromise();
         } else {
             return this.pcrud.search('acmc', {id: course_ids},
-                {}, {atomic: true}).toPromise();
+                {flesh: 1, flesh_fields: {'acmc': ['owning_lib']}},
+                {atomic: true}).toPromise();
         }
     }
 
diff --git a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor-field.component.ts b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor-field.component.ts
deleted file mode 100644 (file)
index bfed188..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-import {Component, Host, Input, OnInit} from '@angular/core';
-import {MarcSimplifiedEditorComponent} from './simplified-editor.component';
-import {MarcSubfield} from '../marcrecord';
-
-/**
- * A field that a user can edit, which will later be
- * compiled into MARC
- */
-
-@Component({
-  selector: 'eg-marc-simplified-editor-field',
-  template: '<ng-template></ng-template>'
-})
-export class MarcSimplifiedEditorFieldComponent implements OnInit {
-
-  @Input() tag: string;
-  @Input() subfield: string;
-  @Input() defaultValue: string;
-
-  constructor(@Host() private editor: MarcSimplifiedEditorComponent) {}
-
-  ngOnInit() {
-      this.editor.addField({
-          tag: this.tag,
-          subfields: [[
-              this.subfield,
-              this.defaultValue ? this.defaultValue : '',
-              0
-          ]],
-          authValid: false,
-          authChecked: false,
-          isCtrlField: false,
-          isControlfield: () => false,
-          indicator: (ind: number) => '0',
-          deleteExactSubfields: (...subfield: MarcSubfield[]) => 0,
-      });
-  }
-
-}
-
-
-
diff --git a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor-field.directive.ts b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor-field.directive.ts
new file mode 100644 (file)
index 0000000..a5e7e0a
--- /dev/null
@@ -0,0 +1,60 @@
+import {Directive, Host, Input, OnInit, AfterViewInit} from '@angular/core';
+import {MarcSimplifiedEditorComponent} from './simplified-editor.component';
+import {MarcField, MarcSubfield} from '../marcrecord';
+import {MarcSimplifiedEditorSubfieldDirective} from './simplified-editor-subfield.directive';
+
+/**
+ * A field that a user can edit, which will later be
+ * compiled into MARC
+ */
+
+@Directive({
+  selector: 'eg-marc-simplified-editor-field',
+})
+export class MarcSimplifiedEditorFieldDirective implements OnInit, AfterViewInit {
+
+  @Input() tag = 'a';
+  @Input() ind1 = ' ';
+  @Input() ind2 = ' ';
+
+  subfieldIndex = 1;
+
+  marcVersion: MarcField;
+
+  addSubfield: (code: string, defaultValue?: string) => void;
+
+  constructor(@Host() private editor: MarcSimplifiedEditorComponent) {}
+
+  ngOnInit() {
+    this.marcVersion = {
+      tag: this.tag,
+      subfields: [],
+      authValid: false,
+      authChecked: false,
+      isCtrlField: false,
+      isControlfield: () => false,
+      indicator: (ind: number) => (ind === 1) ? this.ind1 : this.ind2,
+      deleteExactSubfields: (...subfield: MarcSubfield[]) => 0, // not used by the simplified editor
+    };
+
+    this.addSubfield = (code: string, defaultValue?: string) => {
+      this.marcVersion.subfields.push(
+        [
+          code,
+          defaultValue ? defaultValue : '',
+          this.subfieldIndex
+        ]
+      );
+      this.subfieldIndex += 1;
+
+    }
+  }
+
+  ngAfterViewInit() {
+    this.editor.addField(this.marcVersion);
+  }
+
+}
+
+
+
diff --git a/Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor-subfield.directive.ts b/Open-ILS/src/eg2/src/app/staff/share/marc-edit/simplified-editor/simplified-editor-subfield.directive.ts
new file mode 100644 (file)
index 0000000..d9474a8
--- /dev/null
@@ -0,0 +1,23 @@
+import {Directive, Input, Host, OnInit} from '@angular/core';
+import {MarcSimplifiedEditorFieldDirective} from './simplified-editor-field.directive';
+
+/**
+ * A subfield that a user can edit, which will later be
+ * compiled into MARC
+ */
+
+@Directive({
+  selector: 'eg-marc-simplified-editor-subfield',
+})
+export class MarcSimplifiedEditorSubfieldDirective implements OnInit {
+
+  @Input() code: string;
+  @Input() defaultValue: string;
+
+  constructor(@Host() private field: MarcSimplifiedEditorFieldDirective) {}
+
+  ngOnInit() {
+    this.field.addSubfield(this.code, this.defaultValue);
+  }
+
+}
index a82dbf3..50ce7b6 100644 (file)
@@ -1,15 +1,31 @@
-<ng-container *ngIf="editor">
+<ng-container *ngIf="editor && subfieldLabels && marcForms && marcTypes">
   <form [formGroup]="editor">
+    <div class="row">
+      <div class="col-lg-3" i18n>Form</div>
+      <div class="col-lg-9">
+        <eg-combobox #formCombobox [entries]="marcForms" formControlName="marcForm">
+          <eg-combobox-entry entryId=" " entryLabel="Default" [selected]="true"></eg-combobox-entry>
+        </eg-combobox>
+      </div>
+    </div>
+    <div class="row">
+      <div class="col-lg-3" i18n>Type</div>
+      <div class="col-lg-9">
+        <eg-combobox #typeCombobox [entries]="marcTypes" formControlName="marcType"></eg-combobox>
+      </div>
+    </div>   
     <ng-container *ngFor="let field of fields">
-      <div class="row" *ngIf="!field.subfields[0][1]">
-        <div class="col-lg-3">
-          <label for="{{idPrefix}}-{{field.tag}}{{field.subfields[0]}}">
-            {{fieldLabels[field.fieldId]}}
-          </label>
-        </div>
-        <div class="col-lg-9">
-          <input id="{{idPrefix}}-{{field.tag}}{{field.subfields[0]}}" formControlName="{{field.fieldId}}" />
-        </div>
+      <div class="row" *ngFor="let subfield of field.subfields">
+        <ng-container *ngIf="!subfield[1]">
+          <div class="col-lg-3">
+            <label for="{{idPrefix}}-{{editorFieldIdentifier(field, subfield)}}">
+              {{subfieldLabels[editorFieldIdentifier(field, subfield)]}}
+            </label>
+          </div>
+          <div class="col-lg-9">
+            <input id="{{idPrefix}}-{{editorFieldIdentifier(field, subfield)}}" formControlName="{{editorFieldIdentifier(field, subfield)}}" />
+          </div>
+        </ng-container>
       </div>
     </ng-container>
     <button class="btn btn-primary" (click)="emitXml()">
index 80f900a..77405cc 100644 (file)
@@ -1,7 +1,13 @@
 import {AfterViewInit, Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
-import {FormGroup, FormControl, ValidationErrors, ValidatorFn, FormArray} from '@angular/forms';
+import {FormGroup, FormControl} from '@angular/forms';
 import {MarcField, MarcRecord} from '../marcrecord';
 import {TagTableService} from '../tagtable.service';
+import {NetService} from '@eg/core/net.service';
+import { ComboboxEntry } from '@eg/share/combobox/combobox.component';
+import { Observable, of } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
+
+const DEFAULT_RECORD_TYPE = 'BKS';
 
 /**
  * A simplified editor for basic MARC records, which
@@ -16,41 +22,76 @@ export class MarcSimplifiedEditorComponent implements AfterViewInit, OnInit {
 
     @Input() buttonLabel: string;
     @Output() xmlRecordEvent = new EventEmitter<string>();
+    @Input() defaultMarcForm: string;
 
     fields: MarcField[] = [];
     editor: FormGroup;
+    marcForms: ComboboxEntry[];
+    marcTypes: ComboboxEntry[];
 
     // DOM id prefix to prevent id collisions.
     idPrefix: string;
 
     fieldIndex = 0;
-    fieldLabels: string[] = [];
+    subfieldLabels = {};
 
     addField: (field: MarcField) => void;
 
+    editorFieldIdentifier: (field: MarcField, subfield: Array<any>) => string;
+
     constructor(
+        private net: NetService,
         private tagTable: TagTableService
     ) {}
 
     ngOnInit() {
         // Add some randomness to the generated DOM IDs to ensure against clobbering
         this.idPrefix = 'marc-simplified-editor-' + Math.floor(Math.random() * 100000);
-        this.editor = new FormGroup({});
+        this.editor = new FormGroup({
+            marcForm: new FormControl(),
+            marcType: new FormControl()
+        });
 
         // Add a fieldId, and then add a new field to the array
         this.addField = (field: MarcField) => {
             field.fieldId = this.fieldIndex;
             this.fields.push(field);
-            this.editor.addControl(String(this.fieldIndex), new FormControl(null, []));
+            field.subfields.forEach((subfield) => {
+                this.editor.addControl(this.editorFieldIdentifier(field, subfield), new FormControl(null, []));               
+            })
             this.fieldIndex++;
         };
 
+        this.editorFieldIdentifier = (field: MarcField, subfield: Array<any>) => {
+            return field.tag + subfield[0]; // e.g. 245a
+        }
+
+        this.net.request('open-ils.cat',
+            'open-ils.cat.biblio.fixed_field_values.by_rec_type',
+            DEFAULT_RECORD_TYPE, 'Form')
+            .subscribe((forms) => {
+                this.marcForms = forms['Form'].map((form) => {
+                    return {id: form[0], label: form[1]}
+                })
+            });
+
+        this.net.request('open-ils.cat',
+            'open-ils.cat.biblio.fixed_field_values.by_rec_type',
+            DEFAULT_RECORD_TYPE, 'Type')
+            .subscribe((types) => {
+                this.marcTypes = types['Type'].map((type) => {
+                    return {id: type[0], label: type[1]}
+                })
+            });
+
     }
 
     ngAfterViewInit() {
-        this.tagTable.loadTags({marcRecordType: 'biblio', ffType: 'BKS'}).then(table => {
+        this.tagTable.loadTags({marcRecordType: 'biblio', ffType: DEFAULT_RECORD_TYPE}).then(table => {
             this.fields.forEach((field) => {
-                this.fieldLabels[field.fieldId] = table.getSubfieldLabel(field.tag, field.subfields[0][0]);
+                field.subfields.forEach((subfield) => {
+                    this.subfieldLabels[this.editorFieldIdentifier(field, subfield)] = table.getSubfieldLabel(field.tag, subfield[0]);
+                })
             });
         });
     }
@@ -59,14 +100,35 @@ export class MarcSimplifiedEditorComponent implements AfterViewInit, OnInit {
         const record = new MarcRecord('<record xmlns="http://www.loc.gov/MARC21/slim"></record>');
         // need to add the value to field.subfields[0][1]
         this.fields.forEach((field) => {
-            if (field.subfields[0][1] === '') { // Default value has not been applied
-                field.subfields[0][1] = this.editor.get(String(field.fieldId)).value;
-            }
+            field.subfields.forEach((subfield) => {
+                if (subfield[1] === '') { // Default value has not been applied
+                    subfield[1] = this.editor.get(this.editorFieldIdentifier(field, subfield)).value;
+                }  
+            })
         });
         record.fields = this.fields;
+
+        // We need to generate an accurate 008 before setting the Form fixed field
+        const field008 = record.newField({tag: '008', data: record.generate008()});
+        record.insertOrderedFields(field008);
+
+        record.setFixedField('Type', this.appropriateMarcType);
+        record.setFixedField('Form', this.appropriateMarcForm);
         this.xmlRecordEvent.emit(record.toXml());
     }
 
+    get appropriateMarcType(): string {
+        return this.editor.get('marcType').value ? this.editor.get('marcType').value.id : 'a';
+    }
+
+    get appropriateMarcForm(): string {
+        if (this.editor.get('marcForm').value) {
+            return this.editor.get('marcForm').value.id;
+        }
+        return this.defaultMarcForm ? this.defaultMarcForm : ' ';
+    }
+
+
 }
 
 
index ec40da9..e17ad0e 100644 (file)
@@ -2,13 +2,15 @@ import {NgModule} from '@angular/core';
 import {StaffCommonModule} from '@eg/staff/common.module';
 import {CommonWidgetsModule} from '@eg/share/common-widgets.module';
 import {MarcSimplifiedEditorComponent} from './simplified-editor.component';
-import {MarcSimplifiedEditorFieldComponent} from './simplified-editor-field.component';
+import {MarcSimplifiedEditorFieldDirective} from './simplified-editor-field.directive';
+import {MarcSimplifiedEditorSubfieldDirective} from './simplified-editor-subfield.directive';
 import {TagTableService} from '../tagtable.service';
 
 @NgModule({
     declarations: [
         MarcSimplifiedEditorComponent,
-        MarcSimplifiedEditorFieldComponent,
+        MarcSimplifiedEditorFieldDirective,
+        MarcSimplifiedEditorSubfieldDirective,
     ],
     imports: [
         StaffCommonModule,
@@ -16,7 +18,8 @@ import {TagTableService} from '../tagtable.service';
     ],
     exports: [
         MarcSimplifiedEditorComponent,
-        MarcSimplifiedEditorFieldComponent,
+        MarcSimplifiedEditorFieldDirective,
+        MarcSimplifiedEditorSubfieldDirective
     ],
     providers: [
         TagTableService