Provide timeout field in interface operation implementation
[sdc.git] / catalog-ui / src / app / ng2 / pages / interface-definition / interface-definition.page.component.ts
index 8dd17f6..90d6a6c 100644 (file)
 */
 import {Component, ComponentRef, Inject, Input} from '@angular/core';
 import {Component as IComponent} from 'app/models/components/component';
+import {WorkflowServiceNg2} from 'app/ng2/services/workflow.service';
 
 import {ISdcConfig, SdcConfigToken} from "app/ng2/config/sdc-config.config";
 import {TranslateService} from "app/ng2/shared/translator/translate.service";
-
+import {IModalButtonComponent, SdcUiServices} from 'onap-ui-angular';
 import {ModalComponent} from 'app/ng2/components/ui/modal/modal.component';
+
 import {ModalService} from 'app/ng2/services/modal.service';
-import {ButtonModel, CapabilitiesGroup, ModalModel, OperationModel} from 'app/models';
+import {
+    ArtifactModel,
+    ButtonModel,
+    CapabilitiesGroup,
+    InputBEModel,
+    InterfaceModel,
+    ModalModel,
+    OperationModel,
+    WORKFLOW_ASSOCIATION_OPTIONS
+} from 'app/models';
 
 import {ComponentServiceNg2} from 'app/ng2/services/component-services/component.service';
-
-import {SdcUiServices} from 'onap-ui-angular';
 import {TopologyTemplateService} from "../../services/component-services/topology-template.service";
-import {
-    ComponentInterfaceDefinitionModel,
-    InputOperationParameter,
-    InterfaceOperationModel
-} from "../../../models/interfaceOperation";
-import {
-    PropertyParamRowComponent
-} from "../composition/interface-operatons/operation-creator/property-param-row/property-param-row.component";
-import {
-    InterfaceOperationHandlerComponent
-} from "../composition/interface-operatons/operation-creator/interface-operation-handler.component";
-import {
-    DropdownValue
-} from "../../components/ui/form-components/dropdown/ui-element-dropdown.component";
+import {InterfaceOperationModel} from "../../../models/interfaceOperation";
+import {InterfaceOperationHandlerComponent} from "../composition/interface-operatons/operation-creator/interface-operation-handler.component";
+import {DropdownValue} from "../../components/ui/form-components/dropdown/ui-element-dropdown.component";
 import {ToscaArtifactModel} from "../../../models/toscaArtifact";
 import {ToscaArtifactService} from "../../services/tosca-artifact.service";
-import {
-    UIInterfaceOperationModel
-} from "../composition/interface-operatons/interface-operations.component";
+import {InterfaceOperationComponent} from "../interface-operation/interface-operation.page.component";
+import {Observable} from "rxjs/Observable";
+import {PluginsService} from 'app/ng2/services/plugins.service';
 
 export class UIOperationModel extends OperationModel {
     isCollapsed: boolean = true;
     isEllipsis: boolean;
     MAX_LENGTH = 75;
 
-    constructor(operation: UIOperationModel) {
+    constructor(operation: OperationModel) {
         super(operation);
-
         if (!operation.description) {
             this.description = '';
         }
@@ -84,7 +81,6 @@ export class UIOperationModel extends OperationModel {
     }
 }
 
-// tslint:disable-next-line:max-classes-per-file
 class ModalTranslation {
     CREATE_TITLE: string;
     EDIT_TITLE: string;
@@ -109,15 +105,14 @@ class ModalTranslation {
     }
 }
 
-export class UIInterfaceModel extends ComponentInterfaceDefinitionModel {
+export class UIInterfaceModel extends InterfaceModel {
     isCollapsed: boolean = false;
 
     constructor(interf?: any) {
         super(interf);
-        this.operations = _.map(
-            this.operations,
-            (operation) => new UIInterfaceOperationModel(operation)
-        );
+        if (this.operations) {
+            this.operations = this.operations.map((operation) => new UIOperationModel(operation));
+        }
     }
 
     toggleCollapse() {
@@ -125,21 +120,18 @@ export class UIInterfaceModel extends ComponentInterfaceDefinitionModel {
     }
 }
 
-// tslint:disable-next-line:max-classes-per-file
 @Component({
     selector: 'interface-definition',
     templateUrl: './interface-definition.page.component.html',
     styleUrls: ['interface-definition.page.component.less'],
-    providers: [ModalService, TranslateService]
+    providers: [ModalService, TranslateService, InterfaceOperationComponent]
 })
-
 export class InterfaceDefinitionComponent {
 
     modalInstance: ComponentRef<ModalComponent>;
     interfaces: UIInterfaceModel[];
-    inputs: Array<InputOperationParameter> = [];
+    inputs: InputBEModel[];
 
-    properties: Array<PropertyParamRowComponent> = [];
     deploymentArtifactsFilePath: Array<DropdownValue> = [];
 
     toscaArtifactTypes: Array<DropdownValue> = [];
@@ -151,7 +143,11 @@ export class InterfaceDefinitionComponent {
     modalTranslation: ModalTranslation;
     workflows: any[];
     capabilities: CapabilitiesGroup;
-    isViewOnly: boolean;
+
+    openOperation: OperationModel;
+    enableWorkflowAssociation: boolean;
+    workflowIsOnline: boolean;
+    validImplementationProps:boolean = true;
 
     @Input() component: IComponent;
     @Input() readonly: boolean;
@@ -167,19 +163,53 @@ export class InterfaceDefinitionComponent {
         private modalServiceNg2: ModalService,
         private modalServiceSdcUI: SdcUiServices.ModalService,
         private topologyTemplateService: TopologyTemplateService,
-        private toscaArtifactService: ToscaArtifactService
+        private toscaArtifactService: ToscaArtifactService,
+        private ComponentServiceNg2: ComponentServiceNg2,
+        private WorkflowServiceNg2: WorkflowServiceNg2,
+        private ModalServiceSdcUI: SdcUiServices.ModalService,
+        private PluginsService: PluginsService
     ) {
         this.modalTranslation = new ModalTranslation(translateService);
         this.interfaceTypesMap = new Map<string, string[]>();
     }
 
     ngOnInit(): void {
-        console.info("this.component.lifecycleState ", this.component.lifecycleState);
-        if (this.component) {
-            this.isViewOnly = this.component.componentMetadata.isComponentDataEditable();
-            this.initInterfaceDefinition();
-            this.loadInterfaceTypes();
-            this.loadToscaArtifacts();
+        this.isLoading = true;
+        this.interfaces = [];
+        this.workflowIsOnline = !_.isUndefined(this.PluginsService.getPluginByStateUrl('workflowDesigner'));
+        Observable.forkJoin(
+            this.ComponentServiceNg2.getInterfaceOperations(this.component),
+            this.ComponentServiceNg2.getComponentInputs(this.component),
+            this.ComponentServiceNg2.getInterfaceTypes(this.component),
+            this.ComponentServiceNg2.getCapabilitiesAndRequirements(this.component.componentType, this.component.uniqueId)
+        ).subscribe((response: any[]) => {
+            const callback = (workflows) => {
+                this.isLoading = false;
+                this.initInterfaces(response[0].interfaces);
+                this.sortInterfaces();
+                this.inputs = response[1].inputs;
+                this.interfaceTypes = response[2];
+                this.workflows = (workflows.items) ? workflows.items : workflows;
+                this.capabilities = response[3].capabilities;
+            };
+            if (this.enableWorkflowAssociation && this.workflowIsOnline) {
+                this.WorkflowServiceNg2.getWorkflows().subscribe(
+                    callback,
+                    (err) => {
+                        this.workflowIsOnline = false;
+                        callback([]);
+                    }
+                );
+            } else {
+                callback([]);
+            }
+        });
+        this.loadToscaArtifacts();
+    }
+
+    initInterfaces(interfaces: InterfaceModel[]): void {
+        if (interfaces) {
+            this.interfaces = interfaces.map((interf) => new UIInterfaceModel(interf));
         }
     }
 
@@ -188,19 +218,42 @@ export class InterfaceDefinitionComponent {
     }
 
     private disableSaveButton = (): boolean => {
-        return this.isViewOnly ||
-            (this.isEnableAddArtifactImplementation()
-                && (!this.modalInstance.instance.dynamicContent.instance.toscaArtifactTypeSelected ||
-                    !this.modalInstance.instance.dynamicContent.instance.artifactName)
-            );
+        let disable:boolean = true;
+        if(this.readonly) {
+            return disable;
+        }
+    
+        let selectedInterfaceOperation = this.modalInstance.instance.dynamicContent.instance.selectedInterfaceOperation;
+        let isInterfaceOperation:boolean = !(typeof selectedInterfaceOperation == 'undefined' || _.isEmpty(selectedInterfaceOperation));
+        let selectedInterfaceType = this.modalInstance.instance.dynamicContent.instance.selectedInterfaceType;
+        let isInterfaceType:boolean = !(typeof selectedInterfaceType == 'undefined' || _.isEmpty(selectedInterfaceType));
+        let bothSet: boolean = isInterfaceOperation && isInterfaceType;
+    
+        let enableAddArtifactImplementation = this.modalInstance.instance.dynamicContent.instance.enableAddArtifactImplementation;
+        if(enableAddArtifactImplementation) {
+            let validImplementationProps = this.modalInstance.instance.dynamicContent.instance.validImplementationProps;
+            let toscaArtifactTypeSelected = this.modalInstance.instance.dynamicContent.instance.toscaArtifactTypeSelected;
+            let isToscaArtifactType:boolean = !(typeof toscaArtifactTypeSelected == 'undefined' || _.isEmpty(toscaArtifactTypeSelected));
+            disable = !bothSet || !isToscaArtifactType || !validImplementationProps;
+            return disable;
+        }
+        disable = !bothSet;
+        return disable;
     }
 
     onSelectInterfaceOperation(interfaceModel: UIInterfaceModel, operation: InterfaceOperationModel) {
-        const cancelButton: ButtonModel = new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal);
-        const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue', () =>
-            this.updateOperation(), this.disableSaveButton);
+        const isEdit = operation !== undefined;
+        const modalButtons = [];
+        if (!this.readonly) {
+            const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue',
+                () => isEdit ? this.updateOperation() : this.createOperationCallback(),
+                this.disableSaveButton
+            );
+            modalButtons.push(saveButton);
+        }
+        modalButtons.push(new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal));
         const interfaceDataModal: ModalModel =
-            new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', [saveButton, cancelButton], 'custom');
+            new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', modalButtons, 'custom');
         this.modalInstance = this.modalServiceNg2.createCustomModal(interfaceDataModal);
 
         this.modalServiceNg2.addDynamicContentToModal(
@@ -209,17 +262,36 @@ export class InterfaceDefinitionComponent {
             {
                 deploymentArtifactsFilePath: this.deploymentArtifactsFilePath,
                 toscaArtifactTypes: this.toscaArtifactTypes,
-                selectedInterface: interfaceModel,
-                selectedInterfaceOperation: operation,
+                selectedInterface: interfaceModel ? interfaceModel : new UIInterfaceModel(),
+                selectedInterfaceOperation: operation ? operation : new InterfaceOperationModel(),
                 validityChangedCallback: this.disableSaveButton,
-                isViewOnly: this.isViewOnly,
+                isViewOnly: this.readonly,
+                validImplementationProps: this.validImplementationProps,
+                'isEdit': isEdit,
                 interfaceTypesMap: this.interfaceTypesMap,
-            });
+                modelName: this.component.model
+            }
+        );
         this.modalInstance.instance.open();
     }
 
     private updateOperation = (): void => {
-        let operationToUpdate = this.modalInstance.instance.dynamicContent.instance.operationToUpdate;
+        this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = true;
+        const interfaceOperationHandlerComponentInstance: InterfaceOperationHandlerComponent = this.modalInstance.instance.dynamicContent.instance;
+        const operationToUpdate = this.modalInstance.instance.dynamicContent.instance.operationToUpdate;
+        let timeout = null;
+        if (operationToUpdate.implementation && operationToUpdate.implementation.timeout != null) {
+            timeout = operationToUpdate.implementation.timeout;
+        }
+        const isArtifactChecked = interfaceOperationHandlerComponentInstance.enableAddArtifactImplementation;
+        if (!isArtifactChecked) {
+            const artifactName = interfaceOperationHandlerComponentInstance.artifactName ?
+                interfaceOperationHandlerComponentInstance.artifactName : '';
+            operationToUpdate.implementation = new ArtifactModel({'artifactName': artifactName, 'artifactVersion': ''} as ArtifactModel);
+        }
+        if (timeout != null) {
+            operationToUpdate.implementation.timeout = timeout;
+        }
         this.componentServiceNg2.updateComponentInterfaceOperation(this.component.uniqueId, operationToUpdate)
         .subscribe((newOperation: InterfaceOperationModel) => {
             let oldOpIndex;
@@ -232,11 +304,41 @@ export class InterfaceDefinitionComponent {
                     }
                 });
             });
-            newOperation = this.handleEnableAddArtifactImplementation(newOperation);
             oldInterf.operations.splice(oldOpIndex, 1);
             oldInterf.operations.push(new InterfaceOperationModel(newOperation));
+        }, error => {
+            this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+        }, () => {
+            this.sortInterfaces();
+            this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+            this.modalServiceNg2.closeCurrentModal();
+        });
+    }
+
+    private createOperationCallback(): void {
+        this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = true;
+        const operationToUpdate = this.modalInstance.instance.dynamicContent.instance.operationToUpdate;
+        console.log('createOperationCallback', operationToUpdate);
+        console.log('this.component', this.component);
+        this.componentServiceNg2.createComponentInterfaceOperation(this.component.uniqueId, this.component.getTypeUrl(), operationToUpdate)
+        .subscribe((newOperation: InterfaceOperationModel) => {
+            const foundInterface = this.interfaces.find(value => value.type === newOperation.interfaceType);
+            if (foundInterface) {
+                foundInterface.operations.push(new UIOperationModel(new OperationModel(newOperation)));
+            } else {
+                const uiInterfaceModel = new UIInterfaceModel();
+                uiInterfaceModel.type = newOperation.interfaceType;
+                uiInterfaceModel.uniqueId = newOperation.interfaceType;
+                uiInterfaceModel.operations = [];
+                uiInterfaceModel.operations.push(new UIOperationModel(new OperationModel(newOperation)));
+                this.interfaces.push(uiInterfaceModel);
+            }
+        }, error => {
+            this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+        }, () => {
+            this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+            this.modalServiceNg2.closeCurrentModal();
         });
-        this.modalServiceNg2.closeCurrentModal();
     }
 
     private handleEnableAddArtifactImplementation = (newOperation: InterfaceOperationModel): InterfaceOperationModel => {
@@ -248,7 +350,7 @@ export class InterfaceDefinitionComponent {
     }
 
     private isEnableAddArtifactImplementation = (): boolean => {
-        return this.modalInstance.instance.dynamicContent.instance.enableAddArtifactImplementation;
+        return this.modalInstance.instance.dynamicContent.enableAddArtifactImplementation;
     }
 
     private initInterfaceDefinition() {
@@ -257,7 +359,7 @@ export class InterfaceDefinitionComponent {
         this.topologyTemplateService.getComponentInterfaceOperations(this.component.componentType, this.component.uniqueId)
         .subscribe((response) => {
             if (response.interfaces) {
-                this.interfaces = _.map(response.interfaces, (interfaceModel) => new UIInterfaceModel(interfaceModel));
+                this.interfaces = response.interfaces.map((interfaceModel) => new UIInterfaceModel(interfaceModel));
             }
             this.isLoading = false;
         });
@@ -301,11 +403,11 @@ export class InterfaceDefinitionComponent {
     }
 
     isAllCollapsed(): boolean {
-        return _.every(this.interfaces, (interfaceData) => interfaceData.isCollapsed);
+        return this.interfaces.every((interfaceData) => interfaceData.isCollapsed);
     }
 
     isAllExpanded(): boolean {
-        return _.every(this.interfaces, (interfaceData) => !interfaceData.isCollapsed);
+        return this.interfaces.every((interfaceData) => !interfaceData.isCollapsed);
     }
 
     isInterfaceListEmpty(): boolean {
@@ -313,8 +415,94 @@ export class InterfaceDefinitionComponent {
     }
 
     isOperationListEmpty(): boolean {
-        return _.filter(this.interfaces, (interfaceData) =>
-            interfaceData.operations && interfaceData.operations.length > 0).length > 0;
+        return this.interfaces.filter((interfaceData) => interfaceData.operations && interfaceData.operations.length > 0).length > 0;
+    }
+
+    onRemoveOperation(operation: OperationModel): void {
+        if (this.readonly) {
+            return;
+        }
+
+        const deleteButton: IModalButtonComponent = {
+            id: 'deleteButton',
+            text: this.modalTranslation.DELETE_BUTTON,
+            type: 'primary',
+            size: 'small',
+            closeModal: true,
+            callback: () => {
+                this.ComponentServiceNg2
+                .deleteInterfaceOperation(this.component, operation)
+                .subscribe(() => {
+                    const curInterf = this.interfaces.find((interf) => interf.type === operation.interfaceType);
+                    const index = curInterf.operations.findIndex((el) => el.uniqueId === operation.uniqueId);
+                    curInterf.operations.splice(index, 1);
+                    if (!curInterf.operations.length) {
+                        const interfIndex = this.interfaces.findIndex((interf) => interf.type === operation.interfaceType);
+                        this.interfaces.splice(interfIndex, 1);
+                    }
+                });
+            }
+        };
+
+        const cancelButton: IModalButtonComponent = {
+            id: 'cancelButton',
+            text: this.modalTranslation.CANCEL_BUTTON,
+            type: 'secondary',
+            size: 'small',
+            closeModal: true,
+            callback: () => {
+                this.openOperation = null;
+            },
+        };
+
+        this.ModalServiceSdcUI.openWarningModal(
+            this.modalTranslation.DELETE_TITLE,
+            this.modalTranslation.deleteText(operation.name),
+            'deleteOperationModal',
+            [deleteButton, cancelButton],
+        );
+    }
+
+    private createOperation = (operation: OperationModel): void => {
+        this.ComponentServiceNg2.createInterfaceOperation(this.component, operation).subscribe((response: OperationModel) => {
+            this.openOperation = null;
+
+            let curInterf = this.interfaces.find((interf) => interf.type === operation.interfaceType);
+
+            if (!curInterf) {
+                curInterf = new UIInterfaceModel({
+                    type: response.interfaceType,
+                    uniqueId: response.uniqueId,
+                    operations: []
+                });
+                this.interfaces.push(curInterf);
+            }
+
+            const newOpModel = new UIOperationModel(response);
+            curInterf.operations.push(newOpModel);
+            this.sortInterfaces();
+
+            if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL && operation.artifactData) {
+                this.ComponentServiceNg2.uploadInterfaceOperationArtifact(this.component, newOpModel, operation).subscribe();
+            } else if (response.workflowId && operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING) {
+                this.WorkflowServiceNg2.associateWorkflowArtifact(this.component, response).subscribe();
+            } else if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.NEW) {
+                this.$state.go('workspace.plugins', {path: 'workflowDesigner'});
+            }
+        });
+    }
+
+    private enableOrDisableSaveButton = (shouldEnable: boolean): void => {
+        const saveButton = this.modalInstance.instance.dynamicContent.getButtonById('saveButton');
+        saveButton.disabled = !shouldEnable;
+    }
+
+    private sortInterfaces(): void {
+        this.interfaces = this.interfaces.filter((interf) => interf.operations && interf.operations.length > 0); // remove empty interfaces
+        this.interfaces.sort((a, b) => a.type.localeCompare(b.type)); // sort interfaces alphabetically
+        this.interfaces.forEach((interf) => {
+            interf.operations.sort((a, b) => a.name.localeCompare(b.name)); // sort operations alphabetically
+        });
     }
 
 }