From a387349aadedc1668f0cf9b42f5789b496e7678a Mon Sep 17 00:00:00 2001 From: amentis Date: Thu, 22 Feb 2024 13:57:42 +0200 Subject: [PATCH] create common dmpUser component for dmp ui and dmp overview popup invite --- .../model/persist/DmpUserInvitePersist.java | 25 +----- .../java/eu/eudat/service/dmp/DmpService.java | 4 +- .../eu/eudat/service/dmp/DmpServiceImpl.java | 33 ++++--- .../eu/eudat/controllers/DmpController.java | 4 +- dmp-frontend/src/app/core/model/dmp/dmp.ts | 9 +- .../dmp-editor.component.html | 72 +--------------- .../dmp-editor.component.ts | 38 +------- .../dmp-editor-blueprint/dmp-editor.model.ts | 8 +- .../dmp-editor-blueprint/dmp-editor.module.ts | 2 + .../dmp-editor.resolver.ts | 12 +-- .../dmp-invitation-dialog.component.html | 27 ++---- .../dialog/dmp-invitation-dialog.component.ts | 86 +++---------------- .../dmp-invitation-dialog.editor.model.ts | 34 -------- .../dialog/dmp-invitation-dialog.module.ts | 3 +- .../ui/dmp/overview/dmp-overview.component.ts | 11 ++- .../dmp/user-field/user-field.component.html | 71 +++++++++++++++ .../dmp/user-field/user-field.component.scss | 9 ++ .../ui/dmp/user-field/user-field.component.ts | 74 ++++++++++++++++ .../ui/dmp/user-field/user-field.module.ts | 22 +++++ 19 files changed, 251 insertions(+), 293 deletions(-) delete mode 100644 dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.editor.model.ts create mode 100644 dmp-frontend/src/app/ui/dmp/user-field/user-field.component.html create mode 100644 dmp-frontend/src/app/ui/dmp/user-field/user-field.component.scss create mode 100644 dmp-frontend/src/app/ui/dmp/user-field/user-field.component.ts create mode 100644 dmp-frontend/src/app/ui/dmp/user-field/user-field.module.ts diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/persist/DmpUserInvitePersist.java b/dmp-backend/core/src/main/java/eu/eudat/model/persist/DmpUserInvitePersist.java index 6d4b34fc6..4e3ce42d6 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/persist/DmpUserInvitePersist.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/persist/DmpUserInvitePersist.java @@ -1,6 +1,5 @@ package eu.eudat.model.persist; -import eu.eudat.commons.enums.DmpUserRole; import eu.eudat.commons.validation.BaseValidator; import gr.cite.tools.validation.ValidatorFactory; import gr.cite.tools.validation.specification.Specification; @@ -17,30 +16,18 @@ import java.util.List; public class DmpUserInvitePersist { - private List users; + private List users; public static final String _users = "users"; - private DmpUserRole role; - - public static final String _role = "role"; - - public List getUsers() { + public List getUsers() { return users; } - public void setUsers(List users) { + public void setUsers(List users) { this.users = users; } - public DmpUserRole getRole() { - return role; - } - - public void setRole(DmpUserRole role) { - this.role = role; - } - @Component(DmpUserInvitePersistValidator.ValidatorName) @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public static class DmpUserInvitePersistValidator extends BaseValidator { @@ -65,10 +52,6 @@ public class DmpUserInvitePersist { @Override protected List specifications(DmpUserInvitePersist item) { return Arrays.asList( - this.spec() - .must(() -> !this.isNull(item.getRole())) - .failOn(DmpUserInvitePersist._role).failWith(messageSource.getMessage("Validation_Required", new Object[]{DmpUserInvitePersist._role}, LocaleContextHolder.getLocale())), - this.spec() .must(() -> !this.isListNullOrEmpty(item.getUsers())) .failOn(DmpUserInvitePersist._users).failWith(messageSource.getMessage("Validation_Required", new Object[]{DmpUserInvitePersist._users}, LocaleContextHolder.getLocale())), @@ -76,7 +59,7 @@ public class DmpUserInvitePersist { .iff(() -> !this.isListNullOrEmpty(item.getUsers())) .on(DmpUserInvitePersist._users) .over(item.getUsers()) - .using((itm) -> this.validatorFactory.validator(DmpUserInviteTypePersist.DmpUserInviteTypePersistValidator.class)) + .using((itm) -> this.validatorFactory.validator(DmpUserPersist.DmpUserPersistValidator.class)) ); } } 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 5a9b13a04..257909821 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 @@ -23,7 +23,7 @@ import java.util.UUID; public interface DmpService { - Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException; + Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, IOException; void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException, IOException; @@ -36,7 +36,7 @@ public interface DmpService { ResponseEntity export(UUID id, String exportType) throws InvalidApplicationException, IOException; - void inviteUsers(UUID id, DmpUserInvitePersist model) throws InvalidApplicationException, JAXBException, IOException; + void inviteUsers(UUID id, List users) throws InvalidApplicationException, JAXBException, IOException; void dmpInvitationAccept(String token) throws InvalidApplicationException, IOException; 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 3bdd9beb8..72f57dc6c 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 @@ -166,7 +166,7 @@ public class DmpServiceImpl implements DmpService { this.dmpTouchedIntegrationEventHandler = dmpTouchedIntegrationEventHandler; } - public Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException { + public Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, IOException { this.authorizationService.authorizeForce(Permission.EditDmp); DmpEntity data = this.patchAndSave(model); @@ -188,6 +188,10 @@ public class DmpServiceImpl implements DmpService { this.elasticService.persistDmp(data); + if (!this.conventionService.isListNullOrEmpty(model.getUsers())){ + this.inviteUsers(data.getId(), model.getUsers()); + } + return this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, Dmp._id, Dmp._hash), data); } @@ -777,7 +781,7 @@ public class DmpServiceImpl implements DmpService { } // invites - public void inviteUsers(UUID id, DmpUserInvitePersist model) throws InvalidApplicationException, JAXBException, IOException { + public void inviteUsers(UUID id, List users) throws InvalidApplicationException, JAXBException, IOException { this.authorizationService.authorizeForce(Permission.InviteDmpUsers); @@ -786,15 +790,22 @@ public class DmpServiceImpl implements DmpService { throw new InvalidApplicationException("Dmp does not exist!"); } - for (DmpUserInviteTypePersist type :model.getUsers()) { - if (type.getUserId() != null){ - DmpUserPersist dmpUserPersist = new DmpUserPersist(); - dmpUserPersist.setUser(type.getUserId()); - dmpUserPersist.setRole(model.getRole()); - this.assignUsers(id, List.of(dmpUserPersist), null); - this.sendDmpInvitationExistingUser(type.getUserId(), dmp, model.getRole()); - } else if (type.getEmail() != null) { - this.sendDmpInvitationExternalUser(type.getEmail(),dmp, model.getRole()); + for (DmpUserPersist user :users) { + UUID userId = null; + if (user.getUser() != null){ + userId = user.getUser(); + } else if (user.getEmail() != null) { + UserContactInfoEntity contactInfoEntity = this.queryFactory.query(UserContactInfoQuery.class).values(user.getEmail()).types(ContactInfoType.Email).first(); + if (contactInfoEntity != null){ + userId = contactInfoEntity.getUserId(); + } + } + if (userId != null){ + user.setUser(userId); + this.assignUsers(id, List.of(user), null); + this.sendDmpInvitationExistingUser(user.getUser(), dmp, user.getRole()); + }else if (user.getEmail() != null) { + this.sendDmpInvitationExternalUser(user.getEmail(),dmp, user.getRole()); } } 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 60e6c2b60..a18db9127 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 @@ -126,7 +126,7 @@ public class DmpController { @PostMapping("persist") @Transactional @ValidationFilterAnnotation(validator = DmpPersist.DmpPersistValidator.ValidatorName, argumentName = "model") - public Dmp Persist(@RequestBody DmpPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, IOException { + public Dmp Persist(@RequestBody DmpPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, IOException, JAXBException { logger.debug(new MapLogEntry("persisting" + Dmp.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); Dmp persisted = this.dmpService.persist(model, fieldSet); @@ -228,7 +228,7 @@ public class DmpController { public boolean inviteUsers(@PathVariable("id") UUID id, @RequestBody DmpUserInvitePersist model) throws InvalidApplicationException, JAXBException, IOException { logger.debug(new MapLogEntry("inviting users to dmp").And("model", model)); - this.dmpService.inviteUsers(id, model); + this.dmpService.inviteUsers(id, model.getUsers()); this.auditService.track(AuditableAction.Dmp_Invite_Users, Map.ofEntries( new AbstractMap.SimpleEntry("model", model) diff --git a/dmp-frontend/src/app/core/model/dmp/dmp.ts b/dmp-frontend/src/app/core/model/dmp/dmp.ts index 2e6480b11..bf2de858c 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp.ts @@ -143,12 +143,5 @@ export interface DmpUserRemovePersist { } export interface DmpUserInvitePersist { - users: DmpUserInviteTypePersist[]; - role: DmpUserRole; + users: DmpUserPersist[]; } - -export interface DmpUserInviteTypePersist { - userId: Guid; - email: string; -} - diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.html b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.html index ffc2c6f91..f20cb7046 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.html +++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.html @@ -243,76 +243,8 @@
-
-
-
- {{userIndex + 1}} -
-
drag_indicator
-
- -
- {{enumUtils.toDmpUserTypeString(userType)}} -
-
-
-
-
-
- - {{'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}} - -
-
-
-
- -
-
- {{formGroup.get('users').getError('backendError').message}} - {{'GENERAL.VALIDATION.REQUIRED' | translate}} -
-
-
- -
+
+
diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.ts index 3604a68ad..9e3dc93ab 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.component.ts @@ -196,7 +196,7 @@ export class DmpEditorComponent extends BaseEditor implemen } buildForm() { - this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !this.authService.hasPermission(AppPermission.EditDescription)); + this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !this.authService.hasPermission(AppPermission.EditDmp)); if (this.editorModel.status == DmpStatus.Finalized || this.isDeleted) { this.formGroup.disable(); @@ -372,42 +372,6 @@ export class DmpEditorComponent extends BaseEditor implemen this.formGroup.get('properties').get('contacts').markAsDirty(); } - // - // - // Dmp Users - // - // - addUser(): void { - const userArray = this.formGroup.get('users') as FormArray; - (this.formGroup.get('users') as FormArray).push(this.editorModel.createChildUser(userArray.length)); - } - - removeUser(userIndex: number): void { - (this.formGroup.get('users') as FormArray).removeAt(userIndex); - - DmpEditorModel.reApplyPropertiesValidators( - { - formGroup: this.formGroup, - validationErrorModel: this.editorModel.validationErrorModel - } - ); - this.formGroup.get('users').markAsDirty(); - } - - dropUsers(event: CdkDragDrop) { - const usersFormArray = (this.formGroup.get('users') as FormArray); - - moveItemInArray(usersFormArray.controls, event.previousIndex, event.currentIndex); - usersFormArray.updateValueAndValidity(); - - DmpEditorModel.reApplyPropertiesValidators( - { - formGroup: this.formGroup, - validationErrorModel: this.editorModel.validationErrorModel - } - ); - this.formGroup.get('users').markAsDirty(); - } // // diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.model.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.model.ts index 40ced4ea5..6bcd93449 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.model.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.model.ts @@ -139,10 +139,6 @@ export class DmpEditorModel extends BaseEditorModel implements DmpPersist { return contact.buildForm({ rootPath: 'properties.contacts[' + index + '].' }); } - createChildUser(index: number): UntypedFormGroup { - const user: DmpUserEditorModel = new DmpUserEditorModel(this.validationErrorModel); - return user.buildForm({ rootPath: 'users[' + index + '].' }); - } static reApplyPropertiesValidators(params: { formGroup: UntypedFormGroup, @@ -500,8 +496,8 @@ export class DmpUserEditorModel implements DmpUserPersist { return this.formBuilder.group({ user: [{ value: this.user, disabled: disabled }, context.getValidation('user').validators], role: [{ value: this.role, disabled: disabled }, context.getValidation('role').validators], - email: [{ value: this.role, disabled: disabled }, context.getValidation('email').validators], - sectionId: [{ value: this.role, disabled: disabled }, context.getValidation('sectionId').validators], + email: [{ value: this.email, disabled: disabled }, context.getValidation('email').validators], + sectionId: [{ value: this.sectionId, disabled: disabled }, context.getValidation('sectionId').validators], userType: [{ value: this.userType, disabled: disabled }, context.getValidation('userType').validators], }); } diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.module.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.module.ts index b4c1b6747..b9d78b31e 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.module.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor.module.ts @@ -9,6 +9,7 @@ import { DmpEditorRoutingModule } from './dmp-editor.routing'; import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; import { ReferenceFieldModule } from '@app/ui/reference/reference-field/reference-field.module'; import { DragDropModule } from '@angular/cdk/drag-drop'; +import { UserFieldModule } from '../user-field/user-field.module'; @NgModule({ imports: [ @@ -21,6 +22,7 @@ import { DragDropModule } from '@angular/cdk/drag-drop'; AutoCompleteModule, ReferenceFieldModule, DragDropModule, + UserFieldModule ], declarations: [ DmpEditorComponent, 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 baac027e3..54da65bf9 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 @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Description } from '@app/core/model/description/description'; import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, ExtraFieldInSection, FieldInSection, ReferenceTypeFieldInSection, SystemFieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint'; -import { Dmp, DmpBlueprintValue, DmpContact, DmpDescriptionTemplate, DmpProperties } from '@app/core/model/dmp/dmp'; +import { Dmp, DmpBlueprintValue, DmpContact, DmpDescriptionTemplate, DmpProperties, DmpUser } from '@app/core/model/dmp/dmp'; import { DmpReference, DmpReferenceData } from '@app/core/model/dmp/dmp-reference'; import { ReferenceType } from '@app/core/model/reference-type/reference-type'; import { Reference } from '@app/core/model/reference/reference'; @@ -54,10 +54,12 @@ export class DmpEditorResolver extends BaseEditorResolver { [nameof(x => x.descriptions), nameof(x => x.dmpDescriptionTemplate), nameof(x => x.id)].join('.'), [nameof(x => x.descriptions), nameof(x => x.dmpDescriptionTemplate), nameof(x => x.sectionId)].join('.'), - // [nameof(x => x.dmpUsers), nameof(x => x.id)].join('.'), - // [nameof(x => x.dmpUsers), nameof(x => x.user.id)].join('.'), - // [nameof(x => x.dmpUsers), nameof(x => x.user.name)].join('.'), - // [nameof(x => x.dmpUsers), nameof(x => x.role)].join('.'), + [nameof(x => x.dmpUsers), nameof(x => x.id)].join('.'), + [nameof(x => x.dmpUsers), nameof(x => x.user.id)].join('.'), + [nameof(x => x.dmpUsers), nameof(x => x.user.name)].join('.'), + [nameof(x => x.dmpUsers), nameof(x => x.role)].join('.'), + [nameof(x => x.dmpUsers), nameof(x => x.sectionId)].join('.'), + [nameof(x => x.dmpReferences), nameof(x => x.id)].join('.'), [nameof(x => x.dmpReferences), nameof(x => x.isActive)].join('.'), [nameof(x => x.dmpReferences), nameof(x => x.data), nameof(x => x.blueprintFieldId)].join('.'), 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 a706a3dd4..8dcfc23ab 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 @@ -8,25 +8,12 @@
- - - - -

- info_outlined - {{'DMP-USER-INVITATION-DIALOG.FIELDS.USERS-HINT' | translate}} -

-
-
- - - {{enumUtils.toDmpUserRoleString(dmpUserRoleEnum.Owner)}} - {{enumUtils.toDmpUserRoleString(dmpUserRoleEnum.User)}} - - -
-
- -
+
+ +
+
+ + {{formGroup.get('users').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}}
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.ts b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.ts index a67400936..6a7eb12c3 100644 --- a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.ts +++ b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.component.ts @@ -5,23 +5,18 @@ import { UntypedFormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { ActivatedRoute, Router } from '@angular/router'; import { DmpUserRole } from '@app/core/common/enum/dmp-user-role'; -import { IsActive } from '@app/core/common/enum/is-active.enum'; -import { DmpUserInvitePersist, DmpUserInviteTypePersist } from '@app/core/model/dmp/dmp'; -import { DmpAssociatedUser, User } from '@app/core/model/user/user'; -import { UserLookup } from '@app/core/query/user.lookup'; +import { DmpUserPersist } from '@app/core/model/dmp/dmp'; import { DmpService } from '@app/core/services/dmp/dmp.service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { UserService } from '@app/core/services/user/user.service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; -import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; import { BaseComponent } from '@common/base/base.component'; import { FilterService } from '@common/modules/text-filter/filter-service'; import { Guid } from '@common/types/guid'; import { TranslateService } from '@ngx-translate/core'; -import { Observable } from 'rxjs'; -import { map, takeUntil } from 'rxjs/operators'; -import { nameof } from 'ts-simple-nameof'; -import { DmpInvitationDialogEditorModel } from './dmp-invitation-dialog.editor.model'; +import { DmpEditorModel } from '../../dmp-editor-blueprint/dmp-editor.model'; +import { takeUntil } from 'rxjs/operators'; +import { DmpBlueprint } from '@app/core/model/dmp-blueprint/dmp-blueprint'; @Component({ selector: 'app-invitation-dialog-component', @@ -31,31 +26,12 @@ import { DmpInvitationDialogEditorModel } from './dmp-invitation-dialog.editor.m export class DmpInvitationDialogComponent extends BaseComponent implements OnInit { dmpId: Guid; - editorModel: DmpInvitationDialogEditorModel; + editorModel: DmpEditorModel; formGroup: UntypedFormGroup; dmpUserRoleEnum = DmpUserRole; + selectedBlueprint: DmpBlueprint; readonly separatorKeysCodes: number[] = [ENTER, COMMA]; - usersAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { - filterFn: this.filterUsers.bind(this), - initialItems: (excludedItems: any[]) => this.filterUsers('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), - displayFn: (item) => typeof (item) === 'string' ? item : item.name, - titleFn: (item) => typeof (item) === 'string' ? item : item.name, - subtitleFn: (item) => item.email, - valueAssign: (item) => { - const result = typeof (item) === 'string' ? item : item.id; - return result; - }, - autoSelectFirstOptionOnBlur: true, - appendClassToItem: [{ - class: 'invalid-email', applyFunc: (item) => { - const val = typeof (item) === 'string' ? item : item.email; - const regexp = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/); - return !regexp.test(val); - } - }] - }; - constructor( public enumUtils: EnumUtils, public route: ActivatedRoute, @@ -70,42 +46,19 @@ export class DmpInvitationDialogComponent extends BaseComponent implements OnIni ) { super(); this.dmpId = data.dmpId; + this.editorModel = data ? new DmpEditorModel().fromModel(data) : new DmpEditorModel(); + this.selectedBlueprint = data?.blueprint; } ngOnInit() { - this.editorModel = new DmpInvitationDialogEditorModel(); this.formGroup = this.editorModel.buildForm(); } send() { - if (!this.formGroup.valid) { return; } - let inviteTypeValues: DmpUserInviteTypePersist[] = []; - this.formGroup.get('users').value.forEach(x => { - let inviteType: DmpUserInviteTypePersist; - if (!(/^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$/).test(x)) { - inviteType = { - userId: null, - email: x - }; - }else{ - inviteType = { - userId: Guid.parse(x), - email: null - }; - } - inviteTypeValues.push(inviteType) - }) - const value: DmpUserInvitePersist = { - role: this.formGroup.get('role').value, - users: inviteTypeValues - } - // invitationObject.users.push(...(this.formGroup.get('users').value).filter(user => typeof (user) === 'string').map(email => ({ email: email, name: email }))); - // invitationObject.users.push(...(this.formGroup.get('users').value).filter(user => typeof (user) !== 'string')); - // this.emails.forEach(email => { - // invitationObject.users.push({ email: email, name: email }); - // }); + if (!this.formGroup.get("users").valid) { return; } + const userFormData = this.formGroup.get("users").value as DmpUserPersist[]; - this.dmpService.inviteUsers(this.dmpId, value) + this.dmpService.inviteUsers(this.dmpId, {users: userFormData}) .pipe(takeUntil(this._destroyed)) .subscribe( complete => { @@ -120,23 +73,6 @@ export class DmpInvitationDialogComponent extends BaseComponent implements OnIni this.dialogRef.close(); } - filterUsers(like: string): Observable { - const lookup: UserLookup = new UserLookup(); - lookup.page = { size: 100, offset: 0 }; - // if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; } - // if (ids && ids.length > 0) { lookup.ids = ids; } - lookup.isActive = [IsActive.Active]; - lookup.project = { - fields: [ - nameof(x => x.id), - nameof(x => x.name) - ] - }; - lookup.order = { items: [nameof(x => x.name)] }; - if (like) { lookup.like = this.filterService.transformLike(like); } - return this.userService.queryDmpAssociated(lookup).pipe(takeUntil(this._destroyed), map(x => x.items)); - } - hasValue(): boolean { return this.formGroup.get('users') && this.formGroup.get('users').value && this.formGroup.get('users').value.length > 0; } diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.editor.model.ts b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.editor.model.ts deleted file mode 100644 index 088131fdc..000000000 --- a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.editor.model.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; -import { DmpUserRole } from "@app/core/common/enum/dmp-user-role"; -import { DmpUserInvitePersist, DmpUserInviteTypePersist } from "@app/core/model/dmp/dmp"; -import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; -import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; -import { Validation, ValidationContext } from '@common/forms/validation/validation-context'; - -export class DmpInvitationDialogEditorModel implements DmpUserInvitePersist { - users: DmpUserInviteTypePersist[]; - role: DmpUserRole = DmpUserRole.User; - - public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); - protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); - - constructor() { } - - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { - if (context == null) { context = this.createValidationContext(); } - - return this.formBuilder.group({ - users: [{ value: this.users, disabled: disabled }, context.getValidation('users').validators], - role: [{ value: this.role, disabled: disabled }, context.getValidation('role').validators], - }); - } - - createValidationContext(): ValidationContext { - const baseContext: ValidationContext = new ValidationContext(); - const baseValidationArray: Validation[] = new Array(); - baseValidationArray.push({ key: 'users', validators: [BackendErrorValidator(this.validationErrorModel, 'users')] }); - baseValidationArray.push({ key: 'role', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'role')] }); - baseContext.validation = baseValidationArray; - return baseContext; - } -} diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.module.ts b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.module.ts index f3e47a248..b8cf4ee3d 100644 --- a/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.module.ts +++ b/dmp-frontend/src/app/ui/dmp/invitation/dialog/dmp-invitation-dialog.module.ts @@ -4,9 +4,10 @@ import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.mod import { RichTextEditorModule } from "@app/library/rich-text-editor/rich-text-editor.module"; import { CommonUiModule } from '@common/ui/common-ui.module'; import { DmpInvitationDialogComponent } from './dmp-invitation-dialog.component'; +import { UserFieldModule } from '../../user-field/user-field.module'; @NgModule({ - imports: [CommonUiModule, FormsModule, ReactiveFormsModule, AutoCompleteModule, RichTextEditorModule], + imports: [CommonUiModule, FormsModule, ReactiveFormsModule, AutoCompleteModule, RichTextEditorModule, UserFieldModule], declarations: [DmpInvitationDialogComponent], exports: [DmpInvitationDialogComponent] }) 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 27c4101c7..3f286d078 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 @@ -38,6 +38,7 @@ import { takeUntil } from 'rxjs/operators'; import { nameof } from 'ts-simple-nameof'; import { DmpInvitationDialogComponent } from '../invitation/dialog/dmp-invitation-dialog.component'; import { ReferenceTypeService } from '@app/core/services/reference-type/reference-type.service'; +import { DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint'; @Component({ selector: 'app-dmp-overview', @@ -47,6 +48,7 @@ import { ReferenceTypeService } from '@app/core/services/reference-type/referenc export class DmpOverviewComponent extends BaseComponent implements OnInit { dmp: Dmp; + selectedBlueprint: DmpBlueprint; researchers: DmpReference[] = []; isNew = true; isFinalized = false; @@ -108,6 +110,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { .pipe(takeUntil(this._destroyed)) .subscribe(data => { this.dmp = data; + this.selectedBlueprint= data.blueprint; this.researchers = this.referenceService.getReferencesForTypes(this.dmp?.dmpReferences, [this.referenceTypeService.getResearcherReferenceType()]); if (!this.hasDoi()) { this.selectedModel = this.dmp.entityDois[0]; @@ -566,7 +569,8 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { restoreFocus: false, data: { dmpId: rowId, - dmpName: rowName + dmpName: rowName, + blueprint: this.selectedBlueprint } }); } @@ -738,6 +742,11 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { [nameof(x => x.dmpReferences), nameof(x => x.reference), nameof(x => x.type)].join('.'), [nameof(x => x.dmpReferences), nameof(x => x.reference), nameof(x => x.source)].join('.'), [nameof(x => x.dmpReferences), nameof(x => x.reference), nameof(x => x.reference)].join('.'), + + [nameof(x => x.blueprint), nameof(x => x.id)].join('.'), + [nameof(x => x.blueprint), nameof(x => x.definition)].join('.'), + [nameof(x => x.blueprint), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.id)].join('.'), + [nameof(x => x.blueprint), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.label)].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 new file mode 100644 index 000000000..eb2f1d7ab --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.html @@ -0,0 +1,71 @@ +
+
+
+ {{userIndex + 1}} +
+
drag_indicator
+
+ +
+ {{enumUtils.toDmpUserTypeString(userType)}} +
+
+
+
+
+
+ + {{'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 new file mode 100644 index 000000000..dbaf6e932 --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.scss @@ -0,0 +1,9 @@ +.drag-handle { + cursor: move; + color: var(--primary-color); +} + +.drag-handle-disabled { + cursor: auto; + color: rgba(0, 0, 0, 0.38);; +} \ No newline at end of file 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 new file mode 100644 index 000000000..3ef6f78fb --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/user-field/user-field.component.ts @@ -0,0 +1,74 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { FormArray, UntypedFormArray, UntypedFormGroup } from '@angular/forms'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { BaseComponent } from '@common/base/base.component'; +import { DmpEditorModel, DmpUserEditorModel } from '../dmp-editor-blueprint/dmp-editor.model'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; +import { DmpUserType } from '@app/core/common/enum/dmp-user-type'; +import { DmpUserRole } from '@app/core/common/enum/dmp-user-role'; +import { UserService } from '@app/core/services/user/user.service'; +import { DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint'; + +@Component({ + selector: 'app-user-field-component', + templateUrl: 'user-field.component.html', + styleUrls: ['./user-field.component.scss'] +}) +export class UserFieldComponent extends BaseComponent implements OnInit { + + @Input() form; + @Input() validationErrorModel: ValidationErrorModel; + @Input() label: string = null; + @Input() required: boolean = false; + @Input() placeholder: string; + @Input() sections: DmpBlueprintDefinitionSection[] = null; + + dmpUserTypeEnum = DmpUserType; + dmpUserTypeEnumValues = this.enumUtils.getEnumValues(DmpUserType); + dmpUserRoleEnumValues = this.enumUtils.getEnumValues(DmpUserRole); + + multipleAutoCompleteSearchConfiguration: MultipleAutoCompleteConfiguration; + + constructor( + public enumUtils: EnumUtils, + public userService: UserService + ) { super(); } + + ngOnInit() { + } + + addUser(): void { + const userArray = this.form.get('users') as FormArray; + const dmpUser: DmpUserEditorModel = new DmpUserEditorModel(this.validationErrorModel); + userArray.push(dmpUser.buildForm({rootPath: "users[" + userArray.length + "]."})); + } + + removeUser(userIndex: number): void { + (this.form.get('users') as FormArray).removeAt(userIndex); + + DmpEditorModel.reApplyPropertiesValidators( + { + formGroup: this.form, + validationErrorModel: this.validationErrorModel + } + ); + this.form.get('users').markAsDirty(); + } + + dropUsers(event: CdkDragDrop) { + const usersFormArray = (this.form.get('users') as FormArray); + + moveItemInArray(usersFormArray.controls, event.previousIndex, event.currentIndex); + usersFormArray.updateValueAndValidity(); + + DmpEditorModel.reApplyPropertiesValidators( + { + formGroup: this.form, + validationErrorModel: this.validationErrorModel + } + ); + this.form.get('users').markAsDirty(); + } +} diff --git a/dmp-frontend/src/app/ui/dmp/user-field/user-field.module.ts b/dmp-frontend/src/app/ui/dmp/user-field/user-field.module.ts new file mode 100644 index 000000000..9365117fa --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/user-field/user-field.module.ts @@ -0,0 +1,22 @@ +import { NgModule } from '@angular/core'; +import { FormattingModule } from '@app/core/formatting.module'; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { UserFieldComponent } from './user-field.component'; + +@NgModule({ + imports: [ + CommonUiModule, + CommonFormsModule, + FormattingModule, + AutoCompleteModule + ], + declarations: [ + UserFieldComponent + ], + exports: [ + UserFieldComponent + ] +}) +export class UserFieldModule { }