Merge branch 'dmp-refactoring' of code-repo.d4science.org:MaDgiK-CITE/argos into dmp-refactoring

# Conflicts:
#	dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts
This commit is contained in:
Efstratios Giannopoulos 2024-03-14 11:26:21 +02:00
commit dadda72a09
33 changed files with 475 additions and 532 deletions

View File

@ -116,7 +116,7 @@ public class DashboardServiceImpl implements DashboardService {
referenceTypeStatistics.setCount(this.queryFactory.query(ReferenceQuery.class).isActive(IsActive.Active).typeIds(typeId).authorize(EnumSet.of(Public)) referenceTypeStatistics.setCount(this.queryFactory.query(ReferenceQuery.class).isActive(IsActive.Active).typeIds(typeId).authorize(EnumSet.of(Public))
.dmpReferenceSubQuery(this.queryFactory.query(DmpReferenceQuery.class).isActives(IsActive.Active) .dmpReferenceSubQuery(this.queryFactory.query(DmpReferenceQuery.class).isActives(IsActive.Active)
.dmpSubQuery(dmpQuery)).count()); .dmpSubQuery(dmpQuery)).count());
referenceTypeStatistics.setReferenceType(this.builderFactory.builder(PublicReferenceTypeBuilder.class).build(new BaseFieldSet().ensure(PublicReferenceType._name), this.queryFactory.query(ReferenceTypeQuery.class).ids(typeId).first())); referenceTypeStatistics.setReferenceType(this.builderFactory.builder(PublicReferenceTypeBuilder.class).build(new BaseFieldSet().ensure(PublicReferenceType._id), this.queryFactory.query(ReferenceTypeQuery.class).ids(typeId).first()));
statistics.getReferenceTypeStatistics().add(referenceTypeStatistics); statistics.getReferenceTypeStatistics().add(referenceTypeStatistics);
} }
} }
@ -135,11 +135,15 @@ public class DashboardServiceImpl implements DashboardService {
DashboardStatisticsCacheService.DashboardStatisticsCacheValue cacheValue = this.dashboardStatisticsCacheService.lookup(this.dashboardStatisticsCacheService.buildKey(this.userScope.getUserId().toString().toLowerCase(Locale.ROOT))); DashboardStatisticsCacheService.DashboardStatisticsCacheValue cacheValue = this.dashboardStatisticsCacheService.lookup(this.dashboardStatisticsCacheService.buildKey(this.userScope.getUserId().toString().toLowerCase(Locale.ROOT)));
if (cacheValue == null || cacheValue.getDashboardStatistics() == null) { if (cacheValue == null || cacheValue.getDashboardStatistics() == null) {
DmpQuery dmpQuery = this.queryFactory.query(DmpQuery.class).isActive(IsActive.Active).versionStatuses(DmpVersionStatus.Current); DmpUserQuery dmpUserLookup = this.queryFactory.query(DmpUserQuery.class);
dmpUserLookup.userIds(this.userScope.getUserId());
dmpUserLookup.isActives(IsActive.Active);
DmpQuery dmpQuery = this.queryFactory.query(DmpQuery.class).isActive(IsActive.Active).dmpUserSubQuery(dmpUserLookup).versionStatuses(DmpVersionStatus.Current);
DashboardStatistics statistics = new DashboardStatistics(); DashboardStatistics statistics = new DashboardStatistics();
statistics.setDmpCount(dmpQuery.authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).count()); statistics.setDmpCount(dmpQuery.authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).count());
statistics.setDescriptionCount(this.queryFactory.query(DescriptionQuery.class).isActive(IsActive.Active).dmpSubQuery(dmpQuery).statuses(DescriptionStatus.Finalized).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).count()); statistics.setDescriptionCount(this.queryFactory.query(DescriptionQuery.class).isActive(IsActive.Active).dmpSubQuery(dmpQuery).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).count());
statistics.setReferenceTypeStatistics(new ArrayList<>()); statistics.setReferenceTypeStatistics(new ArrayList<>());
if (!this.conventionService.isListNullOrEmpty(this.config.getReferenceTypeCounters())){ if (!this.conventionService.isListNullOrEmpty(this.config.getReferenceTypeCounters())){
@ -148,7 +152,7 @@ public class DashboardServiceImpl implements DashboardService {
referenceTypeStatistics.setCount(this.queryFactory.query(ReferenceQuery.class).isActive(IsActive.Active).typeIds(typeId).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission) referenceTypeStatistics.setCount(this.queryFactory.query(ReferenceQuery.class).isActive(IsActive.Active).typeIds(typeId).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission)
.dmpReferenceSubQuery(this.queryFactory.query(DmpReferenceQuery.class).isActives(IsActive.Active) .dmpReferenceSubQuery(this.queryFactory.query(DmpReferenceQuery.class).isActives(IsActive.Active)
.dmpSubQuery(dmpQuery)).count()); .dmpSubQuery(dmpQuery)).count());
referenceTypeStatistics.setReferenceType(this.builderFactory.builder(PublicReferenceTypeBuilder.class).build(new BaseFieldSet().ensure(PublicReferenceType._code), this.queryFactory.query(ReferenceTypeQuery.class).ids(typeId).first())); referenceTypeStatistics.setReferenceType(this.builderFactory.builder(PublicReferenceTypeBuilder.class).build(new BaseFieldSet().ensure(PublicReferenceType._id), this.queryFactory.query(ReferenceTypeQuery.class).ids(typeId).first()));
statistics.getReferenceTypeStatistics().add(referenceTypeStatistics); statistics.getReferenceTypeStatistics().add(referenceTypeStatistics);
} }
} }

View File

@ -1,6 +1,6 @@
deposit: deposit:
sources: sources:
- url: http://localhost:8082 - url: http://dev04.local.cite.gr:55330/zenodo
repositoryId: zenodo repositoryId: zenodo
pdfTransformerId: docx-file-transformer pdfTransformerId: docx-file-transformer
rdaTransformerId: rda-file-transformer rdaTransformerId: rda-file-transformer

View File

@ -1,13 +1,13 @@
transformer: transformer:
sources: sources:
- url: http://localhost:8084 - url: http://dev04.local.cite.gr:55330/file/docx
transformerId: docx-file-transformer transformerId: docx-file-transformer
codes: [ docx, pdf ] codes: [ docx, pdf ]
issuer-url: ${IDP_ISSUER_URI_TOKEN:} issuer-url: ${IDP_ISSUER_URI_TOKEN:}
client-id: ${IDP_APIKEY_CLIENT_ID:} client-id: ${IDP_APIKEY_CLIENT_ID:}
client-secret: ${IDP_APIKEY_CLIENT_SECRET:} client-secret: ${IDP_APIKEY_CLIENT_SECRET:}
scope: ${IDP_APIKEY_SCOPE:} scope: ${IDP_APIKEY_SCOPE:}
- url: http://localhost:8086 - url: http://dev04.local.cite.gr:55330/file/rdajson
transformerId: rda-file-transformer transformerId: rda-file-transformer
codes: [ json ] codes: [ json ]
issuer-url: ${IDP_ISSUER_URI_TOKEN:} issuer-url: ${IDP_ISSUER_URI_TOKEN:}

View File

@ -2,5 +2,4 @@ export enum RecentActivityOrder {
UpdatedAt = 0, UpdatedAt = 0,
Label = 1, Label = 1,
Status = 2, Status = 2,
Published = 3
} }

View File

@ -1,6 +1,12 @@
import { PublicReferenceType } from "../dmp/dmp";
export interface DashboardStatistics { export interface DashboardStatistics {
dmpCount: number; dmpCount: number;
descriptionCount: number; descriptionCount: number;
organizationCount: number; referenceTypeStatistics: DashboardReferenceTypeStatistics[];
grantCount: number; }
export interface DashboardReferenceTypeStatistics {
count: number;
referenceType: PublicReferenceType
} }

View File

@ -186,16 +186,9 @@ export interface PublicReference {
export interface PublicReferenceType { export interface PublicReferenceType {
id: Guid; id: Guid;
name: string; name: string;
code: string;
} }
export interface PublicReference {
id: Guid;
label: string;
type: PublicUser;
role: DmpUserRole;
}
export interface PublicDmpUser { export interface PublicDmpUser {
id: Guid; id: Guid;
dmp: PublicDmp; dmp: PublicDmp;

View File

@ -8,7 +8,7 @@ import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/sing
import { QueryResult } from '@common/model/query-result'; import { QueryResult } from '@common/model/query-result';
import { FilterService } from '@common/modules/text-filter/filter-service'; import { FilterService } from '@common/modules/text-filter/filter-service';
import { Guid } from '@common/types/guid'; import { Guid } from '@common/types/guid';
import { Observable, throwError } from 'rxjs'; import { Observable, of, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators'; import { catchError, map } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { ConfigurationService } from '../configuration/configuration.service'; import { ConfigurationService } from '../configuration/configuration.service';
@ -16,6 +16,7 @@ import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { FileFormat } from '@app/core/model/file/file-format.model'; import { FileFormat } from '@app/core/model/file/file-format.model';
import { BaseHttpParams } from '@common/http/base-http-params'; import { BaseHttpParams } from '@common/http/base-http-params';
import { InterceptorType } from '@common/http/interceptors/interceptor-type'; import { InterceptorType } from '@common/http/interceptors/interceptor-type';
import { DescriptionValidationResult } from '@app/ui/dmp/dmp-finalize-dialog/dmp-finalize-dialog.component';
@Injectable() @Injectable()
export class DescriptionService { export class DescriptionService {
@ -90,6 +91,10 @@ export class DescriptionService {
catchError((error: any) => throwError(error))); catchError((error: any) => throwError(error)));
} }
public validate(descriptionIds: Guid[]): Observable<DescriptionValidationResult[]> {
return of(new Array<DescriptionValidationResult>());
}
// public downloadPDF(id: string): Observable<HttpResponse<Blob>> { // public downloadPDF(id: string): Observable<HttpResponse<Blob>> {
// return this.httpClient.get(`${this.apiBase}/${id}/export/Pdf`, { responseType: 'blob', observe: 'response', headers: this.headers }); // return this.httpClient.get(`${this.apiBase}/${id}/export/Pdf`, { responseType: 'blob', observe: 'response', headers: this.headers });
// } // }

View File

@ -137,4 +137,8 @@ export class ReferenceTypeService {
public getGrantReferenceType(): any { public getGrantReferenceType(): any {
return '5b9c284f-f041-4995-96cc-fad7ad13289c'; return '5b9c284f-f041-4995-96cc-fad7ad13289c';
} }
public getOrganizationReferenceType(): any {
return '7eeffb98-58fb-4921-82ec-e27f32f8e738';
}
} }

View File

@ -28,9 +28,9 @@
<mat-card-title *ngIf="isNew">{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.NEW' | translate}}</mat-card-title> <mat-card-title *ngIf="isNew">{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.NEW' | translate}}</mat-card-title>
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<div class="row mt-4"> <div class="d-flex flex-wrap mt-4">
<div class="col-6"> <div class="col-md-12">
<mat-form-field class="col-md-12"> <mat-form-field class="w-100">
<mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.NOTIFICATION-TYPE' | translate}}</mat-label> <mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.NOTIFICATION-TYPE' | translate}}</mat-label>
<mat-select [formControl]="formGroup.get('notificationType')" name="notificationType" required> <mat-select [formControl]="formGroup.get('notificationType')" name="notificationType" required>
<mat-option *ngFor="let type of notificationTypeEnum" [value]="type"> <mat-option *ngFor="let type of notificationTypeEnum" [value]="type">
@ -80,16 +80,18 @@
</div> </div>
<!-- Subject --> <!-- Subject -->
<div class="row"> <div class="d-flex flex-wrap">
<h3 class="col-md-12">{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.SUBJECT-SECTION' | translate}}</h3> <h3 class="col-md-12">{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.SUBJECT-SECTION' | translate}}</h3>
<mat-form-field class="col-md-12"> <div class="col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.SUBJECT-TEXT' | translate}}</mat-label> <mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.SUBJECT-TEXT' | translate}}</mat-label>
<input matInput [formControl]="formGroup.get('value').get('subjectText')"> <input matInput [formControl]="formGroup.get('value').get('subjectText')">
<mat-error *ngIf="formGroup.get('value').get('subjectText').hasError('backendError')">{{formGroup.get('value').get('subjectText').getError('backendError').message}}</mat-error> <mat-error *ngIf="formGroup.get('value').get('subjectText').hasError('backendError')">{{formGroup.get('value').get('subjectText').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('value').get('subjectText').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('value').get('subjectText').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
<div class="col-4"> </div>
<mat-form-field class="col-md-12"> <div class="col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.SUBJECT-KEY' | translate}}</mat-label> <mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.SUBJECT-KEY' | translate}}</mat-label>
<input matInput [formControl]="formGroup.get('value').get('subjectKey')"> <input matInput [formControl]="formGroup.get('value').get('subjectKey')">
<mat-error *ngIf="formGroup.get('value').get('subjectKey').hasError('backendError')">{{formGroup.get('value').get('subjectKey').getError('backendError').message}}</mat-error> <mat-error *ngIf="formGroup.get('value').get('subjectKey').hasError('backendError')">{{formGroup.get('value').get('subjectKey').getError('backendError').message}}</mat-error>
@ -113,8 +115,8 @@
<!-- Body --> <!-- Body -->
<div> <div>
<h3 class="col-md-12">{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.BODY-SECTION' | translate}}</h3> <h3 class="col-md-12">{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.BODY-SECTION' | translate}}</h3>
<div class="col-4"> <div class="col-md-6">
<mat-form-field class="col-md-12"> <mat-form-field class="w-100">
<mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.BODY-KEY' | translate}}</mat-label> <mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.BODY-KEY' | translate}}</mat-label>
<input matInput [formControl]="formGroup.get('value').get('bodyKey')"> <input matInput [formControl]="formGroup.get('value').get('bodyKey')">
<mat-error *ngIf="formGroup.get('value').get('bodyKey').hasError('backendError')">{{formGroup.get('value').get('bodyKey').getError('backendError').message}}</mat-error> <mat-error *ngIf="formGroup.get('value').get('bodyKey').hasError('backendError')">{{formGroup.get('value').get('bodyKey').getError('backendError').message}}</mat-error>
@ -123,7 +125,7 @@
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.BODY-TEXT' | translate}}</mat-label> <mat-label>{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.BODY-TEXT' | translate}}</mat-label>
<editor class="w-100" [init]="{ <editor class="w-100 mt-2" [init]="{
base_url: '/tinymce', base_url: '/tinymce',
suffix: '.min', suffix: '.min',
height: 800, height: 800,
@ -149,7 +151,7 @@
<h4 class="col-md-12">{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.BODY-FIELD-OPTIONS' | translate}} <h4 class="col-md-12">{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.BODY-FIELD-OPTIONS' | translate}}
<mat-checkbox [checked]="bodyFieldOptionsEnabled" (change)="bodyFieldOptionsSelectionChanged($event)"></mat-checkbox> <mat-checkbox [checked]="bodyFieldOptionsEnabled" (change)="bodyFieldOptionsSelectionChanged($event)"></mat-checkbox>
</h4> </h4>
<div *ngIf="bodyFieldOptionsEnabled == true"> <ng-container *ngIf="bodyFieldOptionsEnabled == true">
<app-notification-template-field-options-component <app-notification-template-field-options-component
[form]="formGroup.get('value').get('bodyFieldOptions')" [form]="formGroup.get('value').get('bodyFieldOptions')"
[validationErrorModel]="editorModel.validationErrorModel" [validationErrorModel]="editorModel.validationErrorModel"
@ -157,7 +159,7 @@
[bodyMandatoryFields]="subjectMandatoryFields" [bodyMandatoryFields]="subjectMandatoryFields"
[formatting]="bodyFormatting"> [formatting]="bodyFormatting">
</app-notification-template-field-options-component> </app-notification-template-field-options-component>
</div> </ng-container>
<!--Extra Options --> <!--Extra Options -->
<div class="row"> <div class="row">
<h3 class="col-md-12">{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.EXTRA-OPTIONS' | translate}}</h3> <h3 class="col-md-12">{{'NOTIFICATION-SERVICE.NOTIFICATION-TEMPLATE-EDITOR.FIELDS.EXTRA-OPTIONS' | translate}}</h3>

View File

@ -85,7 +85,8 @@
</div> </div>
<!-- Type reply in thread --> <!-- Type reply in thread -->
<div *ngIf="this.canEdit && !this.isDeleted" class="col-12"> <!-- <div *ngIf="this.canEdit && !this.isDeleted" class="col-12"> -->
<div class="col-12">
<div class="row new-reply mr-0"> <div class="row new-reply mr-0">
<mat-form-field class="col pt-2 pb-2 pr-0"> <mat-form-field class="col pt-2 pb-2 pr-0">
<textarea matInput matTextareaAutosize matAutosizeMinRows="1" [formControl]="this.threadReplyTextsFG[thread.id.toString()].get('replyText')" placeholder="{{'ANNOTATION-DIALOG.THREADS.REPLY' | translate}}"></textarea> <textarea matInput matTextareaAutosize matAutosizeMinRows="1" [formControl]="this.threadReplyTextsFG[thread.id.toString()].get('replyText')" placeholder="{{'ANNOTATION-DIALOG.THREADS.REPLY' | translate}}"></textarea>

View File

@ -64,7 +64,7 @@
<div class="counter-zero">0</div> <div class="counter-zero">0</div>
<a [routerLink]="['/plans']" class="link">{{'DASHBOARD.DMPS' | translate}}</a> <a [routerLink]="['/plans']" class="link">{{'DASHBOARD.DMPS' | translate}}</a>
<div class="counter-zero">0</div> <div class="counter-zero">0</div>
<a [routerLink]="['/datasets']" class="link">{{'DASHBOARD.DESCRIPTIONS' | translate}}</a> <a [routerLink]="['/descriptions']" class="link">{{'DASHBOARD.DESCRIPTIONS' | translate}}</a>
<div class="counter-zero">0</div> <div class="counter-zero">0</div>
<a class="link-disabled">{{'DASHBOARD.GRANTS' | translate}}</a> <a class="link-disabled">{{'DASHBOARD.GRANTS' | translate}}</a>
<div class="counter-zero">0</div> <div class="counter-zero">0</div>
@ -78,12 +78,12 @@
<a [routerLink]="['/plans']" class="link">{{'DASHBOARD.DMPS' | translate}}</a> <a [routerLink]="['/plans']" class="link">{{'DASHBOARD.DMPS' | translate}}</a>
<div [ngClass]="{'counter': dashboardStatistics?.descriptionCount != 0, 'counter-zero': dashboardStatistics?.descriptionCount == 0}"> <div [ngClass]="{'counter': dashboardStatistics?.descriptionCount != 0, 'counter-zero': dashboardStatistics?.descriptionCount == 0}">
{{dashboardStatistics?.descriptionCount}}</div> {{dashboardStatistics?.descriptionCount}}</div>
<a [routerLink]="['/datasets']" class="link">{{'DASHBOARD.DESCRIPTIONS' | translate}}</a> <a [routerLink]="['/descriptions']" class="link">{{'DASHBOARD.DESCRIPTIONS' | translate}}</a>
<div [ngClass]="{'counter': dashboardStatistics?.grantCount != 0, 'counter-zero': dashboardStatistics?.grantCount == 0}"> <div [ngClass]="{'counter': grantCount != 0, 'counter-zero': grantCount == 0}">
{{dashboardStatistics?.grantCount}}</div> {{grantCount}}</div>
<a href="#" class="link-disabled">{{'DASHBOARD.GRANTS' | translate}}</a> <a href="#" class="link-disabled">{{'DASHBOARD.GRANTS' | translate}}</a>
<div [ngClass]="{'counter': dashboardStatistics?.organizationCount != 0, 'counter-zero': dashboardStatistics?.organizationCount == 0}"> <div [ngClass]="{'counter': organizationCount != 0, 'counter-zero': organizationCount == 0}">
{{dashboardStatistics?.organizationCount}}</div> {{organizationCount}}</div>
<a href="#" class="link-disabled">{{'DASHBOARD.RELATED-ORGANISATIONS' | translate}}</a> <a href="#" class="link-disabled">{{'DASHBOARD.RELATED-ORGANISATIONS' | translate}}</a>
</div> </div>
</div> </div>
@ -151,12 +151,12 @@
<a [routerLink]="['/plans']" class="link">{{'DASHBOARD.PUBLIC-DMPS' | translate}}</a> <a [routerLink]="['/plans']" class="link">{{'DASHBOARD.PUBLIC-DMPS' | translate}}</a>
<div [ngClass]="{'counter': dashboardStatistics?.descriptionCount != 0, 'counter-zero': dashboardStatistics?.descriptionCount == 0}"> <div [ngClass]="{'counter': dashboardStatistics?.descriptionCount != 0, 'counter-zero': dashboardStatistics?.descriptionCount == 0}">
{{dashboardStatistics?.descriptionCount}}</div> {{dashboardStatistics?.descriptionCount}}</div>
<a [routerLink]="['/datasets']" class="link">{{'DASHBOARD.PUBLIC-DATASETS' | translate}}</a> <a [routerLink]="['/descriptions']" class="link">{{'DASHBOARD.PUBLIC-DESCRIPTIONS' | translate}}</a>
<div [ngClass]="{'counter': dashboardStatistics?.grantCount != 0, 'counter-zero': dashboardStatistics?.grantCount == 0}"> <div [ngClass]="{'counter': grantCount != 0, 'counter-zero': grantCount == 0}">
{{dashboardStatistics?.grantCount}}</div> {{grantCount}}</div>
<a href="#" class="link-disabled">{{'DASHBOARD.GRANTS' | translate}}</a> <a href="#" class="link-disabled">{{'DASHBOARD.GRANTS' | translate}}</a>
<div [ngClass]="{'counter': dashboardStatistics?.organizationCount != 0, 'counter-zero': dashboardStatistics?.organizationCount == 0}"> <div [ngClass]="{'counter': organizationCount != 0, 'counter-zero': organizationCount == 0}">
{{dashboardStatistics?.organizationCount}}</div> {{organizationCount}}</div>
<a href="#" class="link-disabled">{{'DASHBOARD.RELATED-ORGANISATIONS' | translate}}</a> <a href="#" class="link-disabled">{{'DASHBOARD.RELATED-ORGANISATIONS' | translate}}</a>
</div> </div>
</div> </div>

View File

@ -12,6 +12,7 @@ import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { StartNewDmpDialogComponent } from '../dmp/new/start-new-dmp-dialogue/start-new-dmp-dialog.component'; import { StartNewDmpDialogComponent } from '../dmp/new/start-new-dmp-dialogue/start-new-dmp-dialog.component';
import { ReferenceTypeService } from '@app/core/services/reference-type/reference-type.service';
@Component({ @Component({
@ -22,6 +23,8 @@ import { StartNewDmpDialogComponent } from '../dmp/new/start-new-dmp-dialogue/st
export class DashboardComponent extends BaseComponent implements OnInit { export class DashboardComponent extends BaseComponent implements OnInit {
public dashboardStatistics: DashboardStatistics; public dashboardStatistics: DashboardStatistics;
public grantCount = 0;
public organizationCount = 0;
currentType: string = "recent"; currentType: string = "recent";
constructor( constructor(
@ -32,7 +35,8 @@ export class DashboardComponent extends BaseComponent implements OnInit {
private dialog: MatDialog, private dialog: MatDialog,
private language: TranslateService, private language: TranslateService,
private guidedTourService: GuidedTourService, private guidedTourService: GuidedTourService,
private matomoService: MatomoService private matomoService: MatomoService,
public referenceTypeService: ReferenceTypeService
) { ) {
super(); super();
} }
@ -55,12 +59,16 @@ export class DashboardComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(results => { .subscribe(results => {
this.dashboardStatistics = results; this.dashboardStatistics = results;
this.grantCount = this.dashboardStatistics.referenceTypeStatistics.filter(x => x.referenceType.id == this.referenceTypeService.getGrantReferenceType())?.find(Boolean).count;
this.organizationCount = this.dashboardStatistics.referenceTypeStatistics.filter(x => x.referenceType.id == this.referenceTypeService.getOrganizationReferenceType())?.find(Boolean).count;
}); });
} else { } else {
this.dashboardService.getMyDashboardStatistics() this.dashboardService.getMyDashboardStatistics()
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(results => { .subscribe(results => {
this.dashboardStatistics = results; this.dashboardStatistics = results;
this.grantCount = this.dashboardStatistics.referenceTypeStatistics.filter(x => x.referenceType.id == this.referenceTypeService.getGrantReferenceType())?.find(Boolean).count;
this.organizationCount = this.dashboardStatistics.referenceTypeStatistics.filter(x => x.referenceType.id == this.referenceTypeService.getOrganizationReferenceType())?.find(Boolean).count;
if (this.dashboardStatistics && this.dashboardStatistics.dmpCount === 0) { if (this.dashboardStatistics && this.dashboardStatistics.dmpCount === 0) {
this.openDashboardTour(); this.openDashboardTour();
@ -108,8 +116,7 @@ export class DashboardComponent extends BaseComponent implements OnInit {
if (this.dashboardStatistics) { if (this.dashboardStatistics) {
return this.dashboardStatistics.dmpCount !== 0 return this.dashboardStatistics.dmpCount !== 0
|| this.dashboardStatistics.descriptionCount !== 0 || this.dashboardStatistics.descriptionCount !== 0
|| this.dashboardStatistics.grantCount !== 0 || this.dashboardStatistics.referenceTypeStatistics.length !== 0
|| this.dashboardStatistics.organizationCount !== 0;
} else { } else {
return false; return false;
} }

View File

@ -101,11 +101,10 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
} }
updateUrl() { updateUrl() {
// let parameters = "?type=dmps" +
let parameters = "" + let parameters = "" +
(this.page != 1 ? "&page=" + this.page : "") + (this.page != 1 ? "&page=" + this.page : "") +
//TODO refactor //TODO refactor
(((this.formGroup.get("order").value != this.order.UpdatedAt && !this.publicMode) || (this.formGroup.get("order").value != this.order.Published && this.publicMode)) ? "&order=" + this.formGroup.get("order").value : "") + // (((this.formGroup.get("order").value != this.order.UpdatedAt && !this.publicMode) || (this.formGroup.get("order").value != this.order.Published && this.publicMode)) ? "&order=" + this.formGroup.get("order").value : "") +
(this.formGroup.get("like").value ? ("&keyword=" + this.formGroup.get("like").value) : ""); (this.formGroup.get("like").value ? ("&keyword=" + this.formGroup.get("like").value) : "");
this.location.go(this.router.url.split('?')[0] + parameters); this.location.go(this.router.url.split('?')[0] + parameters);
} }

View File

@ -5,6 +5,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order'; import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { Description } from '@app/core/model/description/description'; import { Description } from '@app/core/model/description/description';
import { RecentActivityItem } from '@app/core/model/dashboard/recent-activity-item';
import { Dmp, DmpUser } from '@app/core/model/dmp/dmp'; import { Dmp, DmpUser } from '@app/core/model/dmp/dmp';
import { DmpReference } from '@app/core/model/dmp/dmp-reference'; import { DmpReference } from '@app/core/model/dmp/dmp-reference';
import { ReferenceType } from '@app/core/model/reference-type/reference-type'; import { ReferenceType } from '@app/core/model/reference-type/reference-type';
@ -121,25 +122,25 @@ export class RecentEditedDescriptionActivityComponent extends BaseComponent impl
this.lookup.project = { this.lookup.project = {
fields: [ fields: [
[nameof<Description>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.id)].join('.'),
[nameof<Description>(x => x.label)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.label)].join('.'),
[nameof<Description>(x => x.status)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.status)].join('.'),
[nameof<Description>(x => x.updatedAt)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.updatedAt)].join('.'),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.label)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.label)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.accessType)].join('.'), [nameof<RecentActivityItem>(x => x.description), 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<RecentActivityItem>(x => x.description), 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<RecentActivityItem>(x => x.description), 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.role)].join('.'), [nameof<RecentActivityItem>(x => x.description), 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<RecentActivityItem>(x => x.description), 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<RecentActivityItem>(x => x.description), 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<RecentActivityItem>(x => x.description), 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), nameof<ReferenceType>(x => x.id)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.type), nameof<ReferenceType>(x => x.id)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.reference)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.reference)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.reference), nameof<Reference>(x => x.isActive)].join('.'), [nameof<RecentActivityItem>(x => x.description), nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.dmpReferences), nameof<DmpReference>(x => x.isActive)].join('.'),
] ]
}; };

View File

@ -55,7 +55,7 @@
</button> </button>
</div> </div>
<div class="col-auto d-flex align-items-center"> <div class="col-auto d-flex align-items-center">
<button [disabled]="saving" *ngIf="!lockStatus && !viewOnly" mat-raised-button class="description-save-btn mr-2" type="button"> <button [disabled]="saving" *ngIf="!lockStatus && !viewOnly && hasReversableStatus() == false" mat-raised-button class="description-save-btn mr-2" type="button">
<span class="d-flex flex-row row"> <span class="d-flex flex-row row">
<span (click)="!saving?formSubmit():null" class="col">{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE' | translate }}</span> <span (click)="!saving?formSubmit():null" class="col">{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE' | translate }}</span>
<mat-divider [vertical]="true"></mat-divider> <mat-divider [vertical]="true"></mat-divider>
@ -73,7 +73,7 @@
<button [disabled]="saving" mat-menu-item (click)="save()" type="button">{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE-AND-CONTINUE' | translate }}</button> <button [disabled]="saving" mat-menu-item (click)="save()" type="button">{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE-AND-CONTINUE' | translate }}</button>
</mat-menu> </mat-menu>
<button [disabled]="saving" *ngIf="!lockStatus && !viewOnly" mat-raised-button class="description-save-btn mr-2" type="button" (click)="saveFinalize()">{{ 'DESCRIPTION-EDITOR.ACTIONS.FINALIZE' | translate }}</button> <button [disabled]="saving" *ngIf="!lockStatus && !viewOnly && hasReversableStatus() == false" mat-raised-button class="description-save-btn mr-2" type="button" (click)="finalize()">{{ 'DESCRIPTION-EDITOR.ACTIONS.FINALIZE' | translate }}</button>
<button [disabled]="saving" *ngIf="lockStatus" mat-raised-button disabled class="description-save-btn cursor-default" type="button">{{ 'DMP-OVERVIEW.LOCKED' | translate}}</button> <button [disabled]="saving" *ngIf="lockStatus" mat-raised-button disabled class="description-save-btn cursor-default" type="button">{{ 'DMP-OVERVIEW.LOCKED' | translate}}</button>
<button [disabled]="saving" *ngIf="hasReversableStatus() && !lockStatus" mat-raised-button class="description-save-btn mr-2" (click)="reverse()" type="button">{{ 'DESCRIPTION-EDITOR.ACTIONS.REVERSE' | translate }}</button> <button [disabled]="saving" *ngIf="hasReversableStatus() && !lockStatus" mat-raised-button class="description-save-btn mr-2" (click)="reverse()" type="button">{{ 'DESCRIPTION-EDITOR.ACTIONS.REVERSE' | translate }}</button>
</div> </div>

View File

@ -6,7 +6,7 @@ import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { IsActive } from '@app/core/common/enum/is-active.enum'; import { IsActive } from '@app/core/common/enum/is-active.enum';
import { AppPermission } from '@app/core/common/enum/permission.enum'; import { AppPermission } from '@app/core/common/enum/permission.enum';
import { Description, DescriptionPersist } from '@app/core/model/description/description'; import { Description, DescriptionPersist, DescriptionStatusPersist } from '@app/core/model/description/description';
import { AuthService } from '@app/core/services/auth/auth.service'; import { AuthService } from '@app/core/services/auth/auth.service';
import { DescriptionTemplateService } from '@app/core/services/description-template/description-template.service'; import { DescriptionTemplateService } from '@app/core/services/description-template/description-template.service';
import { DescriptionService } from '@app/core/services/description/description.service'; import { DescriptionService } from '@app/core/services/description/description.service';
@ -39,6 +39,7 @@ import { PrefillDescriptionDialogComponent } from './prefill-description/prefill
import { ToCEntry } from './table-of-contents/models/toc-entry'; import { ToCEntry } from './table-of-contents/models/toc-entry';
import { ToCEntryType } from './table-of-contents/models/toc-entry-type.enum'; import { ToCEntryType } from './table-of-contents/models/toc-entry-type.enum';
import { TableOfContentsComponent } from './table-of-contents/table-of-contents.component'; import { TableOfContentsComponent } from './table-of-contents/table-of-contents.component';
import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
@Component({ @Component({
selector: 'app-description-editor-component', selector: 'app-description-editor-component',
@ -272,6 +273,11 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
} }
}) })
} }
if(this.route.snapshot.url[1] && this.route.snapshot.url[1].path == 'finalize' && !this.lockStatus && !this.viewOnly) {
setTimeout(() => {
this.finalize();
}, 0);
}
// if (this.itemId != null && this.newDmpId == null) { // if (this.itemId != null && this.newDmpId == null) {
// this.isNew = false; // this.isNew = false;
@ -639,10 +645,11 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
} }
formSubmit(): void { formSubmit(): void {
this.formService.removeAllBackEndErrors(this.formGroup);
this.formService.touchAllFormFields(this.formGroup); this.formService.touchAllFormFields(this.formGroup);
// if (!this.isFormValid()) { if (!this.isFormValid()) {
// return; return;
// } }
this.persistEntity(); this.persistEntity();
} }
@ -971,10 +978,59 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
} }
finalize() { finalize() {
// if (this.checkValidity()) { this.formService.removeAllBackEndErrors(this.formGroup);
// this.formGroup.get('status').setValue(DescriptionStatus.Finalized); this.formService.touchAllFormFields(this.formGroup);
// this.formSubmit(); if (!this.isFormValid()) {
// } this.dialog.open(FormValidationErrorsDialogComponent, {
data: {
errorMessages: [this.language.instant('DESCRIPTION-EDITOR.MESSAGES.MISSING-FIELDS')]
}
})
this.formService.touchAllFormFields(this.formGroup);
return;
}
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.formGroup.get('status').setValue(DescriptionStatus.Finalized);
this.persistEntity();
}});
}
reverse() {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
restoreFocus: false,
data: {
message: this.language.instant('DESCRIPTION-EDITOR.ACTIONS.UNDO-FINALIZATION-QUESTION'),
confirmButton: this.language.instant('DESCRIPTION-EDITOR.ACTIONS.CONFIRM'),
cancelButton: this.language.instant('DESCRIPTION-EDITOR.ACTIONS.REJECT'),
isDeleteConfirmation: false
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
const dmpUserRemovePersist: DescriptionStatusPersist = {
id: this.formGroup.get('id').value,
status: DescriptionStatus.Draft,
hash: this.formGroup.get('hash').value
};
this.descriptionService.persistStatus(dmpUserRemovePersist, DescriptionEditorResolver.lookupFields()).pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.prepareForm(data);
this.onCallbackSuccess()
}, (error: any) => {
this.onCallbackError(error)
});
}});
} }
} }

View File

@ -18,7 +18,7 @@ export class DescriptionEditorModel extends BaseEditorModel implements Descripti
status: DescriptionStatus; status: DescriptionStatus;
description: string; description: string;
properties: DescriptionPropertyDefinitionEditorModel = new DescriptionPropertyDefinitionEditorModel(this.validationErrorModel); properties: DescriptionPropertyDefinitionEditorModel = new DescriptionPropertyDefinitionEditorModel(this.validationErrorModel);
tags: string[]; tags: string[] = [];
references: DescriptionReferenceEditorModel[]; references: DescriptionReferenceEditorModel[];
permissions: string[]; permissions: string[];
@ -470,11 +470,11 @@ export class DescriptionFieldEditorModel implements DescriptionFieldPersist {
const baseContext: ValidationContext = new ValidationContext(); const baseContext: ValidationContext = new ValidationContext();
const baseValidationArray: Validation[] = new Array<Validation>(); const baseValidationArray: Validation[] = new Array<Validation>();
baseValidationArray.push({ key: 'textValue', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}textValue`)] }); baseValidationArray.push({ key: 'textValue', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}textValue`)] });
baseValidationArray.push({ key: 'textListValue', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}textListValue`)] }); baseValidationArray.push({ key: 'textListValue', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}textListValue`)] });
baseValidationArray.push({ key: 'dateValue', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}dateValue`)] }); baseValidationArray.push({ key: 'dateValue', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}dateValue`)] });
baseValidationArray.push({ key: 'references', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}references`)] }); baseValidationArray.push({ key: 'references', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}references`)] });
baseValidationArray.push({ key: 'reference', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}references`)] }); baseValidationArray.push({ key: 'reference', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}references`)] });
baseValidationArray.push({ key: 'externalIdentifier', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}externalIdentifier`)] }); baseValidationArray.push({ key: 'externalIdentifier', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}externalIdentifier`)] });
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
@ -551,8 +551,8 @@ export class DescriptionExternalIdentifierEditorModel implements DescriptionExte
const baseContext: ValidationContext = new ValidationContext(); const baseContext: ValidationContext = new ValidationContext();
const baseValidationArray: Validation[] = new Array<Validation>(); const baseValidationArray: Validation[] = new Array<Validation>();
baseValidationArray.push({ key: 'identifier', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}identifier`)] }); baseValidationArray.push({ key: 'identifier', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}identifier`)] });
baseValidationArray.push({ key: 'type', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}type`)] }); baseValidationArray.push({ key: 'type', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}type`)] });
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
} }

View File

@ -121,6 +121,7 @@ export class DescriptionEditorResolver extends BaseEditorResolver {
return [ return [
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.id)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.id)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.label)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.label)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.status)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.isActive)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.isActive)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.id)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.id)].join('.'),

View File

@ -27,6 +27,23 @@ const routes: Routes = [
} }
} }
}, },
{
path: ':id/finalize',
canActivate: [AuthGuard],
component: DescriptionEditorComponent,
canDeactivate: [PendingChangesGuard],
resolve: {
'entity': DescriptionEditorResolver
},
data: {
...BreadcrumbService.generateRouteDataConfiguration({
title: 'BREADCRUMBS.EDIT-DESCRIPTION'
}),
authContext: {
permissions: [AppPermission.EditDescription]
}
}
},
{ {
path: ':dmpId/:dmpSectionId', path: ':dmpId/:dmpSectionId',
canActivate: [AuthGuard], canActivate: [AuthGuard],

View File

@ -395,7 +395,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
takeUntil(this._destroyed) takeUntil(this._destroyed)
) )
.subscribe(_ => { .subscribe(_ => {
this.router.navigate(['descriptions', 'edit', description.id, 'finalize']); this.router.navigate(['descriptions/edit/' + description.id + '/finalize']);
}) })
} }
@ -409,7 +409,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
data: { data: {
message: this.language.instant('DESCRIPTION-OVERVIEW.UNDO-FINALIZATION-DIALOG.TITLE'), message: this.language.instant('DESCRIPTION-OVERVIEW.UNDO-FINALIZATION-DIALOG.TITLE'),
confirmButton: this.language.instant('DESCRIPTION-OVERVIEW.UNDO-FINALIZATION-DIALOG.CONFIRM'), confirmButton: this.language.instant('DESCRIPTION-OVERVIEW.UNDO-FINALIZATION-DIALOG.CONFIRM'),
cancelButton: this.language.instant('DESCRIPTION-OVERVIEW.UNDO-FINALIZATION-DIALOG.CANCEL'), cancelButton: this.language.instant('DESCRIPTION-OVERVIEW.UNDO-FINALIZATION-DIALOG.NEGATIVE'),
isDeleteConfirmation: false isDeleteConfirmation: false
} }
}); });
@ -438,6 +438,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
nameof<Description>(x => x.description), nameof<Description>(x => x.description),
nameof<Description>(x => x.status), nameof<Description>(x => x.status),
nameof<Description>(x => x.updatedAt), nameof<Description>(x => x.updatedAt),
nameof<Description>(x => x.hash),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'), [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.descriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'), [nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.groupId)].join('.'),
@ -447,6 +448,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.id)].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.label)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.accessType)].join('.'), [nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.accessType)].join('.'),
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.status)].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.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.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.user.name)].join('.'),

View File

@ -0,0 +1,82 @@
<div class="row d-flex flex-row">
<div mat-dialog-title class="col-auto">{{ 'DMP-FINALISE-DIALOG.TITLE' | translate }}</div>
<div class="col-auto close-btn ml-auto" (click)="close()">
<mat-icon>close</mat-icon>
</div>
</div>
<div mat-dialog-content class="pt-2 pb-2">
<div class="container">
<mat-accordion [multi]="true">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'DMP-FINALISE-DIALOG.DMP' | translate }}
</mat-panel-title>
<mat-panel-description class="dmp-title">
{{ dmp.label }}
</mat-panel-description>
</mat-expansion-panel-header>
{{ dmp.description }}
</mat-expansion-panel>
<mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'DMP-FINALISE-DIALOG.DESCRPIPTIONS' | translate }}
</mat-panel-title>
<mat-panel-description></mat-panel-description>
</mat-expansion-panel-header>
<div *ngIf="dmp.descriptions.length > 0">
<div *ngFor="let description of dmp.descriptions" class="row pl-3 descriptions">
<mat-icon *ngIf="description.status == descriptionStatusEnum.Draft" class="col-1 draft-bookmark">bookmark</mat-icon>
<mat-icon *ngIf="description.status == descriptionStatusEnum.Finalized" class="col-1 finalized-bookmark">bookmark</mat-icon>
<h4 *ngIf="description.status == descriptionStatusEnum.Draft" class="col-11 ml-auto mt-1 mb-4">
<span>{{ 'TYPES.DATASET-STATUS.DRAFT' | translate }}
<ng-container *ngIf="!isDescriptionValid(description.id)">
({{'DMP-FINALISE-DIALOG.INVALID' | translate}})
</ng-container>
:</span>
{{ description.label }}
<i *ngIf="isDescriptionValid(description.id)" class="fa fa-spinner fa-spin" ></i>
</h4>
<h4 *ngIf="description.status == descriptionStatusEnum.Finalized" class="col-11 ml-auto mt-1 mb-4">{{ description.label }}</h4>
</div>
</div>
<div *ngIf="dmp.descriptions.length === 0" class="emptyList">{{ 'DMP-FINALISE-DIALOG.EMPTY' | translate }} </div>
</mat-expansion-panel>
</mat-accordion>
<div *ngIf="validDraftDescriptions.length > 0" class="pt-4 pb-2">
<h4 class="pl-2">{{'DMP-FINALISE-DIALOG.FINALISE-TITLE' | translate}}</h4>
<mat-selection-list [(ngModel)]="descriptionsToBeFinalized">
<div class="styleBorder" *ngFor="let description of validDraftDescriptions">
<mat-list-option [value]='description.id' [disabled]="!isDescriptionValid(description.id)">
<span class="text-truncate" [matTooltip]="description.label">{{ description.label }}</span>
</mat-list-option>
</div>
</mat-selection-list>
</div>
<mat-error *ngIf="getFinalizedDescriptions().length === 0 && descriptionsToBeFinalized.length === 0">
{{'DMP-FINALISE-DIALOG.VALIDATION.AT-LEAST-ONE-DESCRPIPTION-FINALISED' | translate}}
</mat-error>
</div>
</div>
<div *ngIf="getFinalizedDescriptions().length != 0">
<div class="row pt-2 pb-2 pl-4 pr-4">
{{ 'DMP-FINALISE-DIALOG.IMPACT' | translate }}
</div>
<div *ngIf="dmp.accessType == dmpAccessTypeEnum.Public" class="row pl-4 pr-4">
{{ 'DMP-FINALISE-DIALOG.PUBLIC-DMP-MESSAGE' | translate }}
</div>
<div *ngIf="dmp.accessType == dmpAccessTypeEnum.Restricted" class="row pl-4 pr-4">
{{ 'DMP-FINALISE-DIALOG.RESTRICTED-DMP-MESSAGE' | translate }}
</div>
</div>
<div mat-dialog-actions class="d-flex justify-content-end mb-1">
<div class="col-auto">
<button mat-raised-button cdkFocusInitial (click)="close()" class="cancel-btn">{{ 'DMP-FINALISE-DIALOG.ACTIONS.CANCEL' | translate }}</button>
</div>
<div class="col-auto">
<button mat-raised-button [disabled]="getFinalizedDescriptions().length === 0 && descriptionsToBeFinalized.length === 0" class="submit-btn" (click)="onSubmit()">{{ 'DMP-FINALISE-DIALOG.ACTIONS.SUBMIT' | translate }}</button>
</div>
</div>

View File

@ -25,7 +25,7 @@
} }
} }
.dataset-card { .description-card {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-width: 0; min-width: 0;
@ -65,7 +65,7 @@
cursor: pointer; cursor: pointer;
} }
.datasets span { .descriptions span {
color: var(--primary-color-3); color: var(--primary-color-3);
} }

View File

@ -0,0 +1,78 @@
import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { DmpAccessType } from '@app/core/common/enum/dmp-access-type';
import { Dmp } from '@app/core/model/dmp/dmp';
import { DescriptionService } from '@app/core/services/description/description.service';
import { BaseComponent } from '@common/base/base.component';
import { Guid } from '@common/types/guid';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-dmp-finalize-dialog-component',
templateUrl: 'dmp-finalize-dialog.component.html',
styleUrls: ['./dmp-finalize-dialog.component.scss']
})
export class DmpFinalizeDialogComponent extends BaseComponent implements OnInit {
dmp: Dmp;
dmpAccessTypeEnum = DmpAccessType;
descriptionStatusEnum = DescriptionStatus;
descriptionValidationOutputEnum = DescriptionValidationOutput;
validationResults: DescriptionValidationResult[] = [];
descriptionsToBeFinalized: Guid[] = [];
constructor(
public router: Router,
public dialogRef: MatDialogRef<DmpFinalizeDialogComponent>,
public descriptionService: DescriptionService,
@Inject(MAT_DIALOG_DATA) public data: any
) {
super();
this.dmp = data.dmp;
}
ngOnInit(): void {
this.validateDescriptions(this.dmp);
}
isDescriptionValid(descriptionId: Guid): boolean {
return this.validationResults.find(x => x.descriptionId == descriptionId)?.result === DescriptionValidationOutput.Valid;
}
onSubmit() {
this.dialogRef.close(this.descriptionsToBeFinalized);
}
getFinalizedDescriptions() {
return this.dmp.descriptions.filter(x => x.status === DescriptionStatus.Finalized);
}
close() {
this.dialogRef.close(null);
}
validateDescriptions(dmp: Dmp) {
if (!dmp.descriptions.some(x => x.status == DescriptionStatus.Draft)) return;
this.descriptionService.validate(dmp.descriptions.filter(x => x.status == DescriptionStatus.Draft).map(x => x.id)).pipe(takeUntil(this._destroyed),
).subscribe(result => {
this.validationResults = result;
});
}
get validDraftDescriptions() {
return this.dmp.descriptions.filter(x => this.validationResults.some(y => y.descriptionId == x.id && y.result == DescriptionValidationOutput.Valid));
}
}
export interface DescriptionValidationResult {
descriptionId: Guid;
result: DescriptionValidationOutput;
}
export enum DescriptionValidationOutput {
Valid = 1,
Invalid = 2
}

View File

@ -0,0 +1,15 @@
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { RichTextEditorModule } from "@app/library/rich-text-editor/rich-text-editor.module";
import { CommonUiModule } from '@common/ui/common-ui.module';
import { DmpFinalizeDialogComponent } from './dmp-finalize-dialog.component';
@NgModule({
imports: [CommonUiModule, FormsModule, ReactiveFormsModule, AutoCompleteModule, RichTextEditorModule],
declarations: [DmpFinalizeDialogComponent],
exports: [DmpFinalizeDialogComponent]
})
export class DmpFinalizeDialogModule {
constructor() { }
}

View File

@ -1,188 +0,0 @@
<div class="row d-flex flex-row">
<div mat-dialog-title class="col-auto">{{ data.message }}</div>
<div class="col-auto close-btn ml-auto" (click)="close()">
<mat-icon>close</mat-icon>
</div>
</div>
<div mat-dialog-content class="pt-2 pb-2">
<div class="container">
<mat-accordion [multi]="true">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'DMP-FINALISE-DIALOG.DMP' | translate }}
</mat-panel-title>
<mat-panel-description class="dmp-title">
{{ inputModel.dmpLabel }}
</mat-panel-description>
</mat-expansion-panel-header>
{{ inputModel.dmpDescription }}
</mat-expansion-panel>
<mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'DMP-FINALISE-DIALOG.DATASETS' | translate }}
</mat-panel-title>
<mat-panel-description></mat-panel-description>
</mat-expansion-panel-header>
<div *ngIf="inputModel.datasets.length > 0">
<div *ngFor="let dataset of inputModel.datasets" class="row pl-3 datasets">
<mat-icon *ngIf="dataset.status == 0" class="col-1 draft-bookmark">bookmark</mat-icon>
<mat-icon *ngIf="dataset.status != 0" class="col-1 finalized-bookmark">bookmark</mat-icon>
<h4 *ngIf="dataset.status == 0" class="col-11 ml-auto mt-1 mb-4">
<span>{{ 'TYPES.DATASET-STATUS.DRAFT' | translate }}
<ng-container *ngIf="datasetLookupStatus[dataset.id] && (datasetLookupStatus[dataset.id] === datasetLookupStatusEnum.INVALID)">
({{'DMP-FINALISE-DIALOG.INVALID' | translate}})
</ng-container>
:</span>
{{ dataset.label }}
<i *ngIf="(datasetLookupStatus[dataset.id] != datasetLookupStatusEnum.INVALID) && (datasetLookupStatus[dataset.id] != datasetLookupStatusEnum.VALID) " class="fa fa-spinner fa-spin" ></i>
</h4>
<h4 *ngIf="dataset.status != 0" class="col-11 ml-auto mt-1 mb-4">{{ dataset.label }}</h4>
</div>
</div>
<div *ngIf="inputModel.datasets.length === 0" class="emptyList">{{ 'DMP-FINALISE-DIALOG.EMPTY' | translate }} </div>
</mat-expansion-panel>
</mat-accordion>
<div *ngIf="validDrafts.length > 0" class="pt-4 pb-2">
<h4 class="pl-2">{{'DMP-FINALISE-DIALOG.FINALISE-TITLE' | translate}}</h4>
<mat-selection-list #datasetsDraftSelectionList [(ngModel)]="outputModel.datasetsToBeFinalized">
<div class="styleBorder" *ngFor="let dataset of validDrafts">
<mat-list-option [value]='dataset.id' [disabled]="!datasetLookupStatus[dataset.id] || (datasetLookupStatus[dataset.id] != datasetLookupStatusEnum.VALID)">
<span class="text-truncate" [matTooltip]="dataset.label">{{ dataset.label }}</span>
</mat-list-option>
</div>
</mat-selection-list>
</div>
<mat-error *ngIf="getFinalizedDatasets().length === 0 && outputModel.datasetsToBeFinalized.length === 0">
{{'DMP-FINALISE-DIALOG.VALIDATION.AT-LEAST-ONE-DATASET-FINALISED' | translate}}
</mat-error>
</div>
</div>
<div *ngIf="getFinalizedDatasets().length != 0">
<div class="row pt-2 pb-2 pl-4 pr-4">
{{ 'DMP-FINALISE-DIALOG.IMPACT' | translate }}
</div>
<div *ngIf="inputModel.accessRights" class="row pl-4 pr-4">
{{ 'DMP-FINALISE-DIALOG.AFTER-FINALIZATION-PUBLISH' | translate }}
</div>
<div *ngIf="!inputModel.accessRights" class="row pl-4 pr-4">
{{ 'DMP-FINALISE-DIALOG.AFTER-FINALIZATION-RESTRICT-ACCESS' | translate }}
</div>
</div>
<div mat-dialog-actions class="d-flex justify-content-end mb-1">
<div class="col-auto">
<button mat-raised-button cdkFocusInitial (click)="close()" class="cancel-btn">{{ data.cancelButton }}</button>
</div>
<div class="col-auto">
<button mat-raised-button [disabled]="getFinalizedDatasets().length === 0 && outputModel.datasetsToBeFinalized.length === 0" class="submit-btn" (click)="onSubmit()">{{ data.confirmButton }}</button>
</div>
</div>
<!-- <form *ngIf="formGroup" (ngSubmit)="onSubmit()">
<div class="row d-flex flex-row">
<div mat-dialog-title class="col-auto">{{ data.message }}</div>
<div class="col-auto close-btn ml-auto" (click)="close()">
<mat-icon>close</mat-icon>
</div>
</div>
<div mat-dialog-content *ngIf="datasetsFinalized && datasetsDraft" class="pt-2 pb-2">
<mat-accordion [multi]="true">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'DMP-FINALISE-DIALOG.DMP' | translate }}
</mat-panel-title>
<mat-panel-description class="dmp-title">
{{ formGroup.get('label').value }}
</mat-panel-description>
</mat-expansion-panel-header>
{{ formGroup.get('description').value }}
</mat-expansion-panel>
<mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'DMP-FINALISE-DIALOG.DATASETS' | translate }}
</mat-panel-title>
<mat-panel-description></mat-panel-description>
</mat-expansion-panel-header>
<div *ngIf="allDatasets.length > 0">
<div *ngFor="let dataset of allDatasets" class="row pl-3 datasets">
<mat-icon *ngIf="isDraft(dataset)" class="col-1 draft-bookmark">bookmark</mat-icon>
<mat-icon *ngIf="!isDraft(dataset)" class="col-1 finalized-bookmark">bookmark</mat-icon>
<h4 *ngIf="isDraft(dataset)" class="col-11 ml-auto mt-1 mb-4">
<span>{{ 'TYPES.DATASET-STATUS.DRAFT' | translate }}:</span>
{{ dataset.label }}</h4>
<h4 *ngIf="!isDraft(dataset)" class="col-11 ml-auto mt-1 mb-4">{{ dataset.label }}</h4>
</div>
</div>
<div *ngIf="allDatasets.length === 0" class="emptyList">{{ 'DMP-FINALISE-DIALOG.EMPTY' | translate }} </div>
</mat-expansion-panel>
</mat-accordion>
<div *ngIf="datasetsDraft.length > 0" class="pt-4 pb-2">
<h4 class="pl-2">{{'DMP-FINALISE-DIALOG.FINALISE-TITLE' | translate}}</h4>
<mat-selection-list #datasetsDraftSelectionList [ngModel]="outputModel.datasetToBeFinalized">
<div class="styleBorder" *ngFor="let dataset of datasetsDraft">
<mat-list-option [value]='dataset.id'>
{{ dataset.label }}
</mat-list-option>
</div>
</mat-selection-list>
</div>
<mat-error *ngIf="datasetsFinalized.length == 0">{{'DMP-FINALISE-DIALOG.VALIDATION.AT-LEAST-ONE-DATASET-FINALISED'
| translate}}</mat-error>
</div>
<div mat-dialog-content *ngIf="isWizard" class="pt-2 pb-2">
<mat-accordion [multi]="true">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'DMP-FINALISE-DIALOG.DMP' | translate }}
</mat-panel-title>
<mat-panel-description class="dmp-title">
{{ formGroup.get('dmp')?.get('label')?.value }}
</mat-panel-description>
</mat-expansion-panel-header>
{{ formGroup.get('dmp')?.get('description')?.value }}
</mat-expansion-panel>
<mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'DMP-FINALISE-DIALOG.DATASETS' | translate }}
</mat-panel-title>
<mat-panel-description></mat-panel-description>
</mat-expansion-panel-header>
<div *ngIf="allDatasetLabels.length > 0">
<div *ngFor="let label of allDatasetLabels" class="row pl-3 datasets">
<mat-icon class="col-1 finalized-bookmark">bookmark</mat-icon>
<h4 class="col-11 ml-auto mt-1 mb-4">{{ label }}</h4>
</div>
</div>
<div *ngIf="allDatasetLabels.length === 0" class="emptyList"> {{ 'DMP-FINALISE-DIALOG.EMPTY' | translate }}
</div>
</mat-expansion-panel>
</mat-accordion>
</div>
<div *ngIf="datasetsFinalized && datasetsFinalized.length != 0">
<div class="row pt-2 pb-2 pl-4 pr-4">
{{ 'DMP-FINALISE-DIALOG.IMPACT' | translate }}
</div>
<div class="row pl-4 pr-4">
{{ 'DMP-FINALISE-DIALOG.AFTER-FINALIZATION' | translate }}
</div>
</div>
<div mat-dialog-actions class="d-flex justify-content-end">
<div class="col-auto">
<button mat-raised-button class="confirm" (click)="onSubmit()">{{ data.confirmButton }}</button>
</div>
<div class="col-auto">
<button mat-raised-button cdkFocusInitial (click)="close()" class="cancel">{{ data.cancelButton }}</button>
</div>
</div>
</form> -->

View File

@ -1,113 +0,0 @@
import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { BaseComponent } from '@common/base/base.component';
import { Observable, of } from 'rxjs';
import { catchError, map, takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-dmp-finalize-dialog-component',
templateUrl: 'dmp-finalize-dialog.component.html',
styleUrls: ['./dmp-finalize-dialog.component.scss']
})
export class DmpFinalizeDialogComponent extends BaseComponent implements OnInit {
inputModel: DmpFinalizeDialogInput;
outputModel: DmpFinalizeDialogOutput;
protected datasetLookupStatus:DatasetStatusLookup[] = [];
protected datasetLookupStatusEnum = DatasetStatusLookup;
constructor(
public router: Router,
public dialogRef: MatDialogRef<DmpFinalizeDialogComponent>,
public datasetService: DatasetService,
@Inject(MAT_DIALOG_DATA) public data: any
) {
super();
this.inputModel = data['dialogInputModel'];
this.outputModel = { datasetsToBeFinalized: [] };
}
ngOnInit(): void {
this.inputModel.datasets.forEach(ds=>{
this.validateDataset(ds.id).subscribe(_=>{
console.log('response', _);
});
})
const drafts = this.getDraftDatasets();
drafts.forEach(draft=>{
this.datasetLookupStatus[draft.id] == DatasetStatusLookup.PENDING_VALIDATION;
this.validateDataset(draft.id)
.subscribe(isValid=>{
if(isValid){
this.datasetLookupStatus[draft.id] = DatasetStatusLookup.VALID;
}else{
this.datasetLookupStatus[draft.id] = DatasetStatusLookup.INVALID;
}
})
});
}
onSubmit() {
this.dialogRef.close(this.outputModel);
}
getFinalizedDatasets() {
return this.inputModel.datasets.filter(x => x.status === DatasetStatus.Finalized);
}
getDraftDatasets() {
return this.inputModel.datasets.filter(x => x.status === DatasetStatus.Draft);
}
close() {
this.dialogRef.close({ cancelled: true } as DmpFinalizeDialogOutput);
}
validateDataset(datasetId: string) : Observable<boolean>{
return this.datasetService
.validateDataset(datasetId)
.pipe(
takeUntil(this._destroyed),
map(_=>{
return true
}),
catchError(error=>{
return of(false);
})
);
}
get validDrafts(){
return this.getDraftDatasets().filter(x=> this.datasetLookupStatus[x.id] && (this.datasetLookupStatus[x.id] == DatasetStatusLookup.VALID));
}
}
export interface DmpFinalizeDialogInput {
dmpLabel: string;
dmpDescription: string;
datasets: DmpFinalizeDialogDataset[];
accessRights: boolean;
}
export interface DmpFinalizeDialogDataset {
label: string;
id?: string;
status: DatasetStatus;
}
export interface DmpFinalizeDialogOutput {
cancelled?: boolean;
datasetsToBeFinalized?: string[];
}
enum DatasetStatusLookup{
VALID = "VALID",
INVALID = "INVALID",
PENDING_VALIDATION = "PENDING"
}

View File

@ -44,6 +44,7 @@ import { NewVersionDmpDialogComponent } from '../new-version-dialog/dmp-new-vers
import { AppPermission } from '@app/core/common/enum/permission.enum'; import { AppPermission } from '@app/core/common/enum/permission.enum';
import { ReferenceType } from '@app/core/model/reference-type/reference-type'; import { ReferenceType } from '@app/core/model/reference-type/reference-type';
import { IsActive } from '@app/core/common/enum/is-active.enum'; import { IsActive } from '@app/core/common/enum/is-active.enum';
import { DmpFinalizeDialogComponent } from '../dmp-finalize-dialog/dmp-finalize-dialog.component';
@Component({ @Component({
selector: 'app-dmp-overview', selector: 'app-dmp-overview',
@ -493,69 +494,27 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
} }
finalize() { finalize() {
//TODO: add this const dialogRef = this.dialog.open(DmpFinalizeDialogComponent, {
// const extraProperties = new ExtraPropertiesFormModel(); maxWidth: '500px',
// this.dmpService.getSingle(this.dmp.id).pipe(map(data => data as Dmp)) restoreFocus: false,
// .pipe(takeUntil(this._destroyed)) autoFocus: false,
// .subscribe(data => { data: {
dmp: this.dmp
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe((descriptionsToBeFinalized: Guid[]) => {
if (descriptionsToBeFinalized && descriptionsToBeFinalized.length > 0) {
// if (!isNullOrUndefined(data.extraProperties)) {
// extraProperties.fromModel(data.extraProperties);
// }
// const dialogInputModel: DmpFinalizeDialogInput = {
// dmpLabel: this.dmp.label,
// dmpDescription: this.dmp.description,
// descriptions: this.dmp.descriptions.map(x => {
// return { label: x.label, id: x.id, status: x.status }
// }),
// accessRights: extraProperties.visible
// }
// const dialogRef = this.dialog.open(DmpFinalizeDialogComponent, {
// maxWidth: '500px',
// restoreFocus: false,
// autoFocus: false,
// data: {
// dialogInputModel: dialogInputModel,
// message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.FINALIZE-ITEM'),
// confirmButton: this.language.instant('DMP-FINALISE-DIALOG.SUBMIT'),
// cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
// }
// });
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe((result: DmpFinalizeDialogOutput) => {
// if (result && !result.cancelled) {
// this.checkIfAnyProfileIsUsedLessThanMin(data).subscribe(checked => {
// if (!checked) {
// var descriptionsToBeFinalized: DescriptionsToBeFinalized = {
// uuids: result.descriptionsToBeFinalized
// };
// this.dmpService.finalize(descriptionsToBeFinalized, this.dmp.id) // this.dmpService.finalize(descriptionsToBeFinalized, this.dmp.id)
// .pipe(takeUntil(this._destroyed)) // .pipe(takeUntil(this._destroyed))
// .subscribe( // .subscribe(
// complete => { // complete => {
// if (extraProperties.visible) {
// //this.publish(this.dmp.id);
// this.dmpService.publish(this.dmp.id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(() => {
// //this.hasPublishButton = false;
// this.dmp.status = DmpStatus.Finalized;
// this.onUpdateCallbackSuccess();
// });
// }
// else {
// this.dmp.status = DmpStatus.Finalized;
// this.onUpdateCallbackSuccess();
// }
// }, // },
// error => this.onUpdateCallbackError(error) // error => this.onUpdateCallbackError(error)
// ); // );
// } }
// }) });
// }
// });
// });
} }

View File

@ -7,6 +7,7 @@ import { CommonFormsModule } from '@common/forms/common-forms.module';
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
import { CommonUiModule } from '@common/ui/common-ui.module'; import { CommonUiModule } from '@common/ui/common-ui.module';
import { NgDialogAnimationService } from 'ng-dialog-animation'; import { NgDialogAnimationService } from 'ng-dialog-animation';
import { DmpFinalizeDialogModule } from '../dmp-finalize-dialog/dmp-finalize-dialog.module';
import { DmpOverviewRoutingModule } from './dmp-overview.routing'; import { DmpOverviewRoutingModule } from './dmp-overview.routing';
@NgModule({ @NgModule({
@ -16,7 +17,8 @@ import { DmpOverviewRoutingModule } from './dmp-overview.routing';
ConfirmationDialogModule, ConfirmationDialogModule,
FormattingModule, FormattingModule,
AutoCompleteModule, AutoCompleteModule,
DmpOverviewRoutingModule DmpOverviewRoutingModule,
DmpFinalizeDialogModule
], ],
declarations: [ declarations: [
DmpOverviewComponent, DmpOverviewComponent,

View File

@ -1,15 +1,15 @@
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { FormArray, UntypedFormArray, UntypedFormGroup } from '@angular/forms'; import { FormArray } from '@angular/forms';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
import { DmpUserType } from '@app/core/common/enum/dmp-user-type';
import { DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { UserService } from '@app/core/services/user/user.service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { BaseComponent } from '@common/base/base.component'; import { BaseComponent } from '@common/base/base.component';
import { DmpEditorModel, DmpUserEditorModel } from '../dmp-editor-blueprint/dmp-editor.model';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; import { DmpEditorModel, DmpUserEditorModel } from '../dmp-editor-blueprint/dmp-editor.model';
import { DmpUserType } from '@app/core/common/enum/dmp-user-type';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
import { UserService } from '@app/core/services/user/user.service';
import { DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
@Component({ @Component({
selector: 'app-user-field-component', selector: 'app-user-field-component',

View File

@ -41,6 +41,8 @@ export class TagsComponent extends BaseComponent implements OnInit {
} }
add(event: MatChipInputEvent): void { add(event: MatChipInputEvent): void {
if(this.form.disabled == true) return;
const value = (event.value || '').trim(); const value = (event.value || '').trim();
// Add our tag // Add our tag
@ -51,10 +53,12 @@ export class TagsComponent extends BaseComponent implements OnInit {
// Clear the input value // Clear the input value
event.chipInput!.clear(); event.chipInput!.clear();
this.form.setValue(null); this.form.setValue(this.tags);
} }
remove(tag: string): void { remove(tag: string): void {
if(this.form.disabled == true) return;
const index = this.tags.indexOf(tag); const index = this.tags.indexOf(tag);
if (index >= 0) { if (index >= 0) {
@ -65,6 +69,6 @@ export class TagsComponent extends BaseComponent implements OnInit {
selected(event: MatAutocompleteSelectedEvent): void { selected(event: MatAutocompleteSelectedEvent): void {
this.tags.push(event.option.viewValue); this.tags.push(event.option.viewValue);
this.tagInput.nativeElement.value = ''; this.tagInput.nativeElement.value = '';
this.form.setValue(null); this.form.setValue(this.tags);
} }
} }

View File

@ -60,7 +60,6 @@
"CONFIRMATION-DIALOG": { "CONFIRMATION-DIALOG": {
"DELETE-ITEM": "Delete this item?", "DELETE-ITEM": "Delete this item?",
"DELETE-USER": "Remove this collaborator?", "DELETE-USER": "Remove this collaborator?",
"FINALIZE-ITEM": "Finalize this item?",
"UNFINALIZE-ITEM": "Undo Finalization?", "UNFINALIZE-ITEM": "Undo Finalization?",
"PUBLISH-ITEM": "Publish this item?", "PUBLISH-ITEM": "Publish this item?",
"ADD-DATASET": "Do you want to continue by adding a Dataset to your DMP? You can always add more Datasets using \"Add Dataset (Wizard)\" menu.", "ADD-DATASET": "Do you want to continue by adding a Dataset to your DMP? You can always add more Datasets using \"Add Dataset (Wizard)\" menu.",
@ -1023,6 +1022,7 @@
"CANCEL": "Cancel" "CANCEL": "Cancel"
}, },
"UNDO-FINALIZATION-DIALOG": { "UNDO-FINALIZATION-DIALOG": {
"TITLE": "Undo Finalization?",
"CONFIRM": "Yes", "CONFIRM": "Yes",
"NEGATIVE": "No" "NEGATIVE": "No"
}, },
@ -1103,7 +1103,14 @@
"SAVE-AND-ADD-NEW": "Save & Add New", "SAVE-AND-ADD-NEW": "Save & Add New",
"SAVE-AND-CLOSE": "Save & Close", "SAVE-AND-CLOSE": "Save & Close",
"FINALIZE": "Finalize", "FINALIZE": "Finalize",
"DISCARD": "Discard" "DISCARD": "Discard",
"REVERSE": "Undo Finalization",
"UNDO-FINALIZATION-QUESTION": "Undo finalization?",
"CONFIRM": "Yes",
"REJECT": "No"
},
"MESSAGES":{
"MISSING-FIELDS": "There are some required fields left unfilled. Please check the DMP and make sure that all required questions are answered and URLs are provided with valid input. (Missing fields are marked in red color)"
} }
}, },
"DESCRIPTION-COPY-DIALOG": { "DESCRIPTION-COPY-DIALOG": {
@ -1431,9 +1438,7 @@
"UNSUCCESSFUL-DELETE": "This item could not be deleted." "UNSUCCESSFUL-DELETE": "This item could not be deleted."
}, },
"INAPP-NOTIFICATION-EDITOR": { "INAPP-NOTIFICATION-EDITOR": {
"FIELDS": { "FIELDS": {},
},
"ACTIONS": { "ACTIONS": {
"CANCEL": "Cancel", "CANCEL": "Cancel",
"DELETE": "Delete" "DELETE": "Delete"
@ -2751,7 +2756,7 @@
"DESCRIPTIONS": "Descriptions", "DESCRIPTIONS": "Descriptions",
"DATASET-DESCRIPTIONS-DASHBOARD-TEXT": "Datasets", "DATASET-DESCRIPTIONS-DASHBOARD-TEXT": "Datasets",
"PUBLIC-DMPS": "Public DMPs", "PUBLIC-DMPS": "Public DMPs",
"PUBLIC-DATASETS": "Public Datasets", "PUBLIC-DESCRIPTIONS": "Public Descriptions",
"RELATED-ORGANISATIONS": "Related Organizations", "RELATED-ORGANISATIONS": "Related Organizations",
"DRAFTS": "Drafts", "DRAFTS": "Drafts",
"ALL": "All", "ALL": "All",
@ -2907,20 +2912,22 @@
} }
}, },
"DMP-FINALISE-DIALOG": { "DMP-FINALISE-DIALOG": {
"TITLE": "Finalize this item?",
"DMP": "DMP", "DMP": "DMP",
"DATASETS": "Datasets", "DESCRPIPTIONS": "Descriptions",
"EMPTY": "No Datasets for this DMP so far", "EMPTY": "No Descriptions for this DMP so far",
"SUBMIT": "Submit", "FINALISE-TITLE": "Do you want to finalize any of the following Draft Descriptions?",
"FINALISE-TITLE": "Do you want to finalize any of the following Draft Datasets?",
"ALREADY-FINALISED-DATASETS": "Already Finalized Datasets",
"NONE": "None",
"VALIDATION": { "VALIDATION": {
"AT-LEAST-ONE-DATASET-FINALISED": "You need to have at least one Dataset Finalized" "AT-LEAST-ONE-DESCRPIPTION-FINALISED": "You need to have at least one Description Finalized"
}, },
"IMPACT": "This action will finalize your DMP, and you won't be able to edit it again.", "IMPACT": "This action will finalize your DMP, and you won't be able to edit it again.",
"AFTER-FINALIZATION-PUBLISH": "After finalizing your DMP, it'll be published and be publicly available to the {{ APP_NAME_CAPS }} tool.", "PUBLIC-DMP-MESSAGE": "After finalizing your DMP, it'll be published and be publicly available to the {{ APP_NAME_CAPS }} tool.",
"AFTER-FINALIZATION-RESTRICT-ACCESS": "Your DMP can be published and be publicly available to the {{ APP_NAME_CAPS }} tool after finalization when its access rights are opened. Current access rights: restricted", "RESTRICTED-DMP-MESSAGE": "Your DMP can be published and be publicly available to the {{ APP_NAME_CAPS }} tool after finalization when its access rights are opened. Current access rights: restricted",
"INVALID": "Invalid" "INVALID": "Invalid",
"ACTIONS": {
"SUBMIT": "Submit",
"CANCEL": "Cancel"
}
}, },
"DRAFTS": { "DRAFTS": {
"FOR-DMP": "For DMP:", "FOR-DMP": "For DMP:",

View File

@ -63,13 +63,13 @@
</div> </div>
</mat-menu> </mat-menu>
<button mat-icon-button (click)="toggleMode()" *ngIf="(listItemTemplate || cardItemTemplate) && !hideModeSelection" > <!-- <button mat-icon-button (click)="toggleMode()" *ngIf="(listItemTemplate || cardItemTemplate) && !hideModeSelection" >
<ng-container [ngSwitch]="mode"> <ng-container [ngSwitch]="mode">
<mat-icon *ngSwitchCase="HybridListingMode.List">table_view</mat-icon> <mat-icon *ngSwitchCase="HybridListingMode.List">table_view</mat-icon>
<mat-icon *ngSwitchCase="HybridListingMode.Table">list</mat-icon> <mat-icon *ngSwitchCase="HybridListingMode.Table">list</mat-icon>
<mat-icon *ngSwitchCase="HybridListingMode.Card">table_view</mat-icon> <mat-icon *ngSwitchCase="HybridListingMode.Card">table_view</mat-icon>
</ng-container> </ng-container>
</button> </button> -->
<ng-content select="[download-listing-report]" /> <ng-content select="[download-listing-report]" />
</div> </div>

View File

@ -1,4 +1,4 @@
<button mat-button [matMenuTriggerFor]="settingsMenu"> <!-- <button mat-button [matMenuTriggerFor]="settingsMenu">
<ng-container *ngIf="currentUserSetting"> <ng-container *ngIf="currentUserSetting">
@ -40,4 +40,4 @@
</button> </button>
</ng-container> </ng-container>
</ng-container> </ng-container>
</mat-menu> </mat-menu> -->