add dmpUser ui

This commit is contained in:
amentis 2024-02-20 17:00:20 +02:00
parent 6e1f1d110a
commit 0cbcae3afe
11 changed files with 233 additions and 17 deletions

View File

@ -11,7 +11,8 @@ public enum DmpBlueprintSystemFieldType implements DatabaseEnum<Short> {
Description((short)1),
Language((short)2),
Contact((short)3),
AccessRights((short)4);
AccessRights((short)4),
User((short)5);
private final Short value;
DmpBlueprintSystemFieldType(Short value) {

View File

@ -7,7 +7,10 @@ import java.util.Map;
public enum DmpUserRole implements DatabaseEnum<Short> {
Owner((short) 0), User((short) 1);
Owner((short) 0),
User((short) 1),
DescriptionContributor((short) 2),
Reviewer((short) 3);
private final Short value;

View File

@ -56,6 +56,9 @@ public class DmpPersist {
public static final String _descriptionTemplates = "descriptionTemplates";
private List<DmpUserPersist> users;
public static final String _users = "users";
private String hash;
public static final String _hash = "hash";
@ -132,6 +135,14 @@ public class DmpPersist {
this.descriptionTemplates = descriptionTemplates;
}
public List<DmpUserPersist> getUsers() {
return users;
}
public void setUsers(List<DmpUserPersist> users) {
this.users = users;
}
public String getHash() {
return hash;
}
@ -212,7 +223,12 @@ public class DmpPersist {
.iff(() -> !this.isListNullOrEmpty(item.getDescriptionTemplates()))
.on(DmpPersist._descriptionTemplates)
.over(item.getDescriptionTemplates())
.using((itm) -> this.validatorFactory.validator(DmpDescriptionTemplatePersist.DmpDescriptionTemplatePersistValidator.class))
.using((itm) -> this.validatorFactory.validator(DmpDescriptionTemplatePersist.DmpDescriptionTemplatePersistValidator.class)),
this.navSpec()
.iff(() -> !this.isListNullOrEmpty(item.getUsers()))
.on(DmpPersist._users)
.over(item.getUsers())
.using((itm) -> this.validatorFactory.validator(DmpUserPersist.DmpUserPersistValidator.class))
);
}
}

View File

@ -9,5 +9,6 @@ export enum DmpBlueprintSystemFieldType {
// GRANT = 7,
// PROJECT = 8,
// LICENSE = 9,
AccessRights = 4
AccessRights = 4,
User = 5
}

View File

@ -1,4 +1,6 @@
export enum DmpUserRole {
Owner = 0,
User = 1
User = 1,
DescriptionContributor = 2,
Reviewer= 3
}

View File

@ -78,6 +78,7 @@ export interface DmpPersist extends BaseEntityPersist {
blueprint: Guid;
accessType: DmpAccessType;
descriptionTemplates: DmpDescriptionTemplatePersist[];
users: DmpUserPersist[];
}
export interface DmpPropertiesPersist {

View File

@ -138,6 +138,7 @@ export class EnumUtils {
case DmpBlueprintSystemFieldType.Language: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.LANGUAGE');
case DmpBlueprintSystemFieldType.Contact: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.CONTACT');
case DmpBlueprintSystemFieldType.AccessRights: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.ACCESS_RIGHTS');
case DmpBlueprintSystemFieldType.User: return this.language.instant('TYPES.DMP-BLUEPRINT-SYSTEM-FIELD-TYPE.USER');
}
}
@ -231,6 +232,8 @@ export class EnumUtils {
switch (role) {
case DmpUserRole.Owner: return this.language.instant('TYPES.DMP-USER-ROLE.OWNER');
case DmpUserRole.User: return this.language.instant('TYPES.DMP-USER-ROLE.USER');
case DmpUserRole.DescriptionContributor: return this.language.instant('TYPES.DMP-USER-ROLE.DESCRIPTION-CONTRIBUTOR');
case DmpUserRole.Reviewer: return this.language.instant('TYPES.DMP-USER-ROLE.REVIEWER');
}
}

View File

@ -215,7 +215,7 @@
</div>
</div>
<div class="col-auto">
<button mat-icon-button class="action-list-icon" matTooltip="{{'DMP-EDITOR.FIELDS.REMOVE-CONTACT' | translate}}" (click)="removeContact(contactIndex)" [disabled]="formGroup.disabled">
<button mat-icon-button class="action-list-icon" matTooltip="{{'DMP-EDITOR.ACTIONS1.REMOVE-CONTACT' | translate}}" (click)="removeContact(contactIndex)" [disabled]="formGroup.disabled">
<mat-icon>delete</mat-icon>
</button>
</div>
@ -242,6 +242,52 @@
<mat-error *ngIf="formGroup.get('accessType').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div *ngIf="field.systemFieldType == dmpBlueprintSystemFieldTypeEnum.User">
<div cdkDropList class="col-12" (cdkDropListDropped)="dropUsers($event)">
<div *ngFor="let user of formGroup.get('users').controls; let userIndex=index;" cdkDrag class="row align-items-center" [cdkDragDisabled]="formGroup.disabled">
<div class="col-auto">
<span style="font-size: 15px;">{{userIndex + 1}}</span>
</div>
<div class="col-auto d-flex"><mat-icon [ngClass]="{'drag-handle-disabled': formGroup.disabled}" cdkDragHandle class="drag-handle">drag_indicator</mat-icon></div>
<div class="col pt-4">
<div class="row">
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'DMP-EDITOR.FIELDS1.USER' | translate}}</mat-label>
<app-single-auto-complete [required]= "true" [formControl]="user.get('user')" [hidePlaceholder]="true" [configuration]="userService.singleAutocompleteConfiguration"></app-single-auto-complete>
<mat-error *ngIf="user.get('user').hasError('backendError')">{{user.get('user').getError('backendError').message}}</mat-error>
<mat-error *ngIf="user.get('user').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'DMP-EDITOR.FIELDS1.USER-ROLE' | translate}}</mat-label>
<mat-select [formControl]="user.get('role')">
<mat-option *ngFor="let userRole of dmpUserRoleEnumValues" [value]="userRole">{{enumUtils.toDmpUserRoleString(userRole)}}</mat-option>
</mat-select>
<mat-error *ngIf="user.get('role').hasError('backendError')">{{user.get('role').getError('backendError').message}}</mat-error>
<mat-error *ngIf="user.get('role').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div>
<div class="col-auto">
<button mat-icon-button class="action-list-icon" matTooltip="{{'DMP-EDITOR.ACTIONS1.REMOVE-USER' | translate}}" (click)="removeUser(userIndex)" [disabled]="formGroup.disabled">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
<mat-error *ngIf="formGroup.get('users').hasError('backendError')">{{formGroup.get('users').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('users').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</div>
<div class="row">
<div class="col">
<button mat-icon-button (click)="addUser()" [disabled]="formGroup.disabled">
<mat-icon>add</mat-icon>
</button>
</div>
</div>
</div>
</div>
<div *ngIf="field.category === dmpBlueprintSectionFieldCategoryEnum.ReferenceType">
<div>

View File

@ -44,6 +44,7 @@ import { map, takeUntil } from 'rxjs/operators';
import { DmpEditorModel } from './dmp-editor.model';
import { DmpEditorResolver } from './dmp-editor.resolver';
import { DmpEditorService } from './dmp-editor.service';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
@Component({
selector: 'app-dmp-editor',
@ -67,6 +68,7 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
dmpAccessTypeEnumValues = this.enumUtils.getEnumValues<DmpAccessType>(DmpAccessType);
dmpContactTypeEnum = DmpContactType;
dmpContactTypeEnumValues = this.enumUtils.getEnumValues<DmpContactType>(DmpContactType);
dmpUserRoleEnumValues = this.enumUtils.getEnumValues<DmpUserRole>(DmpUserRole);
singleAutocompleteBlueprintConfiguration: SingleAutoCompleteConfiguration = {
initialItems: (data?: any) => this.dmpBlueprintService.query(this.dmpBlueprintService.buildAutocompleteLookup(null, null, null, [DmpBlueprintStatus.Finalized])).pipe(map(x => x.items)),
filterFn: (searchQuery: string, data?: any) => this.dmpBlueprintService.query(this.dmpBlueprintService.buildAutocompleteLookup(searchQuery, null, null, [DmpBlueprintStatus.Finalized])).pipe(map(x => x.items)),
@ -353,10 +355,10 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
}
dropContacts(event: CdkDragDrop<string[]>) {
const sectionsFormArray = (this.formGroup.get('properties').get('contacts') as FormArray);
const contactsFormArray = (this.formGroup.get('properties').get('contacts') as FormArray);
moveItemInArray(sectionsFormArray.controls, event.previousIndex, event.currentIndex);
sectionsFormArray.updateValueAndValidity();
moveItemInArray(contactsFormArray.controls, event.previousIndex, event.currentIndex);
contactsFormArray.updateValueAndValidity();
DmpEditorModel.reApplyPropertiesValidators(
{
@ -367,6 +369,43 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> 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<string[]>) {
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();
}
//
//
// Descriptions

View File

@ -2,9 +2,10 @@ import { FormArray, FormControl, UntypedFormArray, UntypedFormBuilder, UntypedFo
import { DmpAccessType } from "@app/core/common/enum/dmp-access-type";
import { DmpContactType } from "@app/core/common/enum/dmp-contact-type";
import { DmpStatus } from "@app/core/common/enum/dmp-status";
import { DmpUserRole } from "@app/core/common/enum/dmp-user-role";
import { IsActive } from "@app/core/common/enum/is-active.enum";
import { DmpBlueprint } from "@app/core/model/dmp-blueprint/dmp-blueprint";
import { Dmp, DmpBlueprintValue, DmpBlueprintValuePersist, DmpContact, DmpContactPersist, DmpDescriptionTemplate, DmpDescriptionTemplatePersist, DmpPersist, DmpProperties, DmpPropertiesPersist, DmpReferenceDataPersist, DmpReferencePersist } from "@app/core/model/dmp/dmp";
import { Dmp, DmpBlueprintValue, DmpBlueprintValuePersist, DmpContact, DmpContactPersist, DmpDescriptionTemplate, DmpDescriptionTemplatePersist, DmpPersist, DmpProperties, DmpPropertiesPersist, DmpReferenceDataPersist, DmpReferencePersist, DmpUser, DmpUserPersist } from "@app/core/model/dmp/dmp";
import { DmpReference } from "@app/core/model/dmp/dmp-reference";
import { ReferencePersist } from "@app/core/model/reference/reference";
import { BaseEditorModel } from "@common/base/base-form-editor-model";
@ -22,6 +23,7 @@ export class DmpEditorModel extends BaseEditorModel implements DmpPersist {
blueprint: Guid;
accessType: DmpAccessType;
descriptionTemplates: DmpDescriptionTemplateEditorModel[] = [];
users: DmpUserEditorModel[] = [];
permissions: string[];
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
@ -39,6 +41,7 @@ export class DmpEditorModel extends BaseEditorModel implements DmpPersist {
this.language = item.language;
this.blueprint = item.blueprint?.id;
this.accessType = item.accessType;
if (item?.dmpUsers) { item.dmpUsers.map(x => this.users.push(new DmpUserEditorModel(this.validationErrorModel).fromModel(x))); }
item.blueprint.definition.sections.forEach(section => {
if (section.hasTemplates) {
@ -83,6 +86,13 @@ export class DmpEditorModel extends BaseEditorModel implements DmpPersist {
properties: this.properties.buildForm({
rootPath: `properties.`
}),
users: this.formBuilder.array(
(this.users ?? []).map(
(item, index) => item.buildForm({
rootPath: `users[${index}].`
})
), context.getValidation('users').validators
),
description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
language: [{ value: this.language, disabled: disabled }, context.getValidation('language').validators],
blueprint: [{ value: this.blueprint, disabled: disabled }, context.getValidation('blueprint').validators],
@ -116,6 +126,7 @@ export class DmpEditorModel extends BaseEditorModel implements DmpPersist {
baseValidationArray.push({ key: 'blueprint', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'blueprint')] });
baseValidationArray.push({ key: 'accessType', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'accessType')] });
baseValidationArray.push({ key: 'descriptionTemplates', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'descriptionTemplates')] });
baseValidationArray.push({ key: 'users', validators: [BackendErrorValidator(this.validationErrorModel, `users`)] });
baseValidationArray.push({ key: 'hash', validators: [] });
baseContext.validation = baseValidationArray;
@ -127,6 +138,11 @@ 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,
validationErrorModel: ValidationErrorModel,
@ -140,10 +156,21 @@ export class DmpEditorModel extends BaseEditorModel implements DmpPersist {
validationErrorModel: validationErrorModel
});
(formGroup.get('descriptionTemplates') as FormArray).controls?.forEach(
(control, index) => DmpDescriptionTemplateEditorModel.reapplyValidators({
const descriptionTemplates = formGroup?.get('descriptionTemplates') as UntypedFormGroup;
const keys = Object.keys(descriptionTemplates.value as Object);
keys.forEach((key) => {
const control = descriptionTemplates?.get(key);
DmpBlueprintValueEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `descriptionTemplates[${index}].`,
rootPath: `descriptionTemplates[${key}].`,
validationErrorModel: validationErrorModel
})
});
(formGroup.get('users') as FormArray).controls?.forEach(
(control, index) => DmpUserEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `users[${index}].`,
validationErrorModel: validationErrorModel
})
);
@ -415,6 +442,77 @@ export class DmpContactEditorModel implements DmpContactPersist {
}
}
export class DmpUserEditorModel implements DmpUserPersist {
user: Guid;
role: DmpUserRole;
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
constructor(
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
) { }
fromModel(item: DmpUser): DmpUserEditorModel {
if(item?.user?.id) this.user = item.user.id;
this.role = item.role;
return this;
}
buildForm(params?: {
context?: ValidationContext,
disabled?: boolean,
rootPath?: string
}): UntypedFormGroup {
let { context = null, disabled = false, rootPath } = params ?? {}
if (context == null) {
context = DmpUserEditorModel.createValidationContext({
validationErrorModel: this.validationErrorModel,
rootPath
});
}
return this.formBuilder.group({
user: [{ value: this.user, disabled: disabled }, context.getValidation('user').validators],
role: [{ value: this.role, disabled: disabled }, context.getValidation('role').validators],
});
}
static createValidationContext(params: {
rootPath?: string,
validationErrorModel: ValidationErrorModel
}): ValidationContext {
const { rootPath = '', validationErrorModel } = params;
const baseContext: ValidationContext = new ValidationContext();
const baseValidationArray: Validation[] = new Array<Validation>();
baseValidationArray.push({ key: 'user', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}user`)] });
baseValidationArray.push({ key: 'role', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}role`)] });
baseContext.validation = baseValidationArray;
return baseContext;
}
static reapplyValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
const context = DmpUserEditorModel.createValidationContext({
rootPath,
validationErrorModel
});
['user', 'role'].forEach(keyField => {
const control = formGroup?.get(keyField);
control?.clearValidators();
control?.addValidators(context.getValidation(keyField).validators);
})
}
}
export class DmpReferenceEditorModel implements DmpReferencePersist {
id: Guid;
reference: ReferencePersist;

View File

@ -1745,7 +1745,8 @@
"USER": "User",
"FIRST-NAME": "First Name",
"LAST-NAME": "Last Name",
"EMAIL": "Email"
"EMAIL": "Email",
"USER-ROLE": "Role"
},
"ACTIONS1": {
"GO-TO-GRANT": "Go To DMP Grant",
@ -1761,7 +1762,9 @@
"PERMISSION": "You have no permission to edit this DMP",
"INSERT-MANUALLY": "Insert it manually",
"CREATE-DATASET": "Create new one",
"DISABLED-EXPORT": "Please save your changes to export this DMP"
"DISABLED-EXPORT": "Please save your changes to export this DMP",
"REMOVE-CONTACT": "Remove Contact",
"REMOVE-USER": "Remove User"
},
"PLACEHOLDER": {
"DESCRIPTION": "Fill with description",
@ -2163,7 +2166,9 @@
},
"DMP-USER-ROLE": {
"OWNER": "Owner",
"USER": "User"
"USER": "User",
"DESCRIPTION-CONTRIBUTOR": "Description Contributor",
"REVIEWER": "Reviewer"
},
"EXTERNAL-DATASET-TYPE": {
"SOURCE": "Source",
@ -2287,7 +2292,8 @@
"DESCRIPTION": "Description",
"LANGUAGE": "Language",
"CONTACT": "Contact",
"ACCESS_RIGHTS": "Access"
"ACCESS_RIGHTS": "Access",
"USER": "User"
},
"DMP-BLUEPRINT-EXTRA-FIELD-DATA-TYPE": {
"DATE": "Date",