LPXXX Angular Volcopy
authorBill Erickson <berickxx@gmail.com>
Tue, 23 Jun 2020 20:57:11 +0000 (16:57 -0400)
committerBill Erickson <berickxx@gmail.com>
Tue, 23 Jun 2020 20:57:11 +0000 (16:57 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/staff/cat/volcopy/copy-attrs.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/copy-attrs.component.ts
Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.service.ts
Open-ILS/src/eg2/src/app/staff/common.module.ts

index 4ea94ab..2f5811b 100644 (file)
 <div class="row border rounded border-dark pt-2 pb-2 bg-faint">
   <div class="col-lg-1 font-weight-bold" i18n>Templates:</div>
   <div class="col-lg-4">
-    <eg-combobox domId="template-select" #copyTemplateCbox></eg-combobox>
+    <eg-combobox #copyTemplateCbox domId="template-select" 
+      [allowFreeText]="true" [entries]="volcopy.templateNames" 
+      [(ngModel)]="currentTemplate">
+    </eg-combobox>
   </div>
   <div class="col-lg-7 d-flex">
     <button class="btn btn-outline-dark mr-2" (click)="applyTemplate()" i18n>Apply</button>
     <button class="btn btn-outline-dark mr-2" (click)="saveTemplate()" i18n>Save</button>
     <button class="btn btn-outline-dark mr-2" (click)="importTemplate()" i18n>Import</button>
-    <button class="btn btn-outline-dark mr-2" (click)="exportTemplate()" i18n>Export</button>
+
+    <button class="btn btn-outline-dark mr-2" (click)="importTemplate()" i18n>Import</button>
+
+    <a (click)="exportTemplate($event)"
+      download="export_copy_template.json" [href]="exportTemplateUrl()">
+      <button class="btn btn-outline-dark mr-2" i18n>Export</button>
+    </a>
+    
     <div class="flex-1"> </div>
     <button class="btn btn-outline-dark mr-2" 
       (click)="copyTemplateCbox.selectedId = null" i18n>Clear</button>
index 44d2858..2eb0ef2 100644 (file)
@@ -1,6 +1,7 @@
 import {Component, Input, OnInit, AfterViewInit, ViewChild,
     QueryList, ViewChildren} from '@angular/core';
 import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {SafeUrl} from '@angular/platform-browser';
 import {tap} from 'rxjs/operators';
 import {IdlObject, IdlService} from '@eg/core/idl.service';
 import {EventService} from '@eg/core/event.service';
@@ -18,6 +19,7 @@ import {CopyAlertsDialogComponent
     } from '@eg/staff/share/holdings/copy-alerts-dialog.component';
 import {ComboboxComponent, ComboboxEntry} from '@eg/share/combobox/combobox.component';
 import {BatchItemAttrComponent} from '@eg/staff/share/holdings/batch-item-attr.component';
+import {FileExportService} from '@eg/share/util/file-export.service';
 
 @Component({
   selector: 'eg-copy-attrs',
@@ -83,6 +85,7 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
         private holdings: HoldingsService,
         private format: FormatService,
         private store: StoreService,
+        private fileExport: FileExportService,
         public  volcopy: VolCopyService
     ) { }
 
@@ -92,7 +95,10 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
     ngAfterViewInit() {
 
         const tmpl = this.store.getLocalItem('cat.copy.last_template');
-        if (tmpl) { this.copyTemplateCbox.selectedId = tmpl; }
+        if (tmpl) {
+            // avoid Express Changed warning w/ timeout
+            setTimeout(() => this.copyTemplateCbox.selectedId = tmpl);
+        }
 
         this.loanDurationLabelMap[1] = this.loanDurationShort.text;
         this.loanDurationLabelMap[2] = this.loanDurationNormal.text;
@@ -233,8 +239,6 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
 
         // TODO: handle circ_lib, owning_lib changes specially
 
-        console.debug('APPLYING', field, value);
-
         this.context.copyList().forEach(copy => {
             if (copy[field] && copy[field]() !== value) {
                 copy[field](value);
@@ -299,6 +303,8 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
 
         this.store.setLocalItem('cat.copy.last_template', entry.id);
 
+        // TODO: handle owning_lib and statcats differently.
+
         const template = this.volcopy.templates[entry.id];
 
         Object.keys(template).forEach(field => {
@@ -307,13 +313,64 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
             if (value === null || value === undefined) { return; }
 
             this.applyCopyValue(field, value);
+
+            // Indicate in the form these values have changed
+            this.batchAttrs
+                .filter(ba => ba.name === field)
+                .forEach(attr => attr.hasChanged = true);
         });
     }
 
     saveTemplate() {
+        const entry: ComboboxEntry = this.copyTemplateCbox.selected;
+        if (!entry) { return; }
+
+        let name;
+        let template;
+
+        if (entry.freetext) {
+            name = entry.label;
+            template = {};
+        } else {
+            name = entry.id;
+            template = this.volcopy.templates[name];
+        }
+
+        // Changes will have applied to all items.
+        const copy = this.context.copyList()[0];
+
         this.batchAttrs.forEach(comp => {
-            console.log(comp.editInputDomId);
+            if (comp.hasChanged) {
+                const value = copy[comp.name]();
+                if (value === null) {
+                    delete template[comp.name];
+                } else {
+                    template[comp.name] = value;
+                }
+            }
         });
+
+        console.debug('Saving template', template);
+
+        this.volcopy.templates[name] = template;
+        this.volcopy.saveTemplates();
+    }
+
+    exportTemplate($event) {
+        if (this.fileExport.inProgress()) { return; }
+
+        const entry: ComboboxEntry = this.copyTemplateCbox.selected;
+        if (!entry) { return; }
+
+        const template = this.volcopy.templates[entry.id];
+
+        this.fileExport.exportFile(
+            $event, JSON.stringify(template), 'text/json');
+    }
+
+    // Returns null when no export is in progress.
+    exportTemplateUrl(): SafeUrl {
+        return this.fileExport.safeUrl;
     }
 
     displayAttr(field: string): boolean {
index d9ce8a0..b411fd1 100644 (file)
@@ -15,6 +15,8 @@ import {ComboboxComponent, ComboboxEntry} from '@eg/share/combobox/combobox.comp
 
 /* Managing volcopy data */
 
+
+
 interface VolCopyDefaults {
     values: {[field: string]: any},
     hidden: {[field: string]: boolean}
@@ -171,6 +173,14 @@ export class VolCopyService {
         return Promise.resolve();
     }
 
+
+    saveTemplates(): Promise<any> {
+        // TODO: templates should be stored on the server.
+        this.store.setLocalItem('cat.copy.templates', this.templates);
+        // Re-sort, etc.
+        return this.fetchTemplates();
+    }
+
     fetchDefaults(): Promise<any> {
         if (this.defaults) { return Promise.resolve(); }
 
index 85dd7fc..f6f4140 100644 (file)
@@ -18,6 +18,7 @@ import {MultiSelectComponent} from '@eg/share/multi-select/multi-select.componen
 import {NotBeforeMomentValidatorDirective} from '@eg/share/validators/not_before_moment_validator.directive';
 import {PatronBarcodeValidatorDirective} from '@eg/share/validators/patron_barcode_validator.directive';
 import {BroadcastService} from '@eg/share/util/broadcast.service';
+import {FileExportService} from '@eg/share/util/file-export.service';
 
 /**
  * Imports the EG common modules and adds modules common to all staff UI's.
@@ -71,7 +72,8 @@ export class StaffCommonModule {
             providers: [ // Export staff-wide services
                 AccessKeyService,
                 AudioService,
-                BroadcastService
+                BroadcastService,
+                FileExportService
             ]
         };
     }