2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021 Nordix Foundation
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 * SPDX-License-Identifier: Apache-2.0
17 * ============LICENSE_END=========================================================
20 import {Component, Input, OnInit} from '@angular/core';
21 import {ComponentMetadata, DataTypeModel, PropertyBEModel, PropertyModel} from 'app/models';
22 import {TopologyTemplateService} from "../../../services/component-services/topology-template.service";
23 import {WorkspaceService} from "../../workspace/workspace.service";
24 import {PropertiesService} from "../../../services/properties.service";
25 import {PROPERTY_DATA} from "../../../../utils/constants";
26 import {DataTypeService} from "../../../services/data-type.service";
27 import {ToscaGetFunctionType} from "../../../../models/tosca-get-function-type";
28 import {TranslateService} from "../../../shared/translator/translate.service";
29 import {ComponentGenericResponse} from '../../../services/responses/component-generic-response';
30 import {Observable} from 'rxjs/Observable';
31 import {PropertySource} from "../../../../models/property-source";
32 import {InstanceFeDetails} from "../../../../models/instance-fe-details";
33 import {ToscaGetFunction} from "../../../../models/tosca-get-function";
36 selector: 'tosca-function',
37 templateUrl: './tosca-function.component.html',
38 styleUrls: ['./tosca-function.component.less'],
40 export class ToscaFunctionComponent implements OnInit {
42 @Input() property: PropertyBEModel;
43 @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
44 @Input() allowClear: boolean = true;
46 TOSCA_FUNCTION_GET_PROPERTY = ToscaGetFunctionType.GET_PROPERTY;
48 selectedProperty: PropertyDropdownValue;
49 isLoading: boolean = false;
50 propertyDropdownList: Array<PropertyDropdownValue> = [];
51 toscaFunctions: Array<string> = [];
52 propertySourceList: Array<string> = [];
53 instanceNameAndIdMap: Map<string, string> = new Map<string, string>();
54 dropdownValuesLabel: string;
55 dropDownErrorMsg: string;
56 propertySource: string
57 toscaGetFunction: ToscaGetFunction = new ToscaGetFunction(undefined);
59 private componentMetadata: ComponentMetadata;
61 constructor(private topologyTemplateService: TopologyTemplateService,
62 private workspaceService: WorkspaceService,
63 private propertiesService: PropertiesService,
64 private dataTypeService: DataTypeService,
65 private translateService: TranslateService) {
69 this.componentMetadata = this.workspaceService.metadata;
70 this.loadToscaFunctions();
71 this.loadPropertySourceDropdown();
72 this.initToscaGetFunction();
75 private initToscaGetFunction(): void {
76 if (!this.property.isToscaGetFunction()) {
79 this.toscaGetFunction = new ToscaGetFunction(this.property.toscaGetFunction);
80 if (this.toscaGetFunction.functionType === ToscaGetFunctionType.GET_PROPERTY) {
81 if (this.toscaGetFunction.propertySource === PropertySource.SELF) {
82 this.propertySource = PropertySource.SELF;
84 this.propertySource = this.toscaGetFunction.sourceName;
87 if (this.toscaGetFunction.propertyName) {
88 this.loadPropertyDropdown(() => {
89 this.selectedProperty = this.propertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.propertyName)
95 private loadToscaFunctions(): void {
96 this.toscaFunctions.push(ToscaGetFunctionType.GET_INPUT);
97 this.toscaFunctions.push(ToscaGetFunctionType.GET_PROPERTY);
100 private loadPropertySourceDropdown(): void {
101 this.propertySourceList.push(PropertySource.SELF);
102 this.componentInstanceMap.forEach((value, key) => {
103 const instanceName = value.name;
104 this.instanceNameAndIdMap.set(instanceName, key);
105 if (instanceName !== PropertySource.SELF) {
106 this.addToPropertySource(instanceName);
111 private addToPropertySource(source: string): void {
112 this.propertySourceList.push(source);
113 this.propertySourceList.sort((a, b) => {
114 if (a === PropertySource.SELF) {
116 } else if (b === PropertySource.SELF) {
120 return a.localeCompare(b);
124 onToscaFunctionChange(): void {
125 this.resetPropertySource();
126 if (this.isGetInputSelected()) {
127 this.setSelfPropertySource();
128 this.loadPropertyDropdown();
132 private loadPropertyDropdown(onComplete: () => any = () => {}): void {
133 this.loadPropertyDropdownLabel();
134 this.loadPropertyDropdownValues(onComplete);
137 private resetForm(): void {
138 this.toscaGetFunction = new ToscaGetFunction(undefined);
139 this.propertySource = undefined;
140 this.selectedProperty = undefined;
143 private resetPropertySource(): void {
144 this.toscaGetFunction.propertyUniqueId = undefined;
145 this.toscaGetFunction.propertyName = undefined;
146 this.toscaGetFunction.propertySource = undefined;
147 this.toscaGetFunction.sourceUniqueId = undefined;
148 this.toscaGetFunction.sourceName = undefined;
149 this.toscaGetFunction.propertyPathFromSource = undefined;
150 this.propertySource = undefined;
151 this.selectedProperty = undefined;
154 private loadPropertyDropdownLabel(): void {
155 if (!this.toscaGetFunction.functionType) {
158 if (this.isGetInputSelected()) {
159 this.dropdownValuesLabel = this.translateService.translate('INPUT_DROPDOWN_LABEL');
160 } else if (this.isGetPropertySelected()) {
161 this.dropdownValuesLabel = this.translateService.translate('TOSCA_FUNCTION_PROPERTY_DROPDOWN_LABEL');
165 private loadPropertyDropdownValues(onComplete: () => any = () => {}): void {
166 if (!this.toscaGetFunction.functionType) {
169 this.resetPropertyDropdown();
170 this.fillPropertyDropdownValues(onComplete);
173 private resetPropertyDropdown(): void {
174 this.dropDownErrorMsg = undefined;
175 this.selectedProperty = undefined;
176 this.propertyDropdownList = [];
179 private fillPropertyDropdownValues(onComplete: () => any = () => {}): void {
181 const propertiesObservable: Observable<ComponentGenericResponse> = this.getPropertyObservable();
182 propertiesObservable.subscribe( (response: ComponentGenericResponse) => {
183 const properties: PropertyBEModel[] = this.extractProperties(response);
184 if (!properties || properties.length === 0) {
185 const msgCode = this.isGetInputSelected() ? 'TOSCA_FUNCTION_NO_INPUT_FOUND' : 'TOSCA_FUNCTION_NO_PROPERTY_FOUND';
186 this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.property.type});
189 this.addPropertiesToDropdown(properties);
190 if (this.propertyDropdownList.length == 0) {
191 const msgCode = this.isGetInputSelected() ? 'TOSCA_FUNCTION_NO_INPUT_FOUND' : 'TOSCA_FUNCTION_NO_PROPERTY_FOUND';
192 this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.property.type});
195 console.error('An error occurred while loading properties.', error);
202 private extractProperties(componentGenericResponse: ComponentGenericResponse): PropertyBEModel[] {
203 if (this.isGetInputSelected()) {
204 return componentGenericResponse.inputs;
206 if (this.isGetPropertySelected()) {
207 if (this.propertySource === PropertySource.SELF) {
208 return componentGenericResponse.properties;
210 const componentInstanceProperties: PropertyModel[] = componentGenericResponse.componentInstancesProperties[this.instanceNameAndIdMap.get(this.propertySource)];
211 return this.removeSelectedProperty(componentInstanceProperties);
215 private getPropertyObservable(): Observable<ComponentGenericResponse> {
216 if (this.isGetInputSelected()) {
217 return this.topologyTemplateService.getComponentInputsValues(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
219 if (this.isGetPropertySelected()) {
220 if (this.propertySource === PropertySource.SELF) {
221 return this.topologyTemplateService.findAllComponentProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
223 return this.topologyTemplateService.getComponentInstanceProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
227 private removeSelectedProperty(componentInstanceProperties: PropertyModel[]): PropertyModel[] {
228 if (!componentInstanceProperties) {
231 return componentInstanceProperties.filter(property =>
232 (property.uniqueId !== this.property.uniqueId) ||
233 (property.uniqueId === this.property.uniqueId && property.resourceInstanceUniqueId !== this.property.parentUniqueId)
237 private addPropertyToDropdown(propertyDropdownValue: PropertyDropdownValue): void {
238 this.propertyDropdownList.push(propertyDropdownValue);
239 this.propertyDropdownList.sort((a, b) => a.propertyLabel.localeCompare(b.propertyLabel));
242 private addPropertiesToDropdown(properties: PropertyBEModel[]): void {
243 for (const property of properties) {
244 if (this.property.type === property.type) {
245 this.addPropertyToDropdown({
246 propertyName: property.name,
247 propertyId: property.uniqueId,
248 propertyLabel: property.name,
249 propertyPath: [property.name]
251 } else if (this.isComplexType(property.type)) {
252 this.fillPropertyDropdownWithMatchingChildProperties(property);
257 private fillPropertyDropdownWithMatchingChildProperties(inputProperty: PropertyBEModel, parentPropertyList: Array<PropertyBEModel> = []): void {
258 const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, inputProperty.type);
259 if (!dataTypeFound || !dataTypeFound.properties) {
262 parentPropertyList.push(inputProperty);
263 dataTypeFound.properties.forEach(dataTypeProperty => {
264 if (dataTypeProperty.type === this.property.type) {
265 this.addPropertyToDropdown({
266 propertyName: dataTypeProperty.name,
267 propertyId: parentPropertyList[0].uniqueId,
268 propertyLabel: parentPropertyList.map(property => property.name).join('->') + '->' + dataTypeProperty.name,
269 propertyPath: [...parentPropertyList.map(property => property.name), dataTypeProperty.name]
271 } else if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(dataTypeProperty.type) === -1) {
272 this.fillPropertyDropdownWithMatchingChildProperties(dataTypeProperty, [...parentPropertyList])
277 private isGetPropertySelected(): boolean {
278 return this.toscaGetFunction.functionType === ToscaGetFunctionType.GET_PROPERTY;
281 private isGetInputSelected(): boolean {
282 return this.toscaGetFunction.functionType === ToscaGetFunctionType.GET_INPUT;
285 private isComplexType(propertyType: string): boolean {
286 return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
289 private stopLoading(): void {
290 this.isLoading = false;
293 private startLoading(): void {
294 this.isLoading = true;
297 showDropdown(): boolean {
298 if (this.toscaGetFunction.functionType === ToscaGetFunctionType.GET_PROPERTY) {
299 return this.toscaGetFunction.propertySource && !this.isLoading && !this.dropDownErrorMsg;
302 return this.toscaGetFunction.functionType && !this.isLoading && !this.dropDownErrorMsg;
305 onPropertySourceChange(): void {
306 if (!this.toscaGetFunction.functionType || !this.propertySource) {
309 this.toscaGetFunction.propertyUniqueId = undefined;
310 this.toscaGetFunction.propertyName = undefined;
311 this.toscaGetFunction.propertyPathFromSource = undefined;
312 if (this.propertySource === PropertySource.SELF) {
313 this.setSelfPropertySource();
315 this.toscaGetFunction.propertySource = PropertySource.INSTANCE;
316 this.toscaGetFunction.sourceName = this.propertySource;
317 this.toscaGetFunction.sourceUniqueId = this.instanceNameAndIdMap.get(this.propertySource);
319 this.loadPropertyDropdown();
322 private setSelfPropertySource(): void {
323 this.toscaGetFunction.propertySource = PropertySource.SELF;
324 this.toscaGetFunction.sourceName = this.componentMetadata.name;
325 this.toscaGetFunction.sourceUniqueId = this.componentMetadata.uniqueId;
328 onPropertyChange(): void {
329 this.toscaGetFunction.propertyUniqueId = this.selectedProperty.propertyId;
330 this.toscaGetFunction.propertyName = this.selectedProperty.propertyName;
331 this.toscaGetFunction.propertyPathFromSource = this.selectedProperty.propertyPath;
338 showClearButton(): boolean {
339 return this.allowClear && this.toscaGetFunction.functionType !== undefined;
343 export interface PropertyDropdownValue {
344 propertyName: string;
346 propertyLabel: string;
347 propertyPath: Array<string>;