diff options
author | eschcam <cameron.scholes@est.tech> | 2023-01-06 12:17:56 +0000 |
---|---|---|
committer | Michael Morris <michael.morris@est.tech> | 2023-02-28 12:24:57 +0000 |
commit | e546c7283de4abf182545cea1aa07a8de0233d3b (patch) | |
tree | 2966cf125ef7d089ca02ccb41aac3243bbf8ac7a | |
parent | 1f589435d0213865e6d82b3441e1c3d18a263aaf (diff) |
Add validation for int and float constraints
Issue-ID: SDC-4316
Signed-off-by: eschcam <cameron.scholes@est.tech>
Change-Id: I6d6172743779291597305583f2a7f4f2145f57fb
7 files changed, 493 insertions, 269 deletions
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.html index 46d4114250..3bbdaff2cb 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.html +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.html @@ -20,99 +20,113 @@ --> <div class="app-constraints"> - <form novalidate class="w-sdc-form two-columns"> - <div class="w-sdc-form-columns-wrapper" *ngFor="let constraint of constraints; let constraintIndex = index; trackBy:trackByFn"> - <div class="w-sdc-form-column-small"> - <select class="i-sdc-form-select" - data-tests-id="constraints" - [disabled]="isViewOnly" - (change)="onChangeConstraintType(constraintIndex, $event.target.value)"> - <option *ngIf="constraint" [value]="constraint.type" - hidden selected> - {{ConstraintTypesMapping[constraint.type]}} - </option> - <option *ngFor="let constraintType of constraintTypes" - [value]="constraintType" - [disabled]="disableConstraint(constraintType, constraint.type)"> - {{ConstraintTypesMapping[constraintType]}} - </option> - </select> - </div> + <form novalidate class="w-sdc-form two-columns" [formGroup]="constraintForm"> + <div *ngFor="let constraint of constraintsArray.controls; let constraintIndex = index; trackBy:trackByFn"> - <div class="w-sdc-form-columns-wrapper"> + <div formArrayName="constraint"> + <div class="w-sdc-form-columns-wrapper" [formGroupName]="constraintIndex"> + <div class="w-sdc-form-column-small"> + <select class="i-sdc-form-select" + data-tests-id="constraints" + formControlName="type" + [value]="constraintsArray.at(constraintIndex).get('type').value" + (change)="onChangeConstraintType(constraintIndex, $event.target.value)"> + <option *ngIf="constraint" [value]="constraint.value.type" + hidden selected> + {{ConstraintTypesMapping[constraint.value.type]}} + </option> + <option *ngFor="let constraintType of constraintTypes" + [value]="constraintType" + [disabled]="disableConstraint(constraintType, constraint.value.type)"> + {{ConstraintTypesMapping[constraintType]}} + </option> + </select> - <div class="w-sdc-form-column"> - <!-- ConstraintTypes.in_range--> - <div class="w-sdc-form-columns-wrapper" *ngIf="constraint.type == 'inRange'"> - <div class="w-sdc-form-column"> - <input type="text" class="i-sdc-form-input myClass" - (input)="onChangeConstrainValueIndex(constraintIndex, $event.target.value, 0)" - [disabled]="isViewOnly" - [value]="getInRangeValue(constraintIndex, 0)"/> - </div> - <div class="w-sdc-form-column"> - <input type="text" class="i-sdc-form-input myClass" - (input)="onChangeConstrainValueIndex(constraintIndex, $event.target.value, 1)" - [disabled]="isViewOnly" - [value]="getInRangeValue(constraintIndex, 1)"/> - </div> + <div class="validation-errors"> + <ng-container *ngFor="let validation of validationMessages.type"> + <div class="input-error" *ngIf="constraintsArray.at(constraintIndex).get('type').hasError(validation.type);"> + {{ validation.message }} + </div> + </ng-container> </div> + </div> - <!-- ConstraintTypes.valid_values--> - <div *ngIf="constraint.type == 'validValues'"> - <div class="w-sdc-form-columns-wrapper-block"> - <div class="add-btn add-list-item w-sdc-form-column-block" - [ngClass]="{'disabled': isViewOnly}" - (click)="addToList(constraintIndex)">Add to List</div> - </div> - <div class="w-sdc-form-columns-wrapper" *ngFor="let value of constraint.value; let valueIndex = index; trackBy:trackByFn"> + + <div class="w-sdc-form-columns-wrapper"> + + <div class="w-sdc-form-column"> + <div class="w-sdc-form-columns-wrapper" *ngIf="constraint.value.type == 'inRange'"> <div class="w-sdc-form-column"> - <input type="text" class="i-sdc-form-input" *ngIf="propertyType !== 'boolean'" - [disabled]="isViewOnly" - [value]="value" - (input)="onChangeConstrainValueIndex(constraintIndex, $event.target.value, valueIndex)"/> - <select class="i-sdc-form-select" *ngIf="propertyType == 'boolean'" - [disabled]="isViewOnly" - [value]="value" - (input)="onChangeConstrainValueIndex(constraintIndex, $event.target.value, valueIndex)"> - <option ngValue="true">true</option> - <option ngValue="false">false</option> - </select> + <input type="text" class="i-sdc-form-input myClass" required + (input)="onChangeConstrainValueIndex(constraintIndex, $event.target.value, 0)" + [value]="getInRangeValue(constraintIndex, 0)"/> + + <ng-container *ngFor="let validation of validationMessages.constraint"> + <div class="input-error" *ngIf="constraintValuesArray(constraintIndex).controls[0].hasError(validation.type);"> + {{ validation.message }} + </div> + </ng-container> </div> <div class="w-sdc-form-column"> - <span class="sprite-new delete-btn" [ngClass]="{'disabled': isViewOnly}" (click)="removeFromList(constraintIndex, valueIndex)"></span> + <input type="text" class="i-sdc-form-input myClass" required + (input)="onChangeConstrainValueIndex(constraintIndex, $event.target.value, 1)" + [value]="getInRangeValue(constraintIndex, 1)"/> + + <ng-container *ngFor="let validation of validationMessages.constraint"> + <div class="input-error" *ngIf="constraintValuesArray(constraintIndex).controls[1].hasError(validation.type);"> + {{ validation.message }} + </div> + </ng-container> </div> </div> - </div> - <!-- ConstraintTypes.equal--> - <div *ngIf="constraint.type == 'equal'"> - <input type="text" class="i-sdc-form-input" *ngIf="propertyType !== 'boolean'" - [disabled]="isViewOnly" - (input)="onChangeConstraintValue(constraintIndex, $event.target.value)" - [value]="constraint.value"/> - <select class="i-sdc-form-select" *ngIf="propertyType == 'boolean'" - [disabled]="isViewOnly" - [value]="constraint.value" - (input)="onChangeConstraintValue(constraintIndex, $event.target.value)"> - <option ngValue="true">true</option> - <option ngValue="false">false</option> - </select> - </div> + <div *ngIf="constraint.value.type == 'validValues'"> + <div class="w-sdc-form-columns-wrapper-block"> + <div class="add-btn add-list-item w-sdc-form-column-block" + [ngClass]="{'disabled': isViewOnly}" + (click)="addToList(constraintIndex)">Add to List</div> + </div> + <div class="w-sdc-form-columns-wrapper" *ngFor="let value of constraintValuesArray(constraintIndex).controls; let valueIndex = index; trackBy:trackByFn"> + <div class="w-sdc-form-column"> + <input type="text" class="i-sdc-form-input" required + [value]="value.value" + (input)="onChangeConstrainValueIndex(constraintIndex, $event.target.value, valueIndex)"/> + </div> + + <ng-container *ngFor="let validation of validationMessages.constraint"> + <div class="input-error" *ngIf="constraintValuesArray(constraintIndex).controls[valueIndex].hasError(validation.type);"> + {{ validation.message }} + </div> + </ng-container> + + <div class="w-sdc-form-column"> + <span class="sprite-new delete-btn" [ngClass]="{'disabled': isViewOnly}" (click)="removeFromList(constraintIndex, valueIndex)"></span> + </div> + </div> + </div> + + <div *ngIf="constraint.get('type').value != 'inRange' && constraint.get('type').value != 'validValues'"> + <input type="text" class="i-sdc-form-input myClass required" required + formControlName="value" + [value]="constraintsArray.at(constraintIndex).get('value').value" + (input)="onChangeConstraintValue(constraintIndex, $event.target.value)"/> - <!-- all other ConstraintTypes--> - <div *ngIf="constraint.type != 'inRange' && constraint.type != 'validValues' && constraint.type != 'equal'"> - <input type="text" class="i-sdc-form-input myClass" - [disabled]="isViewOnly" - (input)="onChangeConstraintValue(constraintIndex, $event.target.value)" - [value]="constraint.value"/> + <div class="validation-errors"> + <ng-container *ngFor="let validation of validationMessages.constraint"> + <div class="input-error" *ngIf="constraintsArray.at(constraintIndex).get('value').hasError(validation.type);"> + {{ validation.message }} + </div> + </ng-container> + </div> + </div> </div> - </div> - <div class="w-sdc-form-column-vsmall"> - <span class="sprite-new delete-btn" [ngClass]="{'disabled': isViewOnly}" (click)="removeConstraint(constraintIndex)"></span> + <div class="w-sdc-form-column-vsmall" *ngIf="!isViewOnly"> + <span class="sprite-new delete-btn" [ngClass]="{'disabled': isViewOnly}" (click)="removeConstraint(constraintIndex)"></span> + </div> </div> </div> + </div> </div> <div class="w-sdc-form-columns-wrapper-small" *ngIf="!isViewOnly"> diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.spec.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.spec.ts index bfee76910e..06112e5830 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.spec.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.spec.ts @@ -19,6 +19,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { ConstraintsComponent } from './constraints.component'; describe('ConstraintsComponent', () => { @@ -27,7 +28,8 @@ describe('ConstraintsComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ ConstraintsComponent ] + declarations: [ ConstraintsComponent ], + imports: [FormsModule, ReactiveFormsModule] }) .compileComponents(); })); diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.ts index 2fb8b64e54..31dbeadd4e 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.component.ts @@ -18,7 +18,15 @@ */ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { PROPERTY_DATA, PROPERTY_TYPES } from "app/utils/constants" +import { + AbstractControl, FormArray, + FormBuilder, + FormControl, + FormGroup, ValidationErrors, + ValidatorFn, + Validators +} from '@angular/forms'; +import { PROPERTY_DATA, PROPERTY_TYPES } from 'app/utils/constants'; @Component({ selector: 'app-constraints', @@ -32,88 +40,358 @@ export class ConstraintsComponent implements OnInit { @Input() isViewOnly: boolean = false; @Output() onConstraintChange: EventEmitter<any> = new EventEmitter<any>(); - constraints: Constraint[] = new Array(); constraintTypes: string[]; ConstraintTypesMapping = ConstraintTypesMapping; - valid: boolean = true; + valid: boolean = false; + constraintForm: FormGroup; + validationMessages; + init: boolean = true; + + constructor(private formBuilder: FormBuilder) {} + + get constraintsArray() { + return this.constraintForm.get('constraint') as FormArray; + } + + get constraintValidators(): ValidatorFn { + switch (this.propertyType) { + case PROPERTY_TYPES.INTEGER: + console.warn('Add int validator'); + return Validators.compose([ + Validators.required, + intValidator() + ]); + case PROPERTY_TYPES.FLOAT: + console.warn('Add float validator'); + return Validators.compose([ + Validators.required, + floatValidator() + ]); + default: + console.warn('Only required validator'); + return Validators.compose([ + Validators.required + ]); + } +} + + public constraintValuesArray(index: number): FormArray { + return this.constraintsArray.at(index).get('value') as FormArray; + } ngOnInit() { - this.constraintTypes = Object.keys(ConstraintTypes).map(key => ConstraintTypes[key]); + console.groupEnd(); + this.constraintTypes = Object.keys(ConstraintTypes).map((key) => ConstraintTypes[key]); + + // This is only used by the spec test + if (!this.constraintForm) { + this.constraintForm = this.formBuilder.group({ + constraint: this.formBuilder.array([]) + }); + } + + this.validationMessages = { + constraint: [ + { type: 'required', message: 'Constraint value is required'}, + { type: 'invalidInt', message: 'Constraint value is not a valid integer'}, + { type: 'invalidFloat', message: 'Constraint value is not a valid floating point value'} + ], + type : [ + { type: 'required', message: 'Constraint type is required'} + ] + }; + + this.init = false; } ngOnChanges(changes): void { + console.groupEnd(); + + // Changes fires before init so form has to be initialised here + if (this.init) { + this.constraintForm = this.formBuilder.group({ + constraint: this.formBuilder.array([]) + }); + + if (changes.propertyConstraints && changes.propertyConstraints.currentValue) { + changes.propertyConstraints.currentValue.forEach((constraint: any) => { + const prop = this.getConstraintFromPropertyBEModel(constraint); + console.log('constraint from BE model', prop); + this.constraintsArray.push(prop); + }); + } + } + if (changes.propertyType) { + if (!this.init) { + // Reset constraints on property type change + console.warn('Property type changed. Resetting constraints'); + this.constraintForm = this.formBuilder.group({ + constraint: this.formBuilder.array([]) + }); + } + if (!this.propertyType || changes.propertyType.currentValue == this.propertyType) { this.propertyType = changes.propertyType.currentValue; } else { - this.constraints = new Array(); this.propertyType = changes.propertyType; this.emitOnConstraintChange(); } + + this.constraintsArray.controls.forEach((control: AbstractControl) => { + control.get('value').setValidators(this.constraintValidators); + }); } - this.constraints = new Array(); - if(changes.propertyConstraints) { - if (changes.propertyConstraints.currentValue) { - changes.propertyConstraints.currentValue.forEach((constraint: any) => { - this.constraints.push(this.getConstraintFromPropertyBEModel(constraint)); - }); - } + + console.log('constraints', this.constraintsArray); + } + + removeFromList(constraintIndex: number, valueIndex: number) { + this.constraintsArray.at(constraintIndex).get('value').value.splice(valueIndex, 1); + this.emitOnConstraintChange(); + } + + addToList(constraintIndex: number) { + const newConstraint = new FormControl('', this.constraintValidators); + + this.constraintValuesArray(constraintIndex).push(newConstraint); + console.log('constraintsArray', this.constraintsArray); + console.log('constraintValuesArray', this.constraintValuesArray(constraintIndex)); + this.emitOnConstraintChange(); + } + + onChangeConstraintType(constraintIndex: number, newType: ConstraintTypes) { + if ((newType == ConstraintTypes.valid_values)) { + const newConstraint = this.formBuilder.group({ + type: new FormControl({ + value: newType, + disabled: this.isViewOnly + }, Validators.required), + value: this.formBuilder.array([])}); + + this.constraintsArray.removeAt(constraintIndex); + this.constraintsArray.push(newConstraint); + } else if (newType == ConstraintTypes.in_range) { + const newConstraint = this.formBuilder.group({ + type: new FormControl({ + value: newType, + disabled: this.isViewOnly + }, Validators.required), + value: this.formBuilder.array([])}); + + const valRef = newConstraint.get('value') as FormArray; + valRef.push(new FormControl('', this.constraintValidators)); + valRef.push(new FormControl('', this.constraintValidators)); + + this.constraintsArray.removeAt(constraintIndex); + this.constraintsArray.push(newConstraint); + } else { + this.constraintsArray.at(constraintIndex).value.type = newType; } + this.emitOnConstraintChange(); + } + + onChangeConstraintValue(constraintIndex: number, newValue: any) { + this.constraintsArray.at(constraintIndex).get('value').setValue(newValue); + this.emitOnConstraintChange(); + } + + onChangeConstrainValueIndex(constraintIndex: number, newValue: any, valueIndex: number) { + this.constraintValuesArray(constraintIndex).controls[valueIndex].setValue(newValue); + this.emitOnConstraintChange(); } - private getConstraintFromPropertyBEModel(constraint: any):Constraint { + removeConstraint(constraintIndex: number) { + this.constraintsArray.removeAt(constraintIndex); + this.emitOnConstraintChange(); +} + + addConstraint() { + const newConstraint = this.formBuilder.group({ + type: new FormControl({ + value: ConstraintTypes.null, + disabled: this.isViewOnly + }, Validators.required), + value: new FormControl({ + value: '', + disabled: this.isViewOnly + }, this.constraintValidators) + }); + this.constraintsArray.push(newConstraint); + this.valid = false; + this.emitOnConstraintChange(); + } + + getInRangeValue(constraintIndex: number, valueIndex: number): string { + const value = this.constraintsArray.at(constraintIndex).get('value').value; + + if (!value || !value[valueIndex]) { + return ''; + } + + return value[valueIndex]; + } + + disableConstraint(optionConstraintType: ConstraintTypes): boolean { + const invalid = this.notAllowedConstraint(optionConstraintType); + return invalid ? invalid : this.getConstraintTypeIfPresent(optionConstraintType) ? true : false; + } + + notAllowedConstraint(optionConstraintType: ConstraintTypes): boolean { + switch (optionConstraintType) { + case ConstraintTypes.less_or_equal: + case ConstraintTypes.less_than: + case ConstraintTypes.greater_or_equal: + case ConstraintTypes.greater_than: + case ConstraintTypes.in_range: + if (this.isComparable(this.propertyType)) { + return false; + } + break; + case ConstraintTypes.length: + case ConstraintTypes.max_length: + case ConstraintTypes.min_length: + if (this.propertyType == PROPERTY_TYPES.STRING || this.propertyType == PROPERTY_TYPES.MAP || this.propertyType == PROPERTY_TYPES.LIST) { + return false; + } + break; + case ConstraintTypes.pattern: + if (this.propertyType == PROPERTY_TYPES.STRING) { + return false; + } + break; + case ConstraintTypes.valid_values: + case ConstraintTypes.equal: + return false; + } + return true; + } + + getConstraintTypeIfPresent(constraintType: ConstraintTypes): AbstractControl { + return this.constraintsArray.controls.find((control: AbstractControl) => { + const type = control.get('type').value; + return type == constraintType; + }); + } + + trackByFn(index) { + return index; + } + + isComparable(propType: string): boolean { + if (PROPERTY_DATA.COMPARABLE_TYPES.indexOf(propType) >= 0) { + return true; + } + return false; + } + + private getConstraintFromPropertyBEModel(constraint: any): AbstractControl { + console.log('be model constraints', constraint); let constraintType: ConstraintTypes; let constraintValue: any; if (!constraint) { constraintType = ConstraintTypes.null; - constraintValue = ""; - } else if(constraint.hasOwnProperty(ConstraintTypes.valid_values)){ + constraintValue = ''; + } else if (constraint.hasOwnProperty(ConstraintTypes.valid_values)) { constraintType = ConstraintTypes.valid_values; - constraintValue = constraint.validValues; - } else if(constraint.hasOwnProperty(ConstraintTypes.equal)) { + } else if (constraint.hasOwnProperty(ConstraintTypes.equal)) { constraintType = ConstraintTypes.equal; constraintValue = constraint.equal; - } else if(constraint.hasOwnProperty(ConstraintTypes.greater_than)) { + } else if (constraint.hasOwnProperty(ConstraintTypes.greater_than)) { constraintType = ConstraintTypes.greater_than; constraintValue = constraint.greaterThan; - } else if(constraint.hasOwnProperty(ConstraintTypes.greater_or_equal)) { + } else if (constraint.hasOwnProperty(ConstraintTypes.greater_or_equal)) { constraintType = ConstraintTypes.greater_or_equal; constraintValue = constraint.greaterOrEqual; - } else if(constraint.hasOwnProperty(ConstraintTypes.less_than)) { + } else if (constraint.hasOwnProperty(ConstraintTypes.less_than)) { constraintType = ConstraintTypes.less_than; constraintValue = constraint.lessThan; - } else if(constraint.hasOwnProperty(ConstraintTypes.less_or_equal)) { + } else if (constraint.hasOwnProperty(ConstraintTypes.less_or_equal)) { constraintType = ConstraintTypes.less_or_equal; constraintValue = constraint.lessOrEqual; - } else if(constraint.hasOwnProperty(ConstraintTypes.in_range)) { + } else if (constraint.hasOwnProperty(ConstraintTypes.in_range)) { constraintType = ConstraintTypes.in_range; constraintValue = new Array(constraint.inRange[0], constraint.inRange[1]); - } else if(constraint.rangeMaxValue || constraint.rangeMinValue) { + } else if (constraint.rangeMaxValue || constraint.rangeMinValue) { constraintType = ConstraintTypes.in_range; constraintValue = new Array(constraint.rangeMinValue, constraint.rangeMaxValue); - } else if(constraint.hasOwnProperty(ConstraintTypes.length)) { + } else if (constraint.hasOwnProperty(ConstraintTypes.length)) { constraintType = ConstraintTypes.length; constraintValue = constraint.length; - } else if(constraint.hasOwnProperty(ConstraintTypes.min_length)) { + } else if (constraint.hasOwnProperty(ConstraintTypes.min_length)) { constraintType = ConstraintTypes.min_length; constraintValue = constraint.minLength; - } else if(constraint.hasOwnProperty(ConstraintTypes.max_length)) { + } else if (constraint.hasOwnProperty(ConstraintTypes.max_length)) { constraintType = ConstraintTypes.max_length; constraintValue = constraint.maxLength; - } else if(constraint.hasOwnProperty(ConstraintTypes.pattern)) { + } else if (constraint.hasOwnProperty(ConstraintTypes.pattern)) { constraintType = ConstraintTypes.pattern; constraintValue = constraint.pattern; } - return { - type:constraintType, - value:constraintValue + + if (!constraint.hasOwnProperty(ConstraintTypes.valid_values) && !constraint.hasOwnProperty(ConstraintTypes.in_range)) { + return this.formBuilder.group({ + type: new FormControl({ + value: constraintType, + disabled: this.isViewOnly + }, Validators.required), + value: new FormControl({ + value: constraintValue, + disabled: this.isViewOnly + }, this.constraintValidators) + }); + } else { + const newForm = this.formBuilder.group({ + type: new FormControl({ + value: constraintType, + disabled: this.isViewOnly + }, Validators.required), + value: this.formBuilder.array([]) + }); + + const valRef = newForm.get('value') as FormArray; + + if (constraint.hasOwnProperty(ConstraintTypes.valid_values)) { + constraint.validValues.forEach((val) => { + valRef.push(new FormControl(val, this.constraintValidators)); + }); + } else { + constraint.inRange.forEach((val) => { + valRef.push(new FormControl(val, this.constraintValidators)); + }); + } + + console.log('new form', newForm); + return newForm; } } private getConstraintsFormat(): any[] { - let constraintArray = new Array(); - this.constraints.forEach((constraint: Constraint) => { - constraintArray.push(this.getConstraintFormat(constraint)) + const constraintArray = new Array(); + this.constraintsArray.controls.forEach((control: AbstractControl) => { + const type = control.get('type').value; + let constraint: Constraint; + + if (type != ConstraintTypes.valid_values && type != ConstraintTypes.in_range) { + constraint = { + type, + value: control.get('value').value + }; + } else { + const valArray = []; + + control.get('value').value.forEach((val) => { + valArray.push(val); + }); + + constraint = { + type, + value: valArray + }; + } + + console.log('New constraint object', constraint); + constraintArray.push(this.getConstraintFormat(constraint)); }); return constraintArray; } @@ -123,224 +401,153 @@ export class ConstraintsComponent implements OnInit { case ConstraintTypes.equal: return { [ConstraintTypes.equal]: constraint.value - } + }; case ConstraintTypes.less_or_equal: return { [ConstraintTypes.less_or_equal]: constraint.value - } + }; case ConstraintTypes.less_than: return { [ConstraintTypes.less_than]: constraint.value - } + }; case ConstraintTypes.greater_or_equal: return { [ConstraintTypes.greater_or_equal]: constraint.value - } + }; case ConstraintTypes.greater_than: return { [ConstraintTypes.greater_than]: constraint.value - } + }; case ConstraintTypes.in_range: return { [ConstraintTypes.in_range]: constraint.value - } + }; case ConstraintTypes.length: return { [ConstraintTypes.length]: constraint.value - } + }; case ConstraintTypes.max_length: return { [ConstraintTypes.max_length]: constraint.value - } + }; case ConstraintTypes.min_length: return { [ConstraintTypes.min_length]: constraint.value - } + }; case ConstraintTypes.pattern: return { [ConstraintTypes.pattern]: constraint.value - } + }; case ConstraintTypes.valid_values: return { [ConstraintTypes.valid_values]: constraint.value - } + }; default: return; } } private validateConstraints(): void { - this.valid = this.constraints.every((constraint: Constraint) => { - if (Array.isArray(constraint.value)) { - return !(constraint.value.length == 0 || this.doesArrayContaintEmptyValues(constraint.value)); + this.valid = this.constraintsArray.controls.every((control: AbstractControl) => { + const value = control.get('value').value; + const type = control.get('type').value; + control.updateValueAndValidity(); + + if (Array.isArray(value)) { + return !(value.length == 0 || this.doesArrayContaintEmptyValues(value)); } - if (constraint.type == ConstraintTypes.pattern) { + if (type == ConstraintTypes.pattern) { try { - new RegExp(constraint.value); + new RegExp(value); this.valid = true; - } catch(e) { + } catch (e) { this.valid = false; } + } else { + this.valid = this.constraintForm.valid; } - return constraint.value && constraint.type != ConstraintTypes.null + + return value && type != ConstraintTypes.null; }); } private doesArrayContaintEmptyValues(arr) { - for(const element of arr) { - if(element === "") return true; + for (const element of arr) { + if (element === '') { return true; } } return false; } private emitOnConstraintChange(): void { + console.log('constraints', this.constraintsArray); + this.validateConstraints(); const newConstraints = this.getConstraintsFormat(); + + this.valid = this.constraintForm.valid; + console.log('emitOnConstraintChange.valid', this.valid); + this.onConstraintChange.emit({ constraints: newConstraints, valid: this.valid }); } - removeFromList(constraintIndex: number, valueIndex: number){ - this.constraints[constraintIndex].value.splice(valueIndex, 1); - this.emitOnConstraintChange() - } - - addToList(constraintIndex: number){ - if (!this.constraints[constraintIndex].value) { - this.constraints[constraintIndex].value = new Array(); - } - this.constraints[constraintIndex].value.push(""); - this.emitOnConstraintChange() - } - - onChangeConstraintType(constraintIndex: number, newType: ConstraintTypes) { - this.constraints[constraintIndex].type = newType; - if ((newType == ConstraintTypes.in_range || newType == ConstraintTypes.valid_values) && !Array.isArray(this.constraints[constraintIndex].value)) { - this.constraints[constraintIndex].value = new Array() - } - this.emitOnConstraintChange(); - } - - onChangeConstraintValue(constraintIndex: number, newValue: any) { - this.constraints[constraintIndex].value = newValue; - this.emitOnConstraintChange(); - } - - onChangeConstrainValueIndex(constraintIndex: number, newValue: any, valueIndex: number) { - if(!this.constraints[constraintIndex].value) { - this.constraints[constraintIndex].value = new Array(); - } - this.constraints[constraintIndex].value[valueIndex] = newValue; - this.emitOnConstraintChange(); - } - - removeConstraint(constraintIndex: number) { - this.constraints.splice(constraintIndex, 1); - this.emitOnConstraintChange(); } - addConstraint() { - let newConstraint: Constraint = { - type: ConstraintTypes.null, - value: "" - } - this.constraints.push(newConstraint); - this.emitOnConstraintChange(); - } - - getInRangeValue(constraintIndex: number, valueIndex: number): string { - if(!this.constraints[constraintIndex].value || !this.constraints[constraintIndex].value[valueIndex]) { - return ""; - } - return this.constraints[constraintIndex].value[valueIndex]; - } - - disableConstraint(optionConstraintType: ConstraintTypes): boolean { - const invalid = this.notAllowedConstraint(optionConstraintType); - return invalid ? invalid : this.getConstraintTypeIfPresent(optionConstraintType) ? true : false; - } - - notAllowedConstraint(optionConstraintType: ConstraintTypes): boolean { - switch (optionConstraintType) { - case ConstraintTypes.less_or_equal: - case ConstraintTypes.less_than: - case ConstraintTypes.greater_or_equal: - case ConstraintTypes.greater_than: - case ConstraintTypes.in_range: - if (this.isComparable(this.propertyType)){ - return false; - } - break; - case ConstraintTypes.length: - case ConstraintTypes.max_length: - case ConstraintTypes.min_length: - if (this.propertyType == PROPERTY_TYPES.STRING || this.propertyType == PROPERTY_TYPES.MAP || this.propertyType == PROPERTY_TYPES.LIST){ - return false; - } - break; - case ConstraintTypes.pattern: - if (this.propertyType == PROPERTY_TYPES.STRING){ - return false; - } - break; - case ConstraintTypes.valid_values: - case ConstraintTypes.equal: - return false; - } - return true; - } +export enum ConstraintTypes { + null = '', + equal= 'equal', + greater_than = 'greaterThan', + greater_or_equal = 'greaterOrEqual', + less_than = 'lessThan', + less_or_equal = 'lessOrEqual', + in_range = 'inRange', + valid_values = 'validValues', + length = 'length', + min_length = 'minLength', + max_length = 'maxLength', + pattern = 'pattern' +} - getConstraintTypeIfPresent(constraintType: ConstraintTypes): Constraint { - return this.constraints.find((constraint) => { - return constraint.type == constraintType ? true : false; - }) - } +export const ConstraintTypesMapping = { + [ConstraintTypes.equal]: 'equal', + [ConstraintTypes.greater_than]: 'greater_than', + [ConstraintTypes.greater_or_equal]: 'greater_or_equal', + [ConstraintTypes.less_than]: 'less_than', + [ConstraintTypes.less_or_equal]: 'less_or_equal', + [ConstraintTypes.in_range]: 'in_range', + [ConstraintTypes.valid_values]: 'valid_values', + [ConstraintTypes.length]: 'length', + [ConstraintTypes.min_length]: 'min_length', + [ConstraintTypes.max_length]: 'max_length', + [ConstraintTypes.pattern]: 'pattern' +}; - trackByFn(index) { - return index; - } +export interface Constraint { + type: ConstraintTypes; + value: any; +} - isComparable(propType: string): boolean { - if (PROPERTY_DATA.COMPARABLE_TYPES.indexOf(propType) >= 0) { - return true; +export function intValidator(): ValidatorFn { + const intRegex = /^[-+]?\d+$/; + return (control: AbstractControl): ValidationErrors | null => { + if (control.value && !intRegex.test(control.value)) { + return {invalidInt: true}; } - return false; - } + return null; + }; } -export enum ConstraintTypes { - null = "", - equal= "equal", - greater_than = "greaterThan", - greater_or_equal = "greaterOrEqual", - less_than = "lessThan", - less_or_equal = "lessOrEqual", - in_range = "inRange", - valid_values = "validValues", - length = "length", - min_length = "minLength", - max_length = "maxLength", - pattern = "pattern" -} +export function floatValidator(): ValidatorFn { + const floatRegex = /^[-+]?\d+(\.\d+)?$/; -export const ConstraintTypesMapping = { - [ConstraintTypes.equal]: "equal", - [ConstraintTypes.greater_than]: "greater_than", - [ConstraintTypes.greater_or_equal]: "greater_or_equal", - [ConstraintTypes.less_than]: "less_than", - [ConstraintTypes.less_or_equal]: "less_or_equal", - [ConstraintTypes.in_range]: "in_range", - [ConstraintTypes.valid_values]: "valid_values", - [ConstraintTypes.length]: "length", - [ConstraintTypes.min_length]: "min_length", - [ConstraintTypes.max_length]: "max_length", - [ConstraintTypes.pattern]: "pattern" -}; + return (control: AbstractControl): ValidationErrors | null => { + if (control.value && !floatRegex.test(control.value)) { + return {invalidFloat: true}; + } -export interface Constraint { - type:ConstraintTypes, - value:any + return null; + }; } diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.module.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.module.ts index 4f14e1f855..48ad24e112 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.module.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/constraints/constraints.module.ts @@ -19,13 +19,14 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ConstraintsComponent } from './constraints.component'; -import { FormsModule } from '@angular/forms'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; @NgModule({ - imports: [ - CommonModule, - FormsModule - ], + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule + ], declarations: [ConstraintsComponent], exports: [ConstraintsComponent], entryComponents: [ diff --git a/catalog-ui/src/app/view-models/forms/property-forms/base-property-form/property-form-base.less b/catalog-ui/src/app/view-models/forms/property-forms/base-property-form/property-form-base.less index 1c1c0c9c52..fabf883151 100644 --- a/catalog-ui/src/app/view-models/forms/property-forms/base-property-form/property-form-base.less +++ b/catalog-ui/src/app/view-models/forms/property-forms/base-property-form/property-form-base.less @@ -6,7 +6,6 @@ } form{ - width: 813px; [name="description"]{ min-height:50px; } diff --git a/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts b/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts index 05045c1529..52e8c0018a 100644 --- a/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts +++ b/catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts @@ -507,6 +507,8 @@ export class PropertyFormViewModel { } this.$scope.onConstraintChange = (constraints: any): void => { + console.log('$scope.onConstraintChange', constraints); + if (!this.$scope.invalidMandatoryFields) { this.$scope.footerButtons[0].disabled = !constraints.valid; } else { diff --git a/catalog-ui/src/app/view-models/forms/property-forms/select-datatype-modal/select-datatype-modal.less b/catalog-ui/src/app/view-models/forms/property-forms/select-datatype-modal/select-datatype-modal.less index 02b7612671..1eb7a4649f 100644 --- a/catalog-ui/src/app/view-models/forms/property-forms/select-datatype-modal/select-datatype-modal.less +++ b/catalog-ui/src/app/view-models/forms/property-forms/select-datatype-modal/select-datatype-modal.less @@ -6,7 +6,6 @@ } form{ - width: 813px; [name="description"]{ min-height:50px; } |