88ff8deec6fc762c0ddb4ed68f86412b109a26ad
[sdc.git] / catalog-ui / src / app / ng2 / pages / composition / interface-operatons / operation-creator / input-list / input-list-item / input-list-item.component.ts
1 /*
2  * -
3  *  ============LICENSE_START=======================================================
4  *  Copyright (C) 2022 Nordix Foundation.
5  *  ================================================================================
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  *  SPDX-License-Identifier: Apache-2.0
19  *  ============LICENSE_END=========================================================
20  */
21
22 import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
23 import {DataTypeModel} from '../../../../../../../models/data-types';
24 import {SchemaPropertyGroupModel} from '../../../../../../../models/schema-property';
25 import {DerivedPropertyType, PropertyBEModel} from '../../../../../../../models/properties-inputs/property-be-model';
26 import {PROPERTY_DATA, PROPERTY_TYPES} from '../../../../../../../utils/constants';
27 import {ToscaFunction} from '../../../../../../../models/tosca-function';
28 import {ToscaFunctionValidationEvent} from "../../../../../../../ng2/pages/properties-assignment/tosca-function/tosca-function.component";
29 import {InstanceFeDetails} from "../../../../../../../models/instance-fe-details";
30
31 @Component({
32   selector: 'app-input-list-item',
33   templateUrl: './input-list-item.component.html',
34   styleUrls: ['./input-list-item.component.less']
35 })
36 export class InputListItemComponent implements OnInit {
37
38   @Input() valueObjRef: any;
39   @Input() name: string;
40   @Input() dataTypeMap: Map<string, DataTypeModel>;
41   @Input() type: DataTypeModel;
42   @Input() schema: SchemaPropertyGroupModel;
43   @Input() nestingLevel: number;
44   @Input() isListChild: boolean = false;
45   @Input() isMapChild: boolean = false;
46   @Input() showToscaFunctionOption: boolean = false;
47   @Input() listIndex: number;
48   @Input() isViewOnly: boolean;
49   @Input() allowDeletion: boolean = false;
50   @Input() toscaFunction: ToscaFunction;
51   @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map();
52   @Output('onValueChange') onValueChangeEvent: EventEmitter<any> = new EventEmitter<any>();
53   @Output('onDelete') onDeleteEvent: EventEmitter<string> = new EventEmitter<string>();
54   @Output('onChildListItemDelete') onChildListItemDeleteEvent: EventEmitter<number> = new EventEmitter<number>();
55
56   isExpanded: boolean = false;
57   mapEntryName: string;
58   isToscaFunction: boolean = false;
59   property: PropertyBEModel;
60
61   ngOnInit() {
62     if (!this.nestingLevel) {
63       this.nestingLevel = 0;
64     }
65     if (this.type.properties) {
66       this.type.properties.forEach(property => {
67         this.initEmptyPropertyInValueObjRef(property);
68       });
69     }
70
71     this.property = new PropertyBEModel();
72     this.property.type = this.type.name;
73     if (this.schema) {
74       this.property.schema = this.schema;
75       this.property.schemaType = this.schema.property.type;
76     }
77     if (this.toscaFunction) {
78       this.property.toscaFunction = this.toscaFunction;
79       this.valueObjRef = this.toscaFunction.value;
80       this.isToscaFunction = true;
81     }
82   }
83
84   private initEmptyPropertyInValueObjRef(property: PropertyBEModel) {
85     if (this.valueObjRef[property.name] == undefined) {
86       if (this.isTypeComplex(property.type) || this.isTypeMap(property.type)) {
87         this.valueObjRef[property.name] = {};
88       } else if (this.isTypeList(property.type) || this.isTypeRange(property.type)) {
89         this.valueObjRef[property.name] = [];
90       } else {
91         this.valueObjRef[property.name] = null;
92       }
93     }
94   }
95
96   getType(typeName: string): DerivedPropertyType {
97     if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(typeName) > -1) {
98       return DerivedPropertyType.SIMPLE;
99     } else if (typeName === PROPERTY_TYPES.LIST) {
100       return DerivedPropertyType.LIST;
101     } else if (typeName === PROPERTY_TYPES.MAP) {
102       return DerivedPropertyType.MAP;
103     } else if (typeName === PROPERTY_TYPES.RANGE) {
104       return DerivedPropertyType.RANGE;
105     } else {
106       return DerivedPropertyType.COMPLEX;
107     }
108   }
109
110   isTypeWithoutProperties(typeName: string): boolean {
111       if (this.dataTypeMap.get(typeName) === undefined) {
112           return true;
113       }
114       return this.dataTypeMap.get(typeName).properties === undefined ||
115           this.dataTypeMap.get(typeName).properties.length == 0;
116   }
117
118   isTypeDerivedFromSimple(typeName: string): boolean {
119     if (typeName === undefined) {
120       return false;
121     }
122     if (this.dataTypeMap.get(typeName) !== undefined) {
123       if (this.isTypeRange(typeName)) {
124         return false;
125       }
126       if (this.dataTypeMap.get(typeName).derivedFromName == PROPERTY_DATA.ROOT_DATA_TYPE) {
127         return false;
128       } else if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.dataTypeMap.get(typeName).derivedFromName) > -1) {
129         return true;
130       } else {
131         return this.isTypeDerivedFromSimple(this.dataTypeMap.get(typeName).derivedFromName);
132       }
133     }
134     return true;
135   }
136
137   isTypeSimple(typeName: string): boolean {
138     if (this.getType(typeName) == DerivedPropertyType.SIMPLE) {
139       return true;
140     }
141     return this.isTypeDerivedFromSimple(typeName) && (this.isTypeWithoutProperties(typeName));
142   }
143
144   isTypeRange(typeName: string): boolean {
145     return this.getType(typeName) == DerivedPropertyType.RANGE;
146   }
147
148   isTypeList(typeName: string): boolean {
149     return this.getType(typeName) == DerivedPropertyType.LIST;
150   }
151
152   isTypeMap(typeName: string): boolean {
153     return this.getType(typeName) == DerivedPropertyType.MAP;
154   }
155
156   isTypeComplex(typeName: string): boolean {
157     return !this.isTypeSimple(typeName) && !this.isTypeList(typeName) && !this.isTypeMap(typeName) && !this.isTypeRange(typeName);
158   }
159
160   expandAndCollapse() {
161     this.isExpanded = !this.isExpanded;
162   }
163
164   getDataType(type: string) {
165     return this.dataTypeMap.get(type);
166   }
167
168   onValueTypeChange () {
169     if ( !this.isToscaFunction ) {
170       this.onValueChange(this.valueObjRef);
171     }
172   }
173
174   onToscaFunctionValidityChange(validationEvent: ToscaFunctionValidationEvent):void {
175     if (validationEvent.isValid) {
176       this.emitValueChangeEvent(validationEvent.toscaFunction, true);
177       return;
178     }
179     this.emitValueChangeEvent(undefined, true);
180   }
181
182   onValueChange(value: any): void {
183     if (this.isNumber(this.type.name)) {
184       this.emitValueChangeEvent(this.parseNumber(value));
185       return;
186     }
187     if (this.type.name == PROPERTY_TYPES.BOOLEAN) {
188       this.emitValueChangeEvent(this.parseBoolean(value));
189       return;
190     }
191     this.emitValueChangeEvent(value);
192   }
193
194   onListValueChange(): void {
195     this.emitValueChangeEvent(this.valueObjRef);
196   }
197
198   onPropertyValueChange($event: any) {
199     this.valueObjRef[$event.name] = $event.value;
200     this.emitValueChangeEvent(this.valueObjRef);
201   }
202
203   private emitValueChangeEvent(value: any, isToscaFunction=false) {
204     let emitValue = {
205       name: this.name,
206       value: value,
207       isToscaFunction:isToscaFunction
208     };
209     this.onValueChangeEvent.emit(emitValue);
210   }
211
212   isRoot(): boolean {
213     return this.nestingLevel === 0;
214   }
215
216   showListItemDelete(): boolean {
217     return !this.isViewOnly && (this.isListChild && this.nestingLevel > 0);
218   }
219
220   showInputDelete(): boolean {
221     return this.allowDeletion && !this.isViewOnly && (this.isRoot() || this.isMapChild);
222   }
223
224   resolveType(): string {
225     if (this.isTypeList(this.type.name)) {
226       return `list of value type ${this.schema.property.type}`
227     }
228     if (this.isTypeMap(this.type.name)) {
229       return `map of 'string' keys and '${this.schema.property.type}' values`
230     }
231     return this.type.name;
232   }
233
234   onInputDelete() {
235     this.onDeleteEvent.emit(this.name);
236   }
237
238   onListItemDelete(index: number): void {
239     this.valueObjRef.splice(index, 1);
240     this.emitValueChangeEvent(this.valueObjRef);
241   }
242
243   addListElement() {
244     if (!this.valueObjRef) {
245       this.valueObjRef = [];
246     }
247     if (this.isTypeSimple(this.schema.property.type)) {
248       this.valueObjRef.push('');
249     } else if (this.isTypeComplex(this.schema.property.type) || this.isTypeMap(this.schema.property.type)) {
250       this.valueObjRef.push({});
251     } else if (this.isTypeList(this.schema.property.type)) {
252       this.valueObjRef.push([]);
253     }
254   }
255
256   trackByIndex(index: number, value: string): number {
257     return index;
258   }
259
260   onChildListItemDelete() {
261     this.onChildListItemDeleteEvent.emit(this.listIndex);
262   }
263
264   getObjectEntries(valueObjRef: object) {
265     return Object.keys(valueObjRef);
266   }
267
268   onMapValueChange() {
269     this.emitValueChangeEvent(this.valueObjRef);
270   }
271
272   onMapKeyDelete(key: string) {
273     delete this.valueObjRef[key]
274     this.emitValueChangeEvent(this.valueObjRef);
275   }
276
277   addMapEntry() {
278     let newKey;
279     if (this.mapEntryName) {
280       newKey = this.mapEntryName.trim();
281     }
282     if (!newKey) {
283       return;
284     }
285     if (Object.keys(this.valueObjRef).indexOf(newKey) !== -1) {
286       return;
287     }
288     this.mapEntryName = '';
289     if (this.isTypeSimple(this.schema.property.type)) {
290       this.valueObjRef[newKey] = '';
291     } else if (this.isTypeComplex(this.schema.property.type) || this.isTypeMap(this.schema.property.type)) {
292       this.valueObjRef[newKey] = {};
293     } else if (this.isTypeList(this.schema.property.type)) {
294       this.valueObjRef[newKey] = [];
295     }
296     this.emitValueChangeEvent(this.valueObjRef);
297   }
298
299   getSimpleValueInputType() {
300     if (this.isNumber(this.type.name)){
301       return 'number';
302     }
303     return 'text';
304   }
305
306   isNumber(type: string): boolean {
307     return type === PROPERTY_TYPES.INTEGER || type === PROPERTY_TYPES.FLOAT;
308   }
309
310   private parseBoolean(value: any) {
311     if (value === 'true') {
312       return true;
313     }
314     if (value === 'false') {
315       return false;
316     }
317     return null;
318   }
319
320   private parseNumber(value: any) {
321     const number = parseInt(value);
322     return isNaN(number) ? null : number;
323   }
324
325 }