From b64e153afd2e90278c4c9341bcaffc54f7bc6b18 Mon Sep 17 00:00:00 2001 From: Mike Risher Date: Mon, 9 Sep 2019 17:47:48 +0000 Subject: [PATCH] lp1840287 Edit Floating Group Members Add functionality so that when editing floating group members, one is taken to a page where one can edit a given floating group as well as all its linked members. Signed-off-by: Mike Risher Changes to be committed: modified: Open-ILS/src/eg2/src/app/staff/admin/server/admin-server.module.ts new file: Open-ILS/src/eg2/src/app/staff/admin/server/edit-floating-group.component.html new file: Open-ILS/src/eg2/src/app/staff/admin/server/edit-floating-group.component.ts new file: Open-ILS/src/eg2/src/app/staff/admin/server/floating-group.component.html new file: Open-ILS/src/eg2/src/app/staff/admin/server/floating-group.component.ts modified: Open-ILS/src/eg2/src/app/staff/admin/server/routing.module.ts --- .../app/staff/admin/server/admin-server.module.ts | 9 +- .../server/edit-floating-group.component.html | 10 + .../admin/server/edit-floating-group.component.ts | 41 +++ .../admin/server/floating-group.component.html | 68 +++++ .../staff/admin/server/floating-group.component.ts | 291 +++++++++++++++++++++ .../src/app/staff/admin/server/routing.module.ts | 8 + 6 files changed, 426 insertions(+), 1 deletion(-) create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/server/edit-floating-group.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/server/edit-floating-group.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/server/floating-group.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/server/floating-group.component.ts diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server.module.ts index cbbadd38d6..0d78a26ae2 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server.module.ts @@ -4,6 +4,8 @@ import {StaffCommonModule} from '@eg/staff/common.module'; import {AdminServerRoutingModule} from './routing.module'; import {AdminCommonModule} from '@eg/staff/admin/common.module'; import {AdminServerSplashComponent} from './admin-server-splash.component'; +import {FloatingGroupComponent} from './floating-group.component'; +import {EditFloatingGroupComponent} from './edit-floating-group.component'; import {OrgUnitTypeComponent} from './org-unit-type.component'; import {PrintTemplateComponent} from './print-template.component'; import {SampleDataService} from '@eg/share/util/sample-data.service'; @@ -12,7 +14,9 @@ import {SampleDataService} from '@eg/share/util/sample-data.service'; declarations: [ AdminServerSplashComponent, OrgUnitTypeComponent, - PrintTemplateComponent + PrintTemplateComponent, + FloatingGroupComponent, + EditFloatingGroupComponent ], imports: [ AdminCommonModule, @@ -30,3 +34,6 @@ export class AdminServerModule { } + + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/edit-floating-group.component.html b/Open-ILS/src/eg2/src/app/staff/admin/server/edit-floating-group.component.html new file mode 100644 index 0000000000..6cd87cda1a --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/server/edit-floating-group.component.html @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/edit-floating-group.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/server/edit-floating-group.component.ts new file mode 100644 index 0000000000..bd7370ee63 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/server/edit-floating-group.component.ts @@ -0,0 +1,41 @@ +import {Component, Input} from '@angular/core'; +import {Router} from '@angular/router'; +import {GridDataSource} from '@eg/share/grid/grid'; +import {Pager} from '@eg/share/util/pager'; +import {PcrudService} from '@eg/core/pcrud.service'; + + @Component({ + templateUrl: './edit-floating-group.component.html' + }) + + export class EditFloatingGroupComponent { + + @Input() idlClass = 'cfgm'; + @Input() sortField: string; + @Input() dataSource: GridDataSource; + @Input() dialogSize: 'sm' | 'lg' = 'lg'; + + // This is the ID of the floating group being edited currently + currentId: string; + + constructor( + private pcrud: PcrudService, + private router: Router + ) { + } + + ngOnInit() { + let url = this.router.routerState.snapshot.url; + let slash = url.lastIndexOf('/'); + this.currentId = url.substring(slash+1); + this.dataSource = new GridDataSource(); + this.dataSource.getRows = (pager: Pager, sort: any[]) => { + const searchOps = { + offset: pager.offset, + limit: pager.limit, + order_by: {} + }; + return this.pcrud.search(this.idlClass, {floating_group: this.currentId}, searchOps); + }; + } + } \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/floating-group.component.html b/Open-ILS/src/eg2/src/app/staff/admin/server/floating-group.component.html new file mode 100644 index 0000000000..6f26411e09 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/server/floating-group.component.html @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/floating-group.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/server/floating-group.component.ts new file mode 100644 index 0000000000..ea02f22c7b --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/server/floating-group.component.ts @@ -0,0 +1,291 @@ +// import {Component} from '@angular/core'; +import {Component, Input, OnInit, TemplateRef, ViewChild} from '@angular/core'; +import { RouterModule, Routes, CanActivate, Router, + ActivatedRouteSnapshot, + RouterStateSnapshot, + CanActivateChild } 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'; +import {TranslateComponent} from '@eg/staff/share/translate/translate.component'; +import {ToastService} from '@eg/share/toast/toast.service'; +import {Pager} from '@eg/share/util/pager'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {OrgService} from '@eg/core/org.service'; +import {PermService} from '@eg/core/perm.service'; +import {AuthService} from '@eg/core/auth.service'; +import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component'; +import {StringComponent} from '@eg/share/string/string.component'; + + @Component({ + templateUrl: './floating-group.component.html' + }) + + export class FloatingGroupComponent { + + @Input() idlClass: string = "cfg"; + + // Default sort field, used when no grid sorting is applied. + @Input() sortField: string; + + // Data source may be provided by the caller. This gives the caller + // complete control over the contents of the grid. If no data source + // is provided, a generic one is create which is sufficient for data + // that requires no special handling, filtering, etc. + @Input() dataSource: GridDataSource; + + // Size of create/edito dialog. Uses large by default. + @Input() dialogSize: 'sm' | 'lg' = 'lg'; + + // If an org unit field is specified, an org unit filter + // is added to the top of the page. + @Input() orgField: string; + + // Disable the auto-matic org unit field filter + @Input() disableOrgFilter: boolean; + + // Include objects linking to org units which are ancestors + // of the selected org unit. + @Input() includeOrgAncestors: boolean; + + // Ditto includeOrgAncestors, but descendants. + @Input() includeOrgDescendants: boolean; + + // Optional grid persist key. This is the part of the key + // following eg.grid. + @Input() persistKey: string; + + // Optional path component to add to the generated grid persist key, + // formatted as (for example): + // 'eg.grid.admin.${persistKeyPfx}.config.billing_type' + @Input() persistKeyPfx: string = "server"; + + @ViewChild('grid') grid: GridComponent; + @ViewChild('editDialog') editDialog: FmRecordEditorComponent; + @ViewChild('successString') successString: StringComponent; + @ViewChild('createString') createString: StringComponent; + @ViewChild('translator') translator: TranslateComponent; + + idlClassDef: any; + pkeyField: string; + createNew: () => void; + deleteSelected: (rows: IdlObject[]) => void; + editSelected: (rows: IdlObject[]) => void; + + // True if any columns on the object support translations + translateRowIdx: number; + translateFieldIdx: number; + translatableFields: string[]; + translate: () => void; + + contextOrg: IdlObject; + orgFieldLabel: string; + viewPerms: string; + canCreate: boolean; + + constructor( + private idl: IdlService, + private org: OrgService, + private auth: AuthService, + private pcrud: PcrudService, + private perm: PermService, + private toast: ToastService, + private router: Router + ) { + this.translatableFields = []; + } + + applyOrgValues() { + + if (this.disableOrgFilter) { + this.orgField = null; + return; + } + + if (!this.orgField) { + // If no org unit field is specified, try to find one. + // If an object type has multiple org unit fields, the + // caller should specify one or disable org unit filter. + this.idlClassDef.fields.forEach(field => { + if (field['class'] === 'aou') { + this.orgField = field.name; + } + }); + } + + if (this.orgField) { + this.orgFieldLabel = this.idlClassDef.field_map[this.orgField].label; + this.contextOrg = this.org.root(); + } + } + + ngOnInit() { + console.log("ngOnInit running in fg component") + this.idlClassDef = this.idl.classes[this.idlClass]; + this.pkeyField = this.idlClassDef.pkey || 'id'; + + // this.translatableFields = + // this.idlClassDef.fields.filter(f => f.i18n).map(f => f.name); + + if (!this.persistKey) { + this.persistKey = + 'admin.' + + (this.persistKeyPfx ? this.persistKeyPfx + '.' : '') + + this.idlClassDef.table; + } + + // Limit the view org selector to orgs where the user has + // permacrud-encoded view permissions. + const pc = this.idlClassDef.permacrud; + if (pc && pc.retrieve) { + this.viewPerms = pc.retrieve.perms; + } + + this.checkCreatePerms(); + this.applyOrgValues(); + + // If the caller provides not data source, create a generic one. + if (!this.dataSource) { + this.initDataSource(); + } + + // TODO: pass the row activate handler via the grid markup + // this.grid.onRowActivate.subscribe( + // (idlThing: IdlObject) => { + // console.log("grid.onrowactivate fg component") + // this.editDialog.mode = 'update'; + // this.editDialog.recId = idlThing[this.pkeyField](); + // this.editDialog.open({size: this.dialogSize}).then( + // ok => { + // this.successString.current() + // .then(str => this.toast.success(str)); + // this.grid.reload(); + // }, + // err => {} + // ); + // } + // ); + + // this.createNew = () => { + // this.editDialog.mode = 'create'; + // this.editDialog.open({size: this.dialogSize}).then( + // ok => { + // this.createString.current() + // .then(str => this.toast.success(str)); + // this.grid.reload(); + // }, + // err => {} + // ); + // }; + + this.deleteSelected = (floatingGroups: IdlObject[]) => { + floatingGroups.forEach(fg => fg.isdeleted(true)); + this.pcrud.autoApply(floatingGroups).subscribe( + val => console.debug('deleted: ' + val), + err => {}, + () => this.grid.reload() + ); + }; + + this.editSelected = (floatingGroups: IdlObject[]) => { + + // console.log(floatingGroups); + // console.log("route to this id:") + // console.log(floatingGroups[0].a[0]); + // console.log("route to this id:") + let idToEdit = floatingGroups[0].a[0]; + console.log("you clicked edit. We are editing id=" + idToEdit); + this.router.navigate(["/staff/admin/server/config/floating_group/" + idToEdit]); + // 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()); + } + } + + checkCreatePerms() { + this.canCreate = false; + const pc = this.idlClassDef.permacrud || {}; + const perms = pc.create ? pc.create.perms : []; + if (perms.length === 0) { return; } + + this.perm.hasWorkPermAt(perms, true).then(permMap => { + Object.keys(permMap).forEach(key => { + if (permMap[key].length > 0) { + this.canCreate = true; + } + }); + }); + } + + orgOnChange(org: IdlObject) { + this.contextOrg = org; + this.grid.reload(); + } + + initDataSource() { + this.dataSource = new GridDataSource(); + + 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 + }; + + if (this.contextOrg) { + // Filter rows by those linking to the context org and + // optionally ancestor and descendant org units. + + let orgs = [this.contextOrg.id()]; + + if (this.includeOrgAncestors) { + orgs = this.org.ancestors(this.contextOrg, true); + } + + if (this.includeOrgDescendants) { + // can result in duplicate workstation org IDs... meh + orgs = orgs.concat( + this.org.descendants(this.contextOrg, true)); + } + + const search = {}; + search[this.orgField] = orgs; + return this.pcrud.search(this.idlClass, search, searchOps); + } + + // No org filter -- fetch all rows + return this.pcrud.retrieveAll(this.idlClass, searchOps); + }; + } + + disableAncestorSelector(): boolean { + return this.contextOrg && + this.contextOrg.id() === this.org.root().id(); + } + + disableDescendantSelector(): boolean { + return this.contextOrg && this.contextOrg.children().length === 0; + } + + + + + + } \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/server/routing.module.ts index 4f9b9ff366..1f4bbe5fa2 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/server/routing.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/admin/server/routing.module.ts @@ -1,11 +1,19 @@ import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; import {AdminServerSplashComponent} from './admin-server-splash.component'; +import {FloatingGroupComponent} from './floating-group.component'; +import {EditFloatingGroupComponent} from './edit-floating-group.component'; import {BasicAdminPageComponent} from '@eg/staff/admin/basic-admin-page.component'; import {OrgUnitTypeComponent} from './org-unit-type.component'; import {PrintTemplateComponent} from './print-template.component'; const routes: Routes = [{ + path: 'config/floating_group', + component: FloatingGroupComponent +}, { + path: 'config/floating_group/:id', + component: EditFloatingGroupComponent +}, { path: 'splash', component: AdminServerSplashComponent }, { -- 2.11.0