<eg-link-table-link i18n-label label="Circulation Limit Sets"
url="/eg/staff/admin/local/config/circ_limit_set"></eg-link-table-link>
<eg-link-table-link i18n-label label="Circulation Policies"
- url="/eg/staff/admin/local/config/circ_matrix_matchpoint"></eg-link-table-link>
+ url="/eg2/en-US/staff/admin/local/config/circ_matrix_matchpoint"></eg-link-table-link>
<eg-link-table-link i18n-label label="Closed Dates Editor"
url="/eg/staff/admin/local/actor/closed_dates"></eg-link-table-link>
<!-- do-able with a list of IDL classes to add to the edit dialog -->
--- /dev/null
+<eg-title i18n-prefix prefix="Circulation Policy Configuration"></eg-title>
+<eg-staff-banner bannerText="Circulation Policy Configuration" i18n-bannerText>
+</eg-staff-banner>
+
+<eg-string #successString i18n-text text="Circulation Policy Update Succeeded"></eg-string>
+<eg-string #createString i18n-text text="Circulation Policy Creation Succeeded"></eg-string>
+
+<div #limitSets>
+ <ng-container >
+ <linked-circ-limit-sets
+ #circLimitSets
+ (outputLinkedLimitSet)="setLimitSets($event)" >
+ </linked-circ-limit-sets>
+ </ng-container>
+</div>
+
+<eg-grid #grid idlClass="ccmm"
+ [dataSource]="dataSource"
+ [sortable]="true"
+ (onRowActivate)="editSelected([$event])"
+ [showFields]='"is_renewal,active,org_unit,copy_circ_lib,copy_owning_lib,user_home_ou"'
+ >
+ <eg-grid-toolbar-button
+ label="New Circ Matrix Matchpoint" i18n-label (onClick)="createNew()">
+ </eg-grid-toolbar-button>
+ <eg-grid-toolbar-action label="Edit Selected" i18n-label (onClick)="editSelected($event)">
+ </eg-grid-toolbar-action>
+ </eg-grid>
+
+
+<eg-fm-record-editor #editDialog
+ idlClass="ccmm"
+ [preloadLinkedValues]="true"
+ readonlyFields="name"
+ (recordSaved)="configureLimitSets($event); clearLinkedCircLimitSets()"
+ (recordCanceled)="clearLinkedCircLimitSets()"
+ (recordError)="clearLinkedCircLimitSets()"
+ >
+</eg-fm-record-editor>
\ No newline at end of file
--- /dev/null
+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<any> {
+ 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();
+ }
+ })
+ }
+}
+
--- /dev/null
+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 {
+}
+
+
--- /dev/null
+<div *ngIf="showLinkLimitSets">
+ <div class="col-lg-15 modal-header bg-info d-flex justify-content-center"><h3 class="modal-title mt-3 mb-3">Linked Limit Sets</h3></div>
+ <ng-container *ngIf="getObjectKeys().length > 0">
+ <ng-container *ngFor="let key of getObjectKeys(); let i = index">
+ <div *ngIf="!linkedSetList[i].isDeleted" class="col-lg-15 d-flex justify-content-center">
+ <div *ngIf="linkedSetList[i].created" class="col-lg-2 mt-3 mb-3 form-group form-check">
+ <label for="name">Name</label>
+ <div class="d-flex justify-content-center">
+ <span>{{limitSetNames[linkedSetList[i].linkedLimitSet.limit_set()]}}</span>
+ </div>
+ </div>
+ <div *ngIf="linkedSetList[i].created" class="col-lg-2 mt-3 mb-3 form-group form-check">
+ <label for="{{fallthrough+i}}">Fallthrough</label>
+ <div class="d-flex justify-content-center">
+ <input
+ class="form-check-input"
+ type="checkbox"
+ name="{{fallthrough+i}}"
+ [ngModel]="linkedSetList[i].linkedLimitSet.fallthrough()"
+ (ngModelChange)="linkedSetList[i].linkedLimitSet.fallthrough($event); this.emitLimitSet();"/>
+ </div>
+ </div>
+ <div *ngIf="linkedSetList[i].created" class="col-lg-2 mt-3 mb-3 form-group form-check">
+ <label for="{{active+i}}">Active</label>
+ <div class="d-flex justify-content-center">
+ <input
+ class="form-check-input"
+ type="checkbox"
+ [ngModel]="linkedSetList[i].linkedLimitSet.active()"
+ (ngModelChange)="linkedSetList[i].linkedLimitSet.active($event); this.emitLimitSet();"/>
+ </div>
+
+ </div>
+ <div *ngIf="linkedSetList[i].created" class="col-lg-2 mt-3 mb-3 form-group form-check">
+ <button
+ type="button"
+ class="btn btn-warning"
+ ng-disabled="!linkedSet"
+ (click)="removeLinkedSet(i)"
+ i18n-title title="Remove">Remove
+ </button>
+ </div>
+ </div>
+ </ng-container>
+ </ng-container>
+ <div class="input-group mt-3">
+ <div class="input-group-prepends col-lg-9">
+ <div class="input-group-text col-lg-4">
+ <label for="linkedLimitName" i18n>Circ Limit Set Name </label>
+ </div>
+ <eg-combobox
+ name="linkedLimitName"
+ idlClass="ccls"
+ idlField="name"
+ (onChange)="onChange($event)">
+ </eg-combobox>
+ <div>
+ <button
+ type="button"
+ class="btn btn-info"
+ (click)="addLinkedSet()"
+ i18n-title title="Add">Add
+ </button>
+ </div>
+ </div>
+ </div>
+</div>
--- /dev/null
+
+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<any>;
+ 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();
+ }
+}
+
--- /dev/null
+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
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
}];