Ports the "Organization Types" admin UI from Dojo to Angular.
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Signed-off-by: Jane Sandberg <sandbej@linnbenton.edu>
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
);
}
+ // 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() {
};
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}'
// 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();
ngOnInit() {}
displayNodes(): TreeNode[] {
+ if (!this.tree) { return []; }
return this.tree.nodeList(true);
}
<eg-link-table-link i18n-label label="Org Unit Proximity Adjustments"
routerLink="/staff/admin/server/actor/org_unit_proximity_adjustment"></eg-link-table-link>
<eg-link-table-link i18n-label label="Organization Types"
- url="/eg/staff/admin/server/legacy/actor/org_unit_type"></eg-link-table-link>
+ routerLink="/staff/admin/server/actor/org_unit_type"></eg-link-table-link>
<eg-link-table-link i18n-label label="Org Unit Setting Types"
routerLink="/staff/admin/server/config/org_unit_setting_type"></eg-link-table-link>
<eg-link-table-link i18n-label label="Organizational Units"
import {NgModule} from '@angular/core';
+import {TreeModule} from '@eg/share/tree/tree.module';
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 {OrgUnitTypeComponent} from './org-unit-type.component';
@NgModule({
declarations: [
- AdminServerSplashComponent
+ AdminServerSplashComponent,
+ OrgUnitTypeComponent
],
imports: [
AdminCommonModule,
- AdminServerRoutingModule
+ AdminServerRoutingModule,
+ TreeModule
],
exports: [
],
--- /dev/null
+<eg-staff-banner bannerText="Org Unit Type Configuration" i18n-bannerText>
+</eg-staff-banner>
+
+<ng-template #editStrTmpl i18n>Org Unit Type Update Succeeded</ng-template>
+<eg-string #editString [template]="editStrTmpl"></eg-string>
+
+<ng-template #createStrTmpl i18n>Org Unit Type Succeessfully Created</ng-template>
+<eg-string #createString [template]="createStrTmpl"></eg-string>
+
+<ng-template #errorStrTmpl i18n>Org Unit Type Update Failed</ng-template>
+<eg-string #errorString [template]="errorStrTmpl"></eg-string>
+
+<eg-confirm-dialog #delConfirm
+ i18n-dialogTitle i18n-dialogBody
+ dialogTitle="Confirm Delete"
+ dialogBody="Delete Org Unit Type {{selected ? selected.label : ''}}?">
+</eg-confirm-dialog>
+
+<eg-fm-record-editor #editDialog idlClass="aout" readonlyFields="depth,parent">
+</eg-fm-record-editor>
+
+<div class="row">
+ <div class="col-lg-4">
+ <h3 i18n>Org Unit Types</h3>
+ <eg-tree [tree]="tree" (nodeClicked)="nodeClicked($event)"></eg-tree>
+ </div>
+ <div class="col-lg-8">
+ <h3 i18n class="mb-3">Selected Org Unit Type</h3>
+ <ng-container *ngIf="!selected">
+ <div class="alert alert-info font-italic" i18n>
+ Select an org unit type from the tree on the left.
+ </div>
+ </ng-container>
+ <div *ngIf="selected" class="common-form striped-even">
+ <div class="row">
+ <div class="col-lg-3">
+ <label i18n>Actions for Selected: </label>
+ </div>
+ <div class="col-lg-9">
+ <button class="btn btn-info mr-2" (click)="edit()" i18n>Edit</button>
+ <button class="btn btn-info mr-2" (click)="addChild()" i18n>Add Child</button>
+ <button class="btn btn-warning mr-2" (click)="remove()" i18n>Delete</button>
+ </div>
+ </div>
+ <div class="row">
+ <!-- TODO: use FmRecordEditPaneComponent once it exists -->
+ <div class="col-lg-4">
+ <label i18n>Name: </label>
+ </div>
+ <div class="col-lg-8 font-weight-bold">
+ {{selected.callerData.name()}}
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-lg-4">
+ <label i18n>Label: </label>
+ </div>
+ <div class="col-lg-8 font-weight-bold">
+ {{selected.callerData.opac_label()}}
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-lg-4">
+ <label i18n>Can Have Users: </label>
+ </div>
+ <div class="col-lg-8 font-weight-bold">
+ <!-- TODO: use <eg-bool/> once merged-->
+ {{selected.callerData.can_have_users() == 't'}}
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-lg-4">
+ <label i18n>Can Have Volumes: </label>
+ </div>
+ <div class="col-lg-8 font-weight-bold">
+ <!-- TODO: use <eg-bool/> once merged-->
+ {{selected.callerData.can_have_vols() == 't'}}
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-lg-4">
+ <label i18n>Depth: </label>
+ </div>
+ <div class="col-lg-8 font-weight-bold">
+ {{selected.callerData.depth()}}
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
--- /dev/null
+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));
+ }
+ );
+ }
+}
+
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
}];