rule target cannot be same field or fieldset

This commit is contained in:
CITE\amentis 2024-07-26 13:47:43 +03:00
parent cc877d8e53
commit ea46c6af80
9 changed files with 34 additions and 7 deletions

View File

@ -120,6 +120,7 @@ public class FieldPersist {
private final ValidatorFactory validatorFactory; private final ValidatorFactory validatorFactory;
private final FieldDataHelperServiceProvider fieldDataHelperServiceProvider; private final FieldDataHelperServiceProvider fieldDataHelperServiceProvider;
private String fieldSetId;
protected FieldPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory, FieldDataHelperServiceProvider fieldDataHelperServiceProvider) { protected FieldPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory, FieldDataHelperServiceProvider fieldDataHelperServiceProvider) {
super(conventionService, errors); super(conventionService, errors);
@ -128,6 +129,11 @@ public class FieldPersist {
this.fieldDataHelperServiceProvider = fieldDataHelperServiceProvider; this.fieldDataHelperServiceProvider = fieldDataHelperServiceProvider;
} }
public FieldPersistValidator withFieldSetId(String fieldSetId) {
this.fieldSetId = fieldSetId;
return this;
}
@Override @Override
protected Class<FieldPersist> modelClass() { protected Class<FieldPersist> modelClass() {
return FieldPersist.class; return FieldPersist.class;
@ -150,7 +156,7 @@ public class FieldPersist {
.iff(() -> !this.isListNullOrEmpty(item.getVisibilityRules())) .iff(() -> !this.isListNullOrEmpty(item.getVisibilityRules()))
.on(FieldPersist._visibilityRules) .on(FieldPersist._visibilityRules)
.over(item.getVisibilityRules()) .over(item.getVisibilityRules())
.using((itm) -> this.validatorFactory.validator(RulePersist.RulePersistValidator.class).withFieldPersist(item)), .using((itm) -> this.validatorFactory.validator(RulePersist.RulePersistValidator.class).withFieldPersist(item).withFieldSetId(fieldSetId)),
this.refSpec() this.refSpec()
.iff(() -> !this.isNull(item.getDefaultValue())) .iff(() -> !this.isNull(item.getDefaultValue()))
.on(FieldPersist._defaultValue) .on(FieldPersist._defaultValue)

View File

@ -176,7 +176,7 @@ public class FieldSetPersist {
.iff(() -> !this.isListNullOrEmpty(item.getFields())) .iff(() -> !this.isListNullOrEmpty(item.getFields()))
.on(FieldSetPersist._fields) .on(FieldSetPersist._fields)
.over(item.getFields()) .over(item.getFields())
.using((itm) -> this.validatorFactory.validator(FieldPersist.FieldPersistValidator.class)) .using((itm) -> this.validatorFactory.validator(FieldPersist.FieldPersistValidator.class).withFieldSetId(item.getId()))
); );
} }
} }

View File

@ -84,6 +84,7 @@ public class RulePersist {
private final MessageSource messageSource; private final MessageSource messageSource;
private final ValidatorFactory validatorFactory; private final ValidatorFactory validatorFactory;
private org.opencdmp.model.persist.descriptiontemplatedefinition.FieldPersist fieldEntity; private org.opencdmp.model.persist.descriptiontemplatedefinition.FieldPersist fieldEntity;
private String fieldSetId;
protected RulePersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory) { protected RulePersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory) {
super(conventionService, errors); super(conventionService, errors);
@ -96,6 +97,11 @@ public class RulePersist {
return this; return this;
} }
public RulePersistValidator withFieldSetId(String fieldSetId) {
this.fieldSetId = fieldSetId;
return this;
}
@Override @Override
protected Class<RulePersist> modelClass() { protected Class<RulePersist> modelClass() {
return RulePersist.class; return RulePersist.class;
@ -108,6 +114,10 @@ public class RulePersist {
this.spec() this.spec()
.must(() -> !this.isEmpty(item.getTarget())) .must(() -> !this.isEmpty(item.getTarget()))
.failOn(RulePersist._target).failWith(this.messageSource.getMessage("Validation_Required", new Object[]{RulePersist._target}, LocaleContextHolder.getLocale())), .failOn(RulePersist._target).failWith(this.messageSource.getMessage("Validation_Required", new Object[]{RulePersist._target}, LocaleContextHolder.getLocale())),
this.spec()
.iff(() -> !this.isEmpty(item.getTarget()))
.must(() -> !item.getTarget().equals(this.fieldEntity.getId()) && !item.getTarget().equals(this.fieldSetId))
.failOn(RulePersist._target).failWith(this.messageSource.getMessage("Validation_UnexpectedValue", new Object[]{RulePersist._target}, LocaleContextHolder.getLocale())),
this.spec() this.spec()
.iff(() -> this.isNull(fieldType)) .iff(() -> this.isNull(fieldType))
.must(() -> !FieldType.TAGS.equals(fieldType) && !FieldType.INTERNAL_ENTRIES_DESCRIPTIONS.equals(fieldType) && !FieldType.INTERNAL_ENTRIES_PLANS.equals(fieldType) && .must(() -> !FieldType.TAGS.equals(fieldType) && !FieldType.INTERNAL_ENTRIES_DESCRIPTIONS.equals(fieldType) && !FieldType.INTERNAL_ENTRIES_PLANS.equals(fieldType) &&

View File

@ -84,7 +84,7 @@
<!-- FIELDS --> <!-- FIELDS -->
<div #inputs transition-group class="col-12" *ngIf="hasFocus" [@fade-in]> <div #inputs transition-group class="col-12" *ngIf="hasFocus" [@fade-in]>
<div *ngFor="let field of fieldsArray.controls; let i=index;" class="row bg-white field-input mt-3" (click)="setTargetField(field)" transition-group-item> <div *ngFor="let field of fieldsArray.controls; let i=index;" class="row bg-white field-input mt-3" (click)="setTargetField(field)" transition-group-item>
<app-description-template-editor-field-component class="col-12" [form]="field" [showOrdinal]="false" [viewOnly]="viewOnly" [expandView]="hasFocus" [canBeDeleted]="fieldsArray.length !=1" [validationErrorModel]="validationErrorModel" [validationRootPath]="validationRootPath + '.fields[' + i + '].'" (delete)="deleteField(i)"> <app-description-template-editor-field-component class="col-12" [form]="field" [showOrdinal]="false" [viewOnly]="viewOnly" [expandView]="hasFocus" [canBeDeleted]="fieldsArray.length !=1" [validationErrorModel]="validationErrorModel" [validationRootPath]="validationRootPath + '.fields[' + i + '].'" [fieldSetId]="form.get('id').value" (delete)="deleteField(i)">
<div class="arrows mt-2"> <div class="arrows mt-2">
<ul class="list-unstyled list-inline d-flex align-items-center"> <ul class="list-unstyled list-inline d-flex align-items-center">
<li *ngIf="canGoUp(i)" class="text-muted"> <li *ngIf="canGoUp(i)" class="text-muted">

View File

@ -155,7 +155,7 @@
<ng-container *ngIf="form.get('visibilityRules')?.value.length"> <ng-container *ngIf="form.get('visibilityRules')?.value.length">
<h4 class="col-12" style="font-weight: bold">{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.FIELD.FIELDS.RULES-TITLE' | translate}} <h4 class="col-12" style="font-weight: bold">{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.FIELD.FIELDS.RULES-TITLE' | translate}}
</h4> </h4>
<app-description-template-editor-visibility-rule-component class="col-12" [form]="form.get('visibilityRules')" [validationErrorModel]="validationErrorModel" [validationRootPath]="validationRootPath" [fieldTypeForCheck]="form.get('data').get('fieldType').value" [formArrayOptionsForCheck]="this.form.get('data')?.get('options')" [viewOnly]="viewOnly"></app-description-template-editor-visibility-rule-component> <app-description-template-editor-visibility-rule-component class="col-12" [form]="form.get('visibilityRules')" [validationErrorModel]="validationErrorModel" [validationRootPath]="validationRootPath" [fieldId]="form.get('id').value" [fieldTypeForCheck]="form.get('data').get('fieldType').value" [formArrayOptionsForCheck]="this.form.get('data')?.get('options')" [fieldSetId]="fieldSetId" [viewOnly]="viewOnly"></app-description-template-editor-visibility-rule-component>
</ng-container> </ng-container>
</div> </div>
<div class="row" [ngSwitch]="form.get('data')?.get('fieldType')?.value"> <div class="row" [ngSwitch]="form.get('data')?.get('fieldType')?.value">

View File

@ -35,6 +35,7 @@ export class DescriptionTemplateEditorFieldComponent extends BaseComponent imple
@Output() delete = new EventEmitter<void>(); @Output() delete = new EventEmitter<void>();
@Input() validationErrorModel: ValidationErrorModel; @Input() validationErrorModel: ValidationErrorModel;
@Input() validationRootPath: string; @Input() validationRootPath: string;
@Input() fieldSetId: string;
readonly separatorKeysCodes: number[] = [ENTER, COMMA]; readonly separatorKeysCodes: number[] = [ENTER, COMMA];

View File

@ -18,7 +18,7 @@
<mat-select formControlName="target" (openedChange)="computeOptions($event)"> <mat-select formControlName="target" (openedChange)="computeOptions($event)">
<!-- SHOW FIELDSETS --> <!-- SHOW FIELDSETS -->
<mat-optgroup [label]="'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.RULE.FIELDS.FIELDSETS' | translate"> <mat-optgroup [label]="'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.RULE.FIELDS.FIELDSETS' | translate">
<mat-option *ngFor="let option of fieldSetOptions" [value]="option.id" style="line-height: normal;" [disabled]="parentIds.includes(option.id) || hiddenBy.includes(option.id)" [matTooltip]="getToolTipMessage(option.id)" [matTooltipShowDelay]="700"> <mat-option *ngFor="let option of fieldSetOptions" [value]="option.id" style="line-height: normal;" [disabled]="parentIds.includes(option.id) || hiddenBy.includes(option.id) || option.id == fieldSetId" [matTooltip]="getToolTipMessage(option.id)" [matTooltipShowDelay]="700">
<div class="row mt-2 mb-2"> <div class="row mt-2 mb-2">
<div class="col"> <div class="col">
<span class="title-text"> <span class="title-text">
@ -33,7 +33,7 @@
</mat-optgroup> </mat-optgroup>
<!-- SHOW FIELDS --> <!-- SHOW FIELDS -->
<mat-optgroup [label]="'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.RULE.FIELDS.FIELDS' | translate"> <mat-optgroup [label]="'DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.RULE.FIELDS.FIELDS' | translate">
<mat-option *ngFor="let option of fieldOptions" [value]="option.id" style="line-height: normal;" [disabled]="parentIds.includes(option.id) ||hiddenBy.includes(option.id)" [matTooltip]="getToolTipMessage(option.id)" [matTooltipShowDelay]="700"> <mat-option *ngFor="let option of fieldOptions" [value]="option.id" style="line-height: normal;" [disabled]="parentIds.includes(option.id) ||hiddenBy.includes(option.id) || option.id == fieldId" [matTooltip]="getToolTipMessage(option.id)" [matTooltipShowDelay]="700">
<div class="row mt-2 mb-2"> <div class="row mt-2 mb-2">
<div class="col"> <div class="col">
<span class="title-text"> <span class="title-text">

View File

@ -23,6 +23,8 @@ export class DescriptionTemplateEditorRuleComponent implements OnInit {
@Input() viewOnly: boolean; @Input() viewOnly: boolean;
@Input() validationErrorModel: ValidationErrorModel; @Input() validationErrorModel: ValidationErrorModel;
@Input() validationRootPath: string; @Input() validationRootPath: string;
@Input() fieldId: string = null;
@Input() fieldSetId: string = null;
options: OptionItem[]; options: OptionItem[];
@ -83,6 +85,11 @@ export class DescriptionTemplateEditorRuleComponent implements OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
this.form.controls?.forEach(
(control, index) => {
if (control.get('target').value == this.fieldId || control.get('target').value == this.fieldSetId) control.get('target').setValue(null);
}
);
this.rootForm = this.findRootForm(); this.rootForm = this.findRootForm();
this._computeOptions(); this._computeOptions();
} }

View File

@ -256,6 +256,9 @@ export class VisibilityRulesService {
for (let i = 0; i < rulesForParentKey.length; i++) { for (let i = 0; i < rulesForParentKey.length; i++) {
const ruleForParentKey = rulesForParentKey[i]; const ruleForParentKey = rulesForParentKey[i];
if (ruleForParentKey.source == ruleForParentKey.target) continue; //Invalid rule where source and target are equal
const field: DescriptionFieldPersist = fieldsMap.get(ruleForParentKey.source); const field: DescriptionFieldPersist = fieldsMap.get(ruleForParentKey.source);
const rulesForGrandParentKey: RuleWithTarget[] = this.getChainParentRules(ruleForParentKey); const rulesForGrandParentKey: RuleWithTarget[] = this.getChainParentRules(ruleForParentKey);