Issues found when trying to create activities in interface operations
[sdc.git] / catalog-ui / src / app / ng2 / pages / composition / interface-operatons / operation-creator / interface-operation-handler.component.ts
index 6bfb09d..f82ad66 100644 (file)
 *  SPDX-License-Identifier: Apache-2.0
 *  ============LICENSE_END=========================================================
 */
-import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core';
+import {Component, EventEmitter, Output, ViewChild} from '@angular/core';
+import { FormControl } from '@angular/forms';
 import {UIInterfaceModel} from "../interface-operations.component";
-import {InputOperationParameter, InterfaceOperationModel, IOperationParamsList} from "../../../../../models/interfaceOperation";
+import {
+    ActivityParameter,
+    IActivityParameterList,
+    IFilterParameterList,
+    InputOperationParameter,
+    InterfaceOperationModel,
+    IOperationParamsList,
+    FilterParameter,
+    Milestone,
+    MilestoneEnum
+} from "../../../../../models/interfaceOperation";
 import {TranslateService} from "../../../../shared/translator/translate.service";
 import {DropdownValue} from "../../../../components/ui/form-components/dropdown/ui-element-dropdown.component";
 import {ArtifactModel} from "../../../../../models/artifacts";
@@ -33,6 +44,9 @@ import {DropDownComponent} from "onap-ui-angular/dist/form-elements/dropdown/dro
 import {DataTypeService} from "../../../../services/data-type.service";
 import {Observable} from "rxjs/Observable";
 import {DataTypeModel} from "../../../../../models/data-types";
+import {InstanceFeDetails} from "../../../../../models/instance-fe-details";
+import {TopologyTemplateService} from "app/ng2/services/component-services/topology-template.service";
+import {CustomToscaFunction} from "../../../../../models/default-custom-functions";
 
 @Component({
     selector: 'operation-handler',
@@ -46,12 +60,16 @@ export class InterfaceOperationHandlerComponent {
     @ViewChild('interfaceOperationDropDown') interfaceOperationDropDown: DropDownComponent;
 
     input: {
+        componentInstanceMap: Map<string, InstanceFeDetails>;
         toscaArtifactTypes: Array<DropdownValue>;
         selectedInterface: UIInterfaceModel;
         selectedInterfaceOperation: InterfaceOperationModel;
         validityChangedCallback: Function;
         isViewOnly: boolean;
         isEdit: boolean;
+        validImplementationProps: boolean;
+        validMilestoneActivities: boolean;
+        validMilestoneFilters: boolean;
         modelName: string;
     };
 
@@ -65,9 +83,11 @@ export class InterfaceOperationHandlerComponent {
     inputs: Array<InputOperationParameter> = [];
     properties: Array<PropertyParamRowComponent> = [];
     isLoading: boolean = false;
-    readonly: boolean;
     isViewOnly: boolean;
     isEdit: boolean;
+    validImplementationProps: boolean;
+    validMilestoneActivities: boolean;
+    validMilestoneFilters: boolean;
     interfaceTypes: Array<DropdownValue> = [];
     interfaceTypeOptions: Array<DropDownOption> = [];
     selectedInterfaceType: DropDownOption = undefined;
@@ -75,40 +95,70 @@ export class InterfaceOperationHandlerComponent {
     interfaceOperationOptions: Array<DropDownOption> = [];
     selectedInterfaceOperation: DropDownOption = undefined;
     modelName: string;
-
     toscaArtifactTypeSelected: string;
     toscaArtifactTypeProperties: Array<PropertyBEModel> = [];
     artifactTypeProperties: Array<InputOperationParameter> = [];
-
     toscaArtifactTypes: Array<DropdownValue> = [];
-
+    componentInstanceMap: Map<string, InstanceFeDetails>;
+    customToscaFunctions: Array<CustomToscaFunction>;
     enableAddArtifactImplementation: boolean;
-
     propertyValueValid: boolean = true;
+    showActivities: boolean = false;
     inputTypeOptions: any[];
+    timeoutValue = new FormControl('');
+    timeoutType = new FormControl('');
+    invalidMilestones: string[] = [];
+    activeTab: string;
+    milestones = Object.keys(MilestoneEnum)
+            .map(key => MilestoneEnum[key]);
 
-    constructor(private dataTypeService: DataTypeService, private componentServiceNg2: ComponentServiceNg2) {
-
-
+    constructor(private dataTypeService: DataTypeService,
+                private componentServiceNg2: ComponentServiceNg2,
+                private topologyTemplateService: TopologyTemplateService) {
     }
 
     ngOnInit() {
         this.isViewOnly = this.input.isViewOnly;
         this.isEdit = this.input.isEdit;
+        this.validImplementationProps = this.input.validImplementationProps;
+        this.validMilestoneActivities = this.input.validMilestoneActivities;
+        this.validMilestoneFilters = this.input.validMilestoneFilters;
+        this.componentInstanceMap =  this.input.componentInstanceMap ? this.input.componentInstanceMap : null;
         this.interfaceType = this.input.selectedInterface.type;
         this.operationToUpdate = new InterfaceOperationModel(this.input.selectedInterfaceOperation);
         this.operationToUpdate.interfaceId = this.input.selectedInterface.uniqueId;
         this.operationToUpdate.interfaceType = this.input.selectedInterface.type;
         this.modelName = this.input.modelName;
+        this.timeoutType.setValue('sec');
+        if (this.operationToUpdate.implementation && this.operationToUpdate.implementation.timeout != null) {
+            this.timeoutValue.setValue(this.operationToUpdate.implementation.timeout);
+            let timeout = this.timeoutValue.value / 3600;
+            if (Number.isInteger(timeout)) {
+                if (timeout > 23 && Number.isInteger(timeout / 24)) {
+                    this.timeoutValue.setValue(timeout / 24);
+                    this.timeoutType.setValue("day");
+                } else {
+                    this.timeoutValue.setValue(timeout);
+                    this.timeoutType.setValue("hour");
+                }
+            } else if (Number.isInteger(timeout / 24)) {
+                this.timeoutValue.setValue(timeout / 24);
+                this.timeoutType.setValue("day");
+            }
+        }
+        if (!this.operationToUpdate.milestones) {
+            this.operationToUpdate.milestones = {};
+        }
+        this.initCustomToscaFunctions();
         this.initInputs();
         this.removeImplementationQuote();
-        this.validityChanged();
         this.loadInterfaceOperationImplementation();
 
         this.dataTypeMap$ = new Observable<Map<string, DataTypeModel>>(subscriber => {
             this.dataTypeService.findAllDataTypesByModel(this.modelName)
             .then((dataTypesMap: Map<string, DataTypeModel>) => {
                 subscriber.next(dataTypesMap);
+                this.showActivities = dataTypesMap.has("tosca.dataTypes.tmf.milestoneJeopardyData");
             });
         });
         this.dataTypeMap$.subscribe(value => {
@@ -125,11 +175,21 @@ export class InterfaceOperationHandlerComponent {
 
         this.inputs = Array.from(this.operationToUpdate.inputs.listToscaDataDefinition);
         this.removeImplementationQuote();
-        this.validityChanged();
         this.loadInterfaceOperationImplementation();
         this.loadInterfaceType();
     }
 
+    private initCustomToscaFunctions() {
+        this.customToscaFunctions = [];
+        this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
+            if (data) {
+                for (let customFunction of data) {
+                    this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
+                }
+            }
+        });
+    }
+
     private loadInterfaceType() {
         this.componentServiceNg2.getInterfaceTypesByModel(this.modelName)
         .subscribe(response => {
@@ -199,8 +259,8 @@ export class InterfaceOperationHandlerComponent {
             this.toscaArtifactTypeSelected = undefined;
             this.artifactVersion = undefined;
             if (this.operationToUpdate.implementation.artifactType) {
-                this.operationToUpdate.implementation.artifactName = '';
                 this.operationToUpdate.implementation.artifactVersion = '';
+                this.operationToUpdate.implementation.artifactType = '';
             }
             this.toscaArtifactTypeProperties = undefined;
             this.artifactTypeProperties = undefined;
@@ -208,7 +268,6 @@ export class InterfaceOperationHandlerComponent {
             this.getArtifactTypesSelected();
         }
         this.enableAddArtifactImplementation = event;
-        this.validateRequiredField();
     }
 
     onSelectToscaArtifactType(type: IDropDownOption) {
@@ -225,7 +284,6 @@ export class InterfaceOperationHandlerComponent {
             this.operationToUpdate.implementation = artifact;
             this.getArtifactTypesSelected();
         }
-        this.validateRequiredField();
     }
 
     onArtifactVersionChange(value: string | undefined) {
@@ -234,20 +292,31 @@ export class InterfaceOperationHandlerComponent {
 
     onAddInput(inputOperationParameter: InputOperationParameter) {
         this.addInput(inputOperationParameter);
-        this.validityChanged();
     }
 
     propertyValueValidation = (propertyValue): void => {
         this.onPropertyValueChange(propertyValue);
         this.propertyValueValid = propertyValue.isValid;
-        this.readonly = !this.propertyValueValid;
-        this.validateRequiredField();
     }
 
     onRemoveInput = (inputParam: InputOperationParameter): void => {
         let index = this.inputs.indexOf(inputParam);
         this.inputs.splice(index, 1);
-        this.validityChanged();
+    }
+
+    timeoutConversion = (): void => {
+        let timeout = this.timeoutValue.value;
+        if (timeout != null) {
+            if (this.timeoutType.value == null || this.timeoutType.value == 'sec') {
+                this.operationToUpdate.implementation.timeout = timeout;
+                return;
+            }
+            if (this.timeoutType.value == 'hour') {
+                this.operationToUpdate.implementation.timeout = timeout * 3600;
+            } else if (this.timeoutType.value == 'day') {
+                this.operationToUpdate.implementation.timeout = (timeout * 24) * 3600;
+            }
+        }
     }
 
     private removeImplementationQuote(): void {
@@ -265,14 +334,6 @@ export class InterfaceOperationHandlerComponent {
         }
     }
 
-    validityChanged = () => {
-        let validState = this.checkFormValidForSubmit();
-        this.input.validityChangedCallback(validState);
-        if (validState) {
-            this.readonly = false;
-        }
-    }
-
     private getArtifactTypesSelected() {
         if (this.operationToUpdate.implementation && this.operationToUpdate.implementation.artifactType) {
             this.artifactName =
@@ -284,33 +345,6 @@ export class InterfaceOperationHandlerComponent {
             this.artifactTypeProperties = this.convertArtifactsPropertiesToInput();
             this.enableAddArtifactImplementation = true;
         }
-        this.validateRequiredField();
-    }
-
-    validateRequiredField = () => {
-        this.readonly = true;
-        const isRequiredFieldSelected = this.isRequiredFieldsSelected();
-        this.input.validityChangedCallback(isRequiredFieldSelected);
-        if (isRequiredFieldSelected && this.propertyValueValid) {
-            this.readonly = false;
-        }
-    }
-
-    private isRequiredFieldsSelected() {
-        return this.toscaArtifactTypeSelected && this.artifactName;
-    }
-
-    private checkFormValidForSubmit = (): boolean => {
-        return this.operationToUpdate.name && this.artifactName && this.isParamsValid();
-    }
-
-    private isParamsValid = (): boolean => {
-        const isInputValid = (input) => input.name && input.inputId && input.type;
-        const isValid = this.inputs.every(isInputValid);
-        if (!isValid) {
-            this.readonly = true;
-        }
-        return isValid;
     }
 
     toDropDownOption(val: string) {
@@ -326,15 +360,30 @@ export class InterfaceOperationHandlerComponent {
             changedInput.value = JSON.stringify(changedInput.value);
         }
         const inputOperationParameter = this.inputs.find(value => value.name == changedInput.name);
+        inputOperationParameter.toscaFunction = null;
         inputOperationParameter.value = changedInput.value;
+        inputOperationParameter.subPropertyToscaFunctions = changedInput.subPropertyToscaFunctions;
+        if (changedInput.isToscaFunction()) {
+            inputOperationParameter.toscaFunction = changedInput.toscaFunction;
+            inputOperationParameter.value = changedInput.toscaFunction.buildValueString();
+        }
     }
 
     onArtifactPropertyValueChange(changedProperty: InputOperationParameter) {
+        const property = this.toscaArtifactTypeProperties.find(artifactProperty => artifactProperty.name == changedProperty.name);
         if (changedProperty.value instanceof Object) {
             changedProperty.value = JSON.stringify(changedProperty.value);
         }
-        const property = this.toscaArtifactTypeProperties.find(artifactProperty => artifactProperty.name == changedProperty.name);
+        property.toscaFunction = null;
         property.value = changedProperty.value;
+        if (changedProperty.isToscaFunction()) {
+            property.toscaFunction = changedProperty.toscaFunction;
+            property.value = changedProperty.toscaFunction.buildValueString();
+        }
+    }
+
+    implementationPropsValidityChange(validImplementationProps: boolean) {
+        this.validImplementationProps = validImplementationProps;
     }
 
     /**
@@ -363,7 +412,7 @@ export class InterfaceOperationHandlerComponent {
         const input1 = currentInputs.find(value => value.name === inputName);
         const indexOfInput = currentInputs.indexOf(input1);
         if (indexOfInput === -1) {
-            console.error(`Could delete input '${inputName}'. Input not found.`);
+            console.error(`Could not delete input '${inputName}'. Input not found.`);
             return;
         }
         currentInputs.splice(currentInputs.indexOf(input1), 1);
@@ -382,6 +431,7 @@ export class InterfaceOperationHandlerComponent {
             input.schema = property.schema;
             input.toscaDefaultValue = property.defaultValue;
             input.value = property.value;
+            input.toscaFunction = property.toscaFunction;
             inputList.push(input);
         });
         return inputList;
@@ -416,6 +466,107 @@ export class InterfaceOperationHandlerComponent {
         this.operationToUpdate.operationType = dropDownOption ? dropDownOption.value : undefined;
         this.selectedInterfaceOperation = dropDownOption ? dropDownOption : undefined;
     }
+
+    getExistingFilters(key: string) {
+        if (this.operationToUpdate.milestones[key] && this.operationToUpdate.milestones[key].filters) {
+            return this.operationToUpdate.milestones[key].filters
+        }
+        return undefined;
+    }
+
+    filtersChangeEvent($event: any, milestone: string) {
+        if ($event.valid) {
+            if (this.invalidMilestones.indexOf(milestone) > -1) {
+                this.invalidMilestones.splice(this.invalidMilestones.indexOf(milestone), 1);
+                this.validMilestoneFilters = this.invalidMilestones.length < 1;
+                this.validMilestoneActivities = this.invalidMilestones.length < 1;
+            }
+            let operationMilestone = this.operationToUpdate.milestones[milestone];
+            if (!operationMilestone) {
+                operationMilestone = new Milestone();
+            }
+            operationMilestone.filters = new class implements IFilterParameterList {
+                listToscaDataDefinition: Array<FilterParameter> = [];
+            }
+            let milestoneFilters = $event.filters;
+            for (let filter of milestoneFilters) {
+                let filterParameter = new FilterParameter();
+                filterParameter.constraint = filter.constraint;
+                filterParameter.name = filter.name;
+                filterParameter.filterValue = filter.filterValue;
+                filterParameter.toscaFunction = filter.toscaFunction;
+                operationMilestone.filters.listToscaDataDefinition.push(filterParameter);
+            }
+            this.operationToUpdate.milestones[milestone] = operationMilestone;
+        } else {
+            if (this.invalidMilestones.indexOf(milestone) == -1) {
+                this.invalidMilestones.push(milestone);
+            }
+            this.validMilestoneFilters = false;
+            this.validMilestoneActivities = false;
+        }
+    }
+
+    getExistingActivities(key: string) {
+        if (
+            this.operationToUpdate.milestones[key]
+            && this.operationToUpdate.milestones[key].activities
+            && this.operationToUpdate.milestones[key].activities.listToscaDataDefinition
+            && this.operationToUpdate.milestones[key].activities.listToscaDataDefinition.length > 0
+        ) {
+            return this.operationToUpdate.milestones[key].activities
+        }
+        return undefined;
+    }
+
+    activitiesChangeEvent($event: any, milestone: string) {
+        if ($event.valid) {
+            if (this.invalidMilestones.indexOf(milestone) > -1) {
+                this.invalidMilestones.splice(this.invalidMilestones.indexOf(milestone), 1);
+                this.validMilestoneActivities = this.invalidMilestones.length < 1;
+                this.validMilestoneFilters  = this.invalidMilestones.length < 1;
+            }
+            let operationMilestone = this.operationToUpdate.milestones[milestone];
+            if (!operationMilestone) {
+                operationMilestone = new Milestone();
+            }
+            operationMilestone.activities = new class implements IActivityParameterList {
+                listToscaDataDefinition: Array<ActivityParameter> = [];
+            }
+            let milestoneActivities = $event.activities;
+            for (let activity of milestoneActivities) {
+                let activityParameter = new ActivityParameter();
+                activityParameter.type = activity.type;
+                activityParameter.workflow = activity.workflow;
+                activityParameter.inputs = activity.inputs;
+                operationMilestone.activities.listToscaDataDefinition.push(activityParameter);
+            }
+            this.operationToUpdate.milestones[milestone] = operationMilestone;
+        } else {
+            if (this.invalidMilestones.indexOf(milestone) == -1) {
+                this.invalidMilestones.push(milestone);
+            }
+            this.validMilestoneActivities = false;
+            this.validMilestoneFilters = false;
+        }
+    }
+
+    isActiveTab(title: string): boolean {
+        if (this.activeTab) {
+            return this.activeTab == title;
+        }
+        return this.milestones[0] == title;
+    }
+
+    tabChanged = (event) => {
+        this.activeTab = event.title;
+      }
+
+    isInvalidActivity(title: string) {
+        if (this.invalidMilestones.indexOf(title) > -1) {
+            return "#cf2a2a";
+        }
+      }
 }
 
 class DropDownOption implements IDropDownOption {