LP1835982 Grid cell text generator API migration
authorBill Erickson <berickxx@gmail.com>
Fri, 9 Aug 2019 16:47:37 +0000 (12:47 -0400)
committerJane Sandberg <sandbej@linnbenton.edu>
Sat, 18 Jan 2020 18:38:14 +0000 (10:38 -0800)
Migrate cell-specific cellPrintValue handlers to a grid-wide
cellTextGenerator handler.  This simplifies the client-side API and
helps to formalize the API a bit more by providing a new
GridCellTextGenerator interface.

Warning messages are now display at page load time when a grid cell uses
a cellTemplate but does not have a matching text generator.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Signed-off-by: Jane Sandberg <sandbej@linnbenton.edu>
16 files changed:
Open-ILS/src/eg2/src/app/share/grid/grid-column.component.ts
Open-ILS/src/eg2/src/app/share/grid/grid-print.component.ts
Open-ILS/src/eg2/src/app/share/grid/grid.component.ts
Open-ILS/src/eg2/src/app/share/grid/grid.ts
Open-ILS/src/eg2/src/app/staff/cat/vandelay/match-set-list.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/match-set-list.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/queued-record-matches.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/queued-record-matches.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/copies.component.html
Open-ILS/src/eg2/src/app/staff/catalog/record/copies.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.html
Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts
Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.html
Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.ts

index 57af2e8..bb30842 100644 (file)
@@ -73,6 +73,12 @@ export class GridColumnComponent implements OnInit {
         col.timezoneContextOrg = this.timezoneContextOrg;
         col.isAuto = false;
         this.grid.context.columnSet.add(col);
+
+        if (this.cellTemplate &&
+            !this.grid.context.columnHasTextGenerator(col)) {
+            console.warn(
+                'No cellTextGenerator provided for "' + col.name + '"');
+        }
     }
 }
 
index d4e1d03..f7c857a 100644 (file)
@@ -24,13 +24,6 @@ export class GridPrintComponent {
         const columns = this.gridContext.columnSet.displayColumns();
         const textItems = {columns: columns, rows: []};
 
-        // Warn on missing print value generators for cells using templates.
-        columns.forEach(col => {
-            if (col.cellTemplate && !col.cellPrintValue) {
-                console.warn("No print value generator set for: " + col.name);
-            }
-        });
-
         this.gridContext.getAllRowsAsText().subscribe(
             row => {
               this.progressDialog.increment();
index e3decc6..191bec6 100644 (file)
@@ -4,7 +4,8 @@ import {IdlService} from '@eg/core/idl.service';
 import {OrgService} from '@eg/core/org.service';
 import {ServerStoreService} from '@eg/core/server-store.service';
 import {FormatService} from '@eg/core/format.service';
-import {GridContext, GridColumn, GridDataSource, GridRowFlairEntry} from './grid';
+import {GridContext, GridColumn, GridDataSource,
+    GridCellTextGenerator, GridRowFlairEntry} from './grid';
 import {GridToolbarComponent} from './grid-toolbar.component';
 
 /**
@@ -107,6 +108,8 @@ export class GridComponent implements OnInit, AfterViewInit, OnDestroy {
     // would go out of view
     @Input() stickyHeader: boolean;
 
+    @Input() cellTextGenerator: GridCellTextGenerator;
+
     context: GridContext;
 
     // These events are emitted from our grid-body component.
@@ -148,6 +151,8 @@ export class GridComponent implements OnInit, AfterViewInit, OnDestroy {
         this.context.showDeclaredFieldsOnly = this.showDeclaredFieldsOnly;
         this.context.rowFlairCallback = this.rowFlairCallback;
         this.context.disablePaging = this.disablePaging === true;
+        this.context.cellTextGenerator = this.cellTextGenerator;
+
         if (this.showFields) {
             this.context.defaultVisibleFields = this.showFields.split(',');
         }
index 42bd982..20bde50 100644 (file)
@@ -399,6 +399,13 @@ export class GridColumnSet {
     }
 }
 
+// Maps colunm names to functions which return plain text values for
+// each mapped column on a given row.  This is primarily useful for
+// generating print-friendly content for grid cells rendered via
+// cellTemplate.
+export interface GridCellTextGenerator {
+    [columnName: string]: (row: any) => string;
+}
 
 export class GridRowSelector {
     indexes: {[string: string]: boolean};
@@ -495,6 +502,7 @@ export class GridContext {
     overflowCells: boolean;
     disablePaging: boolean;
     showDeclaredFieldsOnly: boolean;
+    cellTextGenerator: GridCellTextGenerator;
 
     // Allow calling code to know when the select-all-rows-in-page
     // action has occurred.
@@ -810,8 +818,8 @@ export class GridContext {
 
 
     getColumnTextContent(row: any, col: GridColumn): string {
-        if (col.cellPrintValue) {
-            return col.cellPrintValue(row, col);
+        if (this.columnHasTextGenerator(col)) {
+            return this.cellTextGenerator[col.name](row);
         } else {
             if (col.cellTemplate) {
                 return ''; // avoid 'undefined' values
@@ -1099,6 +1107,10 @@ export class GridContext {
         if (!persistKey) { return Promise.resolve(null); }
         return this.store.getItem('eg.grid.' + persistKey);
     }
+
+    columnHasTextGenerator(col: GridColumn): boolean {
+        return this.cellTextGenerator && col.name in this.cellTextGenerator;
+    }
 }
 
 
index 74cad97..67c9588 100644 (file)
   </a> 
 </ng-template>
 
-<eg-grid #grid [dataSource]="gridSource"
+<eg-grid #grid [dataSource]="gridSource" [cellTextGenerator]="cellTextGenerator"
   persistKey="cat.vandelay.match_set.list"
   idlClass="vms" [dataSource]="queueSource">
   <eg-grid-toolbar-button label="New Match Set" i18n-label [action]="createNew">
   </eg-grid-toolbar-button>
   <eg-grid-toolbar-action label="Delete Selected" i18n-label 
     [action]="deleteSelected"></eg-grid-toolbar-action>
-  <eg-grid-column name="name" [cellTemplate]="nameTmpl" [cellPrintValue]="cellPrintValues">
+  <eg-grid-column name="name" [cellTemplate]="nameTmpl">
   </eg-grid-column>
 </eg-grid>
 
index c58735f..7ea2ae8 100644 (file)
@@ -6,7 +6,7 @@ import {PcrudService} from '@eg/core/pcrud.service';
 import {OrgService} from '@eg/core/org.service';
 import {AuthService} from '@eg/core/auth.service';
 import {GridComponent} from '@eg/share/grid/grid.component';
-import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
+import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
 import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
 
 @Component({
@@ -21,7 +21,7 @@ export class MatchSetListComponent implements AfterViewInit {
     @ViewChild('grid', { static: true }) grid: GridComponent;
     @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent;
 
-    cellPrintValues: (row: any, cell: GridColumn) => string;
+    cellTextGenerator: GridCellTextGenerator;
 
     constructor(
         private router: Router,
@@ -41,12 +41,8 @@ export class MatchSetListComponent implements AfterViewInit {
             });
         };
 
-        // Text-ify function for cells that use display templates.
-        this.cellPrintValues = (row: any, cell: GridColumn): string => {
-            switch (cell.name) {
-                case 'name':
-                    return row.name();
-            }
+        this.cellTextGenerator = {
+            name: row => row.name()
         };
 
         this.createNew = () => {
index 5ff7adc..16c97da 100644 (file)
@@ -130,7 +130,7 @@ because there are a lot of them.
 <eg-grid #queueGrid [dataSource]="queueSource"
   persistKey="cat.vandelay.queue.{{queueType}}"
   (onRowActivate)="openRecord($event)"
-  [pageOffset]="queuePageOffset()"
+  [pageOffset]="queuePageOffset()" [cellTextGenerator]="cellTextGenerator"
   hideFields="language,pagination,price,rec_identifier,eg_tcn_source,eg_identifier,item_barcode,zsource">
 
   <eg-grid-toolbar-checkbox i18n-label label="Records With Matches"
index e763130..02d0034 100644 (file)
@@ -10,7 +10,7 @@ import {AuthService} from '@eg/core/auth.service';
 import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
 import {ProgressDialogComponent} from '@eg/share/dialog/progress.component';
 import {GridComponent} from '@eg/share/grid/grid.component';
-import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
+import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
 import {VandelayService, VandelayImportSelection,
     VANDELAY_EXPORT_PATH} from './vandelay.service';
 
@@ -38,7 +38,7 @@ export class QueueComponent implements OnInit, AfterViewInit {
     @ViewChild('confirmDelDlg', { static: false }) confirmDelDlg: ConfirmDialogComponent;
     @ViewChild('progressDlg', { static: true }) progressDlg: ProgressDialogComponent;
 
-    cellPrintValues: (row: any, cell: GridColumn) => string;
+    cellTextGenerator: GridCellTextGenerator;
 
     constructor(
         private router: Router,
@@ -59,13 +59,10 @@ export class QueueComponent implements OnInit, AfterViewInit {
             return this.loadQueueRecords(pager);
         };
 
-        // Text-ify function for cells that use display templates.
-        this.cellPrintValues = (row: any, cell: GridColumn): string => {
-            return ({
-                '+matches': row.matches.length + '',
-                'import_error': row.import_error,
-                'imported_as': row.imported_as + ''
-            })[cell.name] || '';
+        this.cellTextGenerator = {
+            '+matches': row => row.matches.length + '',
+            'import_error': row => row.import_error,
+            'imported_as': row => row.imported_as + ''
         };
     }
 
index 346230a..2a14c31 100644 (file)
@@ -15,6 +15,7 @@
 <ng-container *ngIf="queueType == 'bib'">
   <eg-grid #bibGrid [dataSource]="bibDataSource" 
     (onRowClick)="matchRowClick($event)"
+    [cellTextGenerator]="cellTextGenerator"
     [disableSelect]="true" [disableMultiSelect]="true">
     <!--
     <eg-grid-toolbar-action i18n-label label="Mark As Overlay Target"
       i18n-label label="Match ID">
     </eg-grid-column>
     <eg-grid-column name="selected" i18n-label label="Merge Target"
-      [cellTemplate]="targetTemplate" [cellPrintValue]="cellPrintValues">
+      [cellTemplate]="targetTemplate">
     </eg-grid-column>
     <eg-grid-column name="eg_record" i18n-label label="Record ID"
-      [cellTemplate]="bibIdTemplate" [cellPrintValue]="cellPrintValues">
+      [cellTemplate]="bibIdTemplate">
     </eg-grid-column>
     <eg-grid-column name="match_score" i18n-label label="Match Score">
     </eg-grid-column>
index 7f2eefb..dfbee69 100644 (file)
@@ -4,7 +4,7 @@ import {Observable, of} from 'rxjs';
 import {map} from 'rxjs/operators';
 import {Pager} from '@eg/share/util/pager';
 import {GridComponent} from '@eg/share/grid/grid.component';
-import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
+import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
 import {IdlObject} from '@eg/core/idl.service';
 import {EventService} from '@eg/core/event.service';
 import {NetService} from '@eg/core/net.service';
@@ -31,7 +31,7 @@ export class QueuedRecordMatchesComponent implements OnInit {
     matchRowClick: (row: any) => void;
     matchMap: {[id: number]: IdlObject};
 
-    cellPrintValues: (row: any, cell: GridColumn) => string;
+    cellTextGenerator: GridCellTextGenerator;
 
     constructor(
         private router: Router,
@@ -50,12 +50,9 @@ export class QueuedRecordMatchesComponent implements OnInit {
             return this.getBibMatchRows(pager);
         };
 
-        // Text-ify function for cells that use display templates.
-        this.cellPrintValues = (row: any, cell: GridColumn): string => {
-            return ({
-                'selected': this.isOverlayTarget(row.id) + '',
-                'eg_record': row.eg_record + ''
-            })[cell.name] || '';
+        this.cellTextGenerator = {
+            selected: row => this.isOverlayTarget(row.id) + '',
+            eg_record: row => row.eg_record + ''
         };
 
 
index 4c2f10f..2d6707b 100644 (file)
@@ -37,7 +37,7 @@
 
 <div class='eg-copies w-100 mt-3'>
   <eg-grid #copyGrid [dataSource]="gridDataSource" 
-    [disableSelect]="true"
+    [disableSelect]="true" [cellTextGenerator]="cellTextGenerator"
     [sortable]="false" persistKey="catalog.record.copies">
     <eg-grid-column i18n-label label="Item ID" path="id" 
       [hidden]="true" [index]="true">
     <eg-grid-column i18n-label label="Location" path="circ_lib" datatype="org_unit">
     </eg-grid-column>
     <eg-grid-column i18n-label label="Call Number / Item Notes" name="callnumber" 
-      [cellTemplate]="cnTemplate" [cellPrintValue]="cellPrintValues">
+      [cellTemplate]="cnTemplate">
     </eg-grid-column>
     <eg-grid-column i18n-label label="Barcode" name="barcode"
-      [cellTemplate]="barcodeTemplate" [cellPrintValue]="cellPrintValues">
+      [cellTemplate]="barcodeTemplate">
     </eg-grid-column>
     <eg-grid-column i18n-label label="Shelving Location" path="copy_location">
     </eg-grid-column>
index d0ce074..b713fd6 100644 (file)
@@ -5,7 +5,7 @@ import {NetService} from '@eg/core/net.service';
 import {StaffCatalogService} from '../catalog.service';
 import {Pager} from '@eg/share/util/pager';
 import {OrgService} from '@eg/core/org.service';
-import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
+import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
 import {GridComponent} from '@eg/share/grid/grid.component';
 
 @Component({
@@ -29,7 +29,7 @@ export class CopiesComponent implements OnInit {
         }
     }
 
-    cellPrintValues: (row: any, cell: GridColumn) => string;
+    cellTextGenerator: GridCellTextGenerator;
 
     constructor(
         private net: NetService,
@@ -55,17 +55,11 @@ export class CopiesComponent implements OnInit {
             }
         };
 
-        // Text-ify function for cells that use display templates.
-        this.cellPrintValues = (row: any, cell: GridColumn): string => {
-            switch (cell.name) {
-                case 'callnumber':
-                    return `${row.call_number_prefix_label} ` +
-                        `${row.call_number_label} ${row.call_number_suffix_label}`;
-                case 'holdable':
-                    return this.copyContext.holdable(row);
-                case 'barcode':
-                    return row.barcode;
-            }
+        this.cellTextGenerator = {
+            callnumber: row => `${row.call_number_prefix_label} ` +
+                `${row.call_number_label} ${row.call_number_suffix_label}`,
+            holdable: row => this.copyContext.holdable(row),
+            barcode: row => row.barcode
         };
     }
 
index ac5bcc9..bb1606c 100644 (file)
@@ -57,7 +57,7 @@
 <div class='eg-copies w-100 mt-3'>
   <eg-grid #holdingsGrid [dataSource]="gridDataSource"
     (onRowActivate)="onRowActivate($event)" [disablePaging]="true"
-    [rowClassCallback]="rowClassCallback"
+    [rowClassCallback]="rowClassCallback" [cellTextGenerator]="cellTextGenerator"
     [sortable]="false" persistKey="cat.holdings">
 
     <!-- checkboxes / filters -->
     </eg-grid-column>
     <eg-grid-column name="owner_label" [flex]="4"
       [cellTemplate]="locationTemplate" [cellContext]="gridTemplateContext" 
-      [cellPrintValue]="cellPrintValues"
       label="Location/Barcode" [disableTooltip]="true" i18n-label>
     </eg-grid-column>
     <eg-grid-column path="callNumCount" datatype="number" label="Call Numbers" i18n-label>
     <eg-grid-column i18n-label label="Deposit Amount" path="copy.deposit_amount" 
       name="deposit_amount" datatype="money" [hidden]="true"></eg-grid-column>
     <eg-grid-column i18n-label label="Holdable?" name="holdable" 
-      [cellTemplate]="holdableTemplate" [cellContext]="gridTemplateContext"
-      [cellPrintValue]="cellPrintValues">
+      [cellTemplate]="holdableTemplate" [cellContext]="gridTemplateContext">
     </eg-grid-column>
     <eg-grid-column i18n-label label="Reference?" path="copy.ref" 
       name="ref" datatype="bool" [hidden]="true"></eg-grid-column>
index 973f31a..4186b7a 100644 (file)
@@ -9,7 +9,7 @@ import {StaffCatalogService} from '../catalog.service';
 import {OrgService} from '@eg/core/org.service';
 import {PcrudService} from '@eg/core/pcrud.service';
 import {AuthService} from '@eg/core/auth.service';
-import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
+import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
 import {GridComponent} from '@eg/share/grid/grid.component';
 import {GridToolbarCheckboxComponent
     } from '@eg/share/grid/grid-toolbar-checkbox.component';
@@ -131,7 +131,7 @@ export class HoldingsMaintenanceComponent implements OnInit {
     renderFromPrefs: boolean;
 
     rowClassCallback: (row: any) => string;
-    cellPrintValues: (row: any, cell: GridColumn) => string;
+    cellTextGenerator: GridCellTextGenerator;
 
     private _recId: number;
     @Input() set recordId(id: number) {
@@ -184,15 +184,10 @@ export class HoldingsMaintenanceComponent implements OnInit {
         };
 
         // Text-ify function for cells that use display templates.
-        this.cellPrintValues = (row: any, cell: GridColumn): string => {
-            switch (cell.name) {
-                case 'owner_label':
-                    return row.locationLabel;
-                case 'holdable':
-                    return row.copy ?
-                        this.gridTemplateContext.copyIsHoldable(row.copy) :
-                        '';
-            }
+        this.cellTextGenerator = {
+            owner_label: row => row.locationLabel,
+            holdable: row => row.copy ?
+                this.gridTemplateContext.copyIsHoldable(row.copy) : ''
         };
 
         this.gridTemplateContext = {
index a4d088c..b3c7705 100644 (file)
@@ -31,7 +31,7 @@
     </div>
 
     <eg-grid #holdsGrid [dataSource]="gridDataSource" [sortable]="true"
-      [useLocalSort]="enablePreFetch"
+      [useLocalSort]="enablePreFetch" [cellTextGenerator]="cellTextGenerator"
       [multiSortable]="true" [persistKey]="persistKey"
       (onRowActivate)="showDetail($event)">
 
@@ -92,7 +92,7 @@
         </a>
       </ng-template>
       <eg-grid-column i18n-label label="Current Item" name='cp_barcode'
-        [cellTemplate]="barcodeTmpl" [cellPrintValue]="cellPrintValues">
+        [cellTemplate]="barcodeTmpl">
       </eg-grid-column>
 
       <ng-template #userBarcodeTmpl let-hold="row">
         </a>
       </ng-template>
       <eg-grid-column i18n-label label="Title" [hidden]="true" name='title' 
-        [cellTemplate]="titleTmpl" [cellPrintValue]="cellPrintValues"></eg-grid-column>
+        [cellTemplate]="titleTmpl"></eg-grid-column>
       <eg-grid-column i18n-label label="Author" path='author'
           [hidden]="true"></eg-grid-column>
       <eg-grid-column i18n-label label="Potential Items" path='potentials' datatype="int">
index effa7c5..029883b 100644 (file)
@@ -6,7 +6,7 @@ import {OrgService} from '@eg/core/org.service';
 import {AuthService} from '@eg/core/auth.service';
 import {Pager} from '@eg/share/util/pager';
 import {ServerStoreService} from '@eg/core/server-store.service';
-import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
+import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
 import {GridComponent} from '@eg/share/grid/grid.component';
 import {ProgressDialogComponent} from '@eg/share/dialog/progress.component';
 import {MarkDamagedDialogComponent
@@ -111,7 +111,7 @@ export class HoldsGridComponent implements OnInit {
         }
     }
 
-    cellPrintValues: (row: any, cell: GridColumn) => string;
+    cellTextGenerator: GridCellTextGenerator;
 
     constructor(
         private net: NetService,
@@ -146,11 +146,9 @@ export class HoldsGridComponent implements OnInit {
         };
 
         // Text-ify function for cells that use display templates.
-        this.cellPrintValues = (row: any, cell: GridColumn): string => {
-            return ({
-                'title': row.title,
-                'cp_barcode': row.cp_barcode
-            })[cell.name] || '';
+        this.cellTextGenerator = {
+            title: row => row.title,
+            cp_barcode: row => row.cp_barcode
         };
     }