Merge branch 'dmp-refactoring' of code-repo.d4science.org:MaDgiK-CITE/argos into dmp-refactoring

This commit is contained in:
Efstratios Giannopoulos 2024-04-03 18:35:52 +03:00
commit ea6ea25116
18 changed files with 260 additions and 85 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())){
for (DescriptionEntity description: descriptionEntities){
DmpDescriptionTemplateQuery dmpDescriptionTemplateQuery = this.queryFactory.query(DmpDescriptionTemplateQuery.class).isActive(IsActive.Active).dmpIds(dmpId).sectionIds(section.getId()); if (description.getDmpDescriptionTemplateId().equals(dmpDescriptionTemplateEntity.getId())) descriptionsCount++;
List<DescriptionEntity> descriptionEntities = this.queryFactory.query(DescriptionQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(dmpId).dmpDescriptionTemplateSubQuery(dmpDescriptionTemplateQuery).isActive(IsActive.Active).collect(); }
if (this.isListNullOrEmpty(descriptionEntities)) continue; if (sectionDescriptionTemplate.getMaxMultiplicity() != null && sectionDescriptionTemplate.getMaxMultiplicity() <= descriptionsCount) return false;
for (DescriptionEntity description: descriptionEntities){
if (description.getDescriptionTemplateId().equals(descriptionTemplateId)) descriptionsCount++;
} }
if (sectionDescriptionTemplate.getMinMultiplicity() != null && sectionDescriptionTemplate.getMinMultiplicity() >= 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

@ -283,6 +283,7 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) { if (result) {
this.formGroup.get('status').setValue(DescriptionTemplateStatus.Finalized); this.formGroup.get('status').setValue(DescriptionTemplateStatus.Finalized);
if(this.isNewVersion) this.isNewVersion = false;
this.persistEntity(); this.persistEntity();
}}); }});
} }

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);
@ -226,4 +230,4 @@ export class PrefillDescriptionDialogComponent extends BaseComponent implements
closeDialog(result = null): void { closeDialog(result = null): void {
this.dialogRef.close(result); this.dialogRef.close(result);
} }
} }

View File

@ -96,11 +96,17 @@
</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>
<small class="text-danger">{{'DMP-EDITOR.DESCRIPTION-TEMPLATES-MAX-MULTIPLICITY'| translate}}</small>
</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

@ -1,43 +1,45 @@
<form *ngIf="formGroup" [formGroup]="formGroup"> <div class="container-fluid">
<div class="row d-flex flex-row"> <form *ngIf="formGroup" [formGroup]="formGroup">
<div mat-dialog-title class="col-auto"> <div class="row d-flex flex-row">
{{'REFERENCE-FIELD.REFERENCE-DIALOG-EDITOR.TITLE' | translate}} {{label}} <div mat-dialog-title class="col-auto">
</div> {{'REFERENCE-FIELD.REFERENCE-DIALOG-EDITOR.TITLE' | translate}} {{label}}
<div class="col-auto ml-auto close-btn" (click)="close()"> </div>
<mat-icon>close</mat-icon> <div class="col-auto ml-auto close-btn" (click)="close()">
</div> <mat-icon>close</mat-icon>
</div>
<div mat-dialog-content class="row">
<div *ngFor="let field of systemFields;">
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{field}}</mat-label>
<input matInput type="text" [name]="field" [formControl]="formGroup.get(field)">
<mat-error *ngIf="formGroup.get(field).hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<ng-container *ngIf="field == systemFields[0]">
<i matSuffix class="fa fa-spinner fa-spin" *ngIf="formGroup.get(field).pending && !referenceExists"></i>
<mat-icon *ngIf="!formGroup.get(field).pending && formGroup.get(field).dirty && formGroup.get(field).valid && !referenceExists" class="text-success" matSuffix>check</mat-icon>
<mat-icon *ngIf="!formGroup.get(field).pending && formGroup.get(field).dirty && formGroup.get(field).invalid || referenceExists" class="text-danger" matSuffix>clear</mat-icon>
<small *ngIf="referenceExists" class="text-danger">{{'REFERENCE-FIELD.REFERENCE-DIALOG-EDITOR.IDENTIFIER-EXISTS' | translate}}</small>
</ng-container>
</mat-form-field>
</div> </div>
</div> </div>
<ng-container *ngIf="referenceType && referenceType.definition && referenceType.definition.fields && referenceType.definition.fields.length > 0"> <div mat-dialog-content class="row">
<div *ngFor="let field of referenceType.definition.fields;"> <div *ngFor="let field of systemFields;">
<div class="col"> <div class="col">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{field.label}}</mat-label> <mat-label>{{field}}</mat-label>
<input matInput type="text" [name]="field.code" [formControl]="formGroup.get(field.code)"> <input matInput type="text" [name]="field" [formControl]="formGroup.get(field)">
<mat-error *ngIf="formGroup.get(field.code).hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get(field).hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<ng-container *ngIf="field == systemFields[0]">
<i matSuffix class="fa fa-spinner fa-spin" *ngIf="formGroup.get(field).pending && !referenceExists"></i>
<mat-icon *ngIf="!formGroup.get(field).pending && formGroup.get(field).dirty && formGroup.get(field).valid && !referenceExists" class="text-success" matSuffix>check</mat-icon>
<mat-icon *ngIf="!formGroup.get(field).pending && formGroup.get(field).dirty && formGroup.get(field).invalid || referenceExists" class="text-danger" matSuffix>clear</mat-icon>
<small *ngIf="referenceExists" class="text-danger">{{'REFERENCE-FIELD.REFERENCE-DIALOG-EDITOR.IDENTIFIER-EXISTS' | translate}}</small>
</ng-container>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
</ng-container> <ng-container *ngIf="referenceType && referenceType.definition && referenceType.definition.fields && referenceType.definition.fields.length > 0">
<div *ngFor="let field of referenceType.definition.fields;">
</div> <div class="col">
<div mat-dialog-actions class="row"> <mat-form-field class="w-100">
<div class="ml-auto col-auto"><button mat-raised-button type="button" mat-dialog-close>Cancel</button></div> <mat-label>{{field.label}}</mat-label>
<div class="col-auto"><button mat-button color="primary" [disabled]="!isFormValid" (click)="send()" type="button">Save</button></div> <input matInput type="text" [name]="field.code" [formControl]="formGroup.get(field.code)">
</div> <mat-error *ngIf="formGroup.get(field.code).hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</form> </mat-form-field>
</div>
</div>
</ng-container>
</div>
<div mat-dialog-actions class="row">
<div class="ml-auto col-auto"><button mat-raised-button type="button" mat-dialog-close>Cancel</button></div>
<div class="col-auto"><button mat-button color="primary" [disabled]="!isFormValid" (click)="send()" type="button">Save</button></div>
</div>
</form>
</div>

View File

@ -3,7 +3,31 @@
<div class="profile"> <div class="profile">
<div class="container-fluid"> <div class="container-fluid">
<div *ngIf="user | async as userProfile; else loading" class="user-profile"> <div *ngIf="user | async as userProfile; else loading" class="user-profile">
<div class="col user-profile-title">{{'USER-DIALOG.USER-PROFILE' | translate}}</div> <div class="row user-profile-title">
<div class="col mb-2">
{{'USER-DIALOG.USER-PROFILE' | translate}}
</div>
<div *ngIf="tenantFormGroup" class="col-auto mr-5">
<div class="row">
<div class="col">
<mat-form-field class="w-100">
<mat-label>Tenant</mat-label>
<mat-select placeholder="Tenant" [formControl]="this.tenantFormGroup.get('tenantCode')">
<ng-container *ngFor="let tenant of tenants | async">
<mat-option [value]="tenant">{{ tenant }}</mat-option>
</ng-container>
</mat-select>
</mat-form-field>
</div>
<div class="col-12 col-lg-auto mt-1">
<button mat-mini-fab (click)="switchTenant()">
<mat-icon class="mat-mini-fab-icon">refresh</mat-icon>
</button>
</div>
</div>
</div>
</div>
<div class="row profile-content" [formGroup]="formGroup"> <div class="row profile-content" [formGroup]="formGroup">
<div class="col"> <div class="col">
<div class="row mb-4"> <div class="row mb-4">

View File

@ -1,6 +1,6 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { UntypedFormArray, UntypedFormGroup } from '@angular/forms'; import { FormBuilder, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router'; import { ActivatedRoute, Params, Router } from '@angular/router';
import { RoleOrganizationType } from '@app/core/common/enum/role-organization-type'; import { RoleOrganizationType } from '@app/core/common/enum/role-organization-type';
@ -22,12 +22,16 @@ import { FormValidationErrorsDialogComponent } from '@common/forms/form-validati
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import * as moment from 'moment-timezone'; import * as moment from 'moment-timezone';
import { Observable, of } from 'rxjs'; import { Observable, from, of } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators'; import { map, takeUntil } from 'rxjs/operators';
import { AddAccountDialogComponent } from './add-account/add-account-dialog.component'; import { AddAccountDialogComponent } from './add-account/add-account-dialog.component';
import { UserProfileEditorModel } from './user-profile-editor.model'; import { UserProfileEditorModel } from './user-profile-editor.model';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { Guid } from '@common/types/guid'; import { Guid } from '@common/types/guid';
import { BaseHttpParams } from '@common/http/base-http-params';
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
import { PrincipalService } from '@app/core/services/http/principal.service';
import { KeycloakService } from 'keycloak-angular';
@Component({ @Component({
selector: 'app-user-profile', selector: 'app-user-profile',
@ -51,6 +55,7 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
errorMessages = []; errorMessages = [];
nestedCount = []; nestedCount = [];
nestedIndex = 0; nestedIndex = 0;
tenants: Observable<Array<string>>;
organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterOrganisations.bind(this), filterFn: this.filterOrganisations.bind(this),
@ -61,6 +66,8 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
}; };
formGroup: UntypedFormGroup; formGroup: UntypedFormGroup;
tenantFormGroup: UntypedFormGroup;
constructor( constructor(
private userService: UserService, private userService: UserService,
private route: ActivatedRoute, private route: ActivatedRoute,
@ -75,7 +82,10 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
private dialog: MatDialog, private dialog: MatDialog,
public enumUtils: EnumUtils, public enumUtils: EnumUtils,
private httpClient: HttpClient, private httpClient: HttpClient,
private matomoService: MatomoService private matomoService: MatomoService,
private formBuilder: UntypedFormBuilder,
private keycloakService: KeycloakService,
private principalService: PrincipalService
) { ) {
super(); super();
this.languages = this.languageService.getAvailableLanguagesCodes(); this.languages = this.languageService.getAvailableLanguagesCodes();
@ -100,6 +110,9 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
} }
ngOnInit() { ngOnInit() {
this.tenantFormGroup = this.formBuilder.group({
tenantCode: [this.authService.selectedTenant(), [Validators.required]]
});
this.matomoService.trackPageView('User Profile'); this.matomoService.trackPageView('User Profile');
this.route.params this.route.params
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
@ -149,6 +162,8 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(x => { if (x) { this.cultures = this._filterCulture(x); } }); .subscribe(x => { if (x) { this.cultures = this._filterCulture(x); } });
// this.initializeDisabledFormGroup(); // this.initializeDisabledFormGroup();
this.tenants = this.loadUserTenants();
this.unlock(); this.unlock();
return result; return result;
})); }));
@ -407,4 +422,29 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
} }
} }
// Switch Tenant
loadUserTenants(): Observable<Array<string>> {
const params = new BaseHttpParams();
params.interceptorContext = {
excludedInterceptors: [InterceptorType.TenantHeaderInterceptor]
};
return this.principalService.myTenants({ params: params });
}
switchTenant(): void {
if (this.tenantFormGroup.valid === false) return;
const selectedTenant = this.tenantFormGroup.get('tenantCode').value;
this.formSubmit(selectedTenant);
this.loadUser();
}
formSubmit(selectedTenant: string): void {
this.authService.selectedTenant(selectedTenant);
}
loadUser(): void {
const returnUrl = '/profile';
this.authService.prepareAuthRequest(from(this.keycloakService.getToken()), {}).pipe(takeUntil(this._destroyed)).subscribe(() => this.authService.onAuthenticateSuccess(returnUrl), (error) => this.authService.onAuthenticateError(error));
}
} }

View File

@ -112,6 +112,10 @@
}, },
"CRITERIA": { "CRITERIA": {
"LIKE": "Search..." "LIKE": "Search..."
},
"START-NEW-DMP-DIALOG": {
"UPLOAD-FILE": "Upoad File",
"REPLACE-FILE": "Replace File"
} }
}, },
"HYBRID-LISTING": { "HYBRID-LISTING": {
@ -1291,6 +1295,7 @@
"LOCKED": "Locked", "LOCKED": "Locked",
"DESCRIPTION": "Description", "DESCRIPTION": "Description",
"NO-TEMPLATE-MESSAGE": "If you can't find a template or if you want to create a personalized template for your institution, research community or training needs, please contact us.", "NO-TEMPLATE-MESSAGE": "If you can't find a template or if you want to create a personalized template for your institution, research community or training needs, please contact us.",
"DESCRIPTION-TEMPLATES-MAX-MULTIPLICITY": "Description Templates has reached the maximun multiplicity",
"FIELDS": { "FIELDS": {
"TITLE": "Title of Plan", "TITLE": "Title of Plan",
"DESCRIPTION": "Description", "DESCRIPTION": "Description",
@ -1304,7 +1309,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",