added dmp filtering (ui)

This commit is contained in:
Sofia Papacharalampous 2024-06-18 18:02:18 +03:00
parent eba6aba19a
commit 570004af96
17 changed files with 364 additions and 412 deletions

View File

@ -5,6 +5,8 @@ import { DmpStatus } from '../common/enum/dmp-status';
import { DmpVersionStatus } from '../common/enum/dmp-version-status';
import { IsActive } from '../common/enum/is-active.enum';
import { DmpDescriptionTemplateLookup } from './dmp-description-template.lookup';
import { DmpUserRole } from '../common/enum/dmp-user-role';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
export class DmpLookup extends Lookup implements DmpFilter {
ids: Guid[];
@ -18,9 +20,29 @@ export class DmpLookup extends Lookup implements DmpFilter {
dmpDescriptionTemplateSubQuery: DmpDescriptionTemplateLookup;
groupIds: Guid[];
dmpBlueprintIds: Guid[]; //TODO
descriptionTemplateIds: Guid[]; //TODO
roleInDmp: DmpUserRole[]; //TODO
constructor() {
super();
}
from(formGroup: UntypedFormGroup): void {
this.statuses = formGroup.get('status')?.value ? [formGroup.get('status')?.value] : null;
this.roleInDmp = formGroup.get('role')?.value ? [formGroup.get('role')?.value] : null;
this.dmpBlueprintIds = formGroup.get('dmpBlueprintIds')?.value ? formGroup.get('dmpBlueprintIds')?.value : null;
this.descriptionTemplateIds = formGroup.get('descriptionTemplateIds')?.value ? formGroup.get('descriptionTemplateIds')?.value : null;
}
buildForm(): UntypedFormGroup {
return (new UntypedFormBuilder()).group({
status: [this.statuses ? this.statuses[0] : null],
role: [this.roleInDmp ? this.roleInDmp[0] : null],
dmpBlueprintIds: [this.dmpBlueprintIds],
descriptionTemplateIds: [this.descriptionTemplateIds],
});
}
}
export interface DmpFilter {
@ -31,6 +53,10 @@ export interface DmpFilter {
versionStatuses: DmpVersionStatus[];
statuses: DmpStatus[];
accessTypes: DmpAccessType[];
versions: Number[]
versions: Number[];
groupIds: Guid[];
dmpBlueprintIds: Guid[]; //TODO
descriptionTemplateIds: Guid[]; //TODO
roleInDmp: DmpUserRole[]; //TODO
}

View File

@ -1,55 +0,0 @@
import { HttpClient } from '@angular/common/http';
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { AnalyticsService } from '@app/core/services/matomo/analytics-service';
import { DescriptionFiltersComponent } from '../description-filter.component';
@Component({
selector: 'description-filter-dialog-component',
templateUrl: './description-filter-dialog.component.html',
styleUrls: ['./description-filter-dialog.component.scss']
})
export class DescriptionFilterDialogComponent implements OnInit {
@ViewChild(DescriptionFiltersComponent, { static: true }) filter: DescriptionFiltersComponent;
public filtersFormGroup = new UntypedFormBuilder().group({
status: new UntypedFormControl(),
role: new UntypedFormControl(),
allVersions: new UntypedFormControl(),
descriptionTemplates: new UntypedFormControl(),
relatedDmps: new UntypedFormControl(),
tags: new UntypedFormControl(),
});
constructor(
public dialogRef: MatDialogRef<DescriptionFiltersComponent>,
private httpClient: HttpClient,
private analyticsService: AnalyticsService,
@Inject(MAT_DIALOG_DATA) public data: {
isPublic: boolean,
status: Number,
filterForm: UntypedFormGroup,
updateDataFn: Function }
) {
}
ngOnInit() {
this.analyticsService.trackPageView(AnalyticsService.DescriptionFiltersDialog);
// this.filters.setfilters(this.data.filters);
}
onNoClick(): void {
this.dialogRef.close();
}
onClose(): void {
this.dialogRef.close();
}
onFiltersChanged(event) {
this.data.updateDataFn(this.filter);
}
}

View File

@ -1,2 +0,0 @@
<a class="col-auto d-flex pointer" (click)="onClose()"><span class="ml-auto mt-3 material-icons clear-icon">clear</span></a>
<app-dmp-criteria-component [showGrant]="data.showGrant" [isPublic]="data.isPublic" [criteriaFormGroup]="data.formGroup" (filtersChanged)="onFiltersChanged($event)"></app-dmp-criteria-component>

View File

@ -1,44 +0,0 @@
import { Inject, Component, ViewChild, OnInit, Output, EventEmitter } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { DmpCriteriaComponent } from './dmp-criteria.component';
import { UntypedFormGroup } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { AnalyticsService } from '@app/core/services/matomo/analytics-service';
@Component({
selector: 'dmp-criteria-dialog-component',
templateUrl: './dmp-criteria-dialog.component.html',
styleUrls: ['./dmp-criteria-dialog.component.scss']
})
export class DmpCriteriaDialogComponent implements OnInit {
@ViewChild(DmpCriteriaComponent, { static: true }) criteria: DmpCriteriaComponent;
constructor(
public dialogRef: MatDialogRef<DmpCriteriaDialogComponent>,
private httpClient: HttpClient,
private analyticsService: AnalyticsService,
@Inject(MAT_DIALOG_DATA) public data: { showGrant: boolean, isPublic: boolean, criteria: DmpCriteria, formGroup: UntypedFormGroup, updateDataFn: Function }
) {
}
ngOnInit() {
this.analyticsService.trackPageView(AnalyticsService.DmpCriteriaDialog);
this.criteria.setCriteria(this.data.criteria);
}
onNoClick(): void {
this.dialogRef.close();
}
onClose(): void {
this.dialogRef.close();
}
onFiltersChanged(event) {
this.data.updateDataFn(this.criteria);
}
}

View File

@ -1,116 +0,0 @@
<div class="dmp-criteria">
<div class="filters">
<div class="row justify-content-center">
<div class="col-10">
<h6 class="criteria-title">{{'CRITERIA.FILTERS'| translate}}</h6>
</div>
</div>
<!-- <h6 class="filters-title">{{'CRITERIA.FILTERS'| translate}}</h6> -->
<div class="row" style="justify-content: center;">
<!-- Search Filter-->
<!-- <mat-form-field class="col-11 search">
<input matInput placeholder="{{'CRITERIA.DMP.LIKE'| translate}}" name="likeCriteria"
[formControl]="formGroup.get('like')">
<mat-error *ngIf="formGroup.get('like').hasError('backendError')">
{{formGroup.get('like').getError('backendError').message}}</mat-error>
<mat-icon matSuffix class="style-icon">search</mat-icon>
</mat-form-field> -->
<!-- End of Search Filter -->
<!-- Visibility Filter-->
<div *ngIf="!isPublic" class="col-10">
<h6 class="category-title">{{ 'TYPES.DMP-VISIBILITY.VISIBILITY' | translate }}</h6>
<mat-radio-group aria-label="Select an option" [formControl]="formGroup.get('status')">
<mat-list-item><mat-radio-button value="null" [checked]="!formGroup.get('status').value">{{ 'TYPES.DMP-VISIBILITY.ANY' | translate }}</mat-radio-button></mat-list-item>
<mat-list-item><mat-radio-button value="2">{{ 'TYPES.DMP-VISIBILITY.PUBLIC' | translate }}</mat-radio-button></mat-list-item>
<mat-list-item><mat-radio-button value="1">{{ 'TYPES.DMP-VISIBILITY.FINALIZED' | translate }}</mat-radio-button></mat-list-item>
<mat-list-item><mat-radio-button value="0">{{ 'TYPES.DMP-VISIBILITY.DRAFT' | translate }}</mat-radio-button></mat-list-item>
</mat-radio-group>
<hr>
</div>
<!-- End of Visibility Filter-->
<!-- Grant Status -->
<div class="col-10" *ngIf="isPublic">
<h6 class="category-title">{{ 'FACET-SEARCH.GRANT-STATUS.TITLE' | translate }}</h6>
<mat-radio-group [formControl]="formGroup.get('grantStatus')">
<mat-list-item>
<mat-radio-button value="null" [checked]="!formGroup.get('grantStatus').value">{{ 'FACET-SEARCH.GRANT-STATUS.OPTIONS.ANY' | translate }}</mat-radio-button>
</mat-list-item>
<mat-list-item>
<mat-radio-button value="0">{{ 'FACET-SEARCH.GRANT-STATUS.OPTIONS.ACTIVE' | translate }}</mat-radio-button>
</mat-list-item>
<mat-list-item>
<mat-radio-button value="1">{{ 'FACET-SEARCH.GRANT-STATUS.OPTIONS.INACTIVE' | translate }}</mat-radio-button>
</mat-list-item>
</mat-radio-group>
<hr>
</div>
<!-- End of Grant Status -->
<!-- Related Dataset Templates Filter -->
<div *ngIf="showGrant" class="col-10">
<h6 class="category-title">{{ 'CRITERIA.DMP.RELATED-DATASET-TEMPLATES' | translate}}</h6>
<mat-form-field>
<mat-label>{{ 'CRITERIA.DMP.SELECT-DATASET-TEMPLATES' | translate }}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('datasetTemplates')"
[configuration]="datasetTemplateAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<hr>
</div>
<!-- End of Related Dataset Templates Filter -->
<!-- Related Grant Filters -->
<div *ngIf="showGrant" class="col-10">
<h6 class="category-title">{{ 'DMP-RELATED-GRANT.RELATED-GRANT' | translate}}</h6>
<mat-form-field>
<mat-label>{{ 'CRITERIA.DMP.SELECT-GRANTS' | translate }}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('grants')"
[configuration]="grantAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<hr>
</div>
<!-- End of Related Grants Filters -->
<!-- Collaborators Filter -->
<div *ngIf="isAuthenticated()" class="col-10">
<h6 class="category-title">{{ 'CRITERIA.DMP.RELATED-COLLABORATORS' | translate}}</h6>
<mat-form-field>
<mat-label>{{'CRITERIA.DMP.SELECT-COLLABORATORS' | translate}}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('collaborators')"
[configuration]="collaboratorsAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<hr>
</div>
<!-- End of Collaborators Filter -->
<!-- Role Filter -->
<div *ngIf="isAuthenticated()" class="col-10">
<h6 class="category-title">{{ 'DATASET-PROFILE-LISTING.COLUMNS.ROLE' | translate }}</h6>
<mat-radio-group aria-label="Select an option" [formControl]="formGroup.get('role')">
<mat-list-item><mat-radio-button value="null" [checked]="!formGroup.get('role').value">{{ 'TYPES.DATASET-ROLE.ANY' | translate }}</mat-radio-button></mat-list-item>
<mat-list-item><mat-radio-button value="0">{{ 'TYPES.DATASET-ROLE.OWNER' | translate }}</mat-radio-button></mat-list-item>
<mat-list-item><mat-radio-button value="1">{{ 'TYPES.DATASET-ROLE.MEMBER' | translate }}</mat-radio-button></mat-list-item>
</mat-radio-group>
<hr>
</div>
<!-- End of Role Filter -->
<!-- Related Organization Filter -->
<div *ngIf="showGrant" class="col-10">
<h6 class="category-title">{{ 'DMP-RELATED-ORGANIZATION.RELATED-ORGANIZATION' | translate }}</h6>
<mat-form-field>
<mat-label>{{'DMP-RELATED-ORGANIZATION.SELECT-ORGANIZATIONS' | translate}}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('organisations')"
[configuration]="organisationAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
</div>
<!-- End of Related Organization Filter -->
</div>
</div>
</div>

View File

@ -1,193 +0,0 @@
import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-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 { TranslateService } from '@ngx-translate/core';
import { map, takeUntil } from 'rxjs/operators';
import { AuthService } from '@app/core/services/auth/auth.service';
import { Observable } from 'rxjs';
import { DmpService } from '@app/core/services/dmp/dmp.service';
@Component({
selector: 'app-dmp-criteria-component',
templateUrl: './dmp-criteria.component.html',
styleUrls: ['./dmp-criteria.component.scss'],
})
export class DmpCriteriaComponent extends BaseCriteriaComponent implements OnInit {
@Input() showGrant: boolean;
@Input() isPublic: boolean;
@Input() criteriaFormGroup: UntypedFormGroup;
@Output() filtersChanged: EventEmitter<any> = new EventEmitter();
filteringGrantsAsync = false;
sizeError = false;
maxFileSize: number = 1048576;
filteringOrganisationsAsync = false;
filteredGrants: GrantListingModel[];
public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(),
grants: new UntypedFormControl(),
status: new UntypedFormControl(),
role: new UntypedFormControl,
organisations: new UntypedFormControl(),
collaborators: new UntypedFormControl(),
datasetTemplates: new UntypedFormControl(),
grantStatus: new UntypedFormControl()
});
collaboratorsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterCollaborators.bind(this),
initialItems: (excludedItems: any[]) => this.filterCollaborators('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['name'],
titleFn: (item) => item['name']
};
datasetTemplateAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterDatasetTemplate.bind(this),
initialItems: (excludedItems: any[]) => this.filterDatasetTemplate('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
subtitleFn: (item) => item['description']
};
grantAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterGrant.bind(this),
initialItems: (excludedItems: any[]) => this.filterGrant('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['label'],
titleFn: (item) => item['label']
};
organisationAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterOrganisations.bind(this),
initialItems: (excludedItems: any[]) => this.filterOrganisations('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
displayFn: (item) => item['name'],
titleFn: (item) => item['name']
}
constructor(
public language: TranslateService,
public grantService: GrantService,
private dmpService: DmpService,
public formBuilder: UntypedFormBuilder,
private dialog: MatDialog,
private organisationService: OrganisationService,
private userService: UserServiceOld,
private datasetProfileService: DatasetService,
private authService: AuthService
) {
super(new ValidationErrorModel());
}
ngOnInit() {
super.ngOnInit();
// This if is just for passing label on chips of dialog
if (this.formGroup && this.criteriaFormGroup) {
this.formGroup.get('datasetTemplates').setValue(this.criteriaFormGroup.get('datasetTemplates').value);
this.formGroup.get('grants').setValue(this.criteriaFormGroup.get('grants').value);
this.formGroup.get('collaborators').setValue(this.criteriaFormGroup.get('collaborators').value);
this.formGroup.get('organisations').setValue(this.criteriaFormGroup.get('organisations').value);
this.formGroup.get('status').setValue(this.criteriaFormGroup.get('status').value);
}
this.formGroup.get('role').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('organisations').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('status').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('grants').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('like').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('collaborators').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('datasetTemplates').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('grantStatus').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
//if (this.criteria == null) { this.criteria = new DataManagementPlanCriteria(); }
}
setCriteria(criteria: DmpCriteria): void {
this.formGroup.get('like').patchValue(criteria.like);
this.formGroup.get('grants').patchValue(criteria.grants);
this.formGroup.get('status').patchValue(criteria.status);
this.formGroup.get('role').patchValue(criteria.role);
this.formGroup.get('collaborators').patchValue(criteria.collaborators);
this.formGroup.get('datasetTemplates').patchValue(criteria.datasetTemplates);
this.formGroup.get('grantStatus').patchValue(criteria.grantStatus);
this.formGroup.get('organisations').patchValue(criteria.organisations);
}
onCallbackError(error: any) {
this.setErrorModel(error.error);
}
controlModified(): void {
this.clearErrorModel();
this.filtersChanged.emit();
if (this.refreshCallback != null &&
(this.formGroup.get('like').value == null || this.formGroup.get('like').value.length === 0 || this.formGroup.get('like').value.length > 2)
) {
setTimeout(() => this.refreshCallback(true));
}
}
filterGrant(query: string) {
const fields: Array<string> = new Array<string>();
fields.push('asc');
const grantRequestItem: DataTableRequest<GrantCriteria> = new DataTableRequest(0, null, { fields: fields });
grantRequestItem.criteria = new GrantCriteria();
grantRequestItem.criteria.like = query;
return this.isPublic ? this.grantService.getPublicPaged(grantRequestItem).pipe(map(x => x.data)) : this.grantService.getPaged(grantRequestItem, "autocomplete").pipe(map(x => x.data));
}
filterOrganisations(value: string) {
this.filteringOrganisationsAsync = true;
const fields: Array<string> = new Array<string>();
fields.push('asc');
const dataTableRequest: DataTableRequest<OrganisationCriteria> = new DataTableRequest(0, null, { fields: fields });
dataTableRequest.criteria = new OrganisationCriteria();
dataTableRequest.criteria.labelLike = value;
return this.isPublic ? this.organisationService.searchPublicOrganisations(dataTableRequest).pipe(map(x => x.data)) : this.organisationService.searchInternalOrganisations(dataTableRequest).pipe(map(x => x.data));
}
filterCollaborators(query: string) {
const fields: Array<string> = new Array<string>();
fields.push('asc');
const collaboratorsRequestItem: DataTableRequest<UserCriteria> = new DataTableRequest(0, null, { fields: fields });
collaboratorsRequestItem.criteria = new UserCriteria();
collaboratorsRequestItem.criteria.collaboratorLike = query;
return this.userService.getCollaboratorsPaged(collaboratorsRequestItem).pipe(map(x => x.data));
}
filterDatasetTemplate(query: string): Observable<any> {
const fields: Array<string> = new Array<string>();
fields.push('+label');
const datasetTemplateRequestItem: DataTableRequest<DatasetProfileCriteria> = new DataTableRequest(0, null, { fields: fields });
datasetTemplateRequestItem.criteria = new DatasetProfileCriteria();
datasetTemplateRequestItem.criteria.like = query;
return this.isPublic ? this.datasetProfileService.getDatasetProfiles(datasetTemplateRequestItem) : this.dmpService.getDatasetProfilesUsedPaged(datasetTemplateRequestItem).pipe(map(x => x.data));
}
isAuthenticated(): boolean {
return this.authService.currentAccountIsAuthenticated();
}
}

View File

@ -15,6 +15,11 @@
<app-navigation-breadcrumb />
</div>
<!-- TODO: implement filters -->
<div *ngIf="listingItems && listingItems.length > 0 || this.lookup.like" 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">
<mat-icon class="mr-4 filter-icon">filter_alt</mat-icon>
</button>
</div>
<!-- <div class="filter-btn" [style.right]="this.dialog.getDialogById('filters') ? '446px' : '0px'" [style.width]="scrollbar || this.dialog.getDialogById('filters') ? '57px' : '37px'" (click)="openFiltersDialog()">
<button mat-raised-button class="p-0">
<mat-icon class="mr-4">filter_alt</mat-icon>

View File

@ -187,6 +187,12 @@
width: 37px;
transition: right 0.3s;
transition-timing-function: ease-in-out;
.filter-icon {
width: 1.5rem;
height: 1.5rem;
font-size: 1.5rem;
}
}
.filter-btn button {

View File

@ -1,7 +1,7 @@
import { HttpClient } from '@angular/common/http';
import { Component, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl } from '@angular/forms';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
@ -34,6 +34,7 @@ import { TranslateService } from '@ngx-translate/core';
import { NgDialogAnimationService } from "ng-dialog-animation";
import { debounceTime, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { DmpFilterDialogComponent } from './filtering/dmp-filter-dialog/dmp-filter-dialog.component';
@Component({
selector: 'app-dmp-listing-component',
@ -299,6 +300,27 @@ export class DmpListingComponent extends BaseComponent implements OnInit {
openFiltersDialog(): void {
//TODO: Add filters dialog
let dialogRef = this.dialog.open(DmpFilterDialogComponent, {
width: '456px',
height: '100%',
id: 'filters',
restoreFocus: false,
position: { right: '0px;' },
panelClass: 'dialog-side-panel',
data: {
isPublic: this.isPublic ?? true,
filterForm: this.lookup.buildForm(),
updateDataFn: this.updateDataFn.bind(this)
}
});
}
updateDataFn(filterForm: UntypedFormGroup): void {
let testLookup = this.lookup;
testLookup.from(filterForm);
console.log('testLookup: ', testLookup);
// this.lookup.from(filterForm);
// this.refresh(this.lookup);
}
hasScrollbar(): boolean {

View File

@ -8,12 +8,16 @@ import { CloneDmpDialogModule } from '../clone-dialog/dmp-clone-dialog.module';
import { NewVersionDmpDialogModule } from '../new-version-dialog/dmp-new-version-dialog.module';
import { DmpListingRoutingModule } from './dmp-listing.routing';
import { DmpInvitationDialogModule } from '../invitation/dialog/dmp-invitation-dialog.module';
import { DmpFilterDialogComponent } from './filtering/dmp-filter-dialog/dmp-filter-dialog.component';
import { DmpFilterComponent } from './filtering/dmp-filter.component';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
FormattingModule,
AutoCompleteModule,
CloneDmpDialogModule,
NewVersionDmpDialogModule,
DmpInvitationDialogModule,
@ -22,6 +26,8 @@ import { DmpInvitationDialogModule } from '../invitation/dialog/dmp-invitation-d
declarations: [
DmpListingComponent,
DmpListingItemComponent,
DmpFilterDialogComponent,
DmpFilterComponent,
],
exports: [
DmpListingItemComponent

View File

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

View File

@ -0,0 +1,44 @@
import { Inject, Component, ViewChild, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { UntypedFormGroup } from '@angular/forms';
import { AnalyticsService } from '@app/core/services/matomo/analytics-service';
import { DmpFilterComponent } from '../dmp-filter.component';
@Component({
selector: 'dmp-filter-dialog-component',
templateUrl: './dmp-filter-dialog.component.html',
styleUrls: ['./dmp-filter-dialog.component.scss']
})
export class DmpFilterDialogComponent implements OnInit {
@ViewChild(DmpFilterComponent, { static: true }) criteria: DmpFilterComponent;
constructor(
public dialogRef: MatDialogRef<DmpFilterDialogComponent>,
private analyticsService: AnalyticsService,
@Inject(MAT_DIALOG_DATA) public data: {
showGrant: boolean,
isPublic: boolean,
filterForm: UntypedFormGroup,
updateDataFn: Function,
}) { }
ngOnInit() {
this.analyticsService.trackPageView(AnalyticsService.DmpCriteriaDialog);
}
onNoClick(): void {
this.dialogRef.close();
}
onClose(): void {
this.dialogRef.close();
}
onFilterChanged(formGroup: UntypedFormGroup) {
this.data.updateDataFn(formGroup);
}
}

View File

@ -0,0 +1,126 @@
<div class="dmp-criteria">
<div class="filters container-fluid">
<div class="row justify-content-center">
<div class="col-10">
<h6 class="criteria-title">{{'DMP-LISTING.FILTERS.NAME'| translate}}</h6>
</div>
</div>
<!-- <h6 class="filters-title">{{'CRITERIA.FILTERS'| translate}}</h6> -->
<div class="row" style="justify-content: center;" *ngIf="formGroup">
<!-- Search Filter-->
<!-- <mat-form-field class="col-11 search">
<input matInput placeholder="{{'CRITERIA.DMP.LIKE'| translate}}" name="likeCriteria"
[formControl]="formGroup.get('like')">
<mat-error *ngIf="formGroup.get('like').hasError('backendError')">
{{formGroup.get('like').getError('backendError').message}}</mat-error>
<mat-icon matSuffix class="style-icon">search</mat-icon>
</mat-form-field> -->
<!-- End of Search Filter -->
<!-- Visibility Filter-->
<div *ngIf="!isPublic" class="col-10">
<h6 class="category-title">{{ 'DMP-LISTING.FILTERS.STATUS.NAME' | translate }}</h6>
<mat-radio-group aria-label="Select an option" [formControl]="formGroup.get('status')" class="row">
<mat-radio-button value="null" [checked]="!formGroup.get('status').value" class="col-12">{{ 'DMP-LISTING.FILTERS.STATUS.TYPE.ANY' | translate }}</mat-radio-button>
<mat-radio-button value="2" class="col-12">{{ 'DMP-LISTING.FILTERS.STATUS.TYPE.PUBLIC' | translate }}</mat-radio-button>
<mat-radio-button value="1" class="col-12">{{ 'DMP-LISTING.FILTERS.STATUS.TYPE.FINALIZED' | translate }}</mat-radio-button>
<mat-radio-button value="0" class="col-12">{{ 'DMP-LISTING.FILTERS.STATUS.TYPE.DRAFT' | translate }}</mat-radio-button>
</mat-radio-group>
<hr>
</div>
<!-- End of Visibility Filter-->
<!-- Grant Status -->
<!-- TODO -->
<!-- <div class="col-10" *ngIf="isPublic">
<h6 class="category-title">{{ 'FACET-SEARCH.GRANT-STATUS.TITLE' | translate }}</h6>
<mat-radio-group [formControl]="formGroup.get('grantStatus')">
<mat-radio-button value="null" [checked]="!formGroup.get('grantStatus').value">{{ 'FACET-SEARCH.GRANT-STATUS.OPTIONS.ANY' | translate }}</mat-radio-button>
<mat-radio-button value="0">{{ 'FACET-SEARCH.GRANT-STATUS.OPTIONS.ACTIVE' | translate }}</mat-radio-button>
<mat-radio-button value="1">{{ 'FACET-SEARCH.GRANT-STATUS.OPTIONS.INACTIVE' | translate }}</mat-radio-button>
</mat-radio-group>
<hr>
</div> -->
<!-- End of Grant Status -->
<!-- Related Dataset Templates Filter -->
<!-- TODO -->
<!-- <div *ngIf="showGrant" class="col-10"> -->
<div class="col-10">
<h6 class="category-title">{{ 'DMP-LISTING.FILTERS.RELATED-DESCRIPTION-TEMPLATES.NAME' | translate}}</h6>
<mat-form-field class="w-100">
<mat-label>{{ 'DMP-LISTING.FILTERS.RELATED-DESCRIPTION-TEMPLATES.PLACEHOLDER' | translate }}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('descriptionTemplateIds')" [configuration]="descriptionTemplateAutoCompleteConfiguration"></app-multiple-auto-complete>
</mat-form-field>
<hr>
</div>
<!-- End of Related Dataset Templates Filter -->
<!-- Dmp Blueprint Filter -->
<div class="col-10">
<h6 class="category-title">{{ 'DMP-LISTING.FILTERS.ASSOCIATED-DMP-BLUEPRINTS.NAME' | translate}}</h6>
<mat-form-field class="w-100">
<mat-label>{{ 'DMP-LISTING.FILTERS.ASSOCIATED-DMP-BLUEPRINTS.PLACEHOLDER' | translate }}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('dmpBlueprintIds')" [configuration]="dmpBlueprintAutoCompleteConfiguration"></app-multiple-auto-complete>
</mat-form-field>
<hr>
</div>
<!-- End of Dmp Blueprint Filter -->
<!-- Related Grant Filters -->
<!-- TODO -->
<!-- <div *ngIf="showGrant" class="col-10">
<h6 class="category-title">{{ 'DMP-RELATED-GRANT.RELATED-GRANT' | translate}}</h6>
<mat-form-field>
<mat-label>{{ 'CRITERIA.DMP.SELECT-GRANTS' | translate }}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('grants')"
[configuration]="grantAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<hr>
</div> -->
<!-- End of Related Grants Filters -->
<!-- Collaborators Filter -->
<!-- TODO -->
<!-- <div *ngIf="isAuthenticated()" class="col-10">
<h6 class="category-title">{{ 'CRITERIA.DMP.RELATED-COLLABORATORS' | translate}}</h6>
<mat-form-field>
<mat-label>{{'CRITERIA.DMP.SELECT-COLLABORATORS' | translate}}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('collaborators')"
[configuration]="collaboratorsAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
<hr>
</div> -->
<!-- End of Collaborators Filter -->
<!-- Role Filter -->
<!-- TODO -->
<div *ngIf="isAuthenticated()" class="col-10">
<h6 class="category-title">{{ 'DMP-LISTING.FILTERS.ROLE.NAME' | translate }}</h6>
<mat-radio-group aria-label="Select an option" [formControl]="formGroup.get('role')" class="row">
<mat-radio-button value="null" [checked]="!formGroup.get('role').value" class="col-12">{{ 'DMP-LISTING.FILTERS.ROLE.TYPE.ANY' | translate }}</mat-radio-button>
<mat-radio-button value="0" class="col-12">{{ 'DMP-LISTING.FILTERS.ROLE.TYPE.OWNER' | translate }}</mat-radio-button>
<mat-radio-button value="1" class="col-12">{{ 'DMP-LISTING.FILTERS.ROLE.TYPE.MEMBER' | translate }}</mat-radio-button>
</mat-radio-group>
<hr>
</div>
<!-- End of Role Filter -->
<!-- Related Organization Filter -->
<!-- TODO -->
<!-- <div *ngIf="showGrant" class="col-10">
<h6 class="category-title">{{ 'DMP-RELATED-ORGANIZATION.RELATED-ORGANIZATION' | translate }}</h6>
<mat-form-field>
<mat-label>{{'DMP-RELATED-ORGANIZATION.SELECT-ORGANIZATIONS' | translate}}</mat-label>
<app-multiple-auto-complete [formControl]="formGroup.get('organisations')"
[configuration]="organisationAutoCompleteConfiguration">
</app-multiple-auto-complete>
</mat-form-field>
</div> -->
<!-- End of Related Organization Filter -->
</div>
</div>
</div>

View File

@ -130,3 +130,7 @@
::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix {
padding: 0.3rem 0rem 0.6rem 0rem !important;
}
::ng-deep label {
margin: 0;
}

View File

@ -0,0 +1,88 @@
import { Component, Input, OnInit, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { TranslateService } from '@ngx-translate/core';
import { takeUntil } from 'rxjs/operators';
import { AuthService } from '@app/core/services/auth/auth.service';
import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
@Component({
selector: 'app-dmp-filter-component',
templateUrl: './dmp-filter.component.html',
styleUrls: ['./dmp-filter.component.scss'],
})
export class DmpFilterComponent extends BaseCriteriaComponent implements OnInit, OnChanges {
@Input() showGrant: boolean;
@Input() isPublic: boolean;
@Input() filterFormGroup: UntypedFormGroup;
@Output() filtersChanged: EventEmitter<any> = new EventEmitter();
filteringGrantsAsync = false;
sizeError = false;
maxFileSize: number = 1048576;
filteringOrganisationsAsync = false;
get descriptionTemplateAutoCompleteConfiguration(): MultipleAutoCompleteConfiguration {
return this.descriptionTemplateTypeService.getMultipleAutoCompleteSearchConfiguration();
};
get dmpBlueprintAutoCompleteConfiguration(): MultipleAutoCompleteConfiguration {
return this.dmpBlueprintService.multipleAutocompleteConfiguration;
};
constructor(
public language: TranslateService,
public formBuilder: UntypedFormBuilder,
private authentication: AuthService,
private descriptionTemplateTypeService: DescriptionTemplateTypeService,
private dmpBlueprintService: DmpBlueprintService,
) {
super(new ValidationErrorModel());
}
ngOnInit() {
super.ngOnInit();
}
ngOnChanges(changes: SimpleChanges): void {
if (changes['filterFormGroup']) {
this.formGroup = this.filterFormGroup;
this.formGroup.get('role')?.valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('status')?.valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('descriptionTemplateIds')?.valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
this.formGroup.get('dmpBlueprintIds')?.valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.controlModified());
}
}
onCallbackError(error: any) {
this.setErrorModel(error.error);
}
controlModified(): void {
this.clearErrorModel();
this.filtersChanged.emit(this.formGroup);
if (this.refreshCallback != null &&
(this.formGroup.get('like').value == null || this.formGroup.get('like').value.length === 0 || this.formGroup.get('like').value.length > 2)
) {
setTimeout(() => this.refreshCallback(true));
}
}
isAuthenticated(): boolean {
return this.authentication.currentAccountIsAuthenticated();
}
}

View File

@ -694,6 +694,34 @@
"TOGGLE-DESCENDING": "Order by ascending",
"TOGGLE-ΑSCENDING": "Order by descending"
},
"FILTERS": {
"NAME": "Filters",
"STATUS": {
"NAME": "Status",
"TYPE": {
"ANY": "Any",
"PUBLIC": "Published",
"FINALIZED": "Finalized",
"DRAFT": "Draft"
}
},
"RELATED-DESCRIPTION-TEMPLATES": {
"NAME":"Related Description Templates",
"PLACEHOLDER": "Select Description Templates"
},
"ASSOCIATED-DMP-BLUEPRINTS": {
"NAME": "Related DMP Blueprints",
"PLACEHOLDER": "Select DMP Blueprints"
},
"ROLE": {
"NAME": "Role",
"TYPE": {
"ANY": "Any",
"OWNER": "Owner",
"MEMBER": "Member"
}
}
},
"EMPTY-LIST": "Nothing here yet."
},
"DMP-UPLOAD": {