2 * Copyright © 2016-2018 European Support Limited
3 * Modification Copyright (C) 2022 Nordix Foundation.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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, PROPERTY_TYPES} 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 {ToscaFunction} from "../../../models/tosca-function";
34 import {ToscaCustomFunction} from "../../../models/tosca-custom-function";
37 selector: 'service-dependencies-editor',
38 templateUrl: './service-dependencies-editor.component.html',
39 styleUrls: ['./service-dependencies-editor.component.less'],
40 providers: [ServiceServiceNg2]
42 export class ServiceDependenciesEditorComponent implements OnInit {
44 @Input() serviceRuleIndex: number;
45 @Input() serviceRules: PropertyFilterConstraintUi[];
46 @Input() compositeServiceName: string;
47 @Input() currentServiceName: string;
48 @Input() parentServiceInputs: InputBEModel[];
49 @Input() parentServiceProperties: PropertyBEModel[];
50 @Input() selectedInstanceProperties: PropertyBEModel[];
51 @Input() allowedOperators: ConstraintOperatorType[] = [
52 ConstraintOperatorType.GREATER_THAN,
53 ConstraintOperatorType.LESS_THAN,
54 ConstraintOperatorType.EQUAL,
55 ConstraintOperatorType.GREATER_OR_EQUAL,
56 ConstraintOperatorType.LESS_OR_EQUAL,
57 ConstraintOperatorType.IN_RANGE,
58 ConstraintOperatorType.VALID_VALUES,
59 ConstraintOperatorType.LENGTH,
60 ConstraintOperatorType.MIN_LENGTH,
61 ConstraintOperatorType.MAX_LENGTH,
62 ConstraintOperatorType.PATTERN
64 @Input() comparableAllowedOperators: ConstraintOperatorType[] = [
65 ConstraintOperatorType.GREATER_THAN,
66 ConstraintOperatorType.LESS_THAN,
67 ConstraintOperatorType.EQUAL,
68 ConstraintOperatorType.GREATER_OR_EQUAL,
69 ConstraintOperatorType.LESS_OR_EQUAL,
70 ConstraintOperatorType.IN_RANGE,
71 ConstraintOperatorType.VALID_VALUES,
73 @Input() capabilityNameAndPropertiesMap: Map<string, PropertyModel[]>;
74 @Input() filterType: FilterType;
75 @Input() filterConstraint: PropertyFilterConstraintUi;
76 @Input() customToscaFunctions: Array<CustomToscaFunction>;
78 currentRule: PropertyFilterConstraintUi;
80 FILTER_TYPE_CAPABILITY: FilterType = FilterType.CAPABILITY
82 listAllowedOperators: ConstraintOperatorType[] = [
83 ConstraintOperatorType.EQUAL,
84 ConstraintOperatorType.LENGTH,
85 ConstraintOperatorType.MIN_LENGTH,
86 ConstraintOperatorType.MAX_LENGTH
89 operatorTypes: DropdownValue[] = [
90 {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.GREATER_THAN), value: ConstraintOperatorType.GREATER_THAN},
91 {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.LESS_THAN), value: ConstraintOperatorType.LESS_THAN},
92 {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.EQUAL), value: ConstraintOperatorType.EQUAL},
93 {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.GREATER_OR_EQUAL), value: ConstraintOperatorType.GREATER_OR_EQUAL},
94 {label: FilterConstraintHelper.convertToSymbol(ConstraintOperatorType.LESS_OR_EQUAL), value: ConstraintOperatorType.LESS_OR_EQUAL}
96 lengthArray: string[] = [ConstraintOperatorType.LENGTH,
97 ConstraintOperatorType.MIN_LENGTH,
98 ConstraintOperatorType.MAX_LENGTH];
100 servicePropertyDropdownList: DropdownValue[];
102 selectedProperty: PropertyFEModel;
103 selectedSourceType: string;
104 componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
106 capabilityDropdownList: DropdownValue[] = [];
107 validValuesToscaFunctionList: ToscaFunction[];
108 rangeToscaFunctionList: ToscaFunction[];
109 overridingType = PROPERTY_TYPES.INTEGER;
112 STATIC: {label: 'Static', value: SourceType.STATIC},
113 TOSCA_FUNCTION: {label: 'Tosca Function', value: SourceType.TOSCA_FUNCTION},
114 TOSCA_FUNCTION_LIST: {label: 'Tosca Function List', value: SourceType.TOSCA_FUNCTION_LIST}
117 constructor(private propertiesUtils: PropertiesUtils, private compositionService: CompositionService, private topologyTemplateService: TopologyTemplateService) {
121 if (this.compositionService.componentInstances) {
122 this.compositionService.componentInstances.forEach(value => {
123 this.componentInstanceMap.set(value.uniqueId, <InstanceFeDetails>{
128 this.initCustomToscaFunctions();
129 this.initCapabilityDropdown();
130 this.initCurrentRule();
131 this.initConstraintOperatorOptions();
132 this.initSelectedSourceType();
133 this.initPropertyDropdown();
135 this.generateRangeToscaFunctionList();
138 private initCustomToscaFunctions() {
139 if (!this.customToscaFunctions) {
140 this.customToscaFunctions = [];
141 this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
142 for (let customFunction of data) {
143 this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
149 private initCapabilityDropdown(): void {
150 if (this.filterType == FilterType.CAPABILITY) {
151 this.capabilityDropdownList = [
152 new DropdownValue(undefined, 'Select'),
153 ...Array.from(this.capabilityNameAndPropertiesMap.keys()).map(capabilityName => new DropdownValue(capabilityName, capabilityName))
158 private initPropertyDropdown(): void {
159 let propertyList: PropertyBEModel[] = [];
160 if (this.filterType == FilterType.CAPABILITY) {
161 if (this.currentRule.capabilityName) {
162 propertyList = this.capabilityNameAndPropertiesMap.get(this.currentRule.capabilityName);
165 propertyList = this.selectedInstanceProperties;
168 if (this.filterType == FilterType.CAPABILITY) {
169 selectLabel = this.currentRule.capabilityName ? 'Select' : 'Select a Capability';
171 selectLabel = 'Select';
173 this.servicePropertyDropdownList = [new DropdownValue(undefined, selectLabel), ...propertyList.map(prop => new DropdownValue(prop.name, prop.name)).sort((prop1, prop2) => prop1.value.localeCompare(prop2.value))];
176 private initConstraintOperatorOptions(): void {
177 if (!this.selectedProperty) {
178 this.operatorTypes = [this.setOperatorDropdownValue(undefined)];
181 const operatorList: DropdownValue[] = [];
183 case this.selectedProperty.type === PROPERTY_TYPES.RANGE:
184 if (this.currentRule.constraintOperator !== ConstraintOperatorType.IN_RANGE) {
185 this.currentRule.constraintOperator = ConstraintOperatorType.IN_RANGE;
187 this.operatorTypes = [this.setOperatorDropdownValue(ConstraintOperatorType.IN_RANGE)];
189 case this.selectedProperty.type === PROPERTY_TYPES.STRING:
190 this.allowedOperators.forEach(constraintOperatorType =>
191 operatorList.push(this.setOperatorDropdownValue(constraintOperatorType))
193 this.operatorTypes = operatorList;
195 case this.selectedProperty.type != PROPERTY_TYPES.STRING &&
196 ((PROPERTY_DATA.SIMPLE_TYPES_COMPARABLE.indexOf(this.selectedProperty.type) > -1) ||
197 (PROPERTY_DATA.COMPARABLE_TYPES.indexOf(this.selectedProperty.type) > -1)):
198 this.comparableAllowedOperators.forEach(constraintOperatorType =>
199 operatorList.push(this.setOperatorDropdownValue(constraintOperatorType))
201 this.operatorTypes = operatorList;
203 case this.selectedProperty.type === PROPERTY_TYPES.LIST:
204 this.listAllowedOperators.forEach(constraintOperatorType =>
205 operatorList.push(this.setOperatorDropdownValue(constraintOperatorType))
207 this.operatorTypes = operatorList;
210 if (this.currentRule.constraintOperator !== ConstraintOperatorType.EQUAL) {
211 this.currentRule.constraintOperator = ConstraintOperatorType.EQUAL;
213 this.operatorTypes = [this.setOperatorDropdownValue(ConstraintOperatorType.EQUAL)];
218 private setOperatorDropdownValue(constraintOperatorType: ConstraintOperatorType) {
219 if (constraintOperatorType === undefined) {
220 return new DropdownValue(undefined, 'Select a Property');
222 return new DropdownValue(constraintOperatorType, FilterConstraintHelper.convertToSymbol(constraintOperatorType));
225 private initSelectedSourceType(): void {
226 if (!this.currentRule.sourceType || this.currentRule.sourceType === SourceType.STATIC
227 || (this.currentRule.sourceType === SourceType.SEVERAL && !ToscaFunctionHelper.convertObjectToToscaFunction(this.currentRule.value[0]))) {
228 this.selectedSourceType = SourceType.STATIC;
230 if (!this.isValidValuesOperator() && !this.isRangeType() && !this.isInRangeOperator()) {
231 this.selectedSourceType = SourceType.TOSCA_FUNCTION;
233 this.selectedSourceType = SourceType.TOSCA_FUNCTION_LIST;
238 private initCurrentRule(): void {
239 if (this.filterConstraint) {
240 this.currentRule = new PropertyFilterConstraintUi(this.filterConstraint);
242 this.currentRule = new PropertyFilterConstraintUi({
243 sourceName: SourceType.STATIC,
244 sourceType: SourceType.STATIC,
245 constraintOperator: ConstraintOperatorType.EQUAL,
247 originalType: undefined
250 let propertyList: PropertyBEModel[] = [];
251 if (this.filterType == FilterType.CAPABILITY) {
252 if (this.currentRule.capabilityName) {
253 propertyList = this.capabilityNameAndPropertiesMap.get(this.currentRule.capabilityName);
256 propertyList = this.selectedInstanceProperties;
258 if (this.filterConstraint) {
259 this.filterConstraint.originalType = propertyList.find(prop => prop.name == this.filterConstraint.servicePropertyName).type;
263 onCapabilityChange(): void {
264 this.initPropertyDropdown();
265 this.resetSelectedProperty();
268 onPropertyChange(): void {
269 this.currentRule.value = undefined;
270 this.onValueChange(false);
271 this.updateSelectedProperty();
272 this.initConstraintOperatorOptions();
275 syncRuleData(): void {
276 if (!this.currentRule.sourceName || this.currentRule.sourceType === SourceType.STATIC) {
277 this.currentRule.sourceName = SourceType.STATIC;
278 this.currentRule.sourceType = SourceType.STATIC;
280 this.initSelectedProperty();
281 this.initConstraintOperatorOptions();
284 onValueChange(isValidValue: any): void {
285 this.currentRule.updateValidity(isValidValue);
288 checkFormValidForSubmit(): boolean {
289 return this.currentRule.isValidRule();
292 initSelectedProperty(): void {
293 if (!this.currentRule.servicePropertyName) {
294 this.selectedProperty = undefined;
298 if (this.filterType === FilterType.CAPABILITY) {
299 const currentProperty = this.capabilityNameAndPropertiesMap.get(this.currentRule.capabilityName)
300 .find(property => property.name === this.currentRule.servicePropertyName);
301 newProperty = new PropertyFEModel(currentProperty);
303 newProperty = new PropertyFEModel(this.selectedInstanceProperties.find(property => property.name === this.currentRule.servicePropertyName));
305 newProperty.value = undefined;
306 newProperty.toscaFunction = undefined;
307 if (typeof this.currentRule.value === 'string') {
308 newProperty.value = this.currentRule.value;
309 this.propertiesUtils.initValueObjectRef(newProperty);
310 } else if (ToscaFunctionHelper.isValueToscaFunction(this.currentRule.value)) {
311 newProperty.toscaFunction = ToscaFunctionHelper.convertObjectToToscaFunction(this.currentRule.value);
312 newProperty.value = newProperty.toscaFunction.buildValueString();
313 } else if (Array.isArray(this.currentRule.value)) {
314 if (typeof this.currentRule.value[0] === 'object') {
315 this.rangeToscaFunctionList = [];
316 this.validValuesToscaFunctionList = [];
317 this.currentRule.value.forEach(val => {
318 this.rangeToscaFunctionList.push(ToscaFunctionHelper.convertObjectToToscaFunction(val));
319 this.validValuesToscaFunctionList.push(ToscaFunctionHelper.convertObjectToToscaFunction(val));
321 newProperty.toscaFunction = this.currentRule.value;
322 newProperty.value = this.currentRule.value;
325 this.validValuesToscaFunctionList = this.currentRule.value;
326 this.rangeToscaFunctionList = this.currentRule.value;
327 newProperty.toscaFunction = this.currentRule.value;
330 newProperty.value = JSON.stringify(this.currentRule.value);
331 this.propertiesUtils.initValueObjectRef(newProperty);
334 this.selectedProperty = newProperty;
335 this.currentRule.originalType = this.selectedProperty.type;
338 updateSelectedProperty(): void {
339 this.selectedProperty = undefined;
340 if (!this.currentRule.servicePropertyName) {
345 if (this.filterType === FilterType.CAPABILITY) {
346 const currentProperty = this.capabilityNameAndPropertiesMap.get(this.currentRule.capabilityName)
347 .find(property => property.name === this.currentRule.servicePropertyName);
348 newProperty = new PropertyFEModel(currentProperty);
350 newProperty = new PropertyFEModel(this.selectedInstanceProperties.find(property => property.name === this.currentRule.servicePropertyName));
352 newProperty.value = undefined;
353 newProperty.toscaFunction = undefined;
355 this.propertiesUtils.initValueObjectRef(newProperty);
356 this.selectedProperty = newProperty;
357 this.currentRule.originalType = this.selectedProperty.type;
360 isStaticSource(): boolean {
361 return this.selectedSourceType === SourceType.STATIC
364 isToscaFunctionSource(): boolean {
365 return this.selectedSourceType === SourceType.TOSCA_FUNCTION
368 isToscaFunctionListSource(): boolean {
369 return this.selectedSourceType === SourceType.TOSCA_FUNCTION_LIST
372 isComplexListMapType(): boolean {
373 return this.selectedProperty && this.selectedProperty.derivedDataType > 0;
376 isRangeType(): boolean {
377 return this.selectedProperty && this.selectedProperty.derivedDataType == 4;
380 isLengthOperator(): boolean {
381 return this.lengthArray.indexOf(this.currentRule.constraintOperator) > -1;
384 isInRangeOperator(): boolean {
385 return this.currentRule.constraintOperator && this.currentRule.constraintOperator === ConstraintOperatorType.IN_RANGE;
388 isValidValuesOperator(): boolean {
389 return this.currentRule.constraintOperator && this.currentRule.constraintOperator === ConstraintOperatorType.VALID_VALUES;
392 updateComplexListMapTypeRuleValue(): void {
393 this.currentRule.value = PropertyFEModel.cleanValueObj(this.selectedProperty.valueObj);
394 this.onValueChange(this.selectedProperty.valueObjIsValid);
397 onToscaFunctionValidityChange(validationEvent: ToscaFunctionValidationEvent): void {
398 if (validationEvent.isValid && validationEvent.toscaFunction) {
399 if (this.isValidValuesOperator()) {
400 this.currentRule.value = this.validValuesToscaFunctionList;
401 this.currentRule.sourceType = SourceType.TOSCA_FUNCTION_LIST;
402 if (validationEvent.toscaFunction instanceof ToscaGetFunction) {
403 this.currentRule.sourceName = SourceType.TOSCA_FUNCTION_LIST;
405 else if (validationEvent.toscaFunction instanceof ToscaCustomFunction) {
406 this.currentRule.sourceName = SourceType.TOSCA_FUNCTION_LIST;
407 this.currentRule.sourceType = SourceType.TOSCA_FUNCTION_LIST;
410 if (this.isLengthOperator()) {
411 this.overridingType = PROPERTY_TYPES.INTEGER;
413 this.currentRule.value = validationEvent.toscaFunction;
414 this.currentRule.sourceType = validationEvent.toscaFunction.type
415 if (validationEvent.toscaFunction instanceof ToscaGetFunction) {
416 this.currentRule.sourceName = validationEvent.toscaFunction.sourceName;
420 this.currentRule.updateValidity(false);
421 this.currentRule.value = undefined;
422 this.currentRule.sourceType = undefined;
423 this.currentRule.sourceName = undefined;
427 onToscaFunctionListValidityChange(validationEvent: ToscaFunctionValidationEvent, valueIndex: number): void {
428 if (validationEvent.isValid && validationEvent.toscaFunction) {
429 this.validValuesToscaFunctionList.splice(this.validValuesToscaFunctionList.length - 1, 1, validationEvent.toscaFunction);
430 this.currentRule.value = this.validValuesToscaFunctionList;
431 this.currentRule.sourceType = 'SEVERAL';
432 if (validationEvent.toscaFunction instanceof ToscaGetFunction) {
433 this.currentRule.sourceName = validationEvent.toscaFunction.sourceName;
436 this.currentRule.updateValidity(false);
437 this.currentRule.value = undefined;
438 this.currentRule.sourceType = undefined;
439 this.currentRule.sourceName = undefined;
443 onToscaRangeFunctionListValidityChange(validationEvent: ToscaFunctionValidationEvent, valueIndex: number): void {
444 if (validationEvent.isValid && validationEvent.toscaFunction) {
445 this.rangeToscaFunctionList.splice(valueIndex, 1, validationEvent.toscaFunction);
446 this.currentRule.value = this.rangeToscaFunctionList;
447 this.currentRule.sourceType = 'SEVERAL';
448 if (validationEvent.toscaFunction instanceof ToscaGetFunction) {
449 this.currentRule.sourceName = validationEvent.toscaFunction.sourceName;
452 this.currentRule.updateValidity(false);
453 this.currentRule.value = undefined;
454 this.currentRule.sourceType = undefined;
455 this.currentRule.sourceName = undefined;
459 onSourceTypeChange(): void {
460 this.currentRule.value = undefined;
461 if (!this.isStaticSource() && (this.isValidValuesOperator() || this.isRangeType() || this.isInRangeOperator())) {
462 this.selectedSourceType = SourceType.TOSCA_FUNCTION_LIST;
464 this.currentRule.sourceType = this.selectedSourceType;
465 if (this.isStaticSource()) {
466 this.currentRule.sourceName = SourceType.STATIC;
468 if (this.isToscaFunctionListSource()) {
469 this.currentRule.sourceName = SourceType.TOSCA_FUNCTION_LIST;
471 this.updateSelectedProperty();
474 private resetSelectedProperty(): void {
475 this.currentRule.servicePropertyName = undefined;
476 this.selectedProperty = undefined;
477 this.onPropertyChange();
481 if (!this.validValuesToscaFunctionList) {
482 this.validValuesToscaFunctionList = new Array();
484 this.validValuesToscaFunctionList.push(ToscaFunctionHelper.convertObjectToToscaFunction(undefined));
487 generateRangeToscaFunctionList() {
488 if (!this.rangeToscaFunctionList) {
489 this.rangeToscaFunctionList = new Array();
490 this.rangeToscaFunctionList.push(ToscaFunctionHelper.convertObjectToToscaFunction(undefined));
491 this.rangeToscaFunctionList.push(ToscaFunctionHelper.convertObjectToToscaFunction(undefined));
499 removeFromList(valueIndex: number) {
500 this.validValuesToscaFunctionList.splice(valueIndex, 1);
501 this.currentRule.updateValidity(!this.doesArrayContainsEmptyValues(this.validValuesToscaFunctionList) && !(this.validValuesToscaFunctionList.length === 0));
502 if (this.doesArrayContainsEmptyValues(this.validValuesToscaFunctionList) || (this.validValuesToscaFunctionList.length === 0)) {
503 this.currentRule.value = undefined;
504 this.currentRule.sourceType = undefined;
505 this.currentRule.sourceName = undefined;
509 private doesArrayContainsEmptyValues(arr) {
510 for (const element of arr) {
511 if (element === undefined) return true;
517 export enum FilterType {