refactored DmpListing, DescriptionListing, DescriptionOverview.

This commit is contained in:
Diamantis Tziotzios 2023-12-01 19:18:41 +02:00
parent 5965acc4aa
commit 6e997b300d
57 changed files with 1256 additions and 2864 deletions

View File

@ -265,8 +265,10 @@ public class UserInterceptor implements WebRequestInterceptor {
user.setId(UUID.randomUUID());
user.setName(name);
user.setCreatedAt(Instant.now());
user.setUpdatedAt(Instant.now());
user.setIsActive(IsActive.Active);
user.setAdditionalInfo(this.jsonHandlingService.toJsonSafe(new AdditionalInfoEntity()));
this.entityManager.persist(user);
UserCredentialEntity credential = this.buildCredential(user.getId(), subjectId);
this.entityManager.persist(credential);
@ -275,7 +277,6 @@ public class UserInterceptor implements WebRequestInterceptor {
UserContactInfoEntity contactInfo = this.buildEmailContact(user.getId(), email);
this.entityManager.persist(contactInfo);
}
this.entityManager.persist(user);
if (roles != null) {
for (String role: roles) {
UserRoleEntity roleEntity = this.buildRole(user.getId(), role);

View File

@ -27,24 +27,6 @@ const appRoutes: Routes = [
title: 'GENERAL.TITLES.DATASETCREATEWIZARD'
}
},
{
path: 'explore',
// loadChildren: () => import('./ui/explore-dataset/explore-dataset.module').then(m => m.ExploreDatasetModule),
loadChildren: () => import('./ui/dataset/dataset.module').then(m => m.DatasetModule),
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.EXPLORE'
}
},
{
path: 'explore-plans',
// loadChildren: () => import('./ui/explore-dmp/explore-dmp.module').then(m => m.ExploreDmpModule),
loadChildren: () => import('./ui/dmp/dmp.module').then(m => m.DmpModule),
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.EXPLORE-PLANS'
}
},
{
path: 'descriptions',
loadChildren: () => import('./ui/description/description.module').then(m => m.DescriptionModule),
@ -53,6 +35,14 @@ const appRoutes: Routes = [
title: 'GENERAL.TITLES.DESCRIPTIONS'
}
},
{
path: 'explore-descriptions',
loadChildren: () => import('./ui/description/description.module').then(m => m.DescriptionModule),
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.EXPLORE'
}
},
{
path: 'about',
loadChildren: () => import('./ui/about/about.module').then(m => m.AboutModule),
@ -78,6 +68,14 @@ const appRoutes: Routes = [
title: 'GENERAL.TITLES.PLANS'
}
},
{
path: 'explore-plans',
loadChildren: () => import('./ui/dmp/dmp.module').then(m => m.DmpModule),
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.EXPLORE-PLANS'
}
},
{
path: 'dmp-blueprints',
loadChildren: () => import('./ui/admin/dmp-blueprint/dmp-blueprint.module').then(m => m.DmpBlueprintModule),

View File

@ -1,7 +1,7 @@
import { DescriptionStatus } from "@app/core/common/enum/description-status";
import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model";
import { Guid } from "@common/types/guid";
import { Dmp } from "../dmp/dmp";
import { Dmp, DmpDescriptionTemplatePersist } from "../dmp/dmp";
import { DescriptionTemplate } from "../description-template/description-template";
import { User } from "../user/user";
import { Reference, ReferencePersist } from "../reference/reference";
@ -18,7 +18,8 @@ export interface Description extends BaseEntity {
finalizedAt: Date;
descriptionReferences: DescriptionReference[];
descriptionTags: DescriptionTag[];
template: DescriptionTemplate;
descriptionTemplate: DescriptionTemplate;
dmpDescriptionTemplate: DmpDescriptionTemplatePersist;
dmp: Dmp;
}

View File

@ -17,6 +17,7 @@ import { DmpVersionStatus } from '@app/core/common/enum/dmp-version-status';
import { DmpAccessType } from '@app/core/common/enum/dmp-access-type';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
import { Guid } from '@common/types/guid';
import { DescriptionTemplate } from '../description-template/description-template';
export interface DmpModel { //TODO: Delete
id: string;
@ -99,6 +100,14 @@ export interface DmpUser extends BaseEntity {
role: DmpUserRole;
}
export interface DmpDescriptionTemplate extends BaseEntity {
dmp: Dmp;
currentDescriptionTemplate: DescriptionTemplate; //TODO: what is this?
descriptionTemplates: DescriptionTemplate[]; //TODO: why it is array?
descriptionTemplateGroupId: Guid;
sectionId: Guid;
}
//
// Persist
//

View File

@ -13,7 +13,8 @@ export class DmpLookup extends Lookup implements DmpFilter {
versionStatuses: DmpVersionStatus[];
statuses: DmpStatus[];
accessTypes: DmpAccessType[];
versions: Number[]
versions: Number[];
constructor() {
super();

View File

@ -1,5 +1,6 @@
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { VersionListingModel } from '@app/core/model/version/version-listing.model';
@ -27,16 +28,24 @@ import { DatasetProfileCriteria } from '../../query/dataset-profile/dataset-prof
import { DmpCriteria } from '../../query/dmp/dmp-criteria';
import { ExploreDmpCriteriaModel } from '../../query/explore-dmp/explore-dmp-criteria';
import { RequestItem } from '../../query/request-item';
import { AuthService } from '../auth/auth.service';
import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { BaseHttpService } from '../http/base-http.service';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
@Injectable()
export class DmpServiceNew {
private headers = new HttpHeaders();
constructor(private http: BaseHttpV2Service, private httpClient: HttpClient, private configurationService: ConfigurationService, private filterService: FilterService) {
constructor(
private http: BaseHttpV2Service,
private httpClient: HttpClient,
private configurationService: ConfigurationService,
private filterService: FilterService,
private authService: AuthService
) {
}
private get apiBase(): string { return `${this.configurationService.server}dmp`; }
@ -142,12 +151,13 @@ export class DmpServiceNew {
valueAssign: (item: Dmp) => item.id,
};
private buildAutocompleteLookup(like?: string, excludedIds?: Guid[], ids?: Guid[]): DmpLookup {
public buildAutocompleteLookup(like?: string, excludedIds?: Guid[], ids?: Guid[], statuses?: DmpStatus[]): DmpLookup {
const lookup: DmpLookup = new DmpLookup();
lookup.page = { size: 100, offset: 0 };
if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; }
if (ids && ids.length > 0) { lookup.ids = ids; }
lookup.isActive = [IsActive.Active];
lookup.statuses = statuses;
lookup.project = {
fields: [
nameof<Dmp>(x => x.id),
@ -158,6 +168,25 @@ export class DmpServiceNew {
if (like) { lookup.like = this.filterService.transformLike(like); }
return lookup;
}
//
//
// UI Helpers
//
//
getCurrentUserRolesInDmp(dmpUsers: DmpUser[]): DmpUserRole[] {
const principalId: Guid = this.authService.userId();
let dmpUserRoles: DmpUserRole[] = null;
if (principalId) {
dmpUserRoles = dmpUsers.filter(element => element?.user?.id === principalId).map(x => x.role);
}
return dmpUserRoles;
}
isDmpOwner(dmpUsers: DmpUser[]): Boolean {
return this.getCurrentUserRolesInDmp(dmpUsers).includes(DmpUserRole.Owner);
}
}

View File

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { ReferenceType } from '@app/core/common/enum/reference-type';
import { Reference, ReferencePersist } from '@app/core/model/reference/reference';
import { DmpReference, Reference, ReferencePersist } from '@app/core/model/reference/reference';
import { ReferenceLookup } from '@app/core/query/reference.lookup';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
@ -15,6 +15,7 @@ import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { ReferenceSourceType } from '@app/core/common/enum/reference-source-type';
import { ReferenceSearchDefinitionLookup, ReferenceSearchLookup } from '@app/core/query/reference-search.lookup';
import { Dmp } from '@app/core/model/dmp/dmp';
@Injectable()
export class ReferenceService {
@ -111,4 +112,18 @@ export class ReferenceService {
if (like) { lookup.like = this.filterService.transformLike(like); }
return lookup;
}
//
//
// UI Helpers
//
//
getReferencesForTypes(dmpReferences: DmpReference[], referenceTypes: ReferenceType[]): DmpReference[] {
return dmpReferences?.filter(x => referenceTypes?.includes(x?.reference?.type));
}
getReferencesForTypesFirstSafe(dmpReferences: DmpReference[], referenceTypes: ReferenceType[]): DmpReference {
return this.getReferencesForTypes(dmpReferences, referenceTypes)?.find(Boolean);
}
}

View File

@ -27,6 +27,7 @@ import { DmpBlueprintType } from '../../common/enum/dmp-blueprint-type';
import { DmpStatus } from '../../common/enum/dmp-status';
import { ValidationType } from '../../common/enum/validation-type';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
@Injectable()
export class EnumUtils {
@ -368,4 +369,11 @@ export class EnumUtils {
}
}
toDmpUserRolesString(roles: DmpUserRole[]): string { return roles.map(x => this.toDmpUserRoleString(x)).join(', ') }
toDmpUserRoleString(role: DmpUserRole): string {
switch (role) {
case DmpUserRole.Owner: return this.language.instant('TYPES.DMP-USER-ROLE.OWNER');
case DmpUserRole.User: return this.language.instant('TYPES.DMP-USER-ROLE.USER');
}
}
}

View File

@ -426,7 +426,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
breadcrumbs.push({
parentComponentName: null,
label: this.language.instant('NAV-BAR.PUBLIC DATASETS'),
url: '/explore'
url: '/explore-descriptions'
});
breadcrumbs.push({
parentComponentName: null,
@ -612,7 +612,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
if (!isNullOrUndefined(this.lock)) {
this.lockService.unlockTarget(this.datasetWizardModel.id).pipe(takeUntil(this._destroyed)).subscribe(
complete => {
this.publicMode ? this.router.navigate(['/explore']) : this.router.navigate(['/datasets']);
this.publicMode ? this.router.navigate(['/explore-descriptions']) : this.router.navigate(['/datasets']);
},
error => {
this.formGroup.get('status').setValue(DmpStatus.Draft);
@ -620,7 +620,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
}
)
} else {
this.publicMode ? this.router.navigate(['/explore']) : this.router.navigate(['/datasets']);
this.publicMode ? this.router.navigate(['/explore-descriptions']) : this.router.navigate(['/datasets']);
}
}

View File

@ -5,7 +5,7 @@
<!-- <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 class="card-content info-text mb-0">
<p>{{'DATASET-LISTING.TEXT-INFO' | translate}} <u class="pointer" [routerLink]="['/explore']">{{'DATASET-LISTING.LINK-PUBLIC-DATASETS' | translate}}</u> {{'DATASET-LISTING.TEXT-INFO-REST' | translate}}</p>
<p>{{'DATASET-LISTING.TEXT-INFO' | translate}} <u class="pointer" [routerLink]="['/explore-descriptions']">{{'DATASET-LISTING.LINK-PUBLIC-DATASETS' | translate}}</u> {{'DATASET-LISTING.TEXT-INFO-REST' | translate}}</p>
<p class="mt-4 pt-2">{{'DATASET-LISTING.TEXT-INFO-PAR' | translate}}
<div class="d-flex">
<button mat-raised-button class="add-dataset align-self-center yellow-btn" (click)="addNewDataset()">

View File

@ -88,7 +88,7 @@ export class DatasetListingComponent extends BaseComponent implements OnInit {//
ngOnInit() {
this.matomoService.trackPageView('Datasets');
this.isPublic = this.router.url === '/explore';
this.isPublic = this.router.url === '/explore-descriptions';
if (this.isPublic) {
this.formGroup.get('order').setValue(this.order.DATASETPUBLISHED);
} else {

View File

@ -1,95 +0,0 @@
import { map, filter } from 'rxjs/operators';
import { Component } from "@angular/core";
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
import { SingleAutoCompleteConfiguration } from "../../../../library/auto-complete/single/single-auto-complete-configuration";
import { Observable } from "rxjs";
import { DataTableRequest } from "../../../../core/model/data-table/data-table-request";
import { DmpCriteria } from "../../../../core/query/dmp/dmp-criteria";
import { DmpListingModel } from "../../../../core/model/dmp/dmp-listing";
import { DmpService } from "../../../../core/services/dmp/dmp.service";
import { Inject } from "@angular/core";
import { DmpModel } from "../../../../core/model/dmp/dmp";
import { TranslateService } from "@ngx-translate/core";
@Component({
selector: 'dataset-copy-dialogue-component',
templateUrl: 'dataset-copy-dialogue.component.html',
styleUrls: ['./dataset-copy-dialogue.component.scss'],
})
export class DatasetCopyDialogueComponent {
dmpAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
dmpModel: DmpModel;
datasetDescriptionTemplateLabel: String;
constructor(
public dialogRef: MatDialogRef<DatasetCopyDialogueComponent>,
public dmpService: DmpService,
public language: TranslateService,
@Inject(MAT_DIALOG_DATA) public data: any
) { }
ngOnInit() {
this.dmpAutoCompleteConfiguration = {
filterFn: this.searchDmp.bind(this),
initialItems: (extraData) => this.searchDmp(''),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
};
}
cancel() {
this.dialogRef.close(this.data);
}
confirm() {
this.datasetProfileValidate().subscribe(x => {
if (this.data.datasetProfileExist) {
this.dialogRef.close(this.data);
}
else if (!this.data.datasetProfileExist) {
this.data.formControl.setErrors({ 'incorrect': true });
}
});
}
searchDmp(query: string): Observable<DmpListingModel[]> {
const fields: Array<string> = new Array<string>();
fields.push('asc');
const dmpDataTableRequest: DataTableRequest<DmpCriteria> = new DataTableRequest(0, null, { fields: fields });
dmpDataTableRequest.criteria = new DmpCriteria();
dmpDataTableRequest.criteria.like = query;
dmpDataTableRequest.criteria.datasetTemplates = [this.data.datasetProfileId];
return this.dmpService.getPaged(dmpDataTableRequest, "profiles").pipe(map(x => x.data));
}
datasetProfileValidate() {
return this.dmpService.getSingle(this.data.formControl.value.id).pipe(map(result => result as DmpModel),
map(result => {
this.dmpModel = result
this.dmpModel.profiles.forEach((element) => {
if (element.id == this.data.datasetProfileId) {
this.data.datasetProfileExist = true;
}
})
}));
}
getErrorMessage() {
return this.language.instant('DATASET-WIZARD.DIALOGUE.ERROR-MESSAGE');
}
hasValidDatasetProfile() {
if (this.data.datasetProfileExist) {
return true;
}
else {
return false;
}
}
close() {
this.dialogRef.close(false);
}
}

View File

@ -1,18 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { DatasetCopyDialogueComponent } from './dataset-copy-dialogue.component';
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
AutoCompleteModule
],
declarations: [
DatasetCopyDialogueComponent
]
})
export class DatasetCopyDialogModule { }

View File

@ -426,7 +426,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme
breadcrumbs.push({
parentComponentName: null,
label: this.language.instant('NAV-BAR.PUBLIC DATASETS'),
url: '/explore'
url: '/explore-descriptions'
});
breadcrumbs.push({
parentComponentName: null,

View File

@ -1,17 +1,17 @@
<div class="dataset-copy-dialog">
<div mat-dialog-title class="row d-flex flex-row">
<div mat-dialog-title class="col-auto">{{'DATASET-WIZARD.DIALOGUE.TITLE' | translate}}</div>
<div mat-dialog-title class="col-auto">{{'DESCRIPTION-COPY-DIALOG.TITLE' | translate}}</div>
<div class="col-auto ml-auto close-btn" (click)="close()"><mat-icon class="close-icon">close</mat-icon></div>
</div>
<div mat-dialog-content class="confirmation-message">
<mat-form-field class="col-12">
<app-single-auto-complete [formControl]="data.formControl" placeholder="{{'DATASET-WIZARD.DIALOGUE.DMP-SEARCH.PLACEHOLDER' | translate}}" [configuration]="dmpAutoCompleteConfiguration">
<app-single-auto-complete [formControl]="data.formControl" placeholder="{{'DESCRIPTION-COPY-DIALOG.PLACEHOLDER' | translate}}" [configuration]="dmpAutoCompleteConfiguration">
</app-single-auto-complete>
</mat-form-field>
<!-- <mat-error *ngIf="data.formControl.hasError('incorrect')">{{getErrorMessage()}}</mat-error> -->
</div>
<div mat-dialog-actions class="row">
<div class="col-auto ml-auto"><button mat-button class="cancel-btn" type="button" (click)="cancel()">{{ data.cancelButton }}</button></div>
<div class="col-auto"><button mat-button class="confirm-btn" type="button" (click)="confirm()">{{ data.confirmButton }}</button></div>
<div class="col-auto"><button mat-button class="confirm-btn" type="button" [disabled]="this.data.formControl.value == null" (click)="confirm()">{{ data.confirmButton }}</button></div>
</div>
</div>

View File

@ -0,0 +1,61 @@
import { map, filter } from 'rxjs/operators';
import { Component } from "@angular/core";
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
import { Observable } from "rxjs";
import { Inject } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { Dmp } from '@app/core/model/dmp/dmp';
import { DmpServiceNew } from '@app/core/services/dmp/dmp.service';
import { DescriptionService } from '@app/core/services/description/description.service';
@Component({
selector: 'description-copy-dialog-component',
templateUrl: 'description-copy-dialog.component.html',
styleUrls: ['./description-copy-dialog.component.scss'],
})
export class DescriptionCopyDialogComponent {
dmpModel: Dmp;
descriptionDescriptionTemplateLabel: String;
dmpAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { //TODO: add filter to only get DMPs that have connection with the same Description Template group.
initialItems: (data?: any) => this.dmpService.query(this.dmpService.buildAutocompleteLookup()).pipe(map(x => x.items)),
filterFn: (searchQuery: string, data?: any) => this.dmpService.query(this.dmpService.buildAutocompleteLookup(searchQuery)).pipe(map(x => x.items)),
getSelectedItem: (selectedItem: any) => this.dmpService.query(this.dmpService.buildAutocompleteLookup(null, null, [selectedItem])).pipe(map(x => x.items[0])),
displayFn: (item: Dmp) => item.label,
titleFn: (item: Dmp) => item.label,
valueAssign: (item: Dmp) => item.id,
};
constructor(
public dialogRef: MatDialogRef<DescriptionCopyDialogComponent>,
public dmpService: DmpServiceNew,
public descriptionService: DescriptionService,
public language: TranslateService,
@Inject(MAT_DIALOG_DATA) public data: any
) { }
ngOnInit() {
}
cancel() {
this.dialogRef.close(this.data);
}
confirm() {
// TODO: create a backend service to copy the description
const newDmpId = this.data.formControl.value;
this.dialogRef.close(newDmpId);
}
getErrorMessage() {
return this.language.instant('DESCRIPTION-COPY-DIALOG.ERROR-MESSAGE');
}
close() {
this.dialogRef.close(false);
}
}

View File

@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { DescriptionCopyDialogComponent } from './description-copy-dialog.component';
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
AutoCompleteModule
],
declarations: [
DescriptionCopyDialogComponent
]
})
export class DescriptionCopyDialogModule { }

View File

@ -25,6 +25,8 @@ import { FormValidationErrorsDialogModule } from '@common/forms/form-validation-
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { AngularStickyThingsModule } from '@w11k/angular-sticky-things';
import { DescriptionCopyDialogModule } from './description-copy-dialog/description-copy-dialog.module';
import { DescriptionOverviewModule } from './overview/description-overview.module';
// import { FormProgressIndicationModule } from '../misc/description-description-form/components/form-progress-indication/form-progress-indication.module';
// import { DescriptionCopyDialogModule } from './description-wizard/description-copy-dialogue/description-copy-dialogue.module';
// import { DescriptionCriteriaDialogComponent } from './listing/criteria/description-criteria-dialogue/description-criteria-dialog.component';
@ -48,7 +50,10 @@ import { AngularStickyThingsModule } from '@w11k/angular-sticky-things';
// DescriptionCopyDialogModule,
// DescriptionOverviewModule,
// FormProgressIndicationModule,
RichTextEditorModule
RichTextEditorModule,
DescriptionCopyDialogModule,
DescriptionOverviewModule
],
declarations: [
DescriptionListingComponent,

View File

@ -1,9 +1,9 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard';
import { AuthGuard } from '../../core/auth-guard.service';
// import { DescriptionWizardComponent } from './description-wizard/description-wizard.component';
import { DescriptionListingComponent } from './listing/description-listing.component';
import { DescriptionOverviewComponent } from './overview/description-overview.component';
// import { DescriptionOverviewComponent } from './overview/description-overview.component';
const routes: Routes = [
@ -23,6 +23,22 @@ const routes: Routes = [
breadcrumb: true
},
},
{
path: 'overview/:id',
component: DescriptionOverviewComponent,
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DATASET-OVERVIEW'
},
},
{
path: 'publicOverview/:publicId',
component: DescriptionOverviewComponent,
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DATASET-OVERVIEW'
},
}
// {
// path: 'new/:dmpId/:dmpSectionIndex',
// component: DescriptionWizardComponent,
@ -76,14 +92,6 @@ const routes: Routes = [
// },
// canDeactivate:[CanDeactivateGuard]
// },
{
path: 'dmp/:dmpId',
component: DescriptionListingComponent,
canActivate: [AuthGuard],
data: {
breadcrumb: true
},
},
// {
// path: 'copy/:id',
// component: DescriptionWizardComponent,
@ -104,22 +112,7 @@ const routes: Routes = [
// },
// canDeactivate:[CanDeactivateGuard]
// },
// {
// path: 'overview/:id',
// component: DescriptionOverviewComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DATASET-OVERVIEW'
// },
// },
// {
// path: 'publicOverview/:publicId',
// component: DescriptionOverviewComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DATASET-OVERVIEW'
// },
// }
];
@NgModule({

View File

@ -5,21 +5,21 @@
<!-- <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 class="card-content info-text mb-0">
<p>{{'DATASET-LISTING.TEXT-INFO' | translate}} <u class="pointer" [routerLink]="['/explore']">{{'DATASET-LISTING.LINK-PUBLIC-DATASETS' | translate}}</u> {{'DATASET-LISTING.TEXT-INFO-REST' | translate}}</p>
<p class="mt-4 pt-2">{{'DATASET-LISTING.TEXT-INFO-PAR' | translate}}
<p>{{'DESCRIPTION-LISTING.TEXT-INFO' | translate}} <u class="pointer" [routerLink]="['/explore-descriptions']">{{'DESCRIPTION-LISTING.LINK-PUBLIC-DATASETS' | translate}}</u> {{'DESCRIPTION-LISTING.TEXT-INFO-REST' | translate}}</p>
<p class="mt-4 pt-2">{{'DESCRIPTION-LISTING.TEXT-INFO-PAR' | translate}}
<div class="d-flex">
<button mat-raised-button class="add-description align-self-center yellow-btn" (click)="addNewDescription()">
{{'DASHBOARD.ACTIONS.ADD-DESCRIPTION' | translate}}
{{'DESCRIPTION-LISTING.ACTIONS.ADD-DESCRIPTION' | translate}}
</button>
<img class="col-auto ml-auto laptop-img" src="../../../assets/images/dashboard-popup.png">
</div>
</div>
</div>
<p *ngIf="listingItems && listingItems.length > 0 || this.lookup.like" class="col-auto header-title">{{(isPublic ? 'GENERAL.TITLES.EXPLORE' : 'GENERAL.TITLES.DESCRIPTIONS') | translate}}</p>
<p *ngIf="listingItems && listingItems.length > 0 || this.lookup.like" class="col-auto header-title">{{(isPublic ? 'DESCRIPTION-LISTING.TITLE-EXPLORE' : 'DESCRIPTION-LISTING.TITLE') | translate}}</p>
<div *ngIf="listingItems && listingItems.length > 0 && !isPublic || this.lookup.like" class="ml-auto">
<div class="col-auto">
<button mat-raised-button class="add-description align-self-center yellow-btn" (click)="addNewDescription()">
{{'DASHBOARD.ACTIONS.ADD-DESCRIPTION' | translate}}
{{'DESCRIPTION-LISTING.ACTIONS.ADD-DESCRIPTION' | translate}}
</button>
</div>
</div>
@ -48,7 +48,7 @@
<div class="d-flex flex-row ml-auto">
<!-- Guided Tour -->
<div *ngIf="!isPublic" class="center-content" (click)="restartTour()">
{{ 'GENERAL.ACTIONS.TAKE-A-TOUR'| translate }}
{{ 'DESCRIPTION-LISTING.ACTIONS.TAKE-A-TOUR'| translate }}
</div>
<!-- End of Guided Tour -->
<!-- Search Filter-->
@ -66,11 +66,11 @@
<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">
<button type="button" class="btn-load-more" (click)="loadMore()">{{'GENERAL.ACTIONS.LOAD-MORE' | translate}}</button>
<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">
<span class="empty-list">{{'DATASET-LISTING.EMPTY-LIST' | translate}}</span>
<span class="empty-list">{{'DESCRIPTION-LISTING.EMPTY-LIST' | translate}}</span>
</div>
</div>
</div>

View File

@ -7,11 +7,13 @@ import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { Description, DescriptionReference } from '@app/core/model/description/description';
import { Dmp, DmpUser } from '@app/core/model/dmp/dmp';
import { Reference } from '@app/core/model/reference/reference';
import { DmpReference, Reference } from '@app/core/model/reference/reference';
import { DescriptionLookup } from '@app/core/query/description.lookup';
import { DmpLookup } from '@app/core/query/dmp.lookup';
import { AuthService } from '@app/core/services/auth/auth.service';
@ -88,7 +90,7 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit
ngOnInit() {
this.matomoService.trackPageView('Descriptions');
this.isPublic = this.router.url === '/explore';
this.isPublic = this.router.url === '/explore-descriptions';
if (this.isPublic) {
this.formGroup.get('order').setValue(this.order.DATASETPUBLISHED);
} else {
@ -106,12 +108,13 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit
this.lookup.page = { size: this.pageSize, offset: 0 };
this.lookup.order = { items: ['-' + nameof<Description>(x => x.updatedAt)] };
this.lookup.metadata = { countAll: true };
this.lookup.isActive = [IsActive.Active];
if (this.dmpId != null && Guid.isGuid(this.dmpId)) {
this.dmpSearchEnabled = false;
//const dmp = await this.dmpService.getSingle(this.dmpId).toPromise();
this.lookup.dmpSubQuery = new DmpLookup();
this.lookup.dmpSubQuery.ids = [Guid.parse(this.dmpId)];
this.refresh(this.lookup);
if (params['dmpLabel'] !== undefined) {
this.titlePrefix = 'for ' + params['dmpLabel'];
}
@ -170,33 +173,39 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit
this.refresh(this.lookup);
}
refresh(lookup: DescriptionLookup) {
loadMore() {
this.lookup.page = { size: this.pageSize, offset: this.lookup.page.offset + this.pageSize };
this.refresh(this.lookup);
}
private refresh(lookup: DescriptionLookup) {
lookup.project = {
fields: [
nameof<Description>(x => x.id),
nameof<Description>(x => x.label),
nameof<Description>(x => x.status),
nameof<Description>(x => x.updatedAt),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.label)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.accessType)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.roles)].join('.'),
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.id)].join('.'),
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.id)].join('.'),
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.label)].join('.'),
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.type)].join('.'),
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.reference)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.label)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.type)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.reference)].join('.'),
]
};
this.descriptionService.query(lookup).pipe(takeUntil(this._destroyed))
.subscribe(result => {
if (!result) { return []; }
// if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
this.totalCount = result.count;
if (lookup?.page?.offset === 0) this.listingItems = [];
this.listingItems = result.items;
this.listingItems.push(...result.items);
this.hasListingItems = true;
});
}
@ -278,18 +287,18 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit
}
public setDashboardTourDmpText(): void {
this.dmpText = this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' +
this.language.instant('DMP-LISTING.TEXT-INFO-QUESTION') + ' ' +
this.language.instant('DMP-LISTING.LINK-ZENODO') + ' ' +
this.language.instant('DMP-LISTING.GET-IDEA');
this.dmpText = this.language.instant('DESCRIPTION-LISTING.TEXT-INFO') + '\n\n' +
this.language.instant('DESCRIPTION-LISTING.TEXT-INFO-QUESTION') + ' ' +
this.language.instant('DESCRIPTION-LISTING.LINK-ZENODO') + ' ' +
this.language.instant('DESCRIPTION-LISTING.GET-IDEA');
this.dashboardTour.steps[0].title = this.dmpText;
}
public setDashboardTourDescriptionText(): void {
this.descriptionText = this.language.instant('DATASET-LISTING.TEXT-INFO') +
this.language.instant('DATASET-LISTING.LINK-PUBLIC-DATASETS') + ' ' +
this.language.instant('DATASET-LISTING.TEXT-INFO-REST') + '\n\n' +
this.language.instant('DATASET-LISTING.TEXT-INFO-PAR');
this.descriptionText = this.language.instant('DESCRIPTION-LISTING.TEXT-INFO') +
this.language.instant('DESCRIPTION-LISTING.LINK-PUBLIC-DATASETS') + ' ' +
this.language.instant('DESCRIPTION-LISTING.TEXT-INFO-REST') + '\n\n' +
this.language.instant('DESCRIPTION-LISTING.TEXT-INFO-PAR');
this.dashboardTour.steps[1].title = this.descriptionText;
}

View File

@ -1,40 +1,40 @@
<div class="description-card">
<a [routerLink]="getItemLink()" class="pointer">
<div class="d-flex flex-direction-row">
<div class="col-auto description-label">{{'DATASET-LISTING.DESCRIPTION' | translate}}</div>
<div *ngIf="!isPublic" class="col-auto ml-auto edited-date">{{'DATASET-LISTING.STATES.EDITED' | translate}}: {{description.updatedAt | dateTimeCultureFormatter: "d MMMM y"}}</div>
<div *ngIf="isPublic" class="col-auto ml-auto edited-date">{{'DATASET-LISTING.STATES.PUBLISHED' | translate}}: {{description.dmpPublishedAt | dateTimeCultureFormatter: "d MMMM y"}}</div>
<div class="col-auto description-label">{{'DESCRIPTION-LISTING.DESCRIPTION' | translate}}</div>
<div *ngIf="!isPublic" class="col-auto ml-auto edited-date">{{'DESCRIPTION-LISTING.STATES.EDITED' | translate}}: {{description.updatedAt | dateTimeCultureFormatter: "d MMMM y"}}</div>
<div *ngIf="isPublic" class="col-auto ml-auto edited-date">{{'DESCRIPTION-LISTING.STATES.PUBLISHED' | translate}}: {{description.dmpPublishedAt | dateTimeCultureFormatter: "d MMMM y"}}</div>
</div>
<div *ngIf="description.status === descriptionStatusEnum.Finalized" class="col-auto description-title">{{description.label}}</div>
<div *ngIf="description.status === descriptionStatusEnum.Draft" class="col-auto description-title-draft">{{description.label}}</div>
<div class="description-subtitle">
<span *ngIf="isUserDescriptionRelated()" class="col-auto">{{ roleDisplay(description.users) }}</span>
<span *ngIf="isUserDescriptionRelated()" class="col-auto">{{ enumUtils.toDmpUserRolesString(dmpService.getCurrentUserRolesInDmp(description?.dmp?.dmpUsers)) }}</span>
<span *ngIf="isUserDescriptionRelated()">.</span>
<span class="col-auto" *ngIf="description.status === descriptionStatusEnum.Finalized && description.dmp.accessType === dmpAccessTypeEnum.Public"><span class="material-icons icon-align">public</span>{{'DATASET-LISTING.STATES.PUBLIC' | translate}}</span>
<span class="col-auto" *ngIf="description.status === descriptionStatusEnum.Finalized && description.dmp.accessType === dmpAccessTypeEnum.Public"><span class="material-icons icon-align">public</span>{{'DESCRIPTION-LISTING.STATES.PUBLIC' | translate}}</span>
<span *ngIf="description.status === descriptionStatusEnum.Finalized && description.dmp.accessType != dmpAccessTypeEnum.Public" class="col-auto"><span class="material-icons icon-align">done</span>{{ enumUtils.toDescriptionStatusString(description.status) }}</span>
<span *ngIf="description.status === descriptionStatusEnum.Draft" class=" col-auto draft"><span class="material-icons icon-align">create</span>{{ enumUtils.toDescriptionStatusString(description.status) }}</span>
<span>.</span>
<!-- <span class="col">{{'DATASET-LISTING.COLUMNS.GRANT' | translate}}: {{description.grant}}</span> -->
<span class="col">{{'DESCRIPTION-LISTING.GRANT' | translate}}: {{referenceService.getReferencesForTypesFirstSafe(description?.dmp?.dmpReferences, [referenceTypeEnum.Grants])?.reference?.label}}</span>
</div>
<div class="d-flex flex-direction-row pt-3 pb-3">
<div class="col-auto description-subtitle pr-0">{{'DATASET-LISTING.TOOLTIP.PART-OF' | translate}}
<div class="col-auto dmp-label ml-3">{{'DATASET-LISTING.TOOLTIP.DMP' | translate}}</div>
<div class="col-auto description-subtitle pr-0">{{'DESCRIPTION-LISTING.PART-OF' | translate}}
<div class="col-auto dmp-label ml-3">{{'DESCRIPTION-LISTING.DMP' | translate}}</div>
</div>
<div class="col dmp-title">{{description.dmp?.label}}</div>
</div>
</a>
<div class="description-card-actions">
<a class="col-auto border-right pointer" [matMenuTriggerFor]="exportMenu"><span class="material-icons icon-align pr-2">open_in_new</span>{{'DATASET-LISTING.ACTIONS.EXPORT' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isUserOwner" (click)="openShareDialog(description.dmp.id, description.dmp.label)"><span class="material-icons icon-align pr-2">group_add</span>{{'DATASET-LISTING.ACTIONS.INVITE-SHORT' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isAuthenticated()" (click)="openDmpSearchDialogue(description)"><span class="material-icons icon-align pr-2">file_copy</span>{{'DATASET-WIZARD.ACTIONS.COPY-DESCRIPTION' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isAuthenticated() && isUserDescriptionRelated()" (click)="deleteClicked(description.id)"><span class="material-icons icon-align pr-2">delete</span>{{ 'DATASET-WIZARD.ACTIONS.DELETE' | translate }}</a>
<a class="col-auto border-right pointer" [matMenuTriggerFor]="exportMenu"><span class="material-icons icon-align pr-2">open_in_new</span>{{'DESCRIPTION-LISTING.ACTIONS.EXPORT' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isUserOwner" (click)="openShareDialog(description.dmp.id, description.dmp.label)"><span class="material-icons icon-align pr-2">group_add</span>{{'DESCRIPTION-LISTING.ACTIONS.INVITE-SHORT' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isAuthenticated()" (click)="copyToDmp(description)"><span class="material-icons icon-align pr-2">file_copy</span>{{'DESCRIPTION-LISTING.ACTIONS.COPY-DESCRIPTION' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isAuthenticated() && isUserDescriptionRelated()" (click)="deleteClicked(description.id)"><span class="material-icons icon-align pr-2">delete</span>{{ 'DESCRIPTION-LISTING.ACTIONS.DELETE' | translate }}</a>
</div>
<mat-menu #actionsMenu="matMenu">
<button *ngIf="isAuthenticated()" mat-menu-item (click)="openDmpSearchDialogue(description)" class="menu-item">
<mat-icon>file_copy</mat-icon>{{'DATASET-WIZARD.ACTIONS.COPY-DESCRIPTION' | translate}}
<button *ngIf="isAuthenticated()" mat-menu-item (click)="copyToDmp(description)" class="menu-item">
<mat-icon>file_copy</mat-icon>{{'DESCRIPTION-LISTING.ACTIONS.COPY-DESCRIPTION' | translate}}
</button>
<button *ngIf="isUserDescriptionRelated()" mat-menu-item (click)="deleteClicked(description.id)" class="menu-item">
<mat-icon>delete</mat-icon>{{ 'DATASET-WIZARD.ACTIONS.DELETE' | translate }}
<mat-icon>delete</mat-icon>{{ 'DESCRIPTION-LISTING.ACTIONS.DELETE' | translate }}
</button>
</mat-menu>

View File

@ -23,6 +23,11 @@ import { DescriptionService } from '@app/core/services/description/description.s
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { Guid } from '@common/types/guid';
import { DmpAccessType } from '@app/core/common/enum/dmp-access-type';
import { DmpUser } from '@app/core/model/dmp/dmp';
import { DmpService, DmpServiceNew } from '@app/core/services/dmp/dmp.service';
import { ReferenceService } from '@app/core/services/reference/reference.service';
import { ReferenceType } from '@app/core/common/enum/reference-type';
import { DescriptionCopyDialogComponent } from '../../description-copy-dialog/description-copy-dialog.component';
@Component({
selector: 'app-description-listing-item-component',
@ -41,6 +46,7 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
isUserOwner: boolean;
descriptionStatusEnum = DescriptionStatus;
dmpAccessTypeEnum = DmpAccessType;
referenceTypeEnum = ReferenceType;
constructor(
private router: Router,
@ -54,7 +60,9 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
private location: Location,
private httpClient: HttpClient,
private matomoService: MatomoService,
private fileUtils: FileUtils
private fileUtils: FileUtils,
public dmpService: DmpServiceNew,
public referenceService: ReferenceService
) {
super();
}
@ -149,29 +157,27 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
});
}
openDmpSearchDialogue(description: Description) {
// TODO: add this.
// const formControl = new UntypedFormControl();
// const dialogRef = this.dialog.open(DescriptionCopyDialogueComponent, {
// width: '500px',
// restoreFocus: false,
// data: {
// formControl: formControl,
// descriptionId: description.id,
// descriptionProfileId: description.profile.id,
// descriptionProfileExist: false,
// confirmButton: this.language.instant('DATASET-WIZARD.DIALOGUE.COPY'),
// cancelButton: this.language.instant('DATASET-WIZARD.DIALOGUE.CANCEL')
// }
// });
copyToDmp(description: Description) {
const formControl = new UntypedFormControl();
const dialogRef = this.dialog.open(DescriptionCopyDialogComponent, {
width: '500px',
restoreFocus: false,
data: {
formControl: formControl,
descriptionId: description.id,
descriptionProfileId: description.descriptionTemplate.id,
descriptionProfileExist: false,
confirmButton: this.language.instant('DESCRIPTION-LISTING.COPY-DIALOG.COPY'),
cancelButton: this.language.instant('DESCRIPTION-LISTING.COPY-DIALOG.CANCEL')
}
});
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed))
// .subscribe(result => {
// if (result && result.descriptionProfileExist) {
// const newDmpId = result.formControl.value.id;
// this.router.navigate(['/descriptions/copy/' + result.descriptionId], { queryParams: { newDmpId: newDmpId } });
// }
// });
dialogRef.afterClosed().pipe(takeUntil(this._destroyed))
.subscribe(newDmpId => {
if (newDmpId) {
this.router.navigate(['/descriptions/copy/' + description.id], { queryParams: { newDmpId: newDmpId } });
}
});
}
deleteClicked(id: Guid) {
@ -213,7 +219,7 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
maxWidth: '400px',
restoreFocus: false,
data: {
message: this.language.instant('DATASET-WIZARD.ACTIONS.LOCK')
message: this.language.instant('DESCRIPTION-LISTING.LOCKED')
}
});
}
@ -234,38 +240,10 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error);
}
roleDisplay(value: any) {
const principalId: string = this.authService.userId()?.toString();
let role: number;
if (principalId) {
value.forEach(element => {
if (principalId === element.id) {
role = element.role;
}
});
}
if (role === 0) {
return this.language.instant('DMP-LISTING.OWNER');
}
else if (role === 1) {
return this.language.instant('DMP-LISTING.MEMBER');
}
else {
return this.language.instant('DMP-LISTING.OWNER');
}
}
isUserDescriptionRelated() {
//TODO: add user to description objects
const principalId: string = this.authService.userId()?.toString();
let isRelated: boolean = false;
// if (this.description && principalId) {
// this.description.users.forEach(element => {
// if (element.id === principalId) {
// isRelated = true;
// }
// })
// }
return isRelated;
isUserDescriptionRelated(): boolean {
const principalId: Guid = this.authService.userId();
return this.description.dmp.dmpUsers.some(x => (x.user.id === principalId));
}
}

View File

@ -1,186 +0,0 @@
<div class="main-content dataset-overview pl-5 pr-5">
<div class="container-fluid pl-0 pr-0">
<div *ngIf="dataset">
<a class="row mb-2 pl-1" (click)="goBack()" role="button">
<mat-icon class="back-icon pointer">chevron_left</mat-icon>
<p class="label-txt pointer">{{'DMP-WIZARD.ACTIONS.BACK' | translate}}</p>
</a>
<div class="row">
<div class="col-md-8 col-lg-8 pl-4">
<div class="row">
<span class="col-auto dataset-logo">{{ 'NAV-BAR.DESCRIPTION' | translate }}</span>
<p class="col dataset-label p-0 ml-3 mb-0">{{ dataset.label }}</p>
</div>
<div class="row d-flex align-items-center mt-3 mb-4 label-txt">
<div *ngIf="isUserDatasetRelated()" class="d-flex">
<p class="ml-0 mb-0 label2-txt">
{{ roleDisplayFromList(dataset.users) }}
</p>
</div>
<span *ngIf="isUserDatasetRelated()" class="ml-2 mr-2">.</span>
<!-- UNCOMMENT TO ADD PRIVATE ICON -->
<!-- <span *ngIf="isUserDatasetRelated() && (dataset.public || !dataset.public || lockStatus)" class="ml-2 mr-2">.</span> -->
<div *ngIf="dataset.public" class="d-flex flex-row">
<mat-icon class="status-icon">public</mat-icon>
{{'DMP-OVERVIEW.PUBLIC' | translate}}
</div>
<span *ngIf="dataset.public" class="ml-2 mr-2">.</span>
<!-- UNCOMMENT TO ADD PRIVATE ICON -->
<!-- <div *ngIf="!dataset.public" class="d-flex flex-row">
<mat-icon class="status-icon">public_off</mat-icon>
{{'DMP-OVERVIEW.PRIVATE' | translate}}
</div>
<span *ngIf="!dataset.public" class="ml-2 mr-2">.</span> -->
<div *ngIf="lockStatus" class="d-flex flex-row">
<mat-icon class="status-icon">lock_outline</mat-icon>
{{'DMP-OVERVIEW.LOCKED' | translate}}
</div>
<span *ngIf="lockStatus" class="ml-2 mr-2">.</span>
<div class="d-flex mr-2">{{'GENERAL.STATUSES.EDIT' | translate}} :
<!-- {{dataset.modified | date:'longDate':'+0200': this.language.store.currentLang }} -->
{{dataset.modified | dateTimeCultureFormatter: "d MMMM y"}}
</div>
<div class="d-flex ml-2 mr-4">
<div *ngIf="dataset.status" class="d-flex flex-row uppercase">
<mat-icon class="status-icon check-icon">check</mat-icon>
{{'TYPES.DATASET-STATUS.FINALISED' | translate}}
</div>
</div>
</div>
<div class="row mb-4 pb-3">
<button *ngIf="isDraftDataset(dataset) && !lockStatus" (click)="editClicked(dataset)" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DMP-LISTING.ACTIONS.EDIT' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">create</mat-icon>
</button>
<button *ngIf="isAuthenticated()" (click)="openDmpSearchDialogue()" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
</button>
<button *ngIf="isUserDatasetRelated() && !lockStatus" (click)="deleteClicked()" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DMP-LISTING.ACTIONS.DELETE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">delete</mat-icon>
</button>
</div>
<div class="row header">{{'DATASET-LISTING.TOOLTIP.PART-OF' | translate}}</div>
<div class="row ">
<button class="dmp-btn" (click)="dmpClicked(dataset.dmp)">
<div class="dmp-btn-label">
{{ this.dataset.dmp.label }}
</div>
<mat-icon>launch</mat-icon>
</button>
</div>
<div *ngIf="dataset.grant">
<div class="row header">{{'DMP-OVERVIEW.GRANT' | translate}}</div>
<div class="row dataset-label">{{ dataset.grant.label }}</div>
</div>
<div class="row header">{{'DMP-OVERVIEW.RESEARCHERS' | translate}}</div>
<div class="row">
<div *ngFor="let researcher of researchers; let last = last">
<span *ngIf="isOrcid(researcher.reference)">
<a href="{{ getOrcidPathForResearcher(researcher.reference) }}" target="blank" class="researcher">
<div class="id-btn">&nbsp;</div>
<div *ngIf="!last">{{ researcher.name }}, </div>
<div *ngIf="last">{{ researcher.name }}</div>
</a>
</span>
<span *ngIf="!isOrcid(researcher.reference)">
<div *ngIf="!last">{{ researcher.name }}, </div>
<div *ngIf="last">{{ researcher.name }}</div>
</span>
</div>
<span *ngIf="!researchers || researchers.length === 0" class="material-icons">horizontal_rule</span>
</div>
<div class="row header">{{'DATASET-LISTING.COLUMNS.DESCRIPTION' | translate}}</div>
<div class="row" *ngIf="dataset.description">
<p class="desc-txt" [innerHTML]="dataset.description"></p>
</div>
<div class="row" *ngIf="!dataset.description">
<span class="material-icons">horizontal_rule</span>
</div>
</div>
<div class="col-md-4 col-lg-4 p-0">
<div class="frame mb-3 pt-4 pl-3 pr-5 pb-1">
<div *ngIf="!dataset.status && isDraftDataset(dataset) && !lockStatus">
<div class="row ml-0 mr-0 pl-4 d-flex align-items-center" (click)="finalize(dataset)">
<button mat-mini-fab class="finalize-btn">
<mat-icon class="mat-mini-fab-icon check-icon">check</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.FINALIZE' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 d-flex align-items-center">
<hr class="hr-line">
</div>
</div>
<div *ngIf="hasReversableStatus(dataset)" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="reverse(dataset)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">unarchive</mat-icon>
</button>
<p class="mb-0 mr-0 pl-2 frame-txt">{{ 'DATASET-WIZARD.ACTIONS.REVERSE' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<button mat-mini-fab class="frame-btn" [matMenuTriggerFor]="exportMenu">
<mat-icon class="mat-mini-fab-icon">open_in_new</mat-icon>
</button>
<p class="mb-0 mr-0 pl-2 frame-txt" [matMenuTriggerFor]="exportMenu">
{{ 'DMP-LISTING.ACTIONS.EXPORT' | translate }}</p>
</div>
<!-- <div *ngIf="!dataset.public && showPublishButton(dataset) && isUserOwner" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="publish(dataset.id)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">public</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.MAKE-PUBLIC' | translate }}</p>
</div> -->
<mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(dataset.id)">
<i class="fa fa-file-pdf-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadDocx(dataset.id)">
<i class="fa fa-file-word-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadXml(dataset.id)">
<i class="fa fa-file-code-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
</button>
<!-- GK: NO-->
<!-- <button mat-menu-item (click)="downloadJson(dataset.id)">
<i class="fa fa-file-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.JSON' | translate}}</span>
</button> -->
</mat-menu>
</div>
<div class="frame mb-3 pt-4 pl-3 pr-3 pb-1">
<div class="row ml-0 mr-0 pl-4 pb-3">
<p class="header">{{ 'DATASET-OVERVIEW.DESCRIPTION-AUTHORS' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 ml-2 pb-3 d-flex align-items-center">
<div *ngFor="let user of dataset.users" class="row authors">
<div class="d-flex flex-row">
<button class="account_btn mr-3 pl-0">
<mat-icon class="account-icon">account_circle</mat-icon>
</button>
<div>
<p class="authors-label">{{ user.name }}
<span *ngIf="isUserAuthor(user.id)">
({{ 'DMP-OVERVIEW.YOU' | translate }})</span>
</p>
<p class="authors-role">{{ roleDisplay(user) }}</p>
</div>
</div>
<button *ngIf="isUserOwner && !dataset.status && user.role" (click)="removeUserFromDmp(user)" class="remove-btn">{{ 'GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE' | translate}}</button>
</div>
</div>
<div *ngIf="isUserOwner" class="row mt-3 mb-3 d-flex align-items-center justify-content-center">
<button mat-raised-button class="invite-btn" (click)="openShareDialog(dataset.dmp.id, dataset.dmp.label)">
<mat-icon>group_add</mat-icon>
{{'DMP-LISTING.ACTIONS.INVITE-SHORT' | translate}}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,549 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { DatasetOverviewModel } from '@app/core/model/dataset/dataset-overview';
import { BaseComponent } from '@common/base/base.component';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { Location } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { Role } from '@app/core/common/enum/role';
import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard';
import { DmpOverviewModel } from '@app/core/model/dmp/dmp-overview';
import { ResearcherModel } from '@app/core/model/researcher/researcher';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { AuthService } from '@app/core/services/auth/auth.service';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { UserServiceOld } from '@app/core/services/user/user.service-old';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { Oauth2DialogService } from '@app/ui/misc/oauth2-dialog/service/oauth2-dialog.service';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import * as FileSaver from 'file-saver';
import { filter, takeUntil } from 'rxjs/operators';
import { DatasetCopyDialogueComponent } from '../dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component';
@Component({
selector: 'app-dataset-overview',
templateUrl: './dataset-overview.component.html',
styleUrls: ['./dataset-overview.component.scss']
})
export class DatasetOverviewComponent extends BaseComponent implements OnInit {
dataset: DatasetOverviewModel;
// datasetWizardEditorModel: DatasetWizardEditorModel;
datasetWizardModel: DatasetWizardModel;
isNew = true;
isFinalized = false;
isPublicView = true;
hasPublishButton: boolean = true;
// breadCrumbs: Observable<BreadcrumbItem[]> = observableOf();
isUserOwner: boolean;
expand = false;
researchers: ResearcherModel[];
users: UserInfoListingModel[];
lockStatus: Boolean;
constructor(
private route: ActivatedRoute,
private router: Router,
private datasetService: DatasetService,
private translate: TranslateService,
private authentication: AuthService,
private dialog: MatDialog,
private language: TranslateService,
private uiNotificationService: UiNotificationService,
private configurationService: ConfigurationService,
private oauth2DialogService: Oauth2DialogService,
private userService: UserServiceOld,
private dmpService: DmpService,
private location: Location,
private datasetWizardService: DatasetWizardService,
private lockService: LockService,
private httpClient: HttpClient,
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
ngOnInit() {
this.matomoService.trackPageView('Dataset Overview');
// Gets dataset data using parameter id
this.route.params
.pipe(takeUntil(this._destroyed))
.subscribe((params: Params) => {
const itemId = params['id'];
const publicId = params['publicId'];
if (itemId != null) {
this.isNew = false;
this.isPublicView = false;
this.datasetService.getOverviewSingle(itemId)
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.dataset = data;
this.researchers = this.dataset.dmp.researchers;
this.users = this.dataset.dmp.users;
this.checkLockStatus(this.dataset.id);
this.setIsUserOwner();
// const breadCrumbs = [];
// breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), url: "/datasets" });
// breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/overview/' + this.dataset.id });
// this.breadCrumbs = observableOf(breadCrumbs);
}, (error: any) => {
if (error.status === 404) {
return this.onFetchingDeletedCallbackError('/datasets/');
}
if (error.status === 403) {
return this.onFetchingForbiddenCallbackError('/datasets/');
}
});
}
else if (publicId != null) {
this.isNew = false;
this.isFinalized = true;
this.isPublicView = true;
this.datasetService.getOverviewSinglePublic(publicId)
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.dataset = data;
this.researchers = this.dataset.dmp.researchers;
this.users = this.dataset.dmp.users;
// const breadCrumbs = [];
// breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), url: "/explore" });
// breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/publicOverview/' + this.dataset.id });
// this.breadCrumbs = observableOf(breadCrumbs);
}, (error: any) => {
if (error.status === 404) {
return this.onFetchingDeletedCallbackError('/explore');
}
if (error.status === 403) {
return this.onFetchingForbiddenCallbackError('/explore');
}
});
}
});
}
checkLockStatus(id: string) {
this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed))
.subscribe(lockStatus => {
this.lockStatus = lockStatus
if (lockStatus) {
this.dialog.open(PopupNotificationDialogComponent, {
data: {
title: this.language.instant('DATASET-OVERVIEW.LOCKED.TITLE'),
message: this.language.instant('DATASET-OVERVIEW.LOCKED.MESSAGE')
}, maxWidth: '30em'
});
}
});
}
onFetchingDeletedCallbackError(redirectRoot: string) {
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.DELETED-DATASET'), SnackBarNotificationLevel.Error);
this.router.navigate([redirectRoot]);
}
onFetchingForbiddenCallbackError(redirectRoot: string) {
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.FORBIDEN-DATASET'), SnackBarNotificationLevel.Error);
this.router.navigate([redirectRoot]);
}
goBack(): void {
this.location.back();
}
reloadPage(): void {
const path = this.location.path();
this.router.navigateByUrl('/reload', { skipLocationChange: true }).then(() => this.router.navigate([path]));
}
setIsUserOwner() {
if (this.dataset) {
const principalId: string = this.authentication.userId()?.toString();
if (principalId) this.isUserOwner = !!this.dataset.users.find(x => (x.role === Role.Owner) && (principalId === x.id));
}
}
isUserAuthor(userId: string): boolean {
if (this.isAuthenticated()) {
const principalId: string = this.authentication.userId()?.toString();
return userId === principalId;
} else return false;
}
isUserDatasetRelated() {
const principalId: string = this.authentication.userId()?.toString();
let isRelated: boolean = false;
if (this.dataset && principalId) {
this.dataset.users.forEach(element => {
if (element.id === principalId) {
isRelated = true;
}
})
}
return isRelated;
}
roleDisplay(value: UserInfoListingModel) {
if (value.role === Role.Owner) {
return this.translate.instant('DMP-LISTING.OWNER');
} else if (value.role === Role.Member) {
return this.translate.instant('DMP-LISTING.MEMBER');
} else {
return this.translate.instant('DMP-LISTING.OWNER');
}
}
roleDisplayFromList(value: UserInfoListingModel[]) {
const principalId: string = this.authentication.userId()?.toString();
let role: number;
if (principalId) {
value.forEach(element => {
if (principalId === element.id) {
role = element.role;
}
});
}
if (role === Role.Owner) {
return this.translate.instant('DMP-LISTING.OWNER');
} else if (role === Role.Member) {
return this.translate.instant('DMP-LISTING.MEMBER');
} else {
return this.translate.instant('DMP-LISTING.OWNER');
}
}
openShareDialog(rowId: any, rowName: any) {
const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
autoFocus: false,
restoreFocus: false,
data: {
dmpId: rowId,
dmpName: rowName
}
});
}
public isAuthenticated(): boolean {
return this.authentication.currentAccountIsAuthenticated();
}
isDraftDataset(dataset: DatasetOverviewModel) {
return dataset.status == DatasetStatus.Draft;
}
isFinalizedDataset(dataset: DatasetOverviewModel) {
return dataset.status == DatasetStatus.Finalized;
}
editClicked(dataset: DatasetOverviewModel) {
if (dataset.public) {
this.router.navigate(['/datasets/publicEdit/', dataset.id]);
// let url = this.router.createUrlTree(['/datasets/publicEdit/', dataset.id]);
// window.open(url.toString(), '_blank');
} else {
this.router.navigate(['/datasets/edit/', dataset.id]);
// let url = this.router.createUrlTree(['/datasets/edit/', dataset.id]);
// let url = this.router.createUrlTree(['/plans/edit/', dataset.dmp.id], { queryParams: { dataset: dataset.id } });
// window.open(url.toString(), '_blank');
}
}
deleteClicked() {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
maxWidth: '300px',
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
isDeleteConfirmation: true
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
this.datasetService.delete(this.dataset.id)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => {
this.onDeleteCallbackSuccess();
},
error => this.onDeleteCallbackError(error)
);
}
});
}
dmpClicked(dmp: DmpOverviewModel) {
if (this.isPublicView) {
this.router.navigate(['/explore-plans/publicOverview/' + dmp.id]);
} else {
this.router.navigate(['/plans/overview/' + dmp.id]);
}
}
onDeleteCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DELETE'), SnackBarNotificationLevel.Success);
this.router.navigate(['/datasets']);
}
onDeleteCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error);
}
onUpdateCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
this.reloadPage();
}
onUpdateCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? this.tryTranslate(error.error.message) : this.language.instant('DATASET-UPLOAD.SNACK-BAR.UNSUCCESSFUL'), SnackBarNotificationLevel.Error);
}
tryTranslate(errorMessage: string): string {
return errorMessage.replace('Field value of', this.language.instant('Field value of'))
.replace('must be filled', this.language.instant('must be filled'));
}
public getOrcidPath(): string {
return this.configurationService.orcidPath;
}
isOrcid(reference: string) {
const head = reference.split(':')[0];
return head === 'orcid';
}
getOrcidPathForResearcher(reference: string): string {
const path = this.getOrcidPath();
const userId = reference.split(':')[1];
return path + userId;
}
downloadPDF(id: string) {
this.datasetService.downloadPDF(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "pdf", id);
});
}
downloadDocx(id: string) {
this.datasetService.downloadDocx(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "docx", id);
});
}
downloadXml(id: string) {
this.datasetService.downloadXML(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/xml' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('datasets', "xml", id);
});
}
//GK: NO
// downloadJson(id: string) {
// this.datasetService.downloadJson(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/json' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// })
// }
openDmpSearchDialogue() {
const formControl = new UntypedFormControl();
const dialogRef = this.dialog.open(DatasetCopyDialogueComponent, {
width: '500px',
restoreFocus: false,
data: {
formControl: formControl,
datasetId: this.dataset.id,
datasetProfileId: this.dataset.datasetTemplate.id,
datasetProfileExist: false,
confirmButton: this.language.instant('DATASET-WIZARD.DIALOGUE.COPY'),
cancelButton: this.language.instant('DATASET-WIZARD.DIALOGUE.CANCEL')
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed))
.subscribe(result => {
if (result && result.datasetProfileExist) {
const newDmpId = result.formControl.value.id;
this.router.navigate(['/datasets/copy/' + result.datasetId], { queryParams: { newDmpId: newDmpId } });
// let url = this.router.createUrlTree(['/datasets/copy/', result.datasetId, { newDmpId: newDmpId }])
// window.open(url.toString(), '_blank')
}
});
}
updateUsers() {
return this.dmpService.updateUsers(this.dataset.dmp.id, this.users).pipe(takeUntil(this._destroyed))
.subscribe(
complete => {
this.onUpdateCallbackSuccess();
},
error => this.onUpdateCallbackError(error)
);
}
removeUserFromDmp(user: UserInfoListingModel) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-USER'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
const index = this.users.findIndex(x => x.id === user.id);
if (index > -1) {
this.users.splice(index, 1);
}
this.updateUsers();
}
});
}
showPublishButton(dataset: DatasetOverviewModel) {
return this.isFinalizedDataset(dataset) && !dataset.public && this.hasPublishButton;
}
// publish(id: String) {
// const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
// maxWidth: '500px',
// restoreFocus: false,
// data: {
// message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.PUBLISH-ITEM'),
// privacyPolicyNames: this.language.instant('GENERAL.CONFIRMATION-DIALOG.PRIVACY-POLICY-NAMES'),
// confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
// cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
// isDeleteConfirmation: false
// }
// });
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (result) {
// this.datasetService.publish(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(() => {
// this.hasPublishButton = false;
// this.reloadPage();
// });
// }
// });
// }
finalize(dataset: DatasetOverviewModel) {
this.dialog.open(ConfirmationDialogComponent, {
data: {
message: this.language.instant('DATASET-OVERVIEW.FINALISE-POPUP.MESSAGE'),
confirmButton: this.language.instant('DATASET-OVERVIEW.FINALISE-POPUP.CONFIRM'),
cancelButton: this.language.instant('DATASET-OVERVIEW.FINALISE-POPUP.CANCEL'),
},
maxWidth: '30em'
})
.afterClosed()
.pipe(
filter(x => x),
takeUntil(this._destroyed)
)
.subscribe(_ => {
this.router.navigate(['datasets', 'edit', dataset.id, 'finalize']);
})
// const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
// restoreFocus: false,
// data: {
// message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.FINALIZE-ITEM'),
// confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'),
// cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE'),
// isDeleteConfirmation: false
// }
// });
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (result) {
// this.datasetWizardService.getSingle(dataset.id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(data => {
// this.datasetWizardModel = data;
// this.datasetWizardModel.status = DatasetStatus.Finalized;
// this.datasetWizardService.createDataset(this.datasetWizardModel)
// .pipe(takeUntil(this._destroyed))
// .subscribe(
// data => this.onUpdateCallbackSuccess(),
// error => this.onUpdateCallbackError(error)
// );
// });
// }
// });
}
hasReversableStatus(dataset: DatasetOverviewModel): boolean {
return dataset.dmp.status == DmpStatus.Draft && dataset.status == DatasetStatus.Finalized
}
reverse(dataset: DatasetOverviewModel) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
restoreFocus: false,
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.UNFINALIZE-ITEM'),
confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'),
cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
this.datasetWizardService.getSingle(dataset.id)
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.datasetWizardModel = data;
this.datasetWizardModel.status = DatasetStatus.Draft;
this.datasetWizardService.createDataset(this.datasetWizardModel)
.pipe(takeUntil(this._destroyed))
.subscribe(
data => this.onUpdateCallbackSuccess(),
error => this.onUpdateCallbackError(error)
);
});
}
});
}
}

View File

@ -0,0 +1,166 @@
<div class="main-content description-overview pl-5 pr-5">
<div class="container-fluid pl-0 pr-0">
<div *ngIf="description">
<a class="row mb-2 pl-1" (click)="goBack()" role="button">
<mat-icon class="back-icon pointer">chevron_left</mat-icon>
<p class="label-txt pointer">{{'DESCRIPTION-OVERVIEW.ACTIONS.BACK' | translate}}</p>
</a>
<div class="row">
<div class="col-md-8 col-lg-8 pl-4">
<div class="row">
<span class="col-auto description-logo">{{ 'DESCRIPTION-OVERVIEW.TITLE' | translate }}</span>
<p class="col description-label p-0 ml-3 mb-0">{{ description.label }}</p>
</div>
<div class="row d-flex align-items-center mt-3 mb-4 label-txt">
<div *ngIf="isUserDescriptionRelated()" class="d-flex">
<p class="ml-0 mb-0 label2-txt">
{{ enumUtils.toDmpUserRolesString(dmpService.getCurrentUserRolesInDmp(description?.dmp?.dmpUsers)) }}
</p>
</div>
<span *ngIf="isUserDescriptionRelated()" class="ml-2 mr-2">.</span>
<div *ngIf="description.status === descriptionStatusEnum.Finalized && description.dmp.accessType === dmpAccessTypeEnum.Public" class="d-flex flex-row">
<mat-icon class="status-icon">public</mat-icon>
{{'DESCRIPTION-OVERVIEW.PUBLIC' | translate}}
</div>
<span *ngIf="description.status === descriptionStatusEnum.Finalized && description.dmp.accessType === dmpAccessTypeEnum.Public" class="ml-2 mr-2">.</span>
<div *ngIf="lockStatus" class="d-flex flex-row">
<mat-icon class="status-icon">lock_outline</mat-icon>
{{'DESCRIPTION-OVERVIEW.LOCKED' | translate}}
</div>
<span *ngIf="lockStatus" class="ml-2 mr-2">.</span>
<div class="d-flex mr-2">{{'DESCRIPTION-OVERVIEW.EDITED' | translate}} :
{{description.modified | dateTimeCultureFormatter: "d MMMM y"}}
</div>
<div class="d-flex ml-2 mr-4">
<div *ngIf="description.status === descriptionStatusEnum.Draft" class="d-flex flex-row uppercase">
<mat-icon class="status-icon check-icon">check</mat-icon>
{{'DESCRIPTION-OVERVIEW.FINALISED' | translate}}
</div>
</div>
</div>
<div class="row mb-4 pb-3">
<button *ngIf="isDraftDescription(description) && !lockStatus" (click)="editClicked(description)" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DESCRIPTION-OVERVIEW.ACTIONS.EDIT' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">create</mat-icon>
</button>
<button *ngIf="isAuthenticated()" (click)="openCopyToDmpDialog()" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DESCRIPTION-OVERVIEW.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
</button>
<button *ngIf="isUserDescriptionRelated() && !lockStatus" (click)="deleteClicked()" mat-mini-fab class="mr-3 actions-btn" matTooltip="{{'DESCRIPTION-OVERVIEW.ACTIONS.DELETE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">delete</mat-icon>
</button>
</div>
<div class="row header">{{'DESCRIPTION-OVERVIEW.PART-OF' | translate}}</div>
<div class="row ">
<button class="dmp-btn" (click)="dmpClicked(description.dmp)">
<div class="dmp-btn-label">
{{ this.description.dmp.label }}
</div>
<mat-icon>launch</mat-icon>
</button>
</div>
<div *ngIf="description.grant">
<div class="row header">{{'DESCRIPTION-OVERVIEW.GRANT' | translate}}</div>
<div class="row description-label">{{referenceService.getReferencesForTypesFirstSafe(description?.dmp?.dmpReferences, [referenceTypeEnum.Grants])?.reference?.label}}</div>
</div>
<div class="row header">{{'DESCRIPTION-OVERVIEW.RESEARCHERS' | translate}}</div>
<div class="row">
<div *ngFor="let dmpReference of researchers let last = last">
<span *ngIf="isOrcid(dmpReference.reference)">
<a href="{{ getOrcidPathForResearcher(dmpReference.reference?.reference) }}" target="blank" class="researcher">
<div class="id-btn">&nbsp;</div>
<div *ngIf="!last">{{ dmpReference.reference?.data?.name }}, </div> <!-- TODO: data is missign after refactor -->
<div *ngIf="last">{{ dmpReference.reference?.data?.name }}</div><!-- TODO: data is missign after refactor -->
</a>
</span>
<span *ngIf="!isOrcid(dmpReference.reference)">
<div *ngIf="!last">{{ dmpReference.reference?.data?.name }}, </div> <!-- TODO: data is missign after refactor -->
<div *ngIf="last">{{ dmpReference.reference?.data?.name }}</div> <!-- TODO: data is missign after refactor -->
</span>
</div>
<span *ngIf="!researchers || researchers.length === 0" class="material-icons">horizontal_rule</span>
</div>
<div class="row header">{{'DESCRIPTION-OVERVIEW.DESCRIPTION' | translate}}</div>
<div class="row" *ngIf="description.description">
<p class="desc-txt" [innerHTML]="description.description"></p>
</div>
<div class="row" *ngIf="!description.description">
<span class="material-icons">horizontal_rule</span>
</div>
</div>
<div class="col-md-4 col-lg-4 p-0">
<div class="frame mb-3 pt-4 pl-3 pr-5 pb-1">
<div *ngIf="isDraftDescription(description) && !lockStatus">
<div class="row ml-0 mr-0 pl-4 d-flex align-items-center" (click)="finalize(description)">
<button mat-mini-fab class="finalize-btn">
<mat-icon class="mat-mini-fab-icon check-icon">check</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DESCRIPTION-OVERVIEW.ACTIONS.FINALIZE' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 d-flex align-items-center">
<hr class="hr-line">
</div>
</div>
<div *ngIf="hasReversableStatus(description)" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="reverse(description)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">unarchive</mat-icon>
</button>
<p class="mb-0 mr-0 pl-2 frame-txt">{{ 'DESCRIPTION-OVERVIEW.ACTIONS.REVERSE' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<button mat-mini-fab class="frame-btn" [matMenuTriggerFor]="exportMenu">
<mat-icon class="mat-mini-fab-icon">open_in_new</mat-icon>
</button>
<p class="mb-0 mr-0 pl-2 frame-txt" [matMenuTriggerFor]="exportMenu">
{{ 'DESCRIPTION-OVERVIEW.ACTIONS.EXPORT' | translate }}</p>
</div>
<mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(description.id)">
<i class="fa fa-file-pdf-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadDocx(description.id)">
<i class="fa fa-file-word-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span>
</button>
<button mat-menu-item (click)="downloadXml(description.id)">
<i class="fa fa-file-code-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
</button>
</mat-menu>
</div>
<div class="frame mb-3 pt-4 pl-3 pr-3 pb-1">
<div class="row ml-0 mr-0 pl-4 pb-3">
<p class="header">{{ 'DESCRIPTION-OVERVIEW.DESCRIPTION-AUTHORS' | translate }}</p>
</div>
<div class="row ml-0 mr-0 pl-4 ml-2 pb-3 d-flex align-items-center">
<div *ngFor="let dmpUser of description.dmp?.dmpUsers" class="row authors">
<div class="d-flex flex-row">
<button class="account_btn mr-3 pl-0">
<mat-icon class="account-icon">account_circle</mat-icon>
</button>
<div>
<p class="authors-label">{{ dmpUser.user?.name }}
<span *ngIf="isUserAuthor(dmpUser.user?.id)">
({{ 'DESCRIPTION-OVERVIEW.YOU' | translate }})</span>
</p>
<p class="authors-role">{{ enumUtils.toDmpUserRoleString(dmpUser.role) }}</p>
</div>
</div>
<button *ngIf="isUserOwner && !description.status && dmpUser.role" (click)="removeUserFromDmp(dmpUser)" class="remove-btn">{{ 'GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE' | translate}}</button>
</div>
</div>
<div *ngIf="isUserOwner" class="row mt-3 mb-3 d-flex align-items-center justify-content-center">
<button mat-raised-button class="invite-btn" (click)="openShareDialog(description.dmp.id, description.dmp.label)">
<mat-icon>group_add</mat-icon>
{{'DESCRIPTION-OVERVIEW.ACTIONS.INVITE-SHORT' | translate}}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -3,7 +3,7 @@
padding: 2em;
}
.dataset-overview {
.description-overview {
// margin-top: 5rem;
}
@ -41,6 +41,8 @@
.account-icon {
font-size: 2.5em;
height: auto;
width: auto;
}
// ********BUTTONS********
@ -126,7 +128,7 @@
// ********TEXT********
.dataset-logo {
.description-logo {
width: 6em;
height: 2.6em;
background: var(--secondary-color);
@ -151,7 +153,7 @@
font-weight: 400;
}
.dataset-label {
.description-label {
font-weight: bold;
width: auto;
}
@ -173,7 +175,7 @@
margin-bottom: 0.5em;
}
.dataset-label,
.description-label,
.header {
font-size: 1.25em;
color: #212121;
@ -279,7 +281,7 @@
.mat-mini-fab-icon,
.actions-btn,
.status-icon,
.dataset-logo,
.description-logo,
.frame-btn,
.finalize-btn {
display: flex;
@ -287,7 +289,7 @@
align-items: center;
}
.dataset-label,
.description-label,
.dmp-btn,
.doi-panel,
.researcher {

View File

@ -0,0 +1,459 @@
import { Component, OnInit } from '@angular/core';
import { BaseComponent } from '@common/base/base.component';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { Location } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { DmpAccessType } from '@app/core/common/enum/dmp-access-type';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
import { ReferenceType } from '@app/core/common/enum/reference-type';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { Description } from '@app/core/model/description/description';
import { Dmp, DmpUser } from '@app/core/model/dmp/dmp';
import { DmpReference, Reference } from '@app/core/model/reference/reference';
import { AuthService } from '@app/core/services/auth/auth.service';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { DescriptionService } from '@app/core/services/description/description.service';
import { DmpServiceNew } from '@app/core/services/dmp/dmp.service';
import { LockService } from '@app/core/services/lock/lock.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { ReferenceService } from '@app/core/services/reference/reference.service';
import { UserService } from '@app/core/services/user/user.service';
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
import { Oauth2DialogService } from '@app/ui/misc/oauth2-dialog/service/oauth2-dialog.service';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import { filter, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof';
import { DescriptionCopyDialogComponent } from '../description-copy-dialog/description-copy-dialog.component';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
@Component({
selector: 'app-description-overview',
templateUrl: './description-overview.component.html',
styleUrls: ['./description-overview.component.scss']
})
export class DescriptionOverviewComponent extends BaseComponent implements OnInit {
description: Description;
researchers: DmpReference[] = [];
isNew = true;
isFinalized = false;
isPublicView = true;
hasPublishButton: boolean = true;
// breadCrumbs: Observable<BreadcrumbItem[]> = observableOf();
isUserOwner: boolean;
expand = false;
lockStatus: Boolean;
descriptionStatusEnum = DescriptionStatus;
dmpAccessTypeEnum = DmpAccessType;
referenceTypeEnum = ReferenceType;
constructor(
private route: ActivatedRoute,
private router: Router,
private descriptionService: DescriptionService,
private translate: TranslateService,
private authentication: AuthService,
private dialog: MatDialog,
private language: TranslateService,
private uiNotificationService: UiNotificationService,
private configurationService: ConfigurationService,
private oauth2DialogService: Oauth2DialogService,
private userService: UserService,
private dmpService: DmpServiceNew,
public referenceService: ReferenceService,
private location: Location,
private lockService: LockService,
public enumUtils: EnumUtils,
private matomoService: MatomoService,
private fileUtils: FileUtils
) {
super();
}
ngOnInit() {
this.matomoService.trackPageView('Description Overview');
// Gets description data using parameter id
this.route.params
.pipe(takeUntil(this._destroyed))
.subscribe((params: Params) => {
const itemId = params['id'];
const publicId = params['publicId'];
if (itemId != null) {
this.isNew = false;
this.isPublicView = false;
this.descriptionService.getSingle(itemId, this.lookupFields())
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.description = data;
this.researchers = this.referenceService.getReferencesForTypes(this.description?.dmp?.dmpReferences, [ReferenceType.Researcher]);
// this.users = this.description.dmp.users;
this.checkLockStatus(this.description.id);
this.setIsUserOwner();
// const breadCrumbs = [];
// breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DESCRIPTION-DESCRIPTIONS'), url: "/descriptions" });
// breadCrumbs.push({ parentComponentName: 'DescriptionListingComponent', label: this.description.label, url: '/descriptions/overview/' + this.description.id });
// this.breadCrumbs = observableOf(breadCrumbs);
}, (error: any) => {
if (error.status === 404) {
return this.onFetchingDeletedCallbackError('/descriptions/');
}
if (error.status === 403) {
return this.onFetchingForbiddenCallbackError('/descriptions/');
}
});
}
else if (publicId != null) {
this.isNew = false;
this.isFinalized = true;
this.isPublicView = true;
this.descriptionService.getPublicSingle(publicId, this.lookupFields())
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.description = data;
this.researchers = this.referenceService.getReferencesForTypes(this.description?.dmp?.dmpReferences, [ReferenceType.Researcher]);
// this.users = this.description.dmp.users;
// const breadCrumbs = [];
// breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DESCRIPTIONS'), url: "/explore" });
// breadCrumbs.push({ parentComponentName: 'DescriptionListingComponent', label: this.description.label, url: '/descriptions/publicOverview/' + this.description.id });
// this.breadCrumbs = observableOf(breadCrumbs);
}, (error: any) => {
if (error.status === 404) {
return this.onFetchingDeletedCallbackError('/explore-descriptions');
}
if (error.status === 403) {
return this.onFetchingForbiddenCallbackError('/explore-descriptions');
}
});
}
});
}
checkLockStatus(id: Guid) {
// TODO: add this
// this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed))
// .subscribe(lockStatus => {
// this.lockStatus = lockStatus
// if (lockStatus) {
// this.dialog.open(PopupNotificationDialogComponent, {
// data: {
// title: this.language.instant('DESCRIPTION-OVERVIEW.LOCKED-DIALOG.TITLE'),
// message: this.language.instant('DESCRIPTION-OVERVIEW.LOCKED-DIALOG.MESSAGE')
// }, maxWidth: '30em'
// });
// }
// });
}
onFetchingDeletedCallbackError(redirectRoot: string) {
this.uiNotificationService.snackBarNotification(this.language.instant('DESCRIPTION-OVERVIEW.ERROR.DELETED-DESCRIPTION'), SnackBarNotificationLevel.Error);
this.router.navigate([redirectRoot]);
}
onFetchingForbiddenCallbackError(redirectRoot: string) {
this.uiNotificationService.snackBarNotification(this.language.instant('DESCRIPTION-OVERVIEW.ERROR.FORBIDEN-DESCRIPTION'), SnackBarNotificationLevel.Error);
this.router.navigate([redirectRoot]);
}
goBack(): void {
this.location.back();
}
reloadPage(): void {
const path = this.location.path();
this.router.navigateByUrl('/reload', { skipLocationChange: true }).then(() => this.router.navigate([path]));
}
setIsUserOwner() {
if (this.description) {
const principalId: Guid = this.authentication.userId();
if (principalId) this.isUserOwner = !!this.description.dmp.dmpUsers.find(x => (x.role === DmpUserRole.Owner) && (principalId === x.id));
}
}
isUserAuthor(userId: Guid): boolean {
if (this.isAuthenticated()) {
const principalId: Guid = this.authentication.userId();
return userId === principalId;
} else return false;
}
isUserDescriptionRelated(): boolean {
const principalId: Guid = this.authentication.userId();
return this.description.dmp.dmpUsers.some(x => (x.user.id === principalId));
}
openShareDialog(rowId: any, rowName: any) {
// TODO: add dialog
// const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
// autoFocus: false,
// restoreFocus: false,
// data: {
// dmpId: rowId,
// dmpName: rowName
// }
// });
}
public isAuthenticated(): boolean {
return this.authentication.currentAccountIsAuthenticated();
}
isDraftDescription(description: Description) {
return description.status == DescriptionStatus.Draft;
}
editClicked(description: Description) {
if (description.status === DescriptionStatus.Finalized && description.dmp.accessType === DmpAccessType.Public) {
this.router.navigate(['/descriptions/publicEdit/', description.id]);
} else {
this.router.navigate(['/descriptions/edit/', description.id]);
}
}
deleteClicked() {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
maxWidth: '300px',
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
isDeleteConfirmation: true
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
this.descriptionService.delete(this.description.id)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => {
this.onDeleteCallbackSuccess();
},
error => this.onDeleteCallbackError(error)
);
}
});
}
dmpClicked(dmp: Dmp) {
if (this.isPublicView) {
this.router.navigate(['/explore-plans/publicOverview/' + dmp.id]);
} else {
this.router.navigate(['/plans/overview/' + dmp.id]);
}
}
private onDeleteCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DELETE'), SnackBarNotificationLevel.Success);
this.router.navigate(['/descriptions']);
}
private onDeleteCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error);
}
private onUpdateCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
this.reloadPage();
}
private onUpdateCallbackError(error) {
this.uiNotificationService.snackBarNotification(error.error.message ? this.tryTranslate(error.error.message) : this.language.instant('DESCRIPTION-UPLOAD.SNACK-BAR.UNSUCCESSFUL'), SnackBarNotificationLevel.Error);
}
private tryTranslate(errorMessage: string): string {
return errorMessage.replace('Field value of', this.language.instant('Field value of'))
.replace('must be filled', this.language.instant('must be filled'));
}
public getOrcidPath(): string {
return this.configurationService.orcidPath;
}
isOrcid(reference: Reference) {
return reference.source === 'orcid';
}
getOrcidPathForResearcher(reference: string): string {
const path = this.getOrcidPath();
return path + reference;
}
downloadPDF(id: string) {
// TODO: add download
// this.descriptionService.downloadPDF(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/pdf' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('descriptions', "pdf", id);
// });
}
downloadDocx(id: string) {
// TODO: add download
// this.descriptionService.downloadDocx(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/msword' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('descriptions', "docx", id);
// });
}
downloadXml(id: string) {
// TODO: add download
// this.descriptionService.downloadXML(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/xml' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('descriptions', "xml", id);
// });
}
openCopyToDmpDialog() {
const formControl = new UntypedFormControl();
const dialogRef = this.dialog.open(DescriptionCopyDialogComponent, {
width: '500px',
restoreFocus: false,
data: {
formControl: formControl,
descriptionId: this.description.id,
descriptionProfileId: this.description.descriptionTemplate.id,
descriptionProfileExist: false,
confirmButton: this.language.instant('DESCRIPTION-OVERVIEW.COPY-DIALOG.COPY'),
cancelButton: this.language.instant('DESCRIPTION-OVERVIEW.COPY-DIALOG.CANCEL')
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed))
.subscribe(newDmpId => {
if (newDmpId) {
this.router.navigate(['/descriptions/copy/' + this.description.id], { queryParams: { newDmpId: newDmpId } });
// let url = this.router.createUrlTree(['/descriptions/copy/', result.descriptionId, { newDmpId: newDmpId }])
// window.open(url.toString(), '_blank')
}
});
}
removeUserFromDmp(dmpUser: DmpUser) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-USER'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
//TODO: implement remove user from backend
// const index = this.users.findIndex(x => x.id === user.id);
// if (index > -1) {
// this.users.splice(index, 1);
// }
// this.dmpService.updateUsers(this.description.dmp.id, this.users).pipe(takeUntil(this._destroyed))
// .subscribe(
// complete => {
// this.onUpdateCallbackSuccess();
// },
// error => this.onUpdateCallbackError(error)
// );
}
});
}
finalize(description: Description) {
this.dialog.open(ConfirmationDialogComponent, {
data: {
message: this.language.instant('DESCRIPTION-OVERVIEW.FINALISE-POPUP.MESSAGE'),
confirmButton: this.language.instant('DESCRIPTION-OVERVIEW.FINALISE-POPUP.CONFIRM'),
cancelButton: this.language.instant('DESCRIPTION-OVERVIEW.FINALISE-POPUP.CANCEL'),
},
maxWidth: '30em'
})
.afterClosed()
.pipe(
filter(x => x),
takeUntil(this._destroyed)
)
.subscribe(_ => {
this.router.navigate(['descriptions', 'edit', description.id, 'finalize']);
})
}
hasReversableStatus(description: Description): boolean {
return description.dmp.status == DmpStatus.Draft && description.status == DescriptionStatus.Finalized
}
reverse(description: Description) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
restoreFocus: false,
data: {
message: this.language.instant('DESCRIPTION-OVERVIEW.UNDO-FINALIZATION-DIALOG.TITLE'),
confirmButton: this.language.instant('DESCRIPTION-OVERVIEW.UNDO-FINALIZATION-DIALOG.CONFIRM'),
cancelButton: this.language.instant('DESCRIPTION-OVERVIEW.UNDO-FINALIZATION-DIALOG.CANCEL'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
// TODO: implement endpoint to undo finalization to a Description and set it to Draft again
// this.descriptionWizardService.getSingle(description.id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(data => {
// this.description = data;
// this.description.status = DescriptionStatus.Draft;
// this.descriptionWizardService.createDescription(this.description)
// .pipe(takeUntil(this._destroyed))
// .subscribe(
// data => this.onUpdateCallbackSuccess(),
// error => this.onUpdateCallbackError(error)
// );
// });
}
});
}
private lookupFields(): string[] {
return [
nameof<Description>(x => x.id),
nameof<Description>(x => x.label),
nameof<Description>(x => x.status),
nameof<Description>(x => x.updatedAt),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.label)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.accessType)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.name)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.label)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.type)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.source)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.reference)].join('.'),
]
}
}

View File

@ -1,12 +1,12 @@
import { NgModule } from '@angular/core';
import { FormattingModule } from '@app/core/formatting.module';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module';
import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { DatasetOverviewComponent } from './dataset-overview.component';
import { DescriptionOverviewComponent } from './description-overview.component';
@NgModule({
imports: [
@ -19,7 +19,7 @@ import { DatasetOverviewComponent } from './dataset-overview.component';
AutoCompleteModule
],
declarations: [
DatasetOverviewComponent
DescriptionOverviewComponent
]
})
export class DatasetOverviewModule { }
export class DescriptionOverviewModule { }

View File

@ -35,7 +35,6 @@ import { ReferenceService } from '@app/core/services/reference/reference.service
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component';
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component';
import { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { FormService } from '@common/forms/form-service';
import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
@ -401,8 +400,9 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im
grantControl = new GrantTabModel();
grantControl.fromModel(this.formGroup.get('grant').get('existGrant').value);
} else {
grantControl = new GrantEditorModel();
grantControl.fromModel(this.formGroup.get('grant').value);
// TODO: Commented in refactor
//grantControl = new GrantEditorModel();
//grantControl.fromModel(this.formGroup.get('grant').value);
}
grantControl.buildForm()

View File

@ -24,66 +24,54 @@ const routes: Routes = [
breadcrumb: true
},
},
// Uncomment to get dmp plans for grant with grantId
{
path: 'grant/:grantId',
component: DmpListingComponent,
data: {
breadcrumb: true
},
},
{
path: 'edit/:id',
component: DmpEditorBlueprintComponent,
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DMP-EDIT'
},
canDeactivate: [CanDeactivateGuard]
},
{
path: 'publicEdit/:publicId',
component: DmpEditorComponent,
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DMP-PUBLIC-EDIT'
},
canDeactivate: [CanDeactivateGuard]
},
{
path: 'overview/:id',
component: DmpOverviewComponent,
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DMP-OVERVIEW'
},
},
{
path: 'publicOverview/:publicId',
component: DmpOverviewComponent,
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DMP-OVERVIEW'
},
},
// ----------- UNCOMMENT TO ADD AGAIN GRANTS --------
// {
// path: 'new/grant/:grantId',
// path: 'edit/:id',
// component: DmpEditorBlueprintComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DMP-EDIT'
// },
// canDeactivate: [CanDeactivateGuard]
// },
// {
// path: 'publicEdit/:publicId',
// component: DmpEditorComponent,
// data: {
// breadcrumbs: 'new'
// }
// breadcrumb: true,
// title: 'GENERAL.TITLES.DMP-PUBLIC-EDIT'
// },
// canDeactivate: [CanDeactivateGuard]
// },
// {
// path: 'overview/:id',
// component: DmpOverviewComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DMP-OVERVIEW'
// },
// },
// {
// path: 'publicOverview/:publicId',
// component: DmpOverviewComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.DMP-OVERVIEW'
// },
// },
// {
// path: 'new',
// component: DmpEditorBlueprintComponent,
// canActivate: [AuthGuard],
// data: {
// breadcrumbs: 'new',
// title: 'GENERAL.TITLES.DMP-NEW'
// },
// canDeactivate: [CanDeactivateGuard]
// },
{
path: 'new',
component: DmpEditorBlueprintComponent,
canActivate: [AuthGuard],
data: {
breadcrumbs: 'new',
title: 'GENERAL.TITLES.DMP-NEW'
},
canDeactivate: [CanDeactivateGuard]
},
// {
// path: 'new/dataset',
// component: DmpEditorComponent,
@ -102,32 +90,32 @@ const routes: Routes = [
// title: 'GENERAL.TITLES.DATASET-NEW'
// }
// },
{
path: 'new_version/:id',
// component: DmpWizardComponent,
component: DmpCloneComponent,
data: {
clone: false,
breadcrumb: true,
title: 'GENERAL.TITLES.DMP-NEW-VERSION'
},
},
{
path: 'clone/:id',
component: DmpCloneComponent,
data: {
clone: false,
breadcrumb: true,
title: 'GENERAL.TITLES.DMP-CLONE'
},
},
{
path: 'invitation/:id',
component: InvitationAcceptedComponent,
data: {
breadcrumb: true
},
}
// {
// path: 'new_version/:id',
// // component: DmpWizardComponent,
// component: DmpCloneComponent,
// data: {
// clone: false,
// breadcrumb: true,
// title: 'GENERAL.TITLES.DMP-NEW-VERSION'
// },
// },
// {
// path: 'clone/:id',
// component: DmpCloneComponent,
// data: {
// clone: false,
// breadcrumb: true,
// title: 'GENERAL.TITLES.DMP-CLONE'
// },
// },
// {
// path: 'invitation/:id',
// component: InvitationAcceptedComponent,
// data: {
// breadcrumb: true
// },
// }
];
@NgModule({

View File

@ -29,7 +29,6 @@ import { DmpFinalizeDialogComponent, DmpFinalizeDialogInput } from '@app/ui/dmp/
import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model';
import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model';
import { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model';
// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { DmpBlueprint, DmpBlueprintDefinition } from '@app/core/model/dmp-blueprint/dmp-blueprint';
@ -1071,8 +1070,9 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements
grantControl = new GrantTabModel();
grantControl.fromModel(this.formGroup.get('grant').get('existGrant').value);
} else {
grantControl = new GrantEditorModel();
grantControl.fromModel(this.formGroup.get('grant').value);
// TODO: Commented in refactor
// grantControl = new GrantEditorModel();
// grantControl.fromModel(this.formGroup.get('grant').value);
}
grantControl.buildForm()

View File

@ -2,8 +2,6 @@
<div class="container-fluid">
<div class="d-flex flex-direction-row">
<div *ngIf="hasListingItems && listingItems && listingItems.length === 0 && !hasLikeCriteria()" class="card mt-0">
<!-- <div *ngIf="listingItems && listingItems.length === 0" 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 class="card-content info-text mb-0">
<p>{{'DMP-LISTING.TEXT-INFO' | translate}}</p>
<p class="mt-4 pt-2">{{'DMP-LISTING.TEXT-INFO-QUESTION' | translate}} <a class="zenodo-link" href="https://zenodo.org/communities/liber-dmp-cat/?page=1&size=20" target="_blank">{{'DMP-LISTING.LINK-ZENODO' | translate}}</a> {{'DMP-LISTING.GET-IDEA' | translate}}</p>
@ -13,7 +11,7 @@
</div>
</div>
</div>
<p *ngIf="listingItems && listingItems.length > 0 || this.criteria.like" class="col-auto header-title">{{(isPublic ? 'GENERAL.TITLES.EXPLORE-PLANS' : 'GENERAL.TITLES.PLANS') | translate}}</p>
<p *ngIf="listingItems && listingItems.length > 0 || this.lookup.like" class="col-auto header-title">{{(isPublic ? 'GENERAL.TITLES.EXPLORE-PLANS' : 'GENERAL.TITLES.PLANS') | translate}}</p>
<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>
@ -22,7 +20,7 @@
</div>
<div>
<div class="listing row pb-2">
<div *ngIf="listingItems && listingItems.length > 0 || this.criteria.like" class="col-md-12">
<div *ngIf="listingItems && listingItems.length > 0 || this.lookup.like" class="col-md-12">
<div class="d-flex flex-direction-row pt-4">
<!-- Sort by -->
<span class="d-flex align-items-center">{{'DMP-LISTING.SORT-BY' | translate}}:</span>
@ -32,16 +30,10 @@
<mat-option *ngIf="isPublic" [value]="order.PUBLISHED">{{enumUtils.toRecentActivityOrderString(order.PUBLISHED)}}</mat-option>
<mat-option [value]="order.LABEL">{{enumUtils.toRecentActivityOrderString(order.LABEL)}}</mat-option>
<mat-option *ngIf="!isPublic" [value]="order.STATUS">{{enumUtils.toRecentActivityOrderString(order.STATUS)}}</mat-option>
<!-- <mat-option [value]="order.CREATED">{{enumUtils.toRecentActivityOrderString(order.CREATED)}}</mat-option> -->
</mat-select>
</mat-form-field>
<!-- End of Sort by -->
<div class="d-flex flex-row ml-auto">
<!-- Guided Tour -->
<!-- <div class="center-content" [style.display]="!isVisible && isAuthenticated()? 'block' : 'none'" (click)="restartTour()"> -->
<div *ngIf="!isPublic" class="center-content" (click)="restartTour()">{{ 'GENERAL.ACTIONS.TAKE-A-TOUR'| translate }}</div>
<!-- End of Guided Tour -->
<!-- Search Filter-->
<mat-form-field class="search-form ml-auto col-auto pr-0"
floatLabel="never">
<mat-icon matSuffix>search</mat-icon>
@ -50,7 +42,6 @@
<mat-error *ngIf="formGroup.get('like').hasError('backendError')">
{{formGroup.get('like').getError('backendError').message}}</mat-error>
</mat-form-field>
<!-- End of Search Filter -->
</div>
</div>
</div>
@ -58,155 +49,14 @@
<div *ngFor="let item of listingItems; let i = index">
<app-dmp-listing-item-component [showDivider]="i != (listingItems.length - 1)" [dmp]="item" [isPublic]="isPublic"></app-dmp-listing-item-component>
</div>
<div *ngIf="listingItems && listingItems.length > 0 && this.startIndex < this.totalCount - 1 && this.pageSize < this.totalCount - 1" class="d-flex justify-content-center">
<div *ngIf="listingItems && listingItems.length > 0 && 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()">{{'GENERAL.ACTIONS.LOAD-MORE' | translate}}</button>
</div>
</div>
<div *ngIf="hasListingItems && listingItems && listingItems.length === 0 && this.criteria.like !== ''" class="col-md-12 d-flex justify-content-center pt-4 mt-4 mb-4 pb-4">
<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">
<span class="empty-list">{{'DMP-LISTING.EMPTY-LIST' | translate}}</span>
</div>
</div>
</div>
</div>
</div>
<!-- Version 1 -->
<!-- <div class="header-image" *ngIf="isPublic">
<div class="header-text-container">
<h3>{{ 'ABOUT.WELCOME' | translate }}</h3>
<h4>{{ 'ABOUT.WELCOME-MESSAGE' | translate }}</h4>
</div>
</div>
<div [ngClass]="isPublic ? 'explore-dmp-content' : 'main-content'">
<div class="container-fluid">
<div class="card">
<div class="row card-header card-header-plain d-flex">
<div class="card-desc d-flex flex-column justify-content-center">
<h4 class="card-title">{{'DMP-LISTING.TITLE' | translate}} {{titlePrefix}}</h4>
<div *ngIf="allVersions">
<span class="all-versions">
{{'DMP-LISTING.VIEW-ALL-VERSIONS' | translate}}
</span>
<span class="dmp-label">
{{this.groupLabel}}
</span>
</div>
</div>
<div class="row ml-auto p-2" *ngIf="!isPublic">
<button mat-icon-button [matMenuTriggerFor]="actionsMenu" class="ml-auto more-icon" (click)="$event.stopImmediatePropagation();">
<mat-icon class="more-horiz">more_horiz</mat-icon>
</button>
<mat-menu #actionsMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="fileSave($event)">
<mat-icon>cloud_upload</mat-icon> {{'DMP-UPLOAD.ACTIONS.IMPORT' | translate}}
</button>
</mat-menu>
<button mat-raised-button color="primary" class="text-uppercase lightblue-btn m-1" [routerLink]="['./new']">
<mat-icon>add</mat-icon> {{'DMP-LISTING.ACTIONS.NEW' | translate}}
</button>
<button mat-raised-button color="primary" class="text-uppercase lightblue-btn m-1" [routerLink]="['/quick-wizard']">
<mat-icon>play_circle_outline</mat-icon> {{'DMP-LISTING.ACTIONS.NEW-WITH-WIZARD' | translate}}
</button>
</div>
</div>
<div class="card-body table-responsive">
<div class="listing row pb-2">
<div class="col-12 col-sm-12 col-md-3">
<app-dmp-criteria-component [showGrant]="showGrant" [isPublic]="isPublic" class="col-auto"></app-dmp-criteria-component>
</div>
<div class="col-12 col-sm-12 col-md-9 pt-4">
<div *ngFor="let item of listingItems; let i = index">
<app-dmp-listing-item-component [showDivider]="i != (listingItems.length - 1)" [dmp]="item" [isPublic]="isPublic"></app-dmp-listing-item-component>
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-sm-12 col-md-9 ml-auto paginator">
<mat-paginator #paginator [length]="totalCount" [pageSizeOptions]="[10, 25, 100]" (page)="pageThisEvent($event)" class="mt-2"></mat-paginator>
</div>
</div>
</div>
</div>
</div>
</div> -->
<!-- Version 0 -->
<!-- <mat-table [dataSource]="dataSource" matSort (matSortChange)="refresh()">
<ng-container cdkColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header="label">{{'DMP-LISTING.COLUMNS.NAME' | translate}}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.label}}</mat-cell>
</ng-container>
<ng-container cdkColumnDef="grant">
<mat-header-cell *matHeaderCellDef mat-sort-header="|join|grant:label">{{'DMP-LISTING.COLUMNS.GRANT' |
translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.grant}} </mat-cell>
</ng-container>
<ng-container cdkColumnDef="status">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.STATUS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{enumUtils.toDmpStatusString(row.status)}} </mat-cell>
</ng-container>
<ng-container cdkColumnDef="creationTime">
<mat-header-cell *matHeaderCellDef mat-sort-header="created">
{{'DMP-LISTING.COLUMNS.CREATION-TIME' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.creationTime | date:'shortDate'}} </mat-cell>
</ng-container>
<ng-container cdkColumnDef="organisations">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.ORGANISATIONS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.organisations}} </mat-cell>
</ng-container>
<ng-container cdkColumnDef="version">
<mat-header-cell *matHeaderCellDef mat-sort-header="version">
{{'DMP-LISTING.COLUMNS.LATEST_VERSION' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">
{{row.version}}
</mat-cell>
</ng-container>
<ng-container cdkColumnDef="datasets">
<mat-header-cell *matHeaderCellDef mat-sort-header="|count|dataset">
{{'DMP-LISTING.COLUMNS.DATASETS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row" (click)="$event.stopPropagation()">
<app-url-listing [items]="row.datasets" [urlLimit]="5" [parameters]="{ datasetLabel: row.label }">
</app-url-listing>
</mat-cell>
</ng-container>
<ng-container cdkColumnDef="actions">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.ACTIONS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row" (click)="$event.stopPropagation()">
<mat-menu #actionsMenu="matMenu">
<button mat-menu-item (click)="openShareDialog(row.id,row.label)">
<mat-icon>share</mat-icon>{{'DMP-LISTING.ACTIONS.INVITE' | translate}}
</button>
<button mat-menu-item (click)="addDataset(row.id)">
<mat-icon>add</mat-icon>{{'DMP-LISTING.ACTIONS.ADD-DATASET' | translate}}
</button>
<button mat-menu-item (click)="showDatasets(row.id, row.label)">
<mat-icon>list</mat-icon>{{'DMP-LISTING.ACTIONS.DATASETS' | translate}}
</button>
<button mat-menu-item (click)="viewVersions(row.groupId, row.label)">
<mat-icon>library_books</mat-icon>{{'DMP-LISTING.ACTIONS.VIEW-VERSION' | translate}}
</button>
</mat-menu>
<button mat-icon-button [matMenuTriggerFor]="actionsMenu">
<mat-icon>more_vert</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns" (click)="rowClick(row.id);"></mat-row>
</mat-table>
<mat-paginator #paginator [length]="dataSource?.totalCount" [pageSizeOptions]="[10, 25, 100]">
</mat-paginator> -->

View File

@ -1,38 +1,32 @@
import { HttpClient } from '@angular/common/http';
import { Component, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { UntypedFormBuilder, UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { ActivatedRoute, Router } from '@angular/router';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { GrantListingModel } from '@app/core/model/grant/grant-listing';
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
import { AuthService } from '@app/core/services/auth/auth.service';
import { DmpService, DmpServiceNew } from '@app/core/services/dmp/dmp.service';
import { GrantService } from "@app/core/services/grant/grant.service";
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.constants';
import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { DmpCriteriaComponent } from '@app/ui/dmp/listing/criteria/dmp-criteria.component';
// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { Dmp, DmpUser } from '@app/core/model/dmp/dmp';
import { DmpLookup } from '@app/core/query/dmp.lookup';
import { BaseComponent } from '@common/base/base.component';
import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import { NgDialogAnimationService } from "ng-dialog-animation";
import { Observable, of as observableOf } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { DmpCriteriaDialogComponent } from './criteria/dmp-criteria-dialog.component';
import { DmpUploadDialogue } from './upload-dialogue/dmp-upload-dialogue.component';
import { DmpLookup } from '@app/core/query/dmp.lookup';
import { Dmp } from '@app/core/model/dmp/dmp';
import { nameof } from 'ts-simple-nameof';
import { Description } from '@app/core/model/description/description';
@Component({
selector: 'app-dmp-listing-component',
@ -46,23 +40,27 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
// @ViewChild(DmpCriteriaComponent, { static: true }) criteria: DmpCriteriaComponent;
// breadCrumbs: Observable<BreadcrumbItem[]> = observableOf([{ parentComponentName: null, label: 'DMPs', url: "/plans" }]);
itemId: string;
grantId: string;
showGrant: boolean;
titlePrefix: string;
lookup: DmpLookup = new DmpLookup();
groupId: string;
// itemId: string;
// showGrant: boolean;
// titlePrefix: string;
totalCount: number;
listingItems: Dmp[] = [];
allVersions: boolean = false;
groupLabel: string;
// allVersions: boolean = false;
// groupLabel: string;
isPublic: boolean = false;
public isVisible = true
// public isVisible = true
hasListingItems = null;
startIndex: number = 0;
// startIndex: number = 0;
pageSize: number = 5;
criteria: DmpCriteria;
criteriaFormGroup: UntypedFormGroup;
// criteria: DmpCriteria;
// criteriaFormGroup: UntypedFormGroup;
public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(),
order: new UntypedFormControl()
@ -70,8 +68,8 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
scrollbar: boolean;
order = RecentActivityOrder;
dmpText: string;
datasetText: string;
// dmpText: string;
// datasetText: string;
constructor(
private dmpService: DmpService,
@ -106,82 +104,19 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
this.route.params
.pipe(takeUntil(this._destroyed))
.subscribe(async params => {
let grantLabel;
if (params['grantId']) {
this.grantId = params['grantId'];
this.showGrant = true;
this.grantService.getSingle(this.grantId)
.subscribe((grant: GrantListingModel) => {
// const grant: GrantListingModel = {
// id: this.grantId
// }
// this.breadCrumbs = Observable.of([{ parentComponentName: 'GrantEditorComponent', label: grantLabel, url: '/grants/edit/' + this.grantId }]);
grantLabel = this.route.snapshot.queryParams.grantLabel;
this.criteria = { like: null, grants: [grant], groupIds: null, allVersions: false }
// this.criteria.setCriteria({ like: null, grants: [grant], groupIds: null, allVersions: false });
this.groupId = params['groupId'];
this.refresh();
// this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages));
})
this.lookup.page = { size: this.pageSize, offset: 0 };
this.lookup.order = { items: ['-' + nameof<Dmp>(x => x.updatedAt)] };
this.lookup.metadata = { countAll: true };
this.lookup.isActive = [IsActive.Active];
} else if (params['groupId']) {
this.itemId = params['groupId'];
this.showGrant = true;
this.allVersions = true;
this.language.get('NAV-BAR.MY-DMPS').pipe(takeUntil(this._destroyed)).subscribe(x => {
// this.breadCrumbs = observableOf([
// {
// parentComponentName: null,
// label: x,
// url: '/plans'
// }]
// );
})
this.groupLabel = this.route.snapshot.queryParams.groupLabel;
// this.criteria.setCriteria(this.getDefaultCriteria());
this.criteria = this.getDefaultCriteria();
this.criteria.groupIds ? this.criteria.groupIds.push(this.itemId) : this.criteria.groupIds = [this.itemId];
this.refresh();
// this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages));
} else {
this.itemId = params['groupId'];
this.showGrant = true;
const breadCrumbs = [];
// if (this.itemId) {
// const dmplabel = this.route.snapshot.queryParams.groupLabel;
// breadCrumbs.push({
// parentComponentName: null,
// label: this.language.instant('NAV-BAR.DMPS'),
// url: '/plans'
// });
// }
// else
this.language.get('NAV-BAR.MY-DMPS').pipe(takeUntil(this._destroyed)).subscribe(x => {
// this.breadCrumbs = observableOf([
// {
// parentComponentName: null,
// label: x,
// url: '/plans'
// }]
// );
})
// this.criteria.setCriteria(this.getDefaultCriteria());
this.criteria = this.getDefaultCriteria();
this.refresh();
// this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages));
}
if (this.grantId != null) {
if (grantLabel !== undefined) {
this.titlePrefix = 'for ' + grantLabel;
}
if (this.groupId != null && Guid.isGuid(this.groupId)) {
// this.lookup.groupIds = [this.groupId]; //TODO: add filter in backend
}
this.refresh(this.lookup);
});
this.formGroup.get('like').valueChanges
@ -189,7 +124,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
.subscribe(x => this.controlModified());
this.formGroup.get('order').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => this.refresh());
.subscribe(x => this.refresh(this.lookup));
}
public dashboardTour: GuidedTour = {
@ -235,336 +170,160 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
});
}
public refresh(resetPages = false) {
const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
this.startIndex = 0;
loadMore() {
this.lookup.page = { size: this.pageSize, offset: this.lookup.page.offset + this.pageSize };
this.refresh(this.lookup);
}
const request = new DataTableRequest<DmpCriteria>(this.startIndex, this.pageSize, { fields: fields });
this.setPublicCriteria();
request.criteria = this.criteria;
let lookup: DmpLookup = new DmpLookup();
private refresh(lookup: DmpLookup) {
lookup.project = {
fields: [
nameof<Dmp>(x => x.id),
nameof<Dmp>(x => x.label),
nameof<Dmp>(x => x.status),
nameof<Dmp>(x => x.accessType),
nameof<Dmp>(x => x.version),
nameof<Dmp>(x => x.groupId),
nameof<Dmp>(x => x.updatedAt),
[nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.id)].join('.'),
[nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.label)].join('.'),
// [nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
// [nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.id)].join('.'),
// [nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.label)].join('.'),
// [nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.accessType)].join('.'),
[nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'),
[nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'),
[nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.role)].join('.'),
// [nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.id)].join('.'),
// [nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.id)].join('.'),
// [nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.label)].join('.'),
// [nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.type)].join('.'),
// [nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.reference)].join('.'),
]
};
this.dmpServiceNew.query(lookup).pipe(takeUntil(this._destroyed))
.subscribe(result => {
if (!result) { return; }
// result.data.map(item => {
// item['datasets'].map(dmp => {
// dmp.url = 'datasets/edit/' + dmp.url;
// dmp.all = 'datasets/dmp/' + item.id;
// return dmp;
// });
// return item;
// });
this.listingItems = result.items;
this.hasListingItems = true;
if (!this.isPublic && this.listingItems.length === 0 && !this.hasCriteria() && !this.hasLikeCriteria()) {
this.openTour();
}
if (!result) { return []; }
this.totalCount = result.count;
if (lookup?.page?.offset === 0) this.listingItems = [];
this.listingItems.push(...result.items);
this.hasListingItems = true;
});
// const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
// this.startIndex = 0;
// const request = new DataTableRequest<DmpCriteria>(this.startIndex, this.pageSize, { fields: fields });
// this.setPublicCriteria();
// request.criteria = this.criteria;
// this.dmpService
// this.dmpService.getPaged(request, "listing").pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (!result) { return []; }
// result.data.map(item => {
// item['datasets'].map(dmp => {
// dmp.url = 'datasets/edit/' + dmp.url;
// dmp.all = 'datasets/dmp/' + item.id;
// return dmp;
// });
// return item;
// });
// this.listingItems = result.data;
// this.hasListingItems = true;
// if (!this.isPublic && this.listingItems.length === 0 && !this.hasCriteria() && !this.hasLikeCriteria()) {
// this.openTour();
// }
// this.totalCount = result.totalCount;
// });
}
public loadMore() {
// this.startIndex = this.startIndex + this.pageSize;
// // const fields: Array<string> = ["-modified"];
// const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
// const request = new DataTableRequest<DmpCriteria>(this.startIndex, this.pageSize, { fields: fields });
// this.setPublicCriteria();
// request.criteria = this.criteria;
// this.dmpService.getPaged(request, "listing").pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (!result) { return []; }
// result.data.map(item => {
// item['datasets'].map(dmp => {
// dmp.url = 'datasets/edit/' + dmp.url;
// dmp.all = 'datasets/dmp/' + item.id;
// return dmp;
// });
// return item;
// });
// // this.listingItems = this.listingItems.concat(result.data);
// this.listingItems = this.mergeTwoSortedLists(this.listingItems, result.data, this.formGroup.get('order').value);
// this.hasListingItems = true;
// });
}
pageThisEvent(event) {
this.refresh();
}
hasCriteria(): boolean {
if (this.criteria.organisations && this.criteria.organisations.length > 0 ||
this.criteria.grants && this.criteria.grants.length > 0 ||
this.criteria.collaborators && this.criteria.collaborators.length > 0 ||
this.criteria.datasetTemplates && this.criteria.datasetTemplates.length > 0 ||
this.criteria.onlyPublic === true
) { return true; } else { return false; }
}
controlModified(): void {
// this.clearErrorModel();
// 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));
// }
this.criteria.like = this.formGroup.get("like").value;
this.startIndex = 0;
this.refresh();
this.lookup.like = this.formGroup.get("like").value;
this.lookup.page = { size: this.pageSize, offset: 0 };
this.refresh(this.lookup);
}
// rowClicked(dmp: Dmp) {
// this.router.navigate(['/plans/overview/' + dmp.id]);
// }
public closeCard(): void {
this.isVisible = false;
}
// addDataset(rowId: String) {
// this.router.navigate(['/datasets/new/' + rowId]);
// }
showDatasets(rowId: String, rowLabel: String) {
this.router.navigate(['/datasets/dmp/' + rowId, { dmpLabel: rowLabel }]);
}
viewVersions(rowId: String, rowLabel: String) {
this.router.navigate(['/plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } });
}
getDefaultCriteria(): DmpCriteria {
const defaultCriteria = new DmpCriteria();
if (this.isPublic) {
defaultCriteria.isPublic = true;
defaultCriteria.onlyPublic = true;
}
if (this.allVersions) {
defaultCriteria.allVersions = true;
}
return defaultCriteria;
}
openShareDialog(rowId: any, rowName: any) {
const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
autoFocus: false,
data: {
dmpId: rowId,
dmpName: rowName
}
});
}
fileSave(event) {
const dialogRef = this.dialog.open(DmpUploadDialogue, {
data: {
fileList: FileList,
success: Boolean,
dmpTitle: String
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result && result.success) {
this.dmpService.uploadXml(result.fileList[0], result.dmpTitle, result.dmpBlueprints)
.pipe(takeUntil(this._destroyed))
.subscribe((complete) => this.onCallbackImportComplete(),
(error) => this.onCallbackImportFail(error.error));
}
});
}
private onCallbackImportComplete() {
this.uiNotificationService.snackBarNotification(this.language.instant('DMP-UPLOAD.UPLOAD-SUCCESS'), SnackBarNotificationLevel.Success);
this.router.navigate(['/reload']).then(() => this.isPublic ? this.router.navigate(['/explore-plans']) : this.router.navigate(['/plans']));
}
private onCallbackImportFail(error: any) {
this.uiNotificationService.snackBarNotification(error.message, SnackBarNotificationLevel.Error);
//TODO: add this
// const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
// autoFocus: false,
// data: {
// dmpId: rowId,
// dmpName: rowName
// }
// });
}
openFiltersDialog(): void {
const dialogRef = this.dialog.open(DmpCriteriaDialogComponent, {
width: '456px',
height: '100%',
id: 'filters',
restoreFocus: false,
data: {
showGrant: this.showGrant,
isPublic: this.isPublic,
criteria: this.criteria,
formGroup: this.criteriaFormGroup,
// criteria: this.grantId ? this.criteria : this.getDefaultCriteria(),
updateDataFn: this.updateDataFn.bind(this)
},
position: { right: '0px;' },
panelClass: 'dialog-side-panel',
// may remove NgDialogAnimationService package
// animation: {
// to: "left",
// incomingOptions: {
// keyframeAnimationOptions: { duration: 300, easing: "ease-in-out" }
//TODO: Add filters dialog
// const dialogRef = this.dialog.open(DmpCriteriaDialogComponent, {
// width: '456px',
// height: '100%',
// id: 'filters',
// restoreFocus: false,
// data: {
// showGrant: this.showGrant,
// isPublic: this.isPublic,
// criteria: this.criteria,
// formGroup: this.criteriaFormGroup,
// // criteria: this.grantId ? this.criteria : this.getDefaultCriteria(),
// updateDataFn: this.updateDataFn.bind(this)
// },
// position: { right: '0px;' },
// panelClass: 'dialog-side-panel',
// // may remove NgDialogAnimationService package
// // animation: {
// // to: "left",
// // incomingOptions: {
// // keyframeAnimationOptions: { duration: 300, easing: "ease-in-out" }
// // }
// // }
// });
// dialogRef.afterClosed().subscribe(result => {
// });
}
// updateDataFn(criteria: DmpCriteriaComponent): void {
// this.criteriaFormGroup = criteria.formGroup;
// this.toDmpCriteria(criteria);
// this.refresh();
// }
// toDmpCriteria(criteria: DmpCriteriaComponent): void {
// let formGroup = criteria.formGroup;
// this.criteria = {
// like: formGroup.get('like').value,
// grants: formGroup.get('grants').value,
// role: formGroup.get('role').value
// }
// this.criteria.status = formGroup.get('status').value;
// this.setPublicCriteria(formGroup);
// if (formGroup.get('datasetTemplates').value)
// this.criteria.datasetTemplates = formGroup.get('datasetTemplates').value.map(x => x.id);
// if (formGroup.get('collaborators').value)
// this.criteria.collaborators = formGroup.get('collaborators').value.map(x => x.id);
// if (formGroup.get('organisations').value)
// this.criteria.organisations = formGroup.get('organisations').value.map(x => x.id);
// if (this.itemId) {
// this.criteria.groupIds = [this.itemId];
// this.criteria.allVersions = true;
// }
// this.criteria.grantStatus = formGroup.get('grantStatus').value;
// }
});
dialogRef.afterClosed().subscribe(result => {
});
}
updateDataFn(criteria: DmpCriteriaComponent): void {
this.criteriaFormGroup = criteria.formGroup;
this.toDmpCriteria(criteria);
this.refresh();
}
toDmpCriteria(criteria: DmpCriteriaComponent): void {
let formGroup = criteria.formGroup;
this.criteria = {
like: formGroup.get('like').value,
grants: formGroup.get('grants').value,
role: formGroup.get('role').value
}
this.criteria.status = formGroup.get('status').value;
this.setPublicCriteria(formGroup);
if (formGroup.get('datasetTemplates').value)
this.criteria.datasetTemplates = formGroup.get('datasetTemplates').value.map(x => x.id);
if (formGroup.get('collaborators').value)
this.criteria.collaborators = formGroup.get('collaborators').value.map(x => x.id);
if (formGroup.get('organisations').value)
this.criteria.organisations = formGroup.get('organisations').value.map(x => x.id);
if (this.itemId) {
this.criteria.groupIds = [this.itemId];
this.criteria.allVersions = true;
}
this.criteria.grantStatus = formGroup.get('grantStatus').value;
}
setPublicCriteria(formGroup?: UntypedFormGroup): void {
if (!isNullOrUndefined(formGroup)) {
if (formGroup.get('status').value == 2) {
this.criteria.status = 1;
this.criteria.isPublic = true;
} else {
this.criteria.isPublic = false;
}
}
this.criteria.onlyPublic = this.isPublic;
if (this.isPublic) {
this.criteria.isPublic = true;
}
// setPublicCriteria(formGroup?: UntypedFormGroup): void {
// if (!isNullOrUndefined(formGroup)) {
// if (formGroup.get('status').value == 2) {
// this.criteria.status = 1;
// this.criteria.isPublic = true;
// } else {
// this.criteria.isPublic = false;
// }
}
// }
// this.criteria.onlyPublic = this.isPublic;
// if (this.isPublic) {
// this.criteria.isPublic = true;
// }
// // } else {
// // this.criteria.isPublic = false;
// // }
// }
hasScrollbar(): boolean {
return document.getElementById("main-page").scrollHeight > document.documentElement.clientHeight
}
// private mergeTwoSortedLists(arr1: Dmp[], arr2: Dmp[], order: string): Dmp[] {
// let merged = [];
// let index1 = 0;
// let index2 = 0;
// let current = 0;
// while (current < (arr1.length + arr2.length)) {
// let isArr1Depleted = index1 >= arr1.length;
// let isArr2Depleted = index2 >= arr2.length;
// if (order === 'modified') {
// if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].modifiedTime) > new Date(arr2[index2].modifiedTime)))) {
// merged[current] = arr1[index1];
// index1++;
// } else {
// merged[current] = arr2[index2];
// index2++;
// }
// } else if (order === 'created') {
// if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].creationTime) > new Date(arr2[index2].creationTime)))) {
// merged[current] = arr1[index1];
// index1++;
// } else {
// merged[current] = arr2[index2];
// index2++;
// }
// } else if (order === 'label') {
// if (!isArr1Depleted && (isArr2Depleted || (arr1[index1].label.localeCompare(arr2[index2].label)))) {
// merged[current] = arr1[index1];
// index1++;
// } else {
// merged[current] = arr2[index2];
// index2++;
// }
// } else if (order === 'status') {
// if (!isArr1Depleted && (isArr2Depleted || (arr1[index1].status < arr2[index2].status))) {
// merged[current] = arr1[index1];
// index1++;
// } else {
// merged[current] = arr2[index2];
// index2++;
// }
// } else if (order === "publishedAt") {
// if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].publishedAt) > new Date(arr2[index2].publishedAt)))) {
// merged[current] = arr1[index1];
// index1++;
// } else {
// merged[current] = arr2[index2];
// index2++;
// }
// }
// current++;
// }
// return merged;
// }
public setDashboardTourDmpText(): void {
this.dmpText = this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' +
const dmpText = this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' +
this.language.instant('DMP-LISTING.TEXT-INFO-QUESTION') + ' ' +
this.language.instant('DMP-LISTING.LINK-ZENODO') + ' ' +
this.language.instant('DMP-LISTING.GET-IDEA');
this.dashboardTour.steps[0].title = this.dmpText;
this.dashboardTour.steps[0].title = dmpText;
}
public setDashboardTourDatasetText(): void {
this.datasetText = this.language.instant('DATASET-LISTING.TEXT-INFO') +
const datasetText = this.language.instant('DATASET-LISTING.TEXT-INFO') +
this.language.instant('DATASET-LISTING.LINK-PUBLIC-DATASETS') + ' ' +
this.language.instant('DATASET-LISTING.TEXT-INFO-REST') + '\n\n' +
this.language.instant('DATASET-LISTING.TEXT-INFO-PAR');
this.dashboardTour.steps[1].title = this.datasetText;
this.dashboardTour.steps[1].title = datasetText;
}
public restartTour(): void {
@ -574,6 +333,6 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
}
public hasLikeCriteria(): boolean {
return this.criteria.like !== undefined && this.criteria.like !== null;
return this.lookup.like !== undefined && this.lookup.like !== null;
}
}

View File

@ -7,7 +7,7 @@
</div>
<div class="col-auto" [ngClass]="{'dmp-title': !isDraft, 'dmp-title-draft': isDraft}">{{dmp.label}}</div>
<div class="dmp-subtitle">
<span *ngIf="isUserDMPRelated()" class="col-auto">{{ roleDisplay(dmp.users) }}</span>
<span *ngIf="isUserDMPRelated()" class="col-auto">{{ enumUtils.toDmpUserRolesString(dmpService.getCurrentUserRolesInDmp(dmp?.dmpUsers)) }}</span>
<span *ngIf="isUserDMPRelated()">.</span>
<span class="col-auto" *ngIf="dmp.status === dmpStatusEnum.Finalized && isPublic"><span class="material-icons icon-align">public</span>{{'TYPES.DMP-VISIBILITY.PUBLIC' | translate}}</span>
<span *ngIf="dmp.status === dmpStatusEnum.Finalized && !isPublic" class="col-auto"><span class="material-icons icon-align">done</span>{{ enumUtils.toDmpStatusString(dmp.status) }}</span>
@ -15,14 +15,14 @@
<span>.</span>
<span class="col-auto">{{'DMP-LISTING.VERSION' | translate}} {{dmp.version}}</span>
<span>.</span>
<!-- <span class="col">{{ 'DMP-LISTING.GRANT' | translate }}: {{dmp.grant}}</span> -->
<span class="col">{{ 'DMP-LISTING.GRANT' | translate }}: {{referenceService.getReferencesForTypesFirstSafe(dmp?.dmpReferences, [referenceTypeEnum.Grants])?.reference?.label}}</span>
</div>
<div class="col-auto dmp-dataset-descriptions-title">{{'DMP-LISTING.CONTAINED-DESCRIPTIONS' | translate}}: ({{ dmp.descriptions.length }})
</div>
<div *ngFor="let dataset of dmp.descriptions; let i = index; let last = last" [ngClass]="{'pb-3': i === dmp.descriptions.length - 1}">
<div *ngFor="let description of dmp.descriptions; let i = index; let last = last" [ngClass]="{'pb-3': i === dmp.descriptions.length - 1}">
<div *ngIf="i < 3">
<div class="col-auto dmp-dataset-descriptions-name" *ngIf="!last && i !== 2">{{dataset.label}},</div>
<div class="col-auto dmp-dataset-descriptions-name" *ngIf="last || i == 2">{{dataset.label}}</div>
<div class="col-auto dmp-dataset-descriptions-name" *ngIf="!last && i !== 2">{{description.label}},</div>
<div class="col-auto dmp-dataset-descriptions-name" *ngIf="last || i == 2">{{description.label}}</div>
</div>
</div>
<a class="d-flex justify-content-center pb-3 show-more" *ngIf="dmp.descriptions.length > 3" [routerLink]="isPublic ? ['/explore-plans/publicOverview/' + dmp.id] : ['/plans/overview/' + dmp.id]"><u>{{'GENERAL.ACTIONS.SHOW-MORE' | translate}}</u></a>

View File

@ -34,6 +34,9 @@ import { GrantTabModel } from '../../editor/grant-tab/grant-tab-model';
import { ProjectFormModel } from '../../editor/grant-tab/project-form-model';
import { DmpInvitationDialogComponent } from '../../invitation/dmp-invitation-dialog.component';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
import { DmpAccessType } from '@app/core/common/enum/dmp-access-type';
import { ReferenceType } from '@app/core/common/enum/reference-type';
import { ReferenceService } from '@app/core/services/reference/reference.service';
@Component({
selector: 'app-dmp-listing-item-component',
@ -50,9 +53,8 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
isDraft: boolean;
isFinalized: boolean;
isPublished: boolean;
dmpModel: DmpEditorModel;
dmpFormGroup: UntypedFormGroup;
dmpStatusEnum = DmpStatus;
referenceTypeEnum = ReferenceType;
constructor(
private router: Router,
@ -67,6 +69,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
private location: Location,
private httpClient: HttpClient,
private matomoService: MatomoService,
public referenceService: ReferenceService,
private fileUtils: FileUtils) {
super();
}
@ -82,7 +85,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
this.isDraft = false;
this.isFinalized = true;
this.isPublished = false;
// if (this.dmp.public == true) { this.isPublished = true }
if (this.dmp.status === DmpStatus.Finalized && this.dmp.accessType === DmpAccessType.Public) { this.isPublished = true }
}
}
@ -91,16 +94,17 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
}
openShareDialog(rowId: any, rowName: any) {
const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
// height: '250px',
// width: '700px',
autoFocus: false,
restoreFocus: false,
data: {
dmpId: rowId,
dmpName: rowName
}
});
//TODO: add this.
// const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
// // height: '250px',
// // width: '700px',
// autoFocus: false,
// restoreFocus: false,
// data: {
// dmpId: rowId,
// dmpName: rowName
// }
// });
}
editClicked(dmpId: String) {
@ -123,38 +127,9 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
// }
}
roleDisplay(value: any) {
const principalId: string = this.authentication.userId()?.toString();
let role: number;
if (principalId) {
value.forEach(element => {
if (principalId === element.id) {
role = element.role;
}
});
}
if (role === 0) {
return this.language.instant('DMP-LISTING.OWNER');
}
else if (role === 1) {
return this.language.instant('DMP-LISTING.MEMBER');
}
else {
return this.language.instant('DMP-LISTING.OWNER');
}
}
isUserDMPRelated() {
const principalId: string = this.authentication.userId()?.toString();
let isRelated: boolean = false;
if (this.dmp && principalId) {
// this.dmp.users.forEach(element => {
// if (element.id === principalId) {
// isRelated = true;
// }
// })
}
return isRelated;
const principalId: Guid = this.authentication.userId();
return this.dmp.dmpUsers.some(x => (x.user.id === principalId));
}
cloneOrNewVersionClicked(dmp: Dmp, isNewVersion: boolean) {
@ -216,60 +191,19 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
);
}
private checkForGrant(blueprint: DmpBlueprintDefinition) {
let hasGrant = false;
blueprint.sections.forEach(section => section.fields.forEach(
field => {
if (field.category as unknown === DmpBlueprintSectionFieldCategory.SYSTEM && field.systemFieldType === DmpBlueprintSystemFieldType.GRANT) {
hasGrant = true;
}
}
));
if (!hasGrant) {
this.dmpFormGroup.removeControl('grant');
}
}
private checkForFunder(blueprint: DmpBlueprintDefinition) {
let hasFunder = false;
blueprint.sections.forEach(section => section.fields.forEach(
field => {
if (field.category as unknown === DmpBlueprintSectionFieldCategory.SYSTEM && field.systemFieldType === DmpBlueprintSystemFieldType.FUNDER) {
hasFunder = true;
}
}
));
if (!hasFunder) {
this.dmpFormGroup.removeControl('funder');
}
}
private checkForProject(blueprint: DmpBlueprintDefinition) {
let hasProject = false;
blueprint.sections.forEach(section => section.fields.forEach(
field => {
if (field.category as unknown === DmpBlueprintSectionFieldCategory.SYSTEM && field.systemFieldType === DmpBlueprintSystemFieldType.PROJECT) {
hasProject = true;
}
}
));
if (!hasProject) {
this.dmpFormGroup.removeControl('project');
}
}
openCloneDialog(isNewVersion: boolean) {
const dialogRef = this.dialog.open(CloneDialogComponent, {
maxWidth: '700px',
maxHeight: '80vh',
data: {
formGroup: this.dmpFormGroup,
datasets: this.dmpFormGroup.get('datasets').value,
isNewVersion: isNewVersion,
confirmButton: this.language.instant('DMP-EDITOR.CLONE-DIALOG.SAVE'),
cancelButton: this.language.instant('DMP-EDITOR.CLONE-DIALOG.CANCEL'),
}
});
// TODO: fix this
// const dialogRef = this.dialog.open(CloneDialogComponent, {
// maxWidth: '700px',
// maxHeight: '80vh',
// data: {
// formGroup: this.dmpFormGroup,
// datasets: this.dmpFormGroup.get('datasets').value,
// isNewVersion: isNewVersion,
// confirmButton: this.language.instant('DMP-EDITOR.CLONE-DIALOG.SAVE'),
// cancelButton: this.language.instant('DMP-EDITOR.CLONE-DIALOG.CANCEL'),
// }
// });
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
// if (result) {
// if (!isNewVersion) {
@ -291,12 +225,8 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
// });
}
// newVersion(id: String, label: String) {
// let url = this.router.createUrlTree(['/plans/new_version/', id, { dmpLabel: label }]);
// window.open(url.toString(), '_blank');
// }
downloadXml(id: Guid) {
// TODO: Add this
// this.dmpService.downloadXML(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
@ -309,6 +239,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
}
downloadDocx(id: Guid) {
// TODO: Add this
// this.dmpService.downloadDocx(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
@ -321,6 +252,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
}
downloadPDF(id: Guid) {
// TODO: Add this
// this.dmpService.downloadPDF(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
@ -333,6 +265,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
}
downloadJson(id: Guid) {
// TODO: Add this
// this.dmpService.downloadJson(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
@ -345,11 +278,11 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
// });
}
async onExportCallbackError(error: any) {
const errorJsonText = await error.error.text();
const errorObj = JSON.parse(errorJsonText);
this.uiNotificationService.snackBarNotification(errorObj.message, SnackBarNotificationLevel.Error);
}
// async onExportCallbackError(error: any) {
// const errorJsonText = await error.error.text();
// const errorObj = JSON.parse(errorJsonText);
// this.uiNotificationService.snackBarNotification(errorObj.message, SnackBarNotificationLevel.Error);
// }
deleteClicked(id: string) {
this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed))

View File

@ -377,7 +377,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
if (!this.isFinalized)
this.router.navigate(['/plans/edit/' + dmpId], { queryParams: { tab: "datasetDescriptions" } });
else
this.router.navigate(['/explore'], { queryParams: { dmpId: dmpId } });
this.router.navigate(['/explore-descriptions'], { queryParams: { dmpId: dmpId } });
}
goToUri(uri: string) {

View File

@ -1,112 +0,0 @@
<div class="main-content">
<div class="container-fluid">
<div class="grant-editor">
<mat-card-title *ngIf="isNew">{{'GRANT-EDITOR.TITLE.NEW' | translate}}</mat-card-title>
<mat-card-title *ngIf="!isNew">{{formGroup?.get('label')?.value}}</mat-card-title>
<form *ngIf="formGroup" (ngSubmit)="formSubmit()" [formGroup]="formGroup">
<mat-card>
<mat-card-header>
<div class="col-12 row">
<table class="logo-table col-auto">
<tr>
<td>
<img mat-card-avatar (click)='imgEnable() && imgFileInput.click()' *ngIf="!formGroup.get('files') || !formGroup.get('files').value" [src]="host+'files/any?type=jpg'">
<img mat-card-avatar (click)='editMode && imgFileInput.click()' *ngIf="formGroup.get('files') && formGroup.get('files').value" [src]="host+'files/'+formGroup.get('files').value[0].id+'?location='+formGroup.get('files').value[0].location+'&type='+formGroup.get('files').value[0].type">
</td>
<td>
<input class="hidden" type="file" #imgFileInput (change)="previewImage($event)" accept="image/*"/>
<div>
<mat-error *ngIf="sizeError">File is too big!</mat-error>
</div>
</td>
</tr>
</table>
<div class="col"></div>
<div *ngIf="!isNew" class="grant-editor-header-actions col-auto">
<div class="row actions-row">
<div class="col-auto" *ngIf="!editMode && !isExternalGrant()">
<button mat-icon-button (click)="enableForm()">
<mat-icon class="mat-24">edit</mat-icon>
</button>
</div>
<div class="col-auto" *ngIf="editMode && !isExternalGrant()">
<button mat-icon-button (click)="disableForm()">
<mat-icon class="mat-24">lock</mat-icon>
</button>
</div>
<div class="col-auto">
<button mat-button (click)="goToGrantDmps()">
<mat-icon class="mat-24">arrow_right_alt</mat-icon>
<span>{{'GRANT-EDITOR.ACTIONS.GO-TO-DMPS' | translate}}</span>
</button>
</div>
</div>
</div>
</div>
</mat-card-header>
<mat-card-content>
<div class="row">
<mat-form-field class="col-md-12">
<input matInput placeholder="{{'GRANT-EDITOR.FIELDS.LABEL' | translate}}" type="text" name="label" formControlName="label" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<input matInput placeholder="{{'GRANT-EDITOR.FIELDS.ABBREVIATION' | translate}}" type="text" name="abbreviation" formControlName="abbreviation">
<mat-error *ngIf="formGroup.get('abbreviation').hasError('backendError')">{{formGroup.get('abbreviation').getError('backendError').message}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<input matInput placeholder="{{'GRANT-EDITOR.FIELDS.URI' | translate}}" type="text" name="uri" formControlName="uri">
<mat-error *ngIf="formGroup.get('uri').hasError('backendError')">{{formGroup.get('uri').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<input matInput (focus)="startDate.open()" (click)="startDate.open()" placeholder="{{'GRANT-EDITOR.FIELDS.START' | translate}}" class="table-input" [matDatepicker]="startDate" formControlName="startDate">
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
<mat-error *ngIf="formGroup.get('startDate').hasError('backendError')">{{formGroup.get('startDate').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('startDate').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<input matInput (focus)="endDate.open()" (click)="endDate.open()" placeholder="{{'GRANT-EDITOR.FIELDS.END' | translate}}" class="table-input" [matDatepicker]="endDate" formControlName="endDate">
<mat-datepicker-toggle matSuffix [for]="endDate"></mat-datepicker-toggle>
<mat-datepicker #endDate></mat-datepicker>
<mat-error *ngIf="formGroup.get('endDate').hasError('backendError')">{{formGroup.get('endDate').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('endDate').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-error *ngIf="formGroup.hasError('startAfterEndError')"class="col-md-12">{{'GENERAL.VALIDATION.GRANT-START-AFTER-END' | translate}}</mat-error>
<mat-form-field class="col-md-12">
<textarea matInput class="description-area" placeholder="{{'GRANT-EDITOR.FIELDS.DESCRIPTION' | translate}}" formControlName="description" required></textarea>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<div class="col-md-12">
<div class="row">
<div class="col-auto right-button">
<button mat-raised-button color="primary" (click)="cancel()" type="button">{{'GRANT-EDITOR.ACTIONS.CANCEL' |
translate}}</button>
</div>
<div class="col"></div>
<div class="col-auto right-button" *ngIf="!isNew && editMode">
<button mat-raised-button color="primary" type="button" (click)="delete()">{{'GRANT-EDITOR.ACTIONS.DELETE'
| translate}}</button>
</div>
<div class="col-auto right-button" *ngIf="isNew || editMode">
<button mat-raised-button color="primary" type="submit">{{'GRANT-EDITOR.ACTIONS.SAVE'
| translate}}</button>
</div>
</div>
</div>
</div>
</mat-card-content>
</mat-card>
</form>
</div>
</div>
</div>

View File

@ -1,20 +0,0 @@
.grant-editor {
.grant-editor-header-actions {
display: flex;
align-items: center;
}
.logo-table {
table-layout: fixed;
display: inline-block;
td {
padding: 3px;
}
}
.hidden {
display: none;
}
}

View File

@ -1,214 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { GrantType } from '@app/core/common/enum/grant-type';
import { GrantListingModel } from '@app/core/model/grant/grant-listing';
import { GrantFileUploadService } from '@app/core/services/grant/grant-file-upload.service';
import { GrantService } from '@app/core/services/grant/grant.service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent';
import { BaseComponent } from '@common/base/base.component';
import { FormService } from '@common/forms/form-service';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import { environment } from 'environments/environment';
import { Observable, of as observableOf } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
@Component({
selector: 'app-grant-editor-component',
templateUrl: 'grant-editor.component.html',
styleUrls: ['./grant-editor.component.scss']
})
export class GrantEditorComponent extends BaseComponent implements OnInit { //IBreadCrumbComponent
// breadCrumbs: Observable<BreadcrumbItem[]> = observableOf([]);
isNew = true;
grant: GrantEditorModel;
formGroup: FormGroup = null;
host: string;
editMode = false;
sizeError = false;
maxFileSize: number = 1048576;
constructor(
private grantService: GrantService,
private route: ActivatedRoute,
public snackBar: MatSnackBar,
public router: Router,
public language: TranslateService,
private dialog: MatDialog,
private grantFileUploadService: GrantFileUploadService,
private uiNotificationService: UiNotificationService,
private formService: FormService,
private configurationService: ConfigurationService
) {
super();
this.host = this.configurationService.server;
}
ngOnInit() {
this.route.params
.pipe(takeUntil(this._destroyed))
.subscribe((params: Params) => {
const itemId = params['id'];
if (itemId != null) {
this.isNew = false;
this.grantService.getSingle(itemId).pipe(map(data => data as GrantListingModel))
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.grant = new GrantEditorModel().fromModel(data);
this.formGroup = this.grant.buildForm(null, this.grant.type === GrantType.External || !this.editMode);
const breadCrumbs = [];
breadCrumbs.push({
parentComponentName: null,
label: this.language.instant('NAV-BAR.GRANTS').toUpperCase(),
url: '/grants'
});
breadCrumbs.push({
parentComponentName: 'GrantListingComponent',
label: this.grant.label,
url: '/grants/edit/' + this.grant.id
});
//this.breadCrumbs = observableOf(breadCrumbs);
});
} else {
this.language.get('QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.CREATE-NEW-GRANT').pipe(takeUntil(this._destroyed)).subscribe(x => {
// this.breadCrumbs = observableOf([
// {
// parentComponentName: null,
// label: this.language.instant('NAV-BAR.GRANTS').toUpperCase(),
// url: '/grants'
// },
// {
// parentComponentName: 'GrantListingComponent',
// label: x,
// url: '/grants/new/'
// }]
// );
});
this.grant = new GrantEditorModel();
setTimeout(() => {
this.formGroup = this.grant.buildForm();
});
}
});
}
formSubmit(): void {
this.formService.touchAllFormFields(this.formGroup);
if (!this.isFormValid()) { return; }
this.onSubmit();
}
public isFormValid() {
return this.formGroup.valid;
}
onSubmit(): void {
this.grantService.createGrant(this.formGroup.value)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => this.onCallbackSuccess(),
error => this.onCallbackError(error)
);
}
onCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
this.router.navigate(['/grants']);
}
onCallbackError(errorResponse: any) {
this.setErrorModel(errorResponse.error.payload);
this.formService.validateAllFormFields(this.formGroup);
}
public setErrorModel(validationErrorModel: ValidationErrorModel) {
Object.keys(validationErrorModel).forEach(item => {
(<any>this.grant.validationErrorModel)[item] = (<any>validationErrorModel)[item];
});
}
public cancel(): void {
this.router.navigate(['/grants']);
}
public delete(): void {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
maxWidth: '300px',
restoreFocus: false,
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
isDeleteConfirmation: true
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
this.grantService.delete(this.grant.id)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => { this.onCallbackSuccess() },
error => this.onCallbackError(error)
);
}
});
}
public enableForm() {
if (!this.isExternalGrant()) {
this.editMode = true;
this.formGroup.enable();
}
}
public disableForm() {
this.editMode = false;
this.formGroup.disable();
}
public imgEnable(): boolean {
if (this.isNew || this.editMode) {
return true;
}
return false;
}
public goToGrantDmps() {
this.router.navigate(['plans/grant/' + this.grant.id], { queryParams: { grantLabel: this.grant.label } });
}
public isExternalGrant() {
return this.grant.type === GrantType.External;
}
public previewImage(event): void {
const fileList: FileList | File = event.target.files;
const size: number = event.target.files[0].size; // Get file size.
this.sizeError = size > this.maxFileSize; // Checks if file size is valid.
const formdata: FormData = new FormData();
if (!this.sizeError) {
if (fileList instanceof FileList) {
for (let i = 0; i < fileList.length; i++) {
formdata.append('file', fileList[i]);
}
} else {
formdata.append('file', fileList);
}
this.grantFileUploadService.uploadFile(formdata)
.pipe(takeUntil(this._destroyed))
.subscribe(files => this.formGroup.get('files').patchValue(files));
}
}
}

View File

@ -1,83 +0,0 @@
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { BackendErrorValidator } from '@common/forms/validation/custom-validator';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { ValidationContext } from '@common/forms/validation/validation-context';
import { GrantType } from '../../../core/common/enum/grant-type';
import { Status } from '../../../core/common/enum/status';
import { ContentFile, GrantListingModel } from '../../../core/model/grant/grant-listing';
export class GrantEditorModel {
public id: string;
public label: string;
public abbreviation: string;
public reference: string;
public type: GrantType = GrantType.Internal;
public uri: String;
public status: Status = Status.Active;
public startDate: Date;
public endDate: Date;
public description: String;
public contentUrl: string;
public files: ContentFile[];
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
fromModel(item: GrantListingModel): GrantEditorModel {
this.id = item.id;
this.label = item.label;
this.type = item.type;
this.abbreviation = item.abbreviation;
this.reference = item.reference;
this.uri = item.uri;
this.status = item.status;
this.startDate = item.startDate ? new Date(item.startDate) : null;
this.endDate = item.endDate ? new Date(item.endDate) : null;
this.description = item.description;
this.contentUrl = item.contentUrl;
this.files = item.files;
return this;
}
buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
if (context == null) { context = this.createValidationContext(); }
const formGroup = new UntypedFormBuilder().group({
id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators],
abbreviation: [{ value: this.abbreviation, disabled: disabled }, context.getValidation('abbreviation').validators],
uri: [{ value: this.uri, disabled: disabled }, context.getValidation('uri').validators],
status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators],
type: [{ value: this.type, disabled: disabled }, context.getValidation('type').validators],
description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
startDate: [{ value: this.startDate, disabled: disabled }, context.getValidation('startDate').validators],
endDate: [{ value: this.endDate, disabled: disabled }, context.getValidation('endDate').validators],
files: [{ value: this.files, disabled: disabled }, context.getValidation('files').validators]
}, { validator: startEndValidator });
return formGroup;
}
createValidationContext(): ValidationContext {
const baseContext: ValidationContext = new ValidationContext();
baseContext.validation.push({ key: 'id', validators: [] });
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
baseContext.validation.push({ key: 'abbreviation', validators: [BackendErrorValidator(this.validationErrorModel, 'abbreviation')] });
baseContext.validation.push({ key: 'uri', validators: [BackendErrorValidator(this.validationErrorModel, 'uri')] });
baseContext.validation.push({ key: 'type', validators: [BackendErrorValidator(this.validationErrorModel, 'type')] });
baseContext.validation.push({ key: 'status', validators: [] });
baseContext.validation.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'description')] });
baseContext.validation.push({ key: 'startDate', validators: [BackendErrorValidator(this.validationErrorModel, 'startDate')] });
baseContext.validation.push({ key: 'endDate', validators: [BackendErrorValidator(this.validationErrorModel, 'endDate')] });
baseContext.validation.push({ key: 'files', validators: [BackendErrorValidator(this.validationErrorModel, 'files')] });
return baseContext;
}
}
export function startEndValidator(formGroup: UntypedFormGroup) {
const start = formGroup.get('startDate').value;
const end = formGroup.get('endDate').value;
if (start != null && end != null && end < start) {
return { 'startAfterEndError': {} };
}
return null;
}

View File

@ -1,27 +0,0 @@
import { NgModule } from '@angular/core';
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
import { GrantEditorComponent } from '@app/ui/grant/editor/grant-editor.component';
import { GrantRoutingModule } from '@app/ui/grant/grant.routing';
import { GrantCriteriaComponent } from '@app/ui/grant/listing/criteria/grant-criteria.component';
import { GrantListingComponent } from '@app/ui/grant/listing/grant-listing.component';
import { GrantListingItemComponent } from '@app/ui/grant/listing/listing-item/grant-listing-item.component';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
UrlListingModule,
ConfirmationDialogModule,
GrantRoutingModule
],
declarations: [
GrantListingComponent,
GrantCriteriaComponent,
GrantEditorComponent,
GrantListingItemComponent
]
})
export class GrantModule { }

View File

@ -1,37 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { GrantEditorComponent } from './editor/grant-editor.component';
import { GrantListingComponent } from './listing/grant-listing.component';
// ----------- UNCOMMENT TO ADD AGAIN GRANTS --------
const routes: Routes = [
// {
// path: '',
// component: GrantListingComponent,
// data: {
// breadcrumb: true
// },
// },
// {
// path: 'edit/:id',
// component: GrantEditorComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.GRANT-EDIT'
// }
// },
// {
// path: 'new',
// component: GrantEditorComponent,
// data: {
// breadcrumb: true,
// title: 'GENERAL.TITLES.GRANT-NEW'
// },
// }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class GrantRoutingModule { }

View File

@ -1,38 +0,0 @@
<div class="grant-criteria">
<div class="filters">
<h6 class="filters-title">{{'CRITERIA.FILTERS'| translate}}</h6>
<div class="row" style="justify-content: center;">
<!-- <h4 class="col-md-12">{{'CRITERIA.FILTERS'| translate}}</h4> -->
<mat-form-field class="col-11 search">
<input matInput placeholder=" {{'CRITERIA.GRANTS.LIKE'| translate}}" name="grantCriteriaLike" [(ngModel)]="criteria.like" (ngModelChange)="controlModified()">
<mat-icon matSuffix class="style-icon">search</mat-icon>
</mat-form-field>
<mat-form-field class="col-10 filter-category">
<input matInput (focus)="periodStartPicker.open()" (click)="periodStartPicker.open()" placeholder="{{'CRITERIA.GRANTS.PERIOD-FROM'| translate}}" [matDatepicker]="periodStartPicker" name="grantCriteriaPeriodStart" [(ngModel)]="criteria.periodStart" (ngModelChange)="controlModified()" [errorStateMatcher]="this">
<mat-datepicker-toggle matSuffix [for]="periodStartPicker"></mat-datepicker-toggle>
<mat-datepicker #periodStartPicker></mat-datepicker>
<mat-error>{{'GENERAL.VALIDATION.GRANT-START-AFTER-END' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-10 filter-category">
<input matInput (focus)="periodEndPicker.open()" (click)="periodEndPicker.open()" name="grantCriteriaPeriodEnd" placeholder="{{'CRITERIA.GRANTS.PERIOD-TO'| translate}}" [matDatepicker]="periodEndPicker" [(ngModel)]="criteria.periodEnd" (ngModelChange)="controlModified()" [errorStateMatcher]="this">
<mat-datepicker-toggle matSuffix [for]="periodEndPicker"></mat-datepicker-toggle>
<mat-datepicker #periodEndPicker></mat-datepicker>
<mat-error>{{'GENERAL.VALIDATION.GRANT-START-AFTER-END' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-10 filter-category">
<mat-select placeholder=" {{ 'CRITERIA.GRANTS.GRANT-STATE-TYPE' | translate}}" [(ngModel)]="criteria.grantStateType" (ngModelChange)="controlModified()" required>
<mat-option [value]="null">
{{ 'CRITERIA.GRANTS.TYPES.NONE' | translate}}
</mat-option>
<mat-option [value]="GrantStateType.OnGoing">
{{ 'CRITERIA.GRANTS.TYPES.ON-GOING' | translate}}
</mat-option>
<mat-option [value]="GrantStateType.Finished">
{{ 'CRITERIA.GRANTS.TYPES.FINISHED' | translate}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>

View File

@ -1,130 +0,0 @@
.dmp-criteria {
mat-form-field {
padding-bottom: 5px;
width: 100%;
}
mat-card {
padding-bottom: 0px;
}
.hidden {
display: none;
}
.uploadButton {
float: right;
}
}
.search ::ng-deep.mat-form-field-infix {
margin-left: 1em;
}
.filter-category {
background-color: #f6f6f6;
margin: 5px 0px;
}
.category-title {
color: black;
// color: #089dbb;
margin-top: 8px;
margin-bottom: 12px;
}
.import {
margin: 10px;
padding: 0px;
}
.filters {
border: 1px solid #e4e4e4;
border-radius: 5px;
}
.filters-title {
width: 90px;
// color: #089dbb;
color: var(--primary-color-2);
background-color: white;
padding: 0px 20px;
margin-top: -10px;
margin-left: 20px;
text-transform: uppercase;
}
.style-icon {
color: #adadad;
}
// ::ng-deep .mat-checkbox-inner-container {
// background: white;
// }
// ::ng-deep .mat-focused .mat-form-field-label {
// color: var(--primary-color-3) !important;
// }
// ::ng-deep.mat-form-field-underline {
// background-color: #adadad;
// }
// ::ng-deep.mat-form-field-ripple {
// background-color: var(--primary-color-3) !important;
// }
::ng-deep .mat-checkbox {
background-color: #f6f6f6 !important;
}
::ng-deep .mat-checkbox .mat-checkbox-frame {
border: 1px solid #aaaaaa;
}
::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background,
.mat-checkbox-indeterminate.mat-accent .mat-checkbox-background,
.mat-accent .mat-pseudo-checkbox-checked,
.mat-accent .mat-pseudo-checkbox-indeterminate,
.mat-pseudo-checkbox-checked,
.mat-pseudo-checkbox-indeterminate {
background-color: var(--primary-color-3);
}
::ng-deep .mat-ripple-element {
background-color: #2e74b649 !important;
}
::ng-deep .mat-radio-container {
border-radius: 1em;
background: white;
}
::ng-deep .mat-radio-button .mat-radio-outer-circle {
border: 1px solid #aaaaaa;
}
::ng-deep .mat-radio-button.mat-accent.mat-radio-checked .mat-radio-outer-circle {
border-color: #777777;
// border-color: var(--primary-color-3);
}
::ng-deep .mat-radio-button.mat-accent .mat-radio-inner-circle {
color: #777777;
background-color: #777777;
// color: var(--primary-color-3);
// background-color: var(--primary-color-3);
}
.mat-radio-button.mat-accent .mat-radio-ripple .mat-ripple-element {
background-color: #2e74b649;
}
::ng-deep .search-form .mat-form-field-wrapper {
background-color: white !important;
padding-bottom: 0 !important;
}
::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix {
padding: 0.3rem 0rem 0.6rem 0rem !important;
}

View File

@ -1,57 +0,0 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroupDirective, NgForm } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core';
import { GrantStateType } from '@app/core/common/enum/grant-state-type';
import { GrantCriteria } from '@app/core/query/grant/grant-criteria';
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';
@Component({
selector: 'app-grant-criteria-component',
templateUrl: './grant-criteria.component.html',
styleUrls: ['./grant-criteria.component.scss']
})
export class GrantCriteriaComponent extends BaseCriteriaComponent implements OnInit, ErrorStateMatcher {
public GrantStateType = GrantStateType;
public criteria: GrantCriteria = new GrantCriteria();
constructor(
public language: TranslateService,
public formBuilder: FormBuilder
) {
super(new ValidationErrorModel());
}
ngOnInit() {
super.ngOnInit();
if (this.criteria == null) {
this.criteria = new GrantCriteria();
this.criteria.grantStateType = GrantStateType.OnGoing;
}
}
setCriteria(criteria: GrantCriteria): void {
this.criteria = criteria;
}
onCallbackError(error: any) {
this.setErrorModel(error.error);
}
controlModified(): void {
this.clearErrorModel();
if (this.refreshCallback != null &&
(this.criteria.like == null || this.criteria.like.length === 0 || this.criteria.like.length > 2)
) {
setTimeout(() => this.refreshCallback(true));
}
}
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
const isDateInvalid = this.criteria.periodStart != null && this.criteria.periodEnd != null && this.criteria.periodStart > this.criteria.periodEnd
return !!(control && isDateInvalid && (control.dirty || control.touched || isSubmitted));
}
}

View File

@ -1,85 +0,0 @@
<div class="main-content">
<div class="container-fluid">
<div class="card">
<div class="card-header card-header-plain d-flex">
<div class="card-desc d-flex flex-column justify-content-center">
<h4 class="card-title">{{'GRANT-LISTING.TITLE' | translate}}</h4>
<!-- <p class="card-category">{{'GRANT-LISTING.SUBTITLE' | translate}}</p> -->
</div>
<div class="d-flex align-items-center ml-auto p-2">
<button mat-raised-button color="primary" class="text-uppercase lightblue-btn" [routerLink]="['./new']">
<mat-icon>add</mat-icon> {{'GRANT-LISTING.ACTIONS.NEW' | translate}}
</button>
</div>
</div>
<div class="card-body table-responsive">
<div class="grant-listing row">
<div class="col-3">
<app-grant-criteria-component class="col-auto"></app-grant-criteria-component>
</div>
<div class="col-9">
<div class="row" *ngFor="let item of listingItems; let i = index">
<app-grant-listing-item-component class="col-12" [showDivider]="i !== (listingItems.length - 1)" [grant]="item" (onClick)="rowClicked($event)"></app-grant-listing-item-component>
</div>
<mat-paginator #paginator [length]="totalCount" [pageSizeOptions]="[10, 25, 100]" (page)="pageThisEvent($event)" class="mt-2"></mat-paginator>
</div>
</div>
</div>
</div>
</div>
</div>
<!--
<div class="main-content">
<div class="container-fluid">
<h3>{{languageResolverService.getBy('listingTitle') | translate}}</h3>
<app-grant-criteria-component></app-grant-criteria-component>
<mat-card class="mat-card">
<mat-card-content>
<div class="row">
<mat-table class="col-md-12" [dataSource]="dataSource" matSort (matSortChange)="refresh()">
<ng-container cdkColumnDef="avatar">
<mat-header-cell *matHeaderCellDef mat-sort-header="avatar">{{'GRANT-LISTING.COLUMNS.AVATAR' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">
<img mat-card-avatar [src]="host+'files/'+row.files[0].id+'?location='+row.files[0].location+'&type='+row.files[0].type">
</mat-cell>
</ng-container>
<ng-container cdkColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header="label">{{'GRANT-LISTING.COLUMNS.NAME' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.label}}</mat-cell>
</ng-container>
<ng-container cdkColumnDef="abbreviation">
<mat-header-cell *matHeaderCellDef mat-sort-header="abbreviation">{{'GRANT-LISTING.COLUMNS.ABBREVIATION' |
translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.abbreviation}} </mat-cell>
</ng-container>
<ng-container cdkColumnDef="start">
<mat-header-cell *matHeaderCellDef mat-sort-header="startdate">{{'GRANT-LISTING.COLUMNS.START' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.startDate | date:'shortDate'}} </mat-cell>
</ng-container>
<ng-container cdkColumnDef="end">
<mat-header-cell *matHeaderCellDef mat-sort-header="enddate">{{'GRANT-LISTING.COLUMNS.END' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.endDate | date:'shortDate'}} </mat-cell>
</ng-container>
<ng-container cdkColumnDef="dmps">
<mat-header-cell *matHeaderCellDef>{{'GRANT-LISTING.COLUMNS.DMPS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row" (click)="$event.stopPropagation()">
<app-url-listing [items]="row.dmps" [urlLimit]="5" [parameters]="{ grantLabel: row.label }"></app-url-listing>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns" (click)="rowClick(row.id)"></mat-row>
</mat-table>
<mat-paginator #paginator [length]="dataSource?.totalCount" [pageSizeOptions]="[10, 25, 100]">
</mat-paginator>
</div>
</mat-card-content>
</mat-card>
<button mat-fab class="mat-fab-bottom" style="float: right;" color="primary" [routerLink]=" ['./new'] ">
<mat-icon class="mat-24">add</mat-icon>
</button>
</div>
</div> -->

View File

@ -1,45 +0,0 @@
.grant-listing {
.mat-card {
margin: 1em 0;
}
.col-9 {
display: flex;
flex-direction: column;
}
}
// ::ng-deep .mat-paginator {
// margin-top: auto;
// }
::ng-deep .mat-paginator-container {
flex-direction: row-reverse !important;
justify-content: space-between !important;
background-color: #f6f6f6;
height: 30px;
min-height: 30px !important;
}
::ng-deep .mat-paginator-page-size {
height: 43px;
}
::ng-deep .mat-icon-button {
height: 30px !important;
font-size: 12px !important;
}
::ng-deep .mat-paginator-range-label {
margin: 15px 32px 0 24px !important;
}
::ng-deep .mat-paginator-range-actions {
width: 55% !important;
min-height: 43px !important;
justify-content: space-between;
}
::ng-deep .mat-paginator-navigation-previous {
margin-left: auto !important;
}

View File

@ -1,85 +0,0 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { ActivatedRoute, Router } from '@angular/router';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { GrantListingModel } from '@app/core/model/grant/grant-listing';
import { GrantCriteria } from '@app/core/query/grant/grant-criteria';
import { GrantService } from '@app/core/services/grant/grant.service';
import { GrantCriteriaComponent } from '@app/ui/grant/listing/criteria/grant-criteria.component';
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent';
import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core';
import { Observable, of as observableOf } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-grant-listing-component',
templateUrl: 'grant-listing.component.html',
styleUrls: ['./grant-listing.component.scss']
})
export class GrantListingComponent extends BaseComponent implements OnInit { //IBreadCrumbComponent
@ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator;
@ViewChild(MatSort, { static: false }) sort: MatSort;
@ViewChild(GrantCriteriaComponent, { static: true }) criteria: GrantCriteriaComponent;
// breadCrumbs: Observable<BreadcrumbItem[]>;
totalCount: number;
listingItems: GrantListingModel[] = [];
constructor(
private grantService: GrantService,
private router: Router,
private route: ActivatedRoute,
public language: TranslateService
) {
super();
}
ngOnInit() {
this.criteria.setCriteria(this.getDefaultCriteria());
this.refresh();
this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages));
// this.breadCrumbs = observableOf([{
// parentComponentName: null,
// label: this.language.instant('NAV-BAR.GRANTS').toUpperCase(),
// url: '/grants'
// }]);
}
refresh(resetPages = false) {
if (this._paginator.pageSize === undefined) this._paginator.pageSize = 10;
if (resetPages) this._paginator.pageIndex = 0;
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
let fields: Array<string> = new Array();
if (this.sort && this.sort.active) { fields = this.sort.direction === 'asc' ? ['+' + this.sort.active] : ['-' + this.sort.active]; }
const request = new DataTableRequest<GrantCriteria>(startIndex, this._paginator.pageSize, { fields: fields });
request.criteria = this.criteria.criteria;
this.grantService.getPaged(request, "listing").pipe(takeUntil(this._destroyed)).subscribe(result => {
if (!result) { return []; }
if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
this.listingItems = result.data;
});
}
rowClicked(grant: GrantListingModel) {
this.router.navigate(['/grants/edit/' + grant.id]);
}
getDefaultCriteria(): GrantCriteria {
const defaultCriteria = new GrantCriteria();
return defaultCriteria;
}
pageThisEvent(event) {
this.refresh();
}
}

View File

@ -1,50 +0,0 @@
<div class="listing-item">
<div class="col" (click)="itemClicked()">
<div class="row">
<div class="col-12 gray-container container-header">
<p>{{grant.abbreviation}}</p>
</div>
</div>
<div class="row">
<div class="col-12 about-item">
<mat-icon class="draft-icon">lock</mat-icon>
<h4 class="title">{{grant.label}}</h4>
</div>
</div>
<div class="row">
<div class="col-12">
<p class="mt-1 mb-2">{{grant.description}}</p>
</div>
</div>
<div class="row">
<div class="col-12 about-item">
<mat-icon class="gray-icon pt-2">calendar_today</mat-icon>
<h4 class="mt-2 ml-1 mr-3 p-1">{{grant.startDate | date:'shortDate'}} - {{grant.endDate | date:'shortDate'}}</h4>
</div>
</div>
</div>
</div>
<!-- <mat-divider *ngIf="showDivider"></mat-divider> -->
<!-- <div class="grant-listing-item row" (click)="itemClicked()">
<div class="col-auto">
<mat-icon>lock</mat-icon>
</div>
<div class="col">
<div class="row">
<h4 class="col-12 title">{{grant.label}}</h4>
<h4 class="col-12 grant-title">{{grant.abbreviation}}</h4>
</div>
<div class="row d-flex align-items-center my-1">
<mat-icon class="col-auto gray-icon">desc</mat-icon>
<span class="col-auto m-2 p-1">{{grant.description}}</span>
</div>
<div class="row d-flex align-items-center my-1">
<mat-icon class="col-auto gray-icon">settings</mat-icon>
<h4 class="col-auto m-2 p-1">{{grant.startDate | date:'shortDate'}}</h4> - <h4 class="col-auto m-2 p-1">{{grant.endDate | date:'shortDate'}}</h4>
</div>
</div>
</div>
<mat-divider *ngIf="showDivider"></mat-divider> -->

View File

@ -1,42 +0,0 @@
.gray-container {
letter-spacing: 5px;
color: #aaaaaa;
}
.container-header {
display: flex;
align-items: baseline;
margin-top: 0px;
text-transform: uppercase;
}
.container-header p {
letter-spacing: 5px;
color: #aaaaaa;
margin-bottom: 0px;
}
.about-item {
display: flex;
flex-wrap: wrap;
}
.about-item .title {
margin: 2px 10px;
}
.about-item p {
margin-left: auto;
margin-bottom: 0px;
padding-top: 7px;
color: #aaaaaa;
}
.draft-icon {
color: #aaaaaa;
}
.more-horiz {
font-size: 28px;
color: #aaaaaa;
}

View File

@ -1,26 +0,0 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { GrantListingModel } from '../../../../core/model/grant/grant-listing';
@Component({
selector: 'app-grant-listing-item-component',
templateUrl: './grant-listing-item.component.html',
styleUrls: ['./grant-listing-item.component.scss'],
})
export class GrantListingItemComponent implements OnInit {
@Input() grant: GrantListingModel;
@Input() showDivider: boolean = true;
@Output() onClick: EventEmitter<GrantListingModel> = new EventEmitter();
constructor(
) {
}
ngOnInit() {
}
itemClicked() {
this.onClick.emit(this.grant);
}
}

View File

@ -26,7 +26,7 @@ import { AngularStickyThingsModule } from '@w11k/angular-sticky-things';
ConfirmationDialogModule,
QuickWizardRoutingModule,
DatasetDescriptionFormModule,
DmpModule,
// DmpModule,
TableOfContentsModule,
AngularStickyThingsModule
],

View File

@ -36,13 +36,13 @@ export const DMP_ROUTES: RouteInfo[] = [
];
export const DATASETS_ROUTES: RouteInfo[] = [
{ path: '/explore-plans', title: 'SIDE-BAR.PUBLIC-DMPS', icon: 'library_books' },
{ path: '/explore', title: 'SIDE-BAR.PUBLIC-DESC', icon: 'dns' },
{ path: '/explore-descriptions', title: 'SIDE-BAR.PUBLIC-DESC', icon: 'dns' },
// { path: '/datasetcreatewizard', title: 'SIDE-BAR.QUICK-WIZARD-DATASET', icon: "play_circle_outline" },
];
export const PUBLIC_ROUTES: RouteInfo[] = [
{ path: '/explore-plans', title: 'SIDE-BAR.PUBLIC-DMPS', icon: 'library_books' },
{ path: '/explore', title: 'SIDE-BAR.PUBLIC-DESC', icon: 'dns' }
{ path: '/explore-descriptions', title: 'SIDE-BAR.PUBLIC-DESC', icon: 'dns' }
];
// export const GRANTS_ROUTES: RouteInfo[] = [

View File

@ -1,4 +1,4 @@
import {AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup} from "@angular/forms";
import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from "@angular/forms";
export function isNullOrUndefined(object: any): boolean {
return object === null || object === undefined;
@ -40,7 +40,13 @@ export function cloneAbstractControl<T extends AbstractControl>(control: T): T {
throw new Error('Error: unexpected control value');
}
if (control.disabled) newControl.disable({emitEvent: false});
if (control.disabled) newControl.disable({ emitEvent: false });
return newControl;
}
Object.defineProperty(Array.prototype, 'firstSafe', {
value() {
return this.find(e => true) // or this.find(Boolean)
}
})

View File

@ -913,13 +913,41 @@
"MESSAGE": "Add dataset."
}
},
"DATASET-OVERVIEW": {
"DESCRIPTION-OVERVIEW": {
"TITLE": "Description",
"PUBLIC": "Public",
"LOCKED": "Locked",
"EDITED": "Edited",
"FINALISED": "Finalized",
"PART-OF": "Part of",
"GRANT": "Grant",
"RESEARCHERS": "Researchers",
"DESCRIPTION": "Description",
"DESCRIPTION-AUTHORS": "Description authors",
"YOU": "you",
"ERROR": {
"DELETED-DATASET": "The requested dataset is deleted",
"FORBIDEN-DATASET": "You are not allowed to access this dataset"
},
"LOCKED": {
"ACTIONS": {
"BACK":"Back",
"EDIT":"Edit",
"CLONE":"Clone",
"DELETE":"Delete",
"FINALIZE":"Finalize",
"REVERSE":"Undo Finalization",
"EXPORT":"Export",
"INVITE-SHORT": "Invite"
},
"COPY-DIALOG": {
"COPY": "Copy",
"CANCEL": "Cancel"
},
"UNDO-FINALIZATION-DIALOG": {
"CONFIRM": "Yes",
"NEGATIVE": "No"
},
"LOCKED-DIALOG": {
"TITLE": "Dataset is locked",
"MESSAGE": "Somebody else is modifying the dataset at this moment. If you would like to modify or view it, please come back later."
},
@ -929,42 +957,24 @@
"CANCEL": "Cancel"
}
},
"DATASET-LISTING": {
"TITLE": "Datasets",
"DESCRIPTION": "Description",
"SELECT-DESCRIPTIONS-TO-CLONE": "Select which descriptions to include in the new DMP. Selected descriptions will be editable.",
"SELECT-DESCRIPTIONS-NONE": "Not available Descriptions for this DMP.",
"DESCRIPTION-LISTING": {
"TITLE": "My Descriptions",
"TITLE-EXPLORE": "Published Descriptions",
"TEXT-INFO": "Datasets are documented following pre-defined templates which set the content of dataset descriptions. In {{ APP_NAME }}, a DMP can contain as many dataset descriptions as the datasets it documents. Browse ",
"TEXT-INFO-REST": " for a look at datasets described in {{ APP_NAME }} DMPs",
"LINK-PUBLIC-DATASETS": "Public Datasets",
"TEXT-INFO-PAR": "New datasets can be added to existing DMPs at any time and be described with more than one template. Datasets can also be cloned and re-used in other DMPs as well as be deleted without negatively affecting the DMP as a whole.",
"COLUMNS": {
"NAME": "Name",
"REFERNCE": "Reference",
"GRANT": "Grant",
"URI": "Uri",
"STATUS": "Status",
"DESCRIPTION": "Description",
"CREATED": "Created",
"PUBLISHED": "Published",
"FINALIZED": "Finalized",
"LAST-EDITED": "Last Edited",
"ACTIONS": "Actions",
"DMP": "DMP",
"PROFILE": "Template",
"DATAREPOSITORIES": "Data Repositories",
"REGISTRIES": "Registries",
"SERVICES": "Services"
},
"GRANT":"Grant",
"LOCKED": "Dataset is Locked by another user",
"ACTIONS": {
"EDIT": "Edit",
"MAKE-IT-PUBLIC": "Make it public",
"VIEW": "View",
"NEW": "New Dataset",
"CREATE-NEW": "Create new Dataset",
"ADD-DESCRIPTION": "Add Description",
"TAKE-A-TOUR": "Do you need help? Take a tour..",
"LOAD-MORE": "Load more",
"EXPORT": "Export",
"INVITE-COLLABORATORS": "Invite collaborators",
"INVITE-SHORT": "Invite"
"INVITE-SHORT": "Invite",
"DELETE": "Delete",
"COPY-DESCRIPTION": "Copy Description"
},
"STATES": {
"EDITED": "Edited",
@ -972,19 +982,12 @@
"FINALIZED": "Finalized",
"PUBLISHED": "Published"
},
"TOOLTIP": {
"DATASET-STATUS": {
"DRAFT": "Private access - Editable Dataset",
"FINALIZED": "Private access - Closed Dataset"
"COPY-DIALOG": {
"COPY": "Copy",
"CANCEL": "Cancel"
},
"DMP": "DMP",
"GRANT": "Grant",
"TEMPLATES-INVOLVED": "Dataset Template",
"VERSION": "DMP Version",
"PART-OF": "Part of",
"TO-DMP": "To DMP",
"DMP-FOR": "DMP for"
},
"DMP": "DMP",
"EMPTY-LIST": "Nothing here yet."
},
"DATASET-PUBLIC-LISTING": {
@ -1834,10 +1837,9 @@
"FINALISED": "Finalized",
"CANCELED": "Canceled"
},
"DATASET-ROLE": {
"DMP-USER-ROLE": {
"OWNER": "Owner",
"MEMBER": "Member",
"ANY": "Any"
"USER": "User"
},
"EXTERNAL-DATASET-TYPE": {
"SOURCE": "Source",