Support Tosca Function For Operation Implmentation Properties 83/131083/6
authorJvD_Ericsson <jeff.van.dam@est.tech>
Fri, 9 Sep 2022 14:25:52 +0000 (15:25 +0100)
committerVasyl Razinkov <vasyl.razinkov@est.tech>
Fri, 4 Nov 2022 14:20:07 +0000 (14:20 +0000)
Issue-ID: SDC-4170
Signed-off-by: JvD_Ericsson <jeff.van.dam@est.tech>
Change-Id: Ie90626e11885e522fba91e7604c0ed15cc0c7d3a

14 files changed:
catalog-ui/src/app/models/interfaceOperation.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.html
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.spec.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.html
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.less
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.spec.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts
catalog-ui/src/app/ng2/pages/composition/panel/composition-panel.module.ts
catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts

index 98a6040..14715b7 100644 (file)
@@ -22,6 +22,7 @@
 import {ArtifactModel} from "./artifacts";
 import {SchemaPropertyGroupModel} from "./schema-property";
 import {PROPERTY_DATA, PROPERTY_TYPES} from "../utils/constants";
+import {ToscaFunction} from "./tosca-function";
 
 export class InputOperationParameter {
     name: string;
@@ -30,6 +31,8 @@ export class InputOperationParameter {
     inputId: string;
     toscaDefaultValue?: string;
     value?: any;
+    toscaFunction?: ToscaFunction;
+    valid:boolean= true;
 
     constructor(param?: any) {
         if (param) {
@@ -39,6 +42,8 @@ export class InputOperationParameter {
             this.inputId = param.inputId;
             this.toscaDefaultValue = param.toscaDefaultValue;
             this.value = param.value;
+            this.toscaFunction = param.toscaFunction;
+            this.valid = param.valid;
         }
     }
 
@@ -62,6 +67,10 @@ export class InputOperationParameter {
     private isTypeNotSimple() {
         return PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) == -1;
     }
+
+    public isToscaFunction(): boolean {
+        return this.toscaFunction != null;
+    }
 }
 
 export class PropertyOperationParameter {
index 1dc02a5..2c1497e 100644 (file)
@@ -25,11 +25,12 @@ import {
 } from '../../../services/component-services/topology-template.service';
 import {TranslateService} from "../../../shared/translator/translate.service";
 import {ModalService} from 'app/ng2/services/modal.service';
+import {CompositionService} from "app/ng2/pages/composition/composition.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 {InstanceFeDetails} from "../../../../models/instance-fe-details";
 import {WorkspaceService} from "../../workspace/workspace.service";
 import {
     ComponentInterfaceDefinitionModel,
@@ -139,6 +140,8 @@ export class InterfaceOperationsComponent {
 
     deploymentArtifactsFilePath: Array<DropdownValue> = [];
     toscaArtifactTypes: Array<DropdownValue> = [];
+    componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
+    validImplementationProps: boolean = true;
 
     @Input() component: ComponentInstance;
     @Input() isViewOnly: boolean;
@@ -153,6 +156,7 @@ export class InterfaceOperationsComponent {
         private topologyTemplateService: TopologyTemplateService,
         private toscaArtifactService: ToscaArtifactService,
         private modalServiceNg2: ModalService,
+        private compositionService: CompositionService,
         private workspaceService: WorkspaceService,
         @Inject("Notification") private Notification: any,
     ) {
@@ -222,9 +226,10 @@ export class InterfaceOperationsComponent {
 
         let enableAddArtifactImplementation = this.modalInstance.instance.dynamicContent.instance.enableAddArtifactImplementation;
         if(enableAddArtifactImplementation) {
-            let toscaArtifactTypeSelected = this.modalInstance.instance.dynamicContent.instance.toscaArtifactTypeSelected;
-            let isToscaArtifactType:boolean = !(typeof toscaArtifactTypeSelected == 'undefined' || _.isEmpty(toscaArtifactTypeSelected));
-            disable = !isToscaArtifactType;
+            const validImplementationProps = this.modalInstance.instance.dynamicContent.instance.validImplementationProps;
+            const toscaArtifactTypeSelected = this.modalInstance.instance.dynamicContent.instance.toscaArtifactTypeSelected;
+            const isToscaArtifactType:boolean = !(typeof toscaArtifactTypeSelected == 'undefined' || _.isEmpty(toscaArtifactTypeSelected));
+            disable = !isToscaArtifactType || !validImplementationProps;
             return disable;
         }
         disable = false;
@@ -247,16 +252,27 @@ export class InterfaceOperationsComponent {
         const modalModel: ModalModel = new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', buttonList, 'custom');
         this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
 
+        const componentInstances = this.compositionService.getComponentInstances()
+        if (componentInstances) {
+            componentInstances.forEach(value => {
+                this.componentInstanceMap.set(value.uniqueId, <InstanceFeDetails>{
+                    name: value.name
+                });
+            });
+        }
+
         this.modalServiceNg2.addDynamicContentToModal(
             this.modalInstance,
             InterfaceOperationHandlerComponent,
             {
                 deploymentArtifactsFilePath: this.deploymentArtifactsFilePath,
+                componentInstanceMap: this.componentInstanceMap,
                 toscaArtifactTypes: this.toscaArtifactTypes,
                 selectedInterface: interfaceModel ? interfaceModel : new UIInterfaceModel(),
                 selectedInterfaceOperation: operation ? operation : new InterfaceOperationModel(),
                 validityChangedCallback: this.disableSaveButton,
                 isViewOnly: this.isViewOnly,
+                validImplementationProps: this.validImplementationProps,
                 isEdit: true,
                 modelName: this.componentMetaData.model
             }
index 1441a9e..fce8e7e 100644 (file)
     <span class="sprite-new delete-btn" *ngIf="showInputDelete()" (click)="onInputDelete()"></span>
     <span class="sprite-new delete-btn" *ngIf="showListItemDelete()" (click)="onChildListItemDelete()"></span>
   </span>
-  <ng-container *ngIf="isTypeSimple(type.name)">
-    <ul *ngIf="isExpanded">
-      <li class="input-value">
-        <ng-container *ngIf="isViewOnly">
-          {{valueObjRef}}<em class="empty-value" *ngIf="valueObjRef !== false && !valueObjRef">empty</em>
-        </ng-container>
-        <input *ngIf="!isViewOnly" [type]="getSimpleValueInputType()" name="value"
-               [(ngModel)]="valueObjRef"
-               (ngModelChange)="onValueChange($event)"
-        />
-      </li>
-    </ul>
+
+  <ng-container *ngIf="isExpanded && showToscaFunctionOption">
+    <form>
+      <fieldset [disabled]="isViewOnly" >
+        <input type="radio" name="hasGetFunctionValue"
+              [(ngModel)]="isToscaFunction"
+              [value]="false"
+              (change)="onValueTypeChange()"/> Value
+        <input type="radio" name="hasGetFunctionValue"
+              [(ngModel)]="isToscaFunction"
+              [value]="true"/> {{'TOSCA_FUNCTION_LABEL' | translate}}
+      </fieldset>
+    </form>
+    <div *ngIf="isToscaFunction">
+      <ul>
+        <li>
+          <div *ngIf="componentInstanceMap">
+            <tosca-function
+                            [property]="property"
+                            [allowClear]="false"
+                            [componentInstanceMap]="componentInstanceMap"
+                            (onValidityChange)="onToscaFunctionValidityChange($event)">
+            </tosca-function>
+          </div>
+          <div *ngIf="!componentInstanceMap">
+            <tosca-function
+                            [property]="property"
+                            [allowClear]="false"
+                            (onValidityChange)="onToscaFunctionValidityChange($event)">
+            </tosca-function>
+          </div>
+        </li>
+      </ul>
+    </div>
   </ng-container>
-  <ng-container *ngIf="isTypeComplex(type.name)" >
+
+  <div *ngIf="!isToscaFunction">
+    <ng-container *ngIf="isTypeSimple(type.name)">
       <ul *ngIf="isExpanded">
-        <ng-container *ngFor="let property of this.type.properties">
-          <app-input-list-item
-              [name]="property.name"
-              [type]="getDataType(property.type)"
+        <li class="input-value">
+          <ng-container *ngIf="isViewOnly">
+            {{valueObjRef}}<em class="empty-value" *ngIf="valueObjRef !== false && !valueObjRef">empty</em>
+          </ng-container>
+          <input *ngIf="!isViewOnly" [type]="getSimpleValueInputType()" name="value"
+                [(ngModel)]="valueObjRef"
+                (ngModelChange)="onValueChange($event)"
+          />
+        </li>
+      </ul>
+    </ng-container>
+    <ng-container *ngIf="isTypeComplex(type.name)" >
+        <ul *ngIf="isExpanded">
+          <ng-container *ngFor="let property of this.type.properties">
+            <app-input-list-item
+                [name]="property.name"
+                [type]="getDataType(property.type)"
+                [dataTypeMap]="dataTypeMap"
+                [valueObjRef]="valueObjRef[property.name]"
+                [schema]="property.schema"
+                [nestingLevel]="nestingLevel + 1"
+                [isViewOnly]="isViewOnly"
+                [showToscaFunctionOption]="showToscaFunctionOption"
+                [allowDeletion]="allowDeletion"
+                (onValueChange)="onPropertyValueChange($event)">
+            </app-input-list-item>
+          </ng-container>
+        </ul>
+    </ng-container>
+    <ng-container *ngIf="isTypeList(type.name)">
+      <ul *ngIf="isExpanded">
+        <ng-container *ngFor="let value1 of valueObjRef; index as i; trackBy: trackByIndex">
+          <li class="input-value" *ngIf="isTypeSimple(schema.property.type)">
+            <ng-container *ngIf="isViewOnly">
+              {{valueObjRef[i]}}
+            </ng-container>
+            <input type="text" *ngIf="!isViewOnly"
+                  [(ngModel)]="valueObjRef[i]" (ngModelChange)="onListValueChange()" />
+            <span class="sprite-new delete-btn" *ngIf="!isViewOnly" (click)="onListItemDelete(i)"></span>
+          </li>
+          <app-input-list-item *ngIf="!isTypeSimple(schema.property.type)"
+              [name]="i+''"
+              [type]="getDataType(schema.property.type)"
               [dataTypeMap]="dataTypeMap"
-              [valueObjRef]="valueObjRef[property.name]"
-              [schema]="property.schema"
+              [valueObjRef]="valueObjRef[i]"
+              [schema]="schema"
               [nestingLevel]="nestingLevel + 1"
+              [listIndex]="i"
+              [isListChild]="true"
               [isViewOnly]="isViewOnly"
               [allowDeletion]="allowDeletion"
-              (onValueChange)="onPropertyValueChange($event)">
+              (onValueChange)="onPropertyValueChange($event)"
+              (onChildListItemDelete)="onListItemDelete($event)">
           </app-input-list-item>
         </ng-container>
-      </ul>
-  </ng-container>
-  <ng-container *ngIf="isTypeList(type.name)">
-    <ul *ngIf="isExpanded">
-      <ng-container *ngFor="let value1 of valueObjRef; index as i; trackBy: trackByIndex">
-        <li class="input-value" *ngIf="isTypeSimple(schema.property.type)">
-          <ng-container *ngIf="isViewOnly">
-            {{valueObjRef[i]}}
-          </ng-container>
-          <input type="text" *ngIf="!isViewOnly"
-                 [(ngModel)]="valueObjRef[i]" (ngModelChange)="onListValueChange()" />
-          <span class="sprite-new delete-btn" *ngIf="!isViewOnly" (click)="onListItemDelete(i)"></span>
+        <li class="input-value" *ngIf="!isViewOnly">
+          <a class="add-btn" (click)="addListElement()">{{'INPUT_LIST_ADD_LIST_ENTRY' | translate}}</a>
         </li>
-        <app-input-list-item *ngIf="!isTypeSimple(schema.property.type)"
-            [name]="i+''"
-            [type]="getDataType(schema.property.type)"
-            [dataTypeMap]="dataTypeMap"
-            [valueObjRef]="valueObjRef[i]"
-            [schema]="schema"
-            [nestingLevel]="nestingLevel + 1"
-            [listIndex]="i"
-            [isListChild]="true"
-            [isViewOnly]="isViewOnly"
-            [allowDeletion]="allowDeletion"
-            (onValueChange)="onPropertyValueChange($event)"
-            (onChildListItemDelete)="onListItemDelete($event)">
-        </app-input-list-item>
-      </ng-container>
-      <li class="input-value" *ngIf="!isViewOnly">
-        <a class="add-btn" (click)="addListElement()">{{'INPUT_LIST_ADD_LIST_ENTRY' | translate}}</a>
-      </li>
-    </ul>
-  </ng-container>
-  <ng-container *ngIf="isTypeMap(type.name)">
-    <ul *ngIf="isExpanded">
-      <ng-container *ngFor="let key of getObjectEntries(valueObjRef); index as i">
-        <li class="input-value" *ngIf="isTypeSimple(schema.property.type)">
-          <label class="input-label">{{key}}:</label>
-          <ng-container *ngIf="isViewOnly">
-            {{valueObjRef[key]}}
-          </ng-container>
-          <input type="text" *ngIf="!isViewOnly" [(ngModel)]="valueObjRef[key]" (ngModelChange)="onMapValueChange()"/>
-          <span class="sprite-new delete-btn" *ngIf="!isViewOnly" (click)="onMapKeyDelete(key)"></span>
+      </ul>
+    </ng-container>
+    <ng-container *ngIf="isTypeMap(type.name)">
+      <ul *ngIf="isExpanded">
+        <ng-container *ngFor="let key of getObjectEntries(valueObjRef); index as i">
+          <li class="input-value" *ngIf="isTypeSimple(schema.property.type)">
+            <label class="input-label">{{key}}:</label>
+            <ng-container *ngIf="isViewOnly">
+              {{valueObjRef[key]}}
+            </ng-container>
+            <input type="text" *ngIf="!isViewOnly" [(ngModel)]="valueObjRef[key]" (ngModelChange)="onMapValueChange()"/>
+            <span class="sprite-new delete-btn" *ngIf="!isViewOnly" (click)="onMapKeyDelete(key)"></span>
+          </li>
+          <app-input-list-item
+              *ngIf="!isTypeSimple(schema.property.type)"
+              [name]="key"
+              [type]="getDataType(schema.property.type)"
+              [dataTypeMap]="dataTypeMap"
+              [valueObjRef]="valueObjRef[key]"
+              [schema]="schema"
+              [isMapChild]="true"
+              [nestingLevel]="nestingLevel + 1"
+              [isViewOnly]="isViewOnly"
+              [allowDeletion]="allowDeletion"
+              (onValueChange)="onPropertyValueChange($event)"
+              (onDelete)="onMapKeyDelete($event)">
+          </app-input-list-item>
+        </ng-container>
+        <li class="input-value" *ngIf="!isViewOnly">
+          <input type="text" [(ngModel)]="mapEntryName" placeholder="{{ 'INPUT_LIST_MAP_KEY_PLACEHOLDER' | translate }}"/>
+          <a class="add-btn" (click)="addMapEntry()">{{ 'INPUT_LIST_ADD_MAP_ENTRY' | translate }}</a>
         </li>
-        <app-input-list-item
-            *ngIf="!isTypeSimple(schema.property.type)"
-            [name]="key"
-            [type]="getDataType(schema.property.type)"
-            [dataTypeMap]="dataTypeMap"
-            [valueObjRef]="valueObjRef[key]"
-            [schema]="schema"
-            [isMapChild]="true"
-            [nestingLevel]="nestingLevel + 1"
-            [isViewOnly]="isViewOnly"
-            [allowDeletion]="allowDeletion"
-            (onValueChange)="onPropertyValueChange($event)"
-            (onDelete)="onMapKeyDelete($event)">
-        </app-input-list-item>
-      </ng-container>
-      <li class="input-value" *ngIf="!isViewOnly">
-        <input type="text" [(ngModel)]="mapEntryName" placeholder="{{ 'INPUT_LIST_MAP_KEY_PLACEHOLDER' | translate }}"/>
-        <a class="add-btn" (click)="addMapEntry()">{{ 'INPUT_LIST_ADD_MAP_ENTRY' | translate }}</a>
-      </li>
-    </ul>
-  </ng-container>
+      </ul>
+    </ng-container>
+  </div>
 </li>
\ No newline at end of file
index b7e34e5..0c7cf4d 100644 (file)
@@ -25,6 +25,7 @@ import {InputListItemComponent} from './input-list-item.component';
 import {TranslateModule} from '../../../../../../shared/translator/translate.module';
 import {FormsModule} from '@angular/forms';
 import {DataTypeModel} from '../../../../../../../models/data-types';
+import {ToscaFunctionModule} from '../../../../../properties-assignment/tosca-function/tosca-function.module';
 
 describe('InputListItemComponent', () => {
   let component: InputListItemComponent;
@@ -35,7 +36,8 @@ describe('InputListItemComponent', () => {
       declarations: [ InputListItemComponent ],
       imports: [
         TranslateModule,
-        FormsModule
+        FormsModule,
+        ToscaFunctionModule
       ]
     })
     .compileComponents();
index 7fed5d9..4612ca6 100644 (file)
@@ -24,6 +24,9 @@ import {DataTypeModel} from '../../../../../../../models/data-types';
 import {SchemaPropertyGroupModel} from '../../../../../../../models/schema-property';
 import {DerivedPropertyType, PropertyBEModel} from '../../../../../../../models/properties-inputs/property-be-model';
 import {PROPERTY_DATA, PROPERTY_TYPES} from '../../../../../../../utils/constants';
+import {ToscaFunction} from '../../../../../../../models/tosca-function';
+import {ToscaFunctionValidationEvent} from "../../../../../../../ng2/pages/properties-assignment/tosca-function/tosca-function.component";
+import {InstanceFeDetails} from "../../../../../../../models/instance-fe-details";
 
 @Component({
   selector: 'app-input-list-item',
@@ -40,15 +43,20 @@ export class InputListItemComponent implements OnInit {
   @Input() nestingLevel: number;
   @Input() isListChild: boolean = false;
   @Input() isMapChild: boolean = false;
+  @Input() showToscaFunctionOption: boolean = false;
   @Input() listIndex: number;
   @Input() isViewOnly: boolean;
   @Input() allowDeletion: boolean = false;
+  @Input() toscaFunction: ToscaFunction;
+  @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map();
   @Output('onValueChange') onValueChangeEvent: EventEmitter<any> = new EventEmitter<any>();
   @Output('onDelete') onDeleteEvent: EventEmitter<string> = new EventEmitter<string>();
   @Output('onChildListItemDelete') onChildListItemDeleteEvent: EventEmitter<number> = new EventEmitter<number>();
 
   isExpanded: boolean = false;
   mapEntryName: string;
+  isToscaFunction: boolean = false;
+  property: PropertyBEModel;
 
   ngOnInit() {
     if (!this.nestingLevel) {
@@ -59,6 +67,18 @@ export class InputListItemComponent implements OnInit {
         this.initEmptyPropertyInValueObjRef(property);
       });
     }
+
+    this.property = new PropertyBEModel();
+    this.property.type = this.type.name;
+    if (this.schema) {
+      this.property.schema = this.schema;
+      this.property.schemaType = this.schema.property.type;
+    }
+    if (this.toscaFunction) {
+      this.property.toscaFunction = this.toscaFunction;
+      this.valueObjRef = this.toscaFunction.value;
+      this.isToscaFunction = true;
+    }
   }
 
   private initEmptyPropertyInValueObjRef(property: PropertyBEModel) {
@@ -109,7 +129,29 @@ export class InputListItemComponent implements OnInit {
     return this.dataTypeMap.get(type);
   }
 
+  onValueTypeChange () {
+    if ( !this.isToscaFunction ) {
+      this.onValueChange(this.valueObjRef);
+    }
+  }
+
+  onToscaFunctionValidityChange(validationEvent: ToscaFunctionValidationEvent):void {
+    if (validationEvent.isValid) {
+      this.emitValueChangeEvent(validationEvent.toscaFunction, true);
+      return;
+    }
+    this.emitValueChangeEvent(undefined, true);
+  }
+
   onValueChange(value: any): void {
+    if (this.isNumber(this.type.name)) {
+      this.emitValueChangeEvent(this.parseNumber(value));
+      return;
+    }
+    if (this.type.name == PROPERTY_TYPES.BOOLEAN) {
+      this.emitValueChangeEvent(this.parseBoolean(value));
+      return;
+    }
     this.emitValueChangeEvent(value);
   }
 
@@ -122,11 +164,13 @@ export class InputListItemComponent implements OnInit {
     this.emitValueChangeEvent(this.valueObjRef);
   }
 
-  private emitValueChangeEvent(value: any) {
-    this.onValueChangeEvent.emit({
+  private emitValueChangeEvent(value: any, isToscaFunction=false) {
+    let emitValue = {
       name: this.name,
-      value: value
-    });
+      value: value,
+      isToscaFunction:isToscaFunction
+    };
+    this.onValueChangeEvent.emit(emitValue);
   }
 
   isRoot(): boolean {
@@ -161,6 +205,9 @@ export class InputListItemComponent implements OnInit {
   }
 
   addListElement() {
+    if (!this.valueObjRef) {
+      this.valueObjRef = [];
+    }
     if (this.isTypeSimple(this.schema.property.type)) {
       this.valueObjRef.push('');
     } else if (this.isTypeComplex(this.schema.property.type) || this.isTypeMap(this.schema.property.type)) {
@@ -214,9 +261,16 @@ export class InputListItemComponent implements OnInit {
   }
 
   getSimpleValueInputType() {
+    if (this.isNumber(this.type.name)){
+      return 'number';
+    }
     return 'text';
   }
 
+  isNumber(type: string): boolean {
+    return type === PROPERTY_TYPES.INTEGER || type === PROPERTY_TYPES.FLOAT;
+  }
+
   private parseBoolean(value: any) {
     if (value === 'true') {
       return true;
index 273fc7e..9a2d1f3 100644 (file)
         [dataTypeMap]="dataTypeMap"
         [valueObjRef]="input.value"
         [schema]="input.schema"
+        [toscaFunction]="input.toscaFunction"
+        [showToscaFunctionOption]="showToscaFunctionOption"
         [isViewOnly]="isViewOnly"
         [allowDeletion]="allowDeletion"
+        [componentInstanceMap]="componentInstanceMap"
         (onValueChange)="onValueChange($event)"
         (onDelete)="onDelete($event)">
     </app-input-list-item>
index 99cfd21..c98f2bb 100644 (file)
@@ -26,6 +26,8 @@ import {TranslateModule} from '../../../../../shared/translator/translate.module
 import {Component, Input} from '@angular/core';
 import {DataTypeModel} from '../../../../../../models/data-types';
 import {TranslateService} from '../../../../../shared/translator/translate.service';
+import {ToscaFunction} from '../../../../../../models/tosca-function';
+import {InstanceFeDetails} from "../../../../../../models/instance-fe-details";
 
 @Component({selector: 'app-input-list-item', template: ''})
 class InputListItemStubComponent {
@@ -36,6 +38,9 @@ class InputListItemStubComponent {
   @Input() schema: any;
   @Input() allowDeletion: any;
   @Input() isViewOnly: boolean;
+  @Input() toscaFunction: ToscaFunction;
+  @Input() showToscaFunctionOption: boolean;
+  @Input() componentInstanceMap: Map<string, InstanceFeDetails> = null;
 }
 
 const translateServiceMock: Partial<TranslateService> = {
@@ -50,7 +55,9 @@ describe('InputListComponent', () => {
   beforeEach(async(() => {
     TestBed.configureTestingModule({
       declarations: [ InputListComponent, InputListItemStubComponent ],
-      imports: [ TranslateModule ],
+      imports: [
+        TranslateModule
+      ],
       providers: [
         { provide: TranslateService, useValue: translateServiceMock }
       ]
index 832a40e..fa06c3e 100644 (file)
@@ -24,6 +24,7 @@ import {InputOperationParameter} from "../../../../../../models/interfaceOperati
 import {DataTypeModel} from "../../../../../../models/data-types";
 import {DerivedPropertyType} from "../../../../../../models/properties-inputs/property-be-model";
 import {PROPERTY_DATA, PROPERTY_TYPES} from "../../../../../../utils/constants";
+import {InstanceFeDetails} from "../../../../../../models/instance-fe-details";
 
 @Component({
   selector: 'input-list',
@@ -47,7 +48,10 @@ export class InputListComponent {
   @Input() isViewOnly: boolean;
   @Input() title: string;
   @Input() emptyMessage: string;
+  @Input() showToscaFunctionOption: boolean = false;
   @Input() allowDeletion: boolean = false;
+  @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map();
+  @Output('onInputsValidityChange') inputsValidityChangeEvent: EventEmitter<boolean> = new EventEmitter<boolean>();
   @Output('onValueChange') inputValueChangeEvent: EventEmitter<InputOperationParameter> = new EventEmitter<InputOperationParameter>();
   @Output('onDelete') inputDeleteEvent: EventEmitter<string> = new EventEmitter<string>();
 
@@ -116,7 +120,17 @@ export class InputListComponent {
   onValueChange($event: any) {
     const inputOperationParameter = this._inputs.find(input => input.name == $event.name);
     if (inputOperationParameter) {
-      inputOperationParameter.value = $event.value;
+      inputOperationParameter.valid = true;
+      if ($event.isToscaFunction) {
+        inputOperationParameter.toscaFunction = $event.value;
+        if (!inputOperationParameter.toscaFunction) {
+          inputOperationParameter.valid = false;
+        }
+      } else {
+        inputOperationParameter.value = $event.value;
+        inputOperationParameter.toscaFunction = null;
+      }
+      this.inputsValidityChangeEvent.emit(this._inputs.every(input => input.valid === true));
       this.inputValueChangeEvent.emit(new InputOperationParameter(inputOperationParameter));
     }
   }
index 7cc8570..a388574 100644 (file)
                     [inputs]="artifactTypeProperties"
                     [dataTypeMap]="dataTypeMap"
                     [isViewOnly]="isViewOnly"
+                    [showToscaFunctionOption]="true"
+                    [componentInstanceMap]="componentInstanceMap"
                     [allowDeletion]="false"
+                    (onInputsValidityChange)="implementationPropsValidityChange($event)"
                     (onValueChange)="onArtifactPropertyValueChange($event)"
                 >
                 </input-list>
index 216dc32..c7fcea0 100644 (file)
@@ -33,6 +33,7 @@ import {DropDownComponent} from "onap-ui-angular/dist/form-elements/dropdown/dro
 import {DataTypeService} from "../../../../services/data-type.service";
 import {Observable} from "rxjs/Observable";
 import {DataTypeModel} from "../../../../../models/data-types";
+import {InstanceFeDetails} from "../../../../../models/instance-fe-details";
 
 @Component({
     selector: 'operation-handler',
@@ -46,12 +47,14 @@ export class InterfaceOperationHandlerComponent {
     @ViewChild('interfaceOperationDropDown') interfaceOperationDropDown: DropDownComponent;
 
     input: {
+        componentInstanceMap: Map<string, InstanceFeDetails>;
         toscaArtifactTypes: Array<DropdownValue>;
         selectedInterface: UIInterfaceModel;
         selectedInterfaceOperation: InterfaceOperationModel;
         validityChangedCallback: Function;
         isViewOnly: boolean;
         isEdit: boolean;
+        validImplementationProps:boolean;
         modelName: string;
     };
 
@@ -67,6 +70,7 @@ export class InterfaceOperationHandlerComponent {
     isLoading: boolean = false;
     isViewOnly: boolean;
     isEdit: boolean;
+    validImplementationProps:boolean;
     interfaceTypes: Array<DropdownValue> = [];
     interfaceTypeOptions: Array<DropDownOption> = [];
     selectedInterfaceType: DropDownOption = undefined;
@@ -78,6 +82,7 @@ export class InterfaceOperationHandlerComponent {
     toscaArtifactTypeProperties: Array<PropertyBEModel> = [];
     artifactTypeProperties: Array<InputOperationParameter> = [];
     toscaArtifactTypes: Array<DropdownValue> = [];
+    componentInstanceMap: Map<string, InstanceFeDetails>;
     enableAddArtifactImplementation: boolean;
     propertyValueValid: boolean = true;
     inputTypeOptions: any[];
@@ -88,6 +93,8 @@ export class InterfaceOperationHandlerComponent {
     ngOnInit() {
         this.isViewOnly = this.input.isViewOnly;
         this.isEdit = this.input.isEdit;
+        this.validImplementationProps = this.input.validImplementationProps;
+        this.componentInstanceMap =  this.input.componentInstanceMap ? this.input.componentInstanceMap : null;
         this.interfaceType = this.input.selectedInterface.type;
         this.operationToUpdate = new InterfaceOperationModel(this.input.selectedInterfaceOperation);
         this.operationToUpdate.interfaceId = this.input.selectedInterface.uniqueId;
@@ -280,11 +287,20 @@ export class InterfaceOperationHandlerComponent {
     }
 
     onArtifactPropertyValueChange(changedProperty: InputOperationParameter) {
+        const property = this.toscaArtifactTypeProperties.find(artifactProperty => artifactProperty.name == changedProperty.name);
         if (changedProperty.value instanceof Object) {
             changedProperty.value = JSON.stringify(changedProperty.value);
         }
-        const property = this.toscaArtifactTypeProperties.find(artifactProperty => artifactProperty.name == changedProperty.name);
+        property.toscaFunction = null;
         property.value = changedProperty.value;
+        if (changedProperty.isToscaFunction()) {
+            property.toscaFunction = changedProperty.toscaFunction;
+            property.value = changedProperty.toscaFunction.buildValueString();
+        }
+    }
+
+    implementationPropsValidityChange(validImplementationProps: boolean) {
+        this.validImplementationProps = validImplementationProps;
     }
 
     /**
@@ -332,6 +348,7 @@ export class InterfaceOperationHandlerComponent {
             input.schema = property.schema;
             input.toscaDefaultValue = property.defaultValue;
             input.value = property.value;
+            input.toscaFunction = property.toscaFunction;
             inputList.push(input);
         });
         return inputList;
index bcc797c..c829ff9 100644 (file)
@@ -33,6 +33,7 @@ import {InterfaceOperationHandlerComponent} from "./interface-operation-handler.
 import {SdcUiComponentsModule} from "onap-ui-angular/dist";
 import {UiElementsModule} from "app/ng2/components/ui/ui-elements.module";
 import {PropertyTableModule} from "app/ng2/components/logic/properties-table/property-table.module";
+import {ToscaFunctionModule} from '../../../properties-assignment/tosca-function/tosca-function.module';
 
 @NgModule({
   declarations: [
@@ -50,7 +51,8 @@ import {PropertyTableModule} from "app/ng2/components/logic/properties-table/pro
     TranslateModule,
     UiElementsModule,
     PropertyTableModule,
-    ReactiveFormsModule
+    ReactiveFormsModule,
+    ToscaFunctionModule
   ],
   exports: [
     PropertyParamRowComponent
index 595ee21..b1cafb6 100644 (file)
@@ -50,7 +50,7 @@ import { ServiceConsumptionModule } from "../../../components/logic/service-cons
 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";
-
+import {CompositionService} from "../composition.service";
 
 @NgModule({
     declarations: [
@@ -106,7 +106,7 @@ import {InterfaceOperationsComponent} from "../interface-operatons/interface-ope
         CompositionPanelComponent
         // EnvParamsModule
     ],
-    providers: [SdcUiServices.ModalService]
+    providers: [SdcUiServices.ModalService, CompositionService]
 })
 export class CompositionPanelModule {
 
index b3f8dfc..f4706b9 100644 (file)
@@ -147,6 +147,7 @@ export class InterfaceDefinitionComponent {
     openOperation: OperationModel;
     enableWorkflowAssociation: boolean;
     workflowIsOnline: boolean;
+    validImplementationProps:boolean = true;
 
     @Input() component: IComponent;
     @Input() readonly: boolean;
@@ -230,9 +231,10 @@ export class InterfaceDefinitionComponent {
     
         let enableAddArtifactImplementation = this.modalInstance.instance.dynamicContent.instance.enableAddArtifactImplementation;
         if(enableAddArtifactImplementation) {
+            let validImplementationProps = this.modalInstance.instance.dynamicContent.instance.validImplementationProps;
             let toscaArtifactTypeSelected = this.modalInstance.instance.dynamicContent.instance.toscaArtifactTypeSelected;
             let isToscaArtifactType:boolean = !(typeof toscaArtifactTypeSelected == 'undefined' || _.isEmpty(toscaArtifactTypeSelected));
-            disable = !bothSet || !isToscaArtifactType;
+            disable = !bothSet || !isToscaArtifactType || !validImplementationProps;
             return disable;
         }
         disable = !bothSet;
@@ -264,6 +266,7 @@ export class InterfaceDefinitionComponent {
                 selectedInterfaceOperation: operation ? operation : new InterfaceOperationModel(),
                 validityChangedCallback: this.disableSaveButton,
                 isViewOnly: this.readonly,
+                validImplementationProps: this.validImplementationProps,
                 'isEdit': isEdit,
                 interfaceTypesMap: this.interfaceTypesMap,
                 modelName: this.component.model