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