add multiplicity validation ui

This commit is contained in:
amentis 2024-04-03 17:50:47 +03:00
parent 6f7ed58523
commit 26cbe562ad
14 changed files with 147 additions and 45 deletions

View File

@ -219,8 +219,7 @@ public class DescriptionPersist {
.must(() -> !this.isNull(item.getProperties())) .must(() -> !this.isNull(item.getProperties()))
.failOn(DescriptionPersist._properties).failWith(messageSource.getMessage("Validation_Required", new Object[]{DescriptionPersist._properties}, LocaleContextHolder.getLocale())), .failOn(DescriptionPersist._properties).failWith(messageSource.getMessage("Validation_Required", new Object[]{DescriptionPersist._properties}, LocaleContextHolder.getLocale())),
this.spec() this.spec()
.iff(() -> item.getStatus() == DescriptionStatus.Finalized) .must(() -> this.isDescriptionTemplateMaxMultiplicityValid(finalDmpBlueprintEntity, item.getDmpId(), item.getDmpDescriptionTemplateId(), this.isValidGuid(item.getId())))
.must(() -> this.isDescriptionTemplateMultiplicityValid(finalDmpBlueprintEntity, item.getDmpId(), item.getDescriptionTemplateId()))
.failOn(DescriptionPersist._descriptionTemplateId).failWith(messageSource.getMessage("Validation.InvalidDescriptionTemplateMultiplicity", new Object[]{DescriptionPersist._descriptionTemplateId}, LocaleContextHolder.getLocale())) .failOn(DescriptionPersist._descriptionTemplateId).failWith(messageSource.getMessage("Validation.InvalidDescriptionTemplateMultiplicity", new Object[]{DescriptionPersist._descriptionTemplateId}, LocaleContextHolder.getLocale()))
// this.refSpec() // this.refSpec()
// .iff(() -> !this.isNull(item.getProperties())) // .iff(() -> !this.isNull(item.getProperties()))
@ -235,26 +234,28 @@ public class DescriptionPersist {
); );
} }
private boolean isDescriptionTemplateMultiplicityValid(DmpBlueprintEntity dmpBlueprintEntity, UUID dmpId, UUID descriptionTemplateId){ private boolean isDescriptionTemplateMaxMultiplicityValid(DmpBlueprintEntity dmpBlueprintEntity, UUID dmpId, UUID dmpDescriptionTemplateId, Boolean isUpdate){
eu.eudat.commons.types.dmpblueprint.DefinitionEntity definition = this.xmlHandlingService.fromXmlSafe(eu.eudat.commons.types.dmpblueprint.DefinitionEntity.class, dmpBlueprintEntity.getDefinition()); eu.eudat.commons.types.dmpblueprint.DefinitionEntity definition = this.xmlHandlingService.fromXmlSafe(eu.eudat.commons.types.dmpblueprint.DefinitionEntity.class, dmpBlueprintEntity.getDefinition());
if (definition == null || this.isListNullOrEmpty(definition.getSections())) return true; if (definition == null || this.isListNullOrEmpty(definition.getSections())) return true;
DmpDescriptionTemplateEntity dmpDescriptionTemplateEntity = this.queryFactory.query(DmpDescriptionTemplateQuery.class).ids(dmpDescriptionTemplateId).isActive(IsActive.Active).dmpIds(dmpId).first();
if (dmpDescriptionTemplateEntity == null) return true;
List<DescriptionEntity> descriptionEntities = this.queryFactory.query(DescriptionQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(dmpId).dmpDescriptionTemplateIds(dmpDescriptionTemplateId).isActive(IsActive.Active).collect();
for (SectionEntity section: definition.getSections()) { for (SectionEntity section: definition.getSections()) {
if (section.getHasTemplates() && !this.isListNullOrEmpty(section.getDescriptionTemplates())){ if (dmpDescriptionTemplateEntity.getSectionId().equals(section.getId()) && section.getHasTemplates() && !this.isListNullOrEmpty(section.getDescriptionTemplates())){
int descriptionsCount = 0; int descriptionsCount;
if (isUpdate) descriptionsCount = -1;
else descriptionsCount = 0;
for (eu.eudat.commons.types.dmpblueprint.DescriptionTemplateEntity sectionDescriptionTemplate: section.getDescriptionTemplates()) { for (eu.eudat.commons.types.dmpblueprint.DescriptionTemplateEntity sectionDescriptionTemplate: section.getDescriptionTemplates()) {
if (sectionDescriptionTemplate.getMaxMultiplicity() == null && sectionDescriptionTemplate.getMinMultiplicity() == null ) continue; if (sectionDescriptionTemplate.getDescriptionTemplateGroupId().equals(dmpDescriptionTemplateEntity.getDescriptionTemplateGroupId())){
DmpDescriptionTemplateQuery dmpDescriptionTemplateQuery = this.queryFactory.query(DmpDescriptionTemplateQuery.class).isActive(IsActive.Active).dmpIds(dmpId).sectionIds(section.getId());
List<DescriptionEntity> descriptionEntities = this.queryFactory.query(DescriptionQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(dmpId).dmpDescriptionTemplateSubQuery(dmpDescriptionTemplateQuery).isActive(IsActive.Active).collect();
if (this.isListNullOrEmpty(descriptionEntities)) continue;
for (DescriptionEntity description: descriptionEntities){ for (DescriptionEntity description: descriptionEntities){
if (description.getDescriptionTemplateId().equals(descriptionTemplateId)) descriptionsCount++; if (description.getDmpDescriptionTemplateId().equals(dmpDescriptionTemplateEntity.getId())) descriptionsCount++;
} }
if (sectionDescriptionTemplate.getMinMultiplicity() != null && sectionDescriptionTemplate.getMinMultiplicity() >= descriptionsCount) return false;
if (sectionDescriptionTemplate.getMaxMultiplicity() != null && sectionDescriptionTemplate.getMaxMultiplicity() <= descriptionsCount) return false; if (sectionDescriptionTemplate.getMaxMultiplicity() != null && sectionDescriptionTemplate.getMaxMultiplicity() <= descriptionsCount) return false;
}
} }

View File

@ -54,6 +54,8 @@ public class DescriptionQuery extends QueryBase<DescriptionEntity> {
private final UserScope userScope; private final UserScope userScope;
private final AuthorizationService authService; private final AuthorizationService authService;
private final QueryUtilsService queryUtilsService; private final QueryUtilsService queryUtilsService;
private Collection<UUID> dmpDescriptionTemplateIds;
public DescriptionQuery(UserScope userScope, AuthorizationService authService, QueryUtilsService queryUtilsService) { public DescriptionQuery(UserScope userScope, AuthorizationService authService, QueryUtilsService queryUtilsService) {
this.userScope = userScope; this.userScope = userScope;
this.authService = authService; this.authService = authService;
@ -110,7 +112,20 @@ public class DescriptionQuery extends QueryBase<DescriptionEntity> {
return this; return this;
} }
public DescriptionQuery dmpDescriptionTemplateIds(UUID value) {
this.dmpDescriptionTemplateIds = List.of(value);
return this;
}
public DescriptionQuery dmpDescriptionTemplateIds(UUID... value) {
this.dmpDescriptionTemplateIds = Arrays.asList(value);
return this;
}
public DescriptionQuery dmpDescriptionTemplateIds(Collection<UUID> values) {
this.dmpDescriptionTemplateIds = values;
return this;
}
public DescriptionQuery finalizedAfter(Instant value) { public DescriptionQuery finalizedAfter(Instant value) {
this.finalizedAfter = value; this.finalizedAfter = value;
@ -287,6 +302,12 @@ public class DescriptionQuery extends QueryBase<DescriptionEntity> {
QueryContext<DmpEntity, UUID> subQuery = this.applySubQuery(this.dmpQuery, queryContext, UUID.class, dmpEntityRoot -> dmpEntityRoot.get(DmpEntity._id)); QueryContext<DmpEntity, UUID> subQuery = this.applySubQuery(this.dmpQuery, queryContext, UUID.class, dmpEntityRoot -> dmpEntityRoot.get(DmpEntity._id));
predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(DescriptionEntity._dmpId)).value(subQuery.Query)); predicates.add(queryContext.CriteriaBuilder.in(queryContext.Root.get(DescriptionEntity._dmpId)).value(subQuery.Query));
} }
if (this.dmpDescriptionTemplateIds != null) {
CriteriaBuilder.In<UUID> inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(DescriptionEntity._dmpDescriptionTemplateId));
for (UUID item : this.dmpDescriptionTemplateIds)
inClause.value(item);
predicates.add(inClause);
}
if (!predicates.isEmpty()) { if (!predicates.isEmpty()) {
Predicate[] predicatesArray = predicates.toArray(new Predicate[0]); Predicate[] predicatesArray = predicates.toArray(new Predicate[0]);
return queryContext.CriteriaBuilder.and(predicatesArray); return queryContext.CriteriaBuilder.and(predicatesArray);

View File

@ -358,7 +358,9 @@ public class PrefillingSourceServiceImpl implements PrefillingSourceService {
eu.eudat.commons.types.descriptiontemplate.DefinitionEntity descriptionTemplateDefinition = this.xmlHandlingService.fromXml(eu.eudat.commons.types.descriptiontemplate.DefinitionEntity.class, descriptionTemplateEntity.getDefinition()); eu.eudat.commons.types.descriptiontemplate.DefinitionEntity descriptionTemplateDefinition = this.xmlHandlingService.fromXml(eu.eudat.commons.types.descriptiontemplate.DefinitionEntity.class, descriptionTemplateEntity.getDefinition());
Description description = new Description(); Description description = new Description();
description.setDescriptionTemplate(this.builderFactory.builder(DescriptionTemplateBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(fieldSet, descriptionTemplateEntity)); FieldSet descriptionTemplateFields = fieldSet.extractPrefixed(this.conventionService.asPrefix(Description._descriptionTemplate));
description.setDescriptionTemplate(this.builderFactory.builder(DescriptionTemplateBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(descriptionTemplateFields, descriptionTemplateEntity));
return mapPrefilledEntityToDescription(description, descriptionTemplateDefinition, prefillingSourceDefinition, prefillingSourceEntity.getLabel(), externalData.getResults().getFirst());//TODO return mapPrefilledEntityToDescription(description, descriptionTemplateDefinition, prefillingSourceDefinition, prefillingSourceEntity.getLabel(), externalData.getResults().getFirst());//TODO
} }

View File

@ -130,7 +130,8 @@ export class DmpBlueprintService {
lookup.project = { lookup.project = {
fields: [ fields: [
nameof<DmpBlueprint>(x => x.id), nameof<DmpBlueprint>(x => x.id),
nameof<DmpBlueprint>(x => x.label) nameof<DmpBlueprint>(x => x.label),
nameof<DmpBlueprint>(x => x.version)
] ]
}; };
lookup.order = { items: [nameof<DmpBlueprint>(x => x.label)] }; lookup.order = { items: [nameof<DmpBlueprint>(x => x.label)] };

View File

@ -550,6 +550,7 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
finalize() { finalize() {
if (this.checkValidity()) { if (this.checkValidity()) {
this.formGroup.get('status').setValue(DmpBlueprintStatus.Finalized); this.formGroup.get('status').setValue(DmpBlueprintStatus.Finalized);
if(this.isNewVersion) this.isNewVersion = false;
this.formSubmit(); this.formSubmit();
} }
} }

View File

@ -43,6 +43,9 @@ import { FormValidationErrorsDialogComponent } from '@common/forms/form-validati
import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { LockTargetType } from '@app/core/common/enum/lock-target-type'; import { LockTargetType } from '@app/core/common/enum/lock-target-type';
import { FileTransformerService } from '@app/core/services/file-transformer/file-transformer.service'; import { FileTransformerService } from '@app/core/services/file-transformer/file-transformer.service';
import { DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { DmpDescriptionTemplate } from '@app/core/model/dmp/dmp';
@Component({ @Component({
selector: 'app-description-editor-component', selector: 'app-description-editor-component',
@ -55,24 +58,6 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
isNew = true; isNew = true;
isDeleted = false; isDeleted = false;
item: Description; item: Description;
// showInactiveDetails = false;
// selectedSystemFields: Array<DescriptionSystemFieldType> = [];
// DescriptionSectionFieldCategory = DescriptionSectionFieldCategory;
// DescriptionSystemFieldType = DescriptionSystemFieldType;
// public DescriptionSystemFieldTypeEnum = this.enumUtils.getEnumValues<DescriptionSystemFieldType>(DescriptionSystemFieldType);
// DescriptionExtraFieldDataType = DescriptionExtraFieldDataType;
// public DescriptionExtraFieldDataTypeEnum = this.enumUtils.getEnumValues<DescriptionExtraFieldDataType>(DescriptionExtraFieldDataType);
// blueprintsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
// filterFn: this.filterDescriptionTempaltes.bind(this),
// initialItems: (excludedItems: any[]) => this.filterDescriptionTempaltes('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
// displayFn: (item: DatasetProfileModel) => item.label,
// titleFn: (item: DatasetProfileModel) => item.label,
// subtitleFn: (item: DatasetProfileModel) => item.description,
// popupItemActionIcon: 'visibility'
// };
// hasChanges = false;
fieldsetIdWithFocus: string; fieldsetIdWithFocus: string;
viewOnly = false; viewOnly = false;
@ -211,10 +196,14 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
}, },
panelClass: 'custom-modalbox' panelClass: 'custom-modalbox'
}); });
dialogRef.afterClosed().subscribe(result => { dialogRef.afterClosed().subscribe((result: Description) => {
if (result) { if (result) {
result.dmp = this.item.dmp; result.dmp = this.item.dmp;
result.dmpDescriptionTemplate = this.item.dmpDescriptionTemplate; result.dmpDescriptionTemplate = this.item.dmpDescriptionTemplate;
const sectionId = this.item.dmpDescriptionTemplate.sectionId;
result.dmpDescriptionTemplate = this.item.dmp.dmpDescriptionTemplates.find(x => x.sectionId == sectionId && x.descriptionTemplateGroupId == result.descriptionTemplate.groupId);
this.prepareForm(result); this.prepareForm(result);
// this.descriptionModel = this.descriptionModel.fromModel(result); // this.descriptionModel = this.descriptionModel.fromModel(result);
// this.descriptionModel.dmp = data; // this.descriptionModel.dmp = data;
@ -551,6 +540,13 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
try { try {
this.editorModel = data ? new DescriptionEditorModel().fromModel(data, data.descriptionTemplate) : new DescriptionEditorModel(); this.editorModel = data ? new DescriptionEditorModel().fromModel(data, data.descriptionTemplate) : new DescriptionEditorModel();
this.item = data; this.item = data;
if (data && data.dmpDescriptionTemplate?.sectionId && data.dmp?.blueprint?.definition?.sections?.length > 0 && data.dmp?.descriptions?.length > 0){
const section = data.dmp?.blueprint?.definition?.sections.find(x => x.id == data.dmpDescriptionTemplate?.sectionId);
if(section.hasTemplates) {
const notAvailableDescriptionTemplates = this.calculateMultiplicityRejectedDmpDescriptionTemplates(section, data.dmp.descriptions.filter(x => x.isActive == IsActive.Active));
this.item.dmp.dmpDescriptionTemplates = data.dmp.dmpDescriptionTemplates.filter(x => !notAvailableDescriptionTemplates.map(y => y.id).includes(x.id) )
}
}
this.isDeleted = data ? data.isActive === IsActive.Inactive : false; this.isDeleted = data ? data.isActive === IsActive.Inactive : false;
this.buildForm(); this.buildForm();
} catch (error) { } catch (error) {
@ -588,6 +584,26 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
} }
calculateMultiplicityRejectedDmpDescriptionTemplates(section: DmpBlueprintDefinitionSection, descriptions: Description[]) : DmpDescriptionTemplate[]{
if (section.descriptionTemplates?.length > 0){
descriptions = descriptions?.filter(x => x?.dmpDescriptionTemplate?.sectionId === section.id) || [];
let rejectedDmpDescriptionTemplates: DmpDescriptionTemplate[] = [];
section.descriptionTemplates.forEach(sectionDescriptionTemplate => {
if (sectionDescriptionTemplate.maxMultiplicity != null){
const commonDescriptions = descriptions.filter(x => x.dmpDescriptionTemplate.descriptionTemplateGroupId == sectionDescriptionTemplate.descriptionTemplateGroupId);
if (commonDescriptions && commonDescriptions.length >= sectionDescriptionTemplate.maxMultiplicity) {
rejectedDmpDescriptionTemplates = commonDescriptions.map(x => x.dmpDescriptionTemplate);
}
}
})
return rejectedDmpDescriptionTemplates;
} else{
return [];
}
}
refreshData(): void { refreshData(): void {
this.getItem(this.editorModel.id, (data: Description) => this.prepareForm(data)); this.getItem(this.editorModel.id, (data: Description) => this.prepareForm(data));
} }

View File

@ -156,7 +156,7 @@ export class DescriptionEditorResolver extends BaseEditorResolver {
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.descriptionTemplateGroupId)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.descriptionTemplateGroupId)].join('.'),
// (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.label)].join('.'), // (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.label)].join('.'),
// (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.minMultiplicity)].join('.'), // (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.minMultiplicity)].join('.'),
// (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.blueprint), nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.dmpDescriptionTemplates), nameof<DmpDescriptionTemplate>(x => x.id)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.dmpDescriptionTemplates), nameof<DmpDescriptionTemplate>(x => x.id)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.dmpDescriptionTemplates), nameof<DmpDescriptionTemplate>(x => x.sectionId)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.dmpDescriptionTemplates), nameof<DmpDescriptionTemplate>(x => x.sectionId)].join('.'),
@ -165,6 +165,13 @@ export class DescriptionEditorResolver extends BaseEditorResolver {
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.dmpDescriptionTemplates), nameof<DmpDescriptionTemplate>(x => x.currentDescriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.dmpDescriptionTemplates), nameof<DmpDescriptionTemplate>(x => x.currentDescriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.dmpDescriptionTemplates), nameof<DmpDescriptionTemplate>(x => x.currentDescriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.dmpDescriptionTemplates), nameof<DmpDescriptionTemplate>(x => x.currentDescriptionTemplate), nameof<DescriptionTemplate>(x => x.label)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.dmpDescriptionTemplates), nameof<DmpDescriptionTemplate>(x => x.currentDescriptionTemplate), nameof<DescriptionTemplate>(x => x.version)].join('.'), (prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.dmpDescriptionTemplates), nameof<DmpDescriptionTemplate>(x => x.currentDescriptionTemplate), nameof<DescriptionTemplate>(x => x.version)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.id)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.isActive)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.id)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.descriptionTemplateGroupId)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.sectionId)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.isActive)].join('.'),
] ]
} }

View File

@ -17,6 +17,10 @@ import { TranslateService } from "@ngx-translate/core";
import { UUID } from "crypto"; import { UUID } from "crypto";
import { Observable } from "rxjs"; import { Observable } from "rxjs";
import { map, takeUntil } from "rxjs/operators"; import { map, takeUntil } from "rxjs/operators";
import { DescriptionEditorResolver } from "../description-editor.resolver";
import { nameof } from "ts-simple-nameof";
import { Description } from "@app/core/model/description/description";
import { IsActive } from "@app/core/common/enum/is-active.enum";
@Component({ @Component({
selector: 'prefill-description-component', selector: 'prefill-description-component',
@ -47,7 +51,7 @@ export class PrefillDescriptionDialogComponent extends BaseComponent implements
this.dmp = data.dmp; this.dmp = data.dmp;
this.dmpSectionId = data.dmpSectionId; this.dmpSectionId = data.dmpSectionId;
this.availableDescriptionTemplates = this.dmp.dmpDescriptionTemplates.filter(x => x.sectionId == this.dmpSectionId).map(x => x.currentDescriptionTemplate); this.availableDescriptionTemplates = this.dmp.dmpDescriptionTemplates.filter(x => x.sectionId == this.dmpSectionId && x.isActive == IsActive.Active).map(x => x.currentDescriptionTemplate);
} }
ngOnInit() { ngOnInit() {
@ -212,7 +216,7 @@ export class PrefillDescriptionDialogComponent extends BaseComponent implements
// } // }
const formData = this.formService.getValue(this.prefillForm.value) as DescriptionProfilingRequest; const formData = this.formService.getValue(this.prefillForm.value) as DescriptionProfilingRequest;
this.prefillingSourceService.generate(formData, DescriptionTemplateEditorResolver.lookupFields()) this.prefillingSourceService.generate(formData, DescriptionEditorResolver.descriptionTemplateLookupFields(nameof<Description>(x => x.descriptionTemplate)))
.pipe(takeUntil(this._destroyed)).subscribe(description => { .pipe(takeUntil(this._destroyed)).subscribe(description => {
if (description) { if (description) {
this.closeDialog(description); this.closeDialog(description);

View File

@ -96,11 +96,16 @@
</li> </li>
</ol> </ol>
<ul *ngIf="item.id && section.hasTemplates && canEditSection(section.id) && !formGroup.disabled" class="add-description-option"> <ul *ngIf="item.id && section.hasTemplates && canEditSection(section.id) && !formGroup.disabled" class="add-description-option">
<li> <li *ngIf="canAddDescription(section)">
<a class="add-description-action" [routerLink]="['/descriptions/edit/' + item.id + '/' + section.id]"> <a class="add-description-action" [routerLink]="['/descriptions/edit/' + item.id + '/' + section.id]">
<mat-icon>add</mat-icon>{{'DMP-EDITOR.ACTIONS.ADD-DESCRIPTION-IN-SECTION' | translate}} <mat-icon>add</mat-icon>{{'DMP-EDITOR.ACTIONS.ADD-DESCRIPTION-IN-SECTION' | translate}}
</a> </a>
</li> </li>
<li *ngIf="!canAddDescription(section)">
<a [ngClass]="{'drag-handle-disabled': true}" class="add-description-action">
<mat-icon>add</mat-icon>{{'DMP-EDITOR.ACTIONS.ADD-DESCRIPTION-IN-SECTION' | translate}}
</a>
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -18,7 +18,7 @@ import { IsActive } from '@app/core/common/enum/is-active.enum';
import { LockTargetType } from '@app/core/common/enum/lock-target-type'; import { LockTargetType } from '@app/core/common/enum/lock-target-type';
import { AppPermission } from '@app/core/common/enum/permission.enum'; import { AppPermission } from '@app/core/common/enum/permission.enum';
import { DescriptionSectionPermissionResolver } from '@app/core/model/description/description'; import { DescriptionSectionPermissionResolver } from '@app/core/model/description/description';
import { DmpBlueprint } from '@app/core/model/dmp-blueprint/dmp-blueprint'; import { DmpBlueprint, DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { Dmp, DmpPersist } from '@app/core/model/dmp/dmp'; import { Dmp, DmpPersist } from '@app/core/model/dmp/dmp';
import { LanguageInfo } from '@app/core/model/language-info'; import { LanguageInfo } from '@app/core/model/language-info';
import { AuthService } from '@app/core/services/auth/auth.service'; import { AuthService } from '@app/core/services/auth/auth.service';
@ -88,6 +88,7 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
filterFn: (searchQuery: string, data?: any) => this.dmpBlueprintService.query(this.dmpBlueprintService.buildAutocompleteLookup(searchQuery, 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)),
getSelectedItem: (selectedItem: any) => this.dmpBlueprintService.query(this.dmpBlueprintService.buildAutocompleteLookup(null, null, [selectedItem])).pipe(map(x => x.items[0])), getSelectedItem: (selectedItem: any) => this.dmpBlueprintService.query(this.dmpBlueprintService.buildAutocompleteLookup(null, null, [selectedItem])).pipe(map(x => x.items[0])),
displayFn: (item: DmpBlueprint) => item.label, displayFn: (item: DmpBlueprint) => item.label,
subtitleFn: (item: DmpBlueprint) => this.language.instant('DMP-EDITOR.FIELDS.DMP-BLUEPRINT-VERSION') + ' '+ item.version,
titleFn: (item: DmpBlueprint) => item.label, titleFn: (item: DmpBlueprint) => item.label,
valueAssign: (item: DmpBlueprint) => item.id, valueAssign: (item: DmpBlueprint) => item.id,
}; };
@ -446,6 +447,32 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
}); });
} }
canAddDescription(section: DmpBlueprintDefinitionSection ): boolean{
if(section.hasTemplates){
if (section.descriptionTemplates?.length > 0){
const descriptions = this.descriptionsInSection(section.id)
let multiplicityValidResults :boolean[] = [];
section.descriptionTemplates.forEach(sectionDescriptionTemplate => {
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{
multiplicityValidResults.push(true);
}
})
if(multiplicityValidResults.includes(true)) return true
else return false;
}else{
return true;
}
}else{
return false;
}
}
// //
// //
// Description Template // Description Template

View File

@ -61,6 +61,7 @@ export class DmpEditorResolver extends BaseEditorResolver {
[nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.isActive)].join('.'), [nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.isActive)].join('.'),
[nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.id)].join('.'), [nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.id)].join('.'),
[nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.sectionId)].join('.'), [nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.sectionId)].join('.'),
[nameof<Dmp>(x => x.descriptions), nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.descriptionTemplateGroupId)].join('.'),
[nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'), [nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.id)].join('.'),
[nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'), [nameof<Dmp>(x => x.dmpUsers), nameof<DmpUser>(x => x.user.id)].join('.'),
@ -104,6 +105,8 @@ export class DmpEditorResolver extends BaseEditorResolver {
(prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.ordinal)].join('.'), (prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.ordinal)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.hasTemplates)].join('.'), (prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.hasTemplates)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.descriptionTemplateGroupId)].join('.'), (prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.descriptionTemplateGroupId)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.minMultiplicity)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.id)].join('.'), (prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.id)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.category)].join('.'), (prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.category)].join('.'),
(prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.label)].join('.'), (prefix ? prefix + '.' : '') + [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.label)].join('.'),

View File

@ -34,7 +34,7 @@
</div> </div>
<div class="col-12 title-form"> <div class="col-12 title-form">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<app-single-auto-complete [required]="false" [formControl]="formGroup.get('blueprintId')" placeholder="{{'DMP-NEW-VERSION-DIALOG.FIELDS.BLUEPRINT-PLACEHOLDER' | translate}}" [configuration]="dmpBlueprintService.singleAutocompleteConfiguration"> <app-single-auto-complete [required]="false" [formControl]="formGroup.get('blueprintId')" placeholder="{{'DMP-NEW-VERSION-DIALOG.FIELDS.BLUEPRINT-PLACEHOLDER' | translate}}" [configuration]="singleAutocompleteBlueprintConfiguration">
</app-single-auto-complete> </app-single-auto-complete>
</mat-form-field> </mat-form-field>
</div> </div>

View File

@ -6,10 +6,13 @@ import { DmpService } from '@app/core/services/dmp/dmp.service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { BaseComponent } from '@common/base/base.component'; import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { takeUntil } from 'rxjs/operators'; import { map, takeUntil } from 'rxjs/operators';
import { DmpNewVersionDialogEditorModel } from './dmp-new-version-dialog.editor.model'; import { DmpNewVersionDialogEditorModel } from './dmp-new-version-dialog.editor.model';
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { DmpEditorResolver } from '../dmp-editor-blueprint/dmp-editor.resolver'; import { DmpEditorResolver } from '../dmp-editor-blueprint/dmp-editor.resolver';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { DmpBlueprint } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { DmpBlueprintStatus } from '@app/core/common/enum/dmp-blueprint-status';
@Component({ @Component({
selector: 'app-dmp-new-version-dialog', selector: 'app-dmp-new-version-dialog',
@ -22,6 +25,16 @@ export class NewVersionDmpDialogComponent extends BaseComponent {
editorModel: DmpNewVersionDialogEditorModel; editorModel: DmpNewVersionDialogEditorModel;
formGroup: UntypedFormGroup; formGroup: UntypedFormGroup;
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)),
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,
titleFn: (item: DmpBlueprint) => item.label,
valueAssign: (item: DmpBlueprint) => item.id,
};
constructor( constructor(
public dialogRef: MatDialogRef<NewVersionDmpDialogComponent>, public dialogRef: MatDialogRef<NewVersionDmpDialogComponent>,
private dmpService: DmpService, private dmpService: DmpService,

View File

@ -1304,7 +1304,8 @@
"EMAIL": "Email", "EMAIL": "Email",
"USER": "User", "USER": "User",
"USER-ROLE": "Role", "USER-ROLE": "Role",
"SECTION": "Specific DMP Section" "SECTION": "Specific DMP Section",
"DMP-BLUEPRINT-VERSION": "Version"
}, },
"ACTIONS": { "ACTIONS": {
"DISCARD": "Discard", "DISCARD": "Discard",