diff --git a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts
index c5a76d3b0..44b8ba390 100644
--- a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts
+++ b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts
@@ -1,19 +1,16 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
+import { DescriptionStatus } from '@app/core/common/enum/description-status';
+import { DescriptionTemplateVersionStatus } from '@app/core/common/enum/description-template-version-status';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { Description } from '@app/core/model/description/description';
-import { DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
-import { Dmp, DmpDescriptionTemplate } from '@app/core/model/dmp/dmp';
-import { DescriptionTemplateService } from '@app/core/services/description-template/description-template.service';
+import { DmpDescriptionTemplate } from '@app/core/model/dmp/dmp';
import { DescriptionService } from '@app/core/services/description/description.service';
-import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { BaseComponent } from '@common/base/base.component';
import { takeUntil } from 'rxjs/operators';
import { DeprecatedDescriptionTemplateDialog } from './dialog-description-template/deprecated-description-template-dialog.component';
-import { DescriptionTemplateVersionStatus } from '@app/core/common/enum/description-template-version-status';
-import { DescriptionStatus } from '@app/core/common/enum/description-status';
@Component({
selector: 'app-description-base-fields-editor-component',
@@ -47,15 +44,17 @@ export class DescriptionBaseFieldsEditorComponent extends BaseComponent {
const currentVersionsOfDescriptionTemplates = dmpDescriptionTemplates.map(x => x.currentDescriptionTemplate);
this.availableDescriptionTemplates.push(...currentVersionsOfDescriptionTemplates);
- const isPreviousVersion: boolean = this.description.descriptionTemplate.versionStatus === DescriptionTemplateVersionStatus.Previous;
- if (isPreviousVersion === true) {
- if (this.description.status === DescriptionStatus.Draft) {
- this.openDeprecatedDescriptionTemplateDialog();
+ if (this.description?.descriptionTemplate != null) {
+ const isPreviousVersion: boolean = this.description.descriptionTemplate.versionStatus === DescriptionTemplateVersionStatus.Previous;
+ if (isPreviousVersion === true) {
+ if (this.description.status === DescriptionStatus.Draft) {
+ this.openDeprecatedDescriptionTemplateDialog();
+ } else {
+ this.availableDescriptionTemplates.push(this.description.descriptionTemplate);
+ }
} else {
this.availableDescriptionTemplates.push(this.description.descriptionTemplate);
}
- } else {
- this.availableDescriptionTemplates.push(this.description.descriptionTemplate);
}
}
@@ -67,19 +66,19 @@ export class DescriptionBaseFieldsEditorComponent extends BaseComponent {
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(
result => {
- if(result) {
+ if (result) {
this.descriptionService.updateDescriptionTemplate({
id: this.description.id,
hash: this.description.hash
})
- .subscribe(
- result => {
- this.refresh.emit(result);
- },
- error => console.error(error));
+ .subscribe(
+ result => {
+ this.refresh.emit(result);
+ },
+ error => console.error(error));
} else {
this.availableDescriptionTemplates.push(this.description.descriptionTemplate);
}
- });
+ });
}
}
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 c903e861c..66a6bb93c 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
@@ -111,13 +111,13 @@
chevron_left
{{'DMP-EDITOR.ACTIONS.PREVIOUS-STEP' | translate}}
- = selectedBlueprint?.definition?.sections?.length }" (click)="nextStep()">
+
= selectedBlueprint?.definition?.sections?.length }" (click)="nextStep()">
{{'DMP-EDITOR.ACTIONS.NEXT-STEP' | translate}}
chevron_right
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 078d541d8..5348b035f 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
@@ -88,7 +88,7 @@ export class DmpEditorComponent extends BaseEditor implemen
filterFn: (searchQuery: string, data?: any) => this.dmpBlueprintService.query(this.dmpBlueprintService.buildAutocompleteLookup(searchQuery, null, null, [DmpBlueprintStatus.Finalized])).pipe(map(x => x.items)),
getSelectedItem: (selectedItem: any) => this.dmpBlueprintService.query(this.dmpBlueprintService.buildAutocompleteLookup(null, null, [selectedItem])).pipe(map(x => x.items[0])),
displayFn: (item: DmpBlueprint) => item.label,
- subtitleFn: (item: DmpBlueprint) => this.language.instant('DMP-EDITOR.FIELDS.DMP-BLUEPRINT-VERSION') + ' '+ item.version,
+ subtitleFn: (item: DmpBlueprint) => this.language.instant('DMP-EDITOR.FIELDS.DMP-BLUEPRINT-VERSION') + ' ' + item.version,
titleFn: (item: DmpBlueprint) => item.label,
valueAssign: (item: DmpBlueprint) => item.id,
};
@@ -174,14 +174,14 @@ export class DmpEditorComponent extends BaseEditor implemen
try {
this.editorModel = data ? new DmpEditorModel().fromModel(data) : new DmpEditorModel();
if (data) {
- if(data.descriptions){
+ if (data.descriptions) {
if (data.status == DmpStatus.Finalized) {
data.descriptions = data.descriptions.filter(x => x.isActive === IsActive.Active && x.status === DescriptionStatus.Finalized);
} else {
data.descriptions = data.descriptions.filter(x => x.isActive === IsActive.Active && x.status !== DescriptionStatus.Canceled);
}
}
- if(data.dmpDescriptionTemplates){
+ if (data.dmpDescriptionTemplates) {
data.dmpDescriptionTemplates = data.dmpDescriptionTemplates.filter(x => x.isActive === IsActive.Active);
}
@@ -304,6 +304,11 @@ export class DmpEditorComponent extends BaseEditor implemen
// Steps
//
//
+
+ get maxSteps(): number {
+ return this.item?.blueprint?.definition?.sections?.length ?? 0;
+ }
+
changeStep(index: number) {
this.step = index;
this.resetScroll();
@@ -389,7 +394,8 @@ export class DmpEditorComponent extends BaseEditor implemen
DmpEditorModel.reApplyPropertiesValidators(
{
formGroup: this.formGroup,
- validationErrorModel: this.editorModel.validationErrorModel
+ validationErrorModel: this.editorModel.validationErrorModel,
+ blueprint: this.item.blueprint
}
);
this.formGroup.get('properties').get('contacts').markAsDirty();
@@ -404,7 +410,8 @@ export class DmpEditorComponent extends BaseEditor implemen
DmpEditorModel.reApplyPropertiesValidators(
{
formGroup: this.formGroup,
- validationErrorModel: this.editorModel.validationErrorModel
+ validationErrorModel: this.editorModel.validationErrorModel,
+ blueprint: this.item.blueprint
}
);
this.formGroup.get('properties').get('contacts').markAsDirty();
@@ -455,32 +462,32 @@ export class DmpEditorComponent extends BaseEditor implemen
});
}
- canAddDescription(section: DmpBlueprintDefinitionSection ): boolean{
- if(section.hasTemplates){
- if (section.descriptionTemplates?.length > 0){
+ canAddDescription(section: DmpBlueprintDefinitionSection): boolean {
+ if (section.hasTemplates) {
+ if (section.descriptionTemplates?.length > 0) {
const descriptions = this.descriptionsInSection(section.id)
- if (this.item.dmpDescriptionTemplates.filter(x => x.sectionId == section.id).length > descriptions.map(x => x.dmpDescriptionTemplate).length){
+ if (this.item.dmpDescriptionTemplates.filter(x => x.sectionId == section.id).length > descriptions.map(x => x.dmpDescriptionTemplate).length) {
return true;
}
- let multiplicityValidResults :boolean[] = [];
+ let multiplicityValidResults: boolean[] = [];
section.descriptionTemplates.forEach(sectionDescriptionTemplate => {
- if (sectionDescriptionTemplate.maxMultiplicity != null){
+ if (sectionDescriptionTemplate.maxMultiplicity != null) {
const count = descriptions.filter(x => x.dmpDescriptionTemplate.descriptionTemplateGroupId == sectionDescriptionTemplate.descriptionTemplateGroupId).length || 0;
if (count >= sectionDescriptionTemplate.maxMultiplicity) multiplicityValidResults.push(false);
else multiplicityValidResults.push(true);
- }else{
+ } else {
multiplicityValidResults.push(true);
}
})
- if(multiplicityValidResults.includes(true)) return true
+ if (multiplicityValidResults.includes(true)) return true
else return false;
- }else{
+ } else {
return true;
}
- }else{
+ } else {
return false;
}
}
@@ -504,10 +511,10 @@ export class DmpEditorComponent extends BaseEditor implemen
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(groupId => {
if (groupId) {
let data = this.formGroup.get('descriptionTemplates').get(sectionId.toString()).value as Guid[];
- if (data){
+ if (data) {
data.push(groupId);
this.formGroup.get('descriptionTemplates').get(sectionId.toString()).patchValue(data);
- } else{
+ } else {
this.formGroup.get('descriptionTemplates').get(sectionId.toString()).patchValue([groupId]);
}
}
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 86c991402..9559ca651 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
@@ -1,11 +1,12 @@
-import { FormArray, FormControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
+import { FormArray, FormControl, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { DmpAccessType } from "@app/core/common/enum/dmp-access-type";
+import { DmpBlueprintFieldCategory } from "@app/core/common/enum/dmp-blueprint-field-category";
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 { DmpUserType } from "@app/core/common/enum/dmp-user-type";
import { IsActive } from "@app/core/common/enum/is-active.enum";
-import { DmpBlueprint } from "@app/core/model/dmp-blueprint/dmp-blueprint";
+import { DmpBlueprint, FieldInSection } from "@app/core/model/dmp-blueprint/dmp-blueprint";
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";
@@ -103,8 +104,8 @@ export class DmpEditorModel extends BaseEditorModel implements DmpPersist {
const descriptionTemplatesFormGroup = this.formBuilder.group({});
(this.descriptionTemplates ?? []).filter(x => x?.sectionId).map(x => x.sectionId).map(
- (item, index) => descriptionTemplatesFormGroup.addControl(item.toString(),
- new FormControl(this.descriptionTemplates?.filter(x => x.sectionId === item)?.filter(x => x.descriptionTemplateGroupId).map(x => x.descriptionTemplateGroupId) || [], context.getValidation('descriptionTemplates').validators))
+ (item, index) => descriptionTemplatesFormGroup.addControl(item.toString(),
+ new FormControl(this.descriptionTemplates?.filter(x => x.sectionId === item)?.filter(x => x.descriptionTemplateGroupId).map(x => x.descriptionTemplateGroupId) || [], context.getValidation('descriptionTemplates').validators))
);
// // buildForm({
// // rootPath: `descriptionTemplates[${index}].`
@@ -120,13 +121,16 @@ export class DmpEditorModel extends BaseEditorModel implements DmpPersist {
const baseValidationArray: Validation[] = new Array();
baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] });
baseValidationArray.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
- baseValidationArray.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] });
- baseValidationArray.push({ key: 'properties', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'properties')] });
+ baseValidationArray.push({ key: 'status', validators: [BackendErrorValidator(this.validationErrorModel, 'status')] });
+ baseValidationArray.push({ key: 'properties', validators: [BackendErrorValidator(this.validationErrorModel, 'properties')] });
baseValidationArray.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'description')] });
- baseValidationArray.push({ key: 'language', validators: [BackendErrorValidator(this.validationErrorModel, 'language')] });
- baseValidationArray.push({ key: 'blueprint', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'blueprint')] });
- baseValidationArray.push({ key: 'accessType', validators: [BackendErrorValidator(this.validationErrorModel, 'accessType')] });
+ baseValidationArray.push({ key: 'language', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'language')] });
+ baseValidationArray.push({ key: 'blueprint', validators: [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: 'dmpDescriptionValidator', validators: [] });
+
baseValidationArray.push({ key: 'users', validators: [BackendErrorValidator(this.validationErrorModel, `users`)] });
baseValidationArray.push({ key: 'hash', validators: [] });
@@ -143,6 +147,7 @@ export class DmpEditorModel extends BaseEditorModel implements DmpPersist {
static reApplyPropertiesValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
+ blueprint: DmpBlueprint
}): void {
const { formGroup, validationErrorModel } = params;
@@ -150,20 +155,36 @@ export class DmpEditorModel extends BaseEditorModel implements DmpPersist {
DmpPropertiesEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `properties.`,
- validationErrorModel: validationErrorModel
+ validationErrorModel: validationErrorModel,
+ blueprint: params.blueprint
});
+ }
+
+ static reApplyDescriptionTemplateValidators(params: {
+ formGroup: UntypedFormGroup,
+ validationErrorModel: ValidationErrorModel,
+ }): void {
+
+ const { formGroup, validationErrorModel } = params;
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({
+ DmpDescriptionTemplateEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `descriptionTemplates[${key}].`,
validationErrorModel: validationErrorModel
})
});
+ }
+ static reApplyUsersValidators(params: {
+ formGroup: UntypedFormGroup,
+ validationErrorModel: ValidationErrorModel,
+ }): void {
+
+ const { formGroup, validationErrorModel } = params;
(formGroup.get('users') as FormArray).controls?.forEach(
(control, index) => DmpUserEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
@@ -186,14 +207,16 @@ export class DmpPropertiesEditorModel implements DmpPropertiesPersist {
fromModel(item: DmpProperties, dmpReferences: DmpReference[], dmpBlueprint: DmpBlueprint): DmpPropertiesEditorModel {
-
+
dmpBlueprint.definition.sections.forEach(section => {
section.fields?.forEach(field => {
- this.dmpBlueprintValues.set(field.id, new DmpBlueprintValueEditorModel(this.validationErrorModel).fromModel(
- {
- fieldId: field.id,
- fieldValue: item?.dmpBlueprintValues?.find(x => x.fieldId == field.id)?.fieldValue,
- }, dmpReferences));
+ if (field.category !== DmpBlueprintFieldCategory.System) {
+ this.dmpBlueprintValues.set(field.id, new DmpBlueprintValueEditorModel(this.validationErrorModel).fromModel(
+ {
+ fieldId: field.id,
+ fieldValue: item?.dmpBlueprintValues?.find(x => x.fieldId == field.id)?.fieldValue,
+ }, dmpReferences, field));
+ }
});
});
if (item?.contacts) { item.contacts.map(x => this.contacts.push(new DmpContactEditorModel(this.validationErrorModel).fromModel(x))); }
@@ -228,8 +251,8 @@ export class DmpPropertiesEditorModel implements DmpPropertiesPersist {
const dmpBlueprintValuesFormGroup = this.formBuilder.group({});
this.dmpBlueprintValues.forEach((value, key) => dmpBlueprintValuesFormGroup.addControl(key.toString(), value.buildForm({
- rootPath: `${rootPath}dmpBlueprintValues[${key}].`
- })), context.getValidation('dmpBlueprintValues')
+ rootPath: `${rootPath}dmpBlueprintValues[${key}].`
+ })), context.getValidation('dmpBlueprintValues')
)
formGroup.addControl('dmpBlueprintValues', dmpBlueprintValuesFormGroup);
@@ -254,7 +277,8 @@ export class DmpPropertiesEditorModel implements DmpPropertiesPersist {
static reapplyValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
- rootPath: string
+ rootPath: string,
+ blueprint: DmpBlueprint
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
@@ -266,9 +290,10 @@ export class DmpPropertiesEditorModel implements DmpPropertiesPersist {
DmpBlueprintValueEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `${rootPath}dmpBlueprintValues[${key}].`,
- validationErrorModel: validationErrorModel
+ validationErrorModel: validationErrorModel,
+ isRequired: params.blueprint.definition.sections.flatMap(x => x.fields).find(x => x.id.toString() == key).required
})
- });
+ });
(formGroup.get('contacts') as FormArray).controls?.forEach(
(control, index) => DmpContactEditorModel.reapplyValidators({
@@ -284,6 +309,8 @@ export class DmpBlueprintValueEditorModel implements DmpBlueprintValuePersist {
fieldId: Guid;
fieldValue: string;
references: DmpReferencePersist[] = [];
+ isRequired: boolean = false;
+ category: DmpBlueprintFieldCategory;
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
@@ -291,7 +318,7 @@ export class DmpBlueprintValueEditorModel implements DmpBlueprintValuePersist {
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
) { }
- fromModel(item: DmpBlueprintValue, dmpReferences: DmpReference[]): DmpBlueprintValueEditorModel {
+ fromModel(item: DmpBlueprintValue, dmpReferences: DmpReference[], field: FieldInSection): DmpBlueprintValueEditorModel {
this.fieldId = item.fieldId;
this.fieldValue = item.fieldValue;
this.references = dmpReferences?.filter(x => x.data.blueprintFieldId == this.fieldId && x.isActive == IsActive.Active).map(x => {
@@ -311,6 +338,10 @@ export class DmpBlueprintValueEditorModel implements DmpBlueprintValuePersist {
}
});
+ this.isRequired = field.required;
+ if (this.isRequired) console.log(field);
+ this.category = field.category;
+
return this;
}
@@ -323,28 +354,39 @@ export class DmpBlueprintValueEditorModel implements DmpBlueprintValuePersist {
if (context == null) {
context = DmpBlueprintValueEditorModel.createValidationContext({
validationErrorModel: this.validationErrorModel,
- rootPath
+ rootPath,
+ isRequired: this.isRequired
});
}
- return this.formBuilder.group({
+ const formGroup = this.formBuilder.group({
fieldId: [{ value: this.fieldId, disabled: disabled }, context.getValidation('fieldId').validators],
- fieldValue: [{ value: this.fieldValue, disabled: disabled }, context.getValidation('fieldValue').validators],
- references: [{ value: this.references?.map(x => x.reference), disabled: disabled }, context.getValidation('references').validators],
});
+ switch (this.category) {
+ case DmpBlueprintFieldCategory.ReferenceType:
+ formGroup.addControl('references', new FormControl({ value: this.references?.map(x => x.reference), disabled: disabled }, context.getValidation('references').validators));
+ break;
+ case DmpBlueprintFieldCategory.System:
+ case DmpBlueprintFieldCategory.Extra:
+ formGroup.addControl('fieldValue', new FormControl({ value: this.fieldValue, disabled: disabled }, context.getValidation('fieldValue').validators));
+ break;
+ }
+
+ return formGroup;
}
static createValidationContext(params: {
rootPath?: string,
- validationErrorModel: ValidationErrorModel
+ validationErrorModel: ValidationErrorModel,
+ isRequired: boolean,
}): ValidationContext {
const { rootPath = '', validationErrorModel } = params;
const baseContext: ValidationContext = new ValidationContext();
const baseValidationArray: Validation[] = new Array();
baseValidationArray.push({ key: 'fieldId', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}fieldId`)] });
- baseValidationArray.push({ key: 'fieldValue', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}fieldValue`)] });
- baseValidationArray.push({ key: 'references', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}references`)] });
+ baseValidationArray.push({ key: 'fieldValue', validators: params.isRequired ? [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}fieldValue`)] : [BackendErrorValidator(validationErrorModel, `${rootPath}fieldValue`)] });
+ baseValidationArray.push({ key: 'references', validators: params.isRequired ? [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}references`)] : [BackendErrorValidator(validationErrorModel, `${rootPath}references`)] });
baseContext.validation = baseValidationArray;
return baseContext;
@@ -353,13 +395,15 @@ export class DmpBlueprintValueEditorModel implements DmpBlueprintValuePersist {
static reapplyValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
- rootPath: string
+ rootPath: string,
+ isRequired: boolean
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
const context = DmpBlueprintValueEditorModel.createValidationContext({
rootPath,
- validationErrorModel
+ validationErrorModel,
+ isRequired: params.isRequired
});
['fieldId', 'fieldValue', 'references'].forEach(keyField => {
@@ -375,7 +419,7 @@ export class DmpContactEditorModel implements DmpContactPersist {
firstName: string;
lastName: string;
email: string;
- contactType: DmpContactType= DmpContactType.Internal;
+ contactType: DmpContactType = DmpContactType.Internal;
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
@@ -384,11 +428,11 @@ export class DmpContactEditorModel implements DmpContactPersist {
) { }
fromModel(item: DmpContact): DmpContactEditorModel {
- if(item?.user?.id) this.userId = item.user.id;
+ if (item?.user?.id) this.userId = item.user.id;
this.firstName = item.firstName;
this.lastName = item.lastName;
- this.email = item.email;
- this.contactType = (item == null || this.userId != null) ? DmpContactType.Internal : DmpContactType.External;
+ this.email = item.email;
+ this.contactType = (item == null || this.userId != null) ? DmpContactType.Internal : DmpContactType.External;
return this;
}
@@ -457,7 +501,7 @@ export class DmpUserEditorModel implements DmpUserPersist {
user: Guid;
role: DmpUserRole;
email: string;
- userType: DmpUserType= DmpUserType.Internal;
+ userType: DmpUserType = DmpUserType.Internal;
sectionId: Guid;
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
@@ -467,10 +511,10 @@ export class DmpUserEditorModel implements DmpUserPersist {
) { }
fromModel(item: DmpUser): DmpUserEditorModel {
- if(item?.user?.id) this.user = item.user.id;
+ if (item?.user?.id) this.user = item.user.id;
this.role = item.role;
// TODO this.email = item.email;
- this.userType = (item == null || this.user != null) ? DmpUserType.Internal : DmpUserType.External;
+ this.userType = (item == null || this.user != null) ? DmpUserType.Internal : DmpUserType.External;
this.sectionId = item.sectionId;
return this;
@@ -623,7 +667,7 @@ export class DmpDescriptionTemplateEditorModel implements DmpDescriptionTemplate
if (context == null) {
context = DmpDescriptionTemplateEditorModel.createValidationContext({
validationErrorModel: this.validationErrorModel,
- rootPath
+ rootPath: rootPath,
});
}
@@ -635,7 +679,7 @@ export class DmpDescriptionTemplateEditorModel implements DmpDescriptionTemplate
static createValidationContext(params: {
rootPath?: string,
- validationErrorModel: ValidationErrorModel
+ validationErrorModel: ValidationErrorModel,
}): ValidationContext {
const { rootPath = '', validationErrorModel } = params;
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 7a0957885..80b7e8fe4 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
@@ -1,15 +1,16 @@
+import { DragDropModule } from '@angular/cdk/drag-drop';
import { NgModule } from '@angular/core';
import { FormattingModule } from '@app/core/formatting.module';
+import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { RichTextEditorModule } from '@app/library/rich-text-editor/rich-text-editor.module';
+import { ReferenceFieldModule } from '@app/ui/reference/reference-field/reference-field.module';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
+import { DmpUserFieldModule } from '../dmp-user-field/dmp-user-field.module';
import { DmpEditorComponent } from './dmp-editor.component';
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 { DmpUserFieldModule } from '../dmp-user-field/dmp-user-field.module';
+import { DmpFormProgressIndicationModule } from './form-progress-indication/dmp-form-progress-indication.module';
@NgModule({
imports: [
@@ -22,7 +23,8 @@ import { DmpUserFieldModule } from '../dmp-user-field/dmp-user-field.module';
AutoCompleteModule,
ReferenceFieldModule,
DragDropModule,
- DmpUserFieldModule
+ DmpUserFieldModule,
+ DmpFormProgressIndicationModule
],
declarations: [
DmpEditorComponent,
diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.component.html b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.component.html
new file mode 100644
index 000000000..68f919097
--- /dev/null
+++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.component.html
@@ -0,0 +1,5 @@
+
+
{{progressSoFar}} {{'GENERAL.PREPOSITIONS.OF' | translate}} {{total}}
+
+
{{value}}%
+
diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.component.scss b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.component.scss
new file mode 100644
index 000000000..a15510639
--- /dev/null
+++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.component.scss
@@ -0,0 +1,16 @@
+.percentage {
+ color: #212121;
+ opacity: 0.7;
+ font-weight: 400;
+ font-size: 0.875rem;
+}
+
+.progress-bar {
+ border-radius: 20px;
+ height: 11px;
+
+}
+
+::ng-deep .mat-progress-bar .mat-progress-bar-fill::after {
+ border-radius: 20px !important;
+}
diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.component.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.component.ts
new file mode 100644
index 000000000..f38f5c58d
--- /dev/null
+++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.component.ts
@@ -0,0 +1,104 @@
+import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
+import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
+import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
+import { BaseComponent } from '@common/base/base.component';
+import { takeUntil } from 'rxjs/operators';
+
+@Component({
+ selector: 'app-dmp-form-progress-indication',
+ templateUrl: './dmp-form-progress-indication.component.html',
+ styleUrls: ['./dmp-form-progress-indication.component.scss']
+})
+export class DmpFormProgressIndicationComponent extends BaseComponent implements OnInit, OnChanges {
+ @Input() formGroup: UntypedFormGroup;
+
+ @Input() public progressValueAccuracy = 2;
+ progressSoFar: number;
+ total: number;
+ percent: number;
+
+ constructor(private visibilityRulesService: VisibilityRulesService) { super(); }
+
+ public value = 0;
+ ngOnInit() {
+ this.init();
+ }
+
+ ngOnChanges(changes: SimpleChanges) {
+ if (changes.formGroup) {
+ this.init();
+ }
+ }
+
+ init() {
+ setTimeout(() => { this.calculateValueForProgressbar(); });
+ this.formGroup
+ .valueChanges
+ .pipe(takeUntil(this._destroyed))
+ .subscribe(control => {
+ setTimeout(() => { this.calculateValueForProgressbar(); });
+ });
+ }
+
+ calculateValueForProgressbar() {
+ this.progressSoFar = this.countFormControlsValidForProgress(this.formGroup);
+ this.total = this.countFormControlsRequiredFieldsForTotal(this.formGroup);
+ this.percent = (this.progressSoFar / this.total) * 100;
+ this.value = Number.parseFloat(this.percent.toPrecision(this.progressValueAccuracy));
+ }
+
+ countFormControlsValidForProgress(formControl: AbstractControl): number {
+ let valueCurrent = 0;
+ if (formControl instanceof UntypedFormControl) {
+ if (this.controlRequired(formControl) && this.controlEnabled(formControl) && formControl.valid) {
+ valueCurrent++;
+ }
+ } else if (formControl instanceof UntypedFormGroup) {
+ Object.keys(formControl.controls).forEach(item => {
+ const control = formControl.get(item);
+ valueCurrent = valueCurrent + this.countFormControlsValidForProgress(control);
+ });
+ } else if (formControl instanceof UntypedFormArray) {
+ formControl.controls.forEach(item => {
+ valueCurrent = valueCurrent + this.countFormControlsValidForProgress(item);
+ });
+ }
+ return valueCurrent;
+ }
+
+ countFormControlsRequiredFieldsForTotal(formControl: AbstractControl, checkVisibility = false): number {
+ let valueCurrent = 0;
+ if (formControl instanceof UntypedFormControl) {
+ if (this.controlRequired(formControl) && this.controlEnabled(formControl)) {
+ valueCurrent++;
+ }
+ } else if (formControl instanceof UntypedFormGroup) {
+ if (!checkVisibility || (!formControl.get('id')?.value || (this.visibilityRulesService.isVisibleMap[formControl.get('id').value] ?? true))) {
+ Object.keys(formControl.controls).forEach(item => {
+ const control = formControl.get(item);
+ valueCurrent = valueCurrent + this.countFormControlsRequiredFieldsForTotal(control, checkVisibility);
+ });
+ }
+ } else if (formControl instanceof UntypedFormArray) {
+ formControl.controls.forEach(item => {
+ valueCurrent = valueCurrent + this.countFormControlsRequiredFieldsForTotal(item, checkVisibility);
+ });
+ }
+ return valueCurrent;
+ }
+
+ controlRequired(formControl: AbstractControl) {
+ if (formControl.validator) {
+ const validator = formControl.validator({} as AbstractControl);
+ if (validator && validator.required) {
+ return true;
+ }
+ } else { return false }
+ }
+
+ controlEnabled(formControl: AbstractControl) {
+ if (formControl.enabled) {
+ return true;
+ } else { return false }
+ }
+}
diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.module.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.module.ts
new file mode 100644
index 000000000..3c004582a
--- /dev/null
+++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/form-progress-indication/dmp-form-progress-indication.module.ts
@@ -0,0 +1,18 @@
+import { NgModule } from '@angular/core';
+import { CommonFormsModule } from '@common/forms/common-forms.module';
+import { CommonUiModule } from '@common/ui/common-ui.module';
+import { DmpFormProgressIndicationComponent } from './dmp-form-progress-indication.component';
+
+@NgModule({
+ imports: [
+ CommonUiModule,
+ CommonFormsModule
+ ],
+ declarations: [
+ DmpFormProgressIndicationComponent
+ ],
+ exports: [
+ DmpFormProgressIndicationComponent
+ ]
+})
+export class DmpFormProgressIndicationModule { }
diff --git a/dmp-frontend/src/app/ui/dmp/dmp-user-field/dmp-user-field.component.html b/dmp-frontend/src/app/ui/dmp/dmp-user-field/dmp-user-field.component.html
index 0fe457109..e82c4b574 100644
--- a/dmp-frontend/src/app/ui/dmp/dmp-user-field/dmp-user-field.component.html
+++ b/dmp-frontend/src/app/ui/dmp/dmp-user-field/dmp-user-field.component.html
@@ -43,7 +43,7 @@
- {{'DMP-EDITOR.FIELDS.USER' | translate}}*
+ {{'DMP-EDITOR.FIELDS.USER' | translate}}
{{user.get('user').getError('backendError').message}}
{{'GENERAL.VALIDATION.REQUIRED' | translate}}
@@ -51,7 +51,7 @@
- {{'DMP-EDITOR.FIELDS.EMAIL' | translate}}*
+ {{'DMP-EDITOR.FIELDS.EMAIL' | translate}}
{{user.get('email').getError('backendError').message}}
{{'GENERAL.VALIDATION.REQUIRED' | translate}}
diff --git a/dmp-frontend/src/app/ui/dmp/dmp-user-field/dmp-user-field.component.ts b/dmp-frontend/src/app/ui/dmp/dmp-user-field/dmp-user-field.component.ts
index 298f18318..c8e49fa56 100644
--- a/dmp-frontend/src/app/ui/dmp/dmp-user-field/dmp-user-field.component.ts
+++ b/dmp-frontend/src/app/ui/dmp/dmp-user-field/dmp-user-field.component.ts
@@ -57,10 +57,10 @@ export class DmpUserFieldComponent extends BaseComponent implements OnInit {
removeUser(userIndex: number): void {
(this.form.get('users') as FormArray).removeAt(userIndex);
- DmpEditorModel.reApplyPropertiesValidators(
+ DmpEditorModel.reApplyUsersValidators(
{
formGroup: this.form,
- validationErrorModel: this.validationErrorModel
+ validationErrorModel: this.validationErrorModel,
}
);
this.form.get('users').markAsDirty();
@@ -78,7 +78,7 @@ export class DmpUserFieldComponent extends BaseComponent implements OnInit {
moveItemInArray(usersFormArray.controls, event.previousIndex, event.currentIndex);
usersFormArray.updateValueAndValidity();
- DmpEditorModel.reApplyPropertiesValidators(
+ DmpEditorModel.reApplyUsersValidators(
{
formGroup: this.form,
validationErrorModel: this.validationErrorModel