mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[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:
parent
c7e2912759
commit
ec18f6b9cb
@ -139,6 +139,9 @@
|
||||
},
|
||||
"ERRORS": {
|
||||
"DELETE_RULE_SET_LINK_FAILED": "Error while trying to delete a link from a rule set"
|
||||
},
|
||||
"AUTOCOMPLETE": {
|
||||
"NO_OPTIONS_FOUND": "No options found"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,12 +37,65 @@ export const mimeTypeMock: RuleSimpleCondition = {
|
||||
parameter: ''
|
||||
};
|
||||
|
||||
export const categoryMock: RuleSimpleCondition = {
|
||||
field: 'category',
|
||||
export const tagMock: RuleSimpleCondition = {
|
||||
field: 'tag',
|
||||
comparator: 'equals',
|
||||
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 = {
|
||||
field: 'unknown-field',
|
||||
comparator: 'equals',
|
||||
|
@ -22,7 +22,7 @@
|
||||
* 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 {
|
||||
name: string;
|
||||
@ -30,7 +30,7 @@ export interface RuleConditionField {
|
||||
type: RuleConditionFieldType;
|
||||
}
|
||||
|
||||
export const comparatorHiddenForConditionFieldType: string[] = ['special', 'mimeType'];
|
||||
export const comparatorHiddenForConditionFieldType: string[] = ['special', 'mimeType', 'auto-complete'];
|
||||
|
||||
export const ruleConditionFields: RuleConditionField[] = [
|
||||
{
|
||||
@ -56,7 +56,7 @@ export const ruleConditionFields: RuleConditionField[] = [
|
||||
{
|
||||
name: 'category',
|
||||
label: 'ACA_FOLDER_RULES.RULE_DETAILS.FIELDS.HAS_CATEGORY',
|
||||
type: 'special'
|
||||
type: 'auto-complete'
|
||||
},
|
||||
{
|
||||
name: 'tag',
|
||||
|
@ -21,14 +21,54 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="aca-rule-simple-condition__form__parameter-input">
|
||||
<mat-select formControlName="parameter" data-automation-id="simple-condition-value-select" *ngIf="selectedField?.type === 'mimeType'; else valueInput">
|
||||
<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" *ngSwitchCase="'mimeType'">
|
||||
<mat-option *ngFor="let mimeType of mimeTypes"
|
||||
[value]="mimeType.value">
|
||||
{{ mimeType.label }}
|
||||
</mat-option>
|
||||
</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">
|
||||
</ng-template>
|
||||
</mat-form-field>
|
||||
|
@ -15,4 +15,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__auto-complete-loading-spinner {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
@ -22,16 +22,21 @@
|
||||
* 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 { CoreTestingModule } from '@alfresco/adf-core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
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 { 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', () => {
|
||||
let fixture: ComponentFixture<RuleSimpleConditionUiComponent>;
|
||||
let categoryService: CategoryService;
|
||||
|
||||
const getByDataAutomationId = (dataAutomationId: string): DebugElement =>
|
||||
fixture.debugElement.query(By.css(`[data-automation-id="${dataAutomationId}"]`));
|
||||
@ -45,12 +50,20 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
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(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CoreTestingModule, 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', () => {
|
||||
@ -87,6 +100,20 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
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', () => {
|
||||
const onChangeFieldSpy = spyOn(fixture.componentInstance, 'onChangeField').and.callThrough();
|
||||
fixture.detectChanges();
|
||||
@ -165,9 +192,104 @@ describe('RuleSimpleConditionUiComponent', () => {
|
||||
|
||||
expect(getByDataAutomationId('simple-condition-value-select')).toBeTruthy();
|
||||
|
||||
fixture.componentInstance.writeValue(categoryMock);
|
||||
fixture.componentInstance.writeValue(tagMock);
|
||||
fixture.detectChanges();
|
||||
|
||||
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();
|
||||
}));
|
||||
});
|
||||
|
@ -22,22 +22,47 @@
|
||||
* 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 { RuleSimpleCondition } from '../../model/rule-simple-condition.model';
|
||||
import { comparatorHiddenForConditionFieldType, RuleConditionField, ruleConditionFields } from './rule-condition-fields';
|
||||
import { RuleConditionComparator, ruleConditionComparators } from './rule-condition-comparators';
|
||||
import { AppConfigService } from '@alfresco/adf-core';
|
||||
import { MimeType } from './rule-mime-types';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AsyncPipe, CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
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({
|
||||
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',
|
||||
templateUrl: './rule-simple-condition.ui-component.html',
|
||||
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;
|
||||
|
||||
form = new FormGroup({
|
||||
@ -62,6 +87,12 @@ export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnD
|
||||
|
||||
mimeTypes: MimeType[] = [];
|
||||
|
||||
autoCompleteOptions: AutoCompleteOption[] = [];
|
||||
|
||||
showLoadingSpinner: boolean;
|
||||
|
||||
private onDestroy$ = new Subject<void>();
|
||||
private autoCompleteOptionsSubscription: Subscription;
|
||||
private _readOnly = false;
|
||||
@Input()
|
||||
get readOnly(): boolean {
|
||||
@ -71,15 +102,9 @@ export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnD
|
||||
this.setDisabledState(isReadOnly);
|
||||
}
|
||||
|
||||
constructor(private config: AppConfigService) {
|
||||
constructor(private config: AppConfigService, private categoryService: CategoryService) {
|
||||
this.mimeTypes = this.config.get<Array<MimeType>>('mimeTypes');
|
||||
}
|
||||
|
||||
private formSubscription = this.form.valueChanges.subscribe((value: any) => {
|
||||
this.onChange(value);
|
||||
this.onTouch();
|
||||
});
|
||||
|
||||
get isSelectedFieldKnown(): boolean {
|
||||
const selectedFieldName = this.form.get('field').value;
|
||||
return this.fields.findIndex((field: RuleConditionField) => selectedFieldName === field.name) > -1;
|
||||
@ -102,6 +127,7 @@ export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnD
|
||||
get isComparatorHidden(): boolean {
|
||||
return comparatorHiddenForConditionFieldType.includes(this.selectedField?.type);
|
||||
}
|
||||
|
||||
get comparatorControl(): AbstractControl {
|
||||
return this.form.get('comparator');
|
||||
}
|
||||
@ -115,6 +141,18 @@ export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnD
|
||||
|
||||
writeValue(value: RuleSimpleCondition) {
|
||||
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) {
|
||||
@ -147,6 +185,70 @@ export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnD
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user