2 * ============LICENSE_START=======================================================
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
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
21 import {Component, EventEmitter, Output, ViewChild} from '@angular/core';
22 import { FormControl } from '@angular/forms';
23 import {UIInterfaceModel} from "../interface-operations.component";
26 IActivityParameterList,
28 InputOperationParameter,
29 InterfaceOperationModel,
34 } from "../../../../../models/interfaceOperation";
35 import {TranslateService} from "../../../../shared/translator/translate.service";
36 import {DropdownValue} from "../../../../components/ui/form-components/dropdown/ui-element-dropdown.component";
37 import {ArtifactModel} from "../../../../../models/artifacts";
38 import {PropertyBEModel} from "../../../../../models/properties-inputs/property-be-model";
39 import {PropertyParamRowComponent} from "./property-param-row/property-param-row.component";
40 import {PropertyFEModel} from "../../../../../models/properties-inputs/property-fe-model";
41 import {IDropDownOption} from 'onap-ui-angular';
42 import {ComponentServiceNg2} from "../../../../services/component-services/component.service";
43 import {DropDownComponent} from "onap-ui-angular/dist/form-elements/dropdown/dropdown.component";
44 import {DataTypeService} from "../../../../services/data-type.service";
45 import {Observable} from "rxjs/Observable";
46 import {DataTypeModel} from "../../../../../models/data-types";
47 import {InstanceFeDetails} from "../../../../../models/instance-fe-details";
48 import {TopologyTemplateService} from "app/ng2/services/component-services/topology-template.service";
49 import {CustomToscaFunction} from "../../../../../models/default-custom-functions";
52 selector: 'operation-handler',
53 templateUrl: './interface-operation-handler.component.html',
54 styleUrls: ['./interface-operation-handler.component.less'],
55 providers: [TranslateService]
57 export class InterfaceOperationHandlerComponent {
59 @Output('propertyChanged') emitter: EventEmitter<PropertyFEModel> = new EventEmitter<PropertyFEModel>();
60 @ViewChild('interfaceOperationDropDown') interfaceOperationDropDown: DropDownComponent;
63 componentInstanceMap: Map<string, InstanceFeDetails>;
64 toscaArtifactTypes: Array<DropdownValue>;
65 selectedInterface: UIInterfaceModel;
66 selectedInterfaceOperation: InterfaceOperationModel;
67 validityChangedCallback: Function;
70 validImplementationProps: boolean;
71 validMilestoneActivities: boolean;
72 validMilestoneFilters: boolean;
76 dataTypeMap$: Observable<Map<string, DataTypeModel>>;
77 dataTypeMap: Map<string, DataTypeModel>;
78 interfaceType: string;
79 artifactVersion: string;
81 interfaceOperationName: string;
82 operationToUpdate: InterfaceOperationModel;
83 inputs: Array<InputOperationParameter> = [];
84 properties: Array<PropertyParamRowComponent> = [];
85 isLoading: boolean = false;
88 validImplementationProps: boolean;
89 validMilestoneActivities: boolean;
90 validMilestoneFilters: boolean;
91 interfaceTypes: Array<DropdownValue> = [];
92 interfaceTypeOptions: Array<DropDownOption> = [];
93 selectedInterfaceType: DropDownOption = undefined;
94 interfaceOperationMap: Map<string, Array<string>> = new Map<string, Array<string>>();
95 interfaceOperationOptions: Array<DropDownOption> = [];
96 selectedInterfaceOperation: DropDownOption = undefined;
98 toscaArtifactTypeSelected: string;
99 toscaArtifactTypeProperties: Array<PropertyBEModel> = [];
100 artifactTypeProperties: Array<InputOperationParameter> = [];
101 toscaArtifactTypes: Array<DropdownValue> = [];
102 componentInstanceMap: Map<string, InstanceFeDetails>;
103 customToscaFunctions: Array<CustomToscaFunction>;
104 enableAddArtifactImplementation: boolean;
105 propertyValueValid: boolean = true;
106 showActivities: boolean = false;
107 inputTypeOptions: any[];
108 timeoutValue = new FormControl('');
109 timeoutType = new FormControl('');
110 invalidMilestones: string[] = [];
112 milestones = Object.keys(MilestoneEnum)
113 .map(key => MilestoneEnum[key]);
115 constructor(private dataTypeService: DataTypeService,
116 private componentServiceNg2: ComponentServiceNg2,
117 private topologyTemplateService: TopologyTemplateService) {
121 this.isViewOnly = this.input.isViewOnly;
122 this.isEdit = this.input.isEdit;
123 this.validImplementationProps = this.input.validImplementationProps;
124 this.validMilestoneActivities = this.input.validMilestoneActivities;
125 this.validMilestoneFilters = this.input.validMilestoneFilters;
126 this.componentInstanceMap = this.input.componentInstanceMap ? this.input.componentInstanceMap : null;
127 this.interfaceType = this.input.selectedInterface.type;
128 this.operationToUpdate = new InterfaceOperationModel(this.input.selectedInterfaceOperation);
129 this.operationToUpdate.interfaceId = this.input.selectedInterface.uniqueId;
130 this.operationToUpdate.interfaceType = this.input.selectedInterface.type;
131 this.modelName = this.input.modelName;
132 this.timeoutType.setValue('sec');
133 if (this.operationToUpdate.implementation && this.operationToUpdate.implementation.timeout != null) {
134 this.timeoutValue.setValue(this.operationToUpdate.implementation.timeout);
135 let timeout = this.timeoutValue.value / 3600;
136 if (Number.isInteger(timeout)) {
137 if (timeout > 23 && Number.isInteger(timeout / 24)) {
138 this.timeoutValue.setValue(timeout / 24);
139 this.timeoutType.setValue("day");
141 this.timeoutValue.setValue(timeout);
142 this.timeoutType.setValue("hour");
144 } else if (Number.isInteger(timeout / 24)) {
145 this.timeoutValue.setValue(timeout / 24);
146 this.timeoutType.setValue("day");
149 if (!this.operationToUpdate.milestones) {
150 this.operationToUpdate.milestones = {};
152 this.initCustomToscaFunctions();
154 this.removeImplementationQuote();
155 this.loadInterfaceOperationImplementation();
157 this.dataTypeMap$ = new Observable<Map<string, DataTypeModel>>(subscriber => {
158 this.dataTypeService.findAllDataTypesByModel(this.modelName)
159 .then((dataTypesMap: Map<string, DataTypeModel>) => {
160 subscriber.next(dataTypesMap);
161 this.showActivities = dataTypesMap.has("tosca.dataTypes.tmf.milestoneJeopardyData");
164 this.dataTypeMap$.subscribe(value => {
165 this.dataTypeMap = value;
169 private initInputs() {
170 if (!this.operationToUpdate.inputs) {
171 this.operationToUpdate.inputs = new class implements IOperationParamsList {
172 listToscaDataDefinition: Array<InputOperationParameter> = [];
176 this.inputs = Array.from(this.operationToUpdate.inputs.listToscaDataDefinition);
177 this.removeImplementationQuote();
178 this.loadInterfaceOperationImplementation();
179 this.loadInterfaceType();
182 private initCustomToscaFunctions() {
183 this.customToscaFunctions = [];
184 this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
186 for (let customFunction of data) {
187 this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
193 private loadInterfaceType() {
194 this.componentServiceNg2.getInterfaceTypesByModel(this.modelName)
195 .subscribe(response => {
197 this.interfaceOperationMap = new Map<string, Array<string>>();
198 for (const interfaceType of Object.keys(response).sort()) {
199 const operationList = response[interfaceType];
200 operationList.sort();
201 this.interfaceOperationMap.set(interfaceType, operationList);
202 const operationDropDownOption: DropDownOption = new DropDownOption(interfaceType);
203 this.interfaceTypeOptions.push(operationDropDownOption);
204 if (this.interfaceType == interfaceType) {
205 this.selectedInterfaceType = operationDropDownOption;
208 this.loadInterfaceTypeOperations();
213 loadInterfaceTypeOperations() {
214 this.interfaceOperationOptions = new Array<DropDownOption>();
215 const interfaceOperationList = this.interfaceOperationMap.get(this.interfaceType);
217 if (interfaceOperationList) {
218 interfaceOperationList.forEach(operationName => {
219 const operationOption = new DropDownOption(operationName, operationName);
220 this.interfaceOperationOptions.push(operationOption);
221 if (this.operationToUpdate.name == operationName) {
222 this.selectedInterfaceOperation = operationOption
227 this.interfaceOperationDropDown.allOptions = this.interfaceOperationOptions;
230 private loadInterfaceOperationImplementation() {
231 this.toscaArtifactTypes = this.input.toscaArtifactTypes;
232 if (this.operationToUpdate.implementation) {
233 this.artifactVersion = this.operationToUpdate.implementation.artifactVersion;
234 this.artifactName = this.operationToUpdate.implementation.artifactName;
235 this.toscaArtifactTypeProperties = this.operationToUpdate.implementation.properties;
237 this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
238 this.getArtifactTypesSelected();
241 onDescriptionChange = (value: any): void => {
242 this.operationToUpdate.description = value;
245 onURIChange(value: string | undefined) {
246 if(!this.operationToUpdate.implementation){
247 let artifact = new ArtifactModel();
248 this.operationToUpdate.implementation = artifact;
250 this.operationToUpdate.implementation.artifactName = value ? value : '';
253 onPropertyValueChange = (propertyValue) => {
254 this.emitter.emit(propertyValue);
257 onMarkToAddArtifactToImplementation(event: boolean) {
259 this.toscaArtifactTypeSelected = undefined;
260 this.artifactVersion = undefined;
261 if (this.operationToUpdate.implementation.artifactType) {
262 this.operationToUpdate.implementation.artifactVersion = '';
263 this.operationToUpdate.implementation.artifactType = '';
265 this.toscaArtifactTypeProperties = undefined;
266 this.artifactTypeProperties = undefined;
268 this.getArtifactTypesSelected();
270 this.enableAddArtifactImplementation = event;
273 onSelectToscaArtifactType(type: IDropDownOption) {
275 let toscaArtifactType = type.value;
276 let artifact = new ArtifactModel();
277 artifact.artifactName = this.operationToUpdate.implementation.artifactName;
278 artifact.artifactVersion = this.operationToUpdate.implementation.artifactVersion;
279 artifact.artifactType = toscaArtifactType.type;
280 artifact.properties = toscaArtifactType.properties;
281 this.toscaArtifactTypeProperties = artifact.properties;
282 this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
283 this.toscaArtifactTypeSelected = artifact.artifactType;
284 this.operationToUpdate.implementation = artifact;
285 this.getArtifactTypesSelected();
289 onArtifactVersionChange(value: string | undefined) {
290 this.operationToUpdate.implementation.artifactVersion = value ? value : '';
293 onAddInput(inputOperationParameter: InputOperationParameter) {
294 this.addInput(inputOperationParameter);
297 propertyValueValidation = (propertyValue): void => {
298 this.onPropertyValueChange(propertyValue);
299 this.propertyValueValid = propertyValue.isValid;
302 onRemoveInput = (inputParam: InputOperationParameter): void => {
303 let index = this.inputs.indexOf(inputParam);
304 this.inputs.splice(index, 1);
307 timeoutConversion = (): void => {
308 let timeout = this.timeoutValue.value;
309 if (timeout != null) {
310 if (this.timeoutType.value == null || this.timeoutType.value == 'sec') {
311 this.operationToUpdate.implementation.timeout = timeout;
314 if (this.timeoutType.value == 'hour') {
315 this.operationToUpdate.implementation.timeout = timeout * 3600;
316 } else if (this.timeoutType.value == 'day') {
317 this.operationToUpdate.implementation.timeout = (timeout * 24) * 3600;
322 private removeImplementationQuote(): void {
323 if (this.operationToUpdate.implementation) {
324 if (!this.operationToUpdate.implementation
325 || !this.operationToUpdate.implementation.artifactName) {
329 let implementation = this.operationToUpdate.implementation.artifactName.trim();
331 if (implementation.startsWith("'") && implementation.endsWith("'")) {
332 this.operationToUpdate.implementation.artifactName = implementation.slice(1, -1);
337 private getArtifactTypesSelected() {
338 if (this.operationToUpdate.implementation && this.operationToUpdate.implementation.artifactType) {
340 this.artifactName ? this.artifactName : this.operationToUpdate.implementation.artifactName;
341 this.toscaArtifactTypeSelected = this.operationToUpdate.implementation.artifactType;
342 this.artifactVersion =
343 this.artifactVersion ? this.artifactVersion : this.operationToUpdate.implementation.artifactVersion;
344 this.toscaArtifactTypeProperties = this.operationToUpdate.implementation.properties;
345 this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
346 this.enableAddArtifactImplementation = true;
350 toDropDownOption(val: string) {
351 return { value : val, label: val };
355 * Handles the input value change event.
356 * @param changedInput the changed input
358 onInputValueChange(changedInput: InputOperationParameter) {
359 if (changedInput.value instanceof Object) {
360 changedInput.value = JSON.stringify(changedInput.value);
362 const inputOperationParameter = this.inputs.find(value => value.name == changedInput.name);
363 inputOperationParameter.toscaFunction = null;
364 inputOperationParameter.value = changedInput.value;
365 inputOperationParameter.subPropertyToscaFunctions = changedInput.subPropertyToscaFunctions;
366 if (changedInput.isToscaFunction()) {
367 inputOperationParameter.toscaFunction = changedInput.toscaFunction;
368 inputOperationParameter.value = changedInput.toscaFunction.buildValueString();
372 onArtifactPropertyValueChange(changedProperty: InputOperationParameter) {
373 const property = this.toscaArtifactTypeProperties.find(artifactProperty => artifactProperty.name == changedProperty.name);
374 if (changedProperty.value instanceof Object) {
375 changedProperty.value = JSON.stringify(changedProperty.value);
377 property.toscaFunction = null;
378 property.value = changedProperty.value;
379 if (changedProperty.isToscaFunction()) {
380 property.toscaFunction = changedProperty.toscaFunction;
381 property.value = changedProperty.toscaFunction.buildValueString();
385 implementationPropsValidityChange(validImplementationProps: boolean) {
386 this.validImplementationProps = validImplementationProps;
390 * Handles the add input event.
391 * @param input the input to add
394 private addInput(input: InputOperationParameter) {
395 this.operationToUpdate.inputs.listToscaDataDefinition.push(input);
396 this.inputs = Array.from(this.operationToUpdate.inputs.listToscaDataDefinition);
400 * Return a list with current input names.
402 collectInputNames() {
403 return this.inputs.map((input) => input.name);
407 * Handles the delete input event.
408 * @param inputName the name of the input to be deleted
410 onInputDelete(inputName: string) {
411 const currentInputs = this.operationToUpdate.inputs.listToscaDataDefinition;
412 const input1 = currentInputs.find(value => value.name === inputName);
413 const indexOfInput = currentInputs.indexOf(input1);
414 if (indexOfInput === -1) {
415 console.error(`Could not delete input '${inputName}'. Input not found.`);
418 currentInputs.splice(currentInputs.indexOf(input1), 1);
419 this.inputs = Array.from(currentInputs);
422 private convertArtifactsPropertiesToInput(): Array<InputOperationParameter> {
423 if (!this.toscaArtifactTypeProperties) {
426 const inputList: Array<InputOperationParameter> = [];
427 this.toscaArtifactTypeProperties.forEach(property => {
428 const input = new InputOperationParameter();
429 input.name = property.name;
430 input.type = property.type;
431 input.schema = property.schema;
432 input.toscaDefaultValue = property.defaultValue;
433 input.value = property.value;
434 input.toscaFunction = property.toscaFunction;
435 inputList.push(input);
440 onSelectInterface(dropDownOption: DropDownOption) {
441 if (dropDownOption) {
442 this.setInterfaceType(dropDownOption);
444 this.setInterfaceType(undefined);
446 this.setInterfaceOperation(undefined);
447 this.interfaceOperationDropDown.selectOption({} as IDropDownOption);
448 this.loadInterfaceTypeOperations();
451 onSelectOperation(dropDownOption: DropDownOption) {
452 if (this.selectedInterfaceType && dropDownOption) {
453 this.setInterfaceOperation(dropDownOption);
457 private setInterfaceType(dropDownOption: DropDownOption) {
458 this.selectedInterfaceType = dropDownOption ? dropDownOption : undefined;
459 this.interfaceType = dropDownOption ? dropDownOption.value : undefined;
460 this.operationToUpdate.interfaceType = dropDownOption ? dropDownOption.value : undefined;
461 this.operationToUpdate.interfaceId = dropDownOption ? dropDownOption.value : undefined;
464 private setInterfaceOperation(dropDownOption: DropDownOption) {
465 this.operationToUpdate.name = dropDownOption ? dropDownOption.value : undefined;
466 this.operationToUpdate.operationType = dropDownOption ? dropDownOption.value : undefined;
467 this.selectedInterfaceOperation = dropDownOption ? dropDownOption : undefined;
470 getExistingFilters(key: string) {
471 if (this.operationToUpdate.milestones[key] && this.operationToUpdate.milestones[key].filters) {
472 return this.operationToUpdate.milestones[key].filters
477 filtersChangeEvent($event: any, milestone: string) {
479 if (this.invalidMilestones.indexOf(milestone) > -1) {
480 this.invalidMilestones.splice(this.invalidMilestones.indexOf(milestone), 1);
481 this.validMilestoneFilters = this.invalidMilestones.length < 1;
482 this.validMilestoneActivities = this.invalidMilestones.length < 1;
484 let operationMilestone = this.operationToUpdate.milestones[milestone];
485 if (!operationMilestone) {
486 operationMilestone = new Milestone();
488 operationMilestone.filters = new class implements IFilterParameterList {
489 listToscaDataDefinition: Array<FilterParameter> = [];
491 let milestoneFilters = $event.filters;
492 for (let filter of milestoneFilters) {
493 let filterParameter = new FilterParameter();
494 filterParameter.constraint = filter.constraint;
495 filterParameter.name = filter.name;
496 filterParameter.filterValue = filter.filterValue;
497 filterParameter.toscaFunction = filter.toscaFunction;
498 operationMilestone.filters.listToscaDataDefinition.push(filterParameter);
500 this.operationToUpdate.milestones[milestone] = operationMilestone;
502 if (this.invalidMilestones.indexOf(milestone) == -1) {
503 this.invalidMilestones.push(milestone);
505 this.validMilestoneFilters = false;
506 this.validMilestoneActivities = false;
510 getExistingActivities(key: string) {
512 this.operationToUpdate.milestones[key]
513 && this.operationToUpdate.milestones[key].activities
514 && this.operationToUpdate.milestones[key].activities.listToscaDataDefinition
515 && this.operationToUpdate.milestones[key].activities.listToscaDataDefinition.length > 0
517 return this.operationToUpdate.milestones[key].activities
522 activitiesChangeEvent($event: any, milestone: string) {
524 if (this.invalidMilestones.indexOf(milestone) > -1) {
525 this.invalidMilestones.splice(this.invalidMilestones.indexOf(milestone), 1);
526 this.validMilestoneActivities = this.invalidMilestones.length < 1;
527 this.validMilestoneFilters = this.invalidMilestones.length < 1;
529 let operationMilestone = this.operationToUpdate.milestones[milestone];
530 if (!operationMilestone) {
531 operationMilestone = new Milestone();
533 operationMilestone.activities = new class implements IActivityParameterList {
534 listToscaDataDefinition: Array<ActivityParameter> = [];
536 let milestoneActivities = $event.activities;
537 for (let activity of milestoneActivities) {
538 let activityParameter = new ActivityParameter();
539 activityParameter.type = activity.type;
540 activityParameter.workflow = activity.workflow;
541 activityParameter.inputs = activity.inputs;
542 operationMilestone.activities.listToscaDataDefinition.push(activityParameter);
544 this.operationToUpdate.milestones[milestone] = operationMilestone;
546 if (this.invalidMilestones.indexOf(milestone) == -1) {
547 this.invalidMilestones.push(milestone);
549 this.validMilestoneActivities = false;
550 this.validMilestoneFilters = false;
554 isActiveTab(title: string): boolean {
555 if (this.activeTab) {
556 return this.activeTab == title;
558 return this.milestones[0] == title;
561 tabChanged = (event) => {
562 this.activeTab = event.title;
565 isInvalidActivity(title: string) {
566 if (this.invalidMilestones.indexOf(title) > -1) {
572 class DropDownOption implements IDropDownOption {
576 constructor(value: string, label?: string) {
578 this.label = label || value;