diff options
author | andre.schmid <andre.schmid@est.tech> | 2022-07-18 17:25:41 +0100 |
---|---|---|
committer | Michael Morris <michael.morris@est.tech> | 2022-07-29 20:08:14 +0000 |
commit | 3f9669fdae5f7c6cb1bfe34742df35dfe3a14aa7 (patch) | |
tree | 307686e72403ee837fd342efb9865b0b6a83da7c /catalog-ui/src/app/ng2 | |
parent | 22d13840722a4020b1aaf75eeff3622e83c4b6d4 (diff) |
Support a custom yaml value in tosca function
Allows to add a custom YAML value to properties in the TOSCA function
feature.
Change-Id: I15e65088a18537d9832428717be826ac0ef6049a
Issue-ID: SDC-4099
Signed-off-by: André Schmid <andre.schmid@est.tech>
Diffstat (limited to 'catalog-ui/src/app/ng2')
10 files changed, 244 insertions, 15 deletions
diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html index 81f0d533b4..f855265157 100644 --- a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html +++ b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html @@ -15,13 +15,13 @@ <div *ngIf="!property.hidden" class="dynamic-property-row nested-level-{{nestedLevel}}" [@fadeIn] - [ngClass]="{'selected': selectedPropertyId && selectedPropertyId === property.propertiesName, 'readonly': property.isDisabled || property.isDeclared || property.isToscaGetFunction()}" + [ngClass]="{'selected': selectedPropertyId && selectedPropertyId === property.propertiesName, 'readonly': property.isDisabled || property.isDeclared || property.isToscaFunction()}" [class.with-top-border]="property.isChildOfListOrMap" (click)="onClickPropertyRow(property, $event)"> <!-- LEFT CELL --> <ng-container *ngIf="!isPropertyFEModel"> <div class="table-cell" *ngIf="canBeDeclared" [ngClass]="{'filtered':property.name === propertyNameSearchText}" [class.round-checkbox]="property.isDeclared"> <!-- simple children of complex type [@checkEffect]="property.isDeclared"--> - <checkbox *ngIf="hasDeclareOption" [(checked)]="property.isSelected" [disabled]="property.isDisabled || property.isDeclared || readonly || property.isToscaGetFunction()" (checkedChange)="checkProperty.emit(property.propertiesName)" ></checkbox> + <checkbox *ngIf="hasDeclareOption" [(checked)]="property.isSelected" [disabled]="property.isDisabled || property.isDeclared || readonly || property.isToscaFunction()" (checkedChange)="checkProperty.emit(property.propertiesName)" ></checkbox> <div class="inner-cell-div" tooltip="{{property.name}}"><span>{{property.name}}</span></div> </div> <div class="table-cell" *ngIf="!canBeDeclared && !property.isChildOfListOrMap"> @@ -41,31 +41,31 @@ </div> </ng-container> <!-- RIGHT CELL OR FULL WIDTH CELL--> - <ng-container *ngIf="propType == derivedPropertyTypes.SIMPLE || property.isDeclared || property.isToscaGetFunction() || (property.isChildOfListOrMap && propType == derivedPropertyTypes.MAP && property.schema.property.isSimpleType)"> + <ng-container *ngIf="propType == derivedPropertyTypes.SIMPLE || property.isDeclared || property.isToscaFunction() || (property.isChildOfListOrMap && propType == derivedPropertyTypes.MAP && property.schema.property.isSimpleType)"> <div class="table-cell"> <dynamic-element class="value-input" pattern="validationUtils.getValidationPattern(property.type)" - [value]="property.isDeclared || property.isToscaGetFunction() ? property.value : property.valueObj" - [type]="property.isDeclared || property.isToscaGetFunction() ? 'string' : property.type" + [value]="property.isDeclared || property.isToscaFunction() ? property.value : property.valueObj" + [type]="property.isDeclared || property.isToscaFunction() ? 'string' : property.type" [name]="property.name" [path]="property.propertiesName" (elementChanged)="onElementChanged($event)" - [readonly]="readonly || property.isDeclared || property.isDisabled || property.isToscaGetFunction()" + [readonly]="readonly || property.isDeclared || property.isDisabled || property.isToscaFunction()" [testId]="'prop-' + propertyTestsId" [declared] = "property.isDeclared" [constraints] = "constraints" ></dynamic-element> </div> </ng-container> - <ng-container *ngIf="!isPropertyFEModel && propType != derivedPropertyTypes.SIMPLE && !property.isDeclared && !property.isToscaGetFunction()"> <!-- right cell for complex elements, or list complex --> + <ng-container *ngIf="!isPropertyFEModel && propType != derivedPropertyTypes.SIMPLE && !property.isDeclared && !property.isToscaFunction()"> <!-- right cell for complex elements, or list complex --> <div class="table-cell" *ngIf="propType == derivedPropertyTypes.COMPLEX">{{property.type | contentAfterLastDot }}</div> <div class="table-cell" *ngIf="propType == derivedPropertyTypes.MAP && !property.schema.property.isSimpleType">{{property.schema.property.type | contentAfterLastDot }}</div> </ng-container> - <ng-container *ngIf="isPropertyFEModel && (propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && !property.isDeclared && !property.isToscaGetFunction()"><!-- empty, full-width table cell - for PropertyFEModel of type list or map --> + <ng-container *ngIf="isPropertyFEModel && (propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && !property.isDeclared && !property.isToscaFunction()"><!-- empty, full-width table cell - for PropertyFEModel of type list or map --> <div class="table-cell empty"></div> </ng-container> <!-- ICONS: add, delete, and expand --> - <ng-container *ngIf="!property.isDeclared && !property.isToscaGetFunction()"> + <ng-container *ngIf="!property.isDeclared && !property.isToscaFunction()"> <a *ngIf="(propType == derivedPropertyTypes.LIST) && (!property.isChildOfListOrMap || property.mapInlist)" class="property-icon add-item" (click)="createNewChildProperty();" [ngClass]="{'disabled':readonly || preventInsertItem(property)}" [attr.data-tests-id]="'add-to-list-' + propertyTestsId">Add value to list</a> <a *ngIf="(propType == derivedPropertyTypes.MAP) && (!property.isChildOfListOrMap || property.mapInlist)" class="property-icon add-item" (click)="createNewChildProperty();" [ngClass]="{'disabled':readonly || preventInsertItem(property)}" [attr.data-tests-id]="'add-to-list-' + propertyTestsId">Add value to map</a> <span *ngIf="property.isChildOfListOrMap" (click)="deleteItem.emit(property);" class="property-icon sprite-new delete-item-icon" [ngClass]="{'disabled':readonly}" [attr.data-tests-id]="'delete-from-list-' + propertyTestsId"></span> @@ -74,7 +74,7 @@ </div> <!-- FLAT CHILDREN --> -<div class="flat-children-container" *ngIf="isPropertyFEModel && !property.isDeclared && !property.isToscaGetFunction()"> +<div class="flat-children-container" *ngIf="isPropertyFEModel && !property.isDeclared && !property.isToscaFunction()"> <ng-container *ngFor="let prop of property.flattenedChildren | filterChildProperties: expandedChildId; trackBy:prop?.propertiesName"> <dynamic-property [selectedPropertyId]="selectedPropertyId" diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts index 70c9303c14..8e9be8b9a0 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts @@ -55,7 +55,7 @@ export class PropertiesUtils { newFEProp.updateExpandedChildPropertyId(newFEProp.name); //display only the first level of children this.dataTypeService.checkForCustomBehavior(newFEProp); - if (newFEProp.isToscaGetFunction()) { + if (newFEProp.isToscaFunction()) { return; } //if this prop (or any children) are declared, set isDeclared and disable checkbox on parents/children 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 5c9af47361..199f73349e 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 @@ -27,6 +27,7 @@ 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('ToscaConcatFunctionComponent', () => { let component: ToscaConcatFunctionComponent; @@ -34,7 +35,7 @@ describe('ToscaConcatFunctionComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ToscaConcatFunctionComponent, ToscaFunctionComponent, ToscaGetFunctionComponent], + declarations: [ToscaConcatFunctionComponent, ToscaFunctionComponent, ToscaGetFunctionComponent, YamlFunctionComponent], imports: [ FormsModule, ReactiveFormsModule, 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 e98f688eef..f93973cb16 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 @@ -36,6 +36,9 @@ [functionType]="toscaFunctionTypeForm.value" (onValidityChange)="onGetFunctionValidityChange($event)"></app-tosca-get-function> </div> + <div *ngIf="isYamlFunctionSelected()"> + <app-yaml-function [yamlFunction]="toscaFunction" (onValidityChange)="onYamlFunctionValidityChange($event)"></app-yaml-function> + </div> <div *ngIf="showClearButton()" class="button-container"> <button (click)="onClearValues()" class="tlv-btn red ng-star-inserted">{{'TOSCA_FUNCTION_CLEAR_VALUE_BUTTON' | translate}}</button> </div> diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts index 076e1182ad..ae778006ce 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts @@ -30,6 +30,7 @@ import {ToscaGetFunctionValidationEvent} from "./tosca-get-function/tosca-get-fu import {ToscaFunction} from "../../../../models/tosca-function"; import {ToscaConcatFunctionValidationEvent} from "./tosca-concat-function/tosca-concat-function.component"; import {PROPERTY_TYPES} from "../../../../utils/constants"; +import {YamlFunctionValidationEvent} from "./yaml-function/yaml-function.component"; @Component({ selector: 'tosca-function', @@ -75,7 +76,7 @@ export class ToscaFunctionComponent implements OnInit { this.onValidFunction.emit(this.toscaFunctionForm.value); } }); - this.initToscaGetFunction(); + this.initToscaFunction(); this.emitValidityChange(); this.isInitialized = true; } @@ -84,8 +85,8 @@ export class ToscaFunctionComponent implements OnInit { return (!this.toscaFunctionForm.value && !this.toscaFunctionTypeForm.value) || this.formGroup.valid; } - private initToscaGetFunction() { - if (!this.property.isToscaGetFunction()) { + private initToscaFunction() { + if (!this.property.isToscaFunction()) { return; } this.toscaFunctionForm.setValue(this.property.toscaFunction); @@ -99,6 +100,7 @@ export class ToscaFunctionComponent implements OnInit { if (this.property.type === PROPERTY_TYPES.STRING) { this.toscaFunctions.push(ToscaFunctionType.CONCAT); } + this.toscaFunctions.push(ToscaFunctionType.YAML); } private resetForm(): void { @@ -126,6 +128,10 @@ export class ToscaFunctionComponent implements OnInit { return this.isGetInputSelected() || this.isGetPropertySelected() || this.isGetAttributeSelected(); } + isYamlFunctionSelected(): boolean { + return this.formGroup.get('toscaFunctionType').value === ToscaFunctionType.YAML; + } + onClearValues() { this.resetForm(); } @@ -150,6 +156,14 @@ export class ToscaFunctionComponent implements OnInit { } } + onYamlFunctionValidityChange(validationEvent: YamlFunctionValidationEvent) { + if (validationEvent.isValid) { + this.toscaFunctionForm.setValue(validationEvent.value); + } else { + this.toscaFunctionForm.setValue(undefined); + } + } + private emitValidityChange() { const isValid = this.validate(); this.onValidityChange.emit({ @@ -157,6 +171,7 @@ export class ToscaFunctionComponent implements OnInit { toscaFunction: isValid ? this.toscaFunctionForm.value : undefined }); } + } export class ToscaFunctionValidationEvent { diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.module.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.module.ts index 2db76cf544..19cf2fb260 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.module.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.module.ts @@ -27,12 +27,14 @@ import { ToscaFunctionComponent } from './tosca-function.component'; import { SdcUiComponentsModule } from 'onap-ui-angular'; import { ToscaGetFunctionComponent } from './tosca-get-function/tosca-get-function.component'; import { ToscaConcatFunctionComponent } from './tosca-concat-function/tosca-concat-function.component'; +import { YamlFunctionComponent } from './yaml-function/yaml-function.component'; @NgModule({ declarations: [ ToscaFunctionComponent, ToscaGetFunctionComponent, ToscaConcatFunctionComponent, + YamlFunctionComponent, ], imports: [ CommonModule, diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.html new file mode 100644 index 0000000000..ac51d413be --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.html @@ -0,0 +1,35 @@ +<!-- + ~ - + ~ ============LICENSE_START======================================================= + ~ Copyright (C) 2022 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========================================================= + --> + +<div> + <div [formGroup]="formGroup"> + <div> + <textarea class="yaml-text-area" + [formControl]="yamlValueForm" + [class.input-error]="yamlValueForm.invalid && (yamlValueForm.dirty || yamlValueForm.touched)"></textarea> + <div *ngIf="yamlValueForm.invalid && (yamlValueForm.dirty || yamlValueForm.touched)"> + <div *ngIf="yamlValueForm.errors && yamlValueForm.errors['invalidYaml']" class="error"> + {{'YAML_FUNCTION_INVALID_YAML_ERROR' | translate}} + </div> + </div> + </div> + </div> +</div> diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.less b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.less new file mode 100644 index 0000000000..7cbcbc4985 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.less @@ -0,0 +1,40 @@ +/* + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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"; + +.yaml-text-area { + width: 100%; + min-height: 250px; + max-height: 400px; + font-size: 12px; +} + +.error { + color: @func_color_q; +} + +.input-error { + .error(); + border: solid 1px @func_color_q; + outline: none; + box-sizing: border-box; +}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.spec.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.spec.ts new file mode 100644 index 0000000000..500fe643c8 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.spec.ts @@ -0,0 +1,53 @@ +/* + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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 {YamlFunctionComponent} from './yaml-function.component'; +import {FormsModule, ReactiveFormsModule} from "@angular/forms"; +import {TranslateModule} from "../../../../shared/translator/translate.module"; + +describe('YamlFunctionComponent', () => { + let component: YamlFunctionComponent; + let fixture: ComponentFixture<YamlFunctionComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [YamlFunctionComponent], + imports: [ + FormsModule, + ReactiveFormsModule, + TranslateModule + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(YamlFunctionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.ts new file mode 100644 index 0000000000..e0272270d1 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/yaml-function/yaml-function.component.ts @@ -0,0 +1,80 @@ +/* + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2022 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 {YamlFunction} from "../../../../../models/yaml-function"; +import {FormControl, FormGroup, Validators, AbstractControl, ValidationErrors, ValidatorFn} from "@angular/forms"; +import * as jsYaml from 'js-yaml'; + +@Component({ + selector: 'app-yaml-function', + templateUrl: './yaml-function.component.html', + styleUrls: ['./yaml-function.component.less'] +}) +export class YamlFunctionComponent implements OnInit { + + @Input() yamlFunction: YamlFunction; + @Output() onValidityChange: EventEmitter<YamlFunctionValidationEvent> = new EventEmitter<YamlFunctionValidationEvent>(); + + yamlValueForm: FormControl = new FormControl('', [Validators.minLength(1), YamlValidator()]); + formGroup: FormGroup = new FormGroup( + { + 'value': this.yamlValueForm + } + ); + + ngOnInit() { + this.formGroup.valueChanges.subscribe(() => { + this.onValidityChange.emit({ + isValid: this.formGroup.valid, + value: this.formGroup.valid ? this.buildYamlFunctionFromForm() : undefined + }); + }); + if (this.yamlFunction) { + this.yamlValueForm.setValue(this.yamlFunction.value); + } + } + + private buildYamlFunctionFromForm(): YamlFunction { + const yamlFunction = new YamlFunction(); + yamlFunction.value = this.yamlValueForm.value; + return yamlFunction; + } +} + +export class YamlFunctionValidationEvent { + isValid: boolean; + value: YamlFunction; +} + +export function YamlValidator(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + if (!control.value) { + return {invalidYaml: {value: control.value}}; + } + try { + jsYaml.load(control.value); + return null; + } catch (e) { + return {invalidYaml: {value: control.value}}; + } + }; +}
\ No newline at end of file |