From f13f58eb867c763e6ed1c3b674fd99b1081a0664 Mon Sep 17 00:00:00 2001 From: "andre.schmid" Date: Wed, 9 Feb 2022 19:00:35 +0000 Subject: Support complex types in interface operation inputs Issue-ID: SDC-3897 Change-Id: Ieac2d74ad340de1d9f6e4cd3ac830e2ec8c35d5b Signed-off-by: andre.schmid Signed-off-by: vasraz Signed-off-by: MichaelMorris --- catalog-ui/src/app/app.ts | 2 +- catalog-ui/src/app/models/data-types-map.ts | 10 +- catalog-ui/src/app/models/data-types.ts | 35 ++- catalog-ui/src/app/models/interfaceOperation.ts | 28 ++- .../models/properties-inputs/property-be-model.ts | 56 ++++- .../logic/inputs-table/inputs-table.component.html | 2 +- .../interface-operations.component.ts | 55 +++-- .../add-input/add-input.component.html | 69 ++++++ .../add-input/add-input.component.less | 64 ++++++ .../add-input/add-input.component.spec.ts | 67 ++++++ .../add-input/add-input.component.ts | 210 ++++++++++++++++++ .../input-list-item/input-list-item.component.html | 119 ++++++++++ .../input-list-item/input-list-item.component.less | 123 +++++++++++ .../input-list-item.component.spec.ts | 55 +++++ .../input-list-item/input-list-item.component.ts | 245 +++++++++++++++++++++ .../input-list/input-list.component.html | 36 +++ .../input-list/input-list.component.less | 36 +++ .../input-list/input-list.component.spec.ts | 69 ++++++ .../input-list/input-list.component.ts | 125 +++++++++++ .../input-param-row/input-param-row.component.html | 45 ---- .../input-param-row/input-param-row.component.less | 72 ------ .../input-param-row/input-param-row.component.ts | 48 ---- .../interface-operation-handler.component.html | 41 ++-- .../interface-operation-handler.component.less | 13 +- .../interface-operation-handler.component.ts | 109 ++++++--- .../interface-operation-handler.module.ts | 26 ++- .../panel/panel-tabs/panel-tab.component.ts | 16 +- .../property-creator/property-creator.module.ts | 49 +++-- .../src/app/ng2/services/data-type.service.ts | 4 + catalog-ui/src/app/services/data-types-service.ts | 33 ++- 30 files changed, 1553 insertions(+), 309 deletions(-) create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.spec.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.spec.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.spec.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.html delete mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.less delete mode 100644 catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.ts (limited to 'catalog-ui/src/app') diff --git a/catalog-ui/src/app/app.ts b/catalog-ui/src/app/app.ts index ffa43895a7..e7e2828eb5 100644 --- a/catalog-ui/src/app/app.ts +++ b/catalog-ui/src/app/app.ts @@ -675,7 +675,7 @@ ng1appModule.run([ // $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'; $http.defaults.headers.common[cookieService.getUserIdSuffix()] = cookieService.getUserId(); - DataTypesService.fetchDataTypesByModel(null); + DataTypesService.loadDataTypesCache(null); //handle stateChangeStart let internalDeregisterStateChangeStartWatcher: Function = (): void => { diff --git a/catalog-ui/src/app/models/data-types-map.ts b/catalog-ui/src/app/models/data-types-map.ts index 3591bc2705..e7b1c6922a 100644 --- a/catalog-ui/src/app/models/data-types-map.ts +++ b/catalog-ui/src/app/models/data-types-map.ts @@ -25,13 +25,13 @@ import {DataTypeModel} from "./data-types"; export class DataTypesMapData { - [dataTypeId:string]:Array; + [dataTypeId: string]: Array; } export class DataTypesMap { - dataTypesMap:DataTypesMapData; + dataTypesMap: DataTypesMapData; - constructor(dataTypesMap:DataTypesMapData) { - this.dataTypesMap = dataTypesMap; - } + constructor(dataTypesMap: DataTypesMapData) { + this.dataTypesMap = dataTypesMap; + } } diff --git a/catalog-ui/src/app/models/data-types.ts b/catalog-ui/src/app/models/data-types.ts index 7004b43cbc..7fc788bf93 100644 --- a/catalog-ui/src/app/models/data-types.ts +++ b/catalog-ui/src/app/models/data-types.ts @@ -25,6 +25,7 @@ import {PropertyBEModel} from "./properties-inputs/property-be-model"; import {AttributeBEModel} from "./attributes-outputs/attribute-be-model"; import {Model} from "./model"; +import {PROPERTY_DATA} from "../utils/constants"; export class DataTypeModel { @@ -39,16 +40,24 @@ export class DataTypeModel { attributes: Array; model: Model; - constructor(dataType:DataTypeModel) { + constructor(dataType: DataTypeModel) { if (dataType) { this.uniqueId = dataType.uniqueId; this.name = dataType.name; this.derivedFromName = dataType.derivedFromName; + if (dataType.derivedFrom) { + this.derivedFrom = new DataTypeModel(dataType.derivedFrom); + } this.creationTime = dataType.creationTime; this.modificationTime = dataType.modificationTime; - this.properties = dataType.properties; + if (dataType.properties) { + this.properties = []; + dataType.properties.forEach(property => { + this.properties.push(new PropertyBEModel(property)); + }); + } this.attributes = dataType.attributes; - this.model = this.model; + this.model = dataType.model; } } @@ -56,5 +65,25 @@ export class DataTypeModel { return this; }; + + /** + * Parses the default value to JSON. + */ + public parseDefaultValueToJson(): any { + if (PROPERTY_DATA.TYPES.indexOf(this.name) > -1) { + return undefined; + } + const defaultValue = {}; + if (this.properties) { + this.properties.forEach(property => { + const propertyDefaultValue = property.parseDefaultValueToJson(); + if (propertyDefaultValue != undefined) { + defaultValue[property.name] = propertyDefaultValue; + } + }); + } + + return defaultValue === {} ? undefined : defaultValue; + } } diff --git a/catalog-ui/src/app/models/interfaceOperation.ts b/catalog-ui/src/app/models/interfaceOperation.ts index 109babb068..9d8ab366a2 100644 --- a/catalog-ui/src/app/models/interfaceOperation.ts +++ b/catalog-ui/src/app/models/interfaceOperation.ts @@ -20,21 +20,47 @@ 'use strict'; import {ArtifactModel} from "./artifacts"; +import {SchemaPropertyGroupModel} from "./schema-property"; +import {PROPERTY_DATA, PROPERTY_TYPES} from "../utils/constants"; export class InputOperationParameter { name: string; type: string; + schema: SchemaPropertyGroupModel; inputId: string; toscaDefaultValue?: string; + value?: any; constructor(param?: any) { if (param) { this.name = param.name; this.type = param.type; + this.schema = param.schema; this.inputId = param.inputId; this.toscaDefaultValue = param.toscaDefaultValue; + this.value = param.value; + } + } + + public getDefaultValue(): any { + if (this.isTypeNotSimple()) { + if (this.toscaDefaultValue) { + this.toscaDefaultValue = JSON.parse(this.toscaDefaultValue); + return JSON.parse(this.toscaDefaultValue); + } + switch (this.type) { + case PROPERTY_TYPES.LIST: + return []; + default: + return {}; + } } - console.info("InputOperationParameter Constructor: ", param) + + return this.toscaDefaultValue; + } + + private isTypeNotSimple() { + return PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) == -1; } } diff --git a/catalog-ui/src/app/models/properties-inputs/property-be-model.ts b/catalog-ui/src/app/models/properties-inputs/property-be-model.ts index bd65c3a70a..267a2adc71 100644 --- a/catalog-ui/src/app/models/properties-inputs/property-be-model.ts +++ b/catalog-ui/src/app/models/properties-inputs/property-be-model.ts @@ -109,15 +109,61 @@ export class PropertyBEModel { return temp; } - public getDerivedPropertyType = () => { + public getDerivedPropertyType = (): DerivedPropertyType => { if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) > -1) { return DerivedPropertyType.SIMPLE; - } else if (this.type === PROPERTY_TYPES.LIST) { + } + if (this.type === PROPERTY_TYPES.LIST) { return DerivedPropertyType.LIST; - } else if (this.type === PROPERTY_TYPES.MAP) { + } + if (this.type === PROPERTY_TYPES.MAP) { return DerivedPropertyType.MAP; - } else { - return DerivedPropertyType.COMPLEX; + } + return DerivedPropertyType.COMPLEX; + } + + /** + * Parses default value to JSON. + */ + public parseDefaultValueToJson(): any { + if (this.defaultValue == undefined) { + return undefined; + } + + const propertyType: DerivedPropertyType = this.getDerivedPropertyType(); + if (propertyType == DerivedPropertyType.SIMPLE) { + return this.parseDefaultSimpleValue(); + } + + try { + return JSON.parse(this.defaultValue); + } catch (e) { + console.error(`Could not parse the property of type '${this.type}' default value to JSON '${this.defaultValue}'`, e); + } + + return undefined; + } + + private parseDefaultSimpleValue() { + switch (this.type) { + case PROPERTY_TYPES.INTEGER: + try { + return parseInt(this.defaultValue); + } catch (e) { + console.error(`Could not parse the property of type '${this.type}' default value to int '${this.defaultValue}'`, e); + } + return undefined; + case PROPERTY_TYPES.FLOAT: + try { + return parseFloat(this.defaultValue); + } catch (e) { + console.error(`Could not parse the property of type '${this.type}' default value to float '${this.defaultValue}'`, e); + } + return undefined; + case PROPERTY_TYPES.BOOLEAN: + return this.defaultValue === 'true'; + default: + return this.defaultValue; } } diff --git a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html index e1638fb00f..7c83c55ae6 100644 --- a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html +++ b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html @@ -117,7 +117,7 @@
{ this.EDIT_TITLE = this.TranslateService.translate('INTERFACE_EDIT_TITLE'); this.CANCEL_BUTTON = this.TranslateService.translate("INTERFACE_CANCEL_BUTTON"); + this.CLOSE_BUTTON = this.TranslateService.translate("INTERFACE_CLOSE_BUTTON"); this.SAVE_BUTTON = this.TranslateService.translate("INTERFACE_SAVE_BUTTON"); }); } @@ -135,7 +123,7 @@ export class InterfaceOperationsComponent { toscaArtifactTypes: Array = []; @Input() component: ComponentInstance; - @Input() readonly: boolean; + @Input() isViewOnly: boolean; @Input() enableMenuItems: Function; @Input() disableMenuItems: Function; @Input() componentType: SelectedComponentType; @@ -209,14 +197,23 @@ export class InterfaceOperationsComponent { } private enableOrDisableSaveButton = (): boolean => { - return this.modalInstance.instance.dynamicContent.instance.readonly; + return this.isViewOnly; } onSelectInterfaceOperation(interfaceModel: UIInterfaceModel, operation: InterfaceOperationModel) { - const cancelButton: ButtonModel = new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal); - const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue', () => - this.updateInterfaceOperation(), this.enableOrDisableSaveButton); - const modalModel: ModalModel = new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', [saveButton, cancelButton], 'custom'); + + const buttonList = []; + if (this.isViewOnly) { + const closeButton: ButtonModel = new ButtonModel(this.modalTranslation.CLOSE_BUTTON, 'outline white', this.cancelAndCloseModal); + buttonList.push(closeButton); + } else { + const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue', () => + this.updateInterfaceOperation(), this.enableOrDisableSaveButton); + const cancelButton: ButtonModel = new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal); + buttonList.push(saveButton); + buttonList.push(cancelButton); + } + const modalModel: ModalModel = new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', buttonList, 'custom'); this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel); this.modalServiceNg2.addDynamicContentToModal( @@ -228,7 +225,7 @@ export class InterfaceOperationsComponent { selectedInterface: interfaceModel, selectedInterfaceOperation: operation, validityChangedCallback: this.enableOrDisableSaveButton, - isViewOnly: false + isViewOnly: this.isViewOnly } ); this.modalInstance.instance.open(); @@ -241,7 +238,7 @@ export class InterfaceOperationsComponent { private updateInterfaceOperation() { this.isLoading = true; - let operationUpdated = this.modalInstance.instance.dynamicContent.instance.operationToUpdate; + const operationUpdated: InterfaceOperationModel = this.modalInstance.instance.dynamicContent.instance.operationToUpdate; this.topologyTemplateService.updateComponentInstanceInterfaceOperation( this.componentMetaData.uniqueId, this.componentMetaData.componentType, diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.html new file mode 100644 index 0000000000..6753b82167 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.html @@ -0,0 +1,69 @@ + + +
+ +
+ +
+ + +
+
+ + + +
+
+ + + +
+
+ + +
+
+
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.less new file mode 100644 index 0000000000..5eb4a7f5b1 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.less @@ -0,0 +1,64 @@ +/* + * - + * ============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========================================================= + */ + +.add-button-container { + display: flex; + flex-flow: row wrap; + justify-content: flex-end; + margin: 7px 5px 7px 0; +} + +.confirmation-button-container { + display: flex; + flex-flow: row wrap; + justify-content: flex-end; + margin: 7px 5px 7px 0; + button { + margin: 0 5px; + } +} + +.sdc-input-label { + margin-bottom: 5px; + display: block; + font-family: OpenSans-Semibold, Arial, sans-serif; + font-style: normal; + font-weight: 600; + font-size: 12px; +} + +.sdc-input { + box-sizing: border-box; + padding: 0 10px; + height: 38px; + width: 100%; + border: solid 1px #d2d2d2; + border-radius: 2px; + color: #5a5a5a; +} + +.add-param-link { + +} + +.add-btn { + +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.spec.ts new file mode 100644 index 0000000000..2c6c1e6614 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.spec.ts @@ -0,0 +1,67 @@ +/* + * - + * ============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 {AddInputComponent} from './add-input.component'; +import {TranslateModule} from '../../../../../shared/translator/translate.module'; +import {ReactiveFormsModule} from '@angular/forms'; +import {SdcUiComponentsModule} from 'onap-ui-angular/dist'; +import {Observable} from 'rxjs/Observable'; +import {DataTypesMap} from '../../../../../../models/data-types-map'; +import {TranslateService} from '../../../../../shared/translator/translate.service'; + +const translateServiceMock: Partial = { + translate: jest.fn((str: string) => { + }) +}; + +describe('AddInputComponent', () => { + let component: AddInputComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AddInputComponent ], + imports: [ + TranslateModule, + SdcUiComponentsModule, + ReactiveFormsModule + ], + providers: [ + { provide: TranslateService, useValue: translateServiceMock } + ] + }) + .compileComponents(); + + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddInputComponent); + component = fixture.componentInstance; + component.dataTypeMap$ = new Observable(); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.ts new file mode 100644 index 0000000000..6632d1a69e --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.ts @@ -0,0 +1,210 @@ +/* + * - + * ============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 {InputOperationParameter} from '../../../../../../models/interfaceOperation'; +import {IDropDownOption} from 'onap-ui-angular/dist/form-elements/dropdown/dropdown-models'; +import {Observable} from 'rxjs/Observable'; +import {AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators} from '@angular/forms'; +import {PROPERTY_TYPES} from '../../../../../../utils/constants'; +import {SchemaProperty, SchemaPropertyGroupModel} from '../../../../../../models/schema-property'; +import {DataTypeModel} from "../../../../../../models/data-types"; + +@Component({ + selector: 'app-add-input', + templateUrl: './add-input.component.html', + styleUrls: ['./add-input.component.less'] +}) +export class AddInputComponent implements OnInit { + + @Input('dataTypeMap') dataTypeMap$: Observable>; + @Input('isView') isView: boolean; + @Input() existingInputNames: Array = []; + @Output('onAddInput') onAddInputEvent: EventEmitter; + + dataTypeMap: Map; + inputToAdd: InputOperationParameter; + inputTypeOptions: Array; + inputSchemaOptions: Array; + showForm: boolean = false; + showAddLink: boolean = true; + showInputSchema: boolean = false; + + inputForm: FormGroup; + + constructor() { + this.onAddInputEvent = new EventEmitter(); + this.inputTypeOptions = []; + this.inputSchemaOptions = []; + this.inputToAdd = new InputOperationParameter(); + } + + schemaValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { + const type = control.get('type'); + const schema = control.get('schema'); + return (type.value === 'list' || type.value === 'map') && !schema.value ? { schemaRequired: true } : null; + }; + + uniqueNameValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { + const name = control.get('name'); + return this.existingInputNames.indexOf(name.value) === -1 ? null : { nameIsNotUnique: true }; + }; + + ngOnInit() { + this.initForm(); + this.initInputType(); + } + + private initForm() { + this.inputForm = new FormGroup({ + name: new FormControl({value: '', disabled: this.isView}, [Validators.required, Validators.minLength(1)]), + type: new FormControl({value: '', disabled: this.isView}, [Validators.required, Validators.minLength(1)]), + schema: new FormControl({value: '', disabled: this.isView}) + }, { validators: [this.schemaValidator, this.uniqueNameValidator] }); + } + + private initInputType() { + this.dataTypeMap$.subscribe((dataTypesMap: Map) => { + this.dataTypeMap = dataTypesMap; + this.inputTypeOptions = []; + this.inputSchemaOptions = []; + dataTypesMap.forEach((value, key) => { + const entry = {label: key, value: key}; + this.inputTypeOptions.push(entry); + if (key != PROPERTY_TYPES.LIST && key != PROPERTY_TYPES.MAP) { + this.inputSchemaOptions.push(entry); + } + }); + }); + } + + onChangeInputType(inputType) { + const typeForm = this.inputForm.get('type'); + if (!inputType) { + this.inputToAdd.type = undefined; + typeForm.setValue(undefined); + this.toggleInputSchema(); + return; + } + typeForm.setValue(inputType); + this.inputToAdd.type = inputType; + this.toggleInputSchema(); + } + + onChangeInputSchema(inputSchema: string) { + const schemaForm = this.inputForm.get('schema'); + if (!inputSchema) { + this.inputToAdd.schema = undefined; + schemaForm.setValue(undefined); + return; + } + schemaForm.setValue(inputSchema); + this.inputToAdd.schema = new SchemaPropertyGroupModel(); + this.inputToAdd.schema.property = new SchemaProperty(); + this.inputToAdd.schema.property.type = inputSchema; + } + + onSubmit() { + this.trimForm(); + if (this.inputForm.valid) { + const nameForm = this.inputForm.get('name'); + const typeForm = this.inputForm.get('type'); + const schemaForm = this.inputForm.get('schema'); + const input = new InputOperationParameter(); + input.name = nameForm.value; + input.type = typeForm.value; + if (this.typeHasSchema()) { + input.schema = new SchemaPropertyGroupModel(); + input.schema.property = new SchemaProperty(); + input.schema.property.type = schemaForm.value; + } + input.inputId = this.generateUniqueId(); + this.onAddInputEvent.emit(input); + this.hideAddInput(); + this.resetForm(); + } + } + + showAddInput() { + this.showForm = true; + this.showAddLink = false; + } + + hideAddInput() { + this.showForm = false; + this.showAddLink = true; + } + + onCancel() { + this.hideAddInput(); + this.resetForm(); + } + + private generateUniqueId(): string { + let result = ''; + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + const charactersLength = characters.length; + for (let i = 0; i < 36; i++ ) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; + } + + private resetForm() { + this.inputForm.reset(); + this.showInputSchema = false; + this.inputToAdd = new InputOperationParameter(); + } + + getSchemaType() { + return this.inputToAdd.schema == undefined ? undefined : this.inputToAdd.schema.property.type; + } + + getSchemaPlaceholder() { + const schemaType = this.getSchemaType(); + return schemaType === undefined ? 'Select...' : schemaType; + } + + private toggleInputSchema() { + this.showInputSchema = this.typeHasSchema(); + } + + private typeHasSchema() { + const typeForm = this.inputForm.get('type'); + return typeForm.value == PROPERTY_TYPES.LIST || typeForm.value == PROPERTY_TYPES.MAP; + } + + private trimForm() { + const nameForm = this.inputForm.get('name'); + if (nameForm.value) { + nameForm.setValue(nameForm.value.trim()); + } + const typeForm = this.inputForm.get('type'); + if (typeForm.value) { + typeForm.setValue(typeForm.value.trim()); + } + const schemaForm = this.inputForm.get('schema'); + if (schemaForm.value) { + schemaForm.setValue(schemaForm.value.trim()); + } + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.html new file mode 100644 index 0000000000..0449da7d05 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.html @@ -0,0 +1,119 @@ + + +
  • + + + {{resolveType()}} + + + + +
      +
    • + + {{valueObjRef}}empty + + +
    • +
    +
    + +
      + + + + +
    +
    + + + + + + +
  • \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.less new file mode 100644 index 0000000000..cb7346e390 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.less @@ -0,0 +1,123 @@ +/* + * - + * ============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========================================================= + */ + +* { + font-size: 0.875rem; +} + +.input-info { + display: flex; + flex-flow: row nowrap; + align-items: center; + gap: 10px; + font-family: OpenSans-Regular, sans-serif; + font-weight: 400; +} + +.input-label { + margin: 0; + font-weight: bold; +} + +.input-value { + display: flex; + flex-flow: row nowrap; + gap: 7px; + + input { + min-width: 150px; + max-width: 250px; + } +} + +.input-map-key { + input { + max-width: 150px; + } +} + +.input-action-container { + flex-grow: 1; + margin-left: auto; +} + +.input-action { + flex-grow: 2 +} + +ul { + margin: 0 0 0 20px; + list-style: none; + line-height: 2em; +} + +li { + position: relative; + + &:before { + position: absolute; + left: -15px; + top: 0; + content: ''; + display: block; + border-left: 1px solid #ddd; + height: 1em; + border-bottom: 1px solid #ddd; + width: 10px; + } + + &:after { + position: absolute; + left: -15px; + bottom: -7px; + content: ''; + display: block; + border-left: 1px solid #ddd; + height: 100%; + } + + &.root { + margin: 0 0 0 -20px; + + &:before { + display: none; + } + + &:after { + display: none; + } + } + + &:last-child { + &:after { + display: none + } + } +} + +label { + margin: 0; + font-weight: normal; +} + +.empty-value { + color: #aaaaaa; +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.spec.ts new file mode 100644 index 0000000000..b7e34e5c32 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.spec.ts @@ -0,0 +1,55 @@ +/* + * - + * ============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 {InputListItemComponent} from './input-list-item.component'; +import {TranslateModule} from '../../../../../../shared/translator/translate.module'; +import {FormsModule} from '@angular/forms'; +import {DataTypeModel} from '../../../../../../../models/data-types'; + +describe('InputListItemComponent', () => { + let component: InputListItemComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ InputListItemComponent ], + imports: [ + TranslateModule, + FormsModule + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(InputListItemComponent); + component = fixture.componentInstance; + component.valueObjRef = ""; + component.type = new DataTypeModel(undefined); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeDefined(); + }); +}); diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts new file mode 100644 index 0000000000..cd75fe87e6 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts @@ -0,0 +1,245 @@ +/* + * - + * ============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 {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'; + +@Component({ + selector: 'app-input-list-item', + templateUrl: './input-list-item.component.html', + styleUrls: ['./input-list-item.component.less'] +}) +export class InputListItemComponent implements OnInit { + + @Input() valueObjRef: any; + @Input() name: string; + @Input() dataTypeMap: Map; + @Input() type: DataTypeModel; + @Input() schema: SchemaPropertyGroupModel; + @Input() nestingLevel: number; + @Input() isListChild: boolean = false; + @Input() isMapChild: boolean = false; + @Input() listIndex: number; + @Input() isViewOnly: boolean; + @Output('onValueChange') onValueChangeEvent: EventEmitter = new EventEmitter(); + @Output('onDelete') onDeleteEvent: EventEmitter = new EventEmitter(); + @Output('onChildListItemDelete') onChildListItemDeleteEvent: EventEmitter = new EventEmitter(); + + isExpanded: boolean = false; + mapEntryName: string; + + ngOnInit() { + if (!this.nestingLevel) { + this.nestingLevel = 0; + } + if (this.type.properties) { + this.type.properties.forEach(property => { + this.initEmptyPropertyInValueObjRef(property); + }); + } + } + + private initEmptyPropertyInValueObjRef(property: PropertyBEModel) { + if (this.valueObjRef[property.name] == undefined) { + if (this.isTypeComplex(property.type) || this.isTypeMap(property.type)) { + this.valueObjRef[property.name] = {}; + } else if (this.isTypeList(property.type)) { + this.valueObjRef[property.name] = []; + } else { + this.valueObjRef[property.name] = null; + } + } + } + + getType(typeName: string): DerivedPropertyType { + if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(typeName) > -1) { + return DerivedPropertyType.SIMPLE; + } else if (typeName === PROPERTY_TYPES.LIST) { + return DerivedPropertyType.LIST; + } else if (typeName === PROPERTY_TYPES.MAP) { + return DerivedPropertyType.MAP; + } else { + return DerivedPropertyType.COMPLEX; + } + } + + isTypeSimple(typeName: string): boolean { + return this.getType(typeName) == DerivedPropertyType.SIMPLE; + } + + isTypeList(typeName: string): boolean { + return this.getType(typeName) == DerivedPropertyType.LIST; + } + + isTypeMap(typeName: string): boolean { + return this.getType(typeName) == DerivedPropertyType.MAP; + } + + isTypeComplex(typeName: string): boolean { + return !this.isTypeSimple(typeName) && !this.isTypeList(typeName) && !this.isTypeMap(typeName); + } + + expandAndCollapse() { + this.isExpanded = !this.isExpanded; + } + + getDataType(type: string) { + return this.dataTypeMap.get(type); + } + + onValueChange(value: any): void { + if (this.type.name == PROPERTY_TYPES.INTEGER || this.type.name == PROPERTY_TYPES.FLOAT) { + this.emitValueChangeEvent(this.parseNumber(value)); + return; + } + if (this.type.name == PROPERTY_TYPES.BOOLEAN) { + this.emitValueChangeEvent(this.parseBoolean(value)); + return; + } + this.emitValueChangeEvent(value); + } + + onListValueChange(): void { + this.emitValueChangeEvent(this.valueObjRef); + } + + onPropertyValueChange($event: any) { + this.valueObjRef[$event.name] = $event.value; + this.emitValueChangeEvent(this.valueObjRef); + } + + private emitValueChangeEvent(value: any) { + this.onValueChangeEvent.emit({ + name: this.name, + value: value + }); + } + + isRoot(): boolean { + return this.nestingLevel === 0; + } + + showListItemDelete(): boolean { + return !this.isViewOnly && (this.isListChild && this.nestingLevel > 0); + } + + showInputDelete(): boolean { + return !this.isViewOnly && (this.isRoot() || this.isMapChild); + } + + resolveType(): string { + if (this.isTypeList(this.type.name)) { + return `list of value type ${this.schema.property.type}` + } + if (this.isTypeMap(this.type.name)) { + return `map of 'string' keys and '${this.schema.property.type}' values` + } + return this.type.name; + } + + onInputDelete() { + this.onDeleteEvent.emit(this.name); + } + + onListItemDelete(index: number): void { + this.valueObjRef.splice(index, 1); + this.emitValueChangeEvent(this.valueObjRef); + } + + addListElement() { + if (this.isTypeSimple(this.schema.property.type)) { + this.valueObjRef.push(''); + } else if (this.isTypeComplex(this.schema.property.type) || this.isTypeMap(this.schema.property.type)) { + this.valueObjRef.push({}); + } else if (this.isTypeList(this.schema.property.type)) { + this.valueObjRef.push([]); + } + } + + trackByIndex(index: number, value: string): number { + return index; + } + + onChildListItemDelete() { + this.onChildListItemDeleteEvent.emit(this.listIndex); + } + + getObjectEntries(valueObjRef: object) { + return Object.keys(valueObjRef); + } + + onMapValueChange() { + this.emitValueChangeEvent(this.valueObjRef); + } + + onMapKeyDelete(key: string) { + delete this.valueObjRef[key] + this.emitValueChangeEvent(this.valueObjRef); + } + + addMapEntry() { + let newKey; + if (this.mapEntryName) { + newKey = this.mapEntryName.trim(); + } + if (!newKey) { + return; + } + if (Object.keys(this.valueObjRef).indexOf(newKey) !== -1) { + return; + } + this.mapEntryName = ''; + if (this.isTypeSimple(this.schema.property.type)) { + this.valueObjRef[newKey] = ''; + } else if (this.isTypeComplex(this.schema.property.type) || this.isTypeMap(this.schema.property.type)) { + this.valueObjRef[newKey] = {}; + } else if (this.isTypeList(this.schema.property.type)) { + this.valueObjRef[newKey] = []; + } + this.emitValueChangeEvent(this.valueObjRef); + } + + getSimpleValueInputType() { + if (this.type.name == PROPERTY_TYPES.INTEGER || this.type.name == PROPERTY_TYPES.FLOAT) { + return 'number'; + } + return 'text'; + } + + private parseBoolean(value: any) { + if (value === 'true') { + return true; + } + if (value === 'false') { + return false; + } + return null; + } + + private parseNumber(value: any) { + const number = parseInt(value); + return isNaN(number) ? null : number; + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.html new file mode 100644 index 0000000000..802bd63838 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.html @@ -0,0 +1,36 @@ + + + +
    +
      + + +
    +
    \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.less new file mode 100644 index 0000000000..b9784f9564 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.less @@ -0,0 +1,36 @@ +/* + * - + * ============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========================================================= + */ + +.input-tree { + overflow: scroll; + max-height: 300px; + max-width: 100%; + + ul { + margin: 0 0 0 20px; + list-style: none; + line-height: 2em; + } +} + +.input-tree::-webkit-scrollbar-track { + border: 0; +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.spec.ts new file mode 100644 index 0000000000..b07a4bb55f --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.spec.ts @@ -0,0 +1,69 @@ +/* + * - + * ============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 {InputListComponent} from './input-list.component'; +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'; + +@Component({selector: 'app-input-list-item', template: ''}) +class InputListItemStubComponent { + @Input() name: string; + @Input() type: DataTypeModel; + @Input() dataTypeMap: any; + @Input() valueObjRef: any; + @Input() schema: any; + @Input() isViewOnly: boolean; +} + +const translateServiceMock: Partial = { + translate: jest.fn((str: string) => { + }) +}; + +describe('InputListComponent', () => { + let component: InputListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ InputListComponent, InputListItemStubComponent ], + imports: [ TranslateModule ], + providers: [ + { provide: TranslateService, useValue: translateServiceMock } + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(InputListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeDefined(); + }); +}); diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.ts new file mode 100644 index 0000000000..72812d810d --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.ts @@ -0,0 +1,125 @@ +/* + * - + * ============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, Output} from '@angular/core'; +import {InputOperationParameter} from "../../../../../../models/interfaceOperation"; +import {DataTypeModel} from "../../../../../../models/data-types"; +import {DerivedPropertyType} from "../../../../../../models/properties-inputs/property-be-model"; +import {PROPERTY_DATA, PROPERTY_TYPES} from "../../../../../../utils/constants"; + +@Component({ + selector: 'input-list', + templateUrl: './input-list.component.html', + styleUrls: ['./input-list.component.less'] +}) +export class InputListComponent { + + @Input() set inputs(inputs: Array) { + this._inputs = new Array(); + if (inputs) { + inputs.forEach(input => { + const inputCopy = new InputOperationParameter(input); + this.initValue(inputCopy); + + this._inputs.push(inputCopy); + }); + } + } + @Input() dataTypeMap: Map; + @Input() isViewOnly: boolean; + @Output('onValueChange') inputValueChangeEvent: EventEmitter = new EventEmitter(); + @Output('onDelete') inputDeleteEvent: EventEmitter = new EventEmitter(); + + _inputs: Array; + + getDataType(type: string): DataTypeModel { + return this.dataTypeMap.get(type); + } + + private initValue(input: InputOperationParameter): void { + if (input.value) { + try { + input.value = JSON.parse(input.value); + } catch (e) { + console.debug('Could not parse value', input.value, e); + } + return; + } + + if (input.toscaDefaultValue) { + try { + input.value = JSON.parse(input.toscaDefaultValue); + return; + } catch (e) { + console.debug('Could not parse value', input.value, e); + } + } + + if (this.isTypeComplex(input.type) || this.isTypeMap(input.type)) { + input.value = {}; + } else if (this.isTypeList(input.type)) { + input.value = []; + } else { + input.value = undefined; + } + } + + getType(typeName: string): DerivedPropertyType { + if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(typeName) > -1) { + return DerivedPropertyType.SIMPLE; + } else if (typeName === PROPERTY_TYPES.LIST) { + return DerivedPropertyType.LIST; + } else if (typeName === PROPERTY_TYPES.MAP) { + return DerivedPropertyType.MAP; + } else { + return DerivedPropertyType.COMPLEX; + } + } + + isTypeSimple(typeName: string): boolean { + return this.getType(typeName) == DerivedPropertyType.SIMPLE; + } + + isTypeList(typeName: string): boolean { + return this.getType(typeName) == DerivedPropertyType.LIST; + } + + isTypeMap(typeName: string): boolean { + return this.getType(typeName) == DerivedPropertyType.MAP; + } + + isTypeComplex(typeName: string): boolean { + return !this.isTypeSimple(typeName) && !this.isTypeList(typeName) && !this.isTypeMap(typeName); + } + + onValueChange($event: any) { + const inputOperationParameter = this._inputs.find(input => input.name == $event.name); + if (inputOperationParameter) { + inputOperationParameter.value = $event.value; + this.inputValueChangeEvent.emit(new InputOperationParameter(inputOperationParameter)); + } + } + + onDelete(inputName: string) { + this.inputDeleteEvent.emit(inputName); + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.html deleted file mode 100644 index 156b657645..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.html +++ /dev/null @@ -1,45 +0,0 @@ - - -
    - - -
    - -
    - - -
    - -
    - - -
    diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.less deleted file mode 100644 index 12eacc6473..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.less +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2021 Nordix Foundation. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ - -@import '../../../../../../../assets/styles/variables.less'; - -.remove { - display: flex; - align-items: center; - justify-content: center; - - svg-icon { - position: relative; - right: -3px; - - &:hover { - cursor: pointer; - } - } -} - -.cell { - min-height: 50px; - padding: 10px; - display: flex; - align-items: center; - - > * { - flex-basis: 100%; - } - - /deep/ select { - height: 30px; - } - - input { - height: 30px; - border: none; - padding-left: 10px; - } - - select { - width: 100%; - } - - &.field-property { - &:last-child { - flex: 1; - } - - .no-properties-error { - color: @func_color_q; - font-style: italic; - } - } -} diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.ts deleted file mode 100644 index 48bb804173..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-param-row/input-param-row.component.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* -* ============LICENSE_START======================================================= -* SDC -* ================================================================================ -* Copyright (C) 2021 Nordix Foundation. All rights reserved. -* ================================================================================ -* 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, Input} from '@angular/core'; -import {InputOperationParameter} from "../../../../../../models/interfaceOperation"; - -@Component({ - selector: 'input-param-row', - templateUrl: './input-param-row.component.html', - styleUrls: ['./input-param-row.component.less'] -}) - -export class InputParamRowComponent { - @Input() input: InputOperationParameter; - @Input() onRemoveInput: Function; - @Input() readonly: boolean; - @Input() validityChanged: Function; - - constructor() { - } - - ngOnInit() { - this.validityChanged(); - } - - onChange() { - this.validityChanged(); - } - -} diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html index 6dec4160f6..46db3b94a9 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html @@ -124,32 +124,23 @@
    - -
    - - {{'OPERATION_ADD_INPUT' | translate}} - +
    + +
    - -
    -
    - {{ 'OPERATION_PARAM_NAME' | translate }} - {{ 'OPERATION_INPUT_VALUE' | translate }} - ●●● -
    -
    -
    {{ 'OPERATION_INPUT_EMPTY' | translate }}
    -
    - - +
    + +
    -
    diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less index 955720c49d..cb47c8d167 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less @@ -28,10 +28,9 @@ padding-bottom: 20px; .group-with-border { - margin: 25px 0; - padding: 15px 0; + margin: 10px 0; + padding: 10px 0; border-top: 1px solid @tlv_color_u; - border-bottom: 1px solid @tlv_color_u; .content-row:not(:last-of-type) { padding-bottom: 13px; } @@ -148,6 +147,14 @@ } } + .input-param-component { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 14px; + } + .generic-table { max-height: 244px; min-height: 91px; diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts index 1099391548..ed295e867c 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts @@ -19,13 +19,9 @@ * ============LICENSE_END========================================================= */ -import {Component, EventEmitter, Output} from '@angular/core'; +import {Component, EventEmitter, Input, Output} from '@angular/core'; import {UIInterfaceModel} from "../interface-operations.component"; -import { - InputOperationParameter, - InterfaceOperationModel, - IOperationParamsList -} from "../../../../../models/interfaceOperation"; +import {InputOperationParameter, InterfaceOperationModel, IOperationParamsList} from "../../../../../models/interfaceOperation"; import {TranslateService} from "../../../../shared/translator/translate.service"; import {IDropDownOption} from "onap-ui-angular/dist/form-elements/dropdown/dropdown-models"; import {DropdownValue} from "../../../../components/ui/form-components/dropdown/ui-element-dropdown.component"; @@ -33,6 +29,9 @@ import {ArtifactModel} from "../../../../../models/artifacts"; import {PropertyBEModel} from "../../../../../models/properties-inputs/property-be-model"; import {PropertyParamRowComponent} from "./property-param-row/property-param-row.component"; import {PropertyFEModel} from "../../../../../models/properties-inputs/property-fe-model"; +import {DataTypeService} from "../../../../services/data-type.service"; +import {Observable} from "rxjs/Observable"; +import {DataTypeModel} from "../../../../../models/data-types"; @Component({ selector: 'operation-handler', @@ -40,10 +39,10 @@ import {PropertyFEModel} from "../../../../../models/properties-inputs/property- styleUrls: ['./interface-operation-handler.component.less'], providers: [TranslateService] }) - export class InterfaceOperationHandlerComponent { - @Output('propertyChanged') emitter: EventEmitter = new EventEmitter(); + @Input() private modelName: string; + @Output('propertyChanged') emitter: EventEmitter = new EventEmitter(); input: { toscaArtifactTypes: Array; selectedInterface: UIInterfaceModel; @@ -52,6 +51,8 @@ export class InterfaceOperationHandlerComponent { isViewOnly: boolean; }; + dataTypeMap$: Observable>; + dataTypeMap: Map; interfaceType: string; artifactVersion: string; artifactName: string; @@ -70,23 +71,40 @@ export class InterfaceOperationHandlerComponent { enableAddArtifactImplementation: boolean; propertyValueValid: boolean = true; + inputTypeOptions: any[]; + + constructor(private dataTypeService: DataTypeService) { + this.dataTypeMap$ = new Observable>(subscriber => { + this.dataTypeService.findAllDataTypesByModel(this.modelName) + .then((dataTypesMap: Map) => { + subscriber.next(dataTypesMap); + }); + }); + this.dataTypeMap$.subscribe(value => { + this.dataTypeMap = value; + }); + + } ngOnInit() { this.isViewOnly = this.input.isViewOnly; this.interfaceType = this.input.selectedInterface.displayType(); - this.operationToUpdate = new InterfaceOperationModel(this.input.selectedInterfaceOperation); + this.operationToUpdate = this.input.selectedInterfaceOperation; this.operationToUpdate.interfaceId = this.input.selectedInterface.uniqueId; this.operationToUpdate.interfaceType = this.input.selectedInterface.type; + this.initInputs(); + this.removeImplementationQuote(); + this.validityChanged(); + this.loadInterfaceOperationImplementation(); + } + + private initInputs() { if (!this.operationToUpdate.inputs) { this.operationToUpdate.inputs = new class implements IOperationParamsList { listToscaDataDefinition: Array = []; } } - - this.inputs = this.operationToUpdate.inputs.listToscaDataDefinition; - this.removeImplementationQuote(); - this.validityChanged(); - this.loadInterfaceOperationImplementation(); + this.inputs = Array.from(this.operationToUpdate.inputs.listToscaDataDefinition); } private loadInterfaceOperationImplementation() { @@ -160,11 +178,8 @@ export class InterfaceOperationHandlerComponent { } } - onAddInput(inputOperationParameter?: InputOperationParameter): void { - let newInput = new InputOperationParameter(inputOperationParameter) - newInput.type = "string"; - newInput.inputId = this.generateUniqueId(); - this.inputs.push(newInput); + onAddInput(inputOperationParameter: InputOperationParameter) { + this.addInput(inputOperationParameter); this.validityChanged(); } @@ -196,16 +211,6 @@ export class InterfaceOperationHandlerComponent { } } - private generateUniqueId = (): string => { - let result = ''; - const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - const charactersLength = characters.length; - for (let i = 0; i < 36; i++ ) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; - } - validityChanged = () => { let validState = this.checkFormValidForSubmit(); this.input.validityChangedCallback(validState); @@ -243,7 +248,7 @@ export class InterfaceOperationHandlerComponent { } private isParamsValid = (): boolean => { - const isInputValid = (input) => input.name && input.inputId; + const isInputValid = (input) => input.name && input.inputId && input.type; const isValid = this.inputs.every(isInputValid); if (!isValid) { this.readonly = true; @@ -255,4 +260,48 @@ export class InterfaceOperationHandlerComponent { return { value : val, label: val }; } + /** + * Handles the input value change event. + * @param changedInput the changed input + */ + onInputValueChange(changedInput: InputOperationParameter) { + if (changedInput.value instanceof Object) { + changedInput.value = JSON.stringify(changedInput.value); + } + const inputOperationParameter = this.inputs.find(value => value.name == changedInput.name); + inputOperationParameter.value = changedInput.value; + } + + /** + * Handles the add input event. + * @param input the input to add + * @private + */ + private addInput(input: InputOperationParameter) { + this.operationToUpdate.inputs.listToscaDataDefinition.push(input); + this.inputs = Array.from(this.operationToUpdate.inputs.listToscaDataDefinition); + } + + /** + * Return a list with current input names. + */ + collectInputNames() { + return this.inputs.map((input) => input.name); + } + + /** + * Handles the delete input event. + * @param inputName the name of the input to be deleted + */ + onInputDelete(inputName: string) { + const currentInputs = this.operationToUpdate.inputs.listToscaDataDefinition; + const input1 = currentInputs.find(value => value.name === inputName); + const indexOfInput = currentInputs.indexOf(input1); + if (indexOfInput === -1) { + console.error(`Could delete input '${inputName}'. Input not found.`); + return; + } + currentInputs.splice(currentInputs.indexOf(input1), 1); + this.inputs = Array.from(currentInputs); + } } diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts index 259530105c..b212eec034 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts @@ -22,22 +22,27 @@ import {NgModule} from "@angular/core"; import {CommonModule} from "@angular/common"; -import {FormsModule} from "@angular/forms"; +import {FormsModule, ReactiveFormsModule} from "@angular/forms"; import {FormElementsModule} from "app/ng2/components/ui/form-components/form-elements.module"; import {TranslateModule} from "app/ng2/shared/translator/translate.module"; -import {SdcUiComponentsModule} from 'onap-ui-angular'; -import {UiElementsModule} from '../../../../components/ui/ui-elements.module'; -import {InputParamRowComponent} from './input-param-row/input-param-row.component'; -import {InterfaceOperationHandlerComponent} from "./interface-operation-handler.component"; -import {PropertyParamRowComponent} from "./property-param-row/property-param-row.component"; -import {PropertyTableModule} from "../../../../components/logic/properties-table/property-table.module"; + +import {SdcUiComponentsModule} from "onap-ui-angular/dist"; +import { InterfaceOperationHandlerComponent } from "app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component"; +import { PropertyParamRowComponent } from "app/ng2/pages/composition/interface-operatons/operation-creator/property-param-row/property-param-row.component"; +import { UiElementsModule } from "app/ng2/components/ui/ui-elements.module"; +import { PropertyTableModule } from "app/ng2/components/logic/properties-table/property-table.module"; +import { AddInputComponent } from './add-input/add-input.component'; +import { InputListComponent } from './input-list/input-list.component'; +import { InputListItemComponent } from './input-list/input-list-item/input-list-item.component'; @NgModule({ declarations: [ InterfaceOperationHandlerComponent, - InputParamRowComponent, - PropertyParamRowComponent + PropertyParamRowComponent, + AddInputComponent, + InputListComponent, + InputListItemComponent ], imports: [ CommonModule, @@ -46,7 +51,8 @@ import {PropertyTableModule} from "../../../../components/logic/properties-table FormElementsModule, TranslateModule, UiElementsModule, - PropertyTableModule + PropertyTableModule, + ReactiveFormsModule ], exports: [ PropertyParamRowComponent diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tab.component.ts index c148a4e579..df8f46d784 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tab.component.ts +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tab.component.ts @@ -1,13 +1,21 @@ -import { NgModule, Component, Compiler, ViewContainerRef, ViewChild, Input, ComponentRef, ComponentFactoryResolver, ChangeDetectorRef } from '@angular/core'; -import {Component as TopologyTemplate} from "app/models"; -import { SdcUiServices } from "onap-ui-angular"; +import { + Component, + ViewContainerRef, + ViewChild, + Input, + ComponentRef, + ComponentFactoryResolver, + ChangeDetectorRef, + OnChanges, OnDestroy, AfterViewInit +} from '@angular/core'; +import {Component as TopologyTemplate} from 'app/models'; // Helper component to add dynamic tabs @Component({ selector: 'panel-tab', template: `
    ` }) -export class PanelTabComponent { +export class PanelTabComponent implements OnChanges, OnDestroy, AfterViewInit { @ViewChild('content', { read: ViewContainerRef }) content; @Input() isActive:boolean; @Input() panelTabType; diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/property-creator/property-creator.module.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/property-creator/property-creator.module.ts index 1cbb4e17ec..6690410653 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/property-creator/property-creator.module.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/property-creator/property-creator.module.ts @@ -1,27 +1,30 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { FormElementsModule } from 'app/ng2/components/ui/form-components/form-elements.module'; -import { UiElementsModule } from 'app/ng2/components/ui/ui-elements.module'; -import { TranslateModule } from '../../../shared/translator/translate.module'; -import { PropertyCreatorComponent } from './property-creator.component'; +import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import {FormElementsModule} from 'app/ng2/components/ui/form-components/form-elements.module'; +import {UiElementsModule} from 'app/ng2/components/ui/ui-elements.module'; +import {TranslateModule} from '../../../shared/translator/translate.module'; +import {PropertyCreatorComponent} from './property-creator.component'; +import {SdcUiComponentsModule} from "onap-ui-angular/dist"; @NgModule({ - declarations: [ - PropertyCreatorComponent, - ], - imports: [ - CommonModule, - FormsModule, - FormElementsModule, - UiElementsModule, - TranslateModule - ], - exports: [], - entryComponents: [ - PropertyCreatorComponent - ], - providers: [] + declarations: [ + PropertyCreatorComponent, + ], + imports: [ + CommonModule, + FormsModule, + SdcUiComponentsModule, + FormElementsModule, + UiElementsModule, + TranslateModule + ], + exports: [], + entryComponents: [ + PropertyCreatorComponent + ], + providers: [] }) -export class PropertyCreatorModule {} +export class PropertyCreatorModule { +} diff --git a/catalog-ui/src/app/ng2/services/data-type.service.ts b/catalog-ui/src/app/ng2/services/data-type.service.ts index 5b08e9323f..70555a5efd 100644 --- a/catalog-ui/src/app/ng2/services/data-type.service.ts +++ b/catalog-ui/src/app/ng2/services/data-type.service.ts @@ -60,6 +60,10 @@ export class DataTypeService { return this.dataTypeService.getAllDataTypesFromModel(modelName); } + public findAllDataTypesByModel(modelName: string): Promise> { + return this.dataTypeService.findAllDataTypesByModel(modelName); + } + public getConstraintsByParentTypeAndUniqueID(rootPropertyType, propertyName){ // const property = this.dataTypes[rootPropertyType].properties.filter(property => // property.name == propertyName); diff --git a/catalog-ui/src/app/services/data-types-service.ts b/catalog-ui/src/app/services/data-types-service.ts index 08b49ae422..1a0fc47aae 100644 --- a/catalog-ui/src/app/services/data-types-service.ts +++ b/catalog-ui/src/app/services/data-types-service.ts @@ -27,7 +27,7 @@ import { PropertyModel, InputPropertyBase, IAppConfigurtaion, - SchemaProperty + SchemaProperty, DataTypeModel } from "../models"; import {PROPERTY_DATA} from "../utils/constants"; @@ -40,7 +40,8 @@ export interface IDataTypesService { selectedInstance:ComponentInstance; selectedComponentInputs:Array; //declare methods - fetchDataTypesByModel(modelName:string):void; + loadDataTypesCache(modelName:string):void; + findAllDataTypesByModel(modelName: string): void; getAllDataTypes():DataTypesMap; getFirsLevelOfDataTypeProperties(dataTypeName:string):Array; isDataTypeForSchemaType(property:SchemaProperty):boolean; @@ -70,7 +71,7 @@ export class DataTypesService implements IDataTypesService { selectedInstance:ComponentInstance; selectedComponentInputs:Array; - public fetchDataTypesByModel = (modelName: string):void => { + public loadDataTypesCache = (modelName: string): void => { let model; if (modelName) { model = {'model': modelName} @@ -82,11 +83,35 @@ export class DataTypesService implements IDataTypesService { }); }; + public fetchDataTypesByModel = (modelName: string): angular.IHttpPromise => { + let model; + if (modelName) { + model = {'model': modelName} + } + return this.$http.get(this.baseUrl + "dataTypes", {params: model}); + }; + public getAllDataTypesFromModel = (modelName: string): DataTypesMap => { - this.fetchDataTypesByModel(modelName); + this.loadDataTypesCache(modelName); return this.dataTypes; } + public findAllDataTypesByModel = (modelName: string): Promise> => { + return new Promise>((resolve, reject) => { + this.fetchDataTypesByModel(modelName).then(response => { + const dataTypes = response.data; + delete dataTypes[PROPERTY_DATA.ROOT_DATA_TYPE]; + const dataTypeMap = new Map(); + for(const dataTypeKey of Object.keys(dataTypes)) { + dataTypeMap.set(dataTypeKey, new DataTypeModel(dataTypes[dataTypeKey])) + } + resolve(dataTypeMap); + }).catch(reason => { + reject(reason); + }); + }); + } + public getAllDataTypes = ():DataTypesMap => { return this.dataTypes; }; -- cgit 1.2.3-korg