dmp blueprint editor fixes

This commit is contained in:
amentis 2024-01-29 13:13:30 +02:00
parent 37d349fa9b
commit 8fb3556acb
13 changed files with 229 additions and 98 deletions

View File

@ -138,7 +138,7 @@ public class SectionPersist {
.failOn(SectionPersist._hasTemplates).failWith(messageSource.getMessage("Validation_Required", new Object[]{SectionPersist._hasTemplates}, LocaleContextHolder.getLocale())), .failOn(SectionPersist._hasTemplates).failWith(messageSource.getMessage("Validation_Required", new Object[]{SectionPersist._hasTemplates}, LocaleContextHolder.getLocale())),
this.spec() this.spec()
.must(() -> !this.isListNullOrEmpty(item.getFields())) .must(() -> !this.isListNullOrEmpty(item.getFields()))
.failOn(SectionPersist._fields).failWith(messageSource.getMessage("Validation_Required", new Object[]{eu.eudat.model.persist.descriptiontemplatedefinition.SectionPersist._fieldSets}, LocaleContextHolder.getLocale())), .failOn(SectionPersist._fields).failWith(messageSource.getMessage("Validation_Required", new Object[]{SectionPersist._fields}, LocaleContextHolder.getLocale())),
this.navSpec() this.navSpec()
.iff(() -> !this.isListNullOrEmpty(item.getFields())) .iff(() -> !this.isListNullOrEmpty(item.getFields()))
.on(SectionPersist._fields) .on(SectionPersist._fields)

View File

@ -44,7 +44,9 @@ public class DescriptionTemplateQuery extends QueryBase<DescriptionTemplateEntit
private Collection<DescriptionTemplateStatus> statuses; private Collection<DescriptionTemplateStatus> statuses;
private Collection<UUID> excludedIds; private Collection<UUID> excludedIds;
private Collection<UUID> excludedGroupIds;
private Collection<UUID> typeIds; private Collection<UUID> typeIds;
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None); private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
@ -159,6 +161,21 @@ public class DescriptionTemplateQuery extends QueryBase<DescriptionTemplateEntit
return this; return this;
} }
public DescriptionTemplateQuery excludedGroupIds(Collection<UUID> values) {
this.excludedGroupIds = values;
return this;
}
public DescriptionTemplateQuery excludedGroupIds(UUID value) {
this.excludedGroupIds = List.of(value);
return this;
}
public DescriptionTemplateQuery excludedGroupIds(UUID... value) {
this.excludedGroupIds = Arrays.asList(value);
return this;
}
public DescriptionTemplateQuery authorize(EnumSet<AuthorizationFlags> values) { public DescriptionTemplateQuery authorize(EnumSet<AuthorizationFlags> values) {
this.authorize = values; this.authorize = values;
return this; return this;
@ -181,7 +198,7 @@ public class DescriptionTemplateQuery extends QueryBase<DescriptionTemplateEntit
@Override @Override
protected Boolean isFalseQuery() { protected Boolean isFalseQuery() {
return this.isEmpty(this.ids) || this.isEmpty(this.typeIds) || this.isEmpty(this.versionStatuses) || this.isEmpty(this.groupIds) ||this.isEmpty(this.isActives) || this.isEmpty(this.excludedIds) || this.isEmpty(this.statuses); return this.isEmpty(this.ids) || this.isEmpty(this.typeIds) || this.isEmpty(this.versionStatuses) || this.isEmpty(this.groupIds) ||this.isEmpty(this.isActives) || this.isEmpty(this.excludedIds) || this.isEmpty(this.excludedGroupIds)|| this.isEmpty(this.statuses);
} }
@Override @Override
@ -263,6 +280,12 @@ public class DescriptionTemplateQuery extends QueryBase<DescriptionTemplateEntit
notInClause.value(item); notInClause.value(item);
predicates.add(notInClause.not()); predicates.add(notInClause.not());
} }
if (this.excludedGroupIds != null) {
CriteriaBuilder.In<UUID> notInClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(DescriptionTemplateEntity._groupId));
for (UUID item : this.excludedGroupIds)
notInClause.value(item);
predicates.add(notInClause.not());
}
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

@ -27,6 +27,8 @@ public class DescriptionTemplateLookup extends Lookup {
private List<UUID> excludedIds; private List<UUID> excludedIds;
private List<UUID> excludedGroupIds;
public String getLike() { public String getLike() {
return like; return like;
} }
@ -91,6 +93,14 @@ public class DescriptionTemplateLookup extends Lookup {
this.versionStatuses = versionStatuses; this.versionStatuses = versionStatuses;
} }
public List<UUID> getExcludedGroupIds() {
return excludedGroupIds;
}
public void setExcludedGroupIds(List<UUID> excludedGroupIds) {
this.excludedGroupIds = excludedGroupIds;
}
public DescriptionTemplateQuery enrich(QueryFactory queryFactory) { public DescriptionTemplateQuery enrich(QueryFactory queryFactory) {
DescriptionTemplateQuery query = queryFactory.query(DescriptionTemplateQuery.class); DescriptionTemplateQuery query = queryFactory.query(DescriptionTemplateQuery.class);
if (this.like != null) query.like(this.like); if (this.like != null) query.like(this.like);
@ -99,6 +109,7 @@ public class DescriptionTemplateLookup extends Lookup {
if (this.statuses != null) query.statuses(this.statuses); if (this.statuses != null) query.statuses(this.statuses);
if (this.ids != null) query.ids(this.ids); if (this.ids != null) query.ids(this.ids);
if (this.excludedIds != null) query.excludedIds(this.excludedIds); if (this.excludedIds != null) query.excludedIds(this.excludedIds);
if (this.excludedGroupIds != null) query.excludedGroupIds(this.excludedGroupIds);
if (this.typeIds != null) query.typeIds(this.typeIds); if (this.typeIds != null) query.typeIds(this.typeIds);
if (this.versionStatuses != null) query.versionStatuses(this.versionStatuses); if (this.versionStatuses != null) query.versionStatuses(this.versionStatuses);

View File

@ -12,6 +12,7 @@ export class DescriptionTemplateLookup extends Lookup implements DescriptionTemp
typeIds: Guid[]; typeIds: Guid[];
statuses: DescriptionTemplateStatus[]; statuses: DescriptionTemplateStatus[];
groupIds: Guid[]; groupIds: Guid[];
excludedGroupIds: Guid[];
versionStatuses: DescriptionTemplateVersionStatus[]; versionStatuses: DescriptionTemplateVersionStatus[];
constructor() { constructor() {
@ -27,5 +28,6 @@ export interface DescriptionTemplateFilter {
typeIds: Guid[]; typeIds: Guid[];
statuses: DescriptionTemplateStatus[]; statuses: DescriptionTemplateStatus[];
groupIds: Guid[]; groupIds: Guid[];
excludedGroupIds: Guid[];
versionStatuses: DescriptionTemplateVersionStatus[]; versionStatuses: DescriptionTemplateVersionStatus[];
} }

View File

@ -101,6 +101,7 @@ export class DescriptionTemplateService {
titleFn: (item: DescriptionTemplate) => item.label, titleFn: (item: DescriptionTemplate) => item.label,
subtitleFn: (item: DescriptionTemplate) => item.description, subtitleFn: (item: DescriptionTemplate) => item.description,
valueAssign: (item: DescriptionTemplate) => item.id, valueAssign: (item: DescriptionTemplate) => item.id,
popupItemActionIcon: 'visibility'
}; };
// tslint:disable-next-line: member-ordering // tslint:disable-next-line: member-ordering
@ -145,6 +146,7 @@ export class DescriptionTemplateService {
titleFn: (item: DescriptionTemplate) => item.label, titleFn: (item: DescriptionTemplate) => item.label,
subtitleFn: (item: DescriptionTemplate) => item.description, subtitleFn: (item: DescriptionTemplate) => item.description,
valueAssign: (item: DescriptionTemplate) => item.groupId, valueAssign: (item: DescriptionTemplate) => item.groupId,
popupItemActionIcon: 'visibility'
}; };
// tslint:disable-next-line: member-ordering // tslint:disable-next-line: member-ordering
@ -159,11 +161,13 @@ export class DescriptionTemplateService {
popupItemActionIcon: 'visibility' popupItemActionIcon: 'visibility'
}; };
public buildDescriptionTempalteGroupAutocompleteLookup(like?: string, excludedIds?: Guid[], groupIds?: Guid[]): DescriptionTemplateLookup { public buildDescriptionTempalteGroupAutocompleteLookup(like?: string, excludedIds?: Guid[], groupIds?: Guid[], excludedGroupIds?: Guid[]): DescriptionTemplateLookup {
const lookup: DescriptionTemplateLookup = new DescriptionTemplateLookup(); const lookup: DescriptionTemplateLookup = new DescriptionTemplateLookup();
lookup.page = { size: 100, offset: 0 }; lookup.page = { size: 100, offset: 0 };
if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; } if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; }
if (groupIds && groupIds.length > 0) { lookup.groupIds = groupIds; } if (groupIds && groupIds.length > 0) { lookup.groupIds = groupIds; }
if (excludedGroupIds && excludedGroupIds.length > 0) { lookup.excludedGroupIds = excludedGroupIds; }
lookup.isActive = [IsActive.Active]; lookup.isActive = [IsActive.Active];
lookup.versionStatuses = [DescriptionTemplateVersionStatus.Current]; lookup.versionStatuses = [DescriptionTemplateVersionStatus.Current];
lookup.statuses = [DescriptionTemplateStatus.Finalized]; lookup.statuses = [DescriptionTemplateStatus.Finalized];

View File

@ -31,6 +31,8 @@ export interface SingleAutoCompleteConfiguration {
optionTemplate?: TemplateRef<any>; optionTemplate?: TemplateRef<any>;
// Selected value formating template // Selected value formating template
selectedValueTemplate?: TemplateRef<any>; selectedValueTemplate?: TemplateRef<any>;
// Display icon that opens popup
popupItemActionIcon?: string;
// // To revert: "We set the items observable on focus to avoid the request being executed on component load." // // To revert: "We set the items observable on focus to avoid the request being executed on component load."
// forceFocus?: boolean; // forceFocus?: boolean;

View File

@ -15,6 +15,7 @@
<span>{{_titleFn(item)}}</span> <span>{{_titleFn(item)}}</span>
<br *ngIf="_subtitleFn(item)"> <br *ngIf="_subtitleFn(item)">
<small *ngIf="_subtitleFn(item)">{{_subtitleFn(item)}}</small> <small *ngIf="_subtitleFn(item)">{{_subtitleFn(item)}}</small>
<span *ngIf="popupItemActionIcon" class="option-icon" (click)="_optionActionClick(item, $event)"><mat-icon>{{popupItemActionIcon}}</mat-icon></span>
</div> </div>
</mat-option> </mat-option>
</mat-optgroup> </mat-optgroup>
@ -31,6 +32,7 @@
<span *ngIf="!_optionTemplate(item)">{{_titleFn(item)}}</span> <span *ngIf="!_optionTemplate(item)">{{_titleFn(item)}}</span>
<br *ngIf="_subtitleFn(item)"> <br *ngIf="_subtitleFn(item)">
<small *ngIf="_subtitleFn(item)">{{_subtitleFn(item)}}</small> <small *ngIf="_subtitleFn(item)">{{_subtitleFn(item)}}</small>
<span *ngIf="popupItemActionIcon" class="option-icon" (click)="_optionActionClick(item, $event)"><mat-icon>{{popupItemActionIcon}}</mat-icon></span>
</div> </div>
</mat-option> </mat-option>
</ng-container> </ng-container>

View File

@ -35,6 +35,15 @@
} }
} }
.option-icon {
mat-icon {
margin: 0px 5px 0px 10px;
}
mat-icon:hover {
color: var(--primary-color);
}
}
.chip-list { .chip-list {
width: auto; width: auto;
} }

View File

@ -50,6 +50,7 @@ export class SingleAutoCompleteComponent extends _CustomComponentMixinBase imple
// Selected Option Event // Selected Option Event
@Output() optionSelected: EventEmitter<any> = new EventEmitter(); @Output() optionSelected: EventEmitter<any> = new EventEmitter();
@Output() optionActionClicked: EventEmitter<any> = new EventEmitter();
id = `single-autocomplete-${SingleAutoCompleteComponent.nextId++}`; id = `single-autocomplete-${SingleAutoCompleteComponent.nextId++}`;
stateChanges = new Subject<void>(); stateChanges = new Subject<void>();
@ -192,6 +193,13 @@ export class SingleAutoCompleteComponent extends _CustomComponentMixinBase imple
this.optionSelectedInternal(event.option.value); this.optionSelectedInternal(event.option.value);
} }
_optionActionClick(item: any, event: MouseEvent): void {
if (event != null) {
event.stopPropagation();
}
this.optionActionClicked.emit(item);
}
private optionSelectedInternal(item: any) { private optionSelectedInternal(item: any) {
const newValue = this._valueToAssign(item); const newValue = this._valueToAssign(item);
@ -331,6 +339,10 @@ export class SingleAutoCompleteComponent extends _CustomComponentMixinBase imple
return this.configuration.autoSelectFirstOptionOnBlur != null ? this.configuration.autoSelectFirstOptionOnBlur : false; return this.configuration.autoSelectFirstOptionOnBlur != null ? this.configuration.autoSelectFirstOptionOnBlur : false;
} }
get popupItemActionIcon(): string {
return this.configuration.popupItemActionIcon != null ? this.configuration.popupItemActionIcon : '';
}
// get forceFocus(): boolean { // get forceFocus(): boolean {
// return this.configuration.forceFocus != null ? this.configuration.forceFocus : false; // return this.configuration.forceFocus != null ? this.configuration.forceFocus : false;
// } // }

View File

@ -87,8 +87,6 @@
<mat-select multiple [(ngModel)]="selectedSystemFields" [disabled]="formGroup.disabled" [ngModelOptions]="{standalone: true}" (selectionChange)= "addSystemField(sectionIndex, $event)"> <mat-select multiple [(ngModel)]="selectedSystemFields" [disabled]="formGroup.disabled" [ngModelOptions]="{standalone: true}" (selectionChange)= "addSystemField(sectionIndex, $event)">
<mat-option *ngFor="let systemFieldType of dmpBlueprintSystemFieldTypeEnum" [disabled]="systemFieldDisabled(systemFieldType)" [value]="systemFieldType">{{enumUtils.toDmpBlueprintSystemFieldTypeString(systemFieldType)}}</mat-option> <mat-option *ngFor="let systemFieldType of dmpBlueprintSystemFieldTypeEnum" [disabled]="systemFieldDisabled(systemFieldType)" [value]="systemFieldType">{{enumUtils.toDmpBlueprintSystemFieldTypeString(systemFieldType)}}</mat-option>
</mat-select> </mat-select>
<!-- <mat-error *ngIf="fieldsArray(sectionIndex).hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> -->
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-auto"> <div class="col-auto">
@ -102,14 +100,13 @@
<div class="col-auto"> <div class="col-auto">
<span style="font-size: 15px;">{{fieldIndex + 1}}</span> <span style="font-size: 15px;">{{fieldIndex + 1}}</span>
</div> </div>
<div class="col-auto"> <div class="col-auto d-flex"><mat-icon [ngClass]="{'drag-handle-disabled': formGroup.disabled}" cdkDragHandle class="drag-handle">drag_indicator</mat-icon></div>
<mat-icon cdkDragHandle [ngClass]="{'drag-handle-disabled': formGroup.disabled}">drag_indicator</mat-icon>
</div>
<div class="col-auto" *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM"> <div class="col-auto" *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SYSTEM-FIELD' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SYSTEM-FIELD' | translate}}</mat-label>
<input matInput disabled value="{{enumUtils.toDmpBlueprintSystemFieldTypeString(field.get('systemFieldType').value)}}" type="text" name="name"> <input matInput disabled value="{{enumUtils.toDmpBlueprintSystemFieldTypeString(field.get('systemFieldType').value)}}" type="text" name="name">
<mat-error *ngIf="field.get('dataType').hasError('backendError')">{{field.get('dataType').getError('backendError').message}}</mat-error> <mat-error *ngIf="field.get('dataType').hasError('backendError')">{{field.get('dataType').getError('backendError').message}}</mat-error>
<mat-error *ngIf="field.get('dataType').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-auto" *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.EXTRA"> <div class="col-auto" *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.EXTRA">
@ -137,6 +134,7 @@
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-PLACEHOLDER' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-PLACEHOLDER' | translate}}</mat-label>
<input matInput type="text" name="placeholder" [formControl]="field.get('placeholder')"> <input matInput type="text" name="placeholder" [formControl]="field.get('placeholder')">
<mat-error *ngIf="field.get('placeholder').hasError('backendError')">{{field.get('placeholder').getError('backendError').message}}</mat-error> <mat-error *ngIf="field.get('placeholder').hasError('backendError')">{{field.get('placeholder').getError('backendError').message}}</mat-error>
<mat-error *ngIf="field.get('placeholder').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col"> <div class="col">
@ -144,11 +142,13 @@
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-DESCRIPTION' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-DESCRIPTION' | translate}}</mat-label>
<input matInput type="text" name="description" [formControl]="field.get('description')"> <input matInput type="text" name="description" [formControl]="field.get('description')">
<mat-error *ngIf="field.get('description').hasError('backendError')">{{field.get('description').getError('backendError').message}}</mat-error> <mat-error *ngIf="field.get('description').hasError('backendError')">{{field.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="field.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<mat-checkbox [disabled]="field.get('systemFieldType')?.value === dmpBlueprintSystemFieldType.TEXT || field.get('systemFieldType')?.value === dmpBlueprintSystemFieldType.HTML_TEXT" [formControl]="field.get('required')"><span>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-REQUIRED' | translate}}</span></mat-checkbox> <mat-checkbox [disabled]="field.get('systemFieldType')?.value === dmpBlueprintSystemFieldType.TEXT || field.get('systemFieldType')?.value === dmpBlueprintSystemFieldType.HTML_TEXT" [formControl]="field.get('required')"><span>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-REQUIRED' | translate}}</span></mat-checkbox>
<mat-error *ngIf="field.get('systemFieldType').hasError('backendError')">{{field.get('systemFieldType').getError('backendError').message}}</mat-error> <mat-error *ngIf="field.get('systemFieldType').hasError('backendError')">{{field.get('systemFieldType').getError('backendError').message}}</mat-error>
<mat-error *ngIf="field.get('systemFieldType').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</div> </div>
<div *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM" [hidden]="viewOnly" class="col-auto"> <div *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM" [hidden]="viewOnly" class="col-auto">
<button mat-icon-button matTooltip="{{'DMP-BLUEPRINT-EDITOR.ACTIONS.REMOVE-SYSTEM-FIELD' | translate}}" (click)="removeSystemField(sectionIndex, fieldIndex)" [disabled]="formGroup.disabled"> <button mat-icon-button matTooltip="{{'DMP-BLUEPRINT-EDITOR.ACTIONS.REMOVE-SYSTEM-FIELD' | translate}}" (click)="removeSystemField(sectionIndex, fieldIndex)" [disabled]="formGroup.disabled">
@ -161,6 +161,8 @@
</button> </button>
</div> </div>
</div> </div>
<mat-error *ngIf="section.get('fields').dirty && section.get('fields').hasError('required')">{{'DMP-BLUEPRINT-EDITOR.FIELDS-REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="section.get('fields').hasError('backendError')">{{section.get('fields').getError('backendError').message}}</mat-error>
</div> </div>
</div> </div>
</mat-card-content> </mat-card-content>
@ -168,50 +170,62 @@
<div class="col-12"> <div class="col-12">
<div class="row"> <div class="row">
<div class="col-auto"> <div class="col-auto">
<!-- <mat-checkbox [formControl]="section.get('hasTemplates')" (change)="checkForBlueprints($event, sectionIndex)"> --> <mat-checkbox [formControl]="section.get('hasTemplates')" (change) = "removeAllDescriptionTemplates($event, sectionIndex)">
<mat-checkbox [formControl]="section.get('hasTemplates')">
{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}} {{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}
<mat-error *ngIf="section.get('hasTemplates').hasError('backendError')">{{section.get('hasTemplates').getError('backendError').message}}</mat-error> <mat-error *ngIf="section.get('hasTemplates').hasError('backendError')">{{section.get('hasTemplates').getError('backendError').message}}</mat-error>
<mat-error *ngIf="section.get('hasTemplates').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-checkbox> </mat-checkbox>
</div> </div>
<div class="col-auto" *ngIf="section.get('hasTemplates').value == true">
<button mat-button class="action-btn" type="button" (click)="addDescriptionTemplate(sectionIndex)" [disabled]="formGroup.disabled">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.ADD-DESCRIPTION-TEMPLATE' | translate}}</button>
</div>
</div> </div>
</div> </div>
<div class="col-12" *ngIf="section.get('hasTemplates').value == true"> <div cdkDropList class="col-12" (cdkDropListDropped)="dropDescriptionTemplates($event, sectionIndex)">
<div class="row"> <div *ngFor="let descriptionTemplate of section.get('descriptionTemplates').controls; let descriptionTemplateIndex=index;" cdkDrag class="row align-items-center" [cdkDragDisabled]="formGroup.disabled">
<div class="col-12"> <div class="col-auto">
<span style="font-size: 15px;">{{descriptionTemplateIndex + 1}}</span>
</div>
<div class="col-auto d-flex"><mat-icon [ngClass]="{'drag-handle-disabled': formGroup.disabled}" cdkDragHandle class="drag-handle">drag_indicator</mat-icon></div>
<div class="col">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}</mat-label>
<app-multiple-auto-complete [disabled]="formGroup.disabled" [hidePlaceholder]="true" required='false' [configuration]="descriptionTemplateService.descriptionTempalteGroupMultipleAutocompleteConfiguration" (optionRemoved)="onRemoveDescritionTemplate($event, sectionIndex)" (optionSelected)="onSelectDescritionTemplate($event, sectionIndex)" (optionActionClicked)="onPreviewDescriptionTemplate($event, i)"></app-multiple-auto-complete> </mat-form-field> <app-single-auto-complete [formControl]="descriptionTemplate.get('descriptionTemplateGroupId')" [hidePlaceholder]="true" [configuration]="descriptionTempalteGroupSingleAutocompleteConfiguration" (optionActionClicked)="onPreviewDescriptionTemplate($event, i)"></app-single-auto-complete>
<mat-error *ngIf="descriptionTemplate.get('descriptionTemplateGroupId').hasError('backendError')">{{descriptionTemplate.get('descriptionTemplateGroupId').getError('backendError').message}}</mat-error>
<mat-error *ngIf="descriptionTemplate.get('descriptionTemplateGroupId').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div> </div>
</div> <div class="col">
</div> <mat-form-field class="w-100">
<div *ngFor="let descriptionTemplate of section.get('descriptionTemplates').controls; let j=index;" class="col-12"> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-LABEL' | translate}}</mat-label>
<div class="col-12"> <input matInput type="text" name="label" [formControl]="descriptionTemplate.get('label')">
<div class="row"> <mat-error *ngIf="descriptionTemplate.get('label').hasError('backendError')">{{descriptionTemplate.get('label').getError('backendError').message}}</mat-error>
<div class="col-4"> <mat-error *ngIf="descriptionTemplate.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-form-field class="w-100"> </mat-form-field>
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-LABEL' | translate}}</mat-label>
<input matInput type="text" value="descriptionTemplate.get('label')" name="label" [formControl]="descriptionTemplate.get('label')">
<mat-error *ngIf="descriptionTemplate.get('label').hasError('backendError')">{{descriptionTemplate.get('label').getError('backendError').message}}</mat-error>
</mat-form-field>
</div>
<div class="col-4">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MIN-MULTIPLICITY' | translate}}</mat-label>
<input matInput type="number" min="0" name="minMultiplicity" [formControl]="descriptionTemplate.get('minMultiplicity')">
<mat-error *ngIf="descriptionTemplate.get('minMultiplicity').hasError('backendError')">{{descriptionTemplate.get('minMultiplicity').getError('backendError').message}}</mat-error>
</mat-form-field>
</div>
<div class="col-4">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MAX-MULTIPLICITY' | translate}}</mat-label>
<input matInput type="number" min="1" name="maxMultiplicity" [formControl]="descriptionTemplate.get('maxMultiplicity')">
<mat-error *ngIf="descriptionTemplate.get('maxMultiplicity').hasError('backendError')">{{descriptionTemplate.get('maxMultiplicity').getError('backendError').message}}</mat-error>
</mat-form-field>
</div>
</div> </div>
</div> <div class="col">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MIN-MULTIPLICITY' | translate}}</mat-label>
<input matInput type="number" min="0" name="minMultiplicity" [formControl]="descriptionTemplate.get('minMultiplicity')">
<mat-error *ngIf="descriptionTemplate.get('minMultiplicity').hasError('backendError')">{{descriptionTemplate.get('minMultiplicity').getError('backendError').message}}</mat-error>
<mat-error *ngIf="descriptionTemplate.get('minMultiplicity').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MAX-MULTIPLICITY' | translate}}</mat-label>
<input matInput type="number" min="1" name="maxMultiplicity" [formControl]="descriptionTemplate.get('maxMultiplicity')">
<mat-error *ngIf="descriptionTemplate.get('maxMultiplicity').hasError('backendError')">{{descriptionTemplate.get('maxMultiplicity').getError('backendError').message}}</mat-error>
<mat-error *ngIf="descriptionTemplate.get('maxMultiplicity').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-auto d-flex">
<button mat-icon-button class="action-list-icon" matTooltip="{{'DMP-BLUEPRINT-EDITOR.ACTIONS.REMOVE-DESCRIPTION-TEMPLATE' | translate}}" (click)="removeDescriptionTemplate(sectionIndex, descriptionTemplateIndex)" [disabled]="formGroup.disabled">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</div> </div>
</mat-card> </mat-card>

View File

@ -17,7 +17,6 @@ import { IsActive } from '@app/core/common/enum/is-active.enum';
import { AppPermission } from '@app/core/common/enum/permission.enum'; import { AppPermission } from '@app/core/common/enum/permission.enum';
import { DmpBlueprint, DmpBlueprintPersist } from '@app/core/model/dmp-blueprint/dmp-blueprint'; import { DmpBlueprint, DmpBlueprintPersist } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { AuthService } from '@app/core/services/auth/auth.service'; import { AuthService } from '@app/core/services/auth/auth.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { LoggingService } from '@app/core/services/logging/logging-service'; import { LoggingService } from '@app/core/services/logging/logging-service';
import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { FileUtils } from '@app/core/services/utilities/file-utils.service'; import { FileUtils } from '@app/core/services/utilities/file-utils.service';
@ -35,15 +34,12 @@ import { map, takeUntil } from 'rxjs/operators';
import { DescriptionTemplatesInSectionEditorModel, DmpBlueprintDefinitionSectionEditorModel, DmpBlueprintEditorModel, FieldInSectionEditorModel } from './dmp-blueprint-editor.model'; import { DescriptionTemplatesInSectionEditorModel, DmpBlueprintDefinitionSectionEditorModel, DmpBlueprintEditorModel, FieldInSectionEditorModel } from './dmp-blueprint-editor.model';
import { DmpBlueprintEditorResolver } from './dmp-blueprint-editor.resolver'; import { DmpBlueprintEditorResolver } from './dmp-blueprint-editor.resolver';
import { DmpBlueprintEditorService } from './dmp-blueprint-editor.service'; import { DmpBlueprintEditorService } from './dmp-blueprint-editor.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { DescriptionTemplateService } from '@app/core/services/description-template/description-template.service'; import { DescriptionTemplateService } from '@app/core/services/description-template/description-template.service';
import { DescriptionTemplateLookup } from '@app/core/query/description-template.lookup';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { nameof } from 'ts-simple-nameof';
import { DescriptionTemplateStatus } from '@app/core/common/enum/description-template-status';
import { DescriptionTemplateVersionStatus } from '@app/core/common/enum/description-template-version-status';
import { MatSelectChange } from '@angular/material/select'; import { MatSelectChange } from '@angular/material/select';
import { DescriptionTemplatePreviewDialogComponent } from '../../description-template/description-template-preview/description-template-preview-dialog.component'; import { DescriptionTemplatePreviewDialogComponent } from '../../description-template/description-template-preview/description-template-preview-dialog.component';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { MatCheckboxChange } from '@angular/material/checkbox';
@Component({ @Component({
@ -64,6 +60,16 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
public dmpBlueprintSystemFieldTypeEnum = this.enumUtils.getEnumValues<DmpBlueprintSystemFieldType>(DmpBlueprintSystemFieldType); public dmpBlueprintSystemFieldTypeEnum = this.enumUtils.getEnumValues<DmpBlueprintSystemFieldType>(DmpBlueprintSystemFieldType);
dmpBlueprintExtraFieldDataType = DmpBlueprintExtraFieldDataType; dmpBlueprintExtraFieldDataType = DmpBlueprintExtraFieldDataType;
public dmpBlueprintExtraFieldDataTypeEnum = this.enumUtils.getEnumValues<DmpBlueprintExtraFieldDataType>(DmpBlueprintExtraFieldDataType); public dmpBlueprintExtraFieldDataTypeEnum = this.enumUtils.getEnumValues<DmpBlueprintExtraFieldDataType>(DmpBlueprintExtraFieldDataType);
descriptionTempalteGroupSingleAutocompleteConfiguration: SingleAutoCompleteConfiguration = {
initialItems: (data?: any) => this.descriptionTemplateService.query(this.descriptionTemplateService.buildDescriptionTempalteGroupAutocompleteLookup(null, null, null, this.getUsedDescriptionTemplateGroupIds())).pipe(map(x => x.items)),
filterFn: (searchQuery: string, data?: any) => this.descriptionTemplateService.query(this.descriptionTemplateService.buildDescriptionTempalteGroupAutocompleteLookup(searchQuery, null, null, this.getUsedDescriptionTemplateGroupIds() ? this.getUsedDescriptionTemplateGroupIds(): null)).pipe(map(x => x.items)),
getSelectedItem: (selectedItem: any) => this.descriptionTemplateService.query(this.descriptionTemplateService.buildDescriptionTempalteGroupAutocompleteLookup(null, null, [selectedItem])).pipe(map(x => x.items[0])),
displayFn: (item: DescriptionTemplate) => item.label,
titleFn: (item: DescriptionTemplate) => item.label,
subtitleFn: (item: DescriptionTemplate) => item.description,
valueAssign: (item: DescriptionTemplate) => item.groupId,
popupItemActionIcon: 'visibility'
}
protected get canDelete(): boolean { protected get canDelete(): boolean {
return !this.isDeleted && !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteDmpBlueprint); return !this.isDeleted && !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteDmpBlueprint);
@ -289,9 +295,21 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
} }
removeSystemField(sectionIndex: number, fieldIndex: number): void { removeSystemField(sectionIndex: number, fieldIndex: number): void {
const formArray = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray); const fieldsArray = (this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray;
formArray.removeAt(fieldIndex); const systemFieldType = fieldsArray.at(fieldIndex).get('systemFieldType').value
formArray.controls.forEach((section, index) => { if(systemFieldType > -1) {
if (this.selectedSystemFields.length == 1){
this.selectedSystemFields = [];
}else{
const index = this.selectedSystemFields.indexOf(systemFieldType);
if (index > -1) {
this.selectedSystemFields.splice(index, 1);
this.selectedSystemFields = [...this.selectedSystemFields];
}
}
}
fieldsArray.removeAt(fieldIndex);
fieldsArray.controls.forEach((section, index) => {
section.get('ordinal').setValue(index + 1); section.get('ordinal').setValue(index + 1);
}); });
@ -301,7 +319,7 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
validationErrorModel: this.editorModel.validationErrorModel validationErrorModel: this.editorModel.validationErrorModel
} }
); );
(this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields').markAsDirty(); fieldsArray.markAsDirty();
} }
addExtraField(sectionIndex: number): void { addExtraField(sectionIndex: number): void {
@ -325,7 +343,6 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
} }
); );
(this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields').markAsDirty(); (this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields').markAsDirty();
// ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).at(fieldIndex).markAsDirty();
} }
@ -346,51 +363,87 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
(this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields').markAsDirty(); (this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields').markAsDirty();
} }
//Description Templates
removeAllDescriptionTemplates(matCheckBox: MatCheckboxChange, sectionIndex: number){
if(matCheckBox.checked == false){
const descriptionTemplateSize = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray).length;
for (let i=0; i< descriptionTemplateSize; i++) this.removeDescriptionTemplate(sectionIndex, 0);
}
}
addDescriptionTemplate(sectionIndex: number): void {
const descriptionTempaltesArray = (this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray ;
descriptionTempaltesArray.push(this.editorModel.createChildDescriptionTemplate(sectionIndex, ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray).length));
}
getUsedDescriptionTemplateGroupIds(): Guid[]{
let excludedGroupIds: Guid[] = [];
(this.formGroup.get('definition').get('sections') as FormArray).controls.forEach((section, index) => {
const descriptionTempaltesArray = (this.formGroup.get('definition').get('sections') as FormArray).at(index).get('descriptionTemplates') as FormArray;
if (descriptionTempaltesArray.length > 1){
descriptionTempaltesArray.controls.forEach((template, index) => {
if(template.get('descriptionTemplateGroupId').value != undefined) excludedGroupIds.push(template.get('descriptionTemplateGroupId').value as Guid);
})
}
});
return excludedGroupIds;
}
removeDescriptionTemplate(sectionIndex: number, descriptionTemplateIndex: number): void {
const descriptionTempaltesArray = (this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray;
descriptionTempaltesArray.removeAt(descriptionTemplateIndex);
DmpBlueprintEditorModel.reApplySectionValidators(
{
formGroup: this.formGroup,
validationErrorModel: this.editorModel.validationErrorModel
}
);
descriptionTempaltesArray.markAsDirty();
}
dropDescriptionTemplates(event: CdkDragDrop<string[]>, sectionIndex: number) {
const descriptionTemplatesFormArray = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray);
moveItemInArray(descriptionTemplatesFormArray.controls, event.previousIndex, event.currentIndex);
descriptionTemplatesFormArray.updateValueAndValidity();
DmpBlueprintEditorModel.reApplySectionValidators({
formGroup: this.formGroup,
validationErrorModel: this.editorModel.validationErrorModel
}
);
(this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates').markAsDirty();
}
// //
// //
// Autocomplete configuration // Autocomplete configuration
// //
// //
private buildAutocompleteLookup(like?: string, excludedIds?: Guid[], ids?: Guid[]): DescriptionTemplateLookup { // onRemoveDescritionTemplate(event, sectionIndex: number) {
const lookup: DescriptionTemplateLookup = new DescriptionTemplateLookup(); // const descriptionTemplateFormArray = (this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray;
lookup.page = { size: 100, offset: 0 }; // const foundIndex = descriptionTemplateFormArray.controls.findIndex(blueprint => blueprint.get('descriptionTemplateId').value === event.id);
if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; } // if (foundIndex !== -1) {
if (ids && ids.length > 0) { lookup.ids = ids; } // descriptionTemplateFormArray.removeAt(foundIndex);
lookup.isActive = [IsActive.Active]; // DmpBlueprintEditorModel.reApplySectionValidators(
lookup.statuses = [DescriptionTemplateStatus.Finalized]; // {
lookup.versionStatuses = [DescriptionTemplateVersionStatus.Current]; // formGroup: this.formGroup,
lookup.project = { // validationErrorModel: this.editorModel.validationErrorModel
fields: [ // }
nameof<DescriptionTemplate>(x => x.id), // )
nameof<DescriptionTemplate>(x => x.label) // this.formGroup.get('definition').get('sections').markAsDirty();
] // }
}; // }
lookup.order = { items: [nameof<DescriptionTemplate>(x => x.label)] };
if (like) { lookup.like = this.filterService.transformLike(like); }
return lookup;
}
onRemoveDescritionTemplate(event, sectionIndex: number) { // onSelectDescritionTemplate(item, sectionIndex) {
const descriptionTemplateFormArray = (this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray; // ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray)
const foundIndex = descriptionTemplateFormArray.controls.findIndex(blueprint => blueprint.get('descriptionTemplateId').value === event.id); // .push(this.editorModel.createChildDescriptionTemplate(item, sectionIndex, ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray).length));
if (foundIndex !== -1) {
descriptionTemplateFormArray.removeAt(foundIndex);
DmpBlueprintEditorModel.reApplySectionValidators(
{
formGroup: this.formGroup,
validationErrorModel: this.editorModel.validationErrorModel
}
)
this.formGroup.get('definition').get('sections').markAsDirty();
}
}
onSelectDescritionTemplate(item, sectionIndex) { // }
((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray)
.push(this.editorModel.createChildDescriptionTemplate(item, sectionIndex, ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray).length));
}
// ngAfterViewInit() { // ngAfterViewInit() {

View File

@ -86,11 +86,8 @@ export class DmpBlueprintEditorModel extends BaseEditorModel implements DmpBluep
return field.buildForm({ rootPath: 'definition.sections[' + sectionIndex + '].fields[' + index + '].' }); return field.buildForm({ rootPath: 'definition.sections[' + sectionIndex + '].fields[' + index + '].' });
} }
createChildDescriptionTemplate(item: any, sectionIndex: number, index: number): UntypedFormGroup { createChildDescriptionTemplate(sectionIndex: number, index: number, item?: any): UntypedFormGroup {
const descriptionTemplate: DescriptionTemplatesInSectionEditorModel = new DescriptionTemplatesInSectionEditorModel(this.validationErrorModel); const descriptionTemplate: DescriptionTemplatesInSectionEditorModel = new DescriptionTemplatesInSectionEditorModel(this.validationErrorModel);
// descriptionTemplate.id = Guid.create();
descriptionTemplate.descriptionTemplateGroupId = item.descriptionTemplateGroupId;
descriptionTemplate.label = item.label;
return descriptionTemplate.buildForm({ rootPath: 'definition.sections[' + sectionIndex + '].descriptionTemplates[' + index + '].' }); return descriptionTemplate.buildForm({ rootPath: 'definition.sections[' + sectionIndex + '].descriptionTemplates[' + index + '].' });
} }
@ -488,7 +485,7 @@ export class DescriptionTemplatesInSectionEditorModel implements DescriptionTemp
validationErrorModel validationErrorModel
}); });
['id', 'descriptionTemplateId', 'label', 'minMultiplicity', 'maxMultiplicity'].forEach(keyField => { ['descriptionTemplateGroupId', 'label', 'minMultiplicity', 'maxMultiplicity'].forEach(keyField => {
const control = formGroup?.get(keyField); const control = formGroup?.get(keyField);
control?.clearValidators(); control?.clearValidators();
control?.addValidators(context.getValidation(keyField).validators); control?.addValidators(context.getValidation(keyField).validators);

View File

@ -1625,10 +1625,12 @@
} }
}, },
"ACTIONS": { "ACTIONS": {
"ADD-EXTRA-FIELD": "Add extra field", "ADD-EXTRA-FIELD": "Add Extra Field",
"REMOVE-SYSTEM-FIELD": "Delete", "REMOVE-SYSTEM-FIELD": "Delete",
"REMOVE-EXTRA-FIELD": "Delete", "REMOVE-EXTRA-FIELD": "Delete",
"REMOVE-SECTION": "Remove Section", "REMOVE-SECTION": "Remove Section",
"ADD-DESCRIPTION-TEMPLATE": "Add Description Template",
"REMOVE-DESCRIPTION-TEMPLATE": "Remove Description Template",
"ADD-SECTION": "Add Section", "ADD-SECTION": "Add Section",
"SAVE": "Save", "SAVE": "Save",
"CANCEL": "Cancel", "CANCEL": "Cancel",
@ -2141,7 +2143,7 @@
"DATE": "Date", "DATE": "Date",
"NUMBER": "Number", "NUMBER": "Number",
"TEXT": "Text", "TEXT": "Text",
"EXTERNAL-AUTOCOMPLETE": "External AutoComplete" "RICH-TEXT": "Rich Text"
}, },
"TYPE": { "TYPE": {
"INPUT": "Input" "INPUT": "Input"