diff --git a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java index 47280bc7a..ec12294f8 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java +++ b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java @@ -42,7 +42,10 @@ public class AuditableAction { public static final EventId Dmp_PublicQuery = new EventId(5010, "Dmp_PublicQuery"); public static final EventId Dmp_Export = new EventId(5011, "Dmp_Export"); public static final EventId Dmp_PublicLookup = new EventId(5012, "Dmp_PublicLookup"); - + public static final EventId Dmp_Finalize = new EventId(5013, "Dmp_Finalize"); + public static final EventId Dmp_Undo_Finalize = new EventId(5014, "Dmp_Undo_Finalize"); + + public static final EventId Description_Query = new EventId(6000, "Description_Query"); public static final EventId Description_Lookup = new EventId(6001, "Description_Lookup"); public static final EventId Description_Persist = new EventId(6002, "Description_Persist"); @@ -52,6 +55,7 @@ public class AuditableAction { public static final EventId Description_PersistStatus = new EventId(6006, "Description_PersistStatus"); public static final EventId Description_UploadFieldFiles = new EventId(6007, "Description_UploadFieldFiles"); public static final EventId Description_GetFieldFile = new EventId(6008, "Description_GetFieldFile"); + public static final EventId Description_Validate = new EventId(6009, "Description_Validate"); public static final EventId Reference_Query = new EventId(7000, "Reference_Query"); diff --git a/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java b/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java index 82a4c44de..952351b6a 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java +++ b/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java @@ -76,6 +76,7 @@ public final class Permission { public static String CreateNewVersionDmp = "CreateNewVersionDmp"; public static String ExportDmp = "ExportDmp"; public static String FinalizeDmp = "FinalizeDmp"; + public static String UndoFinalizeDmp = "UndoFinalizeDmp"; public static String AssignDmpUsers = "AssignDmpUsers"; public static String InviteDmpUsers = "InviteDmpUsers"; diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/enums/DescriptionValidationOutput.java b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/DescriptionValidationOutput.java new file mode 100644 index 000000000..18a37354c --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/DescriptionValidationOutput.java @@ -0,0 +1,30 @@ +package eu.eudat.commons.enums; + +import com.fasterxml.jackson.annotation.JsonValue; +import eu.eudat.data.converters.enums.DatabaseEnum; + +import java.util.Map; + +public enum DescriptionValidationOutput implements DatabaseEnum { + + Valid((short) 1), + Invalid((short) 2); + + private final Short value; + + DescriptionValidationOutput(Short value) { + this.value = value; + } + + @JsonValue + public Short getValue() { + return value; + } + + private static final Map map = EnumUtils.getEnumValueMap(DescriptionValidationOutput.class); + + public static DescriptionValidationOutput of(Short i) { + return map.get(i); + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/DescriptionValidationResult.java b/dmp-backend/core/src/main/java/eu/eudat/model/DescriptionValidationResult.java new file mode 100644 index 000000000..56dab938f --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/DescriptionValidationResult.java @@ -0,0 +1,40 @@ +package eu.eudat.model; + +import eu.eudat.commons.enums.DescriptionValidationOutput; + +import java.util.UUID; + +public class DescriptionValidationResult { + + private UUID descriptionId; + + public static final String _id = "id"; + + private DescriptionValidationOutput result; + + public static final String _result = "result"; + + public DescriptionValidationResult() { + } + + public DescriptionValidationResult(UUID descriptionId, DescriptionValidationOutput result) { + this.descriptionId = descriptionId; + this.result = result; + } + + public UUID getDescriptionId() { + return descriptionId; + } + + public void setDescriptionId(UUID descriptionId) { + this.descriptionId = descriptionId; + } + + public DescriptionValidationOutput getResult() { + return result; + } + + public void setResult(DescriptionValidationOutput result) { + this.result = result; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/DescriptionsToBeFinalized.java b/dmp-backend/core/src/main/java/eu/eudat/model/DescriptionsToBeFinalized.java new file mode 100644 index 000000000..22476ae34 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/DescriptionsToBeFinalized.java @@ -0,0 +1,17 @@ +package eu.eudat.model; + +import java.util.List; +import java.util.UUID; + +public class DescriptionsToBeFinalized { + + private List descriptionIds; + + public List getDescriptionIds() { + return descriptionIds; + } + + public void setDescriptionIds(List descriptionIds) { + this.descriptionIds = descriptionIds; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionService.java b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionService.java index e6075416f..ebef5ee36 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionService.java @@ -2,6 +2,7 @@ package eu.eudat.service.description; import eu.eudat.data.StorageFileEntity; import eu.eudat.model.Description; +import eu.eudat.model.DescriptionValidationResult; import eu.eudat.model.StorageFile; import eu.eudat.model.persist.DescriptionFieldFilePersist; import eu.eudat.model.persist.DescriptionPersist; @@ -16,6 +17,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.management.InvalidApplicationException; import java.io.IOException; +import java.util.List; import java.util.UUID; public interface DescriptionService { @@ -25,6 +27,8 @@ public interface DescriptionService { void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException, IOException; + List validate(List descriptionIds); + void clone(UUID dmpId, UUID descriptionId) throws InvalidApplicationException, IOException; ResponseEntity export(UUID id, String exportType) throws InvalidApplicationException, IOException; diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java index 2ca8ce0ab..e4e0794c1 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java @@ -26,6 +26,7 @@ import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEvent; import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEventHandler; import eu.eudat.model.*; import eu.eudat.model.builder.DescriptionBuilder; +import eu.eudat.model.builder.DescriptionTemplateBuilder; import eu.eudat.model.deleter.DescriptionDeleter; import eu.eudat.model.deleter.DescriptionReferenceDeleter; import eu.eudat.model.deleter.DescriptionTagDeleter; @@ -365,6 +366,27 @@ public class DescriptionServiceImpl implements DescriptionService { return this.builderFactory.builder(DescriptionBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, Description._id), data); } + public List validate(List descriptionIds){ + List descriptionValidationResults = new ArrayList<>(); + + List descriptions = this.queryFactory.query(DescriptionQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(descriptionIds).isActive(IsActive.Active).collect(); + if (descriptions == null){ + return null; + } + + for (DescriptionEntity description: descriptions) { + DescriptionValidationResult descriptionValidationResult = new DescriptionValidationResult(description.getId(), DescriptionValidationOutput.Invalid); + + //TODO description template + if (!this.conventionService.isNullOrEmpty(description.getLabel()) && description.getDmpId() != null && description.getDescriptionTemplateId() != null && description.getStatus() != null && !this.conventionService.isNullOrEmpty(description.getProperties())){ + descriptionValidationResult.setResult(DescriptionValidationOutput.Valid); + } + descriptionValidationResults.add(descriptionValidationResult); + + } + return descriptionValidationResults; + } + private @NotNull PropertyDefinitionEntity buildPropertyDefinitionEntity(PropertyDefinitionPersist persist, eu.eudat.commons.types.descriptiontemplate.DefinitionEntity definition, Map> fieldToReferenceMap){ PropertyDefinitionEntity data = new PropertyDefinitionEntity(); if (persist == null) return data; diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java index 3e405ea24..50b6dec11 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpService.java @@ -24,6 +24,10 @@ public interface DmpService { void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException, IOException; + void finalize(UUID id, List descriptionIds) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException; + + void undoFinalize(UUID id, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException; + Dmp createNewVersion(NewVersionDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, IOException, TransformerException; Dmp buildClone(CloneDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, IOException, InvalidApplicationException; diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java index 530f61038..b11b7d16a 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/dmp/DmpServiceImpl.java @@ -816,6 +816,72 @@ public class DmpServiceImpl implements DmpService { return null; } + public void finalize(UUID id, List descriptionIds) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException { + this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(id)), Permission.FinalizeDmp); + DmpEntity dmp = this.queryFactory.query(DmpQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(id).isActive(IsActive.Active).first(); + + if (dmp == null){ + throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); + } + + if (dmp.getStatus().equals(DmpStatus.Finalized)){ + throw new MyApplicationException("DMP is already finalized"); + } + + List descriptions = this.queryFactory.query(DescriptionQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(id).isActive(IsActive.Active).collect(); + + for (DescriptionEntity description: descriptions) { + if (descriptionIds.contains(description.getId())){ + // description to be finalized + if (description.getStatus().equals(DescriptionStatus.Finalized)){ + throw new MyApplicationException("Description is already finalized"); + } + description.setStatus(DescriptionStatus.Finalized); + description.setUpdatedAt(Instant.now()); + description.setFinalizedAt(Instant.now()); + this.entityManager.merge(description); + } else if (description.getStatus().equals(DescriptionStatus.Draft)) { + // description to be canceled + description.setStatus(DescriptionStatus.Canceled); + this.deleterFactory.deleter(DescriptionDeleter.class).delete(List.of(description), true); + } + } + + dmp.setStatus(DmpStatus.Finalized); + dmp.setUpdatedAt(Instant.now()); + dmp.setFinalizedAt(Instant.now()); + + this.entityManager.merge(dmp); + this.entityManager.flush(); + this.elasticService.persistDmp(dmp); + this.sendNotification(dmp); + } + + public void undoFinalize(UUID id, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException { + this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(id)), Permission.UndoFinalizeDmp); + DmpEntity dmp = this.queryFactory.query(DmpQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(id).isActive(IsActive.Active).firstAs(fields); + + if (dmp == null){ + throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); + } + + if (dmp.getStatus().equals(DmpStatus.Draft)){ + throw new MyApplicationException("DMP is already drafted"); + } + + EntityDoiQuery entityDoiQuery = this.queryFactory.query(EntityDoiQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).types(EntityType.DMP).entityIds(dmp.getId()); + if (entityDoiQuery != null && entityDoiQuery.count() > 0){ + throw new MyApplicationException("DMP is deposited"); + } + + dmp.setStatus(DmpStatus.Draft); + dmp.setUpdatedAt(Instant.now()); + + this.entityManager.merge(dmp); + this.entityManager.flush(); + this.sendNotification(dmp); + } + // invites public void inviteUserOrAssignUsers(UUID id, List users) throws InvalidApplicationException, JAXBException, IOException { this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(id)), Permission.InviteDmpUsers); diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionController.java index d33850bb9..b155696ea 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionController.java @@ -7,14 +7,11 @@ import eu.eudat.commons.enums.DmpStatus; import eu.eudat.commons.enums.IsActive; import eu.eudat.convention.ConventionService; import eu.eudat.data.StorageFileEntity; -import eu.eudat.model.StorageFile; +import eu.eudat.model.*; import eu.eudat.model.builder.PublicDescriptionBuilder; import eu.eudat.model.persist.DescriptionFieldFilePersist; import eu.eudat.service.storage.StorageFileService; import gr.cite.tools.validation.ValidationFilterAnnotation; -import eu.eudat.model.Description; -import eu.eudat.model.Dmp; -import eu.eudat.model.PublicDescription; import eu.eudat.model.builder.DescriptionBuilder; import eu.eudat.model.censorship.DescriptionCensor; import eu.eudat.model.censorship.PublicDescriptionCensor; @@ -115,7 +112,7 @@ public class DescriptionController { DescriptionQuery query = this.queryFactory.query(DescriptionQuery.class).authorize(EnumSet.of(Public)).ids(id).dmpSubQuery(this.queryFactory.query(DmpQuery.class).isActive(IsActive.Active).statuses(DmpStatus.Finalized).accessTypes(DmpAccessType.Public)); PublicDescription model = this.builderFactory.builder(PublicDescriptionBuilder.class).authorize(EnumSet.of(Public)).build(fieldSet, query.firstAs(fieldSet)); - if (model == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); + if (model == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, PublicDescription.class.getSimpleName()}, LocaleContextHolder.getLocale())); this.auditService.track(AuditableAction.Description_PublicLookup, Map.ofEntries( new AbstractMap.SimpleEntry("id", id), @@ -148,7 +145,7 @@ public class DescriptionController { DescriptionQuery query = this.queryFactory.query(DescriptionQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(id); Description model = this.builderFactory.builder(DescriptionBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(fieldSet, query.firstAs(fieldSet)); if (model == null) - throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); + throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Description.class.getSimpleName()}, LocaleContextHolder.getLocale())); this.auditService.track(AuditableAction.Description_Lookup, Map.ofEntries( new AbstractMap.SimpleEntry("id", id), @@ -188,6 +185,21 @@ public class DescriptionController { return persisted; } + @GetMapping("validate") + public List validate(@RequestParam(value="descriptionIds") List descriptionIds) throws MyApplicationException, MyForbiddenException, MyNotFoundException { + logger.debug(new MapLogEntry("validating" + Description.class.getSimpleName()).And("descriptionIds", descriptionIds)); + + this.censorFactory.censor(DescriptionCensor.class).censor(null, null); + + List descriptionValidationResults = this.descriptionService.validate(descriptionIds); + + this.auditService.track(AuditableAction.Description_Validate, Map.ofEntries( + new AbstractMap.SimpleEntry("descriptionIds", descriptionIds) + )); + + return descriptionValidationResults; + } + @DeleteMapping("{id}") @Transactional public void delete(@PathVariable("id") UUID id) throws MyForbiddenException, InvalidApplicationException, IOException { diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DmpController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DmpController.java index b1d068870..eff6a60a9 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DmpController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DmpController.java @@ -171,6 +171,37 @@ public class DmpController { this.auditService.track(AuditableAction.Dmp_Delete, "id", id); } + @PostMapping("finalize/{id}") + @Transactional + public boolean finalize(@PathVariable("id") UUID id, @RequestBody DescriptionsToBeFinalized descriptions) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, IOException { + logger.debug(new MapLogEntry("finalizing" + Dmp.class.getSimpleName()).And("id", id).And("descriptionIds", descriptions.getDescriptionIds())); + + this.dmpService.finalize(id, descriptions.getDescriptionIds()); + + this.auditService.track(AuditableAction.Dmp_Finalize, Map.ofEntries( + new AbstractMap.SimpleEntry("id", id), + new AbstractMap.SimpleEntry("descriptionIds", descriptions.getDescriptionIds()) + )); + + return true; + } + + @GetMapping("undo-finalize/{id}") + @Transactional + public boolean undoFinalize(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, IOException, JAXBException { + logger.debug(new MapLogEntry("undo-finalizing" + Dmp.class.getSimpleName()).And("id", id)); + + this.censorFactory.censor(DmpCensor.class).censor(fieldSet, null); + + this.dmpService.undoFinalize(id, fieldSet); + + this.auditService.track(AuditableAction.Dmp_Undo_Finalize, Map.ofEntries( + new AbstractMap.SimpleEntry("id", id) + )); + + return true; + } + @PostMapping("clone") @Transactional @ValidationFilterAnnotation(validator = CloneDmpPersist.CloneDmpPersistValidator.ValidatorName, argumentName = "model") diff --git a/dmp-backend/web/src/main/resources/config/permissions.yml b/dmp-backend/web/src/main/resources/config/permissions.yml index 0cbcfb49f..2d15c8612 100644 --- a/dmp-backend/web/src/main/resources/config/permissions.yml +++ b/dmp-backend/web/src/main/resources/config/permissions.yml @@ -439,6 +439,19 @@ permissions: clients: [ ] allowAnonymous: false allowAuthenticated: false + UndoFinalizeDmp: + roles: + - Admin + dmp: + roles: + - Owner + - User + - DescriptionContributor + - Reviewer + claims: [ ] + clients: [ ] + allowAnonymous: false + allowAuthenticated: false AssignDmpUsers: roles: - Admin diff --git a/dmp-frontend/src/app/app.component.scss b/dmp-frontend/src/app/app.component.scss index ddc6df33c..26f07d9f5 100644 --- a/dmp-frontend/src/app/app.component.scss +++ b/dmp-frontend/src/app/app.component.scss @@ -21,7 +21,7 @@ display: flex; align-items: center; justify-content: center; - width: 260px; + width: 270px; background: #ffffff 0% 0% no-repeat padding-box; box-shadow: 0px 0px 16px 2px #00000029; border-right-width: 0px; diff --git a/dmp-frontend/src/app/core/services/description/description.service.ts b/dmp-frontend/src/app/core/services/description/description.service.ts index b363ad425..ea122fbb1 100644 --- a/dmp-frontend/src/app/core/services/description/description.service.ts +++ b/dmp-frontend/src/app/core/services/description/description.service.ts @@ -91,8 +91,13 @@ export class DescriptionService { catchError((error: any) => throwError(error))); } - public validate(descriptionIds: Guid[]): Observable { - return of(new Array()); + validate(descriptionIds: Guid[]): Observable { + const url = `${this.apiBase}/validate`; + const options = {params: { descriptionIds: descriptionIds} }; + + return this.http + .get(url, options).pipe( + catchError((error: any) => throwError(error))); } // public downloadPDF(id: string): Observable> { diff --git a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts index 410a38920..772eff79a 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts @@ -90,6 +90,24 @@ export class DmpService { catchError((error: any) => throwError(error))); } + finalize(id: Guid, descriptionIds: Guid[] = []): Observable { + const url = `${this.apiBase}/finalize/${id}`; + + return this.http + .post(url, {descriptionIds: descriptionIds}).pipe( + catchError((error: any) => throwError(error))); + } + + undoFinalize(id: Guid, reqFields: string[] = []): Observable { + const url = `${this.apiBase}/undo-finalize/${id}`; + + const options = { params: { f: reqFields } }; + + return this.http + .get(url, options).pipe( + catchError((error: any) => throwError(error))); + } + clone(item: CloneDmpPersist, reqFields: string[] = []): Observable { const url = `${this.apiBase}/clone`; const options = { params: { f: reqFields } }; diff --git a/dmp-frontend/src/app/ui/dashboard/dashboard.component.html b/dmp-frontend/src/app/ui/dashboard/dashboard.component.html index ff6346b73..e982c10a9 100644 --- a/dmp-frontend/src/app/ui/dashboard/dashboard.component.html +++ b/dmp-frontend/src/app/ui/dashboard/dashboard.component.html @@ -148,10 +148,10 @@
{{'DASHBOARD.PUBLIC-USAGE' | translate}}
{{dashboardStatistics?.dmpCount}}
- {{'DASHBOARD.PUBLIC-DMPS' | translate}} + {{'DASHBOARD.PUBLIC-DMPS' | translate}}
{{dashboardStatistics?.descriptionCount}}
- {{'DASHBOARD.PUBLIC-DESCRIPTIONS' | translate}} + {{'DASHBOARD.PUBLIC-DESCRIPTIONS' | translate}}
{{grantCount}}
{{'DASHBOARD.GRANTS' | translate}} diff --git a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts index 2921e7676..9c20001a1 100644 --- a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts @@ -20,6 +20,9 @@ import { debounceTime, takeUntil } from 'rxjs/operators'; import { nameof } from 'ts-simple-nameof'; import { AuthService } from '../../../core/services/auth/auth.service'; import { ReferenceType } from '@app/core/model/reference-type/reference-type'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { DescriptionStatus } from '@app/core/common/enum/description-status'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; @Component({ selector: 'app-drafts', @@ -30,7 +33,7 @@ export class DraftsComponent extends BaseComponent implements OnInit { lookup: RecentActivityItemLookup = new RecentActivityItemLookup(); pageSize: number = 5; - listingItems: RecentActivityItem[]; + listingItems: RecentActivityItem[] = []; public formGroup = new UntypedFormBuilder().group({ like: new UntypedFormControl(), @@ -131,8 +134,11 @@ export class DraftsComponent extends BaseComponent implements OnInit { [nameof(x => x.dmp), nameof(x => x.version)].join('.'), [nameof(x => x.dmp), nameof(x => x.groupId)].join('.'), [nameof(x => x.dmp), nameof(x => x.updatedAt)].join('.'), + [nameof(x => x.dmp), nameof(x => x.isActive)].join('.'), [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.label)].join('.'), + [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.status)].join('.'), + [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.isActive)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.user.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.role)].join('.'), @@ -147,6 +153,7 @@ export class DraftsComponent extends BaseComponent implements OnInit { [nameof(x => x.description), nameof(x => x.label)].join('.'), [nameof(x => x.description), nameof(x => x.status)].join('.'), [nameof(x => x.description), nameof(x => x.updatedAt)].join('.'), + [nameof(x => x.description), nameof(x => x.isActive)].join('.'), [nameof(x => x.description), nameof(x => x.descriptionTemplate), nameof(x => x.id)].join('.'), [nameof(x => x.description), nameof(x => x.descriptionTemplate), nameof(x => x.label)].join('.'), [nameof(x => x.description), nameof(x => x.descriptionTemplate), nameof(x => x.groupId)].join('.'), @@ -170,7 +177,22 @@ export class DraftsComponent extends BaseComponent implements OnInit { .getMyRecentActivityItems(this.lookup) .pipe(takeUntil(this._destroyed)) .subscribe(response => { - this.listingItems = response; + response.forEach(item => { + if (item.dmp){ + if (item.dmp.descriptions) { + if (item.dmp.status == DmpStatus.Finalized) { + item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status === DescriptionStatus.Finalized); + } else { + item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status != DescriptionStatus.Canceled); + } + } + item.dmp.dmpUsers = item.dmp.dmpUsers.filter(x=> x.isActive === IsActive.Active); + this.listingItems.push(item); + } + if (item.description){ + if (item.description.status != DescriptionStatus.Canceled) this.listingItems.push(item); + } + }) //this.totalCount = response.totalCount; diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts index 4ff40a54d..e3b2e06c3 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts @@ -2,6 +2,9 @@ import { Location } from '@angular/common'; import { Component, Input, OnInit } from '@angular/core'; import { UntypedFormBuilder, UntypedFormControl } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; +import { DescriptionStatus } from '@app/core/common/enum/description-status'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order'; import { RecentActivityItem } from '@app/core/model/dashboard/recent-activity-item'; import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; @@ -30,7 +33,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn lookup: RecentActivityItemLookup = new RecentActivityItemLookup(); pageSize: number = 5; - listingItems: RecentActivityItem[]; + listingItems: RecentActivityItem[]= []; public formGroup = new UntypedFormBuilder().group({ like: new UntypedFormControl(), @@ -130,8 +133,11 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn [nameof(x => x.dmp), nameof(x => x.version)].join('.'), [nameof(x => x.dmp), nameof(x => x.groupId)].join('.'), [nameof(x => x.dmp), nameof(x => x.updatedAt)].join('.'), + [nameof(x => x.dmp), nameof(x => x.isActive)].join('.'), [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.label)].join('.'), + [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.status)].join('.'), + [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.isActive)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.user.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.role)].join('.'), @@ -146,6 +152,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn [nameof(x => x.description), nameof(x => x.label)].join('.'), [nameof(x => x.description), nameof(x => x.status)].join('.'), [nameof(x => x.description), nameof(x => x.updatedAt)].join('.'), + [nameof(x => x.description), nameof(x => x.isActive)].join('.'), [nameof(x => x.description), nameof(x => x.descriptionTemplate), nameof(x => x.id)].join('.'), [nameof(x => x.description), nameof(x => x.descriptionTemplate), nameof(x => x.label)].join('.'), [nameof(x => x.description), nameof(x => x.descriptionTemplate), nameof(x => x.groupId)].join('.'), @@ -168,7 +175,22 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn .getMyRecentActivityItems(this.lookup) .pipe(takeUntil(this._destroyed)) .subscribe(response => { - this.listingItems = response; + response.forEach(item => { + if (item.dmp){ + if (item.dmp.descriptions) { + if (item.dmp.status == DmpStatus.Finalized) { + item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status === DescriptionStatus.Finalized); + } else { + item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status != DescriptionStatus.Canceled); + } + } + item.dmp.dmpUsers = item.dmp.dmpUsers.filter(x=> x.isActive === IsActive.Active); + this.listingItems.push(item); + } + if (item.description){ + if (item.description.status != DescriptionStatus.Canceled) this.listingItems.push(item); + } + }) //this.totalCount = response.totalCount; diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-description-activity/recent-edited-description-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-edited-description-activity/recent-edited-description-activity.component.ts index 6f416d7a2..4c3b60f81 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-description-activity/recent-edited-description-activity.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-description-activity/recent-edited-description-activity.component.ts @@ -18,6 +18,7 @@ import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { BaseComponent } from '@common/base/base.component'; import { debounceTime, takeUntil } from 'rxjs/operators'; import { nameof } from 'ts-simple-nameof'; +import { DescriptionStatus } from '@app/core/common/enum/description-status'; @Component({ selector: 'app-recent-edited-description-activity', @@ -28,7 +29,7 @@ export class RecentEditedDescriptionActivityComponent extends BaseComponent impl lookup: RecentActivityItemLookup = new RecentActivityItemLookup(); pageSize: number = 5; - listingItems: Description[]; + listingItems: Description[] = []; public formGroup = new UntypedFormBuilder().group({ @@ -148,7 +149,11 @@ export class RecentEditedDescriptionActivityComponent extends BaseComponent impl .getMyRecentActivityItems(this.lookup) .pipe(takeUntil(this._destroyed)) .subscribe(response => { - this.listingItems = response.map(x => x.description); + response.forEach(item => { + if (item.description){ + if (item.description.status != DescriptionStatus.Canceled) this.listingItems.push(item.description); + } + }) // this.totalCount = response.count; diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts index 7d597f836..5f01d4ea7 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts @@ -2,6 +2,9 @@ import { Location } from '@angular/common'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; +import { DescriptionStatus } from '@app/core/common/enum/description-status'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order'; import { RecentActivityItem } from '@app/core/model/dashboard/recent-activity-item'; import { Description } from '@app/core/model/description/description'; @@ -33,13 +36,12 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O @ViewChild("dmps") resultsContainer; - listingItems: Dmp[]; + listingItems: Dmp[]= []; isDraft: boolean; totalCount: number; startIndex: number = 0; offsetLess: number = 0; - hasMoreResults: boolean = true; dmpFormGroup: UntypedFormGroup; public formGroup = new UntypedFormBuilder().group({ like: new UntypedFormControl(), @@ -137,6 +139,8 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O [nameof(x => x.dmp), nameof(x => x.updatedAt)].join('.'), [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.label)].join('.'), + [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.status)].join('.'), + [nameof(x => x.dmp), nameof(x => x.descriptions), nameof(x => x.isActive)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.user.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.role)].join('.'), @@ -153,7 +157,20 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O .getMyRecentActivityItems(this.lookup) .pipe(takeUntil(this._destroyed)) .subscribe(response => { - this.listingItems = response.map(x => x.dmp); + response.forEach(item => { + if (item.dmp){ + item.dmp.dmpUsers = item.dmp.dmpUsers.filter(x => x.isActive === IsActive.Active); + if (item.dmp.descriptions) { + if (item.dmp.status == DmpStatus.Finalized) { + item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status === DescriptionStatus.Finalized); + } else { + item.dmp.descriptions = item.dmp.descriptions.filter(x => x.isActive === IsActive.Active && x.status != DescriptionStatus.Canceled); + } + } + this.listingItems.push(item.dmp); + } + + }) //this.totalCount = response.totalCount; diff --git a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html index 42892b5bd..f55816bba 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html +++ b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html @@ -36,7 +36,7 @@
-
1.3 {{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS' | translate}}*
+
1.3 {{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS' | translate}}
diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts index 125bf9237..9e02581ac 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts @@ -75,8 +75,8 @@ export class DescriptionEditorModel extends BaseEditorModel implements Descripti baseValidationArray.push({ key: 'dmpDescriptionTemplateId', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'dmpDescriptionTemplateId')] }); baseValidationArray.push({ key: 'descriptionTemplateId', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'descriptionTemplateId')] }); baseValidationArray.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] }); - baseValidationArray.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'description')] }); - baseValidationArray.push({ key: 'tags', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'tags')] }); + baseValidationArray.push({ key: 'description', validators: [BackendErrorValidator(this.validationErrorModel, 'description')] }); + baseValidationArray.push({ key: 'tags', validators: [BackendErrorValidator(this.validationErrorModel, 'tags')] }); baseValidationArray.push({ key: 'hash', validators: [] }); baseContext.validation = baseValidationArray; diff --git a/dmp-frontend/src/app/ui/description/listing/description-listing.component.ts b/dmp-frontend/src/app/ui/description/listing/description-listing.component.ts index af6b5bd5c..059f33ca5 100644 --- a/dmp-frontend/src/app/ui/description/listing/description-listing.component.ts +++ b/dmp-frontend/src/app/ui/description/listing/description-listing.component.ts @@ -207,6 +207,7 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit [nameof(x => x.descriptionTemplate), nameof(x => x.groupId)].join('.'), [nameof(x => x.dmp), nameof(x => x.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.label)].join('.'), + [nameof(x => x.dmp), nameof(x => x.status)].join('.'), [nameof(x => x.dmp), nameof(x => x.accessType)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.id)].join('.'), [nameof(x => x.dmp), nameof(x => x.dmpUsers), nameof(x => x.user.id)].join('.'), @@ -238,7 +239,9 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit if (!result) { return []; } this.totalCount = result.count; if (lookup?.page?.offset === 0) this.listingItems = []; - this.listingItems.push(...result.items); + result.items.forEach(description => { + if (description.status != DescriptionStatus.Canceled) this.listingItems.push(description); + }) this.hasListingItems = true; }); } diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.resolver.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.resolver.ts index 6d8a3f5aa..7ef04a863 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.resolver.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.resolver.ts @@ -37,6 +37,7 @@ export class DmpEditorResolver extends BaseEditorResolver { nameof(x => x.version), nameof(x => x.updatedAt), nameof(x => x.publicAfter), + nameof(x => x.creator), nameof(x => x.hash), [nameof(x => x.authorizationFlags), AppPermission.EditDmp].join('.'), diff --git a/dmp-frontend/src/app/ui/dmp/dmp-finalize-dialog/dmp-finalize-dialog.component.html b/dmp-frontend/src/app/ui/dmp/dmp-finalize-dialog/dmp-finalize-dialog.component.html index 11cb41d9f..9316e8c3a 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-finalize-dialog/dmp-finalize-dialog.component.html +++ b/dmp-frontend/src/app/ui/dmp/dmp-finalize-dialog/dmp-finalize-dialog.component.html @@ -25,12 +25,12 @@ -
+
bookmark bookmark

- {{ 'TYPES.DATASET-STATUS.DRAFT' | translate }} + {{ 'TYPES.DESCRIPTION-STATUS.DRAFT' | translate }} ({{'DMP-FINALISE-DIALOG.INVALID' | translate}}) @@ -41,7 +41,7 @@

{{ description.label }}

-
{{ 'DMP-FINALISE-DIALOG.EMPTY' | translate }}
+
{{ 'DMP-FINALISE-DIALOG.EMPTY' | translate }}
diff --git a/dmp-frontend/src/app/ui/dmp/dmp-finalize-dialog/dmp-finalize-dialog.component.ts b/dmp-frontend/src/app/ui/dmp/dmp-finalize-dialog/dmp-finalize-dialog.component.ts index 892d9091d..eb4469a25 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-finalize-dialog/dmp-finalize-dialog.component.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp-finalize-dialog/dmp-finalize-dialog.component.ts @@ -43,19 +43,21 @@ export class DmpFinalizeDialogComponent extends BaseComponent implements OnInit } onSubmit() { - this.dialogRef.close(this.descriptionsToBeFinalized); + this.dialogRef.close({ descriptionsToBeFinalized: this.descriptionsToBeFinalized } as DmpFinalizeDialogOutput); } getFinalizedDescriptions() { + if (!this.dmp.descriptions) return []; return this.dmp.descriptions.filter(x => x.status === DescriptionStatus.Finalized); } close() { - this.dialogRef.close(null); + this.dialogRef.close({ cancelled: true } as DmpFinalizeDialogOutput); } validateDescriptions(dmp: Dmp) { - if (!dmp.descriptions.some(x => x.status == DescriptionStatus.Draft)) return; + 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; @@ -63,6 +65,7 @@ export class DmpFinalizeDialogComponent extends BaseComponent implements OnInit } get validDraftDescriptions() { + if (!this.dmp.descriptions) return []; return this.dmp.descriptions.filter(x => this.validationResults.some(y => y.descriptionId == x.id && y.result == DescriptionValidationOutput.Valid)); } } @@ -76,3 +79,8 @@ export enum DescriptionValidationOutput { Valid = 1, Invalid = 2 } + +export interface DmpFinalizeDialogOutput { + cancelled?: boolean; + descriptionsToBeFinalized?: Guid[]; +} diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.html b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.html index 8dcfc23ab..475d3e46b 100644 --- a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.html +++ b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.html @@ -7,9 +7,9 @@ close
-
+
- +
diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts index 56619aef4..d625b4566 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts @@ -32,6 +32,8 @@ import { DmpReference } from '@app/core/model/dmp/dmp-reference'; import { Reference } from '@app/core/model/reference/reference'; import { ReferenceType } from '@app/core/model/reference-type/reference-type'; import { AppPermission } from '@app/core/common/enum/permission.enum'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { DescriptionStatus } from '@app/core/common/enum/description-status'; @Component({ selector: 'app-dmp-listing-component', @@ -197,6 +199,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr [nameof(x => x.descriptions), nameof(x => x.id)].join('.'), [nameof(x => x.descriptions), nameof(x => x.label)].join('.'), + [nameof(x => x.descriptions), nameof(x => x.status)].join('.'), [nameof(x => x.descriptions), nameof(x => x.isActive)].join('.'), [nameof(x => x.blueprint), nameof(x => x.id)].join('.'), @@ -239,7 +242,13 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr this.totalCount = result.count; if (lookup?.page?.offset === 0) this.listingItems = []; result.items.forEach(x=> { - x.descriptions = x.descriptions?.filter(x=> x.isActive === IsActive.Active); + if (x.descriptions) { + if (x.status == DmpStatus.Finalized) { + x.descriptions = x.descriptions.filter(x => x.isActive === IsActive.Active && x.status === DescriptionStatus.Finalized); + } else { + x.descriptions = x.descriptions.filter(x => x.isActive === IsActive.Active && x.status !== DescriptionStatus.Canceled); + } + } x.dmpUsers = x.dmpUsers.filter(x=> x.isActive === IsActive.Active); this.listingItems.push(x); }) diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index 5399d4ddb..feaf3f4f4 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -44,7 +44,8 @@ import { NewVersionDmpDialogComponent } from '../new-version-dialog/dmp-new-vers import { AppPermission } from '@app/core/common/enum/permission.enum'; import { ReferenceType } from '@app/core/model/reference-type/reference-type'; import { IsActive } from '@app/core/common/enum/is-active.enum'; -import { DmpFinalizeDialogComponent } from '../dmp-finalize-dialog/dmp-finalize-dialog.component'; +import { DmpFinalizeDialogComponent, DmpFinalizeDialogOutput } from '../dmp-finalize-dialog/dmp-finalize-dialog.component'; +import { DmpEditorResolver } from '../dmp-editor-blueprint/dmp-editor.resolver'; @Component({ selector: 'app-dmp-overview', @@ -117,7 +118,13 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { .subscribe(data => { this.dmp = data; this.dmp.dmpUsers = data.dmpUsers.filter(x => x.isActive === IsActive.Active); - if (this.dmp.descriptions) this.dmp.descriptions = data.descriptions.filter(x => x.isActive === IsActive.Active); + if (this.dmp.descriptions) { + if (this.dmp.status == DmpStatus.Finalized) { + this.dmp.descriptions = data.descriptions.filter(x => x.isActive === IsActive.Active && x.status === DescriptionStatus.Finalized); + } else { + this.dmp.descriptions = data.descriptions.filter(x => x.isActive === IsActive.Active && x.status !== DescriptionStatus.Canceled); + } + } this.selectedBlueprint = data.blueprint; this.researchers = this.referenceService.getReferencesForTypes(this.dmp?.dmpReferences, [this.referenceTypeService.getResearcherReferenceType()]); if (!this.hasDoi()) { @@ -502,17 +509,17 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { dmp: this.dmp } }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe((descriptionsToBeFinalized: Guid[]) => { - if (descriptionsToBeFinalized && descriptionsToBeFinalized.length > 0) { + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe((result: DmpFinalizeDialogOutput) => { + if (result && !result.cancelled) { - // this.dmpService.finalize(descriptionsToBeFinalized, this.dmp.id) - // .pipe(takeUntil(this._destroyed)) - // .subscribe( - // complete => { - - // }, - // error => this.onUpdateCallbackError(error) - // ); + this.dmpService.finalize(this.dmp.id, result.descriptionsToBeFinalized) + .pipe(takeUntil(this._destroyed)) + .subscribe(data => { + this.reloadPage(); + this.onUpdateCallbackSuccess() + }, (error: any) => { + this.onUpdateCallbackError(error) + }); } }); @@ -603,28 +610,26 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { } reverseFinalization() { - //TODO: add this - // const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - // restoreFocus: false, - // data: { - // message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.UNFINALIZE-ITEM'), - // confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'), - // cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE'), - // isDeleteConfirmation: false - // } - // }); - // dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - // if (result) { - // this.dmpService.unfinalize(this.dmp.id).pipe(takeUntil(this._destroyed)) - // .subscribe( - // complete => { - // this.dmp.status = DmpStatus.Draft; - // this.onUpdateCallbackSuccess() - // }, - // error => this.onUpdateCallbackError(error) - // ); - // } - // }); + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + restoreFocus: false, + data: { + message: this.language.instant('DMP-OVERVIEW.UNDO-FINALIZATION-DIALOG.TITLE'), + confirmButton: this.language.instant('DMP-OVERVIEW.UNDO-FINALIZATION-DIALOG.CONFIRM'), + cancelButton: this.language.instant('DMP-OVERVIEW.UNDO-FINALIZATION-DIALOG.NEGATIVE'), + isDeleteConfirmation: false + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.dmpService.undoFinalize(this.dmp.id, DmpEditorResolver.lookupFields()).pipe(takeUntil(this._destroyed)) + .subscribe(data => { + this.reloadPage(); + this.onUpdateCallbackSuccess() + }, (error: any) => { + this.onUpdateCallbackError(error) + }); + } + }); } goBack(): void { @@ -727,7 +732,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { nameof(x => x.groupId), nameof(x => x.version), nameof(x => x.updatedAt), - nameof(x => x.updatedAt), + nameof(x => x.entityDois), [nameof(x => x.authorizationFlags), AppPermission.CreateNewVersionDmp].join('.'), [nameof(x => x.authorizationFlags), AppPermission.DeleteDmp].join('.'), [nameof(x => x.authorizationFlags), AppPermission.CloneDmp].join('.'), diff --git a/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.html b/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.html index eb2f1d7ab..8da4e4d27 100644 --- a/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.html +++ b/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.html @@ -1,9 +1,26 @@ -
-
-
+
+ hello! + +
+ + + + + +
+
+ +
+
+ + +
+
{{userIndex + 1}}
-
drag_indicator
+
drag_indicator
@@ -11,47 +28,43 @@
-
-
-
- - {{'DMP-EDITOR.FIELDS1.USER' | translate}}* - - {{user.get('user').getError('backendError').message}} - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - -
-
- - {{'DMP-EDITOR.FIELDS1.EMAIL' | translate}}* - - {{user.get('email').getError('backendError').message}} - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - -
-
- - {{'DMP-EDITOR.FIELDS1.USER-ROLE' | translate}} - - {{enumUtils.toDmpUserRoleString(userRole)}} - - {{user.get('role').getError('backendError').message}} - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - -
-
- - {{'DMP-EDITOR.FIELDS1.SECTION' | translate}} - - - {{ section.label }} - - - {{user.get('sectionId').getError('backendError').message}} - {{'GENERAL.VALIDATION.REQUIRED' |translate}} - -
-
+
+ + {{'DMP-EDITOR.FIELDS1.USER' | translate}}* + + {{user.get('user').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
+
+ + {{'DMP-EDITOR.FIELDS1.EMAIL' | translate}}* + + {{user.get('email').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
+
+ + {{'DMP-EDITOR.FIELDS1.USER-ROLE' | translate}} + + {{enumUtils.toDmpUserRoleString(userRole)}} + + {{user.get('role').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
+
+ + {{'DMP-EDITOR.FIELDS1.SECTION' | translate}} + + + {{ section.label }} + + + {{user.get('sectionId').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' |translate}} +
+ {{'DMP-EDITOR.USERS-REQUIRED' | translate}} {{form.get('users').getError('backendError').message}} -
-
-
- -
-
\ No newline at end of file +
diff --git a/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.scss b/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.scss index dbaf6e932..8274928d1 100644 --- a/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.scss +++ b/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.scss @@ -6,4 +6,15 @@ .drag-handle-disabled { cursor: auto; color: rgba(0, 0, 0, 0.38);; -} \ No newline at end of file +} + +.user-fields-wrapper { + display: flex; + flex-direction: row; + justify-content: space-around; + align-items: baseline; + + @media (width <= 1350px) { + flex-direction: column; + } +} diff --git a/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.ts b/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.ts index 1bd5b72f6..0df0b0e9b 100644 --- a/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.ts +++ b/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.ts @@ -24,6 +24,8 @@ export class UserFieldComponent extends BaseComponent implements OnInit { @Input() required: boolean = false; @Input() placeholder: string; @Input() sections: DmpBlueprintDefinitionSection[] = null; + @Input() initializeUsers: boolean = false; + @Input() enableSorting: boolean = true; dmpUserTypeEnum = DmpUserType; dmpUserTypeEnumValues = this.enumUtils.getEnumValues(DmpUserType); @@ -37,6 +39,10 @@ export class UserFieldComponent extends BaseComponent implements OnInit { ) { super(); } ngOnInit() { + console.log('sorting mode: ', this.enableSorting); + if(this.initializeUsers) { + this.addUser(); + } } addUser(): void { diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.ts b/dmp-frontend/src/app/ui/navbar/navbar.component.ts index 0431fdf2d..e6cfef4fb 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.ts +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.ts @@ -243,7 +243,7 @@ export class NavbarComponent extends BaseComponent implements OnInit { autoFocus: false, closeOnNavigation: true, disableClose: false, - position: { top: '64px', right: '1em' }, + position: { top: '71px', right: '1em' }, panelClass: 'custom-userbox' }); } diff --git a/dmp-frontend/src/app/ui/navbar/user-dialog/user-dialog.component.html b/dmp-frontend/src/app/ui/navbar/user-dialog/user-dialog.component.html index 2f9d7bdad..c553e9a04 100644 --- a/dmp-frontend/src/app/ui/navbar/user-dialog/user-dialog.component.html +++ b/dmp-frontend/src/app/ui/navbar/user-dialog/user-dialog.component.html @@ -1,14 +1,15 @@ -
- -