LP1842763 Import from queue selection improvements user/berick/lp1842763-vand-allow-import-from-selection-v2
authorBill Erickson <berickxx@gmail.com>
Wed, 12 May 2021 16:05:40 +0000 (12:05 -0400)
committerBill Erickson <berickxx@gmail.com>
Wed, 12 May 2021 16:15:22 +0000 (12:15 -0400)
Improve retention of selected queue information and selected overlay
targets while navigating Vandelay queue and import interfaces.

Also adds a 'Select All' records option to the queue grid.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/staff/cat/vandelay/import.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/import.component.ts
Open-ILS/src/eg2/src/app/staff/cat/vandelay/queue.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/queue.component.ts
Open-ILS/src/eg2/src/app/staff/cat/vandelay/vandelay.service.ts

index b9f059b..e98d9b3 100644 (file)
@@ -20,7 +20,7 @@
     </div>
     <div class="col-lg-3">
       <eg-combobox #formTemplateSelector
-        id="template-select"
+        domId="template-select"
         (onChange)="templateSelectorChange($event)"
         [allowFreeText]="true"
         [startId]="selectedTemplate"
       </eg-combobox>
     </div>
     <div class="col-lg-6">
-      <button class="btn btn-success"
+      <button class="btn btn-success" *ngIf="!templateInputMatch"
         [disabled]="!selectedTemplate"
         (click)="saveTemplate()" i18n>Save As New Template</button>
+      <button class="btn btn-success" *ngIf="templateInputMatch"
+        [disabled]="!selectedTemplate"
+        (click)="saveTemplate()" i18n>Modify Template</button>
       <button class="btn btn-outline-primary ml-3"
         [disabled]="!selectedTemplate"
         (click)="markTemplateDefault()" i18n>Mark Template as Default</button>
@@ -48,7 +51,7 @@
     </div>
     <div class="col-lg-3">
       <eg-combobox #recordTypeSelector
-        id="type-select"
+        domId="type-select"
         (onChange)="selectEntry($event, 'recordType')"
         [readOnly]="importSelection()" [required]="true"
         [startId]="recordType" placeholder="Record Type..." i18n-placeholder>
@@ -65,7 +68,7 @@
     </div>
     <div class="col-lg-3">
       <eg-combobox #bibSourceSelector
-        id="source-select"
+        domId="source-select"
         [entries]="formatEntries('bibSources')" 
         (onChange)="selectEntry($event, 'bibSources')"
         [startId]="selectedBibSource"
@@ -79,7 +82,8 @@
     </div>
     <div class="col-lg-3">
       <eg-combobox [entries]="formatEntries('activeQueues')"
-        id="queue-select"
+        #queueSelector
+        domId="queue-select"
         [startId]="startQueueId"
         [startIdFiresOnChange]="true"
         [readOnly]="startQueueId"
@@ -93,7 +97,7 @@
     </div>
     <div class="col-lg-3">
       <eg-combobox [entries]="formatEntries('bibBuckets')" 
-        id="bucket-select"
+        domId="bucket-select"
         [startId]="selectedBucket"
         [readOnly]="(selectedQueue && !selectedQueue.freetext) || importSelection()"
         (onChange)="selectEntry($event, 'bibBuckets')"
index 1e86e7f..3a2b378 100644 (file)
@@ -109,6 +109,7 @@ export class ImportComponent implements OnInit, AfterViewInit, OnDestroy {
     selectedTemplate: string;
     formTemplates: {[name: string]: any};
     newTemplateName: string;
+    templateInputMatch: boolean;
 
     @ViewChild('fileSelector', { static: false }) private fileSelector;
     @ViewChild('uploadProgress', { static: true })
@@ -133,6 +134,8 @@ export class ImportComponent implements OnInit, AfterViewInit, OnDestroy {
         private mergeProfileSelector: ComboboxComponent;
     @ViewChild('fallThruMergeProfileSelector', { static: true })
         private fallThruMergeProfileSelector: ComboboxComponent;
+    @ViewChild('queueSelector', { static: true })
+        private queueSelector: ComboboxComponent;
 
     @ViewChild('dupeQueueAlert', { static: true })
         private dupeQueueAlert: AlertDialogComponent;
@@ -147,7 +150,6 @@ export class ImportComponent implements OnInit, AfterViewInit, OnDestroy {
         private store: ServerStoreService,
         private vandelay: VandelayService
     ) {
-        this.applyDefaults();
     }
 
     applyDefaults() {
@@ -167,11 +169,20 @@ export class ImportComponent implements OnInit, AfterViewInit, OnDestroy {
 
             const queue = this.vandelay.importSelection.queue;
             this.recordType = queue.queue_type();
-            this.selectedMatchSet = queue.match_set();
 
-            // This will be propagated to selectedQueue as a combobox
-            // entry via the combobox
+            // Propagate to the selectors differently depending on
+            // wether they have rendered (and applied the startId
+            // already) or not.
             this.startQueueId = queue.id();
+            if (this.queueSelector) {
+                this.queueSelector.selectedId = this.startQueueId;
+                this.selectedQueue = {id: queue.id(), label: queue.name()};
+            }
+
+            this.selectedMatchSet = queue.match_set();
+            if (this.matchSetSelector) {
+                this.matchSetSelector.selectedId = this.selectedMatchSet;
+            }
 
             if (this.recordType === 'bib') {
                 this.selectedBucket = queue.match_bucket();
@@ -180,7 +191,9 @@ export class ImportComponent implements OnInit, AfterViewInit, OnDestroy {
         }
     }
 
-    ngOnInit() {}
+    ngOnInit() {
+        this.applyDefaults();
+    }
 
     ngAfterViewInit() {
         this.loadStartupData();
@@ -589,7 +602,11 @@ export class ImportComponent implements OnInit, AfterViewInit, OnDestroy {
         };
 
         if (this.vandelay.importSelection) {
-            options.overlay_map = this.vandelay.importSelection.overlayMap;
+            options.overlay_map = {};
+            for (let recId in this.vandelay.importSelection.overlayMap) {
+                options.overlay_map[recId] =
+                    this.vandelay.importSelection.overlayMap[recId].eg_record();
+            }
         }
 
         return options;
@@ -612,6 +629,7 @@ export class ImportComponent implements OnInit, AfterViewInit, OnDestroy {
         console.debug('Saving import profile', template);
 
         this.formTemplates[this.selectedTemplate] = template;
+        this.templateInputMatch = true;
         return this.store.setItem(TEMPLATE_SETTING_NAME, this.formTemplates);
     }
 
@@ -636,13 +654,14 @@ export class ImportComponent implements OnInit, AfterViewInit, OnDestroy {
         this.selectedTemplate = entry.label; // label == name
 
         if (entry.freetext) {
+            this.templateInputMatch = false;
             // User is entering a new template name.
             // Nothing to apply.
             return;
         }
 
         // User selected an existing template, apply it to the form.
-
+        this.templateInputMatch = true;
         const template = this.formTemplates[entry.id];
 
         // Copy the template values into "this"
index 480e554..60b1c8e 100644 (file)
@@ -2,6 +2,9 @@
 <eg-progress-dialog #progressDlg
   dialogTitle="Deleting Queue..." i18n-dialogTitle></eg-progress-dialog>
 
+<eg-progress-dialog #progressSelect
+  dialogTitle="Selecting all records..." i18n-dialogTitle></eg-progress-dialog>
+
 <ng-container *ngIf="queueSummary && queueSummary.queue">
 
   <eg-confirm-dialog
@@ -126,12 +129,24 @@ definitions.  Hide a number of stock record attributes by default
 because there are a lot of them.
 -->
 
+<ng-template #selectTemplate let-row="row">
+  <ng-container *ngIf="rowIsSelected(row.id)">
+    <span i18n-title title="Row is Selected"
+      class="material-icons">check_circle</span>
+  </ng-container>
+</ng-template>
+
 <eg-grid #queueGrid [dataSource]="queueSource"
   persistKey="cat.vandelay.queue.{{queueType}}"
   (onRowActivate)="openRecord($event)"
   [pageOffset]="queuePageOffset()" [cellTextGenerator]="cellTextGenerator"
+  [disableSelect]="true"
+  (onRowClick)="rowClicked($event)"
   hideFields="language,pagination,price,rec_identifier,eg_tcn_source,eg_identifier,item_barcode,zsource">
 
+  <eg-grid-toolbar-checkbox i18n-label label="Select All"
+    (onChange)="toggleSelectRows($event)"></eg-grid-toolbar-checkbox>
+
   <eg-grid-toolbar-checkbox i18n-label label="Records With Matches"
     (onChange)="limitToMatches($event)"></eg-grid-toolbar-checkbox>
 
@@ -141,6 +156,9 @@ because there are a lot of them.
   <eg-grid-toolbar-checkbox i18n-label label="Records with Import Errors"
     (onChange)="limitToImportErrors($event)"></eg-grid-toolbar-checkbox>
 
+  <eg-grid-column name="selected" i18n-label label="Select"
+    [cellTemplate]="selectTemplate"></eg-grid-column>
+
   <eg-grid-column name="id" [index]="true" [hidden]="true"></eg-grid-column>
   <eg-grid-column i18n-label label="Matches" name="+matches" 
     [cellTemplate]="matchesTmpl"></eg-grid-column>
index 484e456..7a72fe6 100644 (file)
@@ -37,6 +37,7 @@ export class QueueComponent implements OnInit, AfterViewInit {
     @ViewChild('queueGrid', { static: true }) queueGrid: GridComponent;
     @ViewChild('confirmDelDlg', { static: false }) confirmDelDlg: ConfirmDialogComponent;
     @ViewChild('progressDlg', { static: true }) progressDlg: ProgressDialogComponent;
+    @ViewChild('progressSelect', {static: false}) progressSelect: ProgressDialogComponent;
 
     cellTextGenerator: GridCellTextGenerator;
 
@@ -205,12 +206,46 @@ export class QueueComponent implements OnInit, AfterViewInit {
             Boolean(this.vandelay.importSelection.overlayMap[rid]);
     }
 
+    rowIsSelected(rowId: number): boolean {
+        return this.vandelay.importSelection &&
+            this.vandelay.importSelection.recordIds.includes(rowId);
+    }
+
+    toggleSelectRows(checked: boolean) {
+
+        if (checked) {
+            this.progressSelect.open();
+            this.queueGrid.context.getAllRows().then(_ => {
+                this.queueSource.data.forEach(row => {
+                    if (!this.rowIsSelected(row)) {
+                        this.rowClicked(row);
+                    }
+                });
+                this.progressSelect.close();
+            });
+
+        } else {
+            const selection = this.vandelay.importSelection;
+            if (selection) {
+                selection.recordIds = [];
+            }
+        }
+    }
+
+    rowClicked(row: any) {
+        const selection = this.findOrCreateImportSelection();
+        if (selection.recordIds.includes(row.id)) {
+            selection.recordIds = selection.recordIds.filter(
+                rid => rid !== row.id);
+        } else {
+            selection.recordIds.push(row.id);
+        }
+    }
+
     importSelected() {
-        const rows = this.queueGrid.context.getSelectedRows();
-        if (rows.length) {
-            const selection = this.findOrCreateImportSelection();
-            selection.recordIds = rows.map(row => row.id);
-            console.log('importing: ', this.vandelay.importSelection);
+        const selection = this.findOrCreateImportSelection();
+        if (selection.recordIds.length) {
+            console.debug('importing: ', this.vandelay.importSelection);
             this.router.navigate(['/staff/cat/vandelay/import']);
         }
     }
index cd52d44..3d97ba1 100644 (file)
@@ -19,7 +19,7 @@ export class VandelayImportSelection {
     recordIds: number[];
     queue: IdlObject;
     importQueue: boolean; // import the whole queue
-    overlayMap: {[qrId: number]: /* breId */ number};
+    overlayMap: {[qrId: number]: /* match */ IdlObject};
 
     constructor() {
        this.recordIds = [];