Add support for updating interface operations

Allows to update interface operations on a component instance.

Issue-ID: SDC-3446
Signed-off-by: aribeiro <anderson.ribeiro@est.tech>
Signed-off-by: andre.schmid <andre.schmid@est.tech>
Change-Id: I6a2c44997c04d9d9ea298e3d0bc971da7b137799
diff --git a/catalog-ui/src/app/models/componentsInstances/componentInstance.ts b/catalog-ui/src/app/models/componentsInstances/componentInstance.ts
index 2e0c1a5..a55cd4f 100644
--- a/catalog-ui/src/app/models/componentsInstances/componentInstance.ts
+++ b/catalog-ui/src/app/models/componentsInstances/componentInstance.ts
@@ -103,6 +103,7 @@
     public invariantName:string;
     public originArchived:boolean;
     public directives: string[];
+    public interfaces:any;
 
     constructor(componentInstance?:ComponentInstance) {
 
@@ -135,6 +136,7 @@
             this.sourceModelUuid = componentInstance.sourceModelUuid;
             this.originArchived = componentInstance.originArchived;
             this.directives = componentInstance.directives;
+            this.interfaces = componentInstance.interfaces;
         }
     }
 
diff --git a/catalog-ui/src/app/models/inputs.ts b/catalog-ui/src/app/models/inputs.ts
index 49fd16d..562db98 100644
--- a/catalog-ui/src/app/models/inputs.ts
+++ b/catalog-ui/src/app/models/inputs.ts
@@ -65,6 +65,7 @@
     schema:SchemaPropertyGroupModel;
     defaultValue:string;
     value:string;
+    toscaDefaultValue?: string;
 
     //costom properties
     isNew:boolean;
@@ -94,6 +95,7 @@
             this.filterTerm = this.name + ' ' + this.description + ' ' + this.type + ' ' + this.componentInstanceName;
             this.inputs = input.inputs;
             this.properties = input.properties;
+            this.toscaDefaultValue = input.toscaDefaultValue;
         }
     }
 
diff --git a/catalog-ui/src/app/models/interfaceOperation.ts b/catalog-ui/src/app/models/interfaceOperation.ts
new file mode 100644
index 0000000..5c69688
--- /dev/null
+++ b/catalog-ui/src/app/models/interfaceOperation.ts
@@ -0,0 +1,109 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+'use strict';
+
+export class InputOperationParameter {
+    name: string;
+    type: string;
+    inputId: string;
+    toscaDefaultValue?: string;
+
+    constructor(param?: any) {
+        if (param) {
+            this.name = param.name;
+            this.type = param.type;
+            this.inputId = param.inputId;
+            this.toscaDefaultValue = param.toscaDefaultValue;
+        }
+        console.info("InputOperationParameter Constructor: ", param)
+    }
+}
+
+export interface IOperationParamsList {
+    listToscaDataDefinition: Array<InputOperationParameter>;
+}
+
+export class BEInterfaceOperationModel {
+    name: string;
+    description: string;
+    uniqueId: string;
+    inputs: IOperationParamsList;
+    implementation?: InterfaceOperationImplementation;
+
+    constructor(operation?: any) {
+        if (operation) {
+            this.name = operation.name;
+            this.description = operation.description;
+            this.uniqueId = operation.uniqueId;
+            this.inputs = operation.inputs;
+            this.implementation = operation.implementation;
+        }
+    }
+}
+
+export class InterfaceOperationModel extends BEInterfaceOperationModel {
+    interfaceType: string;
+    interfaceId: string;
+    operationType: string;
+    description: string;
+    uniqueId: string;
+    implementation?: InterfaceOperationImplementation;
+    inputParams: IOperationParamsList;
+
+    constructor(operation?: any) {
+        super(operation);
+        if (operation) {
+            this.interfaceId = operation.interfaceId;
+            this.interfaceType = operation.interfaceType;
+            this.description = operation.description;
+            this.operationType = operation.operationType;
+            this.uniqueId = operation.uniqueId;
+            this.inputParams = operation.inputParams;
+        }
+    }
+
+    public displayType(): string {
+        return displayType(this.interfaceType);
+    }
+}
+
+export class InterfaceOperationImplementation {
+    artifactName: string;
+}
+
+export class ComponentInstanceInterfaceModel {
+    type: string;
+    uniqueId: string;
+    operations: Array<InterfaceOperationModel>;
+
+    constructor(interfaceOperation?: any) {
+        if (interfaceOperation) {
+            this.type = interfaceOperation.type;
+            this.uniqueId = interfaceOperation.uniqueId;
+            this.operations = interfaceOperation.operations;
+        }
+    }
+
+    public displayType(): string {
+        return displayType(this.type);
+    }
+}
+
+const displayType = (type:string) => type && type.substr(type.lastIndexOf('.') + 1);
diff --git a/catalog-ui/src/app/ng2/app.module.ts b/catalog-ui/src/app/ng2/app.module.ts
index b94ba61..ac8a9b6 100644
--- a/catalog-ui/src/app/ng2/app.module.ts
+++ b/catalog-ui/src/app/ng2/app.module.ts
@@ -96,6 +96,7 @@
 import { WorkflowServiceNg2 } from './services/workflow.service';
 import { ToscaTypesServiceNg2 } from "./services/tosca-types.service";
 import {CapabilitiesFilterPropertiesEditorComponentModule} from "./pages/composition/capabilities-filter-properties-editor/capabilities-filter-properties-editor.module";
+import {InterfaceOperationHandlerModule} from "./pages/composition/interface-operatons/operation-creator/interface-operation-handler.module";
 
 
 declare const __ENV__: string;
@@ -149,6 +150,7 @@
         PluginsModule,
         InterfaceOperationModule,
         OperationCreatorModule,
+        InterfaceOperationHandlerModule,
         ServicePathCreatorModule,
         ServicePathsListModule,
         ServicePathSelectorModule,
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.ts b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.ts
index 1b1363e..d7b997d 100644
--- a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.ts
@@ -66,7 +66,7 @@
     }
 
     private setMode = (mode:ZoneInstanceMode, event?:any, afterSaveCallback?:Function):void => {
-        
+
         if(event){ //prevent event from handle and then repeat event from zone instance
             event.stopPropagation();
         }
@@ -125,4 +125,4 @@
         event.stopPropagation();
     };
 
-}
\ No newline at end of file
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.html b/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.html
index 5a0ca3e..9f6a8bc 100644
--- a/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.html
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.html
@@ -54,4 +54,4 @@
                        (assignmentSaveComplete)="zoneAssignmentSaveComplete($event)">
         </zone-instance>
     </zone-container>
-</div>
\ No newline at end of file
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.html
new file mode 100644
index 0000000..7567b90
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.html
@@ -0,0 +1,80 @@
+<!--
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+-->
+
+<div class="interface-operations">
+  <loader [display]="isLoading" [size]="'large'" [relative]="true"></loader>
+  <div class="operation-list">
+    <div *ngIf="!isListEmpty()">
+      <div class="expand-collapse">
+        <a class="link"
+           [ngClass]="{'disabled': isAllExpanded()}"
+           (click)="collapseAll(false)">{{ 'INTERFACE_EXPAND_ALL' | translate }}
+        </a> |
+        <a class="link"
+           [ngClass]="{'disabled': isAllCollapsed()}"
+           (click)="collapseAll()">
+          {{ 'INTERFACE_COLLAPSE_ALL' | translate }}
+        </a>
+      </div>
+
+      <div class="interface-row" *ngFor="let interface1 of interfaces">
+        <div class="interface-accordion" (click)="interface1.toggleCollapse()">
+          <span
+              class="chevron-container"
+              [ngClass]="{'isCollapsed': interface1.isCollapsed}">
+              <svg-icon
+                  name="caret1-down-o"
+                  mode="primary"
+                  size="small">
+              </svg-icon>
+          </span>
+          <span class="interface-name">{{interface1.displayType()}}</span>
+        </div>
+
+        <div class="generic-table" *ngIf="!interface1.isCollapsed">
+          <div class="header-row table-row">
+            <span
+                class="cell header-cell field-name header-name">
+                {{ 'INTERFACE_HEADER_NAME' | translate }}
+            </span>
+            <span class="cell header-cell field-description header-description">
+              {{ 'INTERFACE_HEADER_DESCRIPTION' | translate }}
+            </span>
+          </div>
+
+          <div class="data-row" *ngFor="let operation of interface1.operations"
+               (click)="onSelectInterfaceOperation(interface1, operation)">
+            <span
+                class="cell field-name">
+                {{operation.name}}
+            </span>
+            <span class="cell field-description"
+                  [ngClass]="{'collapsed': operation.isCollapsed}">
+              {{operation.getDescriptionEllipsis()}}
+              <span class="more-or-less link" (click)="operation.toggleCollapsed($event)">
+                {{!operation.isEllipsis ? '' : operation.isCollapsed ? 'More' : 'Less'}}
+              </span>
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.less
new file mode 100644
index 0000000..1ebfb1f
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.less
@@ -0,0 +1,216 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+@import './../../../../../assets/styles/override.less';
+@import './../../../../../assets/styles/variables.less';
+
+.interface-operations {
+  font-size: 14px;
+
+  .top-add-btn {
+    position: relative;
+    top: -31px;
+    text-transform: uppercase;
+    font-size: 14px;
+    font-family: @font-opensans-medium;
+  }
+
+  .link {
+    color: @sdcui_color_blue;
+    text-decoration: underline;
+    font-family: @font-opensans-regular;
+
+    &:not(.disabled) {
+      &:not(.empty-list-add-btn) {
+        &:hover {
+          color: @sdcui_color_dark-blue;
+          cursor: pointer;
+        }
+      }
+    }
+  }
+
+  .operation-list {
+    border-top: 1px solid @main_color_o;
+    padding-top: 5px;
+
+    .empty-list-container {
+      width: 100%;
+      display: flex;
+      justify-content: center;
+
+      .empty-list-add-btn {
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+
+        border: 1px solid @main_color_o;
+        margin-top: 50px;
+
+        height: 229px;
+        width: 480px;
+
+        &.disabled {
+          pointer-events: none;
+        }
+
+        &:hover {
+          &:not(.disabled) {
+            border: 1px solid @sdcui_color_blue;
+            cursor: pointer;
+          }
+        }
+
+        .button-text {
+          margin-top: 9px;
+          font-family: @font-opensans-medium;
+          font-size: 16px;
+          text-transform: uppercase;
+          color: @sdcui_color_blue;
+        }
+      }
+    }
+
+    .expand-collapse {
+      margin-top: 4px;
+      margin-bottom: 18px;
+      color: @sdcui_color_light-gray;
+    }
+
+    .interface-row {
+      width: 100%;
+      margin-top: 13px;
+      border-bottom: 1px solid @main_color_o;
+      padding-left: 4px;
+      min-height: 37px;
+
+
+      .interface-accordion {
+        cursor: pointer;
+
+        .chevron-container {
+          position: relative;
+          margin-right: 5px;
+
+          &.isCollapsed {
+            right: -6px;
+            top: 0;
+            * {
+              transform: rotate(270deg);
+            }
+          }
+          &:not(.isCollapsed) {
+            top: 6px;
+          }
+          * {
+            &:hover {
+              cursor: pointer;
+            }
+          }
+        }
+        .interface-name {
+          font-size: 18px;
+          font-family: @font-opensans-bold;
+          margin-bottom: 15px;
+        }
+      }
+
+      .generic-table {
+        margin-bottom: 24px;
+        margin-top: 10px;
+        margin-left: 22px;
+        font-size: 14px;
+
+        .header-row, .data-row {
+          .cell {
+            &.field-description {
+              flex: 2.5;
+            }
+
+            &.field-actions {
+              flex-basis: 72px;
+              display: flex;
+              justify-content: center;
+              align-items: center;
+            }
+          }
+        }
+
+        .header-row {
+          .cell {
+            background: @sdcui_color_silver;
+
+            &.field-actions {
+              font-size: 10px;
+            }
+          }
+        }
+
+        .data-row {
+          cursor: pointer;
+
+          &:hover {
+            background: @sdcui_color_light-silver;
+
+            .cell {
+              &.field-name {
+                color: @sdcui_color_dark-blue;
+              }
+            }
+          }
+
+          &:not(:hover) {
+            .field-actions {
+              visibility: hidden;
+            }
+          }
+
+          .cell {
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+
+            &.field-description {
+              &:not(.collapsed) {
+                white-space: normal;
+              }
+              &.collapsed {
+                text-overflow: clip;
+              }
+              .more-or-less {
+                margin-left: 5px;
+              }
+            }
+
+            &.field-actions {
+              .delete-action {
+                position: relative;
+                top: 2px;
+              }
+            }
+          }
+
+        }
+      }
+
+    }
+  }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts
new file mode 100644
index 0000000..304fbce
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts
@@ -0,0 +1,247 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+*  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+*  ================================================================================
+*  Licensed under the Apache License, Version 2.0 (the "License");
+*  you may not use this file except in compliance with the License.
+*  You may obtain a copy of the License at
+*
+*        http://www.apache.org/licenses/LICENSE-2.0
+*  Unless required by applicable law or agreed to in writing, software
+*  distributed under the License is distributed on an "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*  See the License for the specific language governing permissions and
+*  limitations under the License.
+*
+*  SPDX-License-Identifier: Apache-2.0
+*  ============LICENSE_END=========================================================
+*/
+
+import {Component, ComponentRef, Input} from '@angular/core';
+import {TopologyTemplateService} from '../../../services/component-services/topology-template.service';
+import {TranslateService} from "../../../shared/translator/translate.service";
+import {ModalService } from 'app/ng2/services/modal.service';
+import { ModalComponent } from 'app/ng2/components/ui/modal/modal.component';
+import {
+  Component as TopologyTemplate
+} from "../../../../models/components/component";
+import {PluginsService} from "app/ng2/services/plugins.service";
+import {SelectedComponentType} from "../common/store/graph.actions";
+
+import {WorkspaceService} from "../../workspace/workspace.service";
+import {
+  ComponentInstanceInterfaceModel,
+  InterfaceOperationModel
+} from "../../../../models/interfaceOperation";
+import {
+  InterfaceOperationHandlerComponent
+} from "./operation-creator/interface-operation-handler.component";
+
+import {
+  ButtonModel,
+  ComponentMetadata,
+  InterfaceModel,
+  InputBEModel,
+  ModalModel,
+  ComponentInstance
+} from 'app/models';
+
+export class UIInterfaceOperationModel extends InterfaceOperationModel {
+  isCollapsed: boolean = true;
+  isEllipsis: boolean;
+  MAX_LENGTH = 75;
+  _description: string;
+
+  constructor(operation: InterfaceOperationModel) {
+    super(operation);
+
+    if (!operation.description) {
+      this.description = '';
+    }
+
+    if (this.description.length > this.MAX_LENGTH) {
+      this.isEllipsis = true;
+    } else {
+      this.isEllipsis = false;
+    }
+  }
+
+  getDescriptionEllipsis(): string {
+    if (this.isCollapsed && this.description.length > this.MAX_LENGTH) {
+      return this.description.substr(0, this.MAX_LENGTH - 3) + '...';
+    }
+    return this.description;
+  }
+
+  toggleCollapsed(e) {
+    e.stopPropagation();
+    this.isCollapsed = !this.isCollapsed;
+  }
+}
+
+class ModalTranslation {
+  EDIT_TITLE: string;
+  CANCEL_BUTTON: string;
+  SAVE_BUTTON: string;
+
+  constructor(private TranslateService: TranslateService) {
+    this.TranslateService.languageChangedObservable.subscribe(lang => {
+      this.EDIT_TITLE = this.TranslateService.translate('INTERFACE_EDIT_TITLE');
+      this.CANCEL_BUTTON = this.TranslateService.translate("INTERFACE_CANCEL_BUTTON");
+      this.SAVE_BUTTON = this.TranslateService.translate("INTERFACE_SAVE_BUTTON");
+    });
+  }
+}
+
+export class UIInterfaceModel extends ComponentInstanceInterfaceModel {
+  isCollapsed: boolean = false;
+
+  constructor(interf?: any) {
+    super(interf);
+    this.operations = _.map(
+        this.operations,
+        (operation) => new UIInterfaceOperationModel(operation)
+    );
+  }
+
+  toggleCollapse() {
+    this.isCollapsed = !this.isCollapsed;
+  }
+}
+
+@Component({
+  selector: 'app-interface-operations',
+  templateUrl: './interface-operations.component.html',
+  styleUrls: ['./interface-operations.component.less'],
+  providers: [ModalService, TranslateService]
+})
+export class InterfaceOperationsComponent {
+  interfaces: UIInterfaceModel[];
+  selectedOperation: InterfaceOperationModel;
+  inputs: Array<InputBEModel>;
+  isLoading: boolean;
+  interfaceTypes: { [interfaceType: string]: string[] };
+  topologyTemplate: TopologyTemplate;
+  componentMetaData: ComponentMetadata;
+  componentInstanceSelected: ComponentInstance;
+  modalInstance: ComponentRef<ModalComponent>;
+  modalTranslation: ModalTranslation;
+  componentInstancesInterfaces: Map<string, InterfaceModel[]>;
+
+  @Input() component: ComponentInstance;
+  @Input() readonly: boolean;
+  @Input() enableMenuItems: Function;
+  @Input() disableMenuItems: Function;
+  @Input() componentType: SelectedComponentType;
+
+
+  constructor(
+      private TranslateService: TranslateService,
+      private PluginsService: PluginsService,
+      private topologyTemplateService: TopologyTemplateService,
+      private modalServiceNg2: ModalService,
+      private workspaceService: WorkspaceService,
+  ) {
+    this.modalTranslation = new ModalTranslation(TranslateService);
+  }
+
+  ngOnInit(): void {
+    this.componentMetaData = this.workspaceService.metadata;
+    this.loadComponentInstances();
+  }
+
+  private loadComponentInstances() {
+    this.isLoading = true;
+    this.topologyTemplateService.getComponentInstances(this.componentMetaData.componentType, this.componentMetaData.uniqueId)
+    .subscribe((response) => {
+      this.componentInstanceSelected = response.componentInstances.find(ci => ci.uniqueId === this.component.uniqueId);
+      this.initComponentInstanceInterfaceOperations();
+      this.isLoading = false;
+    });
+  }
+
+  private initComponentInstanceInterfaceOperations() {
+    this.initInterfaces(this.componentInstanceSelected.interfaces);
+    this.sortInterfaces();
+  }
+
+  private initInterfaces(interfaces: InterfaceModel[]): void {
+    this.interfaces = _.map(interfaces, (interfaceModel) => new UIInterfaceModel(interfaceModel));
+  }
+
+  private sortInterfaces(): void {
+    this.interfaces = _.filter(this.interfaces, (interf) => interf.operations && interf.operations.length > 0); // remove empty interfaces
+    this.interfaces.sort((a, b) => a.type.localeCompare(b.type)); // sort interfaces alphabetically
+    _.forEach(this.interfaces, (interf) => {
+      interf.operations.sort((a, b) => a.name.localeCompare(b.name)); // sort operations alphabetically
+    });
+  }
+
+  collapseAll(value: boolean = true): void {
+    _.forEach(this.interfaces, (interf) => {
+      interf.isCollapsed = value;
+    });
+  }
+
+  isAllCollapsed(): boolean {
+    return _.every(this.interfaces, (interf) => interf.isCollapsed);
+  }
+
+  isAllExpanded(): boolean {
+    return _.every(this.interfaces, (interf) => !interf.isCollapsed);
+  }
+
+  isListEmpty(): boolean {
+    return _.filter(
+        this.interfaces,
+        (interf) => interf.operations && interf.operations.length > 0
+    ).length === 0;
+  }
+
+  private enableOrDisableSaveButton = (): boolean => {
+    return !this.modalInstance.instance.dynamicContent.instance.checkFormValidForSubmit();
+  }
+
+  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.updateInterfaceOperation(), this.enableOrDisableSaveButton);
+    const modalModel: ModalModel = new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', [saveButton, cancelButton], 'custom');
+    this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
+
+    this.modalServiceNg2.addDynamicContentToModal(
+        this.modalInstance,
+        InterfaceOperationHandlerComponent,
+        {
+          selectedInterface: interfaceModel,
+          selectedInterfaceOperation: operation,
+          validityChangedCallback: this.enableOrDisableSaveButton
+        }
+    );
+    this.modalInstance.instance.open();
+  }
+
+  private cancelAndCloseModal = () => {
+    this.loadComponentInstances();
+    return this.modalServiceNg2.closeCurrentModal();
+  }
+
+  private updateInterfaceOperation() {
+    this.isLoading = true;
+    let operationUpdated = this.modalInstance.instance.dynamicContent.instance.operationToUpdate;
+    this.topologyTemplateService.updateComponentInstanceInterfaceOperation(
+        this.componentMetaData.uniqueId,
+        this.componentMetaData.componentType,
+        this.componentInstanceSelected.uniqueId,
+        operationUpdated)
+    .subscribe((updatedComponentInstance: ComponentInstance) => {
+      this.componentInstanceSelected = new ComponentInstance(updatedComponentInstance);
+      this.initComponentInstanceInterfaceOperations();
+    });
+    this.modalServiceNg2.closeCurrentModal();
+    this.isLoading = false;
+  }
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.html
new file mode 100644
index 0000000..80aceea
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.html
@@ -0,0 +1,44 @@
+<!--
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ -->
+
+<div class="cell field-input-name">
+    <sdc-input
+        [(value)]="input.name"
+        (valueChange)="onChange()">
+    </sdc-input>
+</div>
+
+<div class="cell field-input-value">
+    <sdc-input
+        [(value)]="input.toscaDefaultValue"
+        (valueChange)="onChange()">
+    </sdc-input>
+
+</div>
+
+<div class="cell remove" *ngIf="!readonly">
+    <svg-icon
+        name="trash-o"
+        mode="info"
+        size="small"
+        (click)="onRemoveInput(input)"
+        [clickable]="true">
+    </svg-icon>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.less
new file mode 100644
index 0000000..12eacc6
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.less
@@ -0,0 +1,72 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+@import '../../../../../../../assets/styles/variables.less';
+
+.remove {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    svg-icon {
+        position: relative;
+        right: -3px;
+
+        &:hover {
+            cursor: pointer;
+        }
+    }
+}
+
+.cell {
+    min-height: 50px;
+    padding: 10px;
+    display: flex;
+    align-items: center;
+
+    > * {
+        flex-basis: 100%;
+    }
+
+    /deep/ select {
+        height: 30px;
+    }
+
+    input {
+        height: 30px;
+        border: none;
+        padding-left: 10px;
+    }
+
+    select {
+        width: 100%;
+    }
+
+    &.field-property {
+        &:last-child {
+            flex: 1;
+        }
+
+        .no-properties-error {
+            color: @func_color_q;
+            font-style: italic;
+        }
+    }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.ts
new file mode 100644
index 0000000..48bb804
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.ts
@@ -0,0 +1,48 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+*  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+*  ================================================================================
+*  Licensed under the Apache License, Version 2.0 (the "License");
+*  you may not use this file except in compliance with the License.
+*  You may obtain a copy of the License at
+*
+*        http://www.apache.org/licenses/LICENSE-2.0
+*  Unless required by applicable law or agreed to in writing, software
+*  distributed under the License is distributed on an "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*  See the License for the specific language governing permissions and
+*  limitations under the License.
+*
+*  SPDX-License-Identifier: Apache-2.0
+*  ============LICENSE_END=========================================================
+*/
+
+import {Component, Input} from '@angular/core';
+import {InputOperationParameter} from "../../../../../../models/interfaceOperation";
+
+@Component({
+  selector: 'input-param-row',
+  templateUrl: './input-param-row.component.html',
+  styleUrls: ['./input-param-row.component.less']
+})
+
+export class InputParamRowComponent {
+  @Input() input: InputOperationParameter;
+  @Input() onRemoveInput: Function;
+  @Input() readonly: boolean;
+  @Input() validityChanged: Function;
+
+  constructor() {
+  }
+
+  ngOnInit() {
+    this.validityChanged();
+  }
+
+  onChange() {
+    this.validityChanged();
+  }
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html
new file mode 100644
index 0000000..cd2d606
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html
@@ -0,0 +1,86 @@
+<!--
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+-->
+
+<div class="operation-handler">
+  <loader [display]="isLoading" [size]="'large'" [relative]="true"></loader>
+
+  <form class="w-sdc-form">
+
+    <div class="side-by-side">
+      <div class="form-item">
+        <sdc-input
+            label="{{ 'OPERATION_INTERFACE_TYPE' | translate }}"
+            [(value)]="interfaceType"
+            [disabled]="true">
+        </sdc-input>
+      </div>
+
+      <div class="form-item">
+        <sdc-input
+            label="{{ 'OPERATION_NAME' | translate }}"
+            [(value)]="operationToUpdate.name"
+            [disabled]="true">
+        </sdc-input>
+      </div>
+    </div>
+
+    <div class="i-sdc-form-item">
+      <sdc-input
+          label="{{'OPERATION_DESCRIPTION' | translate}}"
+          [(value)]="operationToUpdate.description"
+          (valueChange)="onDescriptionChange($event)">
+      </sdc-input>
+    </div>
+
+    <div class="i-sdc-form-item">
+      <sdc-input
+          label="{{'IMPLEMENTATION_NAME' | translate}}"
+          [(value)]="operationToUpdate.implementation.artifactName">
+      </sdc-input>
+    </div>
+
+    <div class="separator-buttons">
+      <tab tabTitle="Inputs"></tab>
+      <a class="add-param-link add-btn"
+         [ngClass]="{'disabled': readonly}"
+         (click)="onAddInput()">{{'OPERATION_ADD_INPUT' | translate}}
+      </a>
+    </div>
+
+    <div class="generic-table">
+      <div class="header-row table-row">
+        <span class="cell header-cell field-input-name">{{ 'OPERATION_PARAM_NAME' | translate }}</span>
+        <span class="cell header-cell field-input-value">{{ 'OPERATION_INPUT_VALUE' | translate }}</span>
+        <span class="cell header-cell remove">●●●</span>
+      </div>
+      <div class="empty-msg data-row" *ngIf="!inputs.length">
+        <div>{{ 'OPERATION_INPUT_EMPTY' | translate }}</div>
+      </div>
+      <input-param-row
+          *ngFor="let inputParameter of inputs"
+          class="data-row"
+          [input]="inputParameter"
+          [onRemoveInput]="onRemoveInput"
+          [validityChanged]="validityChanged">
+      </input-param-row>
+    </div>
+
+  </form>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less
new file mode 100644
index 0000000..8bbed9d
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less
@@ -0,0 +1,200 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+@import '../../../../../../assets/styles/variables.less';
+@import '../../../../../../assets/styles/override.less';
+
+.operation-handler {
+    font-family: @font-opensans-regular;
+    user-select: none;
+    padding-top: 12px;
+    padding-bottom: 20px;
+
+    .i-sdc-form-label {
+        font-size: 12px;
+    }
+
+    .w-sdc-form .i-sdc-form-item {
+        margin-bottom: 15px;
+    }
+
+    textarea {
+        min-height: 74px;
+        margin-bottom: 18px;
+    }
+
+    /deep/ .sdc-dropdown__component-container {
+        .sdc-dropdown__header {
+            height: 38px;
+            line-height: 35px;
+
+            svg-icon {
+                margin: 13px 6px;
+            }
+        }
+    }
+
+    /deep/ .sdc-input {
+        margin-bottom: 0;
+
+        .sdc-input__input {
+            height: 38px;
+        }
+    }
+
+    .side-by-side {
+        display: flex;
+
+        .form-item {
+            flex: 1;
+
+            &:first-child {
+                margin-right: 14px;
+                flex-basis: 37%;
+                flex-grow: 0;
+                flex-shrink: 0;
+            }
+
+            &:nth-child(3) {
+                margin-left: 14px;
+                flex: 0.4;
+            }
+
+            .i-sdc-form-file-upload {
+                height: 37px;
+                margin-bottom: 0;
+
+                .i-sdc-form-file-name {
+                    padding: 8px 10px;
+                }
+
+                .i-sdc-form-file-upload-x-btn {
+                    top: 13px;
+                }
+
+                .file-upload-browse-btn {
+                    height: 100%;
+                    padding: 7px 6px;
+                    z-index: 1;
+                }
+            }
+
+        }
+    }
+
+    .archive-warning {
+        font-family: @font-opensans-bold;
+        color: @main_color_i;
+    }
+
+    .no-workflow-warning {
+        font-family: @font-opensans-bold;
+        color: @sdcui_color_red;
+        float: right;
+    }
+
+    .input-param-title {
+        font-size: 16px;
+        text-transform: uppercase;
+    }
+
+    .separator-buttons {
+        display: flex;
+        justify-content: space-between;
+        margin-top: 10px;
+
+        .add-param-link {
+            &:not(.disabled):hover {
+                cursor: pointer;
+            }
+        }
+
+        .tab {
+            width: 84px;
+            text-align: center;
+        }
+    }
+
+    .generic-table {
+        max-height: 244px;
+        min-height: 91px;
+        background: @main_color_p;
+
+        .header-row .header-cell {
+            .info-icon {
+                float: right;
+                position: relative;
+                top: 2px;
+            }
+            /deep/ .tooltip-inner {
+                padding: 2px;
+                max-width: 270px;
+                font-size: 11px;
+            }
+            &.remove {
+                padding: 10px;
+                font-size: 10px;
+            }
+        }
+
+        .data-row {
+            &.empty-msg {
+                .bold-message {
+                    font-family: @font-opensans-bold;
+                }
+
+                :first-child {
+                    &:not(:only-child) {
+                        margin: 6px 0;
+                    }
+                }
+
+                display: flex;
+                flex-direction: column;
+                justify-content: center;
+                align-items: center;
+                padding: 14px;
+            }
+        }
+
+        /deep/ .cell {
+            &.field-input-name, &.field-input-value{
+                flex: 1;
+            }
+
+            &.field-property {
+                &, &:last-child {
+                    flex: 1;
+                }
+            }
+
+            &.field-mandatory {
+                flex: 0.5;
+                text-align: center;
+            }
+
+            &.remove {
+                min-width: 40px;
+                max-width: 40px;
+            }
+        }
+
+    }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts
new file mode 100644
index 0000000..1618af4
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts
@@ -0,0 +1,130 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+*  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+*  ================================================================================
+*  Licensed under the Apache License, Version 2.0 (the "License");
+*  you may not use this file except in compliance with the License.
+*  You may obtain a copy of the License at
+*
+*        http://www.apache.org/licenses/LICENSE-2.0
+*  Unless required by applicable law or agreed to in writing, software
+*  distributed under the License is distributed on an "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*  See the License for the specific language governing permissions and
+*  limitations under the License.
+*
+*  SPDX-License-Identifier: Apache-2.0
+*  ============LICENSE_END=========================================================
+*/
+
+import {Component} from '@angular/core';
+import {UIInterfaceModel} from "../interface-operations.component";
+import {
+    InputOperationParameter,
+    InterfaceOperationModel,
+    IOperationParamsList
+} from "../../../../../models/interfaceOperation";
+import {TranslateService} from "../../../../shared/translator/translate.service";
+
+@Component({
+    selector: 'operation-handler',
+    templateUrl: './interface-operation-handler.component.html',
+    styleUrls: ['./interface-operation-handler.component.less'],
+    providers: [TranslateService]
+})
+
+export class InterfaceOperationHandlerComponent {
+
+    input: {
+        selectedInterface: UIInterfaceModel;
+        selectedInterfaceOperation: InterfaceOperationModel;
+        validityChangedCallback: Function;
+    };
+
+    interfaceType: string;
+    interfaceOperationName: string;
+    operationToUpdate: InterfaceOperationModel;
+    inputs: Array<InputOperationParameter> = [];
+    isLoading: boolean = false;
+    readonly: boolean;
+
+    ngOnInit() {
+        this.interfaceType = this.input.selectedInterface.displayType();
+        this.operationToUpdate = new InterfaceOperationModel(this.input.selectedInterfaceOperation);
+        this.operationToUpdate.interfaceId = this.input.selectedInterface.uniqueId;
+        this.operationToUpdate.interfaceType = this.input.selectedInterface.type;
+        if (!this.operationToUpdate.inputs) {
+            this.operationToUpdate.inputs = new class implements IOperationParamsList {
+                listToscaDataDefinition: Array<InputOperationParameter> = [];
+            }
+        }
+        this.inputs = this.operationToUpdate.inputs.listToscaDataDefinition;
+        this.removeImplementationQuote();
+        this.validityChanged();
+    }
+
+    onAddInput(inputOperationParameter?: InputOperationParameter): void {
+        let newInput = new InputOperationParameter(inputOperationParameter)
+        newInput.type = "string";
+        newInput.inputId = this.generateUniqueId();
+        this.inputs.push(newInput);
+        this.validityChanged();
+    }
+
+    onRemoveInput = (inputParam: InputOperationParameter): void => {
+        let index = this.inputs.indexOf(inputParam);
+        this.inputs.splice(index, 1);
+        this.validityChanged();
+    }
+
+    private generateUniqueId = (): string => {
+        let result = '';
+        const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+        const charactersLength = characters.length;
+        for (let i = 0; i < 36; i++ ) {
+            result += characters.charAt(Math.floor(Math.random() * charactersLength));
+        }
+        return result;
+    }
+
+    validityChanged = () => {
+        let validState = this.checkFormValidForSubmit();
+        this.input.validityChangedCallback(validState);
+        if (validState) {
+            this.readonly = false;
+        }
+    }
+
+    onDescriptionChange= (value: any): void => {
+        this.operationToUpdate.description = value;
+    }
+
+    private checkFormValidForSubmit = (): boolean => {
+        return this.operationToUpdate.name && this.isParamsValid();
+    }
+
+    private isParamsValid = (): boolean => {
+        const isInputValid = (input) => input.name && input.inputId;
+        const isValid = this.inputs.every(isInputValid);
+        if (!isValid) {
+            this.readonly = true;
+        }
+        return isValid;
+    }
+
+    private removeImplementationQuote(): void {
+        if (!this.operationToUpdate.implementation
+            || !this.operationToUpdate.implementation.artifactName) {
+            return;
+        }
+
+        let implementation = this.operationToUpdate.implementation.artifactName.trim();
+
+        if (implementation.startsWith("'") && implementation.endsWith("'")) {
+            this.operationToUpdate.implementation.artifactName = implementation.slice(1, -1);
+        }
+    }
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts
new file mode 100644
index 0000000..deba50a
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts
@@ -0,0 +1,55 @@
+/*
+* ============LICENSE_START=======================================================
+* SDC
+* ================================================================================
+*  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+*  ================================================================================
+*  Licensed under the Apache License, Version 2.0 (the "License");
+*  you may not use this file except in compliance with the License.
+*  You may obtain a copy of the License at
+*
+*        http://www.apache.org/licenses/LICENSE-2.0
+*  Unless required by applicable law or agreed to in writing, software
+*  distributed under the License is distributed on an "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*  See the License for the specific language governing permissions and
+*  limitations under the License.
+*
+*  SPDX-License-Identifier: Apache-2.0
+*  ============LICENSE_END=========================================================
+*/
+
+import {NgModule} from "@angular/core";
+import {CommonModule} from "@angular/common";
+
+import {FormsModule} from "@angular/forms";
+import {FormElementsModule} from "app/ng2/components/ui/form-components/form-elements.module";
+import {TranslateModule} from "app/ng2/shared/translator/translate.module";
+
+import {SdcUiComponentsModule} from 'onap-ui-angular';
+import {UiElementsModule} from '../../../../components/ui/ui-elements.module';
+import {InputParamRowComponent} from './input-param-row/input-param-row.component';
+import {InterfaceOperationHandlerComponent} from "./interface-operation-handler.component";
+
+@NgModule({
+  declarations: [
+    InterfaceOperationHandlerComponent,
+    InputParamRowComponent
+  ],
+  imports: [
+    CommonModule,
+    SdcUiComponentsModule,
+    FormsModule,
+    FormElementsModule,
+    TranslateModule,
+    UiElementsModule
+  ],
+  exports: [],
+  entryComponents: [
+    InterfaceOperationHandlerComponent
+  ],
+  providers: []
+})
+
+export class InterfaceOperationHandlerModule {
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.spec.ts
index 1761bfd..6d96764 100644
--- a/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.spec.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.spec.ts
@@ -8,7 +8,7 @@
 import { Resource } from '../../../../models/components/resource';
 import { GroupInstance } from '../../../../models/graph/zones/group-instance';
 import { PolicyInstance } from '../../../../models/graph/zones/policy-instance';
-import { ArtifactGroupType, ResourceType } from '../../../../utils/constants';
+import { ArtifactGroupType } from '../../../../utils/constants';
 import { WorkspaceState } from '../../../store/states/workspace.state';
 import { CompositionPanelComponent } from './composition-panel.component';
 import { ArtifactsTabComponent } from './panel-tabs/artifacts-tab/artifacts-tab.component';
@@ -19,6 +19,7 @@
 import { PropertiesTabComponent } from './panel-tabs/properties-tab/properties-tab.component';
 import { ReqAndCapabilitiesTabComponent } from './panel-tabs/req-capabilities-tab/req-capabilities-tab.component';
 import {SubstitutionFilterTabComponent} from "./panel-tabs/substitution-filter-tab/substitution-filter-tab.component";
+import {InterfaceOperationsComponent} from "../interface-operatons/interface-operations.component";
 
 describe('composition-panel component', () => {
 
@@ -61,7 +62,13 @@
             },
             inputs: {titleIcon: 'inputs-o', component: PropertiesTabComponent, input: {title: 'Inputs'}, isActive: false, tooltipText: 'Inputs'},
             settings: {titleIcon: 'settings-o', component: PropertiesTabComponent, input: {}, isActive: false, tooltipText: 'Settings'},
-
+            interfaceOperations: {
+                titleIcon: 'composition-o',
+                component: InterfaceOperationsComponent,
+                input: {title: 'Interface Operations'},
+                isActive: false,
+                tooltipText: 'Interface Operations'
+            }
         };
 
     beforeEach(
@@ -157,17 +164,17 @@
         fixture.componentInstance.store.select = jest.fn(() => Observable.of(selectedComponent));
         fixture.componentInstance.selectedComponentIsServiceProxyInstance = jest.fn(() => true);
 
-        // const pnfMock = Mock.of<Service>({ isResource : () => false });
         fixture.componentInstance.topologyTemplate = selectedComponent;
 
         // Call ngOnInit
         fixture.componentInstance.ngOnInit();
 
         // Expect that
-        expect (fixture.componentInstance.tabs.length).toBe(6);
+        expect (fixture.componentInstance.tabs.length).toBe(7);
         expect (fixture.componentInstance.tabs[0]).toEqual(tabs.infoTab);
         expect (fixture.componentInstance.tabs[1]).toEqual(tabs.properties);
         expect (fixture.componentInstance.tabs[2]).toEqual(tabs.reqAndCapabilities);
+        expect (fixture.componentInstance.tabs[6]).toEqual(tabs.interfaceOperations);
 
     });
 
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.ts
index 2fce002..2ef4e7c 100644
--- a/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.component.ts
@@ -39,6 +39,7 @@
 import { ServiceConsumptionTabComponent } from './panel-tabs/service-consumption-tab/service-consumption-tab.component';
 import { ServiceDependenciesTabComponent } from './panel-tabs/service-dependencies-tab/service-dependencies-tab.component';
 import {SubstitutionFilterTabComponent} from "./panel-tabs/substitution-filter-tab/substitution-filter-tab.component";
+import {InterfaceOperationsComponent} from "../interface-operatons/interface-operations.component";
 
 const tabs = {
     infoTab : {titleIcon: 'info-circle', component: InfoTabComponent, input: {}, isActive: true, tooltipText: 'Information'},
@@ -55,7 +56,8 @@
     settings: {titleIcon: 'settings-o', component: PropertiesTabComponent, input: {}, isActive: false, tooltipText: 'Settings'},
     consumption: {titleIcon: 'api-o', component: ServiceConsumptionTabComponent, input: {title: 'OPERATION CONSUMPTION'}, isActive: false, tooltipText: 'Service Consumption'},
     dependencies: {titleIcon: 'archive', component: ServiceDependenciesTabComponent, input: {title: 'DIRECTIVES AND NODE FILTER'}, isActive: false, tooltipText: 'Service Dependencies'},
-    substitutionFilter: {titleIcon: 'composition-o', component: SubstitutionFilterTabComponent, input: {title: 'SUBSTITUTION FILTER'}, isActive: false, tooltipText: 'Substitution Filter'}
+    substitutionFilter: {titleIcon: 'composition-o', component: SubstitutionFilterTabComponent, input: {title: 'SUBSTITUTION FILTER'}, isActive: false, tooltipText: 'Substitution Filter'},
+    interfaceOperations: {titleIcon: 'composition-o', component: InterfaceOperationsComponent, input: {title: 'Interface Operations'}, isActive: false, tooltipText: 'Interface Operations'}
 };
 
 @Component({
@@ -86,6 +88,12 @@
         });
     }
 
+
+    onRightClick(selectedComponent: any) {
+        console.info("onRightClick", selectedComponent)
+        return false;
+    }
+
     ngOnDestroy() {
         if (this.subscription) {
             this.subscription.unsubscribe();
@@ -151,8 +159,10 @@
         if (component.isService() && (this.selectedComponentIsServiceProxyInstance() || this.selectedComponentIsServiceSubstitutionInstance())) {
             this.tabs.push(tabs.consumption);
             this.tabs.push(tabs.dependencies);
+            this.tabs.push(tabs.interfaceOperations);
         } else if (component.isResource() && this.isComponentInstanceSelected()) {
             this.tabs.push(tabs.dependencies);
+            this.tabs.push(tabs.interfaceOperations);
         }
 
     }
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.module.ts b/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.module.ts
index a89db21..595ee21 100644
--- a/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.module.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.module.ts
@@ -49,7 +49,7 @@
 import { ServiceConsumptionModule } from "../../../components/logic/service-consumption/service-consumption.module";
 import {SubstitutionFilterTabComponent} from "./panel-tabs/substitution-filter-tab/substitution-filter-tab.component";
 import {SubstitutionFilterModule} from "../../../components/logic/substitution-filter/substitution-filter.module";
-
+import {InterfaceOperationsComponent} from "../interface-operatons/interface-operations.component";
 
 
 @NgModule({
@@ -67,7 +67,8 @@
         ServiceDependenciesTabComponent,
         SubstitutionFilterTabComponent,
         RequirementListComponent,
-        EnvParamsComponent
+        EnvParamsComponent,
+        InterfaceOperationsComponent,
     ],
     imports: [
         GlobalPipesModule,
@@ -81,7 +82,7 @@
         NgxDatatableModule,
         ServiceDependenciesModule,
         ServiceConsumptionModule,
-        SubstitutionFilterModule
+        SubstitutionFilterModule,
         // EnvParamsModule
     ],
     entryComponents: [
@@ -98,7 +99,8 @@
         SubstitutionFilterTabComponent,
         RequirementListComponent,
         PanelTabComponent,
-        EnvParamsComponent
+        EnvParamsComponent,
+        InterfaceOperationsComponent
         ],
     exports: [
         CompositionPanelComponent
diff --git a/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts b/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts
index 492acdc..953f0a1 100644
--- a/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts
+++ b/catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts
@@ -35,7 +35,7 @@
     PropertyModel,
     IFileDownload,
     AttributeModel,
-    Capability, Requirement
+    Capability, Requirement, BEOperationModel, InterfaceModel
 } from "app/models";
 import {ArtifactGroupType, COMPONENT_FIELDS} from "app/utils";
 import {ComponentGenericResponse} from "../responses/component-generic-response";
@@ -65,6 +65,11 @@
 import { PropertyBEModel } from "../../../models/properties-inputs/property-be-model";
 import {map} from "rxjs/operators";
 import {CapabilitiesConstraintObject} from "../../components/logic/capabilities-constraint/capabilities-constraint.component";
+import {
+    BEInterfaceOperationModel,
+    ComponentInstanceInterfaceModel,
+    InterfaceOperationModel
+} from "../../../models/interfaceOperation";
 
 /* we need to use this service from now, we will remove component.service when we finish remove the angular1.
  The service is duplicated since we can not use downgrades service with NGXS*/
@@ -108,8 +113,8 @@
             [COMPONENT_FIELDS.COMPONENT_INSTANCES, COMPONENT_FIELDS.COMPONENT_POLICIES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_GROUPS]);
     }
 
-    getComponentResourceInstances(component: Component): Observable<ComponentGenericResponse> {
-        return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES]);
+    getComponentInstances(componentType: string, componentId: string): Observable<ComponentGenericResponse> {
+        return this.getComponentDataByFieldsName(componentType, componentId, [COMPONENT_FIELDS.COMPONENT_INSTANCES]);
     }
 
     getComponentInputs(component: Component): Observable<ComponentGenericResponse> {
@@ -478,6 +483,7 @@
     }
 
     protected getComponentDataByFieldsName(componentType: string, componentId: string, fields: string[]): Observable<ComponentGenericResponse> {
+        console.info("Topology template -> getComponentDataByFieldsName with id:", componentId)
         let params: HttpParams = new HttpParams();
         _.forEach(fields, (field: string): void => {
             params = params.append(API_QUERY_PARAMS.INCLUDE, field);
@@ -485,6 +491,7 @@
         // tslint:disable-next-line:object-literal-shorthand
         return this.http.get<ComponentGenericResponse>(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/filteredDataByParams', {params: params})
             .map((res) => {
+                console.info("Topology template -> getComponentDataByFieldsName response:", res);
                 return componentType === ComponentType.SERVICE ? new ServiceGenericResponse().deserialize(res) :
                         new ComponentGenericResponse().deserialize(res);
             });
@@ -564,4 +571,22 @@
         .pipe(map(response => response.directives));
     }
 
+    updateComponentInstanceInterfaceOperation(componentMetaDataId: string,
+                                              componentMetaDataType: string,
+                                              componentInstanceId: string,
+                                              operation: InterfaceOperationModel): Observable<ComponentInstance> {
+        const operationList = {
+            interfaces: {
+                [operation.interfaceType]: {
+                    type: operation.interfaceType,
+                    operations: {
+                        [operation.name]: new BEInterfaceOperationModel(operation)
+                    }
+                }
+            }
+        };
+        return this.http.put<ComponentInstance>(this.baseUrl + this
+        .getServerTypeUrl(componentMetaDataType) + componentMetaDataId + '/componentInstance/' + componentInstanceId + '/interfaceOperation', operationList);
+    }
+
 }
diff --git a/catalog-ui/src/assets/languages/en_US.json b/catalog-ui/src/assets/languages/en_US.json
index cc33b36..7cc6d55 100644
--- a/catalog-ui/src/assets/languages/en_US.json
+++ b/catalog-ui/src/assets/languages/en_US.json
@@ -468,6 +468,7 @@
     "OPERATION_INTERFACE_TYPE": "Interface Name",
     "OPERATION_NAME": "Operation Name",
     "OPERATION_IMPLEMENTATION": "Implementation",
+    "IMPLEMENTATION_NAME": "Implementation Name",
     "OPERATION_DESCRIPTION": "Description",
     "OPERATION_ARTIFACT": "Workflow Artifact",
     "OPERATION_WORKFLOW_ASSIGNMENT": "Workflow Assignment",
@@ -482,6 +483,9 @@
     "OPERATION_PARAM_VALUE": "Value",
     "OPERATION_PARAM_PROPERTY": "Property",
     "OPERATION_PARAM_MANDATORY": "Mandatory",
+    "OPERATION_INPUT_EMPTY": "No Input Data",
+    "OPERATION_INPUT_VALUE": "Value",
+    "OPERATION_ADD_INPUT": "Add Input",
     "OPERATION_ADD": "Add",
     "OPERATION_ADD1": "Add Operation",
     "OPERATION_CANCEL": "Cancel",