From 37c9c2ff75d459ddddeb4ad43ed1b79f27d5381d Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Thu, 2 Jan 2020 16:17:59 -0500 Subject: [PATCH] LP1858138 Link selector consolidation/repairs Move more of the IDL link class selector extraction logic into the IDL service. Avoid using 'name' as a fall-through selector field when no 'name' field exists on the class. Teach the idl service to log warnings on invalid class and field name combinations in selector lookups. Modify fm-editor and combobox to use the new idl link selector functions. While we're in there, avoid unnecessary API calls from the combobox by preventing async data lookups with a search term of "_CLICK_". Signed-off-by: Bill Erickson Signed-off-by: Galen Charlton --- Open-ILS/src/eg2/src/app/core/idl.service.ts | 26 +++++++++++++++++-- .../app/share/combobox/combobox.component.ts | 10 ++++--- .../share/fm-editor/fm-editor.component.ts | 17 +++--------- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/core/idl.service.ts b/Open-ILS/src/eg2/src/app/core/idl.service.ts index b5abf61d78..fee3bd9637 100644 --- a/Open-ILS/src/eg2/src/app/core/idl.service.ts +++ b/Open-ILS/src/eg2/src/app/core/idl.service.ts @@ -140,6 +140,12 @@ export class IdlService { getLinkSelector(fmClass: string, field: string): string { let fieldDef = this.classes[fmClass].field_map[field]; + if (!fieldDef) { + console.warn( + `No such field "${field}" for IDL class "${fmClass}"`); + return null; + } + if (fieldDef.map) { // For mapped fields, we want the selector field on the // remotely linked object instead of the directly @@ -149,11 +155,27 @@ export class IdlService { } if (fieldDef.class) { - const classDef = this.classes[fieldDef.class]; + return this.getClassSelector(fieldDef.class); + } + return null; + } + + // Return the selector field for the class. If no selector is + // defined, use 'name' if it exists as a field on the class. + getClassSelector(idlClass: string): string { + + if (idlClass) { + const classDef = this.classes[idlClass]; + if (classDef.pkey) { - return classDef.field_map[classDef.pkey].selector || null; + let selector = classDef.field_map[classDef.pkey].selector; + if (selector) { return selector; } + + // No selector defined in the IDL, try 'name'. + if ('name' in classDef.field_map) { return 'name'; } } } + return null; } diff --git a/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts b/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts index ea49034a57..3d9860471f 100644 --- a/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts +++ b/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts @@ -173,7 +173,7 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit { } if (!this.idlField) { - this.idlField = classDef.field_map[classDef.pkey].selector || 'name'; + this.idlField = this.idl.getClassSelector(this.idlClass); } this.asyncDataSource = term => { @@ -332,8 +332,12 @@ export class ComboboxComponent implements ControlValueAccessor, OnInit { let searchTerm: string; searchTerm = term; - if (searchTerm === '_CLICK_' && this.asyncSupportsEmptyTermClick) { - searchTerm = ''; + if (searchTerm === '_CLICK_') { + if (this.asyncSupportsEmptyTermClick) { + searchTerm = ''; + } else { + return of(); + } } return new Observable(observer => { 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 6b6d3eb670..58c400fcf1 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 @@ -399,24 +399,13 @@ export class FmRecordEditorComponent }); } - // Returns the name of the field on a class (typically via a linked - // field) that acts as the selector value for display / search. - getClassSelector(class_: string): string { - if (class_) { - const linkedClass = this.idl.classes[class_]; - return linkedClass.pkey ? - linkedClass.field_map[linkedClass.pkey].selector : null; - } - return null; - } - private flattenLinkedValues(field: any, list: IdlObject[]): ComboboxEntry[] { const class_ = field.class; const fieldOptions = this.fieldOptions[field.name] || {}; const idField = this.idl.classes[class_].pkey; const selector = fieldOptions.linkedSearchField - || this.getClassSelector(class_) || idField; + || this.idl.getClassSelector(class_) || idField; return list.map(item => { return {id: item[idField](), label: item[selector]()}; @@ -499,7 +488,7 @@ export class FmRecordEditorComponent // field. Otherwise, avoid the network lookup and let the // bare value (usually an ID) be displayed. const selector = fieldOptions.linkedSearchField || - this.getClassSelector(field.class); + this.idl.getClassSelector(field.class); if (selector && selector !== field.name) { promise = this.pcrud.retrieve(field.class, idToFetch) @@ -544,7 +533,7 @@ export class FmRecordEditorComponent } const selector = fieldOptions.linkedSearchField || - this.getClassSelector(field.class); + this.idl.getClassSelector(field.class); if (!selector && !fieldOptions.preloadLinkedValues) { // User probably expects an async data source, but we can't -- 2.43.2