From a8bbbae3086e98dc92f772884f7ce9c0b953449e Mon Sep 17 00:00:00 2001 From: Kyle Huckins Date: Tue, 13 Aug 2019 15:07:07 +0000 Subject: [PATCH] lp1839341 Port Org Setting Editor UI - Speedy Retrieval for display all Org Unit Settings (~6 seconds instead of DOJO's 20) - Implement org_unit.settings.history.retrieve API Call utilizing CSTORE operations - View and revert OU settings to specific changes - Update Org Unit Setting context orgs and values - Filtering of Org Unit Settings by string found in name, description, label, and/or group fields of Org Unit settings - Get history in properly descending order based on date_applied field - Strip surrounding quotes from new values in history log - Add columns for Edit and History actions. - Add sql changes to support workstation setting for org unit settings grid - Port Import/Export Dialog for batch-modifying settings using a JSON string. Signed-off-by: Kyle Huckins Changes to be committed: modified: Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html new file: Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.html new file: Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.ts new file: Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component.html new file: Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component.ts new file: Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component.html new file: Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component.ts new file: Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings-routing.module.ts new file: Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.component.html new file: Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.component.ts new file: Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.module.ts modified: Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts modified: Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm modified: Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm modified: Open-ILS/src/sql/Pg/950.data.seed-values.sql new file: Open-ILS/src/sql/Pg/upgrade/XXXX.data.ouSettings-grid-ws-settings.sql Signed-off-by: Jane Sandberg Signed-off-by: Bill Erickson Signed-off-by: Terran McCanna Signed-off-by: Jane Sandberg --- .../admin/local/admin-local-splash.component.html | 2 +- .../edit-org-unit-setting-dialog.component.html | 152 +++++++++ .../edit-org-unit-setting-dialog.component.ts | 60 ++++ .../org-unit-setting-history-dialog.component.html | 39 +++ .../org-unit-setting-history-dialog.component.ts | 67 ++++ .../org-unit-setting-json-dialog.component.html | 32 ++ .../org-unit-setting-json-dialog.component.ts | 28 ++ .../org-unit-settings-routing.module.ts | 15 + .../org-unit-settings.component.html | 84 +++++ .../org-unit-settings.component.ts | 368 +++++++++++++++++++++ .../org-unit-settings/org-unit-settings.module.ts | 29 ++ .../src/app/staff/admin/local/routing.module.ts | 5 +- .../src/perlmods/lib/OpenILS/Application/Actor.pm | 27 ++ .../perlmods/lib/OpenILS/Application/AppUtils.pm | 58 +++- Open-ILS/src/sql/Pg/950.data.seed-values.sql | 6 + .../XXXX.data.ouSettings-grid-ws-settings.sql | 15 + 16 files changed, 978 insertions(+), 9 deletions(-) create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings-routing.module.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.module.ts create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.data.ouSettings-grid-ws-settings.sql 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 29e42ef375..e527e3b280 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 @@ -47,7 +47,7 @@ + routerLink="/staff/admin/local/asset/org_unit_settings"> + + + + + + + {{r.label}} + \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.ts new file mode 100644 index 0000000000..ce2add0a8a --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.ts @@ -0,0 +1,60 @@ +import {Component, Input, ViewChild, TemplateRef} from '@angular/core'; +import {DialogComponent} from '@eg/share/dialog/dialog.component'; +import {AuthService} from '@eg/core/auth.service'; +import {NetService} from '@eg/core/net.service'; +import {OrgService} from '@eg/core/org.service'; +import {IdlObject} from '@eg/core/idl.service'; +import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap'; +import {OrgUnitSetting} from '@eg/staff/admin/local/org-unit-settings/org-unit-settings.component'; + +@Component({ + selector: 'eg-admin-edit-org-unit-setting-dialog', + templateUrl: './edit-org-unit-setting-dialog.component.html' +}) + +export class EditOuSettingDialogComponent extends DialogComponent { + + // What OU Setting we're editing + entry: any = {}; + entryValue: any; + entryContext: IdlObject; + linkedFieldOptions: IdlObject[]; + + constructor( + private auth: AuthService, + private net: NetService, + private org: OrgService, + private modal: NgbModal + ) { + super(modal); + if (!this.entry) { + this.entryValue = null; + this.entryContext = null; + this.linkedFieldOptions = null; + } + } + + inputType() { + return this.entry.dataType; + } + + setInputValue(inputValue) { + console.log("In Input value"); + console.log(inputValue); + this.entryValue = inputValue; + } + + getFieldClass() { + return this.entry.fm_class; + } + + delete() { + this.close({setting: {[this.entry.name]: null}, context: this.entryContext}); + } + + update() { + this.close({setting: {[this.entry.name]: this.entryValue}, context: this.entryContext}); + } +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component.html new file mode 100644 index 0000000000..082fdf2694 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component.html @@ -0,0 +1,39 @@ + + + + + + + Revert + + + + \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component.ts new file mode 100644 index 0000000000..62823d3340 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component.ts @@ -0,0 +1,67 @@ +import {Component, Input, ViewChild, OnInit, TemplateRef} from '@angular/core'; +import {Observable, Observer, of} from 'rxjs'; +import {DialogComponent} from '@eg/share/dialog/dialog.component'; +import {AuthService} from '@eg/core/auth.service'; +import {NetService} from '@eg/core/net.service'; +import {OrgService} from '@eg/core/org.service'; +import {Pager} from '@eg/share/util/pager'; +import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap'; +import {GridDataSource} from '@eg/share/grid/grid'; +import {GridComponent} from '@eg/share/grid/grid.component'; +import {GridToolbarCheckboxComponent + } from '@eg/share/grid/grid-toolbar-checkbox.component'; +import {OrgUnitSetting} from '@eg/staff/admin/local/org-unit-settings/org-unit-settings.component'; + +@Component({ + selector: 'eg-admin-ou-setting-history-dialog', + templateUrl: './org-unit-setting-history-dialog.component.html' +}) + +export class OuSettingHistoryDialogComponent extends DialogComponent { + + entry: any = {}; + history: any[] = []; + gridDataSource: GridDataSource; + @ViewChild('historyGrid', { static:true }) historyGrid: GridComponent; + + + constructor( + private auth: AuthService, + private net: NetService, + private org: OrgService, + private modal: NgbModal + ) { + super(modal); + this.gridDataSource = new GridDataSource(); + } + + ngOnInit() { + this.gridDataSource.getRows = (pager: Pager, sort: any[]) => { + return this.fetchHistory(pager); + }; + } + + fetchHistory(pager: Pager): Observable { + return new Observable(observer => { + this.gridDataSource.data = this.history; + observer.complete(); + }); + } + + revert(log) { + if (log) { + var intTypes = ["integer", "currency", "link"]; + if (intTypes.includes(this.entry.dataType)) { + log.new_value = parseInt(log.new_value); + } else { + log.new_value = log.new_value.replace(/^"(.*)"$/, '$1'); + } + this.close({ + setting: {[this.entry.name]: log.new_value}, + context: this.org.get(log.org), + revert: true + }); + this.gridDataSource.data = null; + } + } +} \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component.html new file mode 100644 index 0000000000..2158174b1e --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component.html @@ -0,0 +1,32 @@ + + + + \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component.ts new file mode 100644 index 0000000000..f2eb3aa01a --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component.ts @@ -0,0 +1,28 @@ +import {Component, Input, ViewChild, TemplateRef} from '@angular/core'; +import {DialogComponent} from '@eg/share/dialog/dialog.component'; +import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap'; +import {OrgUnitSetting} from '@eg/staff/admin/local/org-unit-settings/org-unit-settings.component'; + +@Component({ + selector: 'eg-admin-ou-setting-json-dialog', + templateUrl: './org-unit-setting-json-dialog.component.html' +}) + +export class OuSettingJsonDialogComponent extends DialogComponent { + + isExport: boolean; + @Input() jsonData: string; + + constructor( + private modal: NgbModal + ) { + super(modal); + } + + update() { + this.close({ + apply: true, + jsonData: this.jsonData + }); + } +} \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings-routing.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings-routing.module.ts new file mode 100644 index 0000000000..c80ffdb9bf --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings-routing.module.ts @@ -0,0 +1,15 @@ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; +import {OrgUnitSettingsComponent} from './org-unit-settings.component'; + +const routes: Routes = [{ + path: '', + component: OrgUnitSettingsComponent +}]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) + +export class OrgUnitSettingsRoutingModule {} \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.component.html new file mode 100644 index 0000000000..1da8149d3a --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.component.html @@ -0,0 +1,84 @@ + + + + + + + + + + + + + +
+
+
+
+
Context Location
+ + +
+
+
+
+
+ + + +
+
+
+
+ + +
+
+ +
+ +
+ + + + + + + + + + +
+ + + + + Edit + + + + + + + + History + + + \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.component.ts new file mode 100644 index 0000000000..9422b62917 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.component.ts @@ -0,0 +1,368 @@ +import {Component, OnInit, Input, ViewChild, ViewEncapsulation + } from '@angular/core'; +import {Router} from '@angular/router'; +import {Observable, Observer, of} from 'rxjs'; +import {map} from 'rxjs/operators'; +import {Pager} from '@eg/share/util/pager'; +import {IdlObject, IdlService} from '@eg/core/idl.service'; +import {OrgService} from '@eg/core/org.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {AuthService} from '@eg/core/auth.service'; +import {NetService} from '@eg/core/net.service'; +import {GridDataSource} from '@eg/share/grid/grid'; +import {GridComponent} from '@eg/share/grid/grid.component'; +import {GridToolbarCheckboxComponent + } from '@eg/share/grid/grid-toolbar-checkbox.component'; +import {StoreService} from '@eg/core/store.service'; +import {ServerStoreService} from '@eg/core/server-store.service'; +import {ToastService} from '@eg/share/toast/toast.service'; + +import {EditOuSettingDialogComponent + } from '@eg/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component'; +import {OuSettingHistoryDialogComponent + } from '@eg/staff/admin/local/org-unit-settings/org-unit-setting-history-dialog.component'; +import {OuSettingJsonDialogComponent + } from '@eg/staff/admin/local/org-unit-settings/org-unit-setting-json-dialog.component'; + +export class OrgUnitSetting { + name: string; + label: string; + grp: string; + description: string; + value: any; + value_str: any; + dataType: string; + fmClass: string; + _idlOptions: IdlObject[]; + _org_unit: IdlObject; + context: string; + view_perm: string; + _history: any[]; +} + +@Component({ + templateUrl: './org-unit-settings.component.html' +}) + +export class OrgUnitSettingsComponent { + + contextOrg: IdlObject; + + initDone = false; + gridDataSource: GridDataSource; + gridTemplateContext: any; + prevFilter: string; + currentHistory: any[]; + currentOptions: any[]; + jsonFieldData: {}; + @ViewChild('orgUnitSettingsGrid', { static:true }) orgUnitSettingsGrid: GridComponent; + + @ViewChild('editOuSettingDialog', { static:true }) + private editOuSettingDialog: EditOuSettingDialogComponent; + @ViewChild('orgUnitSettingHistoryDialog', { static:true }) + private orgUnitSettingHistoryDialog: OuSettingHistoryDialogComponent; + @ViewChild('ouSettingJsonDialog', { static:true }) + private ouSettingJsonDialog: OuSettingJsonDialogComponent; + + refreshSettings: boolean; + renderFromPrefs: boolean; + + settingTypeArr: any[]; + + @Input() filterString: string; + + constructor( + private router: Router, + private org: OrgService, + private idl: IdlService, + private pcrud: PcrudService, + private auth: AuthService, + private store: ServerStoreService, + private localStore: StoreService, + private toast: ToastService, + private net: NetService, + ) { + this.gridDataSource = new GridDataSource(); + this.refreshSettings = true; + this.renderFromPrefs = true; + + this.contextOrg = this.org.get(this.auth.user().ws_ou()); + } + + ngOnInit() { + this.initDone = true; + this.settingTypeArr = []; + this.gridDataSource.getRows = (pager: Pager, sort: any[]) => { + return this.fetchSettingTypes(pager); + }; + } + + fetchSettingTypes(pager: Pager): Observable { + return new Observable(observer => { + this.pcrud.retrieveAll('coust', {flesh: 3, flesh_fields: { + 'coust': ['grp', 'view_perm'] + }}, + { authoritative: true }).subscribe( + settingTypes => this.allocateSettingTypes(settingTypes), + err => {}, + () => { + this.refreshSettings = false; + this.mergeSettingValues().then( + ok => { + this.flattenSettings(observer); + } + ); + } + ); + }); + } + + mergeSettingValues(): Promise { + const settingNames = this.settingTypeArr.map(setting => setting.name); + return new Promise((resolve, reject) => { + this.net.request( + 'open-ils.actor', + 'open-ils.actor.ou_setting.ancestor_default.batch', + this.contextOrg.id(), settingNames, this.auth.token() + ).subscribe( + blob => { + let settingVals = Object.keys(blob).map(key => { + return {'name': key, 'setting': blob[key]} + }); + settingVals.forEach(key => { + if (key.setting) { + let settingsObj = this.settingTypeArr.filter( + setting => setting.name == key.name + )[0]; + settingsObj.value = key.setting.value; + settingsObj.value_str = settingsObj.value; + if (settingsObj.dataType == 'link' && (key.setting.value || key.setting.value == 0)) { + this.fetchLinkedField(settingsObj.fmClass, key.setting.value, settingsObj.value_str).then(res => { + settingsObj.value_str = res; + }); + } + settingsObj._org_unit = this.org.get(key.setting.org); + settingsObj.context = settingsObj._org_unit.shortname(); + } + }); + resolve(this.settingTypeArr); + }, + err => reject(err) + ); + }); + } + + fetchLinkedField(fmClass, id, val) { + return new Promise((resolve, reject) => { + return this.pcrud.retrieve(fmClass, id).subscribe(linkedField => { + val = linkedField.name(); + resolve(val); + }); + }); + } + + fetchHistory(setting): Promise { + let name = setting.name; + return new Promise((resolve, reject) => { + this.net.request( + 'open-ils.actor', + 'open-ils.actor.org_unit.settings.history.retrieve', + this.auth.token(), name, this.contextOrg.id() + ).subscribe(res=> { + this.currentHistory = []; + if (!Array.isArray(res)) { + res = [res]; + } + res.forEach(log => { + log.org = this.org.get(log.org); + log.new_value_str = log.new_value; + log.original_value_str = log.original_value; + if (setting.dataType == "link") { + if (log.new_value) { + this.fetchLinkedField(setting.fmClass, parseInt(log.new_value), log.new_value_str).then(val => { + log.new_value_str = val; + }); + } + if (log.original_value) { + this.fetchLinkedField(setting.fmClass, parseInt(log.original_value), log.original_value_str).then(val => { + log.original_value_str = val; + }); + } + } + if (log.new_value_str) log.new_value_str = log.new_value_str.replace(/^"(.*)"$/, '$1'); + if (log.original_value_str) log.original_value_str = log.original_value_str.replace(/^"(.*)"$/, '$1'); + }); + this.currentHistory = res; + this.currentHistory.sort((a, b) => { + return a.date_applied < b.date_applied ? 1 : -1; + }); + + resolve(this.currentHistory); + }, err=>{reject(err);}); + }); + } + + allocateSettingTypes(coust: IdlObject) { + let entry = new OrgUnitSetting(); + entry.name = coust.name(); + entry.label = coust.label(); + entry.dataType = coust.datatype(); + if (coust.fm_class()) entry.fmClass = coust.fm_class(); + if (coust.description()) entry.description = coust.description(); + // For some reason some setting types don't have a grp, should look into this... + if (coust.grp()) entry.grp = coust.grp().label(); + if (coust.view_perm()) + entry.view_perm = coust.view_perm().code(); + + this.settingTypeArr.push(entry); + } + + flattenSettings(observer: Observer) { + this.gridDataSource.data = this.settingTypeArr; + observer.complete(); + } + + contextOrgChanged(org: IdlObject) { + this.updateGrid(org); + } + + applyFilter(clear?: boolean) { + if (clear) this.filterString = ''; + this.updateGrid(this.contextOrg); + } + + updateSetting(obj, entry) { + this.net.request( + 'open-ils.actor', + 'open-ils.actor.org_unit.settings.update', + this.auth.token(), obj.context.id(), obj.setting + ).toPromise().then(res=> { + this.toast.success(entry.label + " Updated."); + if (!obj.setting[entry.name]) { + let settingsObj = this.settingTypeArr.filter( + setting => setting.name == entry.name + )[0]; + settingsObj.value = null; + settingsObj._org_unit = null; + settingsObj.context = null; + } + this.mergeSettingValues(); + }, + err => { + this.toast.danger(entry.label + " failed to update: " + err.desc); + }); + } + + showEditSettingValueDialog(entry: OrgUnitSetting) { + this.editOuSettingDialog.entry = entry; + this.editOuSettingDialog.entryValue = entry.value; + this.editOuSettingDialog.entryContext = entry._org_unit || this.contextOrg; + this.editOuSettingDialog.open({size: 'lg'}).subscribe( + res => { + this.updateSetting(res, entry); + } + ); + } + + showHistoryDialog(entry: OrgUnitSetting) { + if (entry) { + this.fetchHistory(entry).then( + fetched => { + this.orgUnitSettingHistoryDialog.history = this.currentHistory; + this.orgUnitSettingHistoryDialog.gridDataSource.data = this.currentHistory; + this.orgUnitSettingHistoryDialog.entry = entry; + this.orgUnitSettingHistoryDialog.open({size: 'lg'}).subscribe(res => { + if (res.revert) { + this.updateSetting(res, entry); + } + }); + } + ) + } + } + + showJsonDialog(isExport: boolean) { + this.ouSettingJsonDialog.isExport = isExport; + this.ouSettingJsonDialog.jsonData = ""; + if (isExport) { + this.ouSettingJsonDialog.jsonData = "{"; + this.gridDataSource.data.forEach(entry => { + this.ouSettingJsonDialog.jsonData += + "\"" + entry.name + "\": {\"org\": \"" + + this.contextOrg.id() + "\", \"value\": "; + if (entry.value) { + this.ouSettingJsonDialog.jsonData += "\"" + entry.value + "\""; + } else { + this.ouSettingJsonDialog.jsonData += "null"; + } + this.ouSettingJsonDialog.jsonData += "}"; + if (this.gridDataSource.data.indexOf(entry) != (this.gridDataSource.data.length - 1)) + this.ouSettingJsonDialog.jsonData += ","; + }); + this.ouSettingJsonDialog.jsonData += "}"; + } + + this.ouSettingJsonDialog.open({size: 'lg'}).subscribe(res => { + if (res.apply && res.jsonData) { + let jsonSettings = JSON.parse(res.jsonData); + Object.entries(jsonSettings).forEach((fields) => { + let entry = this.settingTypeArr.find(x => x.name == fields[0]); + let obj = {setting: {}, context: {}}; + let val = this.parseValType(fields[1]['value'], entry.dataType); + obj.setting[fields[0]] = val; + obj.context = this.org.get(fields[1]['org']); + this.updateSetting(obj, entry); + }); + } + }); + } + + parseValType(value, dataType) { + if (dataType == "integer" || "currency" || "link") { + return Number(value); + } else if (dataType == "bool") { + return (value === 'true'); + } else { + return value; + } + } + + filterCoust() { + if (this.filterString != this.prevFilter) { + this.prevFilter = this.filterString; + if (this.filterString) { + this.gridDataSource.data = []; + let tempGrid = this.settingTypeArr; + tempGrid.forEach(row => { + let containsString = + row.name.includes(this.filterString) || + row.label.includes(this.filterString) || + (row.grp && row.grp.includes(this.filterString)) || + (row.description && row.description.includes(this.filterString)); + if (containsString) { + this.gridDataSource.data.push(row); + } + }); + } else { + this.gridDataSource.data = this.settingTypeArr; + } + } + } + + updateGrid(org) { + if (this.contextOrg != org) { + this.contextOrg = org; + this.refreshSettings = true; + } + + if (this.filterString != this.prevFilter) { + this.refreshSettings = true; + } + + if (this.refreshSettings) { + this.mergeSettingValues().then( + res => this.filterCoust() + ); + } + } +} diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.module.ts new file mode 100644 index 0000000000..62ee75e096 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.module.ts @@ -0,0 +1,29 @@ +import {NgModule} from '@angular/core'; +import {AdminCommonModule} from '@eg/staff/admin/common.module'; +import {TreeModule} from '@eg/share/tree/tree.module'; +import {OrgUnitSettingsComponent} from './org-unit-settings.component'; +import {EditOuSettingDialogComponent} from './edit-org-unit-setting-dialog.component'; +import {OuSettingHistoryDialogComponent} from './org-unit-setting-history-dialog.component'; +import {OrgUnitSettingsRoutingModule} from './org-unit-settings-routing.module'; +import {OuSettingJsonDialogComponent} from './org-unit-setting-json-dialog.component'; + +@NgModule({ + declarations: [ + OrgUnitSettingsComponent, + EditOuSettingDialogComponent, + OuSettingHistoryDialogComponent, + OuSettingJsonDialogComponent + ], + imports: [ + AdminCommonModule, + OrgUnitSettingsRoutingModule, + TreeModule + ], + exports: [ + ], + providers: [ + ] +}) + +export class OrgUnitSettingsModule { +} \ 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 2376260fec..fd9e5e8a4e 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 @@ -69,7 +69,10 @@ const routes: Routes = [{ }] }, { path: 'config/standing_penalty', - component: StandingPenaltyComponent + component: StandingPenaltyComponent, +}, { + path: 'asset/org_unit_settings', + loadChildren: '@eg/staff/admin/local/org-unit-settings/org-unit-settings.module#OrgUnitSettingsModule' }, { path: 'config/ui_staff_portal_page_entry', component: AdminStaffPortalPageComponent diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm index 3adc2a3ebf..01741b5b5c 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm @@ -186,6 +186,33 @@ sub update_privacy_waiver { return 1; } +__PACKAGE__->register_method( + method => "get_ou_setting_history", + api_name => "open-ils.actor.org_unit.settings.history.retrieve", + signature => { + desc => "Retrieves the history of an Org Unit Setting. The permission to retrieve " . + "an org unit setting's history is dependant on a specific permission specified " . + "in the view_perm column of the config.org_unit_setting_type " . + "table's row corresponding to the setting being changed." , + params => [ + {desc => 'Authentication token', type => 'string'}, + {desc => 'Org Unit ID', type => 'number'}, + {desc => 'Setting Type Name', type => 'string'} + ], + return => {desc => 'History IDL Object'} + } +); + +sub get_ou_setting_history { + my( $self, $client, $auth, $setting, $orgid ) = @_; + my $e = new_editor(authtoken => $auth, xact => 1); + return $e->die_event unless $e->checkauth; + + return $U->ou_ancestor_setting_log( + $orgid, $setting, $e, $auth + ); + +} __PACKAGE__->register_method( method => "set_ou_settings", diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm index 566342b908..3c323775ba 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm @@ -1318,19 +1318,63 @@ sub ou_ancestor_setting { my $coust = $e->retrieve_config_org_unit_setting_type([ $name, {flesh => 1, flesh_fields => {coust => ['view_perm']}} ]); - if ($coust && $coust->view_perm) { - # And you can't have permission if you don't have a valid session. - return undef if not $e->checkauth; - # And now that we know you MIGHT have permission, we check it. - return undef if not $e->allowed($coust->view_perm->code, $orgid); - } + return undef unless ou_ancestor_setting_perm_check($orgid, $coust, $auth) } my $query = {from => ['actor.org_unit_ancestor_setting', $name, $orgid]}; my $setting = $e->json_query($query)->[0]; return undef unless $setting; return {org => $setting->{org_unit}, value => OpenSRF::Utils::JSON->JSON2perl($setting->{value})}; -} +} + +# Returns the org id if the requestor has the permissions required +# to view the ou setting. +sub ou_ancestor_setting_perm_check { + my( $self, $orgid, $view_perm, $e, $auth ) = @_; + $e = $e || OpenILS::Utils::CStoreEditor->new( + (defined $auth) ? (authtoken => $auth) : () + ); + + # And you can't have permission if you don't have a valid session. + return undef if not $e->checkauth; + # And now that we know you MIGHT have permission, we check it. + if ($view_perm) { + return undef unless $e->allowed($view_perm, $orgid); + } + + return $orgid; +} + +sub ou_ancestor_setting_log { + my ( $self, $orgid, $name, $e, $auth ) = @_; + $e = $e || OpenILS::Utils::CStoreEditor->new( + (defined $auth) ? (authtoken => $auth, xact => 1) : () + ); + my $coust; + + if ($auth) { + $coust = $e->retrieve_config_org_unit_setting_type([ + $name, {flesh => 1, flesh_fields => {coust => ['view_perm']}} + ]); + my $orgs = $self->get_org_ancestors($orgid); + + my $qorg = $self->ou_ancestor_setting_perm_check( + $orgs, + $coust, + $e, + $auth + ); + my $sort = { order_by => { coustl => 'date_applied DESC' } }; + return $e->json_query({ + from => 'coustl', + where => { + field_name => $name, + org => $qorg + }, + $sort + }); + }; +} # This fetches a set of OU settings in one fell swoop, # which can be significantly faster than invoking diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql index e662764e0c..b74a46121f 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -19534,6 +19534,12 @@ VALUES ( 'cwst', 'label' ) ), ( + 'eg.grid.asset.ouSettings', 'gui', 'object', + oils_i18n_gettext( + 'eg.grid.asset.ouSettings', + 'Grid Config: asset.ouSettings', + 'cwst', 'label' +), ( 'eg.cat.record.summary.collapse', 'gui', 'bool', oils_i18n_gettext( 'eg.cat.record.summary.collapse', diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.ouSettings-grid-ws-settings.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.ouSettings-grid-ws-settings.sql new file mode 100644 index 0000000000..92141f4939 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.ouSettings-grid-ws-settings.sql @@ -0,0 +1,15 @@ +BEGIN; + +SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +INSERT INTO config.workstation_setting_type (name, grp, datatype, label) +VALUES ( + 'eg.grid.asset.ouSettings', 'gui', 'object', + oils_i18n_gettext( + 'eg.grid.asset.ouSettings', + 'Grid Config: asset.ouSettings', + 'cwst', 'label' + ) +); + +COMMIT; \ No newline at end of file -- 2.11.0