From 0bdb373741359bb674272cd0f4f11f3cbc178e89 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Thu, 24 Jan 2019 12:22:42 -0500 Subject: [PATCH] LP1823393 Org unit type Angular admin UI Ports the "Organization Types" admin UI from Dojo to Angular. Signed-off-by: Bill Erickson Signed-off-by: Galen Charlton Signed-off-by: Jane Sandberg --- .../src/app/share/fm-editor/fm-editor.component.ts | 24 +++- .../src/eg2/src/app/share/tree/tree.component.ts | 1 + .../server/admin-server-splash.component.html | 2 +- .../app/staff/admin/server/admin-server.module.ts | 8 +- .../admin/server/org-unit-type.component.html | 90 ++++++++++++ .../staff/admin/server/org-unit-type.component.ts | 159 +++++++++++++++++++++ .../src/app/staff/admin/server/routing.module.ts | 4 + 7 files changed, 281 insertions(+), 7 deletions(-) create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/server/org-unit-type.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/server/org-unit-type.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 3e41fa221d..14aa386581 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 @@ -85,7 +85,6 @@ export class FmRecordEditorComponent recId: any; // IDL record we are editing - // TODO: allow this to be update in real time by the caller? record: IdlObject; // Permissions extracted from the permacrud defs in the IDL @@ -180,6 +179,13 @@ export class FmRecordEditorComponent ); } + // Set the record value and clear the recId value to + // indicate the record is our current source of data. + setRecord(record: IdlObject) { + this.record = record; + this.recId = null; + } + // Translate comma-separated string versions of various inputs // to arrays. private listifyInputs() { @@ -207,8 +213,16 @@ export class FmRecordEditorComponent }; if (this.mode === 'update' || this.mode === 'view') { - return this.pcrud.retrieve(this.idlClass, this.recId) - .toPromise().then(rec => { + + let promise; + if (this.record && this.recId === null) { + promise = Promise.resolve(this.record); + } else { + promise = + this.pcrud.retrieve(this.idlClass, this.recId).toPromise(); + } + + return promise.then(rec => { if (!rec) { return Promise.reject(`No '${this.idlClass}' @@ -224,7 +238,9 @@ export class FmRecordEditorComponent // create a new record from scratch or from a stub record // provided by the caller. this.pkeyIsEditable = !('pkey_sequence' in this.idlDef); - if (!this.record) { + if (!this.record || this.recId) { + // user provided no seed record, create one. + this.recId = null; this.record = this.idl.create(this.idlClass); } return this.getFieldList(); diff --git a/Open-ILS/src/eg2/src/app/share/tree/tree.component.ts b/Open-ILS/src/eg2/src/app/share/tree/tree.component.ts index d3fccdae8f..f519268f46 100644 --- a/Open-ILS/src/eg2/src/app/share/tree/tree.component.ts +++ b/Open-ILS/src/eg2/src/app/share/tree/tree.component.ts @@ -47,6 +47,7 @@ export class TreeComponent implements OnInit { ngOnInit() {} displayNodes(): TreeNode[] { + if (!this.tree) { return []; } return this.tree.nodeList(true); } diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server-splash.component.html b/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server-splash.component.html index 5e6058da9c..211283e341 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server-splash.component.html +++ b/Open-ILS/src/eg2/src/app/staff/admin/server/admin-server-splash.component.html @@ -72,7 +72,7 @@ + routerLink="/staff/admin/server/actor/org_unit_type"> + + +Org Unit Type Update Succeeded + + +Org Unit Type Succeessfully Created + + +Org Unit Type Update Failed + + + + + + + + +
+
+

Org Unit Types

+ +
+
+

Selected Org Unit Type

+ +
+ Select an org unit type from the tree on the left. +
+
+
+
+
+ +
+
+ + + +
+
+
+ +
+ +
+
+ {{selected.callerData.name()}} +
+
+
+
+ +
+
+ {{selected.callerData.opac_label()}} +
+
+
+
+ +
+
+ + {{selected.callerData.can_have_users() == 't'}} +
+
+
+
+ +
+
+ + {{selected.callerData.can_have_vols() == 't'}} +
+
+
+
+ +
+
+ {{selected.callerData.depth()}} +
+
+
+
+
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/org-unit-type.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/server/org-unit-type.component.ts new file mode 100644 index 0000000000..1820cc8e4e --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/server/org-unit-type.component.ts @@ -0,0 +1,159 @@ +import {Component, Input, ViewChild, OnInit} from '@angular/core'; +import {Tree, TreeNode} from '@eg/share/tree/tree'; +import {IdlService, IdlObject} from '@eg/core/idl.service'; +import {OrgService} from '@eg/core/org.service'; +import {AuthService} from '@eg/core/auth.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {ToastService} from '@eg/share/toast/toast.service'; +import {StringComponent} from '@eg/share/string/string.component'; +import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component'; +import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component'; + +@Component({ + templateUrl: './org-unit-type.component.html' +}) + +export class OrgUnitTypeComponent implements OnInit { + + tree: Tree; + selected: TreeNode; + @ViewChild('editDialog') editDialog: FmRecordEditorComponent; + @ViewChild('editString') editString: StringComponent; + @ViewChild('createString') createString: StringComponent; + @ViewChild('errorString') errorString: StringComponent; + @ViewChild('delConfirm') delConfirm: ConfirmDialogComponent; + + constructor( + private idl: IdlService, + private org: OrgService, + private auth: AuthService, + private pcrud: PcrudService, + private toast: ToastService + ) {} + + + ngOnInit() { + this.loadAoutTree(); + } + + loadAoutTree() { + this.pcrud.search('aout', {depth: 0}, + {flesh: -1, flesh_fields: {aout: ['children']}}, + {anonymous: true} + ).subscribe(aoutTree => this.ingestAoutTree(aoutTree)); + } + + // Translate the org unt type tree into a structure EgTree can use. + ingestAoutTree(aoutTree) { + + const handleNode = (aoutNode: IdlObject): TreeNode => { + if (!aoutNode) { return; } + + const treeNode = new TreeNode({ + id: aoutNode.id(), + label: aoutNode.name(), + callerData: aoutNode + }); + + aoutNode.children().forEach(childNode => + treeNode.children.push(handleNode(childNode)) + ); + + return treeNode; + }; + + const rootNode = handleNode(aoutTree); + this.tree = new Tree(rootNode); + } + + nodeClicked($event: any) { + this.selected = $event; + } + + postUpdate(message: StringComponent) { + // Modifying org unit types means refetching the org unit + // data normally fetched on page load, since it includes + // org unit type data. + this.org.fetchOrgs().then( + ok => { + message.current().then(str => this.toast.success(str)); + } + ); + } + + edit() { + this.editDialog.mode = 'update'; + this.editDialog.setRecord(this.selected.callerData); + + this.editDialog.open().then( + success => { + this.postUpdate(this.editString); + }, + rejected => { + if (rejected && rejected.dismissed) { + return; + } + this.errorString.current() + .then(str => this.toast.danger(str)); + } + ); + } + + remove() { + this.delConfirm.open().then( + ok => { + this.pcrud.remove(this.selected.callerData) + .subscribe( + ok2 => {}, + err => { + this.errorString.current() + .then(str => this.toast.danger(str)); + }, + () => { + // Avoid updating until we know the entire + // pcrud action/transaction completed. + this.tree.removeNode(this.selected); + this.selected = null; + this.postUpdate(this.editString); + } + ); + }, + notConfirmed => {} + ); + } + + addChild() { + const parentTreeNode = this.selected; + const parentType = parentTreeNode.callerData; + + const newType = this.idl.create('aout'); + newType.parent(parentType.id()); + newType.depth(Number(parentType.depth()) + 1); + + this.editDialog.setRecord(newType); + this.editDialog.mode = 'create'; + + this.editDialog.open().then( + result => { // aout object + + // Add our new node to the tree + const newNode = new TreeNode({ + id: result.id(), + label: result.name(), + callerData: result + }); + parentTreeNode.children.push(newNode); + this.postUpdate(this.createString); + }, + + rejected => { + if (rejected && rejected.dismissed) { + return; + } + this.errorString.current() + .then(str => this.toast.danger(str)); + } + ); + } +} + 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 ceb60f27f4..c971ed74a7 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 @@ -2,11 +2,15 @@ import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; import {AdminServerSplashComponent} from './admin-server-splash.component'; import {BasicAdminPageComponent} from '@eg/staff/admin/basic-admin-page.component'; +import {OrgUnitTypeComponent} from './org-unit-type.component'; const routes: Routes = [{ path: 'splash', component: AdminServerSplashComponent }, { + path: 'actor/org_unit_type', + component: OrgUnitTypeComponent +}, { path: ':schema/:table', component: BasicAdminPageComponent }]; -- 2.11.0