[ACS-4130] Added autocomplete to folder rules 'Has Category' condition (#3464)

* [ACS-4130] Added autocomplete for 'Has Category' option in manage rules

* [ACS-4130] Added loading spinner and 'No options found' template for Has Category rule condition. Options are now fetched as soon as user selected 'Has Category' option

* [ACS-4130] Added code to fetch category name when viewing/editing existing rule with has category option selected

* [ACS-4130] Resolved issues related to editing existing rules with 'Has Category' condition

* [ACS-4130] Added safety checks and minor code refactoring

* [ACS-4130] Added unit tests for new autocomplete functionality

* [ACS-4130] Added feature to auto select first option from autocomplete dropdown when user focuses out of autocomplete input field

* [ACS-4130] Minor code refactoring. Moved constants from global scope to local scope

* [ACS-4130] Moved mock data to conditions.mock.ts. Removed redundant return type

* [ACS-4130] Resolved PR review comments - AutoCompleteOption is now an interface. Changed occurences of autocomplete with auto-complete. Removed/Added types

* [ACS-4130] Resolved PR review comments - AutoCompleteOption is now built using a single common helper method

* [ACS-4130] Added missed types
This commit is contained in:
swapnil-verma-gl 2023-10-11 18:00:44 +05:30 committed by GitHub
parent c7e2912759
commit ec18f6b9cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 350 additions and 23 deletions

View File

@ -139,6 +139,9 @@
}, },
"ERRORS": { "ERRORS": {
"DELETE_RULE_SET_LINK_FAILED": "Error while trying to delete a link from a rule set" "DELETE_RULE_SET_LINK_FAILED": "Error while trying to delete a link from a rule set"
},
"AUTOCOMPLETE": {
"NO_OPTIONS_FOUND": "No options found"
} }
} }
} }

View File

@ -37,12 +37,65 @@ export const mimeTypeMock: RuleSimpleCondition = {
parameter: '' parameter: ''
}; };
export const categoryMock: RuleSimpleCondition = { export const tagMock: RuleSimpleCondition = {
field: 'category', field: 'tag',
comparator: 'equals', comparator: 'equals',
parameter: '' parameter: ''
}; };
export const categoriesListMock = {
list: {
pagination: {
count: 3,
hasMoreItems: false,
totalItems: 0,
skipCount: 0,
maxItems: 25
},
entries: [
{
entry: {
path: {
name: '/a/fake/category/path/1'
},
hasChildren: false,
name: 'FakeCategory1',
id: 'fake-category-id-1',
nodeType: 'cm:category',
isFile: false,
isFolder: false
}
},
{
entry: {
path: {
name: '/a/fake/category/path/2'
},
hasChildren: false,
name: 'FakeCategory2',
id: 'fake-category-id-2',
nodeType: 'cm:category',
isFile: false,
isFolder: false
}
},
{
entry: {
path: {
name: '/a/fake/category/path/3'
},
hasChildren: false,
name: 'FakeCategory3',
id: 'fake-category-id-3',
nodeType: 'cm:category',
isFile: false,
isFolder: false
}
}
]
}
};
export const simpleConditionUnknownFieldMock: RuleSimpleCondition = { export const simpleConditionUnknownFieldMock: RuleSimpleCondition = {
field: 'unknown-field', field: 'unknown-field',
comparator: 'equals', comparator: 'equals',

View File

@ -22,7 +22,7 @@
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>. * from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
*/ */
export type RuleConditionFieldType = 'string' | 'number' | 'date' | 'type' | 'special' | 'mimeType'; export type RuleConditionFieldType = 'string' | 'number' | 'date' | 'type' | 'special' | 'mimeType' | 'auto-complete';
export interface RuleConditionField { export interface RuleConditionField {
name: string; name: string;
@ -30,7 +30,7 @@ export interface RuleConditionField {
type: RuleConditionFieldType; type: RuleConditionFieldType;
} }
export const comparatorHiddenForConditionFieldType: string[] = ['special', 'mimeType']; export const comparatorHiddenForConditionFieldType: string[] = ['special', 'mimeType', 'auto-complete'];
export const ruleConditionFields: RuleConditionField[] = [ export const ruleConditionFields: RuleConditionField[] = [
{ {
@ -56,7 +56,7 @@ export const ruleConditionFields: RuleConditionField[] = [
{ {
name: 'category', name: 'category',
label: 'ACA_FOLDER_RULES.RULE_DETAILS.FIELDS.HAS_CATEGORY', label: 'ACA_FOLDER_RULES.RULE_DETAILS.FIELDS.HAS_CATEGORY',
type: 'special' type: 'auto-complete'
}, },
{ {
name: 'tag', name: 'tag',

View File

@ -21,14 +21,54 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="aca-rule-simple-condition__form__parameter-input"> <mat-form-field class="aca-rule-simple-condition__form__parameter-input" [ngSwitch]="selectedField.type">
<mat-select formControlName="parameter" data-automation-id="simple-condition-value-select" *ngIf="selectedField?.type === 'mimeType'; else valueInput"> <mat-select formControlName="parameter" data-automation-id="simple-condition-value-select" *ngSwitchCase="'mimeType'">
<mat-option *ngFor="let mimeType of mimeTypes" <mat-option *ngFor="let mimeType of mimeTypes"
[value]="mimeType.value"> [value]="mimeType.value">
{{ mimeType.label }} {{ mimeType.label }}
</mat-option> </mat-option>
</mat-select> </mat-select>
<ng-template #valueInput> <ng-template [ngSwitchCase]="'auto-complete'">
<input
matInput
[matAutocomplete]="auto"
formControlName="parameter"
(focusout)="autoSelectValidOption()"
data-automation-id="auto-complete-input-field"
/>
<mat-autocomplete
#auto="matAutocomplete"
data-automation-id="folder-rule-auto-complete"
[autoActiveFirstOption]="true"
[autoSelectActiveOption]="true"
[displayWith]="autoCompleteDisplayFunction">
<mat-option disabled *ngIf="showLoadingSpinner; else optionList">
<span class="aca-rule-simple-condition__auto-complete-loading-spinner">
<mat-progress-spinner
color="primary"
mode="indeterminate"
data-automation-id="auto-complete-loading-spinner"
[diameter]="25"
></mat-progress-spinner>
</span>
</mat-option>
<ng-template #optionList>
<ng-container *ngIf="autoCompleteOptions?.length > 0; else noOptionsTemplate">
<mat-option
*ngFor="let option of autoCompleteOptions"
[value]="option.value">
{{ option.displayLabel }}
</mat-option>
</ng-container>
<ng-template #noOptionsTemplate>
<mat-option disabled>
{{ 'ACA_FOLDER_RULES.AUTOCOMPLETE.NO_OPTIONS_FOUND' | translate }}
</mat-option>
</ng-template>
</ng-template>
</mat-autocomplete>
</ng-template>
<ng-template ngSwitchDefault>
<input matInput placeholder="{{ 'ACA_FOLDER_RULES.RULE_DETAILS.PLACEHOLDER.VALUE' | translate }}" type="text" formControlName="parameter" data-automation-id="value-input"> <input matInput placeholder="{{ 'ACA_FOLDER_RULES.RULE_DETAILS.PLACEHOLDER.VALUE' | translate }}" type="text" formControlName="parameter" data-automation-id="value-input">
</ng-template> </ng-template>
</mat-form-field> </mat-form-field>

View File

@ -15,4 +15,11 @@
} }
} }
} }
&__auto-complete-loading-spinner {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
} }

View File

@ -22,16 +22,21 @@
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>. * from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, discardPeriodicTasks, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { RuleSimpleConditionUiComponent } from './rule-simple-condition.ui-component'; import { RuleSimpleConditionUiComponent } from './rule-simple-condition.ui-component';
import { CoreTestingModule } from '@alfresco/adf-core'; import { CoreTestingModule } from '@alfresco/adf-core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core'; import { DebugElement } from '@angular/core';
import { categoryMock, mimeTypeMock, simpleConditionUnknownFieldMock } from '../../mock/conditions.mock'; import { tagMock, mimeTypeMock, simpleConditionUnknownFieldMock, categoriesListMock } from '../../mock/conditions.mock';
import { MimeType } from './rule-mime-types'; import { MimeType } from './rule-mime-types';
import { CategoryService } from '@alfresco/adf-content-services';
import { of } from 'rxjs';
import { RuleSimpleCondition } from '../../model/rule-simple-condition.model';
import { delay } from 'rxjs/operators';
describe('RuleSimpleConditionUiComponent', () => { describe('RuleSimpleConditionUiComponent', () => {
let fixture: ComponentFixture<RuleSimpleConditionUiComponent>; let fixture: ComponentFixture<RuleSimpleConditionUiComponent>;
let categoryService: CategoryService;
const getByDataAutomationId = (dataAutomationId: string): DebugElement => const getByDataAutomationId = (dataAutomationId: string): DebugElement =>
fixture.debugElement.query(By.css(`[data-automation-id="${dataAutomationId}"]`)); fixture.debugElement.query(By.css(`[data-automation-id="${dataAutomationId}"]`));
@ -45,12 +50,20 @@ describe('RuleSimpleConditionUiComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}; };
const setValueInInputField = (inputFieldDataAutomationId: string, value: string) => {
const inputField = fixture.debugElement.query(By.css(`[data-automation-id="${inputFieldDataAutomationId}"]`)).nativeElement;
inputField.value = value;
inputField.dispatchEvent(new Event('input'));
fixture.detectChanges();
};
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [CoreTestingModule, RuleSimpleConditionUiComponent] imports: [CoreTestingModule, RuleSimpleConditionUiComponent]
}); });
fixture = TestBed.createComponent(RuleSimpleConditionUiComponent); fixture = TestBed.createComponent(RuleSimpleConditionUiComponent);
categoryService = TestBed.inject(CategoryService);
}); });
it('should default the field to the name, the comparator to equals and the value empty', () => { it('should default the field to the name, the comparator to equals and the value empty', () => {
@ -87,6 +100,20 @@ describe('RuleSimpleConditionUiComponent', () => {
expect(getComputedStyle(comparatorFormField).display).toBe('none'); expect(getComputedStyle(comparatorFormField).display).toBe('none');
}); });
it('should hide the comparator select box if the type of the field is autoComplete', () => {
const autoCompleteField = 'category';
fixture.detectChanges();
const comparatorFormField = getByDataAutomationId('comparator-form-field').nativeElement;
expect(fixture.componentInstance.isComparatorHidden).toBeFalsy();
expect(getComputedStyle(comparatorFormField).display).not.toBe('none');
changeMatSelectValue('field-select', autoCompleteField);
expect(fixture.componentInstance.isComparatorHidden).toBeTruthy();
expect(getComputedStyle(comparatorFormField).display).toBe('none');
});
it('should set the comparator to equals if the field is set to a type with different comparators', () => { it('should set the comparator to equals if the field is set to a type with different comparators', () => {
const onChangeFieldSpy = spyOn(fixture.componentInstance, 'onChangeField').and.callThrough(); const onChangeFieldSpy = spyOn(fixture.componentInstance, 'onChangeField').and.callThrough();
fixture.detectChanges(); fixture.detectChanges();
@ -165,9 +192,104 @@ describe('RuleSimpleConditionUiComponent', () => {
expect(getByDataAutomationId('simple-condition-value-select')).toBeTruthy(); expect(getByDataAutomationId('simple-condition-value-select')).toBeTruthy();
fixture.componentInstance.writeValue(categoryMock); fixture.componentInstance.writeValue(tagMock);
fixture.detectChanges(); fixture.detectChanges();
expect(getByDataAutomationId('value-input').nativeElement.value).toBe(''); expect(getByDataAutomationId('value-input').nativeElement.value).toBe('');
}); });
it('should provide auto-complete option when category is selected', () => {
fixture.detectChanges();
changeMatSelectValue('field-select', 'category');
expect(getByDataAutomationId('auto-complete-input-field')).toBeTruthy();
expect(fixture.componentInstance.form.get('parameter').value).toEqual('');
});
it('should fetch category list when category option is selected', fakeAsync(() => {
spyOn(categoryService, 'searchCategories').and.returnValue(of(categoriesListMock));
fixture.detectChanges();
changeMatSelectValue('field-select', 'category');
tick(500);
expect(categoryService.searchCategories).toHaveBeenCalledWith('');
}));
it('should fetch new category list with user input when user types into parameter field after category option is select', fakeAsync(() => {
const categoryValue = 'a new category';
spyOn(categoryService, 'searchCategories').and.returnValue(of(categoriesListMock));
fixture.detectChanges();
changeMatSelectValue('field-select', 'category');
tick(500);
expect(categoryService.searchCategories).toHaveBeenCalledWith('');
setValueInInputField('auto-complete-input-field', categoryValue);
tick(500);
expect(categoryService.searchCategories).toHaveBeenCalledWith(categoryValue);
}));
it('should fetch category details when a saved rule with category condition is edited', () => {
const savedCategoryMock: RuleSimpleCondition = {
field: 'category',
comparator: 'equals',
parameter: 'a-fake-category-id'
};
const fakeCategory = {
entry: {
path: '/a/fake/category/path',
hasChildren: false,
name: 'FakeCategory',
id: 'fake-category-id-1'
}
};
spyOn(categoryService, 'getCategory').and.returnValue(of(fakeCategory));
fixture.componentInstance.writeValue(savedCategoryMock);
fixture.detectChanges();
expect(categoryService.getCategory).toHaveBeenCalledWith(savedCategoryMock.parameter, { include: ['path'] });
});
it('should show loading spinner while auto-complete options are fetched, and then remove it once it is received', fakeAsync(() => {
spyOn(categoryService, 'searchCategories').and.returnValue(of(categoriesListMock).pipe(delay(1000)));
fixture.detectChanges();
changeMatSelectValue('field-select', 'category');
tick(500);
getByDataAutomationId('auto-complete-input-field')?.nativeElement?.click();
let loadingSpinner = getByDataAutomationId('auto-complete-loading-spinner');
expect(loadingSpinner).not.toBeNull();
tick(1000);
fixture.detectChanges();
loadingSpinner = getByDataAutomationId('auto-complete-loading-spinner');
expect(loadingSpinner).toBeNull();
discardPeriodicTasks();
}));
it('should display correct label for category when user selects a category from auto-complete dropdown', fakeAsync(() => {
spyOn(categoryService, 'searchCategories').and.returnValue(of(categoriesListMock));
fixture.detectChanges();
changeMatSelectValue('field-select', 'category');
tick(500);
getByDataAutomationId('auto-complete-input-field')?.nativeElement?.click();
changeMatSelectValue('folder-rule-auto-complete', categoriesListMock.list.entries[0].entry.id);
const displayValue = getByDataAutomationId('auto-complete-input-field')?.nativeElement?.value;
expect(displayValue).toBe('category/path/1/FakeCategory1');
discardPeriodicTasks();
}));
it('should automatically select first category when user focuses out of parameter form field with category option selected', fakeAsync(() => {
spyOn(categoryService, 'searchCategories').and.returnValue(of(categoriesListMock));
fixture.detectChanges();
changeMatSelectValue('field-select', 'category');
tick(500);
const autoCompleteInputField = getByDataAutomationId('auto-complete-input-field')?.nativeElement;
autoCompleteInputField.value = 'FakeCat';
autoCompleteInputField.dispatchEvent(new Event('focusout'));
const parameterValue = fixture.componentInstance.form.get('parameter').value;
expect(parameterValue).toEqual(categoriesListMock.list.entries[0].entry.id);
discardPeriodicTasks();
}));
}); });

View File

@ -22,22 +22,47 @@
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>. * from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { Component, forwardRef, Input, OnDestroy, ViewEncapsulation } from '@angular/core'; import { Component, forwardRef, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { AbstractControl, ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms'; import { AbstractControl, ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
import { RuleSimpleCondition } from '../../model/rule-simple-condition.model'; import { RuleSimpleCondition } from '../../model/rule-simple-condition.model';
import { comparatorHiddenForConditionFieldType, RuleConditionField, ruleConditionFields } from './rule-condition-fields'; import { comparatorHiddenForConditionFieldType, RuleConditionField, ruleConditionFields } from './rule-condition-fields';
import { RuleConditionComparator, ruleConditionComparators } from './rule-condition-comparators'; import { RuleConditionComparator, ruleConditionComparators } from './rule-condition-comparators';
import { AppConfigService } from '@alfresco/adf-core'; import { AppConfigService } from '@alfresco/adf-core';
import { MimeType } from './rule-mime-types'; import { MimeType } from './rule-mime-types';
import { CommonModule } from '@angular/common'; import { AsyncPipe, CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { CategoryService } from '@alfresco/adf-content-services';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { debounceTime, distinctUntilChanged, first, takeUntil } from 'rxjs/operators';
import { Subject, Subscription } from 'rxjs';
import { MatOptionModule } from '@angular/material/core';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { CategoryEntry } from '@alfresco/js-api';
interface AutoCompleteOption {
displayLabel: string;
value: string;
}
const AUTOCOMPLETE_OPTIONS_DEBOUNCE_TIME = 500;
@Component({ @Component({
standalone: true, standalone: true,
imports: [CommonModule, TranslateModule, ReactiveFormsModule, MatFormFieldModule, MatSelectModule, MatInputModule], imports: [
CommonModule,
TranslateModule,
ReactiveFormsModule,
MatFormFieldModule,
MatSelectModule,
MatInputModule,
MatAutocompleteModule,
AsyncPipe,
MatOptionModule,
MatProgressSpinnerModule
],
selector: 'aca-rule-simple-condition', selector: 'aca-rule-simple-condition',
templateUrl: './rule-simple-condition.ui-component.html', templateUrl: './rule-simple-condition.ui-component.html',
styleUrls: ['./rule-simple-condition.ui-component.scss'], styleUrls: ['./rule-simple-condition.ui-component.scss'],
@ -51,7 +76,7 @@ import { MatInputModule } from '@angular/material/input';
} }
] ]
}) })
export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnDestroy { export class RuleSimpleConditionUiComponent implements OnInit, ControlValueAccessor, OnDestroy {
readonly fields = ruleConditionFields; readonly fields = ruleConditionFields;
form = new FormGroup({ form = new FormGroup({
@ -62,6 +87,12 @@ export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnD
mimeTypes: MimeType[] = []; mimeTypes: MimeType[] = [];
autoCompleteOptions: AutoCompleteOption[] = [];
showLoadingSpinner: boolean;
private onDestroy$ = new Subject<void>();
private autoCompleteOptionsSubscription: Subscription;
private _readOnly = false; private _readOnly = false;
@Input() @Input()
get readOnly(): boolean { get readOnly(): boolean {
@ -71,15 +102,9 @@ export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnD
this.setDisabledState(isReadOnly); this.setDisabledState(isReadOnly);
} }
constructor(private config: AppConfigService) { constructor(private config: AppConfigService, private categoryService: CategoryService) {
this.mimeTypes = this.config.get<Array<MimeType>>('mimeTypes'); this.mimeTypes = this.config.get<Array<MimeType>>('mimeTypes');
} }
private formSubscription = this.form.valueChanges.subscribe((value: any) => {
this.onChange(value);
this.onTouch();
});
get isSelectedFieldKnown(): boolean { get isSelectedFieldKnown(): boolean {
const selectedFieldName = this.form.get('field').value; const selectedFieldName = this.form.get('field').value;
return this.fields.findIndex((field: RuleConditionField) => selectedFieldName === field.name) > -1; return this.fields.findIndex((field: RuleConditionField) => selectedFieldName === field.name) > -1;
@ -102,6 +127,7 @@ export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnD
get isComparatorHidden(): boolean { get isComparatorHidden(): boolean {
return comparatorHiddenForConditionFieldType.includes(this.selectedField?.type); return comparatorHiddenForConditionFieldType.includes(this.selectedField?.type);
} }
get comparatorControl(): AbstractControl { get comparatorControl(): AbstractControl {
return this.form.get('comparator'); return this.form.get('comparator');
} }
@ -115,6 +141,18 @@ export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnD
writeValue(value: RuleSimpleCondition) { writeValue(value: RuleSimpleCondition) {
this.form.setValue(value); this.form.setValue(value);
if (value?.field === 'category') {
this.showLoadingSpinner = true;
this.categoryService
.getCategory(value.parameter, { include: ['path'] })
.pipe(first())
.subscribe((category: CategoryEntry) => {
this.showLoadingSpinner = false;
const option = this.buildAutocompleteOptionFromCategory(category.entry.id, category.entry.path, category.entry.name);
this.autoCompleteOptions.push(option);
this.parameterControl.setValue(option.value);
});
}
} }
registerOnChange(fn: () => void) { registerOnChange(fn: () => void) {
@ -147,6 +185,70 @@ export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnD
} }
ngOnDestroy() { ngOnDestroy() {
this.formSubscription.unsubscribe(); this.onDestroy$.next();
this.onDestroy$.complete();
}
ngOnInit() {
this.form.valueChanges.pipe(takeUntil(this.onDestroy$)).subscribe((value: RuleSimpleCondition) => {
this.onChange(value);
this.onTouch();
});
this.form
.get('field')
.valueChanges.pipe(distinctUntilChanged(), takeUntil(this.onDestroy$))
.subscribe((field: string) => {
if (field === 'category') {
this.autoCompleteOptionsSubscription = this.form
.get('parameter')
.valueChanges.pipe(distinctUntilChanged(), debounceTime(AUTOCOMPLETE_OPTIONS_DEBOUNCE_TIME), takeUntil(this.onDestroy$))
.subscribe((categoryName) => {
this.getCategories(categoryName);
});
this.parameterControl.setValue('');
} else {
this.autoCompleteOptionsSubscription?.unsubscribe();
}
});
}
private getCategories(categoryName: string) {
this.showLoadingSpinner = true;
this.categoryService
.searchCategories(categoryName)
.pipe(first())
.subscribe((existingCategoriesResult) => {
this.showLoadingSpinner = false;
const options: AutoCompleteOption[] = existingCategoriesResult?.list?.entries?.map((rowEntry) =>
this.buildAutocompleteOptionFromCategory(rowEntry.entry.id, rowEntry.entry.path.name, rowEntry.entry.name)
);
if (options.length > 0) {
this.autoCompleteOptions = this.sortAutoCompleteOptions(options);
}
});
}
private sortAutoCompleteOptions(autoCompleteOptions: AutoCompleteOption[]): AutoCompleteOption[] {
return autoCompleteOptions.sort((option1, option2) => option1.displayLabel.localeCompare(option2.displayLabel));
}
autoCompleteDisplayFunction = (optionValue: string): string =>
optionValue && this.autoCompleteOptions ? this.autoCompleteOptions.find((option) => option.value === optionValue)?.displayLabel : optionValue;
autoSelectValidOption() {
const currentValue = this.parameterControl.value;
const isValidValueSelected = !!this.autoCompleteOptions?.find((option) => option.value === currentValue);
if (!isValidValueSelected) {
this.parameterControl.setValue(this.autoCompleteOptions?.[0].value);
}
}
buildAutocompleteOptionFromCategory(categoryId: string, categoryPath: string, categoryName: string): AutoCompleteOption {
const path = categoryPath.split('/').splice(3).join('/');
return {
value: categoryId,
displayLabel: path ? `${path}/${categoryName}` : categoryName
};
} }
} }