aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-ui/src/app/ng2/pages/composition/interface-operatons
diff options
context:
space:
mode:
Diffstat (limited to 'catalog-ui/src/app/ng2/pages/composition/interface-operatons')
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.html80
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.less216
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts247
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.html44
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.less72
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.ts48
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html86
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less200
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts130
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts55
10 files changed, 1178 insertions, 0 deletions
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 0000000000..7567b90365
--- /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 0000000000..1ebfb1fe82
--- /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 0000000000..304fbcec3e
--- /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 0000000000..80aceeadda
--- /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 0000000000..12eacc6473
--- /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 0000000000..48bb804173
--- /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 0000000000..cd2d6063c1
--- /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 0000000000..8bbed9de02
--- /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 0000000000..1618af4aea
--- /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 0000000000..deba50aa7d
--- /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 {
+}