add backend validation in language, references, tenant,supportive material editor forms.

This commit is contained in:
amentis 2024-01-16 11:55:46 +02:00
parent d760209d20
commit 412c778d8c
13 changed files with 229 additions and 77 deletions

View File

@ -40,6 +40,9 @@ public abstract class BaseValidator<T> extends AbstractValidator<T> {
protected Boolean isEmpty(String value) { protected Boolean isEmpty(String value) {
return this.conventionService.isNullOrEmpty(value); return this.conventionService.isNullOrEmpty(value);
} }
protected Boolean isListNullOrEmpty(List<?> value) {
return this.conventionService.isListNullOrEmpty(value);
}
protected Boolean isNull(Object value) { protected Boolean isNull(Object value) {
return value == null; return value == null;
} }

View File

@ -186,9 +186,6 @@ public class ReferencePersist {
.iff(() -> !this.isEmpty(item.getReference())) .iff(() -> !this.isEmpty(item.getReference()))
.must(() -> this.lessEqualLength(item.getReference(), ReferenceEntity._referenceLength)) .must(() -> this.lessEqualLength(item.getReference(), ReferenceEntity._referenceLength))
.failOn(ReferencePersist._reference).failWith(messageSource.getMessage("Validation_MaxLength", new Object[]{ReferencePersist._reference}, LocaleContextHolder.getLocale())), .failOn(ReferencePersist._reference).failWith(messageSource.getMessage("Validation_MaxLength", new Object[]{ReferencePersist._reference}, LocaleContextHolder.getLocale())),
this.spec()
.must(() -> !this.isEmpty(item.getAbbreviation()))
.failOn(ReferencePersist._abbreviation).failWith(messageSource.getMessage("Validation_Required", new Object[]{ReferencePersist._abbreviation}, LocaleContextHolder.getLocale())),
this.spec() this.spec()
.iff(() -> !this.isEmpty(item.getAbbreviation())) .iff(() -> !this.isEmpty(item.getAbbreviation()))
.must(() -> this.lessEqualLength(item.getAbbreviation(), ReferenceEntity._abbreviationLength)) .must(() -> this.lessEqualLength(item.getAbbreviation(), ReferenceEntity._abbreviationLength))

View File

@ -47,7 +47,7 @@ public class TenantDepositConfigPersist {
@Override @Override
protected List<Specification> specifications(TenantDepositConfigPersist item) { protected List<Specification> specifications(TenantDepositConfigPersist item) {
return Collections.singletonList( return Collections.singletonList(
this.refSpec() this.navSpec()
.iff(() -> !this.isNull(item.getSources())) .iff(() -> !this.isNull(item.getSources()))
.on(TenantDepositConfigPersist._sources) .on(TenantDepositConfigPersist._sources)
.over(item.getSources()) .over(item.getSources())

View File

@ -47,7 +47,7 @@ public class TenantFileTransformersConfigPersist {
@Override @Override
protected List<Specification> specifications(TenantFileTransformersConfigPersist item) { protected List<Specification> specifications(TenantFileTransformersConfigPersist item) {
return Collections.singletonList( return Collections.singletonList(
this.refSpec() this.navSpec()
.iff(() -> !this.isNull(item.getSources())) .iff(() -> !this.isNull(item.getSources()))
.on(TenantFileTransformersConfigPersist._sources) .on(TenantFileTransformersConfigPersist._sources)
.over(item.getSources()) .over(item.getSources())

View File

@ -112,7 +112,7 @@ public class TenantSourcePersist {
.must(() -> !this.isEmpty(item.getUrl())) .must(() -> !this.isEmpty(item.getUrl()))
.failOn(TenantSourcePersist._url).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantSourcePersist._url}, LocaleContextHolder.getLocale())), .failOn(TenantSourcePersist._url).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantSourcePersist._url}, LocaleContextHolder.getLocale())),
this.spec() this.spec()
.must(() -> !this.isNull(item.getCodes())) .must(() -> !this.isListNullOrEmpty(item.getCodes()))
.failOn(TenantSourcePersist._codes).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantSourcePersist._codes}, LocaleContextHolder.getLocale())), .failOn(TenantSourcePersist._codes).failWith(messageSource.getMessage("Validation_Required", new Object[]{TenantSourcePersist._codes}, LocaleContextHolder.getLocale())),
this.spec() this.spec()
.must(() -> !this.isEmpty(item.getIssuerUrl())) .must(() -> !this.isEmpty(item.getIssuerUrl()))

View File

@ -33,8 +33,8 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'LANGUAGE-EDITOR.FIELDS.CODE' | translate}}</mat-label> <mat-label>{{'LANGUAGE-EDITOR.FIELDS.CODE' | translate}}</mat-label>
<input matInput type="text" name="code" [formControl]="formGroup.get('code')" required> <input matInput type="text" name="code" [formControl]="formGroup.get('code')" required>
<mat-error *ngIf="formGroup.get('code').hasError('required')"> <mat-error *ngIf="formGroup.get('code').hasError('backendError')">{{formGroup.get('code').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('code').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-4" *ngIf="!isNew"> <div class="col-4" *ngIf="!isNew">
@ -45,24 +45,24 @@
{{languageCode}} {{languageCode}}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="formGroup.get('code').hasError('required')"> <mat-error *ngIf="formGroup.get('code').hasError('backendError')">{{formGroup.get('code').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('code').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-4"> <div class="col-4">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'LANGUAGE-EDITOR.FIELDS.ORDINAL' | translate}}</mat-label> <mat-label>{{'LANGUAGE-EDITOR.FIELDS.ORDINAL' | translate}}</mat-label>
<input matInput type="text" name="ordinal" [formControl]="formGroup.get('ordinal')" required> <input matInput type="text" name="ordinal" [formControl]="formGroup.get('ordinal')" required>
<mat-error *ngIf="formGroup.get('ordinal').hasError('required')"> <mat-error *ngIf="formGroup.get('ordinal').hasError('backendError')">{{formGroup.get('ordinal').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('ordinal').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12"> <div class="col-12">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'LANGUAGE-EDITOR.FIELDS.PAYLOAD' | translate}}</mat-label> <mat-label>{{'LANGUAGE-EDITOR.FIELDS.PAYLOAD' | translate}}</mat-label>
<input matInput type="text" name="payload" [formControl]="formGroup.get('payload')"> <input matInput type="text" name="payload" [formControl]="formGroup.get('payload')">
<mat-error *ngIf="formGroup.get('payload').hasError('required')"> <mat-error *ngIf="formGroup.get('payload').hasError('backendError')">{{formGroup.get('payload').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('payload').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
<h9 class="col-12">{{'LANGUAGE-EDITOR.FIELDS.OVERRIDE' | translate}} <h9 class="col-12">{{'LANGUAGE-EDITOR.FIELDS.OVERRIDE' | translate}}
<mat-checkbox (change)="overrideFromFile($event, formGroup.get('code').value)"></mat-checkbox> <mat-checkbox (change)="overrideFromFile($event, formGroup.get('code').value)"></mat-checkbox>

View File

@ -33,8 +33,8 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'REFERENCE-EDITOR.FIELDS.LABEL' | translate}}</mat-label> <mat-label>{{'REFERENCE-EDITOR.FIELDS.LABEL' | translate}}</mat-label>
<input matInput type="text" name="label" [formControl]="formGroup.get('label')" required> <input matInput type="text" name="label" [formControl]="formGroup.get('label')" required>
<mat-error *ngIf="formGroup.get('label').hasError('required')"> <mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-4"> <div class="col-4">
@ -45,8 +45,8 @@
{{enumUtils.toReferenceTypeString(type)}} {{enumUtils.toReferenceTypeString(type)}}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="formGroup.get('type').hasError('required')"> <mat-error *ngIf="formGroup.get('type').hasError('backendError')">{{formGroup.get('type').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('type').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12"> <div class="col-12">
@ -55,9 +55,8 @@
<rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'description'" [placeholder]="'REFERENCE-EDITOR.FIELDS.DESCRIPTION-PLACEHOLDER'" [wrapperClasses]="(formGroup.get('description').touched && formGroup.get('description').hasError('required')) ? 'required' : ''" [editable]="formGroup.controls['description'].status !== 'DISABLED'"> <rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'description'" [placeholder]="'REFERENCE-EDITOR.FIELDS.DESCRIPTION-PLACEHOLDER'" [wrapperClasses]="(formGroup.get('description').touched && formGroup.get('description').hasError('required')) ? 'required' : ''" [editable]="formGroup.controls['description'].status !== 'DISABLED'">
</rich-text-editor-component> </rich-text-editor-component>
<div [class]="(formGroup.get('description').touched && formGroup.get('description').hasError('required')) ? 'visible' : 'invisible'" class="mat-form-field formGroup-field-subscript-wrapper"> <div [class]="(formGroup.get('description').touched && formGroup.get('description').hasError('required')) ? 'visible' : 'invisible'" class="mat-form-field formGroup-field-subscript-wrapper">
<mat-error> <mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED'| translate}} <mat-error>{{'GENERAL.VALIDATION.REQUIRED'| translate}}</mat-error>
</mat-error>
</div> </div>
</div> </div>
</div> </div>
@ -65,8 +64,8 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'REFERENCE-EDITOR.FIELDS.SOURCE' | translate}}</mat-label> <mat-label>{{'REFERENCE-EDITOR.FIELDS.SOURCE' | translate}}</mat-label>
<input matInput type="text" name="source" [formControl]="formGroup.get('source')" required> <input matInput type="text" name="source" [formControl]="formGroup.get('source')" required>
<mat-error *ngIf="formGroup.get('source').hasError('required')"> <mat-error *ngIf="formGroup.get('source').hasError('backendError')">{{formGroup.get('source').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('source').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-4"> <div class="col-4">
@ -77,24 +76,24 @@
{{enumUtils.toReferenceSourceTypeString(sourceType)}} {{enumUtils.toReferenceSourceTypeString(sourceType)}}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="formGroup.get('sourceType').hasError('required')"> <mat-error *ngIf="formGroup.get('sourceType').hasError('backendError')">{{formGroup.get('sourceType').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('sourceType').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'REFERENCE-EDITOR.FIELDS.REFERENCE' | translate}}</mat-label> <mat-label>{{'REFERENCE-EDITOR.FIELDS.REFERENCE' | translate}}</mat-label>
<input matInput type="text" name="reference" [formControl]="formGroup.get('reference')" required> <input matInput type="text" name="reference" [formControl]="formGroup.get('reference')" required>
<mat-error *ngIf="formGroup.get('reference').hasError('required')"> <mat-error *ngIf="formGroup.get('reference').hasError('backendError')">{{formGroup.get('reference').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('reference').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-4"> <div class="col-4">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'REFERENCE-EDITOR.FIELDS.ABBREVIATION' | translate}}</mat-label> <mat-label>{{'REFERENCE-EDITOR.FIELDS.ABBREVIATION' | translate}}</mat-label>
<input matInput type="text" name="abbreviation" [formControl]="formGroup.get('abbreviation')"> <input matInput type="text" name="abbreviation" [formControl]="formGroup.get('abbreviation')">
<mat-error *ngIf="formGroup.get('abbreviation').hasError('required')"> <mat-error *ngIf="formGroup.get('abbreviation').hasError('backendError')">{{formGroup.get('abbreviation').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('abbreviation').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
@ -121,8 +120,8 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'REFERENCE-EDITOR.FIELDS.CODE' | translate}}</mat-label> <mat-label>{{'REFERENCE-EDITOR.FIELDS.CODE' | translate}}</mat-label>
<input matInput type="text" name="code" [formControl]="field.get('code')" required> <input matInput type="text" name="code" [formControl]="field.get('code')" required>
<mat-error *ngIf="field.get('code').hasError('required')"> <mat-error *ngIf="field.get('code').hasError('backendError')">{{field.get('code').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="field.get('code').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
@ -133,16 +132,16 @@
{{enumUtils.toReferenceFieldDataTypeString(dataType)}} {{enumUtils.toReferenceFieldDataTypeString(dataType)}}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="field.get('dataType').hasError('required')"> <mat-error *ngIf="field.get('dataType').hasError('backendError')">{{field.get('dataType').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</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-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'REFERENCE-EDITOR.FIELDS.VALUE' | translate}}</mat-label> <mat-label>{{'REFERENCE-EDITOR.FIELDS.VALUE' | translate}}</mat-label>
<input matInput type="text" name="value" [formControl]="field.get('value')" required> <input matInput type="text" name="value" [formControl]="field.get('value')" required>
<mat-error *ngIf="field.get('value').hasError('required')"> <mat-error *ngIf="field.get('value').hasError('backendError')">{{field.get('value').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="field.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>

View File

@ -190,12 +190,19 @@ export class ReferenceEditorComponent extends BaseEditor<ReferenceEditorModel, R
// fields // fields
// //
addField(): void { addField(): void {
const field: FieldEditorModel = new FieldEditorModel(); (this.formGroup.get('definition').get('fields') as FormArray).push(this.editorModel.createChildField((this.formGroup.get('definition').get('fields') as FormArray).length));
(this.formGroup.get('definition').get('fields') as FormArray).push(field.buildForm());
} }
removeField(fieldIndex: number): void { removeField(fieldIndex: number): void {
(this.formGroup.get('definition').get('fields') as FormArray).removeAt(fieldIndex); (this.formGroup.get('definition').get('fields') as FormArray).removeAt(fieldIndex);
ReferenceEditorModel.reApplyDefinitionFieldsValidators(
{
formGroup: this.formGroup,
validationErrorModel: this.editorModel.validationErrorModel
}
)
this.formGroup.get('definition').get('fields').markAsDirty();
} }

View File

@ -1,4 +1,4 @@
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { ReferenceFieldDataType } from "@app/core/common/enum/reference-field-data-type"; import { ReferenceFieldDataType } from "@app/core/common/enum/reference-field-data-type";
import { ReferenceSourceType } from "@app/core/common/enum/reference-source-type"; import { ReferenceSourceType } from "@app/core/common/enum/reference-source-type";
import { ReferenceType } from "@app/core/common/enum/reference-type"; import { ReferenceType } from "@app/core/common/enum/reference-type";
@ -76,6 +76,25 @@ export class ReferenceEditorModel extends BaseEditorModel implements ReferencePe
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
} }
createChildField(index: number): UntypedFormGroup {
const field: FieldEditorModel = new FieldEditorModel(this.validationErrorModel);
return field.buildForm({ rootPath: 'definition.fields[' + index + '].' });
}
static reApplyDefinitionFieldsValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
}): void {
const { formGroup, validationErrorModel } = params;
const control = formGroup?.get('definition');
DefinitionEditorModel.reapplyFieldsValidators({
formArray: control.get('fields') as UntypedFormArray,
rootPath: `definition.`,
validationErrorModel: validationErrorModel
});
}
} }
export class DefinitionEditorModel implements DefinitionPersist { export class DefinitionEditorModel implements DefinitionPersist {
@ -133,6 +152,21 @@ export class DefinitionEditorModel implements DefinitionPersist {
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
} }
static reapplyFieldsValidators(params: {
formArray: UntypedFormArray,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const { validationErrorModel, rootPath, formArray } = params;
formArray?.controls?.forEach(
(control, index) => FieldEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `${rootPath}fields[${index}].`,
validationErrorModel: validationErrorModel
})
);
}
} }
export class FieldEditorModel implements FieldPersist { export class FieldEditorModel implements FieldPersist {
@ -191,5 +225,24 @@ export class FieldEditorModel implements FieldPersist {
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
} }
static reapplyValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
const context = FieldEditorModel.createValidationContext({
rootPath,
validationErrorModel
});
['code', 'dataType', 'value'].forEach(keyField => {
const control = formGroup?.get(keyField);
control?.clearValidators();
control?.addValidators(context.getValidation(keyField).validators);
})
}
} }

View File

@ -32,16 +32,16 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.NAME' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.NAME' | translate}}</mat-label>
<input matInput type="text" name="name" [formControl]="formGroup.get('name')" required> <input matInput type="text" name="name" [formControl]="formGroup.get('name')" required>
<mat-error *ngIf="formGroup.get('name').hasError('required')"> <mat-error *ngIf="formGroup.get('name').hasError('backendError')">{{formGroup.get('name').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('name').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-4"> <div class="col-4">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.CODE' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.CODE' | translate}}</mat-label>
<input matInput type="text" name="code" [formControl]="formGroup.get('code')" required> <input matInput type="text" name="code" [formControl]="formGroup.get('code')" required>
<mat-error *ngIf="formGroup.get('code').hasError('required')"> <mat-error *ngIf="formGroup.get('code').hasError('backendError')">{{formGroup.get('code').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('code').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12"> <div class="col-12">
@ -50,9 +50,8 @@
<rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'description'" [placeholder]="'TENANT-EDITOR.FIELDS.DESCRIPTION-PLACEHOLDER'" [wrapperClasses]="(formGroup.get('description').touched && formGroup.get('description').hasError('required')) ? 'required' : ''" [editable]="formGroup.controls['description'].status !== 'DISABLED'"> <rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'description'" [placeholder]="'TENANT-EDITOR.FIELDS.DESCRIPTION-PLACEHOLDER'" [wrapperClasses]="(formGroup.get('description').touched && formGroup.get('description').hasError('required')) ? 'required' : ''" [editable]="formGroup.controls['description'].status !== 'DISABLED'">
</rich-text-editor-component> </rich-text-editor-component>
<div [class]="(formGroup.get('description').touched && formGroup.get('description').hasError('required')) ? 'visible' : 'invisible'" class="mat-form-field formGroup-field-subscript-wrapper"> <div [class]="(formGroup.get('description').touched && formGroup.get('description').hasError('required')) ? 'visible' : 'invisible'" class="mat-form-field formGroup-field-subscript-wrapper">
<mat-error> <mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED'| translate}} <mat-error>{{'GENERAL.VALIDATION.REQUIRED'| translate}}</mat-error>
</mat-error>
</div> </div>
</div> </div>
</div> </div>
@ -79,40 +78,40 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.URL' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.URL' | translate}}</mat-label>
<input matInput type="text" name="url" [formControl]="source.get('url')" required> <input matInput type="text" name="url" [formControl]="source.get('url')" required>
<mat-error *ngIf="source.get('url').hasError('required')"> <mat-error *ngIf="source.get('url').hasError('backendError')">{{source.get('url').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="source.get('url').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.ISSUER-URL' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.ISSUER-URL' | translate}}</mat-label>
<input matInput type="text" name="issuerUrl" [formControl]="source.get('issuerUrl')" required> <input matInput type="text" name="issuerUrl" [formControl]="source.get('issuerUrl')" required>
<mat-error *ngIf="source.get('issuerUrl').hasError('required')"> <mat-error *ngIf="source.get('issuerUrl').hasError('backendError')">{{source.get('issuerUrl').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="source.get('issuerUrl').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.CLIENT-ID' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.CLIENT-ID' | translate}}</mat-label>
<input matInput type="text" name="clientId" [formControl]="source.get('clientId')" required> <input matInput type="text" name="clientId" [formControl]="source.get('clientId')" required>
<mat-error *ngIf="source.get('clientId').hasError('required')"> <mat-error *ngIf="source.get('clientId').hasError('backendError')">{{source.get('clientId').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="source.get('clientId').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.CLIENT-SECRET' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.CLIENT-SECRET' | translate}}</mat-label>
<input matInput type="text" name="clientSecret" [formControl]="source.get('clientSecret')" required> <input matInput type="text" name="clientSecret" [formControl]="source.get('clientSecret')" required>
<mat-error *ngIf="source.get('clientSecret').hasError('required')"> <mat-error *ngIf="source.get('clientSecret').hasError('backendError')">{{source.get('clientSecret').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="source.get('clientSecret').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.SCOPE' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.SCOPE' | translate}}</mat-label>
<input matInput type="text" name="scope" [formControl]="source.get('scope')" required> <input matInput type="text" name="scope" [formControl]="source.get('scope')" required>
<mat-error *ngIf="source.get('scope').hasError('required')"> <mat-error *ngIf="source.get('scope').hasError('backendError')">{{source.get('scope').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="source.get('scope').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
@ -134,6 +133,8 @@
[matChipInputAddOnBlur]="true" [matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addDepositCode($event)"/> (matChipInputTokenEnd)="addDepositCode($event)"/>
</mat-chip-grid> </mat-chip-grid>
<mat-error *ngIf="source.get('codes').hasError('backendError')">{{source.get('codes').getError('backendError').message}}</mat-error>
<mat-error *ngIf="source.get('codes').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@ -162,40 +163,40 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.URL' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.URL' | translate}}</mat-label>
<input matInput type="text" name="url" [formControl]="source.get('url')" required> <input matInput type="text" name="url" [formControl]="source.get('url')" required>
<mat-error *ngIf="source.get('url').hasError('required')"> <mat-error *ngIf="source.get('url').hasError('backendError')">{{source.get('url').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="source.get('url').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.ISSUER-URL' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.ISSUER-URL' | translate}}</mat-label>
<input matInput type="text" name="issuerUrl" [formControl]="source.get('issuerUrl')" required> <input matInput type="text" name="issuerUrl" [formControl]="source.get('issuerUrl')" required>
<mat-error *ngIf="source.get('issuerUrl').hasError('required')"> <mat-error *ngIf="source.get('issuerUrl').hasError('backendError')">{{source.get('issuerUrl').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="source.get('issuerUrl').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.CLIENT-ID' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.CLIENT-ID' | translate}}</mat-label>
<input matInput type="text" name="clientId" [formControl]="source.get('clientId')" required> <input matInput type="text" name="clientId" [formControl]="source.get('clientId')" required>
<mat-error *ngIf="source.get('clientId').hasError('required')"> <mat-error *ngIf="source.get('clientId').hasError('backendError')">{{source.get('clientId').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="source.get('clientId').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.CLIENT-SECRET' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.CLIENT-SECRET' | translate}}</mat-label>
<input matInput type="text" name="clientSecret" [formControl]="source.get('clientSecret')" required> <input matInput type="text" name="clientSecret" [formControl]="source.get('clientSecret')" required>
<mat-error *ngIf="source.get('clientSecret').hasError('required')"> <mat-error *ngIf="source.get('clientSecret').hasError('backendError')">{{source.get('clientSecret').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="source.get('clientSecret').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'TENANT-EDITOR.FIELDS.SCOPE' | translate}}</mat-label> <mat-label>{{'TENANT-EDITOR.FIELDS.SCOPE' | translate}}</mat-label>
<input matInput type="text" name="scope" [formControl]="source.get('scope')" required> <input matInput type="text" name="scope" [formControl]="source.get('scope')" required>
<mat-error *ngIf="source.get('scope').hasError('required')"> <mat-error *ngIf="source.get('scope').hasError('backendError')">{{source.get('scope').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="source.get('scope').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
@ -217,6 +218,8 @@
[matChipInputAddOnBlur]="true" [matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addFileCode($event)"/> (matChipInputTokenEnd)="addFileCode($event)"/>
</mat-chip-grid> </mat-chip-grid>
<mat-error *ngIf="source.get('codes').hasError('backendError')">{{source.get('codes').getError('backendError').message}}</mat-error>
<mat-error *ngIf="source.get('codes').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>

View File

@ -192,12 +192,20 @@ export class TenantEditorComponent extends BaseEditor<TenantEditorModel, Tenant>
// deposit source // deposit source
// //
addDepositSource(): void { addDepositSource(): void {
const source: TenantSourceEditorModel = new TenantSourceEditorModel(); (this.formGroup.get('config').get('deposit').get('sources') as FormArray).push(this.editorModel.createChildDeposit((this.formGroup.get('config').get('deposit').get('sources') as FormArray).length));
(this.formGroup.get('config').get('deposit').get('sources') as FormArray).push(source.buildForm());
} }
removeDepositSource(sourceIndex: number): void { removeDepositSource(sourceIndex: number): void {
(this.formGroup.get('config').get('deposit').get('sources') as FormArray).removeAt(sourceIndex); (this.formGroup.get('config').get('deposit').get('sources') as FormArray).removeAt(sourceIndex);
//Reapply validators
TenantEditorModel.reApplyDepositSourcesValidators(
{
formGroup: this.formGroup,
validationErrorModel: this.editorModel.validationErrorModel
}
)
this.formGroup.get('config').get('deposit').get('sources').markAsDirty();
} }
// deposit source codes // deposit source codes
@ -232,12 +240,20 @@ export class TenantEditorComponent extends BaseEditor<TenantEditorModel, Tenant>
// fileTransformers source // fileTransformers source
// //
addFileSource(): void { addFileSource(): void {
const source: TenantSourceEditorModel = new TenantSourceEditorModel(); (this.formGroup.get('config').get('fileTransformers').get('sources') as FormArray).push(this.editorModel.createChildFileTransformer((this.formGroup.get('config').get('fileTransformers').get('sources') as FormArray).length));
(this.formGroup.get('config').get('fileTransformers').get('sources') as FormArray).push(source.buildForm());
} }
removeFileSource(sourceIndex: number): void { removeFileSource(sourceIndex: number): void {
(this.formGroup.get('config').get('fileTransformers').get('sources') as FormArray).removeAt(sourceIndex); (this.formGroup.get('config').get('fileTransformers').get('sources') as FormArray).removeAt(sourceIndex);
//Reapply validators
TenantEditorModel.reApplyFileTransformerSourcesValidators(
{
formGroup: this.formGroup,
validationErrorModel: this.editorModel.validationErrorModel
}
)
this.formGroup.get('config').get('fileTransformers').get('sources').markAsDirty();
} }
// fileTransformers source codes // fileTransformers source codes

View File

@ -1,4 +1,4 @@
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { Tenant, TenantConfig, TenantConfigPersist, TenantDepositConfig, TenantDepositConfigPersist, TenantFileTransformersConfig, TenantFileTransformersConfigPersist, TenantPersist, TenantSource, TenantSourcePersist } from "@app/core/model/tenant/tenant"; import { Tenant, TenantConfig, TenantConfigPersist, TenantDepositConfig, TenantDepositConfigPersist, TenantFileTransformersConfig, TenantFileTransformersConfigPersist, TenantPersist, TenantSource, TenantSourcePersist } from "@app/core/model/tenant/tenant";
import { BaseEditorModel } from "@common/base/base-form-editor-model"; import { BaseEditorModel } from "@common/base/base-form-editor-model";
import { BackendErrorValidator } from "@common/forms/validation/custom-validator"; import { BackendErrorValidator } from "@common/forms/validation/custom-validator";
@ -55,6 +55,44 @@ export class TenantEditorModel extends BaseEditorModel implements TenantPersist
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
} }
createChildDeposit(index: number): UntypedFormGroup {
const deposit: TenantSourceEditorModel = new TenantSourceEditorModel(this.validationErrorModel);
return deposit.buildForm({ rootPath: 'config.deposit.sources[' + index + '].' });
}
static reApplyDepositSourcesValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
}): void {
const { formGroup, validationErrorModel } = params;
const control = formGroup?.get('config').get('deposit');
TenantDepositConfigEditorModel.reapplySourcesFieldsValidators({
formArray: control.get('sources') as UntypedFormArray,
rootPath: `config.deposit.`,
validationErrorModel: validationErrorModel
});
}
createChildFileTransformer(index: number): UntypedFormGroup {
const deposit: TenantSourceEditorModel = new TenantSourceEditorModel(this.validationErrorModel);
return deposit.buildForm({ rootPath: 'config.fileTransformers.sources[' + index + '].' });
}
static reApplyFileTransformerSourcesValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
}): void {
const { formGroup, validationErrorModel } = params;
const control = formGroup?.get('config').get('fileTransformers');
TenantDepositConfigEditorModel.reapplySourcesFieldsValidators({
formArray: control.get('sources') as UntypedFormArray,
rootPath: `config.fileTransformers.`,
validationErrorModel: validationErrorModel
});
}
} }
export class TenantConfigEditorModel implements TenantConfigPersist { export class TenantConfigEditorModel implements TenantConfigPersist {
@ -167,6 +205,21 @@ export class TenantDepositConfigEditorModel implements TenantDepositConfigPersis
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
} }
static reapplySourcesFieldsValidators(params: {
formArray: UntypedFormArray,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const { validationErrorModel, rootPath, formArray } = params;
formArray?.controls?.forEach(
(control, index) => TenantSourceEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `${rootPath}sources[${index}].`,
validationErrorModel: validationErrorModel
})
);
}
} }
export class TenantFileTransformersConfigEditorModel implements TenantFileTransformersConfigPersist { export class TenantFileTransformersConfigEditorModel implements TenantFileTransformersConfigPersist {
@ -294,4 +347,23 @@ export class TenantSourceEditorModel implements TenantSourcePersist {
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
} }
static reapplyValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
const context = TenantSourceEditorModel.createValidationContext({
rootPath,
validationErrorModel
});
['url', 'codes', 'issuerUrl', 'clientId', 'clientSecret', 'scope'].forEach(keyField => {
const control = formGroup?.get(keyField);
control?.clearValidators();
control?.addValidators(context.getValidation(keyField).validators);
})
}
} }

View File

@ -11,8 +11,8 @@
{{enumUtils.toSupportiveMaterialTypeString(type)}} {{enumUtils.toSupportiveMaterialTypeString(type)}}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="formGroup.get('type').hasError('required')"> <mat-error *ngIf="formGroup.get('type').hasError('backendError')">{{formGroup.get('type').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('type').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col"> <div class="col">
@ -23,8 +23,8 @@
{{languageCode}} {{languageCode}}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="formGroup.get('languageCode').hasError('required')"> <mat-error *ngIf="formGroup.get('languageCode').hasError('backendError')">{{formGroup.get('languageCode').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('languageCode').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@ -50,6 +50,8 @@
alignleft aligncenter alignright alignjustify | \ alignleft aligncenter alignright alignjustify | \
bullist numlist outdent indent | code codesample | searchreplace | preview | removeformat | help' bullist numlist outdent indent | code codesample | searchreplace | preview | removeformat | help'
}" [formControl]="formGroup.get('payload')"></editor> }" [formControl]="formGroup.get('payload')"></editor>
<mat-error *ngIf="formGroup.get('payload').hasError('backendError')">{{formGroup.get('payload').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('payload').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</div> </div>
</div> </div>
</mat-card> </mat-card>