From: Bill Erickson Date: Fri, 11 May 2018 20:04:21 +0000 (-0400) Subject: LP#1626157 Grid / billing types continued X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=36635bb6ecf2e5d53a13373814575e1231c1e362;p=working%2FEvergreen.git LP#1626157 Grid / billing types continued Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.html b/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.html index b992adc78b..18623f0e51 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.html +++ b/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.html @@ -1,7 +1,7 @@
- +
# diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.ts b/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.ts index 2b9f00daa1..fc08727136 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.ts +++ b/Open-ILS/src/eg2/src/app/share/grid/grid-header.component.ts @@ -1,7 +1,9 @@ import {Component, Input, OnInit, Host} from '@angular/core'; -import {EgGridService, EgGridColumn, EgGridColumnSet} from './grid.service'; +import {EgGridService, EgGridColumn, + EgGridRowSelector, EgGridColumnSet} from './grid.service'; import {EgGridDataSource} from './grid-data-source'; import {EgGridComponent} from './grid.component'; +import {Pager} from '@eg/share/util/pager'; @Component({ selector: 'eg-grid-header', @@ -11,8 +13,9 @@ import {EgGridComponent} from './grid.component'; export class EgGridHeaderComponent implements OnInit { @Input() columnSet: EgGridColumnSet; - @Input() selected: {[idx:number] : boolean}; + @Input() rowSelector: EgGridRowSelector; @Input() dataSource: EgGridDataSource; + @Input() pager: Pager; dragColumn: EgGridColumn; constructor( @@ -57,5 +60,29 @@ export class EgGridHeaderComponent implements OnInit { let sort = this.dataSource.sort.filter(c => c.name == col.name)[0]; return sort && sort.dir == dir; } + + handleBatchSelect($event) { + if ($event.target.checked) { + if (this.rowSelector.isEmpty() || !this.allRowsAreSelected()) { + // clear selections from other pages to avoid confusion. + this.rowSelector.clear(); + this.selectAll(); + } + } else { + this.rowSelector.clear(); + } + } + + selectAll() { + let rows = this.dataSource.getPageOfRows(this.pager); + let indexes = rows.map(r => this.grid.getRowIndex(r)); + this.rowSelector.select(indexes); + } + + allRowsAreSelected(): boolean { + let rows = this.dataSource.getPageOfRows(this.pager); + let indexes = rows.map(r => this.grid.getRowIndex(r)); + return this.rowSelector.contains(indexes); + } } diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.ts b/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.ts index a7f1913f65..8cc95b97fe 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.ts +++ b/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.ts @@ -27,10 +27,6 @@ export class EgGridToolbarComponent implements OnInit { } ngOnInit() { - - // listen for pagination changes - this.pager.onChange$.subscribe( - val => this.dataSource.requestPage(this.pager)); } saveColumns() { diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid.component.css b/Open-ILS/src/eg2/src/app/share/grid/grid.component.css index 81fb257617..c571b894a9 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid.component.css +++ b/Open-ILS/src/eg2/src/app/share/grid/grid.component.css @@ -17,7 +17,8 @@ .eg-grid-body-row { } -.eg-grid-body-row.selected { +.eg-grid-body-row.selected, +.eg-grid-column-config-dialog .visible { color: #004085; background-color: #cce5ff; border-color: #b8daff; @@ -86,11 +87,3 @@ box-shadow: none; } -.eg-grid-column-config-dialog .visible { - color: #000; - background-color: rgb(201, 221, 225); - border-bottom: 1px solid #888; -} - - - diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid.component.html b/Open-ILS/src/eg2/src/app/share/grid/grid.component.html index 8d5e85366e..52a58d482b 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid.component.html +++ b/Open-ILS/src/eg2/src/app/share/grid/grid.component.html @@ -6,15 +6,17 @@ [toolbarButtons]="toolbarButtons" [toolbarActions]="toolbarActions" [colWidthConfig]="colWidthConfig" persistKey="{{persistKey}}"> - + +
- +
{{pager.rowNumber(idx)}} diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid.component.ts b/Open-ILS/src/eg2/src/app/share/grid/grid.component.ts index 2ca4b43896..aa4ce60997 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid.component.ts +++ b/Open-ILS/src/eg2/src/app/share/grid/grid.component.ts @@ -1,11 +1,12 @@ -import {Component, Input, OnInit, AfterViewInit, EventEmitter, +import {Component, Input, OnInit, AfterViewInit, EventEmitter, OnDestroy HostListener, ViewEncapsulation} from '@angular/core'; +import {Subscription} from "rxjs/Subscription"; import {EgGridDataSource} from './grid-data-source'; import {EgIdlService} from '@eg/core/idl.service'; import {EgOrgService} from '@eg/core/org.service'; import {Pager} from '@eg/share/util/pager'; import {EgGridService, EgGridColumn, EgGridColumnSet, EgGridToolbarButton, - EgGridToolbarAction} from '@eg/share/grid/grid.service'; + EgGridRowSelector, EgGridToolbarAction} from '@eg/share/grid/grid.service'; @Component({ selector: 'eg-grid', @@ -15,7 +16,7 @@ import {EgGridService, EgGridColumn, EgGridColumnSet, EgGridToolbarButton, encapsulation: ViewEncapsulation.None }) -export class EgGridComponent implements OnInit, AfterViewInit { +export class EgGridComponent implements OnInit, AfterViewInit, OnDestroy { @Input() dataSource: EgGridDataSource; @Input() idlClass: string; @@ -26,16 +27,17 @@ export class EgGridComponent implements OnInit, AfterViewInit { pager: Pager; columnSet: EgGridColumnSet; - selector: {[idx:number] : boolean}; + rowSelector: EgGridRowSelector; onRowDblClick$: EventEmitter; onRowClick$: EventEmitter; toolbarButtons: EgGridToolbarButton[]; toolbarActions: EgGridToolbarAction[]; lastSelectedIndex: any; + pageChanges: Subscription; constructor(private gridSvc: EgGridService) { this.pager = new Pager(); - this.selector = {}; + this.rowSelector = new EgGridRowSelector(); this.pager.limit = 10; // TODO config this.onRowDblClick$ = new EventEmitter(); this.onRowClick$ = new EventEmitter(); @@ -56,15 +58,41 @@ export class EgGridComponent implements OnInit, AfterViewInit { this.gridSvc.getColumnsConfig(this.persistKey) .then(conf => this.columnSet.applyColumnSettings(conf)) .then(ok => this.dataSource.requestPage(this.pager)) + .then(ok => this.listenToPager()) + } + + ngOnDestroy() { + this.dontListenToPager(); + } + + // Subscribe or unsubscribe to page-change events from the pager. + listenToPager() { + if (this.pageChanges) return; + this.pageChanges = this.pager.onChange$.subscribe( + val => this.dataSource.requestPage(this.pager)); + } + + dontListenToPager() { + if (!this.pageChanges) return; + this.pageChanges.unsubscribe(); + this.pageChanges = null } // Grid keyboard navigation handlers. @HostListener('window:keydown', ['$event']) onKeyDown(evt: KeyboardEvent) { if (evt.key == 'ArrowUp') { this.selectPreviousRow(); + } else if (evt.key == 'ArrowDown') { this.selectNextRow(); + + } else if (evt.key == 'ArrowLeft') { + this.toPrevPage().then(ok => this.selectFirstRow(), err => {}); + } else if (evt.key == 'ArrowRight') { + this.toNextPage().then(ok => this.selectFirstRow(), err => {}); + + } else if (evt.key == 'Enter') { if (this.lastSelectedIndex) this.onRowDblClick(this.getRowByIndex(this.lastSelectedIndex)); } @@ -106,9 +134,8 @@ export class EgGridComponent implements OnInit, AfterViewInit { // currently visible in the grid display. getSelectedRows(): any[] { let selected = []; - Object.keys(this.selector).forEach(index => { - let row = this.dataSource.data.filter( - r => this.getRowIndex(r) == index)[0]; + this.rowSelector.selected().forEach(index => { + let row = this.getRowByIndex(index); if (row) selected.push(row); }); return selected; @@ -138,61 +165,74 @@ export class EgGridComponent implements OnInit, AfterViewInit { } selectOneRow(index: any) { - this.selector = {}; - this.selector[index] = true; + this.rowSelector.clear(); + this.rowSelector.select(index); this.lastSelectedIndex = index; } // selects or deselects an item, without affecting the others. // returns true if the item is selected; false if de-selected. toggleSelectOneRow(index: any) { - if (this.selector[index]) { - delete this.selector[index]; + if (this.rowSelector.contains(index)) { + this.rowSelector.deselect(index); return false; } - this.selector[index] = true; + this.rowSelector.select(index); return true; } - + selectRowByPos(pos: number) { + let row = this.dataSource.data[pos]; + if (row) this.selectOneRow(this.getRowIndex(row)); + } selectPreviousRow() { if (!this.lastSelectedIndex) return; let pos = this.getRowPosition(this.lastSelectedIndex); - if (pos == 0) return; if (pos == this.pager.offset) { - // Request the previous page of data - this.pager.decrement(); - this.dataSource.requestPage(this.pager) - .then(ok => { - let row = this.dataSource.data[pos - 1]; - if (row) this.selectOneRow(this.getRowIndex(row)); - }); + this.toPrevPage().then(ok => this.selectLastRow(), err => {}); } else { - let row = this.dataSource.data[pos - 1]; - this.selectOneRow(this.getRowIndex(row)); + this.selectRowByPos(pos - 1); } } selectNextRow() { if (!this.lastSelectedIndex) return; let pos = this.getRowPosition(this.lastSelectedIndex); - if (pos == (this.pager.offset + this.pager.limit - 1)) { - // Request the next page of data - this.pager.increment(); - this.dataSource.requestPage(this.pager) - .then(ok => { - let row = this.dataSource.data[pos + 1]; - if (row) this.selectOneRow(this.getRowIndex(row)); - }); + this.toNextPage().then(ok => this.selectFirstRow(), err => {}); } else { - let row = this.dataSource.data[pos + 1]; - if (row) this.selectOneRow(this.getRowIndex(row)); + this.selectRowByPos(pos + 1); } } + selectFirstRow() { + this.selectRowByPos(this.pager.offset); + } + + selectLastRow() { + this.selectRowByPos(this.pager.offset + this.pager.limit - 1); + } + + toPrevPage(): Promise { + if (this.pager.isFirstPage()) return Promise.reject('on first'); + // temp ignore pager events since we're calling requestPage manually. + this.dontListenToPager(); + this.pager.decrement(); + this.listenToPager(); + return this.dataSource.requestPage(this.pager); + } + + toNextPage(): Promise { + if (this.pager.isLastPage()) return Promise.reject('on last'); + // temp ignore pager events since we're calling requestPage manually. + this.dontListenToPager(); + this.pager.increment(); + this.listenToPager(); + return this.dataSource.requestPage(this.pager); + } } + diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid.service.ts b/Open-ILS/src/eg2/src/app/share/grid/grid.service.ts index 14914545cf..17703f36e3 100644 --- a/Open-ILS/src/eg2/src/app/share/grid/grid.service.ts +++ b/Open-ILS/src/eg2/src/app/share/grid/grid.service.ts @@ -285,3 +285,44 @@ export class EgGridToolbarButton { action: () => any; } +export class EgGridRowSelector { + indexes: {[string:string] : boolean}; + + constructor() { + this.clear(); + } + + // Returns true if all of the requested indexes exist in the selector. + contains(index: string | string[]): boolean { + let indexes = [].concat(index); + let selected = Object.keys(this.indexes); + for (let i = 0; i < indexes.length; i++) { // early exit + if (!selected.includes(indexes[i])) + return false; + } + return true; + } + + select(index: string | string[]) { + let indexes = [].concat(index); + indexes.forEach(i => this.indexes[i] = true); + } + + deselect(index: string | string[]) { + let indexes = [].concat(index); + indexes.forEach(i => delete this.indexes[i]); + } + + selected() { + return Object.keys(this.indexes); + } + + isEmpty(): boolean { + return this.selected().length == 0; + } + + clear() { + this.indexes = {}; + } +} + diff --git a/Open-ILS/src/eg2/src/app/share/util/pager.ts b/Open-ILS/src/eg2/src/app/share/util/pager.ts index 524e1787b7..6d420b8ecf 100644 --- a/Open-ILS/src/eg2/src/app/share/util/pager.ts +++ b/Open-ILS/src/eg2/src/app/share/util/pager.ts @@ -10,6 +10,7 @@ export class Pager { onChange$: EventEmitter; constructor() { + this.resultCount = null; this.onChange$ = new EventEmitter(); } @@ -49,6 +50,7 @@ export class Pager { } pageCount(): number { + if (this.resultCount === null) return -1; let pages = this.resultCount / this.limit; if (Math.floor(pages) < pages) pages = Math.floor(pages) + 1; diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/config/billing_type.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/server/config/billing_type.component.ts index 91d37a5bcd..4f19a2c40c 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/server/config/billing_type.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/admin/server/config/billing_type.component.ts @@ -22,6 +22,8 @@ export class BillingTypeComponent implements OnInit { @ViewChild('successString') successString: EgStringComponent; @ViewChild('createString') createString: EgStringComponent; contextOrg: EgIdlObject; + createBillingType: () => void; + deleteSelected: (rows: any) => void; constructor( private org: EgOrgService, @@ -32,30 +34,11 @@ export class BillingTypeComponent implements OnInit { this.dataSource = new EgGridDataSource(); } - orgOnChange(org: EgIdlObject) { - console.log('orgOnChange called ' + org.id()); this.contextOrg = org; this.btGrid.reload(); } - createBillingType() { - this.btEditDialog.mode = 'create'; - this.btEditDialog.open().then( - ok => { - this.createString.current() - .then(str => this.toast.success(str)); - this.btGrid.reload(); - }, - err => { } - ); - } - - deleteSelected(billingTypes) { - console.log('deleting...'); - console.log(billingTypes); - } - ngOnInit() { this.contextOrg = this.org.get(this.auth.user().ws_ou()); @@ -87,6 +70,27 @@ export class BillingTypeComponent implements OnInit { ); } ); + + this.createBillingType = () => { + this.btEditDialog.mode = 'create'; + this.btEditDialog.open().then( + ok => { + this.createString.current() + .then(str => this.toast.success(str)); + this.btGrid.reload(); + }, + err => { } + ); + } + + this.deleteSelected = (billingTypes) => { + billingTypes.forEach(bt => bt.isdeleted(true)); + this.pcrud.autoApply(billingTypes).subscribe( + val => console.debug('deleted: ' + val), + err => {}, + () => this.btGrid.reload() + ); + } } }