From: Bill Erickson <berickxx@gmail.com> Date: Wed, 27 Mar 2019 14:50:36 +0000 (-0400) Subject: LP1821382 Make items bookable (part 2) X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=311d189c820696609dd70fc63d626eee98221d39;p=evergreen%2Fequinox.git LP1821382 Make items bookable (part 2) Including support for passing filters and default context org values to admin page grids. Signed-off-by: Bill Erickson <berickxx@gmail.com> Signed-off-by: Dan Wells <dbw2@calvin.edu> --- diff --git a/Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.ts b/Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.ts index 125d3a0fd2..955e95aa5f 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.ts @@ -1,4 +1,5 @@ import {Component, Input, OnInit, TemplateRef, ViewChild} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; import {IdlService, IdlObject} from '@eg/core/idl.service'; import {GridDataSource} from '@eg/share/grid/grid'; import {GridComponent} from '@eg/share/grid/grid.component'; @@ -90,7 +91,12 @@ export class AdminPageComponent implements OnInit { viewPerms: string; canCreate: boolean; + // Filters may be passed via URL query param. + // They are used to augment the grid data search query. + gridFilters: {[key: string]: string | number}; + constructor( + private route: ActivatedRoute, private idl: IdlService, private org: OrgService, private auth: AuthService, @@ -101,7 +107,7 @@ export class AdminPageComponent implements OnInit { this.translatableFields = []; } - applyOrgValues() { + applyOrgValues(orgId?: number) { if (this.disableOrgFilter) { this.orgField = null; @@ -121,7 +127,7 @@ export class AdminPageComponent implements OnInit { if (this.orgField) { this.orgFieldLabel = this.idlClassDef.field_map[this.orgField].label; - this.contextOrg = this.org.root(); + this.contextOrg = this.org.get(orgId) || this.org.root(); } } @@ -139,6 +145,16 @@ export class AdminPageComponent implements OnInit { this.idlClassDef.table; } + // gridFilters are a JSON encoded string + const filters = this.route.snapshot.queryParamMap.get('gridFilters'); + if (filters) { + try { + this.gridFilters = JSON.parse(filters); + } catch (E) { + console.error('Invalid grid filters provided: ', filters) + } + } + // Limit the view org selector to orgs where the user has // permacrud-encoded view permissions. const pc = this.idlClassDef.permacrud; @@ -146,8 +162,9 @@ export class AdminPageComponent implements OnInit { this.viewPerms = pc.retrieve.perms; } + const contextOrg = this.route.snapshot.queryParamMap.get('contextOrg'); this.checkCreatePerms(); - this.applyOrgValues(); + this.applyOrgValues(Number(contextOrg)); // If the caller provides not data source, create a generic one. if (!this.dataSource) { @@ -288,6 +305,14 @@ export class AdminPageComponent implements OnInit { order_by: orderBy }; + if (!this.contextOrg && !this.gridFilters) { + // No org filter -- fetch all rows + return this.pcrud.retrieveAll( + this.idlClass, searchOps, {fleshSelectors: true}); + } + + const search: any = {}; + if (this.contextOrg) { // Filter rows by those linking to the context org and // optionally ancestor and descendant org units. @@ -304,15 +329,18 @@ export class AdminPageComponent implements OnInit { this.org.descendants(this.contextOrg, true)); } - const search = {}; search[this.orgField] = orgs; - return this.pcrud.search( - this.idlClass, search, searchOps, {fleshSelectors: true}); } - // No org filter -- fetch all rows - return this.pcrud.retrieveAll( - this.idlClass, searchOps, {fleshSelectors: true}); + if (this.gridFilters) { + // Lay the URL grid filters over our search object. + Object.keys(this.gridFilters).forEach(key => { + search[key] = this.gridFilters[key]; + }); + } + + return this.pcrud.search( + this.idlClass, search, searchOps, {fleshSelectors: true}); }; } diff --git a/Open-ILS/src/eg2/src/app/staff/share/booking/make-bookable-dialog.component.html b/Open-ILS/src/eg2/src/app/staff/share/booking/make-bookable-dialog.component.html index cc03fc66dc..25ad596575 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/booking/make-bookable-dialog.component.html +++ b/Open-ILS/src/eg2/src/app/staff/share/booking/make-bookable-dialog.component.html @@ -16,11 +16,22 @@ </button> </div> <div class="modal-body"> - <div class="row"> - <div class="col-lg-12 d-flex justify-content-center"> + <div class="row" *ngIf="!updateComplete"> + <div class="col-lg-12"> <span i18n>Make {{copyIds.length}} Item(s) Bookable?</span> </div> </div> + <div class="row" *ngIf="updateComplete"> + <div class="col-lg-12 d-flex flex-column"> + <div i18n>{{numSucceeded}} Item(s) Made Bookable.</div> + <div class="mt-2"> + <a target="_blank" routerLink="/staff/admin/booking/resource" + [queryParams]="manageUrlParams()" i18n> + Manage Bookable Resources + </a> + </div> + </div> + </div> </div> <div class="modal-footer"> <ng-container> diff --git a/Open-ILS/src/eg2/src/app/staff/share/booking/make-bookable-dialog.component.ts b/Open-ILS/src/eg2/src/app/staff/share/booking/make-bookable-dialog.component.ts index 84d7941467..9df3f9f668 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/booking/make-bookable-dialog.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/booking/make-bookable-dialog.component.ts @@ -1,5 +1,4 @@ -import {Component, OnInit, OnDestroy, Input, ViewChild, - Renderer2} from '@angular/core'; +import {Component, OnInit, OnDestroy, Input, ViewChild} from '@angular/core'; import {Subscription} from 'rxjs'; import {IdlObject} from '@eg/core/idl.service'; import {NetService} from '@eg/core/net.service'; @@ -7,7 +6,7 @@ import {EventService} from '@eg/core/event.service'; import {PcrudService} from '@eg/core/pcrud.service'; import {ToastService} from '@eg/share/toast/toast.service'; import {AuthService} from '@eg/core/auth.service'; -import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap'; +import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; import {DialogComponent} from '@eg/share/dialog/dialog.component'; import {StringComponent} from '@eg/share/string/string.component'; @@ -30,6 +29,8 @@ export class MakeBookableDialogComponent numSucceeded: number; numFailed: number; updateComplete: boolean; + newResourceType: number; + newResourceOrg: number; onOpenSub: Subscription; @@ -42,7 +43,6 @@ export class MakeBookableDialogComponent private net: NetService, private pcrud: PcrudService, private evt: EventService, - private renderer: Renderer2, private auth: AuthService) { super(modal); // required for subclassing } @@ -58,6 +58,54 @@ export class MakeBookableDialogComponent ngOnDestroy() { this.onOpenSub.unsubscribe(); } + + manageUrlParams(): any { + if (this.newResourceOrg) { + return { + gridFilters: JSON.stringify({type: this.newResourceType}), + contextOrg: this.newResourceOrg + }; + } + } + + makeBookable() { + this.newResourceType = null; + + this.net.request( + 'open-ils.booking', + 'open-ils.booking.resources.create_from_copies', + this.auth.token(), this.copyIds + ).toPromise().then( + resp => { + // resp.brsrc = [[brsrc.id, acp.id, existed], ...] + // resp.brt = [[brt.id, brt.peer_record, existed], ...] + const evt = this.evt.parse(resp); + if (evt) { return Promise.reject(evt); } + this.numSucceeded = resp.brsrc.length; + this.newResourceType = resp.brt[0][0]; // new resource ID + this.updateComplete = true; + this.successMsg.current().then(msg => this.toast.success(msg)); + }, + err => Promise.reject(err) + ).then( + ok => { + // Once resource creation is complete, grab the call number + // for the first copy to get the owning library + this.pcrud.retrieve('acp', this.copyIds[0], + {flesh: 1, flesh_fields: {acp: ['call_number']}}) + .toPromise().then(copy => { + this.newResourceOrg = copy.call_number().owning_lib(); + this.updateComplete = true; + }); + }, + err => { + console.error(err); + this.numFailed++; + this.errorMsg.current().then(msg => this.toast.danger(msg)); + this.updateComplete = true; + } + ); + } }