UI support for default custom function names
[sdc.git] / catalog-ui / src / app / ng2 / pages / service-dependencies-editor / service-dependencies-editor.component.ts
1 /*!
2  * Copyright © 2016-2018 European Support Limited
3  * Modification 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  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14  * or implied. See the License for the specific language governing
15  * permissions and limitations under the License.
16  */
17 import {Component, Input, OnInit} from '@angular/core';
18 import {InputBEModel, PropertyBEModel, PropertyFEModel, PropertyModel} from 'app/models';
19 import {SourceType} from 'app/ng2/components/logic/service-dependencies/service-dependencies.component';
20 import {DropdownValue} from 'app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component';
21 import {ServiceServiceNg2} from 'app/ng2/services/component-services/service.service';
22 import {PROPERTY_DATA} from 'app/utils';
23 import {PropertiesUtils} from '../properties-assignment/services/properties.utils';
24 import {ToscaFunctionValidationEvent} from "../properties-assignment/tosca-function/tosca-function.component";
25 import {InstanceFeDetails} from "../../../models/instance-fe-details";
26 import {CompositionService} from "../composition/composition.service";
27 import {ToscaGetFunction} from "../../../models/tosca-get-function";
28 import {PropertyFilterConstraintUi} from "../../../models/ui-models/property-filter-constraint-ui";
29 import {ConstraintOperatorType, FilterConstraintHelper} from "../../../utils/filter-constraint-helper";
30 import {ToscaFunctionHelper} from "../../../utils/tosca-function-helper";
31 import {TopologyTemplateService} from "app/ng2/services/component-services/topology-template.service";
32 import {CustomToscaFunction} from "../../../models/default-custom-functions";
33 import {ToscaFunctionType} from "../../../models/tosca-function-type.enum";
34
35 @Component({
36   selector: 'service-dependencies-editor',
37   templateUrl: './service-dependencies-editor.component.html',
38   styleUrls: ['./service-dependencies-editor.component.less'],
39   providers: [ServiceServiceNg2]
40 })
41 export class ServiceDependenciesEditorComponent implements OnInit {
42
43   @Input() serviceRuleIndex: number;
44   @Input() serviceRules: PropertyFilterConstraintUi[];
45   @Input() compositeServiceName: string;
46   @Input() currentServiceName: string;
47   @Input() parentServiceInputs: InputBEModel[];
48   @Input() parentServiceProperties: PropertyBEModel[];
49   @Input() selectedInstanceProperties: PropertyBEModel[];
50   @Input() allowedOperators: ConstraintOperatorType[] = [
51       ConstraintOperatorType.GREATER_THAN,
52       ConstraintOperatorType.LESS_THAN,
53       ConstraintOperatorType.EQUAL,
54       ConstraintOperatorType.GREATER_OR_EQUAL,
55       ConstraintOperatorType.LESS_OR_EQUAL
56   ];
57   @Input() capabilityNameAndPropertiesMap: Map<string, PropertyModel[]>;
58   @Input() filterType: FilterType;
59   @Input() filterConstraint: PropertyFilterConstraintUi;
60   //output
61   currentRule: PropertyFilterConstraintUi;
62
63   FILTER_TYPE_CAPABILITY: FilterType = FilterType.CAPABILITY
64
65   operatorTypes: DropdownValue[] = [
66     {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.GREATER_THAN), value: ConstraintOperatorType.GREATER_THAN},
67     {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.LESS_THAN), value: ConstraintOperatorType.LESS_THAN},
68     {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.EQUAL), value: ConstraintOperatorType.EQUAL},
69     {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.GREATER_OR_EQUAL), value: ConstraintOperatorType.GREATER_OR_EQUAL},
70     {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.LESS_OR_EQUAL), value: ConstraintOperatorType.LESS_OR_EQUAL}
71   ];
72
73   servicePropertyDropdownList: DropdownValue[];
74   isLoading: false;
75   selectedProperty: PropertyFEModel;
76   selectedSourceType: string;
77   componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
78   customToscaFunctions: Array<CustomToscaFunction>;
79   capabilityDropdownList: DropdownValue[] = [];
80
81   SOURCE_TYPES = {
82     STATIC: {label: 'Static', value: SourceType.STATIC},
83     TOSCA_FUNCTION: {label: 'Tosca Function', value: SourceType.TOSCA_FUNCTION}
84   };
85
86   constructor(private propertiesUtils: PropertiesUtils, private compositionService: CompositionService, private topologyTemplateService: TopologyTemplateService) {}
87
88   ngOnInit(): void {
89     if (this.compositionService.componentInstances) {
90       this.compositionService.componentInstances.forEach(value => {
91         this.componentInstanceMap.set(value.uniqueId, <InstanceFeDetails>{
92           name: value.name
93         });
94       });
95     }
96     this.initCustomToscaFunctions();
97     this.initCapabilityDropdown();
98     this.initCurrentRule();
99     this.initConstraintOperatorOptions();
100     this.initSelectedSourceType();
101     this.initPropertyDropdown();
102     this.syncRuleData();
103   }
104
105   private initCustomToscaFunctions() {
106     this.customToscaFunctions = [];
107     this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
108         for (let customFunction of data) {
109             this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
110         }
111     });
112 }
113
114   private initCapabilityDropdown(): void {
115     if (this.filterType == FilterType.CAPABILITY) {
116       this.capabilityDropdownList = [
117         new DropdownValue(undefined, 'Select'),
118         ...Array.from(this.capabilityNameAndPropertiesMap.keys()).map(capabilityName => new DropdownValue(capabilityName, capabilityName))
119       ];
120     }
121   }
122
123   private initPropertyDropdown(): void {
124     let propertyList: PropertyBEModel[] = [];
125     if (this.filterType == FilterType.CAPABILITY) {
126       if (this.currentRule.capabilityName) {
127         propertyList = this.capabilityNameAndPropertiesMap.get(this.currentRule.capabilityName);
128       }
129     } else {
130       propertyList = this.selectedInstanceProperties;
131     }
132     let selectLabel;
133     if (this.filterType == FilterType.CAPABILITY) {
134       selectLabel = this.currentRule.capabilityName ? 'Select' : 'Select a Capability';
135     } else {
136       selectLabel = 'Select';
137     }
138     this.servicePropertyDropdownList = [new DropdownValue(undefined, selectLabel), ...propertyList.map(prop => new DropdownValue(prop.name, prop.name)).sort((prop1, prop2) => prop1.value.localeCompare(prop2.value))];
139   }
140
141   private initConstraintOperatorOptions(): void {
142     if (!this.selectedProperty) {
143       this.operatorTypes = [new DropdownValue(undefined, 'Select a Property')];
144       return;
145     }
146
147     if (PROPERTY_DATA.SIMPLE_TYPES_COMPARABLE.indexOf(this.selectedProperty.type) === -1) {
148       if (this.currentRule.constraintOperator !== ConstraintOperatorType.EQUAL) {
149         this.currentRule.constraintOperator = ConstraintOperatorType.EQUAL;
150       }
151       this.operatorTypes = [new DropdownValue(ConstraintOperatorType.EQUAL, FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.EQUAL))];
152     } else {
153       const operatorList: DropdownValue[] = [];
154       this.allowedOperators.forEach(constraintOperatorType =>
155         operatorList.push(new DropdownValue(constraintOperatorType, FilterConstraintHelper.convertToSymbol(constraintOperatorType)))
156       );
157       this.operatorTypes = operatorList;
158     }
159   }
160
161   private initSelectedSourceType(): void {
162     if (!this.currentRule.sourceType || this.currentRule.sourceType === SourceType.STATIC) {
163       this.selectedSourceType = SourceType.STATIC;
164     } else {
165       this.selectedSourceType = SourceType.TOSCA_FUNCTION;
166     }
167   }
168
169   private initCurrentRule(): void {
170     if (this.filterConstraint) {
171       this.currentRule = new PropertyFilterConstraintUi(this.filterConstraint);
172     } else {
173       this.currentRule = new PropertyFilterConstraintUi({
174         sourceName: SourceType.STATIC,
175         sourceType: SourceType.STATIC,
176         constraintOperator: ConstraintOperatorType.EQUAL,
177         value: undefined
178       });
179     }
180   }
181
182   onCapabilityChange(): void {
183     this.initPropertyDropdown();
184     this.resetSelectedProperty();
185   }
186
187   onPropertyChange(): void {
188     this.currentRule.value = undefined;
189     this.onValueChange(false);
190     this.updateSelectedProperty();
191     this.initConstraintOperatorOptions();
192   }
193
194   syncRuleData(): void {
195     if (!this.currentRule.sourceName || this.currentRule.sourceType === SourceType.STATIC) {
196       this.currentRule.sourceName = SourceType.STATIC;
197       this.currentRule.sourceType = SourceType.STATIC;
198     }
199     this.initSelectedProperty();
200     this.initConstraintOperatorOptions();
201   }
202
203   onValueChange(isValidValue:any): void {
204     this.currentRule.updateValidity(isValidValue);
205   }
206
207   checkFormValidForSubmit(): boolean {
208     return this.currentRule.isValidRule();
209   }
210
211   initSelectedProperty(): void {
212     if (!this.currentRule.servicePropertyName) {
213       this.selectedProperty = undefined;
214       return;
215     }
216     let newProperty;
217     if (this.filterType === FilterType.CAPABILITY) {
218       const currentProperty = this.capabilityNameAndPropertiesMap.get(this.currentRule.capabilityName)
219         .find(property => property.name === this.currentRule.servicePropertyName);
220       newProperty = new PropertyFEModel(currentProperty);
221     } else {
222       newProperty = new PropertyFEModel(this.selectedInstanceProperties.find(property => property.name === this.currentRule.servicePropertyName));
223     }
224     newProperty.value = undefined;
225     newProperty.toscaFunction = undefined;
226     if (typeof this.currentRule.value === 'string') {
227       newProperty.value = this.currentRule.value;
228       this.propertiesUtils.initValueObjectRef(newProperty);
229     } else if (ToscaFunctionHelper.isValueToscaFunction(this.currentRule.value)) {
230       newProperty.toscaFunction = ToscaFunctionHelper.convertObjectToToscaFunction(this.currentRule.value);
231       newProperty.value = newProperty.toscaFunction.buildValueString();
232     } else {
233       newProperty.value = JSON.stringify(this.currentRule.value);
234       this.propertiesUtils.initValueObjectRef(newProperty);
235     }
236
237     this.selectedProperty = newProperty;
238   }
239
240   updateSelectedProperty(): void {
241     this.selectedProperty = undefined;
242     if (!this.currentRule.servicePropertyName) {
243       return;
244     }
245
246     let newProperty;
247     if (this.filterType === FilterType.CAPABILITY) {
248       const currentProperty = this.capabilityNameAndPropertiesMap.get(this.currentRule.capabilityName)
249         .find(property => property.name === this.currentRule.servicePropertyName);
250       newProperty = new PropertyFEModel(currentProperty);
251     } else {
252       newProperty = new PropertyFEModel(this.selectedInstanceProperties.find(property => property.name === this.currentRule.servicePropertyName));
253     }
254     newProperty.value = undefined;
255     newProperty.toscaFunction = undefined;
256
257     this.propertiesUtils.initValueObjectRef(newProperty);
258     this.selectedProperty = newProperty;
259   }
260
261   isStaticSource(): boolean {
262     return this.selectedSourceType === SourceType.STATIC
263   }
264
265   isToscaFunctionSource(): boolean {
266     return this.selectedSourceType === SourceType.TOSCA_FUNCTION
267   }
268
269   isComplexListMapType(): boolean {
270     return this.selectedProperty && this.selectedProperty.derivedDataType > 0;
271   }
272
273   updateComplexListMapTypeRuleValue(): void {
274     this.currentRule.value = PropertyFEModel.cleanValueObj(this.selectedProperty.valueObj);
275     this.onValueChange(this.selectedProperty.valueObjIsValid);
276   }
277
278   onToscaFunctionValidityChange(validationEvent: ToscaFunctionValidationEvent): void {
279     if (validationEvent.isValid && validationEvent.toscaFunction) {
280       this.currentRule.value = validationEvent.toscaFunction;
281       this.currentRule.sourceType = validationEvent.toscaFunction.type
282       if (validationEvent.toscaFunction instanceof ToscaGetFunction) {
283         this.currentRule.sourceName = validationEvent.toscaFunction.sourceName;
284       }
285     } else {
286       this.currentRule.updateValidity(false);
287       this.currentRule.value = undefined;
288       this.currentRule.sourceType = undefined;
289       this.currentRule.sourceName = undefined;
290     }
291   }
292
293   onSourceTypeChange(): void {
294     this.currentRule.value = undefined;
295     this.currentRule.sourceType = this.selectedSourceType;
296     if (this.isStaticSource()) {
297       this.currentRule.sourceName = SourceType.STATIC;
298     }
299     this.updateSelectedProperty();
300   }
301
302   private resetSelectedProperty(): void {
303     this.currentRule.servicePropertyName = undefined;
304     this.selectedProperty = undefined;
305     this.onPropertyChange();
306   }
307
308 }
309
310 export enum FilterType {
311   CAPABILITY,
312   PROPERTY
313 }