2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021 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
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.
16 * SPDX-License-Identifier: Apache-2.0
17 * ============LICENSE_END=========================================================
20 import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core';
21 import {ComponentMetadata, PropertyBEModel, PropertyDeclareAPIModel, DerivedFEProperty} from 'app/models';
22 import {TopologyTemplateService} from "../../../services/component-services/topology-template.service";
23 import {WorkspaceService} from "../../workspace/workspace.service";
24 import {ToscaGetFunctionType} from "../../../../models/tosca-get-function-type";
25 import {InstanceFeDetails} from "../../../../models/instance-fe-details";
26 import {ToscaGetFunction} from "../../../../models/tosca-get-function";
27 import {FormControl, FormGroup, Validators} from "@angular/forms";
28 import {ToscaFunctionType} from "../../../../models/tosca-function-type.enum";
29 import {ToscaGetFunctionValidationEvent} from "./tosca-get-function/tosca-get-function.component";
30 import {ToscaFunction} from "../../../../models/tosca-function";
31 import {ToscaConcatFunctionValidationEvent} from "./tosca-concat-function/tosca-concat-function.component";
32 import {ToscaCustomFunctionValidationEvent} from "./tosca-custom-function/tosca-custom-function.component";
33 import {PROPERTY_TYPES} from "../../../../utils/constants";
34 import {YamlFunctionValidationEvent} from "./yaml-function/yaml-function.component";
35 import {ToscaConcatFunction} from "../../../../models/tosca-concat-function";
36 import {ToscaCustomFunction} from "../../../../models/tosca-custom-function";
37 import {YamlFunction} from "../../../../models/yaml-function";
38 import {CustomToscaFunction} from "../../../../models/default-custom-functions";
41 selector: 'tosca-function',
42 templateUrl: './tosca-function.component.html',
43 styleUrls: ['./tosca-function.component.less'],
45 export class ToscaFunctionComponent implements OnInit, OnChanges {
47 @Input() property: PropertyBEModel;
48 @Input() overridingType: PROPERTY_TYPES;
49 @Input() inToscaFunction: ToscaFunction;
50 @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
51 @Input() customToscaFunctions: Array<CustomToscaFunction> = [];
52 @Input() allowClear: boolean = true;
53 @Input() compositionMap: boolean = false;
54 @Input() compositionMapKey: string = "";
55 @Input() complexListKey: string = null;
56 @Output() onValidFunction: EventEmitter<ToscaGetFunction> = new EventEmitter<ToscaGetFunction>();
57 @Output() onValidityChange: EventEmitter<ToscaFunctionValidationEvent> = new EventEmitter<ToscaFunctionValidationEvent>();
59 toscaFunctionForm: FormControl = new FormControl(undefined, [Validators.required]);
60 toscaFunctionTypeForm: FormControl = new FormControl(undefined, Validators.required);
61 formGroup: FormGroup = new FormGroup({
62 'toscaFunction': this.toscaFunctionForm,
63 'toscaFunctionType': this.toscaFunctionTypeForm,
66 isLoading: boolean = false;
67 toscaFunction: ToscaFunction;
68 toscaFunctions: Array<string> = [];
69 toscaCustomFunctions: Array<String> = [];
71 private isInitialized: boolean = false;
72 private componentMetadata: ComponentMetadata;
74 constructor(private topologyTemplateService: TopologyTemplateService,
75 private workspaceService: WorkspaceService) {
79 this.componentMetadata = this.workspaceService.metadata;
80 this.toscaFunction = this.inToscaFunction ? this.inToscaFunction : this.property.toscaFunction ? this.property.toscaFunction : undefined;
81 this.loadToscaFunctions();
82 this.formGroup.valueChanges.subscribe(() => {
83 if (!this.isInitialized) {
86 if (this.formGroup.valid) {
87 this.onValidFunction.emit(this.toscaFunctionForm.value);
90 this.initToscaFunction();
91 this.emitValidityChange();
92 this.isInitialized = true;
95 ngOnChanges(changes: SimpleChanges): void {
96 if (changes.property) {
98 this.toscaFunction = this.inToscaFunction ? this.inToscaFunction : this.property.toscaFunction ? this.property.toscaFunction : undefined;
99 this.initToscaFunction();
100 this.loadToscaFunctions();
101 this.emitValidityChange();
105 private validate(): boolean {
106 return (!this.toscaFunctionForm.value && !this.toscaFunctionTypeForm.value) || this.formGroup.valid;
109 private initToscaFunction(): void {
110 if (this.compositionMap && this.property.subPropertyToscaFunctions) {
111 let keyToFind = [this.compositionMapKey];
112 if (this.complexListKey != null) {
113 keyToFind = [this.complexListKey,this.compositionMapKey];
115 let subPropertyToscaFunction;
116 this.property.subPropertyToscaFunctions.forEach(subToscaFunction => {
117 if (subToscaFunction.subPropertyPath.toString() == keyToFind.toString()) {
118 subPropertyToscaFunction = subToscaFunction;
122 if (subPropertyToscaFunction){
123 this.toscaFunction = subPropertyToscaFunction.toscaFunction;
124 this.toscaFunctionForm.setValue(this.toscaFunction);
125 let type = this.toscaFunction.type;
126 if (type == ToscaFunctionType.CUSTOM) {
127 let name = (subPropertyToscaFunction.toscaFunction as ToscaCustomFunction).name;
128 let customToscaFunc = this.customToscaFunctions.find(custToscFunc => _.isEqual(custToscFunc.name, name))
129 if (customToscaFunc) {
130 this.toscaFunctionTypeForm.setValue(name);
132 this.toscaFunctionTypeForm.setValue("other");
135 this.toscaFunctionTypeForm.setValue(type);
140 if (this.property instanceof PropertyDeclareAPIModel && this.property.subPropertyToscaFunctions && (<PropertyDeclareAPIModel> this.property).propertiesName){
141 let propertiesPath = (<PropertyDeclareAPIModel> this.property).propertiesName.split("#");
142 if (propertiesPath.length > 1){
143 let keyToFind = (<DerivedFEProperty>this.property.input).toscaPath;
144 let subPropertyToscaFunction = this.property.subPropertyToscaFunctions.find(subPropertyToscaFunction => this.areEqual(subPropertyToscaFunction.subPropertyPath, keyToFind.length > 0 ? keyToFind : propertiesPath.slice(1)));
146 if (subPropertyToscaFunction){
147 this.toscaFunction = subPropertyToscaFunction.toscaFunction;
148 this.toscaFunctionForm.setValue(this.toscaFunction);
149 let type = this.toscaFunction.type;
150 if (type == ToscaFunctionType.CUSTOM) {
151 let name = (subPropertyToscaFunction.toscaFunction as ToscaCustomFunction).name;
152 let customToscaFunc = this.customToscaFunctions.find(custToscFunc => _.isEqual(custToscFunc.name, name))
153 if (customToscaFunc) {
154 this.toscaFunctionTypeForm.setValue(name);
156 this.toscaFunctionTypeForm.setValue("other");
159 this.toscaFunctionTypeForm.setValue(type);
165 if (!this.property.isToscaFunction()) {
169 this.toscaFunctionForm.setValue(this.inToscaFunction ? this.inToscaFunction : this.property.toscaFunction);
170 let type = this.property.toscaFunction.type ? this.property.toscaFunction.type : this.toscaFunctionForm.value.type;
171 if (type == ToscaFunctionType.CUSTOM) {
172 let name = (this.toscaFunctionForm.value as ToscaCustomFunction).name;
173 let customToscaFunc = this.customToscaFunctions.find(custToscFunc => _.isEqual(custToscFunc.name, name))
174 if (customToscaFunc) {
175 this.toscaFunctionTypeForm.setValue(name);
177 this.toscaFunctionTypeForm.setValue("other");
180 this.toscaFunctionTypeForm.setValue(this.inToscaFunction ? this.inToscaFunction.type : type);
184 private areEqual(array1: string[], array2: string[]): boolean {
185 return array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
188 private loadToscaFunctions(): void {
189 this.toscaFunctions = [];
190 this.toscaFunctions.push(ToscaFunctionType.GET_ATTRIBUTE);
191 this.toscaFunctions.push(ToscaFunctionType.GET_INPUT);
192 this.toscaFunctions.push(ToscaFunctionType.GET_PROPERTY);
193 if ((this.property.type === PROPERTY_TYPES.STRING || this.property.type === PROPERTY_TYPES.ANY) && this.overridingType === undefined) {
194 this.toscaFunctions.push(ToscaFunctionType.CONCAT);
196 this.loadCustomToscaFunctions();
199 private loadCustomToscaFunctions(): void {
200 if (!this.customToscaFunctions.find(custToscFunc => _.isEqual(custToscFunc.name, "other"))) {
201 let other = new CustomToscaFunction();
202 other.name = "other";
203 other.type = ToscaFunctionType.CUSTOM;
204 this.customToscaFunctions.push(other);
206 this.toscaCustomFunctions = [];
207 for (let func of this.customToscaFunctions) {
208 this.toscaCustomFunctions.push(func.name);
212 getCustomToscaFunction(): CustomToscaFunction {
213 let funcName = this.formGroup.get('toscaFunctionType').value;
214 return this.customToscaFunctions.find(custToscFunc => _.isEqual(custToscFunc.name, funcName));
217 getCustomFunctionName():string {
218 let toscaFunctionType: CustomToscaFunction = this.getCustomToscaFunction();
219 let name = toscaFunctionType.name;
220 return name == 'other' ? '' : name;
223 getCustomFunctionType():string {
224 let toscaFunctionType: CustomToscaFunction = this.getCustomToscaFunction();
225 return toscaFunctionType.type;
228 isDefaultCustomFunction(): boolean {
229 let toscaFunctionType: CustomToscaFunction = this.getCustomToscaFunction();
230 if (toscaFunctionType.name === "other") {
233 return this.customToscaFunctions.filter(e => e.name === toscaFunctionType.name).length > 0;
236 private resetForm(): void {
237 this.formGroup.reset();
238 this.toscaFunction = undefined;
241 private isGetPropertySelected(): boolean {
242 return this.formGroup.get('toscaFunctionType').value === ToscaGetFunctionType.GET_PROPERTY;
245 private isGetAttributeSelected(): boolean {
246 return this.formGroup.get('toscaFunctionType').value === ToscaGetFunctionType.GET_ATTRIBUTE;
249 private isGetInputSelected(): boolean {
250 return this.formGroup.get('toscaFunctionType').value === ToscaGetFunctionType.GET_INPUT;
253 isConcatSelected(): boolean {
254 return this.formGroup.get('toscaFunctionType').value === ToscaFunctionType.CONCAT;
257 isCustomSelected(): boolean {
258 let toscaFunctionType: CustomToscaFunction = this.getCustomToscaFunction();
259 return toscaFunctionType && (toscaFunctionType.type === ToscaFunctionType.CUSTOM || toscaFunctionType.type === ToscaFunctionType.GET_INPUT);
262 isGetFunctionSelected(): boolean {
263 return this.isGetInputSelected() || this.isGetPropertySelected() || this.isGetAttributeSelected();
266 isYamlFunctionSelected(): boolean {
267 return this.formGroup.get('toscaFunctionType').value === ToscaFunctionType.YAML;
270 onClearValues(): void {
274 showClearButton(): boolean {
275 return this.allowClear && this.toscaFunctionTypeForm.value;
278 onConcatFunctionValidityChange(validationEvent: ToscaConcatFunctionValidationEvent): void {
279 if (validationEvent.isValid) {
280 this.toscaFunctionForm.setValue(validationEvent.toscaConcatFunction);
282 this.toscaFunctionForm.setValue(undefined);
284 this.emitValidityChange();
287 onCustomFunctionValidityChange(validationEvent: ToscaCustomFunctionValidationEvent): void {
288 if (validationEvent.isValid) {
289 this.toscaFunctionForm.setValue(validationEvent.toscaCustomFunction);
291 this.toscaFunctionForm.setValue(undefined);
293 this.emitValidityChange();
296 onGetFunctionValidityChange(validationEvent: ToscaGetFunctionValidationEvent): void {
297 if (validationEvent.isValid) {
298 this.toscaFunctionForm.setValue(validationEvent.toscaGetFunction);
300 this.toscaFunctionForm.setValue(undefined);
302 this.emitValidityChange();
305 onYamlFunctionValidityChange(validationEvent: YamlFunctionValidationEvent): void {
306 if (validationEvent.isValid) {
307 this.toscaFunctionForm.setValue(validationEvent.value);
309 this.toscaFunctionForm.setValue(undefined);
311 this.emitValidityChange();
314 onFunctionTypeChange(): void {
315 this.toscaFunction = undefined;
316 this.toscaFunctionForm.reset();
319 private emitValidityChange(): void {
320 const isValid: boolean = this.validate();
321 this.onValidityChange.emit({
323 toscaFunction: isValid ? this.buildFunctionFromForm() : undefined
327 private buildFunctionFromForm(): ToscaFunction {
328 if (!this.toscaFunctionTypeForm.value) {
331 if (this.isConcatSelected()) {
332 return new ToscaConcatFunction(this.toscaFunctionForm.value);
334 if (this.isCustomSelected()) {
335 return new ToscaCustomFunction(this.toscaFunctionForm.value);
337 if (this.isGetFunctionSelected()) {
338 return new ToscaGetFunction(this.toscaFunctionForm.value);
340 if (this.isYamlFunctionSelected()) {
341 return new YamlFunction(this.toscaFunctionForm.value);
344 console.error(`Function ${this.toscaFunctionTypeForm.value} not supported`);
348 export class ToscaFunctionValidationEvent {
350 toscaFunction: ToscaFunction;