Constraints in data type view
[sdc.git] / catalog-ui / src / app / ng2 / pages / properties-assignment / constraints / constraints.component.ts
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2022 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19
20 import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
21 import { PROPERTY_DATA, PROPERTY_TYPES } from "app/utils/constants"
22
23 @Component({
24   selector: 'app-constraints',
25   templateUrl: './constraints.component.html',
26   styleUrls: ['./constraints.component.less']
27 })
28 export class ConstraintsComponent implements OnInit {
29
30   @Input() propertyConstraints: any[];
31   @Input() propertyType: string;
32   @Input() isViewOnly: boolean = false;
33   @Output() onConstraintChange: EventEmitter<any> = new EventEmitter<any>();
34
35   constraints: Constraint[] = new Array();
36   constraintTypes: string[];
37   ConstraintTypesMapping = ConstraintTypesMapping;
38   valid: boolean = true;
39
40   ngOnInit() {
41     this.constraintTypes = Object.keys(ConstraintTypes).map(key => ConstraintTypes[key]);
42   }
43
44   ngOnChanges(changes): void {
45     if (changes.propertyType) {
46       if (!this.propertyType || changes.propertyType.currentValue == this.propertyType) {
47         this.propertyType = changes.propertyType.currentValue;
48       } else {
49         this.constraints = new Array();
50         this.propertyType = changes.propertyType;
51         this.emitOnConstraintChange();
52       }
53     }
54     this.constraints = new Array();
55     if(changes.propertyConstraints) {
56       if (changes.propertyConstraints.currentValue) {
57         changes.propertyConstraints.currentValue.forEach((constraint: any) => {
58             this.constraints.push(this.getConstraintFromPropertyBEModel(constraint));
59         });
60       }
61     }
62   }
63
64   private getConstraintFromPropertyBEModel(constraint: any):Constraint {
65     let constraintType: ConstraintTypes;
66     let constraintValue: any;
67     if (!constraint) {
68       constraintType = ConstraintTypes.null;
69       constraintValue = "";
70     } else if(constraint.hasOwnProperty(ConstraintTypes.valid_values)){
71       constraintType = ConstraintTypes.valid_values;
72       constraintValue = constraint.validValues;
73     } else if(constraint.hasOwnProperty(ConstraintTypes.equal)) {
74       constraintType = ConstraintTypes.equal;
75       constraintValue = constraint.equal;
76     } else if(constraint.hasOwnProperty(ConstraintTypes.greater_than)) {
77       constraintType = ConstraintTypes.greater_than;
78       constraintValue = constraint.greaterThan;
79     } else if(constraint.hasOwnProperty(ConstraintTypes.greater_or_equal)) {
80       constraintType = ConstraintTypes.greater_or_equal;
81       constraintValue = constraint.greaterOrEqual;
82     } else if(constraint.hasOwnProperty(ConstraintTypes.less_than)) {
83       constraintType = ConstraintTypes.less_than;
84       constraintValue = constraint.lessThan;
85     } else if(constraint.hasOwnProperty(ConstraintTypes.less_or_equal)) {
86       constraintType = ConstraintTypes.less_or_equal;
87       constraintValue = constraint.lessOrEqual;
88     } else if(constraint.hasOwnProperty(ConstraintTypes.in_range)) {
89       constraintType = ConstraintTypes.in_range;
90       constraintValue = new Array(constraint.inRange[0], constraint.inRange[1]);
91     } else if(constraint.rangeMaxValue || constraint.rangeMinValue) {
92       constraintType = ConstraintTypes.in_range;
93       constraintValue = new Array(constraint.rangeMinValue, constraint.rangeMaxValue);
94     } else if(constraint.hasOwnProperty(ConstraintTypes.length)) {
95       constraintType = ConstraintTypes.length;
96       constraintValue = constraint.length;
97     } else if(constraint.hasOwnProperty(ConstraintTypes.min_length)) {
98       constraintType = ConstraintTypes.min_length;
99       constraintValue = constraint.minLength;
100     } else if(constraint.hasOwnProperty(ConstraintTypes.max_length)) {
101       constraintType = ConstraintTypes.max_length;
102       constraintValue = constraint.maxLength;
103     } else if(constraint.hasOwnProperty(ConstraintTypes.pattern)) {
104       constraintType = ConstraintTypes.pattern;
105       constraintValue = constraint.pattern;
106     }
107     return {
108       type:constraintType,
109       value:constraintValue
110     }
111   }
112
113   private getConstraintsFormat(): any[] {
114     let constraintArray = new Array();
115     this.constraints.forEach((constraint: Constraint) => {
116       constraintArray.push(this.getConstraintFormat(constraint))
117     });
118     return constraintArray;
119   }
120
121   private getConstraintFormat(constraint: Constraint): any {
122     switch (constraint.type) {
123       case ConstraintTypes.equal:
124         return {
125           [ConstraintTypes.equal]: constraint.value
126         }
127       case ConstraintTypes.less_or_equal:
128         return {
129           [ConstraintTypes.less_or_equal]: constraint.value
130         }
131       case ConstraintTypes.less_than:
132         return {
133           [ConstraintTypes.less_than]: constraint.value
134         }
135       case ConstraintTypes.greater_or_equal:
136         return {
137           [ConstraintTypes.greater_or_equal]: constraint.value
138         }
139       case ConstraintTypes.greater_than:
140         return {
141           [ConstraintTypes.greater_than]: constraint.value
142         }
143       case ConstraintTypes.in_range:
144         return {
145           [ConstraintTypes.in_range]: constraint.value
146         }
147       case ConstraintTypes.length:
148         return {
149           [ConstraintTypes.length]: constraint.value
150         }
151       case ConstraintTypes.max_length:
152         return {
153           [ConstraintTypes.max_length]: constraint.value
154         }
155       case ConstraintTypes.min_length:
156         return {
157           [ConstraintTypes.min_length]: constraint.value
158         }
159       case ConstraintTypes.pattern:
160         return {
161           [ConstraintTypes.pattern]: constraint.value
162         }
163       case ConstraintTypes.valid_values:
164         return {
165           [ConstraintTypes.valid_values]: constraint.value
166         }
167       default:
168         return;
169     }
170   }
171
172   private validateConstraints(): void {
173     this.valid = this.constraints.every((constraint: Constraint) => {
174       if (Array.isArray(constraint.value)) {
175         return !(constraint.value.length == 0 || this.doesArrayContaintEmptyValues(constraint.value));
176       }
177       if (constraint.type == ConstraintTypes.pattern) {
178         try {
179           new RegExp(constraint.value);
180           this.valid = true;
181         } catch(e) {
182           this.valid = false;
183         }
184       }
185       return constraint.value && constraint.type != ConstraintTypes.null
186     });
187   }
188
189   private doesArrayContaintEmptyValues(arr) {
190     for(const element of arr) {
191       if(element === "") return true;
192     }
193     return false;
194   }
195
196   private emitOnConstraintChange(): void {
197     this.validateConstraints();
198     const newConstraints = this.getConstraintsFormat();
199     this.onConstraintChange.emit({
200       constraints: newConstraints,
201       valid: this.valid
202     });
203   }
204
205   removeFromList(constraintIndex: number, valueIndex: number){
206     this.constraints[constraintIndex].value.splice(valueIndex, 1);
207     this.emitOnConstraintChange()
208   }
209
210   addToList(constraintIndex: number){
211     if (!this.constraints[constraintIndex].value) {
212       this.constraints[constraintIndex].value = new Array();
213     }
214     this.constraints[constraintIndex].value.push("");
215     this.emitOnConstraintChange()
216   }
217
218   onChangeConstraintType(constraintIndex: number, newType: ConstraintTypes) {
219     this.constraints[constraintIndex].type = newType;
220     if ((newType == ConstraintTypes.in_range || newType == ConstraintTypes.valid_values) && !Array.isArray(this.constraints[constraintIndex].value)) {
221       this.constraints[constraintIndex].value = new Array()
222     }
223     this.emitOnConstraintChange();
224   }
225
226   onChangeConstraintValue(constraintIndex: number, newValue: any) {
227     this.constraints[constraintIndex].value = newValue;
228     this.emitOnConstraintChange();
229   }
230
231   onChangeConstrainValueIndex(constraintIndex: number, newValue: any, valueIndex: number) {
232     if(!this.constraints[constraintIndex].value) {
233       this.constraints[constraintIndex].value = new Array();
234     }
235     this.constraints[constraintIndex].value[valueIndex] = newValue;
236     this.emitOnConstraintChange();
237   }
238
239   removeConstraint(constraintIndex: number) {
240     this.constraints.splice(constraintIndex, 1);
241     this.emitOnConstraintChange();
242 }
243
244   addConstraint() {
245     let newConstraint: Constraint = {
246       type: ConstraintTypes.null,
247       value: ""
248     }
249     this.constraints.push(newConstraint);
250     this.emitOnConstraintChange();
251   }
252
253   getInRangeValue(constraintIndex: number, valueIndex: number): string {
254     if(!this.constraints[constraintIndex].value || !this.constraints[constraintIndex].value[valueIndex]) {
255       return "";
256     }
257     return this.constraints[constraintIndex].value[valueIndex];
258   }
259
260   disableConstraint(optionConstraintType: ConstraintTypes): boolean {
261     const invalid = this.notAllowedConstraint(optionConstraintType);
262     return invalid ? invalid : this.getConstraintTypeIfPresent(optionConstraintType) ? true : false;
263   }
264
265   notAllowedConstraint(optionConstraintType: ConstraintTypes): boolean {
266     switch (optionConstraintType) {
267       case ConstraintTypes.less_or_equal:
268       case ConstraintTypes.less_than:
269       case ConstraintTypes.greater_or_equal:
270       case ConstraintTypes.greater_than:
271       case ConstraintTypes.in_range:
272         if (this.isComparable(this.propertyType)){
273           return false;
274         }
275         break;
276       case ConstraintTypes.length:
277       case ConstraintTypes.max_length:
278       case ConstraintTypes.min_length:
279         if (this.propertyType == PROPERTY_TYPES.STRING || this.propertyType == PROPERTY_TYPES.MAP || this.propertyType == PROPERTY_TYPES.LIST){
280           return false;
281         }
282         break;
283       case ConstraintTypes.pattern:
284         if (this.propertyType == PROPERTY_TYPES.STRING){
285           return false;
286         }
287         break;
288       case ConstraintTypes.valid_values:
289       case ConstraintTypes.equal:
290         return false;
291     }
292     return true;
293   }
294
295   getConstraintTypeIfPresent(constraintType: ConstraintTypes): Constraint {
296     return this.constraints.find((constraint) => {
297       return constraint.type == constraintType ? true : false;
298     })
299   }
300
301   trackByFn(index) {
302     return index;
303   }
304
305   isComparable(propType: string): boolean {
306     if (PROPERTY_DATA.COMPARABLE_TYPES.indexOf(propType) >= 0) {
307       return true;
308     }
309     return false;
310   }
311
312 }
313
314 export enum ConstraintTypes {
315   null = "",
316   equal= "equal",
317   greater_than = "greaterThan",
318   greater_or_equal = "greaterOrEqual",
319   less_than = "lessThan",
320   less_or_equal = "lessOrEqual",
321   in_range = "inRange",
322   valid_values = "validValues",
323   length = "length",
324   min_length = "minLength",
325   max_length = "maxLength",
326   pattern = "pattern"
327 }
328
329 export const ConstraintTypesMapping = {
330   [ConstraintTypes.equal]: "equal",
331   [ConstraintTypes.greater_than]: "greater_than",
332   [ConstraintTypes.greater_or_equal]: "greater_or_equal",
333   [ConstraintTypes.less_than]: "less_than",
334   [ConstraintTypes.less_or_equal]: "less_or_equal",
335   [ConstraintTypes.in_range]: "in_range",
336   [ConstraintTypes.valid_values]: "valid_values",
337   [ConstraintTypes.length]: "length",
338   [ConstraintTypes.min_length]: "min_length",
339   [ConstraintTypes.max_length]: "max_length",
340   [ConstraintTypes.pattern]: "pattern"
341 };
342
343 export interface Constraint {
344   type:ConstraintTypes,
345   value:any
346 }