();
}
ngOnInit() {
@@ -70,11 +73,11 @@ export class SearchFilterAutocompleteChipsComponent implements SearchWidget, OnI
return !!this.selectedOptions;
}
- getCurrentValue(): string[]{
+ getCurrentValue(): AutocompleteOption[] {
return this.selectedOptions;
}
- onOptionsChange(selectedOptions: string[]) {
+ onOptionsChange(selectedOptions: AutocompleteOption[]) {
this.selectedOptions = selectedOptions;
if (this.enableChangeUpdate) {
this.updateQuery();
@@ -82,27 +85,62 @@ export class SearchFilterAutocompleteChipsComponent implements SearchWidget, OnI
}
}
- setValue(value: string[]) {
+ setValue(value: AutocompleteOption[]) {
this.selectedOptions = value;
this.displayValue$.next(this.selectedOptions.join(', '));
this.submitValues();
}
+ onInputChange(value: string) {
+ if (this.settings.field === AutocompleteField.CATEGORIES && value) {
+ this.searchForExistingCategories(value);
+ }
+ }
+
+ optionComparator(option1: AutocompleteOption, option2: AutocompleteOption): boolean {
+ return option1.id
+ ? option1.id.toUpperCase() === option2.id.toUpperCase()
+ : option1.value.toUpperCase() === option2.value.toUpperCase();
+ }
+
private updateQuery() {
- this.displayValue$.next(this.selectedOptions.join(', '));
+ this.displayValue$.next(this.selectedOptions.map(option => option.value).join(', '));
if (this.context && this.settings && this.settings.field) {
- this.context.queryFragments[this.id] = this.selectedOptions.map(val => `${this.settings.field}: "${val}"`).join(' OR ');
+ let queryFragments;
+ if (this.settings.field === AutocompleteField.CATEGORIES) {
+ queryFragments = this.selectedOptions.map(val => `${this.settings.field}:"workspace://SpacesStore/${val.id}"`);
+ } else {
+ queryFragments = this.selectedOptions.map(val => `${this.settings.field}:"${val.value}"`);
+ }
+ this.context.queryFragments[this.id] = queryFragments.join(' OR ');
this.context.update();
}
}
private setOptions() {
- if (this.settings.field === 'TAG') {
- this.tagService.getAllTheTags().subscribe(res => {
- this.autocompleteOptions = res.list.entries.map(tag => tag.entry.tag);
- });
- } else {
- this.autocompleteOptions = this.settings.options;
+ switch (this.settings.field) {
+ case AutocompleteField.TAG:
+ this.tagService.getAllTheTags().subscribe(tagPaging => {
+ this.autocompleteOptionsSubject$.next(tagPaging.list.entries.map(tag => ({
+ value: tag.entry.tag
+ })));
+ });
+ break;
+ case AutocompleteField.CATEGORIES:
+ this.autocompleteOptionsSubject$.next([]);
+ break;
+ default:
+ this.autocompleteOptionsSubject$.next(this.settings.autocompleteOptions);
}
}
+
+ private searchForExistingCategories(searchTerm: string) {
+ this.categoryService.searchCategories(searchTerm, 0, 15).subscribe((existingCategoriesResult) => {
+ this.autocompleteOptionsSubject$.next(existingCategoriesResult.list.entries.map((rowEntry) => {
+ const path = rowEntry.entry.path.name.split('/').splice(3).join('/');
+ const fullPath = path ? `${path}/${rowEntry.entry.name}` : rowEntry.entry.name;
+ return {id: rowEntry.entry.id, value: rowEntry.entry.name, fullPath};
+ }));
+ });
+ }
}
diff --git a/lib/content-services/src/lib/search/components/search-properties/search-properties.component.html b/lib/content-services/src/lib/search/components/search-properties/search-properties.component.html
index 148fbdf48f8..d8a60486a07 100644
--- a/lib/content-services/src/lib/search/components/search-properties/search-properties.component.html
+++ b/lib/content-services/src/lib/search/components/search-properties/search-properties.component.html
@@ -42,7 +42,7 @@
{{ 'SEARCH.SEARCH_PROPERTIES.FILE_TYPE' | translate }}
{
field: 'field',
fileExtensions: ['pdf', 'doc', 'txt']
};
+ component.ngOnInit();
fixture.detectChanges();
- expect(searchChipAutocompleteInputComponent.autocompleteOptions).toBe(component.settings.fileExtensions);
+ expect(searchChipAutocompleteInputComponent.autocompleteOptions).toEqual([{value: 'pdf'}, {value: 'doc'}, {value: 'txt'}]);
});
it('should set onReset$ for SearchChipAutocompleteInputComponent to correct value', () => {
@@ -154,10 +155,10 @@ describe('SearchPropertiesComponent', () => {
});
it('should compare file extensions case insensitive after calling compareOption on SearchChipAutocompleteInputComponent', () => {
- const option1 = 'pdf';
- const option2 = 'PdF';
+ const option1 = {value: 'pdf'};
+ const option2 = {value: 'PdF'};
expect(searchChipAutocompleteInputComponent.compareOption(option1, option2)).toBeTrue();
- expect(searchChipAutocompleteInputComponent.compareOption(option1, `${option2}1`)).toBeFalse();
+ expect(searchChipAutocompleteInputComponent.compareOption(option1, {value: `${option2.value}1`})).toBeFalse();
});
it('should remove preceding dot after calling formatChipValue on SearchChipAutocompleteInputComponent', () => {
@@ -167,11 +168,11 @@ describe('SearchPropertiesComponent', () => {
});
it('should filter file extensions case insensitive without dots after calling filter on SearchChipAutocompleteInputComponent', () => {
- const extensions = ['pdf', 'jpg', 'txt', 'png'];
+ const extensions = [{value: 'pdf'}, {value: 'jpg'}, {value: 'txt'}, {value: 'png'}];
const searchValue = 'p';
- expect(searchChipAutocompleteInputComponent.filter(extensions, searchValue)).toEqual(['pdf', 'jpg', 'png']);
- expect(searchChipAutocompleteInputComponent.filter(extensions, `.${searchValue}`)).toEqual(['pdf', 'png']);
+ expect(searchChipAutocompleteInputComponent.filter(extensions, searchValue)).toEqual([{value:'pdf'}, {value:'jpg'}, {value:'png'}]);
+ expect(searchChipAutocompleteInputComponent.filter(extensions, `.${searchValue}`)).toEqual([{value:'pdf'}, {value:'png'}]);
});
it('should set placeholder for SearchChipAutocompleteInputComponent to correct value', () => {
@@ -259,17 +260,17 @@ describe('SearchPropertiesComponent', () => {
});
it('should search by single file type', () => {
- const extension = 'pdf';
+ const extension = {value: 'pdf'};
getSearchChipAutocompleteInputComponent().optionsChanged.emit([extension]);
component.submitValues();
- expect(component.displayValue$.next).toHaveBeenCalledWith(extension);
- expect(component.context.queryFragments[component.id]).toBe(`${nameField}:("*.${extension}")`);
+ expect(component.displayValue$.next).toHaveBeenCalledWith('pdf');
+ expect(component.context.queryFragments[component.id]).toBe(`${nameField}:("*.${extension.value}")`);
expect(component.context.update).toHaveBeenCalled();
});
it('should search by multiple file types', () => {
- getSearchChipAutocompleteInputComponent().optionsChanged.emit(['pdf', 'txt']);
+ getSearchChipAutocompleteInputComponent().optionsChanged.emit([{value:'pdf'}, {value:'txt'}]);
component.submitValues();
expect(component.displayValue$.next).toHaveBeenCalledWith('pdf, txt');
@@ -279,7 +280,7 @@ describe('SearchPropertiesComponent', () => {
it('should search by file size and type', () => {
typeInFileSizeInput();
- getSearchChipAutocompleteInputComponent().optionsChanged.emit(['pdf', 'txt']);
+ getSearchChipAutocompleteInputComponent().optionsChanged.emit([{value:'pdf'}, {value:'txt'}]);
component.submitValues();
expect(component.displayValue$.next).toHaveBeenCalledWith('SEARCH.SEARCH_PROPERTIES.FILE_SIZE_OPERATOR.AT_LEAST 321 SEARCH.SEARCH_PROPERTIES.FILE_SIZE_UNIT_ABBREVIATION.KB, pdf, txt');
@@ -315,7 +316,7 @@ describe('SearchPropertiesComponent', () => {
clickFileSizeUnitsSelect();
getSelectOptions()[1].nativeElement.click();
fixture.detectChanges();
- const extensions = ['pdf', 'txt'];
+ const extensions = [{value: 'pdf'}, {value: 'txt'}];
getSearchChipAutocompleteInputComponent().optionsChanged.emit(extensions);
expect(component.getCurrentValue()).toEqual({
@@ -324,7 +325,7 @@ describe('SearchPropertiesComponent', () => {
fileSizeUnit: FileSizeUnit.MB,
fileSizeOperator: FileSizeOperator.AT_MOST
},
- fileExtensions: extensions
+ fileExtensions: ['pdf', 'txt']
});
});
});
@@ -342,7 +343,7 @@ describe('SearchPropertiesComponent', () => {
getSelectOptions()[1].nativeElement.click();
fixture.detectChanges();
searchChipAutocompleteInputComponent = getSearchChipAutocompleteInputComponent();
- searchChipAutocompleteInputComponent.optionsChanged.emit(['pdf', 'txt']);
+ searchChipAutocompleteInputComponent.optionsChanged.emit([{value: 'pdf'}, {value: 'txt'}]);
});
it('should reset form', () => {
diff --git a/lib/content-services/src/lib/search/components/search-properties/search-properties.component.ts b/lib/content-services/src/lib/search/components/search-properties/search-properties.component.ts
index 16770e53419..34e44b3d58c 100644
--- a/lib/content-services/src/lib/search/components/search-properties/search-properties.component.ts
+++ b/lib/content-services/src/lib/search/components/search-properties/search-properties.component.ts
@@ -26,6 +26,7 @@ import { SearchQueryBuilderService } from '../../services/search-query-builder.s
import { SearchProperties } from './search-properties';
import { TranslateService } from '@ngx-translate/core';
import { SearchWidget } from '../../models/search-widget.interface';
+import { AutocompleteOption } from '../../models/autocomplete-option.interface';
@Component({
selector: 'adf-search-properties',
@@ -39,6 +40,7 @@ export class SearchPropertiesComponent implements OnInit, AfterViewChecked, Sear
context?: SearchQueryBuilderService;
startValue: SearchProperties;
displayValue$ = new Subject();
+ autocompleteOptions: AutocompleteOption[] = [];
private _form = this.formBuilder.nonNullable.group({
fileSizeOperator: FileSizeOperator.AT_LEAST,
@@ -77,8 +79,8 @@ export class SearchPropertiesComponent implements OnInit, AfterViewChecked, Sear
return this._reset$;
}
- set selectedExtensions(extensions: string[]) {
- this._selectedExtensions = extensions;
+ set selectedExtensions(extensions: AutocompleteOption[]) {
+ this._selectedExtensions = this.parseFromAutocompleteOptions(extensions);
}
constructor(private formBuilder: FormBuilder, private translateService: TranslateService) {}
@@ -88,6 +90,7 @@ export class SearchPropertiesComponent implements OnInit, AfterViewChecked, Sear
if (!this.settings.fileExtensions) {
this.settings.fileExtensions = [];
}
+ this.autocompleteOptions = this.parseToAutocompleteOptions(this.settings.fileExtensions);
[this.sizeField, this.nameField] = this.settings.field.split(',');
}
if (this.startValue) {
@@ -127,8 +130,8 @@ export class SearchPropertiesComponent implements OnInit, AfterViewChecked, Sear
return event.key !== '-' && event.key !== 'e' && event.key !== '+';
}
- compareFileExtensions(extension1: string, extension2: string): boolean {
- return extension1.toUpperCase() === extension2.toUpperCase();
+ compareFileExtensions(extension1: AutocompleteOption, extension2: AutocompleteOption): boolean {
+ return extension1.value.toUpperCase() === extension2.value.toUpperCase();
}
getExtensionWithoutDot(extension: string): string {
@@ -136,11 +139,11 @@ export class SearchPropertiesComponent implements OnInit, AfterViewChecked, Sear
return extensionSplitByDot[extensionSplitByDot.length - 1];
}
- filterExtensions = (extensions: string[], filterValue: string): string[] => {
+ filterExtensions = (extensions: AutocompleteOption[], filterValue: string): AutocompleteOption[] => {
const filterValueLowerCase = this.getExtensionWithoutDot(filterValue).toLowerCase();
const extensionWithDot = filterValue.startsWith('.');
return extensions.filter((option) => {
- const optionLowerCase = option.toLowerCase();
+ const optionLowerCase = option.value.toLowerCase();
return extensionWithDot && filterValueLowerCase ? optionLowerCase.startsWith(filterValueLowerCase) : optionLowerCase.includes(filterValue);
});
};
@@ -196,10 +199,18 @@ export class SearchPropertiesComponent implements OnInit, AfterViewChecked, Sear
setValue(searchProperties: SearchProperties) {
this.form.patchValue(searchProperties.fileSizeCondition);
- this.selectedExtensions = searchProperties.fileExtensions;
+ this.selectedExtensions = this.parseToAutocompleteOptions(searchProperties.fileExtensions);
this.submitValues();
}
+ private parseToAutocompleteOptions(array: string[]): AutocompleteOption[] {
+ return array.map(value => ({value}));
+ }
+
+ private parseFromAutocompleteOptions(array: AutocompleteOption[]): string[] {
+ return array.flatMap(option => option.value);
+ }
+
private getOperatorNameWidth(operator: string, font: string): number {
const context = this.canvas.getContext('2d');
context.font = font;
diff --git a/lib/content-services/src/lib/search/models/autocomplete-option.interface.ts b/lib/content-services/src/lib/search/models/autocomplete-option.interface.ts
new file mode 100644
index 00000000000..a4fc71b5d8e
--- /dev/null
+++ b/lib/content-services/src/lib/search/models/autocomplete-option.interface.ts
@@ -0,0 +1,27 @@
+/*!
+ * @license
+ * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export interface AutocompleteOption {
+ value: string;
+ id?: string;
+ fullPath?: string;
+}
+
+export enum AutocompleteField {
+ TAG = 'TAG',
+ CATEGORIES = 'cm:categories'
+}
diff --git a/lib/content-services/src/lib/search/models/search-widget-settings.interface.ts b/lib/content-services/src/lib/search/models/search-widget-settings.interface.ts
index 4885fd2bbf7..2d80d61e172 100644
--- a/lib/content-services/src/lib/search/models/search-widget-settings.interface.ts
+++ b/lib/content-services/src/lib/search/models/search-widget-settings.interface.ts
@@ -15,6 +15,8 @@
* limitations under the License.
*/
+import { AutocompleteOption } from './autocomplete-option.interface';
+
export interface SearchWidgetSettings {
field: string;
/* allow the user to update search in every change */
@@ -27,6 +29,8 @@ export interface SearchWidgetSettings {
format?: string;
/* allow the user to search only within predefined options */
allowOnlyPredefinedValues?: boolean;
+ /* allow the user to predefine autocomplete options */
+ autocompleteOptions?: AutocompleteOption[];
[indexer: string]: any;
}