From 696781c2d55d35ae57eacfcee338ff08cdafe5bf Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Mon, 3 Feb 2020 12:08:14 -0500 Subject: [PATCH] LP1861701 Staff catalog copy location groups WIP Signed-off-by: Bill Erickson --- .../src/app/share/catalog/catalog-common.module.ts | 11 +- .../app/share/catalog/eg-org-copy-loc-select.html | 2 + .../share/catalog/org-copy-loc-select.component.ts | 116 +++++++++++++++++++++ .../app/staff/catalog/search-form.component.html | 4 + .../src/app/staff/catalog/search-form.component.ts | 2 + 5 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 Open-ILS/src/eg2/src/app/share/catalog/eg-org-copy-loc-select.html create mode 100644 Open-ILS/src/eg2/src/app/share/catalog/org-copy-loc-select.component.ts diff --git a/Open-ILS/src/eg2/src/app/share/catalog/catalog-common.module.ts b/Open-ILS/src/eg2/src/app/share/catalog/catalog-common.module.ts index 5b45d00a60..2bc4718f7d 100644 --- a/Open-ILS/src/eg2/src/app/share/catalog/catalog-common.module.ts +++ b/Open-ILS/src/eg2/src/app/share/catalog/catalog-common.module.ts @@ -1,5 +1,6 @@ import {NgModule} from '@angular/core'; import {EgCommonModule} from '@eg/common.module'; +import {CommonWidgetsModule} from '@eg/share/common-widgets.module'; import {CatalogService} from './catalog.service'; import {AnonCacheService} from '@eg/share/util/anon-cache.service'; import {BasketService} from './basket.service'; @@ -7,17 +8,21 @@ import {CatalogUrlService} from './catalog-url.service'; import {BibRecordService} from './bib-record.service'; import {UnapiService} from './unapi.service'; import {MarcHtmlComponent} from './marc-html.component'; +import {OrgCopyLocSelectComponent} from './org-copy-loc-select.component'; @NgModule({ declarations: [ - MarcHtmlComponent + MarcHtmlComponent, + OrgCopyLocSelectComponent ], imports: [ - EgCommonModule + EgCommonModule, + CommonWidgetsModule ], exports: [ - MarcHtmlComponent + MarcHtmlComponent, + OrgCopyLocSelectComponent ], providers: [ AnonCacheService, diff --git a/Open-ILS/src/eg2/src/app/share/catalog/eg-org-copy-loc-select.html b/Open-ILS/src/eg2/src/app/share/catalog/eg-org-copy-loc-select.html new file mode 100644 index 0000000000..6a0d0875ce --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/catalog/eg-org-copy-loc-select.html @@ -0,0 +1,2 @@ + + diff --git a/Open-ILS/src/eg2/src/app/share/catalog/org-copy-loc-select.component.ts b/Open-ILS/src/eg2/src/app/share/catalog/org-copy-loc-select.component.ts new file mode 100644 index 0000000000..0f8db6533e --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/catalog/org-copy-loc-select.component.ts @@ -0,0 +1,116 @@ +import {Component, EventEmitter, OnInit, AfterViewInit, Input, + Output, ViewChild, forwardRef} from '@angular/core'; +import {ControlValueAccessor, FormGroup, FormControl, NG_VALUE_ACCESSOR} from '@angular/forms'; +import {IdlObject} from '@eg/core/idl.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {OrgService} from '@eg/core/org.service'; +import {AuthService} from '@eg/core/auth.service'; +import {ComboboxComponent, ComboboxEntry} from '@eg/share/combobox/combobox.component'; + +/** Ingtegrated org unit and copy location selector */ + +const PAD_SPACE = ' '; // U+2007 + +@Component({ + selector: 'eg-org-copy-loc-select', + templateUrl: 'eg-org-copy-loc-select.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => OrgCopyLocSelectComponent), + multi: true + } + ] +}) +export class OrgCopyLocSelectComponent implements AfterViewInit { + + @Input() orgDisplayField = 'shortname'; + + @ViewChild('cbox', {static: false}) cbox: ComboboxComponent; + + entries: ComboboxEntry[] = []; + + propagateChange = (_: ComboboxEntry) => {}; + propagateTouch = () => {}; + + constructor( + private org: OrgService, + private pcrud: PcrudService, + private auth: AuthService + ) {} + + ngAfterViewInit() { + this.pcrud.search('acplg', + {owner: this.org.fullPath(this.auth.user().ws_ou(), true)}, + {}, {atomic: true} + ).toPromise().then(groups => this.buildTree(groups)); + } + + buildTree(groups: IdlObject[], org?: IdlObject) { + + if (!org) { + org = this.org.root(); + this.entries = []; + } + + const depth = org.ou_type().depth(); + + // Current org unit + this.entries.push({ + id: 'org_' + org.id(), + label: this.formatLabel(org[this.orgDisplayField](), depth) + }); + + // Groups sorted above this org unit's children. + groups + .filter(grp => grp.owner() === org.id() && grp.top() === 't') + .sort((a, b) => a.pos() < b.pos() ? -1 : 1) + .forEach(grp => this.entries.push({ + id: 'grp_' + grp.id(), + label: this.formatLabel(grp.name(), depth + 1) + })); + + // Org unit children + org.children() + .sort((a, b) => a[this.orgDisplayField]() < b[this.orgDisplayField]() ? -1 : 1) + .forEach(org => this.buildTree(groups, org)); + + // Groups sorted below this org unit's children. + groups + .filter(grp => grp.owner() === org.id() && grp.top() === 'f') + .sort((a, b) => a.pos() < b.pos() ? -1 : 1) + .forEach(grp => this.entries.push({ + id: 'grp_' + grp.id(), + label: this.formatLabel(grp.name(), depth + 1) + })); + + if (org.id() === this.org.root().id()) { + // Pass the list of entries afters fully compiled. + this.cbox.entries = this.entries; + } + } + + formatLabel(label: string, depth: number): string { + return PAD_SPACE.repeat(depth) + label; + } + + cboxChange(entry: ComboboxEntry) { + this.propagateChange(entry); + } + + writeValue(entry: ComboboxEntry) { + if (this.cbox) { + this.cbox.selectedId = entry ? entry.id : null; + } + } + + registerOnChange(fn) { + this.propagateChange = fn; + } + + registerOnTouched(fn) { + this.propagateTouch = fn; + } +} + + diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html index d032f3d08f..a0fd96a816 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html +++ b/Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html @@ -319,11 +319,15 @@ TODO focus search input
+ + +