UI support for default custom function names 73/134173/6
authorJvD_Ericsson <jeff.van.dam@est.tech>
Thu, 13 Apr 2023 07:28:45 +0000 (08:28 +0100)
committerMichael Morris <michael.morris@est.tech>
Thu, 4 May 2023 15:43:18 +0000 (15:43 +0000)
Issue-ID: SDC-4473
Signed-off-by: JvD_Ericsson <jeff.van.dam@est.tech>
Change-Id: Ie4d002989857029300f0cc88123a5616a453aef0

25 files changed:
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DefaultCustomToscaFunctionServlet.java
catalog-ui/src/app/models/default-custom-functions.ts [new file with mode: 0644]
catalog-ui/src/app/models/tosca-concat-function.ts
catalog-ui/src/app/modules/directive-module.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.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.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/properties-assignment/properties-assignment.page.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.html
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.html
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.spec.ts
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts
catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.html
catalog-ui/src/app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component.ts
catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts
catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts
catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view.html
catalog-ui/src/jest/mocks/default-custom-tosca-function.mock.ts [new file with mode: 0644]

index 2ad2266..f43e247 100644 (file)
@@ -85,9 +85,12 @@ public class DefaultCustomToscaFunctionServlet extends BeGenericServlet {
         LOGGER.debug("Start handle request of {}", url);
         final Map<String, Object> defaultCustomToscaFunctionssMap = new HashMap<>();
         try {
-            final List<Configuration.CustomToscaFunction> defaultCustomToscaFunction = getDefaultCustomToscaFunctionValues().stream()
-                .filter(func -> type.name().toLowerCase().equals(func.getType())).collect(
-                    Collectors.toList());
+            List<Configuration.CustomToscaFunction> defaultCustomToscaFunction = getDefaultCustomToscaFunctionValues();
+            if (!type.equals(Type.ALL)) {
+                defaultCustomToscaFunction = defaultCustomToscaFunction.stream()
+                    .filter(func -> type.name().toLowerCase().equals(func.getType())).collect(
+                        Collectors.toList());
+            }
             if (CollectionUtils.isEmpty(defaultCustomToscaFunction)) {
                 return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.NO_CONTENT));
             }
@@ -106,5 +109,5 @@ public class DefaultCustomToscaFunctionServlet extends BeGenericServlet {
         return customFunctions == null ? Collections.emptyList() : customFunctions;
     }
 
-    public enum Type {CUSTOM, GET_INPUT}
+    public enum Type {ALL, CUSTOM, GET_INPUT}
 }
diff --git a/catalog-ui/src/app/models/default-custom-functions.ts b/catalog-ui/src/app/models/default-custom-functions.ts
new file mode 100644 (file)
index 0000000..74c7901
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0z\a
+ *  ============LICENSE_END=========================================================
+ */
+
+import {ToscaFunctionType} from "../models/tosca-function-type.enum";
+
+export interface DefaultCustomFunctions {
+  defaultCustomToscaFunction: CustomToscaFunction[];
+}
+
+export class CustomToscaFunction {
+
+  constructor (customToscaFunction?: CustomToscaFunction) {
+    if (customToscaFunction) {
+      this.name = customToscaFunction.name;
+      this.type = customToscaFunction.type.toUpperCase();
+    }
+  }
+
+  public name: string;
+  public  type: string;
+}
\ No newline at end of file
index 74fe7f6..5ad4091 100644 (file)
@@ -23,6 +23,7 @@ import {ToscaFunction} from "./tosca-function";
 import {ToscaFunctionType} from "./tosca-function-type.enum";
 import {ToscaFunctionParameter} from "./tosca-function-parameter";
 import {ToscaGetFunction} from "./tosca-get-function";
+import {ToscaCustomFunction} from "./tosca-custom-function";
 import {YamlFunction} from "./yaml-function";
 import {ToscaStringParameter} from "./tosca-string-parameter";
 
@@ -53,6 +54,9 @@ export class ToscaConcatFunction implements ToscaFunction, ToscaFunctionParamete
                     case ToscaFunctionType.STRING:
                         this.parameters.push(new ToscaStringParameter(<ToscaStringParameter>parameter));
                         break;
+                    case ToscaFunctionType.CUSTOM:
+                        this.parameters.push(new ToscaCustomFunction(<ToscaCustomFunction>parameter));
+                        break;
                     default:
                         console.error(`Unsupported parameter type "${parameter.type}"`);
                         this.parameters.push(parameter);
index 40e701a..8907f5a 100644 (file)
@@ -322,7 +322,7 @@ directiveModule.directive('deploymentArtifactPage', downgradeComponent({
 
 directiveModule.directive('toscaFunction', downgradeComponent({
   component: ToscaFunctionComponent,
-  inputs: ['componentInstanceMap', 'property'],
+  inputs: ['componentInstanceMap', 'property', 'customToscaFunctions'],
   outputs: []
 }) as angular.IDirectiveFactory);
 
index 6a5bd5a..44db3b0 100644 (file)
@@ -47,6 +47,7 @@
                             [property]="property"
                             [allowClear]="false"
                             [componentInstanceMap]="componentInstanceMap"
+                            [customToscaFunctions]="customToscaFunctions"
                             (onValidityChange)="onToscaFunctionValidityChange($event)">
             </tosca-function>
           </div>
@@ -54,6 +55,7 @@
             <tosca-function
                             [property]="property"
                             [allowClear]="false"
+                            [customToscaFunctions]="customToscaFunctions"
                             (onValidityChange)="onToscaFunctionValidityChange($event)">
             </tosca-function>
           </div>
index 145aad6..103fc5c 100644 (file)
@@ -28,6 +28,7 @@ import {ToscaFunction} from '../../../../../../../models/tosca-function';
 import {ToscaFunctionValidationEvent} from "../../../../../properties-assignment/tosca-function/tosca-function.component";
 import {InstanceFeDetails} from "../../../../../../../models/instance-fe-details";
 import {ToscaTypeHelper} from "app/utils/tosca-type-helper";
+import {CustomToscaFunction} from "../../../../../../../models/default-custom-functions";
 
 @Component({
   selector: 'app-input-list-item',
@@ -51,6 +52,7 @@ export class InputListItemComponent implements OnInit {
   @Input() allowDeletion: boolean = false;
   @Input() toscaFunction: ToscaFunction;
   @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map();
+  @Input() customToscaFunctions: Array<CustomToscaFunction> = [];
   @Output('onValueChange') onValueChangeEvent: EventEmitter<any> = new EventEmitter<any>();
   @Output('onDelete') onDeleteEvent: EventEmitter<string> = new EventEmitter<string>();
   @Output('onChildListItemDelete') onChildListItemDeleteEvent: EventEmitter<number> = new EventEmitter<number>();
index 9a2d1f3..d4b70f9 100644 (file)
@@ -36,6 +36,7 @@
         [isViewOnly]="isViewOnly"
         [allowDeletion]="allowDeletion"
         [componentInstanceMap]="componentInstanceMap"
+        [customToscaFunctions]="customToscaFunctions"
         (onValueChange)="onValueChange($event)"
         (onDelete)="onDelete($event)">
     </app-input-list-item>
index c98f2bb..3230306 100644 (file)
@@ -28,6 +28,7 @@ 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";
+import {CustomToscaFunction} from "../../../../../../models/default-custom-functions";
 
 @Component({selector: 'app-input-list-item', template: ''})
 class InputListItemStubComponent {
@@ -41,6 +42,7 @@ class InputListItemStubComponent {
   @Input() toscaFunction: ToscaFunction;
   @Input() showToscaFunctionOption: boolean;
   @Input() componentInstanceMap: Map<string, InstanceFeDetails> = null;
+  @Input() customToscaFunctions: Array<CustomToscaFunction> = [];
 }
 
 const translateServiceMock: Partial<TranslateService> = {
index fa06c3e..208c003 100644 (file)
@@ -25,6 +25,7 @@ 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";
+import {CustomToscaFunction} from "../../../../../../models/default-custom-functions";
 
 @Component({
   selector: 'input-list',
@@ -51,6 +52,7 @@ export class InputListComponent {
   @Input() showToscaFunctionOption: boolean = false;
   @Input() allowDeletion: boolean = false;
   @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map();
+  @Input() customToscaFunctions: Array<CustomToscaFunction> = [];
   @Output('onInputsValidityChange') inputsValidityChangeEvent: EventEmitter<boolean> = new EventEmitter<boolean>();
   @Output('onValueChange') inputValueChangeEvent: EventEmitter<InputOperationParameter> = new EventEmitter<InputOperationParameter>();
   @Output('onDelete') inputDeleteEvent: EventEmitter<string> = new EventEmitter<string>();
index a388574..8ab1b97 100644 (file)
                     [showToscaFunctionOption]="true"
                     [componentInstanceMap]="componentInstanceMap"
                     [allowDeletion]="false"
+                    [customToscaFunctions]="customToscaFunctions"
                     (onInputsValidityChange)="implementationPropsValidityChange($event)"
                     (onValueChange)="onArtifactPropertyValueChange($event)"
                 >
index a1f72ac..ab9cad0 100644 (file)
@@ -34,6 +34,9 @@ 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";
+import {TopologyTemplateService} from "app/ng2/services/component-services/topology-template.service";
+import {CustomToscaFunction} from "../../../../../models/default-custom-functions";
+import {ToscaFunctionType} from "../../../../../models/tosca-function-type.enum";
 
 @Component({
     selector: 'operation-handler',
@@ -83,11 +86,14 @@ export class InterfaceOperationHandlerComponent {
     artifactTypeProperties: Array<InputOperationParameter> = [];
     toscaArtifactTypes: Array<DropdownValue> = [];
     componentInstanceMap: Map<string, InstanceFeDetails>;
+    customToscaFunctions: Array<CustomToscaFunction>;
     enableAddArtifactImplementation: boolean;
     propertyValueValid: boolean = true;
     inputTypeOptions: any[];
 
-    constructor(private dataTypeService: DataTypeService, private componentServiceNg2: ComponentServiceNg2) {
+    constructor(private dataTypeService: DataTypeService,
+                private componentServiceNg2: ComponentServiceNg2,
+                private topologyTemplateService: TopologyTemplateService) {
     }
 
     ngOnInit() {
@@ -100,6 +106,7 @@ export class InterfaceOperationHandlerComponent {
         this.operationToUpdate.interfaceId = this.input.selectedInterface.uniqueId;
         this.operationToUpdate.interfaceType = this.input.selectedInterface.type;
         this.modelName = this.input.modelName;
+        this.initCustomToscaFunctions();
         this.initInputs();
         this.removeImplementationQuote();
         this.loadInterfaceOperationImplementation();
@@ -128,6 +135,15 @@ export class InterfaceOperationHandlerComponent {
         this.loadInterfaceType();
     }
 
+    private initCustomToscaFunctions() {
+        this.customToscaFunctions = [];
+        this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
+            for (let customFunction of data) {
+                this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
+            }
+        });
+    }
+
     private loadInterfaceType() {
         this.componentServiceNg2.getInterfaceTypesByModel(this.modelName)
         .subscribe(response => {
index 0e3e139..a987564 100644 (file)
@@ -71,6 +71,8 @@ import {TranslateService} from "../../shared/translator/translate.service";
 import {ToscaFunction} from "../../../models/tosca-function";
 import {SubPropertyToscaFunction} from "../../../models/sub-property-tosca-function";
 import {DeclareInputComponent} from "./declare-input/declare-input.component";
+import {CustomToscaFunction} from "../../../models/default-custom-functions";
+import {ToscaFunctionType} from "../../../models/tosca-function-type.enum";
 
 const SERVICE_SELF_TITLE = "SELF";
 @Component({
@@ -83,6 +85,7 @@ export class PropertiesAssignmentComponent {
     component: ComponentData;
     componentInstanceNamesMap: { [key: string]: InstanceFeDetails } = {}; //key is the instance uniqueId
     componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>(); //key is the instance uniqueId
+    customToscaFunctions: Array<CustomToscaFunction> = [];
 
     propertiesNavigationData = [];
     instancesNavigationData = [];
@@ -179,6 +182,13 @@ export class PropertiesAssignmentComponent {
 
         }, error => {
         }); //ignore error
+
+        this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
+            for (let customFunction of data) {
+                this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
+            }
+        });
+
         this.componentServiceNg2
         .getComponentResourcePropertiesData(this.component)
         .subscribe(response => {
@@ -577,7 +587,8 @@ export class PropertiesAssignmentComponent {
 
         this.modalService.addDynamicContentToModalAndBindInputs(modal, ToscaFunctionComponent, {
             'property': checkedInstanceProperty,
-            'componentInstanceMap': this.componentInstanceMap
+            'componentInstanceMap': this.componentInstanceMap,
+            'customToscaFunctions': this.customToscaFunctions
         });
         modal.instance.dynamicContent.instance.onValidityChange.subscribe((validationEvent: ToscaFunctionValidationEvent) => {
             disableSaveButtonFlag = !validationEvent.isValid;
index 6320058..bde29b8 100644 (file)
@@ -30,7 +30,7 @@
               <input type="text" [formControlName]="idx" [value]="parameter.value"/><br/>
             </ng-container>
             <ng-container *ngIf="parameter.type !== STRING_FUNCTION_TYPE">
-              <tosca-function [property]="propertyInputList[idx]" [componentInstanceMap]="componentInstanceMap" [allowClear]="false"
+              <tosca-function [property]="propertyInputList[idx]" [customToscaFunctions]="customToscaFunctions" [componentInstanceMap]="componentInstanceMap" [allowClear]="false"
                               (onValidityChange)="onFunctionValidityChange($event, idx)">
               </tosca-function>
             </ng-container>
index ef45211..dde2bc1 100644 (file)
@@ -9,6 +9,7 @@ import {PROPERTY_TYPES} from "../../../../../utils/constants";
 import {InstanceFeDetails} from "../../../../../models/instance-fe-details";
 import {ToscaFunctionValidationEvent} from "../tosca-function.component";
 import {ToscaFunction} from "../../../../../models/tosca-function";
+import {CustomToscaFunction} from "../../../../../models/default-custom-functions";
 
 @Component({
     selector: 'app-tosca-concat-function',
@@ -19,6 +20,7 @@ export class ToscaConcatFunctionComponent implements OnInit {
 
     @Input() toscaConcatFunction: ToscaConcatFunction;
     @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
+    @Input() customToscaFunctions: Array<CustomToscaFunction> = [];
     @Output() onValidFunction: EventEmitter<ToscaConcatFunction> = new EventEmitter<ToscaConcatFunction>();
     @Output() onValidityChange: EventEmitter<ToscaConcatFunctionValidationEvent> = new EventEmitter<ToscaConcatFunctionValidationEvent>();
 
index a67364c..f77af54 100644 (file)
 
 <div class="component-container">
   <ng-container [formGroup]="formGroup">
-    <label>Custom function name: </label>
-    <input type="text" formControlName="customName" [value]="name" required/><br/><br/>
+    <div *ngIf="!isDefaultCustomFunction" class="i-sdc-form-item">
+      <label>Custom function name: </label>
+      <div class="i-sdc-form-item">
+        <input type="text" formControlName="customName" [value]="name" (input)="name = $event.target.value" required/>
+      </div>
+    </div>
     <div formArrayName="customParameterList">
       <div *ngFor="let parameter of parameters; let idx = index">
         <div *ngIf="idx > 0" class="text-center"><span class="custom-plus-icon"></span></div>
@@ -32,7 +36,7 @@
               <input type="text" [formControlName]="idx" [value]="parameter.value"/><br/>
             </ng-container>
             <ng-container *ngIf="parameter.type !== STRING_FUNCTION_TYPE">
-              <tosca-function [property]="propertyInputList[idx]" [componentInstanceMap]="componentInstanceMap" [allowClear]="false"
+              <tosca-function [property]="propertyInputList[idx]" [customToscaFunctions]="customToscaFunctions" [componentInstanceMap]="componentInstanceMap" [allowClear]="false"
                               (onValidityChange)="onFunctionValidityChange($event, idx)">
               </tosca-function>
             </ng-container>
index 9c3c188..c64547a 100644 (file)
@@ -29,12 +29,19 @@ import {TranslateModule} from "../../../../shared/translator/translate.module";
 import {ToscaGetFunctionComponent} from "../tosca-get-function/tosca-get-function.component";
 import {UiElementsModule} from "../../../../components/ui/ui-elements.module";
 import {YamlFunctionComponent} from "../yaml-function/yaml-function.component";
+import {TopologyTemplateService} from "../../../../services/component-services/topology-template.service";
+import {Observable} from "rxjs/Observable";
+import {defaultCustomFunctionsMock} from "../../../../../../jest/mocks/default-custom-tosca-function.mock";
 
 describe('ToscaCustomFunctionComponent', () => {
     let component: ToscaCustomFunctionComponent;
     let fixture: ComponentFixture<ToscaCustomFunctionComponent>;
+    let topologyTemplateServiceMock: Partial<TopologyTemplateService>;
 
     beforeEach(async(() => {
+        topologyTemplateServiceMock = {
+            getDefaultCustomFunction: jest.fn().mockImplementation(() => Observable.of(defaultCustomFunctionsMock))
+        };
         TestBed.configureTestingModule({
             declarations: [
                 ToscaCustomFunctionComponent,
@@ -47,6 +54,9 @@ describe('ToscaCustomFunctionComponent', () => {
                 ReactiveFormsModule,
                 TranslateModule,
                 UiElementsModule
+            ],
+            providers: [
+                {provide: TopologyTemplateService, useValue: topologyTemplateServiceMock}
             ]
         })
         .compileComponents();
index f368788..7746d38 100644 (file)
@@ -30,6 +30,7 @@ import {PROPERTY_TYPES} from "../../../../../utils/constants";
 import {InstanceFeDetails} from "../../../../../models/instance-fe-details";
 import {ToscaFunctionValidationEvent} from "../tosca-function.component";
 import {ToscaFunction} from "../../../../../models/tosca-function";
+import {CustomToscaFunction} from "../../../../../models/default-custom-functions";
 
 @Component({
     selector: 'app-tosca-custom-function',
@@ -40,10 +41,12 @@ export class ToscaCustomFunctionComponent implements OnInit {
 
     @Input() toscaCustomFunction: ToscaCustomFunction;
     @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
+    @Input() customToscaFunctions: Array<CustomToscaFunction> = [];
+    @Input() name: string;
+    @Input() isDefaultCustomFunction: boolean;
     @Output() onValidFunction: EventEmitter<ToscaCustomFunction> = new EventEmitter<ToscaCustomFunction>();
     @Output() onValidityChange: EventEmitter<ToscaCustomFunctionValidationEvent> = new EventEmitter<ToscaCustomFunctionValidationEvent>();
 
-    name: string = '';
     customFunctionFormName: FormControl = new FormControl('', [Validators.required, Validators.minLength(1)]);
     customParameterFormArray: FormArray = new FormArray([], Validators.minLength(1));
     formGroup: FormGroup = new FormGroup(
@@ -62,12 +65,18 @@ export class ToscaCustomFunctionComponent implements OnInit {
         this.initForm();
     }
 
+    ngOnChanges() {
+        if (this.name && this.isDefaultCustomFunction) {
+            this.customFunctionFormName.setValue(this.name);
+            this.emitOnValidityChange();
+        } else {
+            this.name = "";
+        }
+    }
+
     private initForm(): void {
         this.formGroup.valueChanges.subscribe(() => {
-            this.onValidityChange.emit({
-                isValid: this.formGroup.valid,
-                toscaCustomFunction: this.formGroup.valid ? this.buildCustomFunctionFromForm() : undefined
-            })
+            this.emitOnValidityChange();
             if (this.formGroup.valid) {
                 this.onValidFunction.emit(this.buildCustomFunctionFromForm());
             }
@@ -114,6 +123,13 @@ export class ToscaCustomFunctionComponent implements OnInit {
         return toscaCustomFunction1;
     }
 
+    private emitOnValidityChange() {
+        this.onValidityChange.emit({
+            isValid: this.formGroup.valid,
+            toscaCustomFunction: this.formGroup.valid ? this.buildCustomFunctionFromForm() : undefined
+        })
+    }
+
     addFunction(): void {
         this.propertyInputList.push(this.createProperty());
         this.parameters.push({} as ToscaFunctionParameter);
index 3ec3fa4..898b189 100644 (file)
     <div class="i-sdc-form-item">
       <label class="i-sdc-form-label">{{'TOSCA_FUNCTION_LABEL' | translate}}</label>
       <select formControlName="toscaFunctionType" (change)="onFunctionTypeChange()">
-        <option *ngFor="let toscaFunction of toscaFunctions"
+        <optgroup label="Standard">
+          <option *ngFor="let toscaFunction of toscaFunctions"
                 [ngValue]="toscaFunction">{{toscaFunction | lowercase}}</option>
+        </optgroup>
+        <optgroup *ngIf="toscaCustomFunctions" label="Custom">
+          <option *ngFor="let toscaCustomFunction of toscaCustomFunctions"
+                [ngValue]="toscaCustomFunction">{{toscaCustomFunction | lowercase}}</option>
+        </optgroup>
+        <option value="YAML">yaml</option>
       </select>
     </div>
     <div *ngIf="isConcatSelected()">
-      <app-tosca-concat-function [toscaConcatFunction]="toscaFunction" [componentInstanceMap]="componentInstanceMap"
+      <app-tosca-concat-function [toscaConcatFunction]="toscaFunction" [customToscaFunctions]="customToscaFunctions" [componentInstanceMap]="componentInstanceMap"
                                  (onValidityChange)="onConcatFunctionValidityChange($event)"></app-tosca-concat-function>
     </div>
     <div *ngIf="isCustomSelected()">
-      <app-tosca-custom-function [toscaCustomFunction]="toscaFunction" [componentInstanceMap]="componentInstanceMap"
-                                 (onValidityChange)="onCustomFunctionValidityChange($event)"></app-tosca-custom-function>
+      <app-tosca-custom-function [toscaCustomFunction]="toscaFunction" [customToscaFunctions]="customToscaFunctions" [name]="getCustomFunctionName()" [componentInstanceMap]="componentInstanceMap"
+                                 [isDefaultCustomFunction]="isDefaultCustomFunction()" (onValidityChange)="onCustomFunctionValidityChange($event)"></app-tosca-custom-function>
     </div>
     <div *ngIf="isGetFunctionSelected()">
       <app-tosca-get-function [property]="property" [toscaGetFunction]="toscaFunction"
index 6783f5b..8169694 100644 (file)
@@ -35,6 +35,7 @@ import {YamlFunctionValidationEvent} from "./yaml-function/yaml-function.compone
 import {ToscaConcatFunction} from "../../../../models/tosca-concat-function";
 import {ToscaCustomFunction} from "../../../../models/tosca-custom-function";
 import {YamlFunction} from "../../../../models/yaml-function";
+import {CustomToscaFunction} from "../../../../models/default-custom-functions";
 
 @Component({
     selector: 'tosca-function',
@@ -45,6 +46,7 @@ export class ToscaFunctionComponent implements OnInit, OnChanges {
 
     @Input() property: PropertyBEModel;
     @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
+    @Input() customToscaFunctions: Array<CustomToscaFunction> = [];
     @Input() allowClear: boolean = true;
     @Input() compositionMap: boolean = false;
     @Input() compositionMapKey: string = "";
@@ -61,6 +63,7 @@ export class ToscaFunctionComponent implements OnInit, OnChanges {
     isLoading: boolean = false;
     toscaFunction: ToscaFunction;
     toscaFunctions: Array<string> = [];
+    toscaCustomFunctions: Array<String> = [];
 
     private isInitialized: boolean = false;
     private componentMetadata: ComponentMetadata;
@@ -132,7 +135,18 @@ export class ToscaFunctionComponent implements OnInit, OnChanges {
             return;
         }
         this.toscaFunctionForm.setValue(this.property.toscaFunction);
-        this.toscaFunctionTypeForm.setValue(this.property.toscaFunction.type);
+        let type = this.property.toscaFunction.type;
+        if (type == ToscaFunctionType.CUSTOM) {
+            let name = (this.property.toscaFunction as ToscaCustomFunction).name;
+            let test = this.customToscaFunctions.find(custToscFunc => _.isEqual(custToscFunc.name, name))
+            if (test) {
+                this.toscaFunctionTypeForm.setValue(name);
+            } else {
+                this.toscaFunctionTypeForm.setValue("other");
+            }
+        } else {
+            this.toscaFunctionTypeForm.setValue(type);
+        }
     }
 
     private areEqual(array1: string[], array2: string[]): boolean {
@@ -144,11 +158,41 @@ export class ToscaFunctionComponent implements OnInit, OnChanges {
         this.toscaFunctions.push(ToscaFunctionType.GET_ATTRIBUTE);
         this.toscaFunctions.push(ToscaFunctionType.GET_INPUT);
         this.toscaFunctions.push(ToscaFunctionType.GET_PROPERTY);
-        this.toscaFunctions.push(ToscaFunctionType.CUSTOM);
         if (this.property.type === PROPERTY_TYPES.STRING || this.property.type === PROPERTY_TYPES.ANY) {
             this.toscaFunctions.push(ToscaFunctionType.CONCAT);
         }
-        this.toscaFunctions.push(ToscaFunctionType.YAML);
+        this.loadCustomToscaFunctions();
+    }
+
+    private loadCustomToscaFunctions(): void {
+        if (!this.customToscaFunctions.find(custToscFunc => _.isEqual(custToscFunc.name, "other"))) {
+            let other = new CustomToscaFunction();
+            other.name = "other";
+            other.type = ToscaFunctionType.CUSTOM;
+            this.customToscaFunctions.push(other);
+        }
+        this.toscaCustomFunctions = [];
+        for (let func of this.customToscaFunctions) {
+            this.toscaCustomFunctions.push(func.name);
+        }
+    }
+
+    getCustomToscaFunction(): CustomToscaFunction {
+        let funcName = this.formGroup.get('toscaFunctionType').value;
+        return this.customToscaFunctions.find(custToscFunc => _.isEqual(custToscFunc.name, funcName));
+    }
+
+    getCustomFunctionName():string {
+        let toscaFunctionType: CustomToscaFunction = this.getCustomToscaFunction();
+        return toscaFunctionType.name;
+    }
+
+    isDefaultCustomFunction(): boolean {
+        let toscaFunctionType: CustomToscaFunction = this.getCustomToscaFunction();
+        if (toscaFunctionType.name === "other") {
+            return false;
+        }
+        return this.customToscaFunctions.filter(e => e.name === toscaFunctionType.name).length > 0;
     }
 
     private resetForm(): void {
@@ -173,7 +217,8 @@ export class ToscaFunctionComponent implements OnInit, OnChanges {
     }
 
     isCustomSelected(): boolean {
-        return this.formGroup.get('toscaFunctionType').value === ToscaFunctionType.CUSTOM;
+        let toscaFunctionType: CustomToscaFunction = this.getCustomToscaFunction();
+        return toscaFunctionType && toscaFunctionType.type === ToscaFunctionType.CUSTOM;
     }
 
     isGetFunctionSelected(): boolean {
index 922cda6..8024eb1 100644 (file)
@@ -73,6 +73,7 @@
                 <div class="i-sdc-form-item rule-input-field">
                     <tosca-function [property]="selectedProperty"
                                     [componentInstanceMap]="componentInstanceMap"
+                                    [customToscaFunctions]="customToscaFunctions"
                                     [allowClear]="false"
                                     (onValidityChange)="onToscaFunctionValidityChange($event)"
                     >
index 5666bf5..39609a5 100644 (file)
@@ -28,6 +28,9 @@ import {ToscaGetFunction} from "../../../models/tosca-get-function";
 import {PropertyFilterConstraintUi} from "../../../models/ui-models/property-filter-constraint-ui";
 import {ConstraintOperatorType, FilterConstraintHelper} from "../../../utils/filter-constraint-helper";
 import {ToscaFunctionHelper} from "../../../utils/tosca-function-helper";
+import {TopologyTemplateService} from "app/ng2/services/component-services/topology-template.service";
+import {CustomToscaFunction} from "../../../models/default-custom-functions";
+import {ToscaFunctionType} from "../../../models/tosca-function-type.enum";
 
 @Component({
   selector: 'service-dependencies-editor',
@@ -72,6 +75,7 @@ export class ServiceDependenciesEditorComponent implements OnInit {
   selectedProperty: PropertyFEModel;
   selectedSourceType: string;
   componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
+  customToscaFunctions: Array<CustomToscaFunction>;
   capabilityDropdownList: DropdownValue[] = [];
 
   SOURCE_TYPES = {
@@ -79,7 +83,7 @@ export class ServiceDependenciesEditorComponent implements OnInit {
     TOSCA_FUNCTION: {label: 'Tosca Function', value: SourceType.TOSCA_FUNCTION}
   };
 
-  constructor(private propertiesUtils: PropertiesUtils, private compositionService: CompositionService) {}
+  constructor(private propertiesUtils: PropertiesUtils, private compositionService: CompositionService, private topologyTemplateService: TopologyTemplateService) {}
 
   ngOnInit(): void {
     if (this.compositionService.componentInstances) {
@@ -89,6 +93,7 @@ export class ServiceDependenciesEditorComponent implements OnInit {
         });
       });
     }
+    this.initCustomToscaFunctions();
     this.initCapabilityDropdown();
     this.initCurrentRule();
     this.initConstraintOperatorOptions();
@@ -97,6 +102,14 @@ export class ServiceDependenciesEditorComponent implements OnInit {
     this.syncRuleData();
   }
 
+  private initCustomToscaFunctions() {
+    this.customToscaFunctions = [];
+    this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
+        for (let customFunction of data) {
+            this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
+        }
+    });
+}
 
   private initCapabilityDropdown(): void {
     if (this.filterType == FilterType.CAPABILITY) {
index b6eb857..0003f53 100644 (file)
@@ -62,6 +62,7 @@ import {BEInterfaceOperationModel, InterfaceOperationModel} from "../../../model
 import {AttributeBEModel} from "../../../models/attributes-outputs/attribute-be-model";
 import {InstanceAttributesAPIMap} from "../../../models/attributes-outputs/attribute-fe-map";
 import {FilterConstraint} from "../../../models/filter-constraint";
+import {CustomToscaFunction, DefaultCustomFunctions} from "../../../models/default-custom-functions";
 
 /* we need to use this service from now, we will remove component.service when we finish remove the angular1.
  The service is duplicated since we can not use downgrades service with NGXS*/
@@ -656,4 +657,9 @@ export class TopologyTemplateService {
         .getServerTypeUrl(componentMetaDataType) + componentMetaDataId + '/componentInstance/' + componentInstanceId + '/interfaceOperation', operationList);
     }
 
+    getDefaultCustomFunction(type='ALL'): Observable<CustomToscaFunction[]> {
+        return this.http.get<DefaultCustomFunctions>(this.baseUrl + "customToscaFunctions/" + type)
+        .pipe(map(response => response.defaultCustomToscaFunction ? response.defaultCustomToscaFunction : undefined));
+    }
+
 }
index 4b41e7a..39f008a 100644 (file)
@@ -34,6 +34,8 @@ import {TopologyTemplateService} from "app/ng2/services/component-services/topol
 import {InstanceFeDetails} from "../../../../models/instance-fe-details";
 import {ToscaGetFunction} from "../../../../models/tosca-get-function";
 import {ToscaFunctionValidationEvent} from "../../../../ng2/pages/properties-assignment/tosca-function/tosca-function.component";
+import {CustomToscaFunction} from "../../../../models/default-custom-functions";
+import {ToscaFunctionType} from "../../../../models/tosca-function-type.enum";
 
 export interface IEditPropertyModel {
     property:PropertyModel;
@@ -56,6 +58,7 @@ interface IPropertyFormViewModelScope extends ng.IScope {
     commentValidationPattern:RegExp;
     editPropertyModel: IEditPropertyModel;
     componentInstanceMap: Map<string, InstanceFeDetails>;
+    customToscaFunctions: Array<CustomToscaFunction>;
     modalInstanceProperty:ng.ui.bootstrap.IModalServiceInstance;
     currentPropertyIndex:number;
     isLastProperty:boolean;
@@ -228,6 +231,15 @@ export class PropertyFormViewModel {
         }
     }
 
+    private initCustomToscaFunctions() {
+        this.$scope.customToscaFunctions = [];
+        this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
+            for (let customFunction of data) {
+                this.$scope.customToscaFunctions.push(new CustomToscaFunction(customFunction));
+            }
+        });
+    }
+
     private initEmptyComplexValue(type: string): any {
         switch (type) {
             case PROPERTY_TYPES.MAP:
@@ -308,6 +320,7 @@ export class PropertyFormViewModel {
         this.initResource();
         this.initForNotSimpleType();
         this.initComponentInstanceMap();
+        this.initCustomToscaFunctions();
 
         this.$scope.validateJson = (json:string):boolean => {
             if (!json) {
index b717d7a..d0c3cc6 100644 (file)
                         <div data-ng-if="editPropertyModel.hasGetFunctionValue">
                             <tosca-function [property]="editPropertyModel.property"
                                             [component-instance-map]="componentInstanceMap"
+                                            [custom-tosca-functions]="customToscaFunctions"
                                             [allow-clear]="false"
                                             (on-valid-function)="onGetFunctionValidFunction($event)"
                                             (on-validity-change)="onToscaFunctionValidityChange($event)"
diff --git a/catalog-ui/src/jest/mocks/default-custom-tosca-function.mock.ts b/catalog-ui/src/jest/mocks/default-custom-tosca-function.mock.ts
new file mode 100644 (file)
index 0000000..080a1ed
--- /dev/null
@@ -0,0 +1,12 @@
+export const defaultCustomFunctionsMock = {
+    defaultCustomToscaFunction: [
+        {
+            name: "custom-func-1",
+            type: "custom"
+        },
+        {
+            name: "custom-func-2",
+            type: "custom"
+        }
+    ]
+}
\ No newline at end of file