From b6c9ed78e512e2d96f1725ca3748a5f02b31e7df Mon Sep 17 00:00:00 2001 From: JvD_Ericsson Date: Fri, 31 Mar 2023 14:42:07 +0100 Subject: UI support for custom functions Issue-ID: SDC-4466 Signed-off-by: JvD_Ericsson Change-Id: I8ff794be8783dc31efecbd1f6abe2efefec6b819 --- catalog-ui/src/app/models/tosca-custom-function.ts | 79 ++++++++++ .../src/app/models/tosca-function-type.enum.ts | 1 + .../tosca-concat-function.component.spec.ts | 3 +- .../tosca-custom-function.component.html | 50 +++++++ .../tosca-custom-function.component.less | 98 +++++++++++++ .../tosca-custom-function.component.spec.ts | 64 +++++++++ .../tosca-custom-function.component.ts | 160 +++++++++++++++++++++ .../tosca-function/tosca-function.component.html | 4 + .../tosca-function/tosca-function.component.ts | 20 ++- .../tosca-function/tosca-function.module.ts | 2 + .../tosca-get-function.component.ts | 3 + catalog-ui/src/app/utils/constants.ts | 1 + 12 files changed, 483 insertions(+), 2 deletions(-) create mode 100644 catalog-ui/src/app/models/tosca-custom-function.ts create mode 100644 catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.html create mode 100644 catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.less create mode 100644 catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.spec.ts create mode 100644 catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.ts (limited to 'catalog-ui') diff --git a/catalog-ui/src/app/models/tosca-custom-function.ts b/catalog-ui/src/app/models/tosca-custom-function.ts new file mode 100644 index 0000000000..e13be50993 --- /dev/null +++ b/catalog-ui/src/app/models/tosca-custom-function.ts @@ -0,0 +1,79 @@ +/* + * - + * ============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.0 + * ============LICENSE_END========================================================= + */ + +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 {YamlFunction} from "./yaml-function"; +import {ToscaStringParameter} from "./tosca-string-parameter"; + +export class ToscaCustomFunction implements ToscaFunction, ToscaFunctionParameter { + name: string; + type = ToscaFunctionType.CUSTOM; + value: any; + parameters: Array = []; + + constructor(toscaCustomFunction?: ToscaCustomFunction) { + if (!toscaCustomFunction) { + return; + } + this.value = toscaCustomFunction.value; + this.name = toscaCustomFunction.name; + if (toscaCustomFunction.parameters) { + toscaCustomFunction.parameters.forEach(parameter => { + switch (parameter.type) { + case ToscaFunctionType.GET_INPUT: + case ToscaFunctionType.GET_ATTRIBUTE: + case ToscaFunctionType.GET_PROPERTY: + this.parameters.push(new ToscaGetFunction(parameter)); + break; + case ToscaFunctionType.CONCAT: + this.parameters.push(new ToscaCustomFunction(parameter)); + break; + case ToscaFunctionType.CUSTOM: + this.parameters.push(new ToscaCustomFunction(parameter)); + break; + case ToscaFunctionType.YAML: + this.parameters.push(new YamlFunction(parameter)); + break; + case ToscaFunctionType.STRING: + this.parameters.push(new ToscaStringParameter(parameter)); + break; + default: + console.error(`Unsupported parameter type "${parameter.type}"`); + this.parameters.push(parameter); + } + }); + } + } + + public buildValueString(): string { + return JSON.stringify(this.buildValueObject()); + } + + public buildValueObject(): Object { + return { + [this.name]: this.parameters.map(parameter => parameter.buildValueObject()) + } + } + +} \ No newline at end of file diff --git a/catalog-ui/src/app/models/tosca-function-type.enum.ts b/catalog-ui/src/app/models/tosca-function-type.enum.ts index 116c8815ab..0394048317 100644 --- a/catalog-ui/src/app/models/tosca-function-type.enum.ts +++ b/catalog-ui/src/app/models/tosca-function-type.enum.ts @@ -3,6 +3,7 @@ export enum ToscaFunctionType { GET_ATTRIBUTE = 'GET_ATTRIBUTE', GET_PROPERTY = 'GET_PROPERTY', CONCAT = 'CONCAT', + CUSTOM = 'CUSTOM', YAML = 'YAML', STRING = 'STRING' } diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.spec.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.spec.ts index 199f73349e..65e6339a7b 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.spec.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.spec.ts @@ -22,6 +22,7 @@ import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {ToscaConcatFunctionComponent} from './tosca-concat-function.component'; +import {ToscaCustomFunctionComponent} from '../tosca-custom-function/tosca-custom-function.component'; import {FormsModule, ReactiveFormsModule} from "@angular/forms"; import {ToscaFunctionComponent} from "../tosca-function.component"; import {TranslateModule} from "../../../../shared/translator/translate.module"; @@ -35,7 +36,7 @@ describe('ToscaConcatFunctionComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ToscaConcatFunctionComponent, ToscaFunctionComponent, ToscaGetFunctionComponent, YamlFunctionComponent], + declarations: [ToscaConcatFunctionComponent, ToscaFunctionComponent, ToscaGetFunctionComponent, YamlFunctionComponent, ToscaCustomFunctionComponent], imports: [ FormsModule, ReactiveFormsModule, diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.html new file mode 100644 index 0000000000..a67364cd60 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.html @@ -0,0 +1,50 @@ + + +
+ + +

+
+
+
+
+
+ +
+
+ + + + +
+ +
+
+
+
+
+
+ +
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.less b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.less new file mode 100644 index 0000000000..f37e7befa2 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.less @@ -0,0 +1,98 @@ +/* + * - + * ============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.0 + * ============LICENSE_END========================================================= + */ + +@import "../../../../../../assets/styles/mixins.less"; +@import "../../../../../../assets/styles/sprite.less"; + +.component-container { + max-height: 500px; + overflow: scroll; + padding: 0 5px; + &::-webkit-scrollbar-track { + border: 0; + } +} + +.buttons-container { + display: flex; + flex-direction: row; + justify-content: flex-end; + gap: 10px; + margin-bottom: 10px; + + .add-link { + .f-color.a(); + .f-type._14_m(); + cursor: pointer; + + &:before { + .sprite-new(); + .plus-icon(); + margin-right: 5px; + content: ""; + } + + &:hover { + .f-color.b(); + &:before { + .sprite-new(); + .plus-icon-hover(); + } + } + } + + .delete-icon { + .sprite-new(); + .delete-btn(); + cursor: pointer; + } +} + +.parameter-card { + border: 2px solid @main_color_o; + box-shadow: 0 0 0 0 rgba(0,0,0,0.2); + //padding: 10px; + border-radius: 2px; + transition: 0.3s; + margin-bottom: 5px; + &:hover { + box-shadow: 0 1px 8px 2px rgba(0,0,0,0.2); + } + + .card-content { + padding: 5px 10px; + } + + .text-center { + text-align: center; + } + + input { + border: solid 1px @main_color_o; + } +} + +.custom-plus-icon { + .sprite-new(); + background-position: -216px -1388px; + width: 14px; + height: 14px; +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.spec.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.spec.ts new file mode 100644 index 0000000000..9c3c188711 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.spec.ts @@ -0,0 +1,64 @@ +/* + * - + * ============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.0 + * ============LICENSE_END========================================================= + */ + +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; + +import {ToscaConcatFunctionComponent} from '../tosca-concat-function/tosca-concat-function.component'; +import {ToscaCustomFunctionComponent} from './tosca-custom-function.component'; +import {FormsModule, ReactiveFormsModule} from "@angular/forms"; +import {ToscaFunctionComponent} from "../tosca-function.component"; +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"; + +describe('ToscaCustomFunctionComponent', () => { + let component: ToscaCustomFunctionComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + ToscaCustomFunctionComponent, + ToscaConcatFunctionComponent, + ToscaFunctionComponent, + ToscaGetFunctionComponent, + YamlFunctionComponent], + imports: [ + FormsModule, + ReactiveFormsModule, + TranslateModule, + UiElementsModule + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ToscaCustomFunctionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.ts new file mode 100644 index 0000000000..f3687880f2 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-custom-function/tosca-custom-function.component.ts @@ -0,0 +1,160 @@ +/* + * - + * ============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.0 + * ============LICENSE_END========================================================= + */ + +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {FormArray, FormControl, FormGroup, Validators} from "@angular/forms"; +import {ToscaCustomFunction} from "../../../../../models/tosca-custom-function"; +import {ToscaFunctionParameter} from "../../../../../models/tosca-function-parameter"; +import {ToscaStringParameter} from "../../../../../models/tosca-string-parameter"; +import {ToscaFunctionType} from "../../../../../models/tosca-function-type.enum"; +import {PropertyBEModel} from "../../../../../models/properties-inputs/property-be-model"; +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"; + +@Component({ + selector: 'app-tosca-custom-function', + templateUrl: './tosca-custom-function.component.html', + styleUrls: ['./tosca-custom-function.component.less'] +}) +export class ToscaCustomFunctionComponent implements OnInit { + + @Input() toscaCustomFunction: ToscaCustomFunction; + @Input() componentInstanceMap: Map = new Map(); + @Output() onValidFunction: EventEmitter = new EventEmitter(); + @Output() onValidityChange: EventEmitter = new EventEmitter(); + + name: string = ''; + customFunctionFormName: FormControl = new FormControl('', [Validators.required, Validators.minLength(1)]); + customParameterFormArray: FormArray = new FormArray([], Validators.minLength(1)); + formGroup: FormGroup = new FormGroup( + { + 'customParameterList': this.customParameterFormArray, + 'customName': this.customFunctionFormName + } + ); + + parameters: ToscaFunctionParameter[] = []; + propertyInputList: Array = []; + + STRING_FUNCTION_TYPE = ToscaFunctionType.STRING + + ngOnInit() { + this.initForm(); + } + + private initForm(): void { + this.formGroup.valueChanges.subscribe(() => { + this.onValidityChange.emit({ + isValid: this.formGroup.valid, + toscaCustomFunction: this.formGroup.valid ? this.buildCustomFunctionFromForm() : undefined + }) + if (this.formGroup.valid) { + this.onValidFunction.emit(this.buildCustomFunctionFromForm()); + } + }); + if (!this.toscaCustomFunction) { + return; + } + if (this.toscaCustomFunction.parameters) { + this.name = this.toscaCustomFunction.name; + this.customFunctionFormName.setValue(this.name) + this.parameters = Array.from(this.toscaCustomFunction.parameters); + for (const parameter of this.parameters) { + if (parameter.type !== PROPERTY_TYPES.STRING) { + const propertyBEModel = this.createProperty(parameter.value); + propertyBEModel.toscaFunction = parameter; + this.propertyInputList.push(propertyBEModel); + this.customParameterFormArray.push( + new FormControl(parameter, [Validators.required, Validators.minLength(1)]) + ); + } else { + this.propertyInputList.push(undefined); + this.customParameterFormArray.push( + new FormControl(parameter.value, [Validators.required, Validators.minLength(1)]) + ); + } + } + } + } + + private buildCustomFunctionFromForm(): ToscaCustomFunction { + const toscaCustomFunction1 = new ToscaCustomFunction(); + toscaCustomFunction1.name = this.customFunctionFormName.value; + this.customParameterFormArray.controls.forEach(control => { + const value = control.value; + if (typeof value === 'string') { + const stringParameter = new ToscaStringParameter(); + stringParameter.value = value; + toscaCustomFunction1.parameters.push(stringParameter); + } else { + toscaCustomFunction1.parameters.push(control.value); + } + }); + + return toscaCustomFunction1; + } + + addFunction(): void { + this.propertyInputList.push(this.createProperty()); + this.parameters.push({} as ToscaFunctionParameter); + this.customParameterFormArray.push( + new FormControl(undefined, [Validators.required, Validators.minLength(1)]) + ); + } + + addStringParameter(): void { + const toscaStringParameter = new ToscaStringParameter(); + toscaStringParameter.value = '' + this.parameters.push(toscaStringParameter); + this.propertyInputList.push(undefined); + this.customParameterFormArray.push( + new FormControl('', [Validators.required, Validators.minLength(1)]) + ); + } + + removeParameter(position): void { + this.propertyInputList.splice(position, 1); + this.parameters.splice(position, 1); + this.customParameterFormArray.removeAt(position); + } + + createProperty(value?: any): PropertyBEModel { + const property = new PropertyBEModel(); + property.type = PROPERTY_TYPES.ANY; + property.value = value ? value : undefined; + return property; + } + + onFunctionValidityChange(event: ToscaFunctionValidationEvent, index: number): void { + if (event.isValid && event.toscaFunction) { + this.customParameterFormArray.controls[index].setValue(event.toscaFunction) + } else { + this.customParameterFormArray.controls[index].setValue(undefined); + } + } +} + +export interface ToscaCustomFunctionValidationEvent { + isValid: boolean, + toscaCustomFunction: ToscaCustomFunction, +} diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html index 74a06baa53..3ec3fa45dc 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html @@ -30,6 +30,10 @@ +
+ +
this.property).input instanceof DerivedFEProperty) || this.compositionMap) { let childObject : DerivedFEProperty = (( this.property).input); diff --git a/catalog-ui/src/app/utils/constants.ts b/catalog-ui/src/app/utils/constants.ts index 087ecaf21c..927c778df6 100644 --- a/catalog-ui/src/app/utils/constants.ts +++ b/catalog-ui/src/app/utils/constants.ts @@ -150,6 +150,7 @@ export class SEVERITY { } export class PROPERTY_TYPES { + public static ANY = 'any'; public static STRING = 'string'; public static INTEGER = 'integer'; public static TIMESTAMP = 'timestamp'; -- cgit 1.2.3-korg