Provide tosca function to list of map values
[sdc.git] / catalog-ui / src / app / ng2 / pages / properties-assignment / tosca-function / tosca-function.component.ts
1 /*
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
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, 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 {PROPERTY_TYPES, PROPERTY_DATA} from "../../../../utils/constants";
33 import {YamlFunctionValidationEvent} from "./yaml-function/yaml-function.component";
34 import {ToscaConcatFunction} from "../../../../models/tosca-concat-function";
35 import {YamlFunction} from "../../../../models/yaml-function";
36
37 @Component({
38     selector: 'tosca-function',
39     templateUrl: './tosca-function.component.html',
40     styleUrls: ['./tosca-function.component.less'],
41 })
42 export class ToscaFunctionComponent implements OnInit, OnChanges {
43
44     @Input() property: PropertyBEModel;
45     @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
46     @Input() allowClear: boolean = true;
47     @Input() compositionMap: boolean = false;
48     @Input() compositionMapKey: string = "";
49     @Output() onValidFunction: EventEmitter<ToscaGetFunction> = new EventEmitter<ToscaGetFunction>();
50     @Output() onValidityChange: EventEmitter<ToscaFunctionValidationEvent> = new EventEmitter<ToscaFunctionValidationEvent>();
51
52     toscaFunctionForm: FormControl = new FormControl(undefined, [Validators.required]);
53     toscaFunctionTypeForm: FormControl = new FormControl(undefined, Validators.required);
54     formGroup: FormGroup = new FormGroup({
55         'toscaFunction': this.toscaFunctionForm,
56         'toscaFunctionType': this.toscaFunctionTypeForm,
57     });
58
59     isLoading: boolean = false;
60     toscaFunction: ToscaFunction;
61     toscaFunctions: Array<string> = [];
62
63     private isInitialized: boolean = false;
64     private componentMetadata: ComponentMetadata;
65
66     constructor(private topologyTemplateService: TopologyTemplateService,
67                 private workspaceService: WorkspaceService) {
68     }
69
70     ngOnInit(): void {
71         this.componentMetadata = this.workspaceService.metadata;
72         this.toscaFunction = this.property.toscaFunction ? this.property.toscaFunction : undefined;
73         this.loadToscaFunctions();
74         this.formGroup.valueChanges.subscribe(() => {
75             if (!this.isInitialized) {
76                 return;
77             }
78             this.emitValidityChange();
79             if (this.formGroup.valid) {
80                 this.onValidFunction.emit(this.toscaFunctionForm.value);
81             }
82         });
83         this.initToscaFunction();
84         this.emitValidityChange();
85         this.isInitialized = true;
86     }
87
88     ngOnChanges(changes: SimpleChanges): void {
89         if (changes.property) {
90             this.resetForm();
91             this.toscaFunction = this.property.toscaFunction ? this.property.toscaFunction : undefined;
92             this.initToscaFunction();
93             this.loadToscaFunctions();
94             this.emitValidityChange();
95         }
96     }
97
98     private validate(): boolean {
99         return (!this.toscaFunctionForm.value && !this.toscaFunctionTypeForm.value) || this.formGroup.valid;
100     }
101
102     private initToscaFunction(): void {
103         if (this.compositionMap && this.property.subPropertyToscaFunctions) {
104             let keyToFind = [this.compositionMapKey];
105             let subPropertyToscaFunction = this.property.subPropertyToscaFunctions.find(subPropertyToscaFunction => this.areEqual(subPropertyToscaFunction.subPropertyPath, keyToFind));
106
107                 if (subPropertyToscaFunction){
108                         this.toscaFunction = subPropertyToscaFunction.toscaFunction;
109                     this.toscaFunctionForm.setValue(this.toscaFunction);
110                     this.toscaFunctionTypeForm.setValue(this.toscaFunction.type);
111                 }
112                 return;
113         }
114             if (this.property instanceof PropertyDeclareAPIModel && this.property.subPropertyToscaFunctions && (<PropertyDeclareAPIModel> this.property).propertiesName){
115                 let propertiesPath = (<PropertyDeclareAPIModel> this.property).propertiesName.split("#");
116             if (propertiesPath.length > 1){
117                 let keyToFind = [];
118                 if (this.property.type == PROPERTY_TYPES.MAP || this.property.type == PROPERTY_TYPES.LIST) {
119                     if (this.property.type == PROPERTY_TYPES.LIST && this.property.schemaType == PROPERTY_TYPES.MAP) {
120                         keyToFind.push((<DerivedFEProperty>this.property.input).parentMapKey);
121                     }
122                     keyToFind.push((<DerivedFEProperty>this.property.input).mapKey);
123                     if (this.property.schemaType != PROPERTY_TYPES.MAP && PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.property.schemaType) === -1) {
124                         keyToFind.push(propertiesPath.reverse()[0]);
125                     }
126                 }
127                 let subPropertyToscaFunction = this.property.subPropertyToscaFunctions.find(subPropertyToscaFunction => this.areEqual(subPropertyToscaFunction.subPropertyPath, keyToFind.length > 0 ? keyToFind : propertiesPath.slice(1)));
128
129                 if (subPropertyToscaFunction){
130                         this.toscaFunction = subPropertyToscaFunction.toscaFunction;
131                     this.toscaFunctionForm.setValue(this.toscaFunction);
132                     this.toscaFunctionTypeForm.setValue(this.toscaFunction.type);
133                 }
134                 return;
135             }
136         }
137
138         if (!this.property.isToscaFunction()) {
139             return;
140         }
141         this.toscaFunctionForm.setValue(this.property.toscaFunction);
142         this.toscaFunctionTypeForm.setValue(this.property.toscaFunction.type);
143     }
144
145     private areEqual(array1: string[], array2: string[]): boolean {
146             return array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
147     }
148
149     private loadToscaFunctions(): void {
150         this.toscaFunctions = [];
151         this.toscaFunctions.push(ToscaFunctionType.GET_ATTRIBUTE);
152         this.toscaFunctions.push(ToscaFunctionType.GET_INPUT);
153         this.toscaFunctions.push(ToscaFunctionType.GET_PROPERTY);
154         if (this.property.type === PROPERTY_TYPES.STRING) {
155             this.toscaFunctions.push(ToscaFunctionType.CONCAT);
156         }
157         this.toscaFunctions.push(ToscaFunctionType.YAML);
158     }
159
160     private resetForm(): void {
161         this.formGroup.reset();
162         this.toscaFunction = undefined;
163     }
164
165     private isGetPropertySelected(): boolean {
166         return this.formGroup.get('toscaFunctionType').value === ToscaGetFunctionType.GET_PROPERTY;
167     }
168
169     private isGetAttributeSelected(): boolean {
170         return this.formGroup.get('toscaFunctionType').value === ToscaGetFunctionType.GET_ATTRIBUTE;
171     }
172
173     private isGetInputSelected(): boolean {
174         return this.formGroup.get('toscaFunctionType').value === ToscaGetFunctionType.GET_INPUT;
175     }
176
177     isConcatSelected(): boolean {
178         return this.formGroup.get('toscaFunctionType').value === ToscaFunctionType.CONCAT;
179     }
180
181     isGetFunctionSelected(): boolean {
182         return this.isGetInputSelected() || this.isGetPropertySelected() || this.isGetAttributeSelected();
183     }
184
185     isYamlFunctionSelected(): boolean {
186         return this.formGroup.get('toscaFunctionType').value === ToscaFunctionType.YAML;
187     }
188
189     onClearValues(): void {
190         this.resetForm();
191     }
192
193     showClearButton(): boolean {
194         return this.allowClear && this.toscaFunctionTypeForm.value;
195     }
196
197     onConcatFunctionValidityChange(validationEvent: ToscaConcatFunctionValidationEvent): void {
198         if (validationEvent.isValid) {
199             this.toscaFunctionForm.setValue(validationEvent.toscaConcatFunction);
200         } else {
201             this.toscaFunctionForm.setValue(undefined);
202         }
203     }
204
205     onGetFunctionValidityChange(validationEvent: ToscaGetFunctionValidationEvent): void {
206         if (validationEvent.isValid) {
207             this.toscaFunctionForm.setValue(validationEvent.toscaGetFunction);
208         } else {
209             this.toscaFunctionForm.setValue(undefined);
210         }
211     }
212
213     onYamlFunctionValidityChange(validationEvent: YamlFunctionValidationEvent): void {
214         if (validationEvent.isValid) {
215             this.toscaFunctionForm.setValue(validationEvent.value);
216         } else {
217             this.toscaFunctionForm.setValue(undefined);
218         }
219     }
220
221     onFunctionTypeChange(): void {
222         this.toscaFunction = undefined;
223         this.toscaFunctionForm.reset();
224     }
225
226     private emitValidityChange(): void {
227         const isValid: boolean = this.validate();
228         this.onValidityChange.emit({
229             isValid: isValid,
230             toscaFunction: isValid ? this.buildFunctionFromForm() : undefined
231         });
232     }
233
234     private buildFunctionFromForm(): ToscaFunction {
235         if (!this.toscaFunctionTypeForm.value) {
236             return undefined;
237         }
238         if (this.isConcatSelected()) {
239             return new ToscaConcatFunction(this.toscaFunctionForm.value);
240         }
241         if (this.isGetFunctionSelected()) {
242             return new ToscaGetFunction(this.toscaFunctionForm.value);
243         }
244         if (this.isYamlFunctionSelected()) {
245             return new YamlFunction(this.toscaFunctionForm.value);
246         }
247
248         console.error(`Function ${this.toscaFunctionTypeForm.value} not supported`);
249     }
250 }
251
252 export class ToscaFunctionValidationEvent {
253     isValid: boolean;
254     toscaFunction: ToscaFunction;
255 }