Operation screen changes. 38/69738/2
authorArielk <Ariel.Kenan@amdocs.com>
Wed, 3 Oct 2018 11:06:13 +0000 (14:06 +0300)
committerAvi Gaffa <avi.gaffa@amdocs.com>
Thu, 11 Oct 2018 11:47:26 +0000 (11:47 +0000)
1. [ATTASDC-7390] Output parameter support
2. VF Workflow context
3. [ATTASDC-7420] "Opening same operation displays invalid fields and values"

Change-Id: I7bb94b50ad299af6080266076b5e0b632ef5e0e7
Issue-ID: SDC-1814
Signed-off-by: Arielk <Ariel.Kenan@amdocs.com>
catalog-ui/src/app/models/operation.ts
catalog-ui/src/app/ng2/pages/interface-operation/interface-operation.page.component.html
catalog-ui/src/app/ng2/pages/interface-operation/interface-operation.page.component.ts
catalog-ui/src/app/ng2/pages/interface-operation/operation-creator/operation-creator.component.html
catalog-ui/src/app/ng2/pages/interface-operation/operation-creator/operation-creator.component.less
catalog-ui/src/app/ng2/pages/interface-operation/operation-creator/operation-creator.component.ts
catalog-ui/src/app/ng2/pages/interface-operation/operation-creator/param-row/param-row.component.html
catalog-ui/src/app/ng2/pages/interface-operation/operation-creator/param-row/param-row.component.less
catalog-ui/src/app/ng2/pages/interface-operation/operation-creator/param-row/param-row.component.ts
catalog-ui/src/app/utils/common-utils.ts
catalog-ui/src/app/view-models/workspace/tabs/interface-operation/interface-operation-view.html

index 2a5298c..f15f0b1 100644 (file)
@@ -31,14 +31,6 @@ export class OperationModel {
     workflowId: string;
     workflowVersionId: string;
 
-    protected OperationTypeEnum: Array<String> = [
-        'Create',
-        'Delete',
-        'Instantiate',
-        'Start',
-        'Stop'
-    ];
-
     constructor(operation?: any) {
         if (operation) {
             this.description = operation.description;
@@ -59,7 +51,11 @@ export class OperationModel {
 
     public createOutputParamsList(outputParams: Array<OperationParameter>): void {
         this.outputParams = {
-            listToscaDataDefinition: outputParams
+            listToscaDataDefinition: _.map(outputParams, output => {
+                const newOutput = {...output};
+                delete newOutput.property;
+                return newOutput;
+            })
         };
     }
 }
index e210534..c9fdf94 100644 (file)
@@ -15,6 +15,8 @@
   -->
   
 <div class="interface-operation">
+    <loader [display]="isLoading" [size]="'large'" [relative]="true"></loader>
+
     <div
         class="add-btn"
         [ngClass]="{'disabled': readonly}"
@@ -25,8 +27,6 @@
 
     <div class="operation-list">
 
-        <loader [display]="isLoading" [size]="'large'" [relative]="true"></loader>
-
         <div
             class="operation-row"
             *ngFor="let operation of operationList"
index 21ac609..f23f66a 100644 (file)
@@ -1,5 +1,5 @@
 import * as _ from "lodash";
-import {Component, Input, ComponentRef, Inject} from '@angular/core';
+import {Component, Input, Output, ComponentRef, Inject} from '@angular/core';
 import {Component as IComponent} from 'app/models/components/component';
 
 import {SdcConfigToken, ISdcConfig} from "app/ng2/config/sdc-config.config";
@@ -32,9 +32,12 @@ export class InterfaceOperationComponent {
 
     @Input() component: IComponent;
     @Input() readonly: boolean;
+    @Input() enableMenuItems: Function;
+    @Input() disableMenuItems: Function;
 
     constructor(
-        @Inject(SdcConfigToken) sdcConfig: ISdcConfig,
+        @Inject(SdcConfigToken) private sdcConfig: ISdcConfig,
+        @Inject("$state") private $state: ng.ui.IStateService,
         private ComponentServiceNg2: ComponentServiceNg2,
         private WorkflowServiceNg2: WorkflowServiceNg2,
         private ModalServiceNg2: ModalService,
@@ -44,17 +47,24 @@ export class InterfaceOperationComponent {
 
     ngOnInit(): void {
         this.isLoading = true;
+        let gotOperations = false;
+        let gotInputs = false;
+
         this.ComponentServiceNg2.getInterfaceOperations(this.component).subscribe((response: ComponentGenericResponse) => {
-            if (this.inputs) {
+            if (gotInputs) {
                 this.isLoading = false;
+            } else {
+                gotOperations = true;
             }
-            let {interfaceOperations} = response;
-            this.component.interfaceOperations = interfaceOperations;
-            this.operationList = _.toArray(interfaceOperations).sort((a, b) => a.operationType.localeCompare(b.operationType));
+            this.component.interfaceOperations = response.interfaceOperations;
+            this.operationList = _.toArray(response.interfaceOperations).sort((a, b) => a.operationType.localeCompare(b.operationType));
         });
+
         this.ComponentServiceNg2.getComponentInputs(this.component).subscribe((response: ComponentGenericResponse) => {
-            if (this.component.interfaceOperations) {
+            if (gotOperations) {
                 this.isLoading = false;
+            } else {
+                gotInputs = true;
             }
             this.inputs = response.inputs;
         });
@@ -99,7 +109,7 @@ export class InterfaceOperationComponent {
             modalData.saveBtnText,
             'blue',
             () => {
-                this.modalInstance.instance.dynamicContent.instance.createInputParamList();
+                this.modalInstance.instance.dynamicContent.instance.createParamLists();
                 this.ModalServiceNg2.closeCurrentModal();
 
                 const {operation, isAssociateWorkflow} = this.modalInstance.instance.dynamicContent.instance;
@@ -180,6 +190,8 @@ export class InterfaceOperationComponent {
                 const versionId = response.workflowVersionId;
                 const artifactId = response.artifactUUID;
                 this.WorkflowServiceNg2.associateWorkflowArtifact(resourceId, operationId, workflowId, versionId, artifactId).subscribe();
+            } else {
+                this.$state.go('workspace.plugins', { path: 'workflowDesigner' });
             }
         });
     }
index d7d12d0..5c511c1 100644 (file)
@@ -31,7 +31,7 @@
                     [ngClass]="{'disabled':isEditMode}" />
             </div>
 
-            <div class="i-sdc-form-item" >
+            <div class="i-sdc-form-item">
                 <label class="i-sdc-form-label">Description</label>
                 <input
                     type="text"
             </div>
         </div>
 
-        <div class="i-sdc-form-item" *ngIf="enableWorkflowAssociation">
-            <checkbox
-                [label]="'Assign Workflow'"
-                [(checked)]="isAssociateWorkflow"
-                (checkedChange)="toggleAssociateWorkflow()"
-                [ngClass]="{'disabled': readonly}"
-                data-tests-id="checkbox-assign-workflow">
-            </checkbox>
+        <div class="side-by-side association-options">
+            <div class="i-sdc-form-item" *ngIf="enableWorkflowAssociation">
+                <label class="i-sdc-form-label">Workflow Assignment</label>
+                <ui-element-dropdown
+                    [(value)]="workflowAssociationType"
+                    [values]="associationOptions"
+                    (valueChange)="toggleAssociateWorkflow()"
+                    [readonly]="readonly">
+                </ui-element-dropdown>
+            </div>
+            <div></div>
         </div>
 
-        <div class="side-by-side" *ngIf="isAssociateWorkflow">
+        <div class="side-by-side" *ngIf="workflowAssociationType == WORKFLOW_ASSOCIATION_OPTIONS.EXISTING">
             <div class="i-sdc-form-item">
                 <label class="i-sdc-form-label required">Workflow</label>
                 <ui-element-dropdown
         </div>
 
         <div class="separator-buttons">
-            <span class="input-param-title">Input Parameters</span>
+            <tabs #propertyInputTabs tabStyle="round-tabs" (tabChanged)="tabChanged($event)" [hideIndicationOnTabChange]="true">
+                <tab tabTitle="Inputs"></tab>
+                <tab tabTitle="Outputs"></tab>
+            </tabs>
             <a
                 class="add-param-link add-btn"
-                *ngIf="!isAssociateWorkflow && !readonly"
+                *ngIf="workflowAssociationType != WORKFLOW_ASSOCIATION_OPTIONS.EXISTING && !readonly"
                 data-tests-id="addInputParameter"
                 [ngClass]="{'disabled':!isParamsValid()}"
-                (click)="addParam()">Add Input Parameter</a>
+                (click)="addParam()">Add Parameter</a>
         </div>
 
         <div class="generic-table">
             <div class="header-row table-row">
                 <span class="cell header-cell field-name">Name</span>
                 <span class="cell header-cell field-type">Type</span>
-                <span class="cell header-cell field-property">
+                <span class="cell header-cell field-property" *ngIf="currentTab == TYPE_INPUT">
                     Property
                     <span
-                        *ngIf="!isAssociateWorkflow"
+                        *ngIf="workflowAssociationType != WORKFLOW_ASSOCIATION_OPTIONS.EXISTING"
                         class="sprite-new info-icon"
                         tooltip="{{propertyTooltipText}}"
                         tooltipDelay="0">
                     </span>
                 </span>
-                <span class="cell header-cell field-mandatory" *ngIf="!isAssociateWorkflow">Mandatory</span>
-                <span class="cell header-cell remove" *ngIf="!isAssociateWorkflow && !readonly">●●●</span>
+                <span class="cell header-cell field-mandatory" *ngIf="workflowAssociationType != WORKFLOW_ASSOCIATION_OPTIONS.EXISTING">Mandatory</span>
+                <span class="cell header-cell remove" *ngIf="workflowAssociationType != WORKFLOW_ASSOCIATION_OPTIONS.EXISTING && !readonly">●●●</span>
             </div>
 
-            <div class="empty-msg data-row" *ngIf="inputParameters.length === 0">
+            <div class="empty-msg data-row" *ngIf="tableParameters.length === 0">
                 <div>NO PARAMETERS TO SHOW</div>
-                <div *ngIf="isAssociateWorkflow && !operation.workflowVersionId">
+                <div *ngIf="workflowAssociationType == WORKFLOW_ASSOCIATION_OPTIONS.EXISTING && !operation.workflowVersionId">
                     <div *ngIf="workflows.length">
                         <span class="bold-message">Select Workflow and Workflow Version above</span>
                         <span>in order to see the parameters</span>
             </div>
 
             <param-row
-                *ngFor="let param of inputParameters"
+                *ngFor="let param of tableParameters"
                 class="data-row"
-                [isAssociateWorkflow]="isAssociateWorkflow"
+                [isInputParam]="currentTab == TYPE_INPUT"
+                [isAssociateWorkflow]="workflowAssociationType == WORKFLOW_ASSOCIATION_OPTIONS.EXISTING"
                 [param]="param"
                 [inputProps]="inputProperties"
                 [propTypes]="inputPropertyTypes"
index e2b53be..f64a087 100644 (file)
     .side-by-side {
         display: flex;
 
+        &.association-options {
+            margin-top: 5px;
+        }
+
         .i-sdc-form-item {
             flex-basis: 100%;
 
@@ -33,9 +37,9 @@
     }
 
     .separator-buttons {
-        margin: 10px 0;
         display: flex;
         justify-content: space-between;
+        margin-top: 10px;
 
         .add-param-link {
             &:not(.disabled):hover {
@@ -46,6 +50,8 @@
 
     .generic-table {
         max-height: 233px;
+        min-height: 91px;
+        background: @main_color_p;
 
         .header-row .header-cell {
             &.remove {
             .info-icon {
                 float: right;
             }
-            .tooltip-inner {
-                &.tooltip-inner {
-                    &.tooltip-inner {
-                        max-width: 230px;
-                    }
-                }
+            /deep/ .tooltip-inner {
+                max-width: 280px;
+                font-size: 11px;
             }
         }
 
@@ -79,7 +82,7 @@
                 flex-direction: column;
                 justify-content: center;
                 align-items: center;
-                padding: 11px 0;
+                padding: 14px;
             }
         }
 
 
             &.remove {
                 min-width: 40px;
+                max-width: 40px;
             }
         }
 
index d2bad5f..42f95d5 100644 (file)
@@ -1,12 +1,13 @@
 import * as _ from "lodash";
-import {Component} from '@angular/core';
+import {Component, ViewChild} from '@angular/core';
 
 import {Subscription} from "rxjs/Subscription";
 
 import {TranslateService} from "app/ng2/shared/translator/translate.service";
 import {WorkflowServiceNg2} from 'app/ng2/services/workflow.service';
-import {OperationModel, OperationParameter, InputBEModel} from 'app/models';
+import {OperationModel, OperationParameter, InputBEModel, RadioButtonModel} from 'app/models';
 
+import {Tabs, Tab} from "app/ng2/components/ui/tabs/tabs.component";
 import {DropdownValue} from "app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component";
 
 export interface OperationCreatorInput {
@@ -17,6 +18,7 @@ export interface OperationCreatorInput {
     isService: boolean
 }
 
+
 @Component({
     selector: 'operation-creator',
     templateUrl: './operation-creator.component.html',
@@ -38,8 +40,16 @@ export class OperationCreatorComponent {
     noAssignInputParameters: Array<OperationParameter> = [];
     assignInputParameters: { [key: string]: { [key: string]: Array<OperationParameter>; }; } = {};
 
+    outputParameters: Array<OperationParameter> = [];
+    noAssignOutputParameters: Array<OperationParameter> = [];
+    assignOutputParameters: { [key: string]: { [key: string]: Array<OperationParameter>; }; } = {};
+
+    tableParameters: Array<OperationParameter> = [];
+
+    associationOptions: Array<DropdownValue>;
+    workflowAssociationType: String;
+
     enableWorkflowAssociation: boolean;
-    isAssociateWorkflow: boolean;
     isEditMode: boolean = false;
     isLoading: boolean = false;
     readonly: boolean;
@@ -47,10 +57,30 @@ export class OperationCreatorComponent {
 
     propertyTooltipText: String;
 
+    WORKFLOW_ASSOCIATION_OPTIONS = {
+        NONE: 'No Workflow',
+        NEW: 'New Workflow',
+        EXISTING: 'Existing Workflow'
+    }
+
+    TYPE_INPUT = 'Inputs';
+    TYPE_OUTPUT = 'Outputs';
+
+    @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
+    currentTab: String;
+
     constructor(private workflowServiceNg2: WorkflowServiceNg2, private translateService: TranslateService) {
         this.translateService.languageChangedObservable.subscribe(lang => {
             this.propertyTooltipText = this.translateService.translate("OPERATION_PROPERTY_TOOLTIP_TEXT");
         });
+        this.currentTab = this.TYPE_INPUT;
+
+        this.associationOptions = [
+            new DropdownValue(this.WORKFLOW_ASSOCIATION_OPTIONS.NONE, this.WORKFLOW_ASSOCIATION_OPTIONS.NONE),
+            new DropdownValue(this.WORKFLOW_ASSOCIATION_OPTIONS.NEW, this.WORKFLOW_ASSOCIATION_OPTIONS.NEW),
+            new DropdownValue(this.WORKFLOW_ASSOCIATION_OPTIONS.EXISTING, this.WORKFLOW_ASSOCIATION_OPTIONS.EXISTING)
+        ];
+        this.workflowAssociationType = this.WORKFLOW_ASSOCIATION_OPTIONS.NONE;
     }
 
     ngOnInit() {
@@ -91,20 +121,37 @@ export class OperationCreatorComponent {
         if (inputOperation) {
             if (!this.enableWorkflowAssociation || !inputOperation.workflowVersionId || this.isService) {
                 this.inputParameters = this.noAssignInputParameters;
-                this.isAssociateWorkflow = false;
-                this.buildInputParams();
+                this.outputParameters = this.noAssignOutputParameters;
+                this.buildParams();
+                this.updateTable();
             } else {
-                this.isAssociateWorkflow = true;
-                this.onSelectWorkflow(inputOperation.workflowVersionId).add(this.buildInputParams);
+                this.workflowAssociationType = this.WORKFLOW_ASSOCIATION_OPTIONS.EXISTING;
+                this.onSelectWorkflow(inputOperation.workflowVersionId).add(() => {
+                    this.buildParams();
+                    this.updateTable();
+                });
             }
 
             if (inputOperation.uniqueId) {
                 this.isEditMode = true;
             }
         }
+        this.updateTable();
     }
 
-    buildInputParams = () => {
+    buildParams = () => {
+        if (this.input.operation.outputParams) {
+            this.currentTab = this.TYPE_OUTPUT;
+            this.updateTable();
+            _.forEach(
+                [...this.input.operation.outputParams.listToscaDataDefinition].sort((a, b) => a.name.localeCompare(b.name)),
+                (output: OperationParameter) => {
+                    this.addParam(output);
+                }
+            );
+        }
+        this.currentTab = this.TYPE_INPUT;
+        this.updateTable();
         if (this.input.operation.inputParams) {
             _.forEach(
                 [...this.input.operation.inputParams.listToscaDataDefinition].sort((a, b) => a.name.localeCompare(b.name)),
@@ -120,6 +167,7 @@ export class OperationCreatorComponent {
         this.operation.workflowVersionId = selectedVersionId || null;
         if (!this.assignInputParameters[this.operation.workflowId]) {
             this.assignInputParameters[this.operation.workflowId] = {};
+            this.assignOutputParameters[this.operation.workflowId] = {};
         }
 
         this.isLoading = true;
@@ -141,6 +189,16 @@ export class OperationCreatorComponent {
                             });
                         })
                         .sort((a, b) => a.name.localeCompare(b.name));
+
+                        this.assignOutputParameters[this.operation.workflowId][version.id] = _.map(version.outputs, (output: any) => {
+                            return new OperationParameter({
+                                name: output.name,
+                                type: output.type && output.type.toLowerCase(),
+                                property: null,
+                                mandatory: output.mandatory,
+                            });
+                        })
+                        .sort((a, b) => a.name.localeCompare(b.name));
                     }
                     return new DropdownValue(version.id, `V ${version.name}`);
                 }
@@ -156,30 +214,55 @@ export class OperationCreatorComponent {
 
     changeWorkflowVersion() {
         this.inputParameters = this.assignInputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+        this.outputParameters = this.assignOutputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+        this.updateTable();
     }
 
     toggleAssociateWorkflow() {
 
-        if (!this.isAssociateWorkflow) {
+        if (this.workflowAssociationType !== this.WORKFLOW_ASSOCIATION_OPTIONS.EXISTING) {
             this.inputParameters = this.noAssignInputParameters;
+            this.outputParameters = this.noAssignOutputParameters;
         } else {
             if (!this.operation.workflowId || !this.operation.workflowVersionId) {
                 this.inputParameters = [];
+                this.outputParameters = [];
             } else {
                 this.inputParameters = this.assignInputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+                this.outputParameters = this.assignOutputParameters[this.operation.workflowId][this.operation.workflowVersionId];
             }
         }
 
+        this.updateTable();
+
+    }
+
+    tabChanged = (event) => {
+        this.currentTab = event.title;
+        this.updateTable();
+    }
+
+    updateTable() {
+        switch (this.currentTab) {
+            case this.TYPE_INPUT:
+                this.tableParameters = this.inputParameters;
+                break;
+            case this.TYPE_OUTPUT:
+                this.tableParameters = this.outputParameters;
+                break;
+        }
     }
 
     addParam(param?: OperationParameter): void {
-        this.inputParameters.push(new OperationParameter(param));
+        this.tableParameters.push(new OperationParameter(param));
     }
 
     isParamsValid(): boolean {
 
-        for (let ctr=0; ctr<this.inputParameters.length; ctr++) {
-            if (!this.inputParameters[ctr].name || !this.inputParameters[ctr].property) {
+        for (let ctr=0; ctr<this.tableParameters.length; ctr++) {
+            if (!this.tableParameters[ctr].name ||
+                (this.currentTab == this.TYPE_INPUT && !this.tableParameters[ctr].property)
+            ) {
                 return false;
             }
         }
@@ -188,17 +271,32 @@ export class OperationCreatorComponent {
     }
 
     onRemoveParam = (param: OperationParameter): void => {
-        let index = _.indexOf(this.inputParameters, param);
-        this.inputParameters.splice(index, 1);
+        let index = _.indexOf(this.tableParameters, param);
+        this.tableParameters.splice(index, 1);
     }
 
-    createInputParamList(): void {
-        this.operation.createInputParamsList(this.inputParameters);
+    createParamLists(): void {
+        this.operation.createInputParamsList(_.map(this.inputParameters, input => {
+            return {
+                name: input.name,
+                type: input.type,
+                property: input.property,
+                mandatory: Boolean(input.mandatory)
+            }
+        }));
+        this.operation.createOutputParamsList(_.map(this.outputParameters, output => {
+            return {
+                name: output.name,
+                type: output.type,
+                property: output.property,
+                mandatory: Boolean(output.mandatory)
+            }
+        }));
     }
 
     checkFormValidForSubmit(): boolean {
         return this.operation.operationType &&
-            (!this.isAssociateWorkflow || this.operation.workflowVersionId) &&
+            (this.workflowAssociationType !== this.WORKFLOW_ASSOCIATION_OPTIONS.EXISTING || this.operation.workflowVersionId) &&
             this.isParamsValid();
     }
 
index 33085b0..8382f1e 100644 (file)
@@ -36,7 +36,7 @@
     <span *ngIf="isAssociateWorkflow">{{param.type}}</span>
 </div>
 
-<div class="cell field-property">
+<div class="cell field-property" *ngIf="isInputParam">
     <ui-element-dropdown
         data-tests-id="paramProperty"
         [values]="filteredInputProps"
index 8795d22..81a1832 100644 (file)
@@ -5,7 +5,7 @@
     align-items: center;
     justify-content: center;
 
-    .delete-btn {
+    .delete-item-icon {
         &:hover {
             cursor: pointer;
         }
@@ -14,6 +14,7 @@
 
 
 .cell {
+    min-height: 50px;
     padding: 10px;
     display: flex;
     align-items: center;
index 53dcffd..9f7f423 100644 (file)
@@ -17,6 +17,7 @@ export class ParamRowComponent {
     @Input() onRemoveParam: Function;
     @Input() isAssociateWorkflow: boolean;
     @Input() readonly: boolean;
+    @Input() isInputParam: boolean;
 
     propTypeEnum: Array<String> = [];
     filteredInputProps: Array<DropdownValue> = [];
index 0c6a8b6..f195e2d 100644 (file)
@@ -145,11 +145,13 @@ export class CommonUtils {
 
             return acc.concat(
                 _.map(interf.operations,
-                    ({description, name, uniqueId, inputs, outputs}) => {
+                    ({description, name, uniqueId, inputs, outputs, workflowId, workflowVersionId}) => {
                         const operation = new OperationModel({
                             description,
                             operationType: name,
-                            uniqueId
+                            uniqueId,
+                            workflowId,
+                            workflowVersionId
                         });
                         if (inputs) {
                             const inputParams = _.map(inputs.listToscaDataDefinition, (input:any) => {
index 6c520d0..a92fca2 100644 (file)
 -->
 
 <div class="workspace-interface-operation">
-    <ng2-interface-operation [component]="component" [readonly]="isViewMode() || !isDesigner()"></ng2-interface-operation>
+    <ng2-interface-operation
+        [component]="component"
+        [readonly]="isViewMode() || !isDesigner()"
+        [disableMenuItems]="disableMenuItems"
+        [enableMenuItems]="enableMenuItems">
+    </ng2-interface-operation>
 </div>