description fitler refactoring

This commit is contained in:
Sofia Papacharalampous 2024-06-27 17:27:04 +03:00
parent bb80a3ddff
commit 2d7787914c
14 changed files with 253 additions and 212 deletions

View File

@ -47,10 +47,8 @@ export interface DescriptionFilter {
}
export class ReferencesWithType {
referenceType?: Guid;
referenceTypeId?: Guid;
referenceIds?: Guid[];
references?: Guid[];
constructor() {
}

View File

@ -124,6 +124,19 @@ export class DescriptionTemplateService {
valueAssign: (item: DescriptionTemplate) => item.id,
popupItemActionIcon: 'visibility'
};
public buildMultipleAutocompleteConfiguration(preview: boolean = false): MultipleAutoCompleteConfiguration {
return {
initialItems: (excludedItems: any[], data?: any) => this.query(this.buildAutocompleteLookup(null, excludedItems ? excludedItems : null)).pipe(map(x => x.items)),
filterFn: (searchQuery: string, excludedItems: any[]) => this.query(this.buildAutocompleteLookup(searchQuery, excludedItems)).pipe(map(x => x.items)),
getSelectedItems: (selectedItems: any[]) => this.query(this.buildAutocompleteLookup(null, null, selectedItems)).pipe(map(x => x.items)),
displayFn: (item: DescriptionTemplate) => item.label,
titleFn: (item: DescriptionTemplate) => item.label,
subtitleFn: (item: DescriptionTemplate) => item.description,
valueAssign: (item: DescriptionTemplate) => item.id,
popupItemActionIcon: preview ? 'visibility' : null,
};
}
public buildAutocompleteLookup(like?: string, excludedIds?: Guid[], ids?: Guid[]): DescriptionTemplateLookup {
const lookup: DescriptionTemplateLookup = new DescriptionTemplateLookup();

View File

@ -104,19 +104,6 @@ export class ReferenceTypeService {
};
public getSingleAutocompleteConfiguration(excludedIds: Guid[] = null): SingleAutoCompleteConfiguration {
return {
initialItems: (data?: any) => this.query(this.buildAutocompleteLookup(null, excludedIds)).pipe(map(x => x.items)),
filterFn: (searchQuery: string, data?: any) => this.query(this.buildAutocompleteLookup(searchQuery, excludedIds)).pipe(map(x => x.items)),
getSelectedItem: (selectedItem: ReferenceType) => this.query(this.buildAutocompleteLookup(null, null, [selectedItem.id])).pipe(map(x => x.items[0])),
displayFn: (item: ReferenceType) => item.name,
titleFn: (item: ReferenceType) => item.name,
valueAssign: (item: ReferenceType) => item,
uniqueAssign: (item: ReferenceType) => JSON.stringify(item),
loadDataOnStart: false
};
}
public getSingleAutocompleteConfigurationForDmp(excludedIds: Guid[] = null): SingleAutoCompleteConfiguration {
return {
initialItems: (data?: any) => this.query(this.buildAutocompleteLookup(null, excludedIds)).pipe(map(x => x.items)),
filterFn: (searchQuery: string, data?: any) => this.query(this.buildAutocompleteLookup(searchQuery, excludedIds)).pipe(map(x => x.items)),

View File

@ -1,9 +1,7 @@
<div class="main-content listing-main-container h-100">
<div class="container-fluid">
<div class="row">
<div *ngIf="hasListingItems && listingItems && listingItems.length === 0 && !hasLikeFilters()" class="card mt-0">
<!-- <div class="card mt-0" [style.display]="isVisible ? 'block' : 'none'"> -->
<!-- <a class="col-auto d-flex" (click)="closeCard()"><span class="ml-auto pt-3 material-icons clear-icon">clear</span></a> -->
<div *ngIf="hasLoadedListingItems && !hasListingItems && !hasFilters" class="card mt-0">
<div class="card-content info-text mb-0">
<p>{{'DESCRIPTION-LISTING.TEXT-INFO' | translate}} <u class="pointer" [routerLink]="routerUtils.generateUrl(['/explore-descriptions'])">{{'DESCRIPTION-LISTING.LINK-PUBLIC-DESCRIPTIONS' | translate}}</u> {{'DESCRIPTION-LISTING.TEXT-INFO-REST' | translate}}</p>
<p class="mt-4 pt-2">{{'DESCRIPTION-LISTING.TEXT-INFO-PAR' | translate}}
@ -16,13 +14,13 @@
</div>
</div>
<div class="col-auto">
<div *ngIf="listingItems && listingItems.length > 0 || lookup.like" class="row">
<div *ngIf="hasLoadedListingItems" class="row">
<div class="col-12">
<app-navigation-breadcrumb />
</div>
</div>
</div>
<div *ngIf="listingItems && listingItems.length > 0 && !isPublic || lookup.like" class="ml-auto">
<div *ngIf="hasLoadedListingItems && !hasListingItems && !isPublic || hasFilters" class="ml-auto">
<div class="col-auto">
<button mat-raised-button class="add-description align-self-center yellow-btn" (click)="addNewDescription()">
{{'DESCRIPTION-LISTING.ACTIONS.ADD-DESCRIPTION' | translate}}
@ -31,14 +29,14 @@
</div>
<div *ngIf="listingItems && listingItems.length > 0 || lookup.like || lookup.descriptionTemplateSubQuery || lookup.dmpSubQuery || lookup.descriptionTagSubQuery || lookup.descriptionReferenceSubQuery"
class="filter-btn" [style.right]="dialog.getDialogById('filters') ? '446px' : '0px'" [style.width]="listingItems.length > 2 ? '57px' : '37px'" (click)="openFiltersDialog()">
<button mat-raised-button class="p-0">
<button mat-raised-button class="p-0" [matBadge]="filtersCount" [matBadgeHidden]="!hasFilters" matBadgePosition="before">
<mat-icon class="mr-4 filter-icon">filter_alt</mat-icon>
</button>
</div>
</div>
<div>
<div class="listing row pb-2">
<div *ngIf="listingItems && listingItems.length > 0 || this.lookup.like" class="col-md-12">
<div *ngIf="hasLoadedListingItems" class="listing row pb-2">
<div *ngIf="hasListingItems || hasFilters" class="col-md-12">
<div class="row pt-4">
<!-- Sort by -->
<div class="col-auto d-flex align-items-center order-1">
@ -84,11 +82,11 @@
<div *ngFor="let item of listingItems; let i = index">
<app-description-listing-item-component [isPublic]="isPublic" [description]="item" [showDivider]="i != (listingItems.length - 1)"></app-description-listing-item-component>
</div>
<div *ngIf="listingItems && listingItems.length > 0 && this.lookup?.page?.offset < this.totalCount - 1 && this.pageSize < this.totalCount - 1" class="d-flex justify-content-center">
<div *ngIf="hasListingItems && this.lookup?.page?.offset < this.totalCount - 1 && this.pageSize < this.totalCount - 1" class="d-flex justify-content-center">
<button type="button" class="btn-load-more" (click)="loadMore()">{{'DESCRIPTION-LISTING.ACTIONS.LOAD-MORE' | translate}}</button>
</div>
</div>
<div *ngIf="hasListingItems && listingItems && listingItems.length === 0 && this.lookup.like !== ''" class="col-md-12 d-flex justify-content-center pt-4 mt-4 mb-4 pb-4">
<div *ngIf="!hasListingItems && hasFilters" class="col-md-12 d-flex justify-content-center pt-4 mt-4 mb-4 pb-4">
<span class="empty-list">{{'DESCRIPTION-LISTING.EMPTY-LIST' | translate}}</span>
</div>
</div>

View File

@ -1,5 +1,5 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { FormBuilder, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
@ -8,7 +8,7 @@ import { IsActive } from '@app/core/common/enum/is-active.enum';
import { AppPermission } from '@app/core/common/enum/permission.enum';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { BaseDescription, Description, DescriptionReference, DescriptionTag } from '@app/core/model/description/description';
import { BaseDescription, Description } from '@app/core/model/description/description';
import { DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { Dmp, DmpDescriptionTemplate, DmpUser } from '@app/core/model/dmp/dmp';
import { DmpReference } from '@app/core/model/dmp/dmp-reference';
@ -36,12 +36,7 @@ import { Observable } from 'rxjs';
import { QueryParamsService } from '@app/core/services/utilities/query-params.service';
import { UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { Guid } from '@common/types/guid';
import { DescriptionReferenceLookup } from '@app/core/query/reference.lookup';
import { DescriptionTagLookup } from '@app/core/query/tag.lookup';
import { Tag } from '@app/core/model/tag/tag';
import { DmpLookup } from '@app/core/query/dmp.lookup';
import { DescriptionTemplateLookup } from '@app/core/query/description-template.lookup';
import { DmpUserLookup } from '@app/core/query/dmp-user.lookup';
import { DescriptionFilterService } from './filtering/description-filter.service';
@Component({
selector: 'app-description-listing-component',
@ -61,12 +56,11 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
totalCount: number;
dmpSearchEnabled = true;
listingItems: any[] = [];
hasListingItems = null;
hasLoadedListingItems: boolean = false;
isPublic: boolean = false;
public isVisible = true
public isVisible = true;
protected ITEMS_PER_PAGE = 5;
filtersCount: number;
pageSize: number = 5;
lookup: DescriptionLookup;
referenceFilters: ReferencesWithType[];
@ -96,8 +90,21 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
get sortingTooltipText(): string {
return this.isAscending ? this.language.instant('DESCRIPTION-LISTING.ACTIONS.TOGGLE-ΑSCENDING') : this.language.instant('DESCRIPTION-LISTING.ACTIONS.TOGGLE-DESCENDING');
}
get hasListingItems(): boolean {
return this.listingItems != null && this.listingItems.length > 0;
}
get hasFilters(): boolean {
return (this.lookup.like != null && this.lookup.like != '') || this.lookup.statuses != null ||
this.lookup.dmpSubQuery != null || this.lookup.descriptionTemplateSubQuery != null ||
this.lookup.descriptionTagSubQuery != null || this.lookup.descriptionReferenceSubQuery != null;
}
constructor(
protected router: Router,
protected route: ActivatedRoute,
protected uiNotificationService: UiNotificationService,
protected httpErrorHandlingService: HttpErrorHandlingService,
protected queryParamsService: QueryParamsService,
public routerUtils: RouterUtilsService,
private descriptionService: DescriptionService,
public dialog: MatDialog,
@ -107,11 +114,6 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
private guidedTourService: GuidedTourService,
private analyticsService: AnalyticsService,
private fb: UntypedFormBuilder,
protected httpErrorHandlingService: HttpErrorHandlingService,
protected router: Router,
protected route: ActivatedRoute,
protected uiNotificationService: UiNotificationService,
protected queryParamsService: QueryParamsService,
protected formBuilder: FormBuilder,
) {
super(router, route, uiNotificationService, httpErrorHandlingService, queryParamsService);
@ -130,7 +132,16 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
.subscribe(async (params: Params) => {
const queryParams = this.route.snapshot.queryParams;
if (!this.lookup) this.lookup = queryParams['lookup'] ? this._parseLookupFromParams(queryParams) : this.initializeLookup();
if (!this.lookup && queryParams['lookup']) {
this.lookup = this._parseLookupFromParams(queryParams);
this.referenceFilters = [{
referenceTypeId: null,
referenceIds: this.lookup?.descriptionReferenceSubQuery?.referenceIds ?? [],
}];
this.filtersCount = this._countFilters(this.lookup);
}
else if (!this.lookup) this.lookup = this.initializeLookup();
if ((this.formGroup.get('order')?.value == null || (!this.isAscending && !this.isDescending)) && this.lookup.order.items && this.lookup.order.items.length > 0) {
@ -161,7 +172,7 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
this.totalCount = result.count;
if (this.lookup?.page?.offset === 0) this.listingItems = [];
this.listingItems.push(...result.items);
this.hasListingItems = true;
this.hasLoadedListingItems = true;
}));
} else {
return this.descriptionService.query(this.lookup).pipe(takeUntil(this._destroyed))
@ -170,7 +181,7 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
this.totalCount = result.count;
if (this.lookup?.page?.offset === 0) this.listingItems = [];
this.listingItems.push(...result.items);
this.hasListingItems = true;
this.hasLoadedListingItems = true;
}));
}
}
@ -179,7 +190,6 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
const lookup = new DescriptionLookup();
lookup.metadata = { countAll: true };
lookup.page = { offset: 0, size: this.ITEMS_PER_PAGE };
// lookup.statuses = [DescriptionStatus.Draft, DescriptionStatus.Finalized, DescriptionStatus.Canceled]
lookup.isActive = [IsActive.Active];
let recentActivityOrder = this.isPublic ? this.toAscSortField(nameof<Description>(x => x.label)) : this.toDescSortField(nameof<Description>(x => x.updatedAt));
@ -193,74 +203,8 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
return lookup;
}
protected initializeReferenceLookup(): DescriptionReferenceLookup {
const lookup = new DescriptionReferenceLookup();
lookup.metadata = { countAll: true };
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
[nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.id)].join('.'),
]
};
return lookup;
}
protected initializeTagLookup(): DescriptionTagLookup {
const lookup = new DescriptionTagLookup();
lookup.metadata = { countAll: true };
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
[nameof<DescriptionTag>(x => x.tag), nameof<Tag>(x => x.id)].join('.'),
]
};
return lookup;
}
protected initializeDmpLookup(): DmpLookup {
const lookup = new DmpLookup();
lookup.metadata = { countAll: true };
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.id)].join('.'),
]
};
return lookup;
}
protected initializeDmpUserLookup(): DmpUserLookup {
const lookup = new DmpUserLookup();
lookup.metadata = { countAll: true };
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
[nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'),
]
};
return lookup;
}
protected initializeDescriptionTemplateLookup(): DescriptionTemplateLookup {
const lookup = new DescriptionTemplateLookup();
lookup.metadata = { countAll: true };
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
]
};
return lookup;
}
protected setupColumns() {
}
protected setupColumns() { }
public dashboardTour: GuidedTour = {
tourId: 'dmp-description-tour',
@ -320,6 +264,7 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
data: {
isPublic: this.isPublic ?? true,
filterForm: this._buildFormFromLookup(this.lookup, this.referenceFilters),
referencesWithTypeItems: this.referenceFilters ?? [],
}
});
@ -333,6 +278,7 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
updateDataFn(filterForm: UntypedFormGroup): void {
this.referenceFilters = this._patchReferenceFiltersFromForm(filterForm);
this.lookup = this._patchLookupFromForm(this.lookup, filterForm);
this.filtersCount = this._countFilters(this.lookup);
this.filterChanged(this.lookup)
}
@ -416,7 +362,6 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
const queryOffset = 0;
const querySize = (lookup.page?.offset ?? 0) + this.pageSize;
lookup.page = { size: querySize, offset: queryOffset };
// lookup.statuses = [DescriptionStatus.Draft, DescriptionStatus.Finalized];
lookup.project = { fields: this._lookupFields };
lookup.metadata = { countAll: true };
return lookup;
@ -438,7 +383,7 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
// Description Templates
let descriptionTemplates = formGroup.get("descriptionTemplates")?.value ?? null;
if (descriptionTemplates && descriptionTemplates?.length > 0) {
lookup.descriptionTemplateSubQuery = this.initializeDescriptionTemplateLookup();
lookup.descriptionTemplateSubQuery = DescriptionFilterService.initializeDescriptionTemplateLookup();
lookup.descriptionTemplateSubQuery.ids = descriptionTemplates;
} else lookup.descriptionTemplateSubQuery = null;
@ -446,12 +391,12 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
let dmps = formGroup.get("associatedDmpIds")?.value ?? null; let addDmps = dmps && dmps?.length > 0;
let roles = formGroup.get("role")?.value !== null ? [formGroup.get("role")?.value] : null; let addRoles = roles && roles?.length > 0;
if (addDmps || addRoles) {
lookup.dmpSubQuery = this.initializeDmpLookup();
lookup.dmpSubQuery = DescriptionFilterService.initializeDmpLookup();
if (addDmps) lookup.dmpSubQuery.ids = dmps?.length > 0 ? dmps : null;
if (addRoles) {
lookup.dmpSubQuery.dmpUserSubQuery = this.initializeDmpUserLookup();
lookup.dmpSubQuery.dmpUserSubQuery = DescriptionFilterService.initializeDmpUserLookup();
lookup.dmpSubQuery.dmpUserSubQuery.userRoles = roles;
}
} else lookup.dmpSubQuery = null;
@ -459,17 +404,17 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
// Tags
let tags = formGroup.get("tags")?.value ?? null;
if (tags && tags?.length > 0) {
lookup.descriptionTagSubQuery = this.initializeTagLookup();
lookup.descriptionTagSubQuery = DescriptionFilterService.initializeTagLookup();
lookup.descriptionTagSubQuery.tagIds = tags;
} else lookup.descriptionTagSubQuery = null;
// References
let references: Guid[] = formGroup.get("references")?.value
?.filter((reference: ReferencesWithType) => reference.referenceType != null && reference.references?.length > 0)
?.flatMap((referencesWithType: ReferencesWithType) => referencesWithType.references) as Guid[];
?.filter((reference: ReferencesWithType) => reference.referenceTypeId != null && reference.referenceIds?.length > 0)
?.flatMap((referencesWithType: ReferencesWithType) => referencesWithType.referenceIds) as Guid[];
if (references && references?.length > 0) {
lookup.descriptionReferenceSubQuery = this.initializeReferenceLookup();
lookup.descriptionReferenceSubQuery = DescriptionFilterService.initializeReferenceLookup();
lookup.descriptionReferenceSubQuery.referenceIds = references;
} else lookup.descriptionReferenceSubQuery = null;
@ -477,30 +422,33 @@ export class DescriptionListingComponent extends BaseListingComponent<BaseDescri
}
_patchReferenceFiltersFromForm(formGroup: UntypedFormGroup): ReferencesWithType[] {
return formGroup?.get("references")?.value?.filter(reference => reference.referenceType != null && reference.references?.length > 0) ?? null;
return formGroup?.get("references")?.value?.filter(( referencesWithType: ReferencesWithType ) => referencesWithType.referenceTypeId != null && referencesWithType.referenceIds?.length > 0) ?? null;
}
_buildFormFromLookup(lookup: DescriptionLookup, referenceFilters: ReferencesWithType[]): UntypedFormGroup {
const formArray = this.formBuilder.array([]) as UntypedFormArray;
referenceFilters?.forEach(reference => {
let referenceForm = this.formBuilder.group({
referenceType: reference.referenceType,
references: reference.references?.length > 0 ? [reference.references] : []
});
formArray.push(referenceForm);
});
return (new UntypedFormBuilder()).group({
status: [lookup.statuses?.length > 0 ? lookup.statuses[0] : null],
role: lookup.dmpSubQuery?.dmpUserSubQuery?.userRoles ? lookup.dmpSubQuery?.dmpUserSubQuery?.userRoles[0] : [],
descriptionTemplates: lookup.descriptionTemplateSubQuery?.ids ? [lookup.descriptionTemplateSubQuery?.ids] : [],
associatedDmpIds: lookup.dmpSubQuery?.ids ? [lookup.dmpSubQuery?.ids] : [],
tags: lookup.descriptionTagSubQuery?.tagIds ? [lookup.descriptionTagSubQuery?.tagIds] : [],
references: formArray
});
}
private _countFilters(lookup: DescriptionLookup): number {
let count = 0;
if (lookup.statuses) count += lookup.statuses.length;
if (lookup.descriptionTemplateSubQuery) count += lookup.descriptionTemplateSubQuery.ids?.length;
if (lookup.descriptionTagSubQuery) count += lookup.descriptionTagSubQuery.tagIds?.length;
if (lookup.dmpSubQuery) {
if (lookup.dmpSubQuery.ids) count += lookup.dmpSubQuery.ids?.length;
if (lookup.dmpSubQuery.dmpUserSubQuery) count += lookup.dmpSubQuery.dmpUserSubQuery.userRoles?.length;
}
if (lookup.descriptionReferenceSubQuery) count += lookup.descriptionReferenceSubQuery.referenceIds?.length;
return count;
}
private get _lookupFields(): string[] {
return [

View File

@ -10,6 +10,7 @@ import { StartNewDescriptionDialogModule } from '../start-new-description-dialog
import { DescriptionFilterDialogComponent } from './filtering/description-filter-dialogue/description-filter-dialog.component';
import { DescriptionFilterComponent } from './filtering/description-filter.component';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { DescriptionFilterService } from './filtering/description-filter.service';
@NgModule({
imports: [
@ -28,7 +29,10 @@ import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.mod
DescriptionFilterComponent,
],
exports: [
DescriptionListingItemComponent
DescriptionListingItemComponent,
],
providers: [
DescriptionFilterService,
]
})
export class DescriptionListingModule { }

View File

@ -2,6 +2,7 @@
<a class="col-auto d-flex pointer" (click)="onClose()"><span class="ml-auto mt-3 material-icons clear-icon">clear</span></a>
<app-description-filter-component
[filterFormGroup]="data.filterForm"
[referencesWithTypeItems]="data.referencesWithTypeItems"
[isPublic]="data.isPublic"
(filterChanged)="onFilterChanged($event)"
></app-description-filter-component>

View File

@ -3,6 +3,7 @@ import { UntypedFormGroup } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { AnalyticsService } from '@app/core/services/matomo/analytics-service';
import { DescriptionFilterComponent } from '../description-filter.component';
import { ReferencesWithType } from '@app/core/query/description.lookup';
@Component({
selector: 'description-filter-dialog-component',
@ -20,9 +21,9 @@ export class DescriptionFilterDialogComponent implements OnInit {
@Inject(MAT_DIALOG_DATA) public data: {
isPublic: boolean,
filterForm: UntypedFormGroup,
referencesWithTypeItems: ReferencesWithType[],
}
) {
}
) { }
ngOnInit() {
this.analyticsService.trackPageView(AnalyticsService.DescriptionFilterDialog);

View File

@ -83,24 +83,23 @@
<ng-container *ngFor="let referenceForm of filterFormGroup.get('references')?.controls; let i=index">
<div class="row">
<div class="col-12">
<mat-form-field class="w-100" *ngIf="referenceForm.get('referenceType')">
<mat-form-field class="w-100" *ngIf="referenceForm.get('referenceTypeId')">
<mat-label>{{'DESCRIPTION-LISTING.FILTERS.REFERENCE-TYPES.REFERENCE-TYPE' | translate}}</mat-label>
<app-single-auto-complete [formControl]="referenceForm.get('referenceType')" [configuration]="referenceTypeAutocompleteConfiguration">
<app-single-auto-complete [formControl]="referenceForm.get('referenceTypeId')" [configuration]="referenceTypeAutocompleteConfiguration">
</app-single-auto-complete>
</mat-form-field>
</div>
</div>
<div class="row" *ngIf="referenceForm.get('referenceType')?.value && selectReferenceAutocompleteConfiguration(referenceForm.get('referenceType').value.id)">
<div class="row" *ngIf="referenceForm.get('referenceTypeId')?.value">
<div class="col-12">
<mat-form-field class="w-100 mb-2">
<mat-label>{{'DESCRIPTION-LISTING.FILTERS.REFERENCE-TYPES.REFERENCE' | translate}}</mat-label>
<app-multiple-auto-complete [formControl]="referenceForm.get('references')" [configuration]="selectReferenceAutocompleteConfiguration(referenceForm.get('referenceType').value.id)">
<app-multiple-auto-complete [formControl]="referenceForm.get('referenceIds')" [configuration]="selectReferenceAutocompleteConfiguration(referenceForm.get('referenceTypeId').value)">
</app-multiple-auto-complete>
</mat-form-field>
</div>
</div>
<button mat-icon-button class="col-auto" (click)="deleteRow(i)" type="button">
<mat-icon>delete</mat-icon>
</button>

View File

@ -1,10 +1,12 @@
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { FormBuilder, UntypedFormArray, UntypedFormGroup } from '@angular/forms';
import { AbstractControl, FormBuilder, UntypedFormArray, UntypedFormGroup } from '@angular/forms';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
import { ReferenceType } from '@app/core/model/reference-type/reference-type';
import { Reference } from '@app/core/model/reference/reference';
import { ReferencesWithType } from '@app/core/query/description.lookup';
import { ReferenceLookup } from '@app/core/query/reference.lookup';
import { AuthService } from '@app/core/services/auth/auth.service';
import { DescriptionTemplateService } from '@app/core/services/description-template/description-template.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
@ -16,8 +18,11 @@ import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/mu
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { QueryResult } from '@common/model/query-result';
import { Guid } from '@common/types/guid';
import { IsActive } from '@notification-service/core/enum/is-active.enum';
import { takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
@Component({
selector: 'app-description-filter-component',
@ -28,6 +33,7 @@ export class DescriptionFilterComponent extends BaseCriteriaComponent implements
@Input() status;
@Input() isPublic: boolean;
@Input() referencesWithTypeItems: ReferencesWithType[];
@Input() filterFormGroup: UntypedFormGroup;
@Output() filterChanged: EventEmitter<any> = new EventEmitter();
@ -37,7 +43,6 @@ export class DescriptionFilterComponent extends BaseCriteriaComponent implements
statuses = DescriptionStatus;
dmpRole = DmpUserRole;
options: UntypedFormGroup;
selectedReferenceTypes: Guid[];
descriptionTemplateAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
dmpAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
@ -65,78 +70,58 @@ export class DescriptionFilterComponent extends BaseCriteriaComponent implements
ngOnChanges(changes: SimpleChanges): void {
if (changes['filterFormGroup']) {
this.descriptionTemplateAutoCompleteConfiguration = this.descriptionTemplateService.multipleAutocompleteConfiguration;
this.descriptionTemplateAutoCompleteConfiguration = this.descriptionTemplateService.buildMultipleAutocompleteConfiguration();
this.dmpAutoCompleteConfiguration = this.dmpService.multipleAutocompleteConfiguration;
this.tagAutoCompleteConfiguration = this.tagService.multipleAutocompleteConfiguration;
this.selectedReferenceTypes = this._buildSelectedReferenceTypes(this.filterFormGroup);
this.referenceTypeAutocompleteConfiguration = this.getReferenceTypeAutocompleteConfiguration(this.selectedReferenceTypes);
this.referenceTypeAutocompleteConfiguration = this.getReferenceTypeAutocompleteConfiguration();
this.referenceAutocompleteConfiguration = new Map<string, MultipleAutoCompleteConfiguration>();
this.formGroup = this.filterFormGroup;
const formArray = this.formGroup.get('references') as UntypedFormArray;
formArray?.controls.forEach(control => {
this.referencesWithTypeItems.forEach((referencesWithType: ReferencesWithType) => {
let referenceTypeId: string = control.get('referenceType')?.value?.id;
if (referenceTypeId && referenceTypeId != '') {
let excludedReferences = control.get('references')?.value ?? [];
let referenceAutocomplete = this.getReferenceAutocompleteConfiguration(Guid.parse(referenceTypeId), excludedReferences);
this.referenceAutocompleteConfiguration.set(referenceTypeId, referenceAutocomplete);
if (referencesWithType.referenceTypeId) {
this.addReferenceType(referencesWithType.referenceTypeId.toString(), referencesWithType.referenceIds.map(x => x.toString()));
}
else if (referencesWithType.referenceIds && referencesWithType.referenceIds?.length > 0) {
this.referenceService.query(this._referenceLookup(referencesWithType.referenceIds)).pipe(takeUntil(this._destroyed))
.subscribe((result: QueryResult<Reference>) => {
const references: Reference[] = result.items;
control.get('referenceType')?.valueChanges.pipe(takeUntil(this._destroyed))
.subscribe(referenceType => {
this.selectedReferenceTypes = this._buildSelectedReferenceTypes(this.formGroup);
this.referenceTypeAutocompleteConfiguration = this.getReferenceTypeAutocompleteConfiguration(this.selectedReferenceTypes);
const groupedReferencesByTypeIds = new Map<string, string[]>();
references.forEach(reference => {
if (!groupedReferencesByTypeIds.has(reference.type.id.toString())) groupedReferencesByTypeIds.set(reference.type.id.toString(), []);
if (referenceTypeId && referenceTypeId != '') {
let excludedReferences = control.get('references')?.value ?? [];
let referenceAutocomplete = this.getReferenceAutocompleteConfiguration(Guid.parse(referenceTypeId), excludedReferences);
this.referenceAutocompleteConfiguration.set(referenceTypeId, referenceAutocomplete);
}
control.get('references')?.reset()
});
control.get('references')?.valueChanges.pipe(takeUntil(this._destroyed))
.subscribe(references => {
let referenceAutocomplete = this.getReferenceAutocompleteConfiguration(Guid.parse(referenceTypeId), references ?? []);
this.referenceAutocompleteConfiguration.set(referenceTypeId, referenceAutocomplete);
groupedReferencesByTypeIds.get(reference.type.id.toString()).push(reference.id.toString());
});
groupedReferencesByTypeIds.forEach((referenceIds: string[], referenceId: string) => {
this.addReferenceType(referenceId, referenceIds);
});
});
}
});
}
}
addReferenceType(): void {
addReferenceType(referenceTypeId: string = null, referenceIds: string[] = null): void {
if (!this.formGroup.get('references')) this.formGroup.addControl('references', this.formBuilder.array([]));
const formArray = this.formGroup.get('references') as UntypedFormArray;
const referenceForm = this.formBuilder.group({
referenceType: null,
references: []
referenceTypeId: referenceTypeId,
referenceIds: referenceIds ? [referenceIds] : null,
});
referenceForm?.get('referenceType')?.valueChanges.pipe(takeUntil(this._destroyed))
.subscribe((reference: ReferenceType) => {
this.selectedReferenceTypes = this._buildSelectedReferenceTypes(this.formGroup);
this.referenceTypeAutocompleteConfiguration = this.getReferenceTypeAutocompleteConfiguration(this.selectedReferenceTypes);
referenceForm.get('references')?.reset();
if (reference?.id) {
let referenceAutocomplete = this.getReferenceAutocompleteConfiguration(reference.id, []);
this.referenceAutocompleteConfiguration.set(reference?.id?.toString(), referenceAutocomplete);
}
});
referenceForm.get('references')?.valueChanges.pipe(takeUntil(this._destroyed))
.subscribe(references => {
let referenceTypeId = references?.filter(reference => reference?.type?.id != null)?.first?.type?.id ?? null;
if (!referenceTypeId) return;
let referenceAutocomplete = this.getReferenceAutocompleteConfiguration(referenceTypeId, references ?? []);
this.referenceAutocompleteConfiguration.set(referenceTypeId, referenceAutocomplete);
});
if (referenceTypeId && referenceTypeId != '' && referenceIds && referenceIds.length > 0) {
let referenceAutocomplete = this.getReferenceAutocompleteConfiguration(Guid.parse(referenceTypeId));
this.referenceAutocompleteConfiguration.set(referenceTypeId, referenceAutocomplete);
}
this._registerReferenceTypeListener(referenceForm);
this._registerReferencesListener(referenceForm);
formArray.push(referenceForm);
}
@ -160,28 +145,57 @@ export class DescriptionFilterComponent extends BaseCriteriaComponent implements
return this.authentication.currentAccountIsAuthenticated();
}
getReferenceTypeAutocompleteConfiguration(selectedReferenceTypes: Guid[]): SingleAutoCompleteConfiguration {
return this.referenceTypeService.getSingleAutocompleteConfiguration(selectedReferenceTypes);
getReferenceTypeAutocompleteConfiguration(): SingleAutoCompleteConfiguration {
return this.referenceTypeService.getSingleAutocompleteConfiguration();
};
selectReferenceAutocompleteConfiguration(referenceTypeId: string): MultipleAutoCompleteConfiguration {
return this.referenceAutocompleteConfiguration.get(referenceTypeId);
};
getReferenceAutocompleteConfiguration(referenceTypeId: Guid, excludedIds: Reference[]): MultipleAutoCompleteConfiguration {
getReferenceAutocompleteConfiguration(referenceTypeId: Guid): MultipleAutoCompleteConfiguration {
let autocomplete = this.referenceService.getMultipleAutoCompleteQueryConfiguration([referenceTypeId]);
return autocomplete;
};
private _buildSelectedReferenceTypes(formGroup: UntypedFormGroup): Guid[] {
const formArray = formGroup.get('references') as UntypedFormArray;
let selectedReferenceTypes = [];
formArray.controls.forEach(control => {
let id = control.get('referenceType')?.value?.id;
if (id) selectedReferenceTypes.push(Guid.parse(id));
});
private _referenceLookup(ids: Guid[]): ReferenceLookup {
const lookup: ReferenceLookup = new ReferenceLookup();
lookup.page = { size: 100, offset: 0 };
if (ids && ids.length > 0) { lookup.ids = ids; }
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
nameof<Reference>(x => x.id),
nameof<Reference>(x => x.label),
[nameof<Reference>(x => x.type), nameof<ReferenceType>(x => x.id)].join('.'),
[nameof<Reference>(x => x.type), nameof<ReferenceType>(x => x.name)].join('.'),
]
};
lookup.order = { items: [nameof<Reference>(x => x.label)] };
return lookup;
}
return selectedReferenceTypes;
private _registerReferenceTypeListener(control: AbstractControl) {
control.get('referenceTypeId')?.valueChanges.pipe(takeUntil(this._destroyed))
.subscribe((referenceTypeId: string) => {
this.referenceTypeAutocompleteConfiguration = this.getReferenceTypeAutocompleteConfiguration();
control.get('referenceIds')?.reset();
if (referenceTypeId && referenceTypeId != '') {
let referenceAutocomplete = this.getReferenceAutocompleteConfiguration(Guid.parse(referenceTypeId));
this.referenceAutocompleteConfiguration.set(referenceTypeId, referenceAutocomplete);
}
});
}
private _registerReferencesListener(control: AbstractControl) {
control.get('referenceIds')?.valueChanges.pipe(takeUntil(this._destroyed))
.subscribe(references => {
let referenceTypeId = control.get('referenceTypeId').value;
if (!referenceTypeId) return;
let referenceAutocomplete = this.getReferenceAutocompleteConfiguration(Guid.parse(referenceTypeId));
this.referenceAutocompleteConfiguration.set(referenceTypeId, referenceAutocomplete);
});
}
}

View File

@ -0,0 +1,82 @@
import { Injectable } from "@angular/core";
import { DescriptionTemplate } from "@app/core/model/description-template/description-template";
import { Description, DescriptionReference, DescriptionTag } from "@app/core/model/description/description";
import { Dmp, DmpUser } from "@app/core/model/dmp/dmp";
import { Reference } from "@app/core/model/reference/reference";
import { Tag } from "@app/core/model/tag/tag";
import { DescriptionTemplateLookup } from "@app/core/query/description-template.lookup";
import { DmpUserLookup } from "@app/core/query/dmp-user.lookup";
import { DmpLookup } from "@app/core/query/dmp.lookup";
import { DescriptionReferenceLookup } from "@app/core/query/reference.lookup";
import { DescriptionTagLookup } from "@app/core/query/tag.lookup";
import { IsActive } from "@notification-service/core/enum/is-active.enum";
import { nameof } from "ts-simple-nameof";
@Injectable()
export class DescriptionFilterService {
public static initializeReferenceLookup(): DescriptionReferenceLookup {
const lookup = new DescriptionReferenceLookup();
lookup.metadata = { countAll: true };
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
[nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.id)].join('.'),
]
};
return lookup;
}
public static initializeTagLookup(): DescriptionTagLookup {
const lookup = new DescriptionTagLookup();
lookup.metadata = { countAll: true };
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
[nameof<DescriptionTag>(x => x.tag), nameof<Tag>(x => x.id)].join('.'),
]
};
return lookup;
}
public static initializeDmpLookup(): DmpLookup {
const lookup = new DmpLookup();
lookup.metadata = { countAll: true };
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.id)].join('.'),
]
};
return lookup;
}
public static initializeDmpUserLookup(): DmpUserLookup {
const lookup = new DmpUserLookup();
lookup.metadata = { countAll: true };
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
[nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'),
]
};
return lookup;
}
public static initializeDescriptionTemplateLookup(): DescriptionTemplateLookup {
const lookup = new DescriptionTemplateLookup();
lookup.metadata = { countAll: true };
lookup.isActive = [IsActive.Active];
lookup.project = {
fields: [
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
]
};
return lookup;
}
}

View File

@ -82,11 +82,9 @@ export class DmpListingComponent extends BaseListingComponent<BaseDmp, DmpLookup
get sortingTooltipText(): string {
return this.isAscending ? this.language.instant('DMP-LISTING.ACTIONS.TOGGLE-ΑSCENDING') : this.language.instant('DMP-LISTING.ACTIONS.TOGGLE-DESCENDING');
}
get hasListingItems(): boolean {
return this.listingItems != null && this.listingItems.length > 0;
}
get hasFilters(): boolean {
return (this.lookup.like != null && this.lookup.like != '') || this.lookup.statuses != null ||
this.lookup.dmpReferenceSubQuery != null || this.lookup.dmpDescriptionTemplateSubQuery != null ||

View File

@ -21,7 +21,7 @@ export class DmpFilterDialogComponent implements OnInit {
@Inject(MAT_DIALOG_DATA) public data: {
isPublic: boolean,
filterForm: UntypedFormGroup,
referencesWithTypeItems: ReferencesWithType[];
referencesWithTypeItems: ReferencesWithType[],
}) { }
ngOnInit() {

View File

@ -29,7 +29,6 @@ import { ReferencesWithType } from '@app/core/query/description.lookup';
})
export class DmpFilterComponent extends BaseCriteriaComponent implements OnInit, OnChanges {
@Input() showGrant: boolean;
@Input() isPublic: boolean;
@Input() referencesWithTypeItems: ReferencesWithType[];
@Input() filterFormGroup: UntypedFormGroup;
@ -143,12 +142,11 @@ export class DmpFilterComponent extends BaseCriteriaComponent implements OnInit,
}
selectReferenceAutocompleteConfiguration(referenceTypeId: string): MultipleAutoCompleteConfiguration {
let foo = this.referenceAutocompleteConfiguration.get(referenceTypeId);
return this.referenceAutocompleteConfiguration.get(referenceTypeId);
};
private getReferenceTypeAutocompleteConfiguration() {
return this.referenceTypeService.getSingleAutocompleteConfigurationForDmp();
return this.referenceTypeService.getSingleAutocompleteConfiguration();
}
private getReferenceAutocompleteConfiguration(referenceTypeId: Guid): MultipleAutoCompleteConfiguration {