From f444743fff305455b4fde92add6762f3341b96ea Mon Sep 17 00:00:00 2001 From: Galen Charlton Date: Mon, 29 Nov 2021 16:04:16 -0500 Subject: [PATCH] LP#1357037: add sorting option to Angular line item lists This applies to the line item lists in the following new Angular interfaces: - purchase order - selection list - list of line items related to a bib record The available sort options are: - line item ID - title - author - publisher - order identifier (i.e., ISBN, ISSN, and/or UPC) The method open-ils.acq.lineitem.unified_search is now used to retrieve line items to make use of existing sorting functionality. The last sort order used is persistant via a workstation setting Signed-off-by: Galen Charlton Signed-off-by: Ruth Frasur Signed-off-by: Bill Erickson Signed-off-by: Jane Sandberg --- .../acq/lineitem/lineitem-list.component.html | 31 ++++++ .../staff/acq/lineitem/lineitem-list.component.ts | 107 ++++++++++++++------- 2 files changed, 105 insertions(+), 33 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.html b/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.html index c471adef0c..c6413c15ef 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.html +++ b/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.html @@ -87,6 +87,14 @@ +
+ +
+
@@ -127,6 +135,29 @@
+
+
+
+
+ + +
+
+
+
diff --git a/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.ts b/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.ts index 941bc9f07a..0e2caacd03 100644 --- a/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.ts @@ -17,6 +17,22 @@ const DELETABLE_STATES = [ 'new', 'selector-ready', 'order-ready', 'approved', 'pending-order' ]; +const DEFAULT_SORT_ORDER = 'li_id_asc'; +const SORT_ORDER_MAP = { + li_id_asc: { 'order_by': [{'class': 'jub', 'field': 'id', 'direction': 'ASC'}] }, + li_id_desc: { 'order_by': [{'class': 'jub', 'field': 'id', 'direction': 'DESC'}] }, + title_asc: { 'order_by': [{'class': 'acqlia', 'field': 'attr_value', 'direction': 'ASC'}], 'order_by_attr': 'title' }, + title_desc: { 'order_by': [{'class': 'acqlia', 'field': 'attr_value', 'direction': 'DESC'}], 'order_by_attr': 'title' }, + author_asc: { 'order_by': [{'class': 'acqlia', 'field': 'attr_value', 'direction': 'ASC'}], 'order_by_attr': 'author' }, + author_desc: { 'order_by': [{'class': 'acqlia', 'field': 'attr_value', 'direction': 'DESC'}], 'order_by_attr': 'author' }, + publisher_asc: { 'order_by': [{'class': 'acqlia', 'field': 'attr_value', 'direction': 'ASC'}], 'order_by_attr': 'publisher' }, + publisher_desc: { 'order_by': [{'class': 'acqlia', 'field': 'attr_value', 'direction': 'DESC'}], 'order_by_attr': 'publisher' }, + order_ident_asc: { 'order_by': [{'class': 'acqlia', 'field': 'attr_value', 'direction': 'ASC'}], + 'order_by_attr': ['isbn', 'issn', 'upc'] }, + order_ident_desc: { 'order_by': [{'class': 'acqlia', 'field': 'attr_value', 'direction': 'DESC'}], + 'order_by_attr': ['isbn', 'issn', 'upc'] }, +}; + @Component({ templateUrl: 'lineitem-list.component.html', selector: 'eg-lineitem-list', @@ -46,6 +62,10 @@ export class LineitemListComponent implements OnInit { // a lot of repetitive looping. liMarcAttrs: {[id: number]: {[name: string]: IdlObject[]}} = {}; + // sorting and filtering + sortOrder = DEFAULT_SORT_ORDER; + showFilterSort = false; + batchNote: string; noteIsPublic = false; batchSelectPage = false; @@ -56,6 +76,9 @@ export class LineitemListComponent implements OnInit { action = ''; batchFailure: EgEvent; focusLi: number; + firstLoad = true; // using this to ensure that we avoid loading the LI table + // until the page size and sort order WS settings have been fetched + // TODO: route guard might be better @ViewChild('cancelDialog') cancelDialog: CancelDialogComponent; @@ -75,7 +98,9 @@ export class LineitemListComponent implements OnInit { this.route.queryParamMap.subscribe((params: ParamMap) => { this.pager.offset = +params.get('offset'); this.pager.limit = +params.get('limit'); - this.load(); + if (!this.firstLoad) { + this.load(); + } }); this.route.fragment.subscribe((fragment: string) => { @@ -87,13 +112,24 @@ export class LineitemListComponent implements OnInit { this.picklistId = +params.get('picklistId'); this.poId = +params.get('poId'); this.recordId = +params.get('recordId'); - this.load(); + if (!this.firstLoad) { + this.load(); + } }); this.store.getItem('acq.lineitem.page_size').then(count => { this.pager.setLimit(count || 20); - this.load(); + this.store.getItem('acq.lineitem.sort_order').then(sortOrder => { + if (sortOrder && (sortOrder in SORT_ORDER_MAP)) { + this.sortOrder = sortOrder; + } else { + this.sortOrder = DEFAULT_SORT_ORDER; + } + this.load(); + this.firstLoad = false; + }); }); + } pageSizeChange(count: number) { @@ -104,6 +140,18 @@ export class LineitemListComponent implements OnInit { }); } + sortOrderChange(sortOrder: string) { + this.store.setItem('acq.lineitem.sort_order', sortOrder).then(_ => { + this.sortOrder = sortOrder; + if (this.pager.isFirstPage()) { + this.load(); + } else { + this.pager.toFirst(); + this.goToPage(); + } + }); + } + // Focus the selected lineitem, which may not yet exist in the // DOM for focusing. focusLineitem(id?: number) { @@ -136,44 +184,33 @@ export class LineitemListComponent implements OnInit { loadIds(): Promise { this.lineitemIds = []; - let id = this.poId; - let options: any = {flesh_lineitem_ids: true, li_limit: 10000}; - let method = 'open-ils.acq.purchase_order.retrieve'; - let handler = (po) => po.lineitems(); - let sort = true; + const searchTerms = {}; + const opts = { id_list: true, limit: 1000 }; if (this.picklistId) { - - id = this.picklistId; - options = {idlist: true, limit: 1000}; - method = 'open-ils.acq.lineitem.picklist.retrieve.atomic'; - handler = (ids) => ids; - + Object.assign(searchTerms, { jub: [ { picklist: this.picklistId } ] }); } else if (this.recordId) { + Object.assign(searchTerms, { jub: [ { eg_bib_id: this.recordId } ] }); + } else { + Object.assign(searchTerms, { jub: [ { purchase_order: this.poId } ] }); + } - id = this.recordId; - method = 'open-ils.acq.lineitems_for_bib.by_bib_id.atomic'; - options = {idlist: true, limit: 1000}; - handler = (ids) => ids; - // The API sorts the newest to oldest, which is what - // we want here. - sort = false; + if (!(this.sortOrder in SORT_ORDER_MAP)) { + this.sortOrder = DEFAULT_SORT_ORDER; } + Object.assign(opts, SORT_ORDER_MAP[this.sortOrder]); return this.net.request( - 'open-ils.acq', method, this.auth.token(), id, options + 'open-ils.acq', + 'open-ils.acq.lineitem.unified_search.atomic', + this.auth.token(), + searchTerms, // "and" terms + {}, // "or" terms + null, + opts ).toPromise().then(resp => { - const ids = handler(resp); - - if (sort) { - this.lineitemIds = ids - .map(i => Number(i)) - .sort((id1, id2) => id1 < id2 ? -1 : 1); - } else { - this.lineitemIds = ids.map(i => Number(i)); - } - - this.pager.resultCount = ids.length; + this.lineitemIds = resp.map(i => Number(i)); + this.pager.resultCount = resp.length; }); } @@ -423,6 +460,10 @@ export class LineitemListComponent implements OnInit { this.expandAll = !this.expandAll; } + toggleFilterSort() { + this.showFilterSort = !this.showFilterSort; + } + liHasAlerts(li: IdlObject): boolean { return li.lineitem_notes().filter(n => n.alert_text()).length > 0; } -- 2.11.0