<field reporter:label="Organizational Unit ID" name="id" reporter:datatype="org_unit" reporter:selector="shortname"/>
<field reporter:label="ILL Receiving Address" name="ill_address" reporter:datatype="link"/>
<field reporter:label="Mailing Address" name="mailing_address" reporter:datatype="link"/>
- <field reporter:label="Name" name="name" reporter:datatype="text" oils_persist:i18n="true"/>
- <field reporter:label="Organizational Unit Type" name="ou_type" reporter:datatype="link"/>
+ <field reporter:label="Name" name="name" reporter:datatype="text" oils_persist:i18n="true" oils_obj:required="true"/>
+ <field reporter:label="Organizational Unit Type" name="ou_type" reporter:datatype="link" oils_obj:required="true"/>
<field reporter:label="Parent Organizational Unit" name="parent_ou" reporter:datatype="link"/>
<field reporter:label="Short (Policy) Name" name="shortname" reporter:datatype="text" oils_obj:required="true" oils_obj:validate="^.+$"/>
<field reporter:label="Email Address" name="email" reporter:datatype="text"/>
<field reporter:label="Phone Number" name="phone" reporter:datatype="text"/>
<field reporter:label="OPAC Visible" name="opac_visible" reporter:datatype="bool"/>
- <field reporter:label="Fiscal Calendar" name="fiscal_calendar" reporter:datatype="link"/>
+ <field reporter:label="Fiscal Calendar" name="fiscal_calendar" reporter:datatype="link" oils_obj:required="true"/>
<field reporter:label="Users" name="users" oils_persist:virtual="true" reporter:datatype="link"/>
<field reporter:label="Closed Dates" name="closed_dates" oils_persist:virtual="true" reporter:datatype="link"/>
<field reporter:label="Circulations" name="circulations" oils_persist:virtual="true" reporter:datatype="link"/>
--- /dev/null
+<eg-staff-banner bannerText="Org Unit Configuration" i18n-bannerText>
+</eg-staff-banner>
+
+<ng-template #editStrTmpl i18n>Org Unit Update Succeeded</ng-template>
+<eg-string #editString [template]="editStrTmpl"></eg-string>
+
+<ng-template #createStrTmpl i18n>Org Unit Succeessfully Created</ng-template>
+<eg-string #createString [template]="createStrTmpl"></eg-string>
+
+<ng-template #errorStrTmpl i18n>Org Unit 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 {{selected.label}}?">
+</eg-confirm-dialog>
+
+<div class="row">
+ <div class="col-lg-4">
+ <h3 i18n>Org Units</h3>
+ <eg-tree [tree]="tree" (nodeClicked)="nodeClicked($event)"></eg-tree>
+ </div>
+ <div class="col-lg-8">
+ <ngb-tabset #rootTabs [activeId]="main">
+ <ngb-tab title="Main Settings" i18n-title id="main">
+ <ng-template ngbTabContent>
+ <eg-fm-record-editor #editDialog idlClass="aou" [displayMode]="inline"
+ [mode]="selected ? 'update' : 'create'"
+ readonlyFields="parent,ou_type,parent_ou" [recordId]="selected ? selected.id : null"
+ fieldOrder="parent_ou,ou_type,name,shortname,phone,email,opac_visible,fiscal_calendar"
+ hiddenFields="id,billing_address,mailing_address,holds_address,ill_address">
+ </eg-fm-record-editor>
+ </ng-template>
+ </ngb-tab>
+ </ngb-tabset>
+ </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.component.html'
+})
+
+export class OrgUnitComponent implements OnInit {
+
+ tree: Tree;
+ selected: TreeNode;
+ @ViewChild('editDialog') editDialog: FmRecordEditorComponent;
+ @ViewChild('createString') createString: StringComponent;
+ @ViewChild('editString') editString: 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() {
+ // On initial page load, use the existing org tree data and
+ // select the root node.
+ this.ingestAouTree(this.org.tree());
+ this.selected = this.tree.rootNode;
+ }
+
+ loadAouTree() {
+ this.org.fetchOrgs().then(() => this.ingestAouTree(this.org.tree()));
+ }
+
+ // Translate the org unt type tree into a structure EgTree can use.
+ ingestAouTree(aouTree) {
+
+ const handleNode = (orgNode: IdlObject): TreeNode => {
+ if (!orgNode) { return; }
+
+ // Clone to avoid modifying the shared org tree
+ const node = this.idl.clone(orgNode);
+ node.ou_type(node.ou_type().id());
+
+ const treeNode = new TreeNode({
+ id: node.id(),
+ label: node.name(),
+ callerData: {orgUnit: node}
+ });
+
+ node.children().forEach(childNode =>
+ treeNode.children.push(handleNode(childNode))
+ );
+
+ return treeNode;
+ };
+
+ const rootNode = handleNode(aouTree);
+ 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(() =>
+ message.current().then(str => this.toast.success(str)));
+ }
+
+ remove() {
+ this.delConfirm.open().subscribe(confirmed => {
+ if (!confirmed) { return; }
+
+ const org = this.selected.callerData.orgUnit;
+
+ this.pcrud.remove(org).subscribe(
+ ok2 => {},
+ err => {
+ this.errorString.current()
+ .then(str => this.toast.danger(str));
+ },
+ () => {
+ // Avoid updating until we know the entire
+ // pcrud action/transaction completed.
+ this.loadAouTree();
+
+ // After removal, select the parent org if available
+ // otherwise the root org.
+ const orgId = org.parent_ou() ? org.parent_ou() : this.org.root().id();
+ this.selected = this.tree.findNode(orgId);
+ this.postUpdate(this.editString);
+ }
+ );
+ });
+ }
+
+ addChild() {
+ const parentTreeNode = this.selected;
+ const parentOrg = parentTreeNode.callerData.orgUnit;
+
+ const newOrg = this.idl.create('aou');
+ newOrg.parent(parentOrg.id());
+
+ // TODO UNSUBSCRIBE
+ this.editDialog.onSave$.subscribe(result => { // aou object
+
+ // Add our new node to the tree
+ const newNode = new TreeNode({
+ id: result.id(),
+ label: result.name(),
+ callerData: {orgUnit: result}
+ });
+ this.loadAouTree();
+ this.postUpdate(this.createString);
+ });
+
+ // TODO subscribe / unsub error events
+
+ /*
+ rejected => {
+ this.errorString.current()
+ .then(str => this.toast.danger(str));
+ }
+ );
+ */
+ }
+}
+