Merge pull request #10490 from opf/fix/41718/filter-values-in-frontend

[41718] Filter query filter values in the frontend
pull/10517/head
Henriette Darge 3 years ago committed by GitHub
commit f406da2f8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 72
      frontend/src/app/features/work-packages/components/filters/filter-searchable-multiselect-value/filter-searchable-multiselect-value.component.ts
  2. 6
      frontend/src/app/shared/components/autocompleter/op-autocompleter/op-autocompleter.component.ts

@ -8,6 +8,7 @@ import { CurrentProjectService } from 'core-app/core/current-project/current-pro
import { ApiV3FilterBuilder } from 'core-app/shared/helpers/api-v3/api-v3-filter-builder';
import {
map,
shareReplay,
switchMap,
withLatestFrom,
} from 'rxjs/operators';
@ -24,6 +25,7 @@ import {
EventEmitter,
Input,
NgZone,
OnInit,
Output,
ViewChild,
} from '@angular/core';
@ -31,13 +33,14 @@ import { HalResource } from 'core-app/features/hal/resources/hal-resource';
import { I18nService } from 'core-app/core/i18n/i18n.service';
import { CurrentUserService } from 'core-app/core/current-user/current-user.service';
import { take } from 'rxjs/internal/operators/take';
import { CollectionResource } from 'core-app/features/hal/resources/collection-resource';
@Component({
selector: 'op-filter-searchable-multiselect-value',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './filter-searchable-multiselect-value.component.html',
})
export class FilterSearchableMultiselectValueComponent extends UntilDestroyedMixin {
export class FilterSearchableMultiselectValueComponent extends UntilDestroyedMixin implements OnInit {
@Input() public filter:QueryFilterInstanceResource;
@Input() public shouldFocus = false;
@ -55,7 +58,9 @@ export class FilterSearchableMultiselectValueComponent extends UntilDestroyedMix
}, true,
);
autocompleterFn = (searchTerm:string):Observable<HalResource[]> => this.loadAvailable(searchTerm);
autocompleterFn = (searchTerm:string):Observable<HalResource[]> => this.autocomplete(searchTerm);
initialRequest$:Observable<CollectionResource>;
readonly text = {
placeholder: this.I18n.t('js.placeholders.selection'),
@ -78,23 +83,57 @@ export class FilterSearchableMultiselectValueComponent extends UntilDestroyedMix
super();
}
public loadAvailable(matching:string):Observable<HalResource[]> {
const filters:ApiV3FilterBuilder = this.createFilters(matching);
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
const { href } = this.filter.currentSchema!.values!.allowedValues as { href:string };
ngOnInit():void {
this.initialRequest$ = this
.loadCollection('')
.pipe(
shareReplay(1),
);
}
const filteredData = (this.apiV3Service.collectionFromString(href) as
ApiV3ResourceCollection<HalResource, ApiV3Resource>)
.filtered(filters, { pageSize: '-1' })
.get()
private autocomplete(matching:string):Observable<HalResource[]> {
return this
.initialRequest$
.pipe(
switchMap((collection) => this.withMeValue(matching, collection.elements)),
switchMap((initialLoad) => {
// If we already loaded all values, just compare in the frontend
if (initialLoad.count === initialLoad.total) {
return this.matchingItems(initialLoad.elements, matching);
}
// Otherwise, request the matching API call
return this
.loadCollection(matching)
.pipe(
switchMap((collection) => this.withMeValue(matching, collection.elements)),
);
}),
);
}
return filteredData;
matchingItems(elements:HalResource[], matching:string):Observable<HalResource[]> {
let filtered:HalResource[];
if (matching === '') {
filtered = elements;
} else {
const lowered = matching.toLowerCase();
filtered = elements.filter((el) => el.name.toLowerCase().includes(lowered));
}
return this.withMeValue(matching, filtered);
}
private loadCollection(matching:string):Observable<CollectionResource> {
const filters:ApiV3FilterBuilder = this.createFilters(matching);
return (this.apiV3Service.collectionFromString(this.allowedValuesLink) as
ApiV3ResourceCollection<HalResource, ApiV3Resource>)
.filtered(filters, { pageSize: '-1' })
.get();
}
protected createFilters(matching:string):ApiV3FilterBuilder {
private createFilters(matching:string):ApiV3FilterBuilder {
const filters = new ApiV3FilterBuilder();
if (matching) {
@ -110,6 +149,13 @@ export class FilterSearchableMultiselectValueComponent extends UntilDestroyedMix
this.cdRef.detectChanges();
}
private get allowedValuesLink():string {
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
const { href } = this.filter.currentSchema!.values!.allowedValues as { href:string };
return href;
}
private withMeValue(matching:string, elements:HalResource[]):Observable<HalResource[]> {
if (!this.isUserResource || (!!matching && matching !== 'me')) {
return of(elements);

@ -301,10 +301,8 @@ export class OpAutocompleterComponent extends UntilDestroyedMixin implements Aft
}
public opened(_:unknown) { // eslint-disable-line no-unused-vars
if (this.openDirectly) {
this.typeahead.next('');
}
// Re-search for empty value as search value gets removed
this.typeahead.next('');
this.repositionDropdown();
this.open.emit();
}

Loading…
Cancel
Save