Update Interface definition on VFC
[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
22 import {Component, EventEmitter, Input, Output} from '@angular/core';
23 import {UIInterfaceModel} from "../interface-operations.component";
24 import {InputOperationParameter, InterfaceOperationModel, IOperationParamsList} from "../../../../../models/interfaceOperation";
25 import {TranslateService} from "../../../../shared/translator/translate.service";
26 import {IDropDownOption} from "onap-ui-angular/dist/form-elements/dropdown/dropdown-models";
27 import {DropdownValue} from "../../../../components/ui/form-components/dropdown/ui-element-dropdown.component";
28 import {ArtifactModel} from "../../../../../models/artifacts";
29 import {PropertyBEModel} from "../../../../../models/properties-inputs/property-be-model";
30 import {PropertyParamRowComponent} from "./property-param-row/property-param-row.component";
31 import {PropertyFEModel} from "../../../../../models/properties-inputs/property-fe-model";
32 import {DataTypeService} from "../../../../services/data-type.service";
33 import {Observable} from "rxjs/Observable";
34 import {DataTypeModel} from "../../../../../models/data-types";
35
36 @Component({
37     selector: 'operation-handler',
38     templateUrl: './interface-operation-handler.component.html',
39     styleUrls: ['./interface-operation-handler.component.less'],
40     providers: [TranslateService]
41 })
42 export class InterfaceOperationHandlerComponent {
43
44     @Input() private modelName: string;
45     @Output('propertyChanged') emitter: EventEmitter<PropertyFEModel> = new EventEmitter<PropertyFEModel>();
46     input: {
47         toscaArtifactTypes: Array<DropdownValue>;
48         selectedInterface: UIInterfaceModel;
49         selectedInterfaceOperation: InterfaceOperationModel;
50         validityChangedCallback: Function;
51         isViewOnly: boolean;
52         interfaceTypesMap: Map<string, string[]>;
53     };
54
55     dataTypeMap$: Observable<Map<string, DataTypeModel>>;
56     dataTypeMap: Map<string, DataTypeModel>;
57     interfaceType: string;
58     artifactVersion: string;
59     artifactName: string;
60     interfaceOperationName: string;
61     operationToUpdate: InterfaceOperationModel;
62     inputs: Array<InputOperationParameter> = [];
63     properties: Array<PropertyParamRowComponent> = [];
64     isLoading: boolean = false;
65     readonly: boolean;
66     isViewOnly: boolean;
67     interfaceTypes: Array<DropdownValue> = [];
68     interfaceOperations: Array<DropdownValue> = [];
69
70     interfaceTypesMap: Map<string, string[]>;
71
72     toscaArtifactTypeSelected: string;
73     toscaArtifactTypeProperties: Array<PropertyBEModel> = [];
74     artifactTypeProperties: Array<InputOperationParameter> = [];
75
76     toscaArtifactTypes: Array<DropdownValue> = [];
77
78     enableAddArtifactImplementation: boolean;
79
80     propertyValueValid: boolean = true;
81     inputTypeOptions: any[];
82
83     constructor(private dataTypeService: DataTypeService) {
84         this.dataTypeMap$ = new Observable<Map<string, DataTypeModel>>(subscriber => {
85             this.dataTypeService.findAllDataTypesByModel(this.modelName)
86             .then((dataTypesMap: Map<string, DataTypeModel>) => {
87                 subscriber.next(dataTypesMap);
88             });
89         });
90         this.dataTypeMap$.subscribe(value => {
91             this.dataTypeMap = value;
92         });
93
94     }
95
96     ngOnInit() {
97         this.isViewOnly = this.input.isViewOnly;
98         this.interfaceType = this.input.selectedInterface.type;
99         this.operationToUpdate = this.input.selectedInterfaceOperation;
100         this.operationToUpdate.interfaceId = this.input.selectedInterface.uniqueId;
101         this.operationToUpdate.interfaceType = this.input.selectedInterface.type;
102         this.initInputs();
103         this.removeImplementationQuote();
104         this.validityChanged();
105         this.loadInterfaceOperationImplementation();
106     }
107
108     private initInputs() {
109         if (!this.operationToUpdate.inputs) {
110             this.operationToUpdate.inputs = new class implements IOperationParamsList {
111                 listToscaDataDefinition: Array<InputOperationParameter> = [];
112             }
113         }
114
115         this.inputs = Array.from(this.operationToUpdate.inputs.listToscaDataDefinition);
116         this.interfaceTypesMap = this.input.interfaceTypesMap;
117         this.loadInterfaceTypesAndOperations();
118         this.removeImplementationQuote();
119         this.validityChanged();
120         this.loadInterfaceOperationImplementation();
121     }
122
123     private loadInterfaceOperationImplementation() {
124         this.toscaArtifactTypes = this.input.toscaArtifactTypes;
125         this.artifactVersion = this.operationToUpdate.implementation.artifactVersion;
126         this.artifactName = this.operationToUpdate.implementation.artifactName;
127         this.toscaArtifactTypeProperties = this.operationToUpdate.implementation.properties;
128         this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
129         this.getArtifactTypesSelected();
130     }
131
132     onDescriptionChange = (value: any): void => {
133         this.operationToUpdate.description = value;
134     }
135
136     onImplementationNameChange(value: any) {
137         this.readonly = true
138         if (value || value === '') {
139             let artifact = new ArtifactModel();
140             artifact.artifactName = value;
141             this.operationToUpdate.implementation = artifact;
142             this.enableAddArtifactImplementation = false;
143             this.readonly = false;
144         }
145     }
146
147     onPropertyValueChange = (propertyValue) => {
148         this.emitter.emit(propertyValue);
149     }
150
151     onMarkToAddArtifactToImplementation(event: any) {
152         if (!event) {
153             this.toscaArtifactTypeSelected = undefined;
154             this.artifactVersion = undefined;
155             if (this.operationToUpdate.implementation.artifactType) {
156                 this.operationToUpdate.implementation.artifactName = '';
157                 this.artifactName = undefined;
158             }
159             this.toscaArtifactTypeProperties = undefined;
160             this.artifactTypeProperties = undefined;
161         } else {
162             this.getArtifactTypesSelected();
163         }
164         this.enableAddArtifactImplementation = event;
165         this.validateRequiredField();
166     }
167
168     onSelectToscaArtifactType(type: IDropDownOption) {
169         if (type) {
170             let toscaArtifactType = type.value;
171             let artifact = new ArtifactModel();
172             this.artifactName = undefined;
173             this.artifactVersion = undefined;
174             artifact.artifactType = toscaArtifactType.type;
175             artifact.properties = toscaArtifactType.properties;
176             this.toscaArtifactTypeProperties = artifact.properties;
177             this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
178             this.toscaArtifactTypeSelected = artifact.artifactType;
179             this.operationToUpdate.implementation = artifact;
180             this.getArtifactTypesSelected();
181         }
182         this.validateRequiredField();
183     }
184
185     onArtifactFileChange(value: any) {
186         if (value) {
187             this.operationToUpdate.implementation.artifactName = value;
188         }
189         this.validateRequiredField();
190     }
191
192     onArtifactVersionChange(value: any) {
193         if (value) {
194             this.operationToUpdate.implementation.artifactVersion = value;
195         }
196     }
197
198     onAddInput(inputOperationParameter: InputOperationParameter) {
199         this.addInput(inputOperationParameter);
200         this.validityChanged();
201     }
202
203     propertyValueValidation = (propertyValue): void => {
204         this.onPropertyValueChange(propertyValue);
205         this.propertyValueValid = propertyValue.isValid;
206         this.readonly = !this.propertyValueValid;
207         this.validateRequiredField();
208     }
209
210     onRemoveInput = (inputParam: InputOperationParameter): void => {
211         let index = this.inputs.indexOf(inputParam);
212         this.inputs.splice(index, 1);
213         this.validityChanged();
214     }
215
216     private removeImplementationQuote(): void {
217         if (this.operationToUpdate.implementation) {
218             if (!this.operationToUpdate.implementation
219                 || !this.operationToUpdate.implementation.artifactName) {
220                 return;
221             }
222
223             let implementation = this.operationToUpdate.implementation.artifactName.trim();
224
225             if (implementation.startsWith("'") && implementation.endsWith("'")) {
226                 this.operationToUpdate.implementation.artifactName = implementation.slice(1, -1);
227             }
228         }
229     }
230
231     validityChanged = () => {
232         let validState = this.checkFormValidForSubmit();
233         this.input.validityChangedCallback(validState);
234         if (validState) {
235             this.readonly = false;
236         }
237     }
238
239     private getArtifactTypesSelected() {
240         if (this.operationToUpdate.implementation && this.operationToUpdate.implementation.artifactType) {
241             this.artifactName = this.operationToUpdate.implementation.artifactName;
242             this.toscaArtifactTypeSelected = this.operationToUpdate.implementation.artifactType;
243             this.artifactVersion = this.operationToUpdate.implementation.artifactVersion;
244             this.toscaArtifactTypeProperties = this.operationToUpdate.implementation.properties;
245             this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
246             this.enableAddArtifactImplementation = true;
247         }
248         this.validateRequiredField();
249     }
250
251     validateRequiredField = () => {
252         this.readonly = true;
253         const isRequiredFieldSelected = this.isRequiredFieldsSelected();
254         this.input.validityChangedCallback(isRequiredFieldSelected);
255         if (isRequiredFieldSelected && this.propertyValueValid) {
256             this.readonly = false;
257         }
258     }
259
260     private isRequiredFieldsSelected() {
261         return this.toscaArtifactTypeSelected && this.artifactName;
262     }
263
264     private checkFormValidForSubmit = (): boolean => {
265         return this.operationToUpdate.name && this.artifactName && this.isParamsValid();
266     }
267
268     private isParamsValid = (): boolean => {
269         const isInputValid = (input) => input.name && input.inputId && input.type;
270         const isValid = this.inputs.every(isInputValid);
271         if (!isValid) {
272             this.readonly = true;
273         }
274         return isValid;
275     }
276
277     toDropDownOption(val: string) {
278         return { value : val, label: val };
279     }
280
281     /**
282      * Handles the input value change event.
283      * @param changedInput the changed input
284      */
285     onInputValueChange(changedInput: InputOperationParameter) {
286         if (changedInput.value instanceof Object) {
287             changedInput.value = JSON.stringify(changedInput.value);
288         }
289         const inputOperationParameter = this.inputs.find(value => value.name == changedInput.name);
290         inputOperationParameter.value = changedInput.value;
291     }
292
293     onArtifactPropertyValueChange(changedProperty: InputOperationParameter) {
294         if (changedProperty.value instanceof Object) {
295             changedProperty.value = JSON.stringify(changedProperty.value);
296         }
297         const property = this.toscaArtifactTypeProperties.find(artifactProperty => artifactProperty.name == changedProperty.name);
298         property.value = changedProperty.value;
299     }
300
301     /**
302      * Handles the add input event.
303      * @param input the input to add
304      * @private
305      */
306     private addInput(input: InputOperationParameter) {
307         this.operationToUpdate.inputs.listToscaDataDefinition.push(input);
308         this.inputs = Array.from(this.operationToUpdate.inputs.listToscaDataDefinition);
309     }
310
311     /**
312      * Return a list with current input names.
313      */
314     collectInputNames() {
315         return this.inputs.map((input) => input.name);
316     }
317
318     /**
319      * Handles the delete input event.
320      * @param inputName the name of the input to be deleted
321      */
322     onInputDelete(inputName: string) {
323         const currentInputs = this.operationToUpdate.inputs.listToscaDataDefinition;
324         const input1 = currentInputs.find(value => value.name === inputName);
325         const indexOfInput = currentInputs.indexOf(input1);
326         if (indexOfInput === -1) {
327             console.error(`Could delete input '${inputName}'. Input not found.`);
328             return;
329         }
330         currentInputs.splice(currentInputs.indexOf(input1), 1);
331         this.inputs = Array.from(currentInputs);
332     }
333
334     private convertArtifactsPropertiesToInput(): Array<InputOperationParameter> {
335         if (!this.toscaArtifactTypeProperties) {
336             return [];
337         }
338         const inputList: Array<InputOperationParameter> = [];
339         this.toscaArtifactTypeProperties.forEach(property => {
340             const input = new InputOperationParameter();
341             input.name = property.name;
342             input.type = property.type;
343             input.schema = property.schema;
344             input.toscaDefaultValue = property.defaultValue;
345             input.value = property.value;
346             inputList.push(input);
347         });
348         return inputList;
349     }
350
351     private loadInterfaceTypesAndOperations() {
352         console.log("loadInterfaceTypesAndOperations ", this.interfaceTypesMap.keys());
353
354         Array.from(this.interfaceTypesMap.keys()).forEach(value => this.interfaceTypes.push(new DropdownValue(value, value)));
355         console.log("loadInterfaceTypesAndOperations interfaceType ", this.interfaceTypes);
356     }
357
358 }