From: Mike Risher Date: Tue, 20 Aug 2019 20:29:23 +0000 (+0000) Subject: lp1840327-standing-penalties-to-angular X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=32f8e25703c3f4c7b370cdaa96d6662441e0518f;p=working%2FEvergreen.git lp1840327-standing-penalties-to-angular Convert standing penalty types admin UI from DOJO to Angular. Name field is read only if the ID is below 100. Doing this involved: - creating a new standing penalty component - using rowFlairCallback functionality in the grid, so that an icon and tooltip is shown for fields where the name cannot be edited - making the ID show up in red text when it is below 100 - adding "readonly Override" functionality to fm-editor, so that some fields of a given type are read only, but others are not Signed-off-by: Mike Risher Changes to be committed: modified: Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.ts modified: Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html modified: Open-ILS/src/eg2/src/app/staff/admin/local/admin-local.module.ts modified: Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts new file: Open-ILS/src/eg2/src/app/staff/admin/local/standing-penalty.component.html new file: Open-ILS/src/eg2/src/app/staff/admin/local/standing-penalty.component.ts --- diff --git a/Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.ts b/Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.ts index a574e5491d..fdd08a7ee0 100644 --- a/Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.ts +++ b/Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.ts @@ -65,6 +65,11 @@ export interface FmFieldOptions { // This only has an affect if the value is true. isReadonly?: boolean; + // If this function is defined, the function will be called + // at render time to see if the field should be marked readonly. + // This supersedes all other isReadonly specifiers. + isReadonlyOverride?: (field: string, record: IdlObject) => boolean; + // Render the field using this custom template instead of chosing // from the default set of form inputs. customTemplate?: CustomFieldTemplate; @@ -331,10 +336,16 @@ export class FmRecordEditorComponent let promise = null; const fieldOptions = this.fieldOptions[field.name] || {}; - - field.readOnly = this.mode === 'view' - || fieldOptions.isReadonly === true - || this.readonlyFieldsList.includes(field.name); + + if (this.mode === 'view') { + field.readOnly = true; + } else if (fieldOptions.isReadonlyOverride) { + field.readOnly = + !fieldOptions.isReadonlyOverride(field.name, this.record); + } else { + field.readOnly = fieldOptions.isReadonly === true + || this.readonlyFieldsList.includes(field.name); + } if (fieldOptions.isRequiredOverride) { field.isRequired = () => { 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 edbb68f7ed..d8109d9603 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 @@ -51,7 +51,7 @@ + routerLink="/staff/admin/local/config/standing_penalty"> + + + + +
+ + + + + + + + +
+ + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/standing-penalty.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/standing-penalty.component.ts new file mode 100644 index 0000000000..f1c4bd582f --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/standing-penalty.component.ts @@ -0,0 +1,160 @@ +import {Pager} from '@eg/share/util/pager'; +import {Component, OnInit, Input, ViewChild} 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 {PcrudService} from '@eg/core/pcrud.service'; +import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component'; +import {StringComponent} from '@eg/share/string/string.component'; +import {ToastService} from '@eg/share/toast/toast.service'; + +@Component({ + templateUrl: './standing-penalty.component.html' +}) + +export class StandingPenaltyComponent implements OnInit { + recId: number; + gridDataSource: GridDataSource; + initDone = false; + cspSource: GridDataSource = new GridDataSource(); + @ViewChild('partsGrid') partsGrid: GridComponent; + @ViewChild('editDialog') editDialog: FmRecordEditorComponent; + @ViewChild('grid') grid: GridComponent; + @ViewChild('successString') successString: StringComponent; + @ViewChild('createString') createString: StringComponent; + @ViewChild('createErrString') createErrString: StringComponent; + @ViewChild('updateFailedString') updateFailedString: StringComponent; + @ViewChild('cspFlairTooltip') private cspFlairTooltip: StringComponent; + + cspRowFlairCallback: (row: any) => GridRowFlairEntry; + + canCreate: boolean; + canDelete: boolean; + deleteSelected: (rows: IdlObject[]) => void; + + permissions: {[name: string]: boolean}; + + // Default sort field, used when no grid sorting is applied. + @Input() sortField: string; + + @Input() idlClass: string = "csp"; + // Size of create/edito dialog. Uses large by default. + @Input() dialogSize: 'sm' | 'lg' = 'lg'; + // Optional comma-separated list of read-only fields + // @Input() readonlyFields: string; + + @Input() set recordId(id: number) { + this.recId = id; + // Only force new data collection when recordId() + // is invoked after ngInit() has already run. + if (this.initDone) { + this.partsGrid.reload(); + } + } + + constructor( + private pcrud: PcrudService, + private toast: ToastService + ) { + this.gridDataSource = new GridDataSource(); + } + + ngOnInit() { + this.initDone = true; + this.cspSource.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('csp', searchOps, {fleshSelectors: true}); + } + + this.cspRowFlairCallback = (row: any): GridRowFlairEntry => { + const flair = {icon: null, title: null}; + if (row.id() < 100) { + flair.icon = 'not_interested'; + flair.title = this.cspFlairTooltip.text; + } + return flair; + } + } + + cspReadonlyOverride = (field: string, copy: IdlObject): boolean => { + if (copy.id() >= 100) { + return true; + } + return false; + } + + cspGridCellClassCallback = (row: any, col: GridColumn): string => { + if (col.name === "id" && row.a[0] < 100) { + return "text-danger"; + } + return ""; + }; + + showEditDialog(standingPenalty: IdlObject): Promise { + this.editDialog.mode = 'update'; + this.editDialog.recId = standingPenalty["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); + } + ); + }); + } + + editSelected(standingPenaltyFields: IdlObject[]) { + // Edit each IDL thing one at a time + const editOneThing = (standingPenalty: IdlObject) => { + if (!standingPenalty) { return; } + + this.showEditDialog(standingPenalty).then( + () => editOneThing(standingPenaltyFields.shift())); + }; + + editOneThing(standingPenaltyFields.shift()); + } + + createNew() { + 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.recId = null; + this.editDialog.record = null; + this.editDialog.open({size: this.dialogSize}).subscribe( + ok => { + this.createString.current() + .then(str => this.toast.success(str)); + this.grid.reload(); + }, + rejection => { + if (!rejection.dismissed) { + this.createErrString.current() + .then(str => this.toast.danger(str)); + } + } + ); + } + +} +