From b7577f2e00c0d5a720af7100631ca2ecdb91b3ae Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Mon, 4 Mar 2019 11:12:33 -0500 Subject: [PATCH] LP1818288 WS Option to pre-fetch record holds Adds a workstation setting allowing staff to decide whether to pre-fetch all holds on the record detail holds tab, to perform sorting paging in the client, or to leave the sorting/paging on the server. Improves client-side sorting in the grid. Signed-off-by: Bill Erickson Signed-off-by: Dan Wells --- .../grid/grid-toolbar-checkbox.component.ts | 5 ++ .../share/grid/grid-toolbar.component.html | 1 + Open-ILS/src/eg2/src/app/share/grid/grid.ts | 31 ++++++--- .../catalog/record/record.component.html | 1 + .../app/staff/share/holds/grid.component.html | 13 ++-- .../app/staff/share/holds/grid.component.ts | 69 ++++++++++++++----- Open-ILS/src/sql/Pg/950.data.seed-values.sql | 11 ++- .../XXXX.data.catalog-holds-prefetch.sql | 15 ++++ 8 files changed, 115 insertions(+), 31 deletions(-) create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.catalog-holds-prefetch.sql diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar-checkbox.component.ts b/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar-checkbox.component.ts index 8765917ceb..7ee3019477 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar-checkbox.component.ts +++ b/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar-checkbox.component.ts @@ -12,6 +12,10 @@ export class GridToolbarCheckboxComponent implements OnInit { // Note most input fields should match class fields for GridColumn @Input() label: string; + // Set the render time value. + // This does NOT fire the onChange handler. + @Input() initialValue: boolean; + // This is an input instead of an Output because the handler is // passed off to the grid context for maintenance -- events // are not fired directly from this component. @@ -32,6 +36,7 @@ export class GridToolbarCheckboxComponent implements OnInit { const cb = new GridToolbarCheckbox(); cb.label = this.label; cb.onChange = this.onChange; + cb.isChecked = this.initialValue; this.grid.context.toolbarCheckboxes.push(cb); } diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html b/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html index 52c3ae1099..5dd307f4f9 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html +++ b/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html @@ -18,6 +18,7 @@ diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid.ts b/Open-ILS/src/eg2/src/app/share/grid/grid.ts index f7e681dfcb..7c30438ccc 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid.ts +++ b/Open-ILS/src/eg2/src/app/share/grid/grid.ts @@ -542,18 +542,34 @@ export class GridContext { sortLocalData() { const sortDefs = this.dataSource.sort.map(sort => { + const column = this.columnSet.getColByName(sort.name); + const def = { name: sort.name, dir: sort.dir, - col: this.columnSet.getColByName(sort.name) + col: column }; if (!def.col.comparator) { - def.col.comparator = (a, b) => { - if (a < b) { return -1; } - if (a > b) { return 1; } - return 0; - }; + switch (def.col.datatype) { + case 'id': + case 'money': + case 'int': + def.col.comparator = (a, b) => { + a = Number(a); + b = Number(b); + if (a < b) { return -1; } + if (a > b) { return 1; } + return 0; + }; + break; + default: + def.col.comparator = (a, b) => { + if (a < b) { return -1; } + if (a > b) { return 1; } + return 0; + }; + } } return def; @@ -574,8 +590,6 @@ export class GridContext { const diff = sortDef.col.comparator(valueA, valueB); if (diff === 0) { continue; } - console.log(valueA, valueB, diff); - return sortDef.dir === 'DESC' ? -diff : diff; } @@ -927,6 +941,7 @@ export class GridToolbarButton { export class GridToolbarCheckbox { label: string; + isChecked: boolean; onChange: EventEmitter; } diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.html index ff3475076d..ad75118182 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.html +++ b/Open-ILS/src/eg2/src/app/staff/catalog/record/record.component.html @@ -52,6 +52,7 @@ diff --git a/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.html b/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.html index 62d269b306..db3d31b25a 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.html +++ b/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.html @@ -16,7 +16,7 @@ - +
@@ -31,9 +31,14 @@
+ + + @@ -74,7 +79,7 @@ i18-group group="Hold" i18n-label label="Cancel Hold" (onClick)="showCancelDialog($event)"> - + @@ -107,12 +112,12 @@ name='title' [cellTemplate]="titleTmpl"> - + + path='relative_queue_position' [hidden]="true" datatype="int"> diff --git a/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.ts b/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.ts index e0e894d871..af27574528 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.ts @@ -5,6 +5,7 @@ import {NetService} from '@eg/core/net.service'; 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} from '@eg/share/grid/grid'; import {GridComponent} from '@eg/share/grid/grid.component'; import {ProgressDialogComponent} from '@eg/share/dialog/progress.component'; @@ -33,6 +34,12 @@ export class HoldsGridComponent implements OnInit { // Grid persist key @Input() persistKey: string; + @Input() preFetchSetting: string; + // If set, all holds are fetched on grid load and sorting/paging all + // happens in the client. If false, sorting and paging occur on + // the server. + enablePreFetch: boolean; + // How to sort when no sort parameters have been applied // via grid controls. This uses the eg-grid sort format: // [{name: fname, dir: 'asc'}, {name: fname2, dir: 'desc'}] @@ -46,7 +53,6 @@ export class HoldsGridComponent implements OnInit { detailHold: any; editHolds: number[]; transferTarget: number; - copyStatuses: {[id: string]: IdlObject}; @ViewChild('holdsGrid') private holdsGrid: GridComponent; @ViewChild('progressDialog') @@ -104,34 +110,59 @@ export class HoldsGridComponent implements OnInit { constructor( private net: NetService, private org: OrgService, + private store: ServerStoreService, private auth: AuthService ) { this.gridDataSource = new GridDataSource(); - this.copyStatuses = {}; + this.enablePreFetch = null; } ngOnInit() { this.initDone = true; this.pickupLib = this.org.get(this.initialPickupLib); - this.gridDataSource.getRows = (pager: Pager, sort: any[]) => { + if (this.preFetchSetting) { - if (this.defaultSort && sort.length === 0) { - // Only use initial sort if sorting has not been modified - // by the grid's own sort controls. - sort = this.defaultSort; - } + this.store.getItem(this.preFetchSetting).then( + applied => this.enablePreFetch = Boolean(applied) + ); + + } - // sorting not currently supported + if (!this.defaultSort) { + this.defaultSort = [{name: 'request_time', dir: 'asc'}]; + } + + this.gridDataSource.getRows = (pager: Pager, sort: any[]) => { + sort = sort.length > 0 ? sort : this.defaultSort; return this.fetchHolds(pager, sort); }; } + // Returns true after all data/settings/etc required to render the + // grid have been fetched. + initComplete(): boolean { + return this.enablePreFetch !== null; + } + pickupLibChanged(org: IdlObject) { this.pickupLib = org; this.holdsGrid.reload(); } + preFetchHolds(apply: boolean) { + this.enablePreFetch = apply; + + if (apply) { + setTimeout(() => this.holdsGrid.reload()); + } + + if (this.preFetchSetting) { + // fire and forget + this.store.setItem(this.preFetchSetting, apply); + } + } + applyFilters(): any { const filters: any = { is_staff_request: true, @@ -167,11 +198,16 @@ export class HoldsGridComponent implements OnInit { const filters = this.applyFilters(); const orderBy: any = []; - sort.forEach(obj => { - const subObj: any = {}; - subObj[obj.name] = {dir: obj.dir, nulls: 'last'}; - orderBy.push(subObj); - }); + if (sort.length > 0) { + sort.forEach(obj => { + const subObj: any = {}; + subObj[obj.name] = {dir: obj.dir, nulls: 'last'}; + orderBy.push(subObj); + }); + } + + const limit = this.enablePreFetch ? null : pager.limit; + const offset = this.enablePreFetch ? 0 : pager.offset; let observer: Observer; const observable = new Observable(obs => observer = obs); @@ -183,10 +219,7 @@ export class HoldsGridComponent implements OnInit { this.net.request( 'open-ils.circ', 'open-ils.circ.hold.wide_hash.stream', - // Pre-fetch all holds consistent with AngJS version - this.auth.token(), filters, orderBy - // Alternatively, fetch holds in pages. - // this.auth.token(), filters, orderBy, pager.limit, pager.offset + this.auth.token(), filters, orderBy, limit, offset ).subscribe( holdData => { diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql index 184d80c411..3c8a257018 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -19874,7 +19874,6 @@ INSERT INTO config.org_unit_setting_type 'bool' ); - INSERT INTO config.usr_activity_type (id, ewhat, ehow, egroup, enabled, transient, label) VALUES ( @@ -19897,3 +19896,13 @@ VALUES ( oils_i18n_gettext(30, 'Generic Verify', 'cuat', 'label') ); +INSERT INTO config.workstation_setting_type (name, grp, datatype, label) +VALUES ( + 'catalog.record.holds.prefetch', 'cat', 'bool', + oils_i18n_gettext( + 'catalog.record.holds.prefetch', + 'Pre-Fetch Record Holds', + 'cwst', 'label' + ) +); + diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.catalog-holds-prefetch.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.catalog-holds-prefetch.sql new file mode 100644 index 0000000000..8de3ff210e --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.catalog-holds-prefetch.sql @@ -0,0 +1,15 @@ +BEGIN; + +--SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +INSERT INTO config.workstation_setting_type (name, grp, datatype, label) +VALUES ( + 'catalog.record.holds.prefetch', 'cat', 'bool', + oils_i18n_gettext( + 'catalog.record.holds.prefetch', + 'Pre-Fetch Record Holds', + 'cwst', 'label' + ) +); + +COMMIT; -- 2.43.2