4a68de26bc00cbb506df2866c772f5cba5ef87e3
[sdc.git] / catalog-ui / src / app / ng2 / pages / composition / interface-operatons / operation-creator / interface-operation-handler.component.ts
1 /*
2 * ============LICENSE_START=======================================================
3 * SDC
4 * ================================================================================
5 *  Copyright (C) 2021 Nordix Foundation. All rights reserved.
6 *  ================================================================================
7 *  Licensed under the Apache License, Version 2.0 (the "License");
8 *  you may not use this file except in compliance with the License.
9 *  You may obtain a copy of the License at
10 *
11 *        http://www.apache.org/licenses/LICENSE-2.0
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 import {Component, EventEmitter, Output, ViewChild} from '@angular/core';
22 import {UIInterfaceModel} from "../interface-operations.component";
23 import {InputOperationParameter, InterfaceOperationModel, IOperationParamsList} from "../../../../../models/interfaceOperation";
24 import {TranslateService} from "../../../../shared/translator/translate.service";
25 import {DropdownValue} from "../../../../components/ui/form-components/dropdown/ui-element-dropdown.component";
26 import {ArtifactModel} from "../../../../../models/artifacts";
27 import {PropertyBEModel} from "../../../../../models/properties-inputs/property-be-model";
28 import {PropertyParamRowComponent} from "./property-param-row/property-param-row.component";
29 import {PropertyFEModel} from "../../../../../models/properties-inputs/property-fe-model";
30 import {IDropDownOption} from 'onap-ui-angular';
31 import {ComponentServiceNg2} from "../../../../services/component-services/component.service";
32 import {DropDownComponent} from "onap-ui-angular/dist/form-elements/dropdown/dropdown.component";
33 import {DataTypeService} from "../../../../services/data-type.service";
34 import {Observable} from "rxjs/Observable";
35 import {DataTypeModel} from "../../../../../models/data-types";
36 import {InstanceFeDetails} from "../../../../../models/instance-fe-details";
37 import {TopologyTemplateService} from "app/ng2/services/component-services/topology-template.service";
38 import {CustomToscaFunction} from "../../../../../models/default-custom-functions";
39
40 @Component({
41     selector: 'operation-handler',
42     templateUrl: './interface-operation-handler.component.html',
43     styleUrls: ['./interface-operation-handler.component.less'],
44     providers: [TranslateService]
45 })
46 export class InterfaceOperationHandlerComponent {
47
48     @Output('propertyChanged') emitter: EventEmitter<PropertyFEModel> = new EventEmitter<PropertyFEModel>();
49     @ViewChild('interfaceOperationDropDown') interfaceOperationDropDown: DropDownComponent;
50
51     input: {
52         componentInstanceMap: Map<string, InstanceFeDetails>;
53         toscaArtifactTypes: Array<DropdownValue>;
54         selectedInterface: UIInterfaceModel;
55         selectedInterfaceOperation: InterfaceOperationModel;
56         validityChangedCallback: Function;
57         isViewOnly: boolean;
58         isEdit: boolean;
59         validImplementationProps:boolean;
60         modelName: string;
61     };
62
63     dataTypeMap$: Observable<Map<string, DataTypeModel>>;
64     dataTypeMap: Map<string, DataTypeModel>;
65     interfaceType: string;
66     artifactVersion: string;
67     artifactName: string;
68     interfaceOperationName: string;
69     operationToUpdate: InterfaceOperationModel;
70     inputs: Array<InputOperationParameter> = [];
71     properties: Array<PropertyParamRowComponent> = [];
72     isLoading: boolean = false;
73     isViewOnly: boolean;
74     isEdit: boolean;
75     validImplementationProps:boolean;
76     interfaceTypes: Array<DropdownValue> = [];
77     interfaceTypeOptions: Array<DropDownOption> = [];
78     selectedInterfaceType: DropDownOption = undefined;
79     interfaceOperationMap: Map<string, Array<string>> = new Map<string, Array<string>>();
80     interfaceOperationOptions: Array<DropDownOption> = [];
81     selectedInterfaceOperation: DropDownOption = undefined;
82     modelName: string;
83     toscaArtifactTypeSelected: string;
84     toscaArtifactTypeProperties: Array<PropertyBEModel> = [];
85     artifactTypeProperties: Array<InputOperationParameter> = [];
86     toscaArtifactTypes: Array<DropdownValue> = [];
87     componentInstanceMap: Map<string, InstanceFeDetails>;
88     customToscaFunctions: Array<CustomToscaFunction>;
89     enableAddArtifactImplementation: boolean;
90     propertyValueValid: boolean = true;
91     inputTypeOptions: any[];
92
93     constructor(private dataTypeService: DataTypeService,
94                 private componentServiceNg2: ComponentServiceNg2,
95                 private topologyTemplateService: TopologyTemplateService) {
96     }
97
98     ngOnInit() {
99         this.isViewOnly = this.input.isViewOnly;
100         this.isEdit = this.input.isEdit;
101         this.validImplementationProps = this.input.validImplementationProps;
102         this.componentInstanceMap =  this.input.componentInstanceMap ? this.input.componentInstanceMap : null;
103         this.interfaceType = this.input.selectedInterface.type;
104         this.operationToUpdate = new InterfaceOperationModel(this.input.selectedInterfaceOperation);
105         this.operationToUpdate.interfaceId = this.input.selectedInterface.uniqueId;
106         this.operationToUpdate.interfaceType = this.input.selectedInterface.type;
107         this.modelName = this.input.modelName;
108         this.initCustomToscaFunctions();
109         this.initInputs();
110         this.removeImplementationQuote();
111         this.loadInterfaceOperationImplementation();
112
113         this.dataTypeMap$ = new Observable<Map<string, DataTypeModel>>(subscriber => {
114             this.dataTypeService.findAllDataTypesByModel(this.modelName)
115             .then((dataTypesMap: Map<string, DataTypeModel>) => {
116                 subscriber.next(dataTypesMap);
117             });
118         });
119         this.dataTypeMap$.subscribe(value => {
120             this.dataTypeMap = value;
121         });
122     }
123
124     private initInputs() {
125         if (!this.operationToUpdate.inputs) {
126             this.operationToUpdate.inputs = new class implements IOperationParamsList {
127                 listToscaDataDefinition: Array<InputOperationParameter> = [];
128             }
129         }
130
131         this.inputs = Array.from(this.operationToUpdate.inputs.listToscaDataDefinition);
132         this.removeImplementationQuote();
133         this.loadInterfaceOperationImplementation();
134         this.loadInterfaceType();
135     }
136
137     private initCustomToscaFunctions() {
138         this.customToscaFunctions = [];
139         this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
140             if (data) {
141                 for (let customFunction of data) {
142                     this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
143                 }
144             }
145         });
146     }
147
148     private loadInterfaceType() {
149         this.componentServiceNg2.getInterfaceTypesByModel(this.modelName)
150         .subscribe(response => {
151             if (response) {
152                 this.interfaceOperationMap = new Map<string, Array<string>>();
153                 for (const interfaceType of Object.keys(response).sort()) {
154                     const operationList = response[interfaceType];
155                     operationList.sort();
156                     this.interfaceOperationMap.set(interfaceType, operationList);
157                     const operationDropDownOption: DropDownOption = new DropDownOption(interfaceType);
158                     this.interfaceTypeOptions.push(operationDropDownOption);
159                     if (this.interfaceType == interfaceType) {
160                         this.selectedInterfaceType = operationDropDownOption;
161                     }
162                 }
163                 this.loadInterfaceTypeOperations();
164             }
165         });
166     }
167
168     loadInterfaceTypeOperations() {
169         this.interfaceOperationOptions = new Array<DropDownOption>();
170         const interfaceOperationList = this.interfaceOperationMap.get(this.interfaceType);
171
172         if (interfaceOperationList) {
173             interfaceOperationList.forEach(operationName => {
174                 const operationOption = new DropDownOption(operationName, operationName);
175                 this.interfaceOperationOptions.push(operationOption);
176                 if (this.operationToUpdate.name == operationName) {
177                     this.selectedInterfaceOperation = operationOption
178                 }
179             });
180         }
181
182         this.interfaceOperationDropDown.allOptions = this.interfaceOperationOptions;
183     }
184
185     private loadInterfaceOperationImplementation() {
186         this.toscaArtifactTypes = this.input.toscaArtifactTypes;
187         if (this.operationToUpdate.implementation) {
188             this.artifactVersion = this.operationToUpdate.implementation.artifactVersion;
189             this.artifactName = this.operationToUpdate.implementation.artifactName;
190             this.toscaArtifactTypeProperties = this.operationToUpdate.implementation.properties;
191         }
192         this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
193         this.getArtifactTypesSelected();
194     }
195
196     onDescriptionChange = (value: any): void => {
197         this.operationToUpdate.description = value;
198     }
199
200     onURIChange(value: string | undefined) {
201         if(!this.operationToUpdate.implementation){
202             let artifact = new ArtifactModel();
203             this.operationToUpdate.implementation = artifact;
204         }
205         this.operationToUpdate.implementation.artifactName = value ? value : '';
206     }
207
208     onPropertyValueChange = (propertyValue) => {
209         this.emitter.emit(propertyValue);
210     }
211
212     onMarkToAddArtifactToImplementation(event: boolean) {
213         if (!event) {
214             this.toscaArtifactTypeSelected = undefined;
215             this.artifactVersion = undefined;
216             if (this.operationToUpdate.implementation.artifactType) {
217                 this.operationToUpdate.implementation.artifactVersion = '';
218                 this.operationToUpdate.implementation.artifactType = '';
219             }
220             this.toscaArtifactTypeProperties = undefined;
221             this.artifactTypeProperties = undefined;
222         } else {
223             this.getArtifactTypesSelected();
224         }
225         this.enableAddArtifactImplementation = event;
226     }
227
228     onSelectToscaArtifactType(type: IDropDownOption) {
229         if (type) {
230             let toscaArtifactType = type.value;
231             let artifact = new ArtifactModel();
232             artifact.artifactName = this.operationToUpdate.implementation.artifactName;
233             artifact.artifactVersion = this.operationToUpdate.implementation.artifactVersion;
234             artifact.artifactType = toscaArtifactType.type;
235             artifact.properties = toscaArtifactType.properties;
236             this.toscaArtifactTypeProperties = artifact.properties;
237             this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
238             this.toscaArtifactTypeSelected = artifact.artifactType;
239             this.operationToUpdate.implementation = artifact;
240             this.getArtifactTypesSelected();
241         }
242     }
243
244     onArtifactVersionChange(value: string | undefined) {
245             this.operationToUpdate.implementation.artifactVersion = value ? value : '';
246     }
247
248     onAddInput(inputOperationParameter: InputOperationParameter) {
249         this.addInput(inputOperationParameter);
250     }
251
252     propertyValueValidation = (propertyValue): void => {
253         this.onPropertyValueChange(propertyValue);
254         this.propertyValueValid = propertyValue.isValid;
255     }
256
257     onRemoveInput = (inputParam: InputOperationParameter): void => {
258         let index = this.inputs.indexOf(inputParam);
259         this.inputs.splice(index, 1);
260     }
261
262     private removeImplementationQuote(): void {
263         if (this.operationToUpdate.implementation) {
264             if (!this.operationToUpdate.implementation
265                 || !this.operationToUpdate.implementation.artifactName) {
266                 return;
267             }
268
269             let implementation = this.operationToUpdate.implementation.artifactName.trim();
270
271             if (implementation.startsWith("'") && implementation.endsWith("'")) {
272                 this.operationToUpdate.implementation.artifactName = implementation.slice(1, -1);
273             }
274         }
275     }
276
277     private getArtifactTypesSelected() {
278         if (this.operationToUpdate.implementation && this.operationToUpdate.implementation.artifactType) {
279             this.artifactName =
280                 this.artifactName ? this.artifactName : this.operationToUpdate.implementation.artifactName;
281             this.toscaArtifactTypeSelected = this.operationToUpdate.implementation.artifactType;
282             this.artifactVersion =
283                 this.artifactVersion ? this.artifactVersion : this.operationToUpdate.implementation.artifactVersion;
284             this.toscaArtifactTypeProperties = this.operationToUpdate.implementation.properties;
285             this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
286             this.enableAddArtifactImplementation = true;
287         }
288     }
289
290     toDropDownOption(val: string) {
291         return { value : val, label: val };
292     }
293
294     /**
295      * Handles the input value change event.
296      * @param changedInput the changed input
297      */
298     onInputValueChange(changedInput: InputOperationParameter) {
299         if (changedInput.value instanceof Object) {
300             changedInput.value = JSON.stringify(changedInput.value);
301         }
302         const inputOperationParameter = this.inputs.find(value => value.name == changedInput.name);
303         inputOperationParameter.toscaFunction = null;
304         inputOperationParameter.value = changedInput.value;
305         inputOperationParameter.subPropertyToscaFunctions = changedInput.subPropertyToscaFunctions;
306         if (changedInput.isToscaFunction()) {
307             inputOperationParameter.toscaFunction = changedInput.toscaFunction;
308             inputOperationParameter.value = changedInput.toscaFunction.buildValueString();
309         }
310     }
311
312     onArtifactPropertyValueChange(changedProperty: InputOperationParameter) {
313         const property = this.toscaArtifactTypeProperties.find(artifactProperty => artifactProperty.name == changedProperty.name);
314         if (changedProperty.value instanceof Object) {
315             changedProperty.value = JSON.stringify(changedProperty.value);
316         }
317         property.toscaFunction = null;
318         property.value = changedProperty.value;
319         if (changedProperty.isToscaFunction()) {
320             property.toscaFunction = changedProperty.toscaFunction;
321             property.value = changedProperty.toscaFunction.buildValueString();
322         }
323     }
324
325     implementationPropsValidityChange(validImplementationProps: boolean) {
326         this.validImplementationProps = validImplementationProps;
327     }
328
329     /**
330      * Handles the add input event.
331      * @param input the input to add
332      * @private
333      */
334     private addInput(input: InputOperationParameter) {
335         this.operationToUpdate.inputs.listToscaDataDefinition.push(input);
336         this.inputs = Array.from(this.operationToUpdate.inputs.listToscaDataDefinition);
337     }
338
339     /**
340      * Return a list with current input names.
341      */
342     collectInputNames() {
343         return this.inputs.map((input) => input.name);
344     }
345
346     /**
347      * Handles the delete input event.
348      * @param inputName the name of the input to be deleted
349      */
350     onInputDelete(inputName: string) {
351         const currentInputs = this.operationToUpdate.inputs.listToscaDataDefinition;
352         const input1 = currentInputs.find(value => value.name === inputName);
353         const indexOfInput = currentInputs.indexOf(input1);
354         if (indexOfInput === -1) {
355             console.error(`Could not delete input '${inputName}'. Input not found.`);
356             return;
357         }
358         currentInputs.splice(currentInputs.indexOf(input1), 1);
359         this.inputs = Array.from(currentInputs);
360     }
361
362     private convertArtifactsPropertiesToInput(): Array<InputOperationParameter> {
363         if (!this.toscaArtifactTypeProperties) {
364             return [];
365         }
366         const inputList: Array<InputOperationParameter> = [];
367         this.toscaArtifactTypeProperties.forEach(property => {
368             const input = new InputOperationParameter();
369             input.name = property.name;
370             input.type = property.type;
371             input.schema = property.schema;
372             input.toscaDefaultValue = property.defaultValue;
373             input.value = property.value;
374             input.toscaFunction = property.toscaFunction;
375             inputList.push(input);
376         });
377         return inputList;
378     }
379
380     onSelectInterface(dropDownOption: DropDownOption) {
381         if (dropDownOption) {
382             this.setInterfaceType(dropDownOption);
383         } else {
384             this.setInterfaceType(undefined);
385         }
386         this.setInterfaceOperation(undefined);
387         this.interfaceOperationDropDown.selectOption({} as IDropDownOption);
388         this.loadInterfaceTypeOperations();
389     }
390
391     onSelectOperation(dropDownOption: DropDownOption) {
392         if (this.selectedInterfaceType && dropDownOption) {
393             this.setInterfaceOperation(dropDownOption);
394         }
395     }
396
397     private setInterfaceType(dropDownOption: DropDownOption) {
398         this.selectedInterfaceType = dropDownOption ? dropDownOption : undefined;
399         this.interfaceType = dropDownOption ? dropDownOption.value : undefined;
400         this.operationToUpdate.interfaceType = dropDownOption ? dropDownOption.value : undefined;
401         this.operationToUpdate.interfaceId = dropDownOption ? dropDownOption.value : undefined;
402     }
403
404     private setInterfaceOperation(dropDownOption: DropDownOption) {
405         this.operationToUpdate.name = dropDownOption ? dropDownOption.value : undefined;
406         this.operationToUpdate.operationType = dropDownOption ? dropDownOption.value : undefined;
407         this.selectedInterfaceOperation = dropDownOption ? dropDownOption : undefined;
408     }
409 }
410
411 class DropDownOption implements IDropDownOption {
412     value: string;
413     label: string;
414
415     constructor(value: string, label?: string) {
416         this.value = value;
417         this.label = label || value;
418     }
419 }