From: Zavier Banks Date: Mon, 9 Dec 2019 20:20:06 +0000 (+0000) Subject: LP 1855781 Circulation Policy Configuration X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=84a0a7b3c44a11cfb56d63c6c5133a0bdc9254be;p=working%2FEvergreen.git LP 1855781 Circulation Policy Configuration I have ported over the circulation policy configuration from dojo to Angular2. Implementing, not only CRUD functionality, but a a componenet for linking sets to specified cirulation policy matchpoints. Signed-off-by: Zavier Banks --- diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html index e051d37c42..3ea4006ac9 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html @@ -20,7 +20,7 @@ + url="/eg2/en-US/staff/admin/local/config/circ_matrix_matchpoint"> diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/circ-matrix-matchpoint.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/circ-matrix-matchpoint.component.html new file mode 100644 index 0000000000..925a022c9a --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/circ-matrix-matchpoint.component.html @@ -0,0 +1,39 @@ + + + + + + + +
+ + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/circ-matrix-matchpoint.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/circ-matrix-matchpoint.component.ts new file mode 100644 index 0000000000..3c6b060deb --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/circ-matrix-matchpoint.component.ts @@ -0,0 +1,211 @@ +import {Pager} from '@eg/share/util/pager'; +import {Component, OnInit, Input, ViewChild, ElementRef} from '@angular/core'; +import {GridComponent} from '@eg/share/grid/grid.component'; +import {GridDataSource, GridColumn, GridRowFlairEntry} from '@eg/share/grid/grid'; +import {IdlObject} from '@eg/core/idl.service'; +import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component'; +import {LinkedCircLimitSetsComponent} from './linked-circ-limit-sets.component'; +import {StringComponent} from '@eg/share/string/string.component'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {ToastService} from '@eg/share/toast/toast.service'; + +@Component({ + templateUrl: './circ-matrix-matchpoint.component.html' +}) + +export class CircMatrixMatchpointComponent implements OnInit { + recId: number; + gridDataSource: GridDataSource; + initDone = false; + dataSource: GridDataSource = new GridDataSource(); + showLinkLimitSets = false; + usedSetLimitList = []; + linkedLimitSets = []; + limitSetNames = {}; + + + @ViewChild('limitSets', { static: false }) limitSets: ElementRef; + @ViewChild('circLimitSets', { static: true }) limitSetsComponent: LinkedCircLimitSetsComponent; + @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent; + @ViewChild('grid', { static: true }) grid: GridComponent; + @ViewChild('successString', { static: true }) successString: StringComponent; + @ViewChild('createString', { static: false }) createString: StringComponent; + @ViewChild('createErrString', { static: false }) createErrString: StringComponent; + @ViewChild('updateFailedString', { static: false }) updateFailedString: StringComponent; + + @Input() idlClass = 'ccmm'; + // Default sort field, used when no grid sorting is applied. + @Input() sortField: string; + + @Input() dialogSize: 'sm' | 'lg' = 'lg'; + + + constructor( + private pcrud: PcrudService, + private toast: ToastService + ) { + this.gridDataSource = new GridDataSource(); + } + + ngOnInit() { + this.initDone = true; + this.dataSource.getRows = (pager: Pager, sort: any[]) => { + const orderBy: any = {}; + if (sort.length) { + // Sort specified from grid + orderBy[this.idlClass] = sort[0].name + ' ' + sort[0].dir; + } else if (this.sortField) { + // Default sort field + orderBy[this.idlClass] = this.sortField; + } + + const searchOps = { + offset: pager.offset, + limit: pager.limit, + order_by: orderBy + }; + return this.pcrud.retrieveAll('ccmm', searchOps, {fleshSelectors: true}); + } + } + + + clearLinkedCircLimitSets() { + this.limitSetsComponent.usedSetLimitList = []; + this.limitSetsComponent.linkedSetList = []; + this.linkedLimitSets = []; + } + + showEditDialog(field: IdlObject): Promise { + this.limitSetsComponent.showLinkLimitSets = true; + this.getLimitSets(field.id()); + this.editDialog.mode = 'update'; + this.editDialog.recordId = field['id'](); + return new Promise((resolve, reject) => { + this.editDialog.open({size: this.dialogSize}).subscribe( + result => { + this.successString.current() + .then(str => this.toast.success(str)); + this.grid.reload(); + resolve(result); + }, + error => { + this.updateFailedString.current() + .then(str => this.toast.danger(str)); + reject(error); + } + ); + const modalBody = document.getElementsByClassName("modal-body"); + modalBody[modalBody.length-1].appendChild(this.limitSets.nativeElement) + }) + } + + editSelected(fields: IdlObject[]) { + // Edit each IDL thing one at a time + const editOneThing = (field: IdlObject) => { + if (!field) { return; } + this.showEditDialog(field).then( + () => editOneThing(fields.shift())); + }; + editOneThing(fields.shift()); + } + + createNew() { + this.getLimitSets(null); + this.limitSetsComponent.showLinkLimitSets = true; + this.editDialog.mode = 'create'; + // We reuse the same editor for all actions. Be sure + // create action does not try to modify an existing record. + this.editDialog.recordId = null; + this.editDialog.record = null; + this.editDialog.open({size: this.dialogSize}).subscribe( + ok => { + this.createString.current() + .then(str => this.toast.success(str)); + this.limitSetsComponent.showLinkLimitSets = false; + this.grid.reload(); + }, + rejection => { + if (!rejection.dismissed) { + this.createErrString.current() + .then(str => this.toast.danger(str)); + } + this.limitSetsComponent.showLinkLimitSets = false; + } + ); + const modalBody = document.getElementsByClassName("modal-body"); + modalBody[modalBody.length-1].appendChild(this.limitSets.nativeElement) + } + + setLimitSets(sets) { + this.linkedLimitSets = sets; + } + + /** + * Runs through the different CRUD operations, specified by the object that is passed into each. + * @param matchpoint + */ + configureLimitSets(matchpoint) { + const linkedSets = this.linkedLimitSets; + Object.keys(linkedSets).forEach((key) =>{ + let ls = linkedSets[key] + if(ls.created) { + this.deleteLimitSets(ls).then(()=>{ + if (ls.isNew && !ls.isDeleted) { + this.pcrud.create(this.createLimitSets(ls.linkedLimitSet,matchpoint)).subscribe(() =>{}) + } else if(!ls.isNew && !ls.isDeleted) { + this.updateLimitSets(ls.linkedLimitSet); + } + }) + } + }) + } + + getLimitSets(id) { + this.pcrud.retrieveAll("ccmlsm").subscribe((res) =>{ + /** + * If the limit set's matchpoint equals the matchpoint given + * by the user, then add that to the set limit list + */ + this.limitSetsComponent.usedSetLimitList.push(res.limit_set()); + if (res.matchpoint() == id) { + this.limitSetsComponent.createFilledLimitSetObject(res) + } + }) + /** + * Retrives all limit set names + */ + this.pcrud.retrieveAll("ccls").subscribe(res =>{ + this.limitSetsComponent.limitSetNames[res.id()] = res.name(); + }) + } + + createLimitSets(limitSet,matchpoint) { + if(typeof matchpoint == "number" || typeof matchpoint == "string") { + limitSet.matchpoint(matchpoint) + } else { + limitSet.matchpoint(matchpoint.id()) + } + return limitSet + } + + updateLimitSets(limitSet) { + this.pcrud.update(limitSet).subscribe(() =>{}) + } + + deleteLimitSets(limitSet) { + return new Promise((resolve, reject) =>{ + if (limitSet.isDeleted) { + if(limitSet.linkedLimitSet.id()) { + this.pcrud.remove(limitSet.linkedLimitSet).subscribe(res =>{ + resolve(); + }) + } else { + resolve(); + } + } else { + resolve(); + } + }) + } +} + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/circ-matrix-matchpoint.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/circ-matrix-matchpoint.module.ts new file mode 100644 index 0000000000..f4299aa7d0 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/circ-matrix-matchpoint.module.ts @@ -0,0 +1,27 @@ +import {NgModule} from '@angular/core'; +import {TreeModule} from '@eg/share/tree/tree.module'; +import {CircMatrixMatchpointRoutingModule} from './routing.module'; +import {AdminCommonModule} from '@eg/staff/admin/common.module'; +import {CircMatrixMatchpointComponent} from './circ-matrix-matchpoint.component' +import {LinkedCircLimitSetsComponent} from './linked-circ-limit-sets.component' + +@NgModule({ + declarations: [ + CircMatrixMatchpointComponent, + LinkedCircLimitSetsComponent + ], + imports: [ + AdminCommonModule, + CircMatrixMatchpointRoutingModule, + TreeModule + ], + exports: [ + ], + providers: [ + ] +}) + +export class CircMatrixMathpointModule { +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/linked-circ-limit-sets.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/linked-circ-limit-sets.component.html new file mode 100644 index 0000000000..1ca4821986 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/linked-circ-limit-sets.component.html @@ -0,0 +1,67 @@ +
+ + + +
+
+ +
+ {{limitSetNames[linkedSetList[i].linkedLimitSet.limit_set()]}} +
+
+
+ +
+ +
+
+
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+
+
+
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/linked-circ-limit-sets.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/linked-circ-limit-sets.component.ts new file mode 100644 index 0000000000..665ceeaf9e --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/linked-circ-limit-sets.component.ts @@ -0,0 +1,100 @@ + +import {Component, OnInit, Input,Output,EventEmitter} from '@angular/core'; +import { IdlService} from '@eg/core/idl.service'; +class LinkedLimitSetObjects { + linkedLimitSet:any; + created:boolean; + isDeleted:boolean; + isNew:boolean; +} + +@Component({ + selector:'linked-circ-limit-sets', + templateUrl: './linked-circ-limit-sets.component.html' +}) + + +export class LinkedCircLimitSetsComponent implements OnInit { + + @Input() usedSetLimitList = []; + @Input() limitSetNames = {}; + @Output() outputLinkedLimitSet: EventEmitter; + linkedSetList = {}; + linkedSet:any; + showLinkLimitSets:boolean + + constructor( + private idl: IdlService + ) { + this.outputLinkedLimitSet = new EventEmitter(); + } + + ngOnInit() {} + + displayLinkedLimitSets() { + this.createEmptyLimitSetObject() + } + + createFilledLimitSetObject(element) { + let newLinkedSetObject = new LinkedLimitSetObjects(); + if(element.fallthrough() == "f") element.fallthrough(false) + if(element.fallthrough() == "t") element.fallthrough(true) + if(element.active() == "f") element.active(false) + if(element.active() == "t") element.active(true) + newLinkedSetObject.linkedLimitSet = element; + newLinkedSetObject.created = true; + newLinkedSetObject.isNew = false; + newLinkedSetObject.isDeleted = false; + this.linkedSetList[this.getObjectKeys().length] = newLinkedSetObject; + } + + createEmptyLimitSetObject() { + let object = this.idl.create("ccmlsm") + let newLinkedSetObject = new LinkedLimitSetObjects(); + newLinkedSetObject.linkedLimitSet = object; + newLinkedSetObject.linkedLimitSet.fallthrough(false); + newLinkedSetObject.linkedLimitSet.active(true); + newLinkedSetObject.isNew = true; + newLinkedSetObject.created = false; + newLinkedSetObject.isDeleted = false; + this.linkedSetList[this.getObjectKeys().length] = newLinkedSetObject; + } + + onChange(object:any) { + this.linkedSet = object; + } + + getObjectKeys() { + if(this.linkedSetList) { + return Object.keys(this.linkedSetList); + } else { + this.linkedSetList = {} + return Object.keys({}) + } + } + + addLinkedSet() { + if (this.linkedSet) { + if( !this.usedSetLimitList.find(element => element == this.linkedSet.id)) { + this.createEmptyLimitSetObject(); + this.linkedSetList[this.getObjectKeys().length-1].linkedLimitSet.limit_set(this.linkedSet.id); + this.linkedSetList[this.getObjectKeys().length-1].created = true; + this.emitLimitSet(); + this.usedSetLimitList.push(this.linkedSet.id) + } + } + } + + emitLimitSet() { + this.outputLinkedLimitSet.emit(this.linkedSetList) + } + + removeLinkedSet(index) { + if(!this.linkedSetList[index].isNew) { + this.usedSetLimitList.splice(index,1); + } + this.linkedSetList[index].isDeleted = true; + this.emitLimitSet(); + } +} + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/routing.module.ts new file mode 100644 index 0000000000..5690d3c1e8 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/circ_matrix_matchpoint/routing.module.ts @@ -0,0 +1,14 @@ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; +import {CircMatrixMatchpointComponent} from './circ-matrix-matchpoint.component' +const routes: Routes = [{ + path: '', + component: CircMatrixMatchpointComponent +}]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) + +export class CircMatrixMatchpointRoutingModule {} \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts index 39c6be7179..0081a3ff1f 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts @@ -23,6 +23,9 @@ const routes: Routes = [{ path: 'config/standing_penalty', component: StandingPenaltyComponent }, { + path: 'config/circ_matrix_matchpoint', + loadChildren: '@eg/staff/admin/local/circ_matrix_matchpoint/circ-matrix-matchpoint.module#CircMatrixMathpointModule' +}, { path: ':schema/:table', component: BasicAdminPageComponent }];