From b4775282403bbbbee4835117b9130a9cb3bea9de Mon Sep 17 00:00:00 2001 From: Galen Charlton Date: Fri, 9 Sep 2022 12:55:22 -0400 Subject: [PATCH] LP#1863387: multi-select now allows filtering shelving locations by owner The Angular multi-select component now has a special case for shelving locations: when the IDL class of "acpl" is selected, rather than just displaying a combobox, the item-location-select component followed by an org selector is displayed and checkbox. The org selector defaults to workstation OU and is used to restrict the list of shelving locations displayed in the shelving location combobox to the context org unit and its ancestors. If the checkbox is also selected, descendants of the context OU are included as well. The effect of this is to allow large consortial to more efficiently select the shelving locations to be used by a carousel. To test ------- [1] Apply the patch. [2] Create or edit carousel definitions. Verify that the widget for the carousel's shelving locations now displays both a combobox for the location selector as well as one for the location owning library. Further verify that when the OU selector for the owning library is changed, that the list of available shelving locations reflects the locations available at the ancestors of the filter OU. Also verify that the "Include descendants?" checkbox updates the list of available locations as well. Signed-off-by: Galen Charlton fix Signed-off-by: Galen Charlton Signed-off-by: Jeff Davis --- .../item-location-select.component.ts | 23 +++++++++++++++ .../share/multi-select/multi-select.component.html | 33 +++++++++++++++++++--- .../share/multi-select/multi-select.component.ts | 21 ++++++++++++++ Open-ILS/src/eg2/src/app/staff/common.module.ts | 4 ++- 4 files changed, 76 insertions(+), 5 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/share/item-location-select/item-location-select.component.ts b/Open-ILS/src/eg2/src/app/share/item-location-select/item-location-select.component.ts index 809043e0a1..3800b1a67e 100644 --- a/Open-ILS/src/eg2/src/app/share/item-location-select/item-location-select.component.ts +++ b/Open-ILS/src/eg2/src/app/share/item-location-select/item-location-select.component.ts @@ -44,12 +44,25 @@ export class ItemLocationSelectComponent this.ngOnInit(); } + // ... though if includeDescendants is true, shelving + // locations at the descendants of the context OU are + // also included; this is a special case for the + // carousels editor + @Input() set includeDescendants(value: boolean) { + this._includeDescendants = value; + this.ngOnInit(); + } + get includeDescendants(): boolean { + return this._includeDescendants; + } + get contextOrgId(): number { return this._contextOrgId; } // Load locations for multiple context org units. private _contextOrgIds = []; + private _includeDescendants = false; @Input() set contextOrgIds(value: number[]) { this._contextOrgIds = value; } @@ -62,6 +75,8 @@ export class ItemLocationSelectComponent // Emits an acpl object or null on combobox value change @Output() valueChange: EventEmitter; + // Emits the combobox entry or null on value change + @Output() entryChange: EventEmitter; @Input() required: boolean; @@ -106,6 +121,7 @@ export class ItemLocationSelectComponent private loc: ItemLocationService ) { this.valueChange = new EventEmitter(); + this.entryChange = new EventEmitter(); } ngOnInit() { @@ -235,6 +251,7 @@ export class ItemLocationSelectComponent const id = entry ? entry.id : null; this.propagateChange(id); this.valueChange.emit(id ? this.loc.locationCache[id] : null); + this.entryChange.emit(entry ? entry : null); } writeValue(id: number) { @@ -277,6 +294,9 @@ export class ItemLocationSelectComponent let orgIds = []; contextOrgIds.forEach(id => orgIds = orgIds.concat(this.org.ancestors(id, true))); + if (this.includeDescendants) { + contextOrgIds.forEach(id => orgIds = orgIds.concat(this.org.descendants(id, true))); + } this.filterOrgsApplied = true; @@ -300,6 +320,9 @@ export class ItemLocationSelectComponent permOrgIds.forEach(orgId => { if (orgIds.includes(orgId)) { trimmedOrgIds = trimmedOrgIds.concat(this.org.ancestors(orgId, true)); + if (this.includeDescendants) { + trimmedOrgIds = trimmedOrgIds.concat(this.org.descendants(orgId, true)); + } } }); diff --git a/Open-ILS/src/eg2/src/app/share/multi-select/multi-select.component.html b/Open-ILS/src/eg2/src/app/share/multi-select/multi-select.component.html index 1926abf220..7ec8cf3e7c 100644 --- a/Open-ILS/src/eg2/src/app/share/multi-select/multi-select.component.html +++ b/Open-ILS/src/eg2/src/app/share/multi-select/multi-select.component.html @@ -1,9 +1,34 @@
- - + +
+ + +
+
+ + + + + +
+
+ + + +
diff --git a/Open-ILS/src/eg2/src/app/share/multi-select/multi-select.component.ts b/Open-ILS/src/eg2/src/app/share/multi-select/multi-select.component.ts index 3496f5551c..7f502d365b 100644 --- a/Open-ILS/src/eg2/src/app/share/multi-select/multi-select.component.ts +++ b/Open-ILS/src/eg2/src/app/share/multi-select/multi-select.component.ts @@ -7,7 +7,9 @@ import {map} from 'rxjs/operators'; import {Observable, of, Subject} from 'rxjs'; import {StoreService} from '@eg/core/store.service'; import {PcrudService} from '@eg/core/pcrud.service'; +import {OrgService} from '@eg/core/org.service'; import {ComboboxComponent, ComboboxEntry} from '@eg/share/combobox/combobox.component'; +import {ItemLocationSelectComponent} from '@eg/share/item-location-select/item-location-select.component'; @Component({ selector: 'eg-multi-select', @@ -30,9 +32,13 @@ export class MultiSelectComponent implements OnInit { @Output() onChange: EventEmitter; + acplContextOrgId: number; + acplIncludeDescendants: boolean; + constructor( private store: StoreService, private pcrud: PcrudService, + private org: OrgService, ) { this.entrylist = []; this.onChange = new EventEmitter(); @@ -45,7 +51,22 @@ export class MultiSelectComponent implements OnInit { this.selected = null; } } + + getOrgShortname(ou: any) { + if (typeof ou === 'object') { + return ou.shortname(); + } else { + return this.org.get(ou).shortname(); + } + } + addSelectedValue() { + // special case to format the label + if (this.idlClass === 'acpl' && this.selected.userdata) { + this.selected.label = + this.selected.userdata.name() + ' (' + + this.getOrgShortname(this.selected.userdata.owning_lib()) + ')'; + } this.entrylist.push(this.selected); this.onChange.emit(this.compileCurrentValue()); } diff --git a/Open-ILS/src/eg2/src/app/staff/common.module.ts b/Open-ILS/src/eg2/src/app/staff/common.module.ts index 7802455746..853576fd50 100644 --- a/Open-ILS/src/eg2/src/app/staff/common.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/common.module.ts @@ -24,6 +24,7 @@ import {BroadcastService} from '@eg/share/util/broadcast.service'; import {CourseService} from './share/course.service'; import {FileExportService} from '@eg/share/util/file-export.service'; import {OfflineService} from '@eg/staff/share/offline.service'; +import {ItemLocationSelectModule} from '@eg/share/item-location-select/item-location-select.module'; /** * Imports the EG common modules and adds modules common to all staff UI's. @@ -51,7 +52,8 @@ import {OfflineService} from '@eg/staff/share/offline.service'; EgCommonModule, CommonWidgetsModule, GridModule, - CatalogCommonModule + CatalogCommonModule, + ItemLocationSelectModule ], exports: [ EgCommonModule, -- 2.11.0