LP1852782 Linker links to auth record editor
authorBill Erickson <berickxx@gmail.com>
Wed, 8 Jan 2020 21:49:35 +0000 (16:49 -0500)
committerBill Erickson <berickxx@gmail.com>
Fri, 21 Feb 2020 16:44:38 +0000 (11:44 -0500)
Adds a new UI at /staff/cat/authority/edit/ for finding authority
records by ID and editing authority records via the Angular MARC editor.

Modifies the "Cataloging" => "Retrieve Authority Record By ID" nav menu
entry to point to the Angular version of the interface.

Augments the MARC edit authority linking dialog to turn authority ID's
into links which open the authority record in its own MARC editor in a
new tab.

Misc. MARC editor repairs related to loading authority records by ID.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jane Sandberg <sandbej@linnbenton.edu>
13 files changed:
Open-ILS/src/eg2/src/app/common.module.ts
Open-ILS/src/eg2/src/app/share/catalog/catalog-common.module.ts
Open-ILS/src/eg2/src/app/staff/cat/authority/authority.module.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/cat/authority/marc-edit.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/cat/authority/marc-edit.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/cat/authority/routing.module.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/cat/routing.module.ts
Open-ILS/src/eg2/src/app/staff/nav.component.html
Open-ILS/src/eg2/src/app/staff/share/marc-edit/authority-linking-dialog.component.html
Open-ILS/src/eg2/src/app/staff/share/marc-edit/editor.component.html
Open-ILS/src/eg2/src/app/staff/share/marc-edit/editor.component.ts
Open-ILS/src/eg2/src/app/staff/share/marc-edit/rich-editor.component.html
Open-ILS/src/templates/staff/navbar.tt2

index 56eddab..5250670 100644 (file)
@@ -13,9 +13,9 @@ Note core services are injected into 'root'.
 They do not have to be added to the providers list.
 */
 
-// consider moving these to core...
 import {HtmlToTxtService} from '@eg/share/util/htmltotxt.service';
 import {PrintService} from '@eg/share/print/print.service';
+import {AnonCacheService} from '@eg/share/util/anon-cache.service';
 
 // Globally available components
 import {PrintComponent} from '@eg/share/print/print.component';
@@ -79,6 +79,7 @@ export class EgCommonModule {
         return {
             ngModule: EgCommonModule,
             providers: [
+                AnonCacheService,
                 HtmlToTxtService,
                 PrintService,
                 ToastService
index 5b45d00..f9e628e 100644 (file)
@@ -1,7 +1,6 @@
 import {NgModule} from '@angular/core';
 import {EgCommonModule} from '@eg/common.module';
 import {CatalogService} from './catalog.service';
-import {AnonCacheService} from '@eg/share/util/anon-cache.service';
 import {BasketService} from './basket.service';
 import {CatalogUrlService} from './catalog-url.service';
 import {BibRecordService} from './bib-record.service';
@@ -20,12 +19,11 @@ import {MarcHtmlComponent} from './marc-html.component';
         MarcHtmlComponent
     ],
     providers: [
-        AnonCacheService,
         CatalogService,
         CatalogUrlService,
         UnapiService,
         BibRecordService,
-        BasketService,
+        BasketService
     ]
 })
 
diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/authority.module.ts b/Open-ILS/src/eg2/src/app/staff/cat/authority/authority.module.ts
new file mode 100644 (file)
index 0000000..ded954a
--- /dev/null
@@ -0,0 +1,23 @@
+import {NgModule} from '@angular/core';
+import {StaffCommonModule} from '@eg/staff/common.module';
+import {CommonWidgetsModule} from '@eg/share/common-widgets.module';
+import {AuthorityRoutingModule} from './routing.module';
+import {MarcEditModule} from '@eg/staff/share/marc-edit/marc-edit.module';
+import {AuthorityMarcEditComponent} from './marc-edit.component';
+
+@NgModule({
+  declarations: [
+    AuthorityMarcEditComponent
+  ],
+  imports: [
+    StaffCommonModule,
+    CommonWidgetsModule,
+    MarcEditModule,
+    AuthorityRoutingModule
+  ],
+  providers: [
+  ]
+})
+
+export class AuthorityModule {
+}
diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/marc-edit.component.html b/Open-ILS/src/eg2/src/app/staff/cat/authority/marc-edit.component.html
new file mode 100644 (file)
index 0000000..e563e3a
--- /dev/null
@@ -0,0 +1,32 @@
+
+<ng-container *ngIf="!authorityId">
+  <!-- If we don't have an authority ID, prompt the user to enter one -->
+  <eg-staff-banner bannerText="Find Authority Record By ID" i18n-bannerText>
+  </eg-staff-banner>
+
+  <div class="row">
+    <div class="col-lg-6 form-inline">
+      <div class="input-group">
+        <div class="input-group-prepend">
+          <span class="input-group-text" i18n>Authorty Record Id</span>
+        </div>
+        <input type="text" class="form-control" 
+          id='auth-id-input'
+          i18n-placeholder placeholder="Authorty Record Id" 
+          i18n-aria-label aria-label="Authorty Record Id"
+          (keyup.enter)="goToAuthority()" [(ngModel)]="loadId"/>
+        <button class="btn btn-success" (click)="goToAuthority()" i18n>Submit</button>
+      </div>
+    </div>
+  </div>
+</ng-container>
+
+<ng-container *ngIf="authorityId">
+  <eg-staff-banner bannerText="Edit Authority Record #{{authorityId}}" i18n-bannerText>
+  </eg-staff-banner>
+
+  <eg-marc-editor #marcEditor recordType="authority" [recordId]="authorityId">
+  </eg-marc-editor>
+</ng-container>
+
+
diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/marc-edit.component.ts b/Open-ILS/src/eg2/src/app/staff/cat/authority/marc-edit.component.ts
new file mode 100644 (file)
index 0000000..88f2cd0
--- /dev/null
@@ -0,0 +1,35 @@
+import {Component, OnInit, AfterViewInit, ViewChild, Renderer2} from '@angular/core';
+import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {MarcSavedEvent} from '@eg/staff/share/marc-edit/editor.component';
+
+@Component({
+  templateUrl: 'marc-edit.component.html'
+})
+export class AuthorityMarcEditComponent implements AfterViewInit {
+
+    authorityId: number;
+
+    // Avoid setting authorityId during lookup because it can
+    // cause the marc editor to load prematurely.
+    loadId: number;
+
+    constructor(
+        private router: Router,
+        private route: ActivatedRoute,
+        private renderer: Renderer2) {
+        this.authorityId = +this.route.snapshot.paramMap.get('id');
+    }
+
+    ngAfterViewInit() {
+        if (!this.authorityId) {
+            this.renderer.selectRootElement('#auth-id-input').focus();
+        }
+    }
+
+    goToAuthority() {
+        if (this.loadId) {
+            this.router.navigate([`/staff/cat/authority/edit/${this.loadId}`]);
+        }
+    }
+}
+
diff --git a/Open-ILS/src/eg2/src/app/staff/cat/authority/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/cat/authority/routing.module.ts
new file mode 100644 (file)
index 0000000..cd6b3a1
--- /dev/null
@@ -0,0 +1,20 @@
+import {NgModule} from '@angular/core';
+import {RouterModule, Routes} from '@angular/router';
+import {AuthorityMarcEditComponent} from './marc-edit.component';
+
+const routes: Routes = [{
+    path: 'edit',
+    component: AuthorityMarcEditComponent
+  }, {
+    path: 'edit/:id',
+    component: AuthorityMarcEditComponent
+}];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+  providers: []
+})
+
+export class AuthorityRoutingModule {}
+
index a923b46..67fb59b 100644 (file)
@@ -4,6 +4,9 @@ import {RouterModule, Routes} from '@angular/router';
 const routes: Routes = [
   { path: 'vandelay',
     loadChildren: '@eg/staff/cat/vandelay/vandelay.module#VandelayModule'
+  }, {
+    path: 'authority',
+    loadChildren: '@eg/staff/cat/authority/authority.module#AuthorityModule'
   }
 ];
 
index 265368a..5310b5b 100644 (file)
             <span class="material-icons">lock</span>
             <span i18n>Manage Authorities</span>
           </a>
-          <a href="/eg/staff/cat/catalog/retrieve_by_authority_id" class="dropdown-item">
+          <a routerLink="/staff/cat/authority/edit" class="dropdown-item">
             <span class="material-icons">collections</span>
             <span i18n>Retrieve Authority Record by ID</span>
           </a>
index 2c8c3fc..03d1eb5 100644 (file)
       </div>
     </div>
     <ul *ngFor="let entry of browseData">
-      <li class="d-flex">
+      <li class="d-flex mt-1">
         <div class="flex-1">
           <ng-container
             *ngTemplateOutlet="headingField;context:{field:entry.main_heading, authId: entry.authority_id}">
           </ng-container>
         </div>
-        <div class="font-italic" i18n-title i18n
-          title="Authority Record ID {{entry.authority_id}}">
-          #{{entry.authority_id}}
+        <div class="font-italic">
+          <a target="_blank" 
+            i18n-title title="Authority Record ID {{entry.authority_id}}"
+            routerLink="/staff/cat/authority/edit/{{entry.authority_id}}">
+            #{{entry.authority_id}}
+          </a>
         </div>
       </li>
       <ul *ngFor="let from of entry.see_froms">
-        <li i18n>
+        <li class="mt-1">
          <ng-container
           *ngTemplateOutlet="headingField;context:{field:from, from:true}">
          </ng-container>
         </li>
       </ul>
       <ul *ngFor="let also of entry.see_alsos">
-        <li i18n>
+        <li class="mt-1">
          <ng-container
           *ngTemplateOutlet="headingField;context:{field:also, also:true}">
          </ng-container>
index 77d4f00..e3daf90 100644 (file)
 
 <div class="row d-flex p-2 m-2">
 
-  <div class="form-check">
-    <input class="form-check-input" type="checkbox"
-      [(ngModel)]="showFastAdd" id="fast-add-item"/>
-    <label class="form-check-label" for="fast-add-item">
-      Add Item
-    </label>
-  </div>
+  <ng-container *ngIf="recordType === 'biblio'">
+    <div class="form-check">
+      <input class="form-check-input" type="checkbox"
+        [(ngModel)]="showFastAdd" id="fast-add-item"/>
+      <label class="form-check-label" for="fast-add-item">
+        Add Item
+      </label>
+    </div>
+  </ng-container>
 
   <ng-container *ngIf="showFastAdd">
     <div class="form-inline">
@@ -65,7 +67,6 @@
     [disabled]="record && record.deleted" i18n>Save Changes</button>
 </div>
 
-
 <ng-container *ngIf="dataSaving">
   <div class="row mt-5">
     <div class="offset-lg-3 col-lg-6">
index 7c0a224..157ff0a 100644 (file)
@@ -16,7 +16,7 @@ import {MarcEditContext} from './editor-context';
 import {NgbTabset, NgbTabChangeEvent} from '@ng-bootstrap/ng-bootstrap';
 import {HoldingsService} from '@eg/staff/share/holdings/holdings.service';
 
-interface MarcSavedEvent {
+export interface MarcSavedEvent {
     marcXml: string;
     bibSource?: number;
     recordId?: number;
@@ -42,14 +42,24 @@ export class MarcEditorComponent implements OnInit {
 
     @Input() recordType: 'biblio' | 'authority' = 'biblio';
 
+    _pendingRecordId: number;
     @Input() set recordId(id: number) {
-        if (!id) { return; }
         if (this.record && this.record.id === id) { return; }
-        this.fromId(id);
+
+        // Avoid fetching the record by ID before OnInit since we may
+        // not yet know our recordType.
+        if (this.initCalled) {
+            this._pendingRecordId = null;
+            this.fromId(id);
+
+         } else {
+            // fetch later in OnInit
+            this._pendingRecordId = id;
+         }
     }
 
     get recordId(): number {
-        return this.record ? this.record.id : null;
+        return this.record ? this.record.id : this._pendingRecordId;
     }
 
     @Input() set recordXml(xml: string) {
@@ -86,6 +96,7 @@ export class MarcEditorComponent implements OnInit {
     fastItemLabel: string;
     fastItemBarcode: string;
     showFastAdd: boolean;
+    initCalled = false;
 
     constructor(
         private evt: EventService,
@@ -107,11 +118,17 @@ export class MarcEditorComponent implements OnInit {
 
     ngOnInit() {
 
+        this.initCalled = true;
+
         this.context.recordType = this.recordType;
 
         this.store.getItem('cat.marcedit.flateditor').then(
             useFlat => this.editorTab = useFlat ? 'flat' : 'rich');
 
+        if (!this.record && this.recordId) {
+            this.fromId(this.recordId);
+        }
+
         if (this.recordType !== 'biblio') { return; }
 
         this.pcrud.retrieveAll('cbs').subscribe(
@@ -247,13 +264,15 @@ export class MarcEditorComponent implements OnInit {
     }
 
     fromId(id: number): Promise<any> {
-        return this.pcrud.retrieve('bre', id)
-        .toPromise().then(bib => {
-            this.context.record = new MarcRecord(bib.marc());
+        const idlClass = this.recordType === 'authority' ? 'are' : 'bre';
+
+        return this.pcrud.retrieve(idlClass, id)
+        .toPromise().then(rec => {
+            this.context.record = new MarcRecord(rec.marc());
             this.record.id = id;
-            this.record.deleted = bib.deleted() === 't';
-            if (bib.source()) {
-                this.sourceSelector.applyEntryId(+bib.source());
+            this.record.deleted = rec.deleted() === 't';
+            if (idlClass === 'bre' && rec.source()) {
+                this.sourceSelector.applyEntryId(+rec.source());
             }
         });
     }
index 531822b..72381e9 100644 (file)
@@ -40,7 +40,7 @@
 <ng-template #postSubfieldsChunk let-field="field">
 
   <ng-container *ngIf="isControlledBibTag(field.tag)">
-    <button class="btn btn-sm btn-info link-button"
+    <button class="btn btn-sm btn-outline-info link-button"
       i18n-title title="Create authority link"
       (click)="openLinkerDialog(field)">
       <span class="material-icons">link</span>
       </eg-marc-editable-content>
 
       <ng-container *ngIf="field.tag === '007'">
-         <button class="btn btn-sm btn-info link-button"
+         <button class="btn btn-sm btn-outline-info link-button"
           i18n-title title="Open physical characteristics wizard"
           (click)="openPhysCharDialog(field)">
           <span class="material-icons">launch</span>
index 1028f42..220c3d1 100644 (file)
             </a>
           </li>
           <li>
-            <a href="./cat/catalog/retrieve_by_authority_id" target="_self">
+            <a href="/eg2/staff/cat/authority/edit" target="_self">
               <span class="glyphicon glyphicon-file"></span>
               [% l('Retrieve Authority Record by ID') %]
             </a>