LP1819053 Angular staff catalog basket export
authorBill Erickson <berickxx@gmail.com>
Thu, 7 Mar 2019 18:55:04 +0000 (13:55 -0500)
committerDan Wells <dbw2@calvin.edu>
Wed, 29 May 2019 19:30:51 +0000 (15:30 -0400)
Adds a new "Export Records" option to the staff catalog basket menu.
When selected, the user is directed to the Vandelay record export
interface, which will be set to "basket export" mode.  Staff can then
apply export preferences (usmarc, marxml, etc.) and export the basket
records.  In "basket export" mode, Vandley provides a link to return to
the catalog (preserving search params).

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Dan Wells <dbw2@calvin.edu>

Open-ILS/src/eg2/src/app/staff/cat/vandelay/export.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/export.component.ts
Open-ILS/src/eg2/src/app/staff/cat/vandelay/routing.module.ts
Open-ILS/src/eg2/src/app/staff/catalog/basket-actions.component.html
Open-ILS/src/eg2/src/app/staff/catalog/basket-actions.component.ts

index 53f36e6..b6fb361 100644 (file)
@@ -3,60 +3,73 @@
 <div class="common-form striped-even form-validated">
   <div class="row">
     <div class="col-lg-6">
-      <div class="row"><label>Select a Record Source</label></div>
-      <ngb-accordion [closeOthers]="true" activeIds="csv" 
-        (panelChange)="sourceChange($event)">
-        <ngb-panel id="csv" title="CSV File">
-          <ng-template ngbPanelContent>
-            <div class="row">
-              <div class="col-lg-6">
-                <label for="csv-input" i18n>Use Field Number</label>
-              </div>
-              <div class="col-lg-6">
-                <input id='csv-input' type="number" class="form-control" 
-                  [(ngModel)]="fieldNumber"
-                  i18n-placeholder placeholder="Starts at 0..."/>
-              </div>
-            </div>
-            <div class="row">
-              <div class="col-lg-6">
-                <label for="use-csv-file" i18n>From CSV file</label>
-              </div>
-              <div class="col-lg-6">
-                <input #fileSelector (change)="fileSelected($event)" 
-                  id="use-csv-file" class="form-control" type="file"/>
-              </div>
-            </div>
-          </ng-template>
-        </ngb-panel>
-        <ngb-panel id="record-id" title="Record ID">
-          <ng-template ngbPanelContent>
-            <div class="row">
-              <div class="col-lg-6">
-                <label for="record-id-input" i18n>Record ID</label>
+     <ng-container *ngIf="exportingBasket">
+        <div class="alert alert-info" i18n>
+          Exporting {{basketRecords.length}} Records from Catalog Basket.
+        </div>
+        <div>
+          <a routerLink="/staff/catalog/search" queryParamsHandling="merge">
+            <button class="btn btn-info" i18n>Return to Catalog</button>
+          </a>
+        </div>
+      </ng-container>
+      <ng-container *ngIf="!exportingBasket">
+        <div class="row"><label>Select a Record Source</label></div>
+        <ngb-accordion [closeOthers]="true" activeIds="csv" 
+          (panelChange)="sourceChange($event)">
+          <ngb-panel id="csv" title="CSV File">
+            <ng-template ngbPanelContent>
+              <div class="row">
+                <div class="col-lg-6">
+                  <label for="csv-input" i18n>Use Field Number</label>
+                </div>
+                <div class="col-lg-6">
+                  <input id='csv-input' type="number" class="form-control" 
+                    [(ngModel)]="fieldNumber"
+                    i18n-placeholder placeholder="Starts at 0..."/>
+                </div>
               </div>
-              <div class="col-lg-6">
-                <input id='record-id-input' type="number" 
-                  class="form-control" [(ngModel)]="recordId"/>
+              <div class="row">
+                <div class="col-lg-6">
+                  <label for="use-csv-file" i18n>From CSV file</label>
+                </div>
+                <div class="col-lg-6">
+                  <input #fileSelector (change)="fileSelected($event)" 
+                    id="use-csv-file" class="form-control" type="file"/>
+                </div>
               </div>
-            </div>
-          </ng-template>
-        </ngb-panel>
-        <ngb-panel id="bucket-id" title="Bucket">
-          <ng-template ngbPanelContent>
-            <div class="row">
-              <div class="col-lg-6">
-                <label for="bucket-id-input" i18n>Bucket ID</label>
+            </ng-template>
+          </ngb-panel>
+          <ngb-panel id="record-id" title="Record ID">
+            <ng-template ngbPanelContent>
+              <div class="row">
+                <div class="col-lg-6">
+                  <label for="record-id-input" i18n>Record ID</label>
+                </div>
+                <div class="col-lg-6">
+                  <input id='record-id-input' type="number" 
+                    class="form-control" [(ngModel)]="recordId"/>
+                </div>
               </div>
-              <div class="col-lg-6">
-                <input id='bucket-id-input' type="number" 
-                  class="form-control" [(ngModel)]="bucketId"/>
+            </ng-template>
+          </ngb-panel>
+          <ngb-panel id="bucket-id" title="Bucket">
+            <ng-template ngbPanelContent>
+              <div class="row">
+                <div class="col-lg-6">
+                  <label for="bucket-id-input" i18n>Bucket ID</label>
+                </div>
+                <div class="col-lg-6">
+                  <input id='bucket-id-input' type="number" 
+                    class="form-control" [(ngModel)]="bucketId"/>
+                </div>
               </div>
-            </div>
-          </ng-template>
-        </ngb-panel>
-      </ngb-accordion>
+            </ng-template>
+          </ngb-panel>
+        </ngb-accordion>
+      </ng-container>
     </div><!-- col -->
+
     <div class="col-lg-6">
       <div class="row">
         <div class="col-lg-6">
@@ -64,6 +77,7 @@
         </div>
         <div class="col-lg-6">
           <select class="form-control" 
+            [disabled]="exportingBasket"
             [(ngModel)]="recordType" id="record-type">
             <option i18n value="biblio">Bibliographic Records</option>
             <option i18n value="authority">Authority Records</option>
       </div>
     </div><!-- left col -->
   </div><!-- row -->
-</div>
+</div><!-- form -->
+
 
index d980e02..648f4d5 100644 (file)
@@ -1,4 +1,5 @@
-import {Component, AfterViewInit, ViewChild, Renderer2} from '@angular/core';
+import {Component, AfterViewInit, ViewChild, Renderer2, OnInit} from '@angular/core';
+import {ActivatedRoute} from '@angular/router';
 import {NgbPanelChangeEvent} from '@ng-bootstrap/ng-bootstrap';
 import {HttpClient, HttpRequest, HttpEventType} from '@angular/common/http';
 import {HttpResponse, HttpErrorResponse} from '@angular/common/http';
@@ -6,13 +7,14 @@ import {saveAs} from 'file-saver';
 import {AuthService} from '@eg/core/auth.service';
 import {ToastService} from '@eg/share/toast/toast.service';
 import {ProgressInlineComponent} from '@eg/share/dialog/progress-inline.component';
-import {VandelayService, VANDELAY_EXPORT_PATH} from './vandelay.service';
+import {VANDELAY_EXPORT_PATH} from './vandelay.service';
+import {BasketService} from '@eg/share/catalog/basket.service';
 
 
 @Component({
   templateUrl: 'export.component.html'
 })
-export class ExportComponent implements AfterViewInit {
+export class ExportComponent implements AfterViewInit, OnInit {
 
     recordSource: string;
     fieldNumber: number;
@@ -24,6 +26,8 @@ export class ExportComponent implements AfterViewInit {
     recordEncoding: string;
     includeHoldings: boolean;
     isExporting: boolean;
+    exportingBasket: boolean;
+    basketRecords: number[];
 
     @ViewChild('fileSelector') private fileSelector;
     @ViewChild('exportProgress')
@@ -31,23 +35,44 @@ export class ExportComponent implements AfterViewInit {
 
     constructor(
         private renderer: Renderer2,
+        private route: ActivatedRoute,
         private http: HttpClient,
         private toast: ToastService,
-        private auth: AuthService
+        private auth: AuthService,
+        private basket: BasketService
     ) {
         this.recordType = 'biblio';
         this.recordFormat = 'USMARC';
         this.recordEncoding = 'UTF-8';
         this.includeHoldings = false;
+        this.basketRecords = [];
+    }
+
+    ngOnInit() {
+        const segments = this.route.snapshot.url.length;
+        if (segments > 0 &&
+            this.route.snapshot.url[segments - 1].path === 'basket') {
+                this.exportingBasket = true;
+                this.basket.getRecordIds().then(
+                    ids => this.basketRecords = ids
+                );
+        }
     }
 
     ngAfterViewInit() {
+        if (this.exportingBasket) {
+            return; // no source to focus
+        }
         this.renderer.selectRootElement('#csv-input').focus();
     }
 
     sourceChange($event: NgbPanelChangeEvent) {
         this.recordSource = $event.panelId;
 
+        if (this.exportingBasket) {
+            return; // no source to focus
+        }
+
         if ($event.nextState) { // panel opened
 
             // give the panel a chance to render before focusing input
@@ -64,7 +89,10 @@ export class ExportComponent implements AfterViewInit {
 
     hasNeededData(): boolean {
         return Boolean(
-            this.selectedFile || this.recordId || this.bucketId
+            this.selectedFile ||
+            this.recordId     ||
+            this.bucketId     ||
+            (this.exportingBasket && this.basketRecords.length > 0)
         );
     }
 
@@ -83,21 +111,27 @@ export class ExportComponent implements AfterViewInit {
             formData.append('holdings', '1');
         }
 
-        switch (this.recordSource) {
+        if (this.exportingBasket) {
+            this.basketRecords.forEach(id => formData.append('id', '' + id));
+
+        } else {
 
-            case 'csv':
-                formData.append('idcolumn', '' + this.fieldNumber);
-                formData.append('idfile',
-                    this.selectedFile, this.selectedFile.name);
-                break;
+            switch (this.recordSource) {
 
-            case 'record-id':
-                formData.append('id', '' + this.recordId);
-                break;
+                case 'csv':
+                    formData.append('idcolumn', '' + this.fieldNumber);
+                    formData.append('idfile',
+                        this.selectedFile, this.selectedFile.name);
+                    break;
 
-            case 'bucket-id':
-                formData.append('containerid', '' + this.bucketId);
-                break;
+                case 'record-id':
+                    formData.append('id', '' + this.recordId);
+                    break;
+
+                case 'bucket-id':
+                    formData.append('containerid', '' + this.bucketId);
+                    break;
+            }
         }
 
         this.sendExportRequest(formData);
index 707b92b..f4095a4 100644 (file)
@@ -28,6 +28,9 @@ const routes: Routes = [{
     path: 'export',
     component: ExportComponent
   }, {
+    path: 'export/basket',
+    component: ExportComponent
+  }, {
     path: 'queue',
     component: QueueListComponent
   }, {
index 4857db8..9fcd873 100644 (file)
@@ -22,6 +22,7 @@
       <option value="print"  i18n>Print Title Details</option>
       <option value="email"  i18n>Email Title Details</option>
       <option value="bucket" i18n>Add Basket to Bucket</option>
+      <option value="export_marc" i18n>Export Records</option>
       <option value="clear"  i18n>Clear Basket</option>
     </select>
   </div>
index f96df6f..da3f793 100644 (file)
@@ -1,6 +1,5 @@
 import {Component, OnInit, ViewChild} from '@angular/core';
 import {BasketService} from '@eg/share/catalog/basket.service';
-import {Subscription} from 'rxjs';
 import {Router} from '@angular/router';
 import {NetService} from '@eg/core/net.service';
 import {AuthService} from '@eg/core/auth.service';
@@ -87,6 +86,13 @@ export class BasketActionsComponent implements OnInit {
                 });
                 break;
 
+            case 'export_marc':
+                this.router.navigate(
+                    ['/staff/cat/vandelay/export/basket'],
+                    {queryParamsHandling: 'merge'}
+                );
+                break;
+
             case 'bucket':
                 this.basket.getRecordIds().then(ids => {
                     this.addToBucketDialog.bucketClass = 'biblio';