Skip to content

Commit

Permalink
Merge pull request #14246 from opf/housekeeping/relations-autocomplet…
Browse files Browse the repository at this point in the history
…er-refactoring

[50486] Cleanup autocompleter implementation for relations autocompleter
  • Loading branch information
oliverguenther authored Nov 29, 2023
2 parents d1f887b + 3a25ba2 commit 3e00c1b
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@

<wp-relations-autocomplete
*ngIf="active"
[inputPlaceholder]="text.set_or_remove_parent"
[placeholder]="text.set_or_remove_parent"
[workPackage]="workPackage"
(onCancel)="close()"
(onSelected)="updateParent($event)"
(cancel)="close()"
(change)="updateParent($event)"
data-test-selector="wp-relations-autocomplete"
filterCandidatesFor="parent">
</wp-relations-autocomplete>
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
<div class="wp-relations-input-section">
<wp-relations-autocomplete
[workPackage]="workPackage"
(onSelected)="onSelected($event)"
[additionalFilters]="queryFilters"
(change)="onSelected($event)"
[filters]="queryFilters"
[filterCandidatesFor]="relationType"
data-test-selector="wp-relations-autocomplete"
hiddenOverflowContainer=".work-packages-full-view--split-left">
</wp-relations-autocomplete>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
// See COPYRIGHT and LICENSE files for more details.
//++

import { Component, Inject } from '@angular/core';
import {
Component,
Inject,
} from '@angular/core';
import { I18nService } from 'core-app/core/i18n/i18n.service';
import { WorkPackageInlineCreateService } from 'core-app/features/work-packages/components/wp-inline-create/wp-inline-create.service';
import { WorkPackageInlineCreateComponent } from 'core-app/features/work-packages/components/wp-inline-create/wp-inline-create.component';
Expand All @@ -37,7 +40,6 @@ import { UrlParamsHelperService } from 'core-app/features/work-packages/componen
import { RelationResource } from 'core-app/features/hal/resources/relation-resource';
import { HalEventsService } from 'core-app/features/hal/services/hal-events.service';
import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
import { ApiV3Filter } from 'core-app/shared/helpers/api-v3/api-v3-filter-builder';
import { WorkPackageNotificationService } from 'core-app/features/work-packages/services/notifications/work-package-notification.service';
import { IsolatedQuerySpace } from 'core-app/features/work-packages/directives/query-space/isolated-query-space';

Expand All @@ -49,22 +51,23 @@ export class WpRelationInlineAddExistingComponent {

public isDisabled = false;

public queryFilters = this.buildQueryFilters();
public queryFilters:IAPIFilter[] = this.buildQueryFilters();

public text = {
abort: this.I18n.t('js.relation_buttons.abort'),
};

constructor(protected readonly parent:WorkPackageInlineCreateComponent,
constructor(
protected readonly parent:WorkPackageInlineCreateComponent,
@Inject(WorkPackageInlineCreateService) protected readonly wpInlineCreate:WpRelationInlineCreateServiceInterface,
protected apiV3Service:ApiV3Service,
protected wpRelations:WorkPackageRelationsService,
protected notificationService:WorkPackageNotificationService,
protected halEvents:HalEventsService,
protected urlParamsHelper:UrlParamsHelperService,
protected querySpace:IsolatedQuerySpace,
protected readonly I18n:I18nService) {
}
protected readonly I18n:I18nService,
) {}

public addExisting() {
if (_.isNil(this.selectedWpId)) {
Expand All @@ -76,7 +79,7 @@ export class WpRelationInlineAddExistingComponent {

this.wpInlineCreate.add(this.workPackage, newRelationId)
.then(() => {
this
void this
.apiV3Service
.work_packages
.id(this.workPackage)
Expand All @@ -101,6 +104,7 @@ export class WpRelationInlineAddExistingComponent {

public onSelected(workPackage?:WorkPackageResource) {
if (workPackage) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.selectedWpId = workPackage.id!;
this.addExisting();
}
Expand All @@ -118,7 +122,7 @@ export class WpRelationInlineAddExistingComponent {
this.parent.resetRow();
}

private buildQueryFilters():ApiV3Filter[] {
private buildQueryFilters():IAPIFilter[] {
const query = this.querySpace.query.value;

if (!query) {
Expand All @@ -131,6 +135,16 @@ export class WpRelationInlineAddExistingComponent {
return relationTypes.indexOf(id) === -1;
});

return this.urlParamsHelper.buildV3GetFilters(filters);
const iApiFilters:IAPIFilter[] = [];

filters.forEach((filter) => {
iApiFilters.push({
name: filter.id,
operator: filter.operator.id,
values: filter.values.map((f) => (typeof f === 'string' ? f : f.id)),
});
});

return iApiFilters;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@
<div class="grid-content medium-8">
<wp-relations-autocomplete
[workPackage]="workPackage"
(onSelected)="onSelected($event)"
(onCancel)="toggleRelationsCreateForm()"
(change)="onSelected($event)"
(cancel)="toggleRelationsCreateForm()"
[hiddenOverflowContainer]="'.work-packages-tab-view--overflow'"
[selectedRelationType]="selectedRelationType">
[selectedRelationType]="selectedRelationType"
data-test-selector="wp-relations-autocomplete">
</wp-relations-autocomplete>
</div>
<div class="grid-content medium-1 collapse wp-relations-controls-section relation-row">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,64 +27,92 @@
//++

import {
ChangeDetectorRef,
ChangeDetectionStrategy,
Component,
EventEmitter, HostListener,
Input, NgZone,
Output,
ViewChild,
ViewEncapsulation,
HostListener,
Input,
} from '@angular/core';
import { I18nService } from 'core-app/core/i18n/i18n.service';
import { WorkPackageResource } from 'core-app/features/hal/resources/work-package-resource';
import { from, Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import { IsolatedQuerySpace } from 'core-app/features/work-packages/directives/query-space/isolated-query-space';
import { PathHelperService } from 'core-app/core/path-helper/path-helper.service';
import {
from,
Observable,
of,
} from 'rxjs';
import {
catchError,
map,
} from 'rxjs/operators';
import { WorkPackageCollectionResource } from 'core-app/features/hal/resources/wp-collection-resource';
import { CurrentProjectService } from 'core-app/core/current-project/current-project.service';
import { HalResourceService } from 'core-app/features/hal/services/hal-resource.service';
import { SchemaCacheService } from 'core-app/core/schemas/schema-cache.service';
import { WorkPackageNotificationService } from 'core-app/features/work-packages/services/notifications/work-package-notification.service';
import { ApiV3Filter } from 'core-app/shared/helpers/api-v3/api-v3-filter-builder';
import { OpAutocompleterComponent } from 'core-app/shared/components/autocompleter/op-autocompleter/op-autocompleter.component';
import { HalResource } from 'core-app/features/hal/resources/hal-resource';
import {
ApiV3Filter,
ApiV3FilterBuilder,
} from 'core-app/shared/helpers/api-v3/api-v3-filter-builder';
import { SchemaCacheService } from 'core-app/core/schemas/schema-cache.service';
import { WorkPackageNotificationService } from 'core-app/features/work-packages/services/notifications/work-package-notification.service';
import { InjectField } from 'core-app/shared/helpers/angular/inject-field.decorator';

export interface IWorkPackageAutocompleteItem extends WorkPackageResource {
id:string,
}

@Component({
selector: 'wp-relations-autocomplete',
templateUrl: './wp-relations-autocomplete.html',

// Allow styling the embedded ng-select
encapsulation: ViewEncapsulation.None,
styleUrls: ['./wp-relations-autocomplete.sass'],
templateUrl: '../../../../../../shared/components/autocompleter/op-autocompleter/op-autocompleter.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class WorkPackageRelationsAutocompleteComponent {
readonly text = {
placeholder: this.I18n.t('js.relations_autocomplete.placeholder'),
};

@Input() inputPlaceholder:string = this.text.placeholder;

export class WorkPackageRelationsAutocompleteComponent extends OpAutocompleterComponent<IWorkPackageAutocompleteItem> {
@Input() workPackage:WorkPackageResource;

@Input() selectedRelationType:string;

@Input() filterCandidatesFor:string;

/** Do we take the current query filters into account? */
@Input() additionalFilters:ApiV3Filter[] = [];

@Input() hiddenOverflowContainer = 'body';

@ViewChild(OpAutocompleterComponent, { static: true }) public ngSelectComponent:OpAutocompleterComponent;
@InjectField(WorkPackageNotificationService) notificationService:WorkPackageNotificationService;

@InjectField(SchemaCacheService) schemaCacheService:SchemaCacheService;

@Output() onCancel = new EventEmitter<undefined>();
resource:TOpAutocompleterResource = 'work_packages';

@Output() onSelected = new EventEmitter<WorkPackageResource>();
appendTo = 'body';

placeholder = this.I18n.t('js.relations_autocomplete.placeholder');

getOptionsFn = this.getAutocompleterData.bind(this);

@HostListener('keydown.escape')
public reset() {
this.cancel.emit();
}

changed(workPackage:IWorkPackageAutocompleteItem|null) {
if (workPackage) {
void this.schemaCacheService
.ensureLoaded(workPackage)
.then(() => {
this.change.emit(workPackage);
this.ngSelectInstance.close();
});
}
}

@Output() onEmptySelected = new EventEmitter<undefined>();
opened() {
// Force reposition as a workaround for BUG
// https://github.com/ng-select/ng-select/issues/1259
this.ngZone.runOutsideAngular(() => {
setTimeout(() => {
this.ngSelectInstance.dropdownPanel.adjustPosition();
jQuery(this.hiddenOverflowContainer).one('scroll', () => {
this.ngSelectInstance.close();
});
}, 25);
});
}

getAutocompleterData = (query:string|null):Observable<HalResource[]> => {
getAutocompleterData(query:string|null):Observable<HalResource[]> {
// Return when the search string is empty
if (query === null || query.length === 0) {
return of([]);
Expand All @@ -93,7 +121,7 @@ export class WorkPackageRelationsAutocompleteComponent {
return from(
this.workPackage.availableRelationCandidates.$link.$fetch({
query,
filters: JSON.stringify(this.additionalFilters),
filters: JSON.stringify(this.createFilters()),
type: this.filterCandidatesFor || this.selectedRelationType,
sortBy: JSON.stringify([['typeahead', 'asc']]),
}) as Promise<WorkPackageCollectionResource>,
Expand All @@ -105,56 +133,17 @@ export class WorkPackageRelationsAutocompleteComponent {
return of([]);
}),
);
};

public autocompleterOptions = {
resource: 'work_packages',
getOptionsFn: this.getAutocompleterData,
};

public appendToContainer = 'body';

constructor(private readonly querySpace:IsolatedQuerySpace,
private readonly pathHelper:PathHelperService,
private readonly notificationService:WorkPackageNotificationService,
private readonly CurrentProject:CurrentProjectService,
private readonly halResourceService:HalResourceService,
private readonly schemaCacheService:SchemaCacheService,
private readonly cdRef:ChangeDetectorRef,
private readonly ngZone:NgZone,
private readonly I18n:I18nService) {
}

@HostListener('keydown.escape')
public reset() {
this.cancel();
}

cancel() {
this.onCancel.emit();
}
private createFilters():ApiV3Filter[] {
const finalFilters = new ApiV3FilterBuilder();

public onWorkPackageSelected(workPackage?:WorkPackageResource) {
if (workPackage) {
this.schemaCacheService
.ensureLoaded(workPackage)
.then(() => {
this.onSelected.emit(workPackage);
this.ngSelectComponent.ngSelectInstance.close();
});
if (this.filters) {
this.filters.forEach((filter) => {
finalFilters.add(filter.name, filter.operator, filter.values);
});
}
}

onOpen() {
// Force reposition as a workaround for BUG
// https://github.com/ng-select/ng-select/issues/1259
this.ngZone.runOutsideAngular(() => {
setTimeout(() => {
this.ngSelectComponent.repositionDropdown();
jQuery(this.hiddenOverflowContainer).one('scroll', () => {
this.ngSelectComponent.closeSelect();
});
}, 25);
});
return finalFilters.filters;
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ export class OpAutocompleterComponent<T extends IAutocompleteItem = IAutocomplet
readonly cdRef:ChangeDetectorRef,
readonly ngZone:NgZone,
readonly vcRef:ViewContainerRef,
private readonly I18n:I18nService,
readonly I18n:I18nService,
) {
super();
}
Expand Down

0 comments on commit 3e00c1b

Please sign in to comment.