dashboard changes and add finalize description

This commit is contained in:
amentis 2024-03-14 09:36:07 +02:00
parent f1290a1e56
commit 9d6fbcd3ee
17 changed files with 175 additions and 74 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

@ -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

@ -184,16 +184,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

@ -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

@ -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

@ -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

@ -1023,6 +1023,7 @@
"CANCEL": "Cancel" "CANCEL": "Cancel"
}, },
"UNDO-FINALIZATION-DIALOG": { "UNDO-FINALIZATION-DIALOG": {
"TITLE": "Undo Finalization?",
"CONFIRM": "Yes", "CONFIRM": "Yes",
"NEGATIVE": "No" "NEGATIVE": "No"
}, },
@ -1103,7 +1104,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": {
@ -2751,7 +2759,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",