dc16a12d3eda3dc4a7f6abdaeea3f6797cce840e
[sdc.git] / catalog-ui / src / app / ng2 / pages / composition / panel / panel-tabs / properties-tab / properties-tab.component.ts
1 import { Component, Input, OnInit } from '@angular/core';
2 import { Store } from '@ngxs/store';
3 import {
4     AttributeModel,
5     AttributesGroup,
6     Component as TopologyTemplate,
7     ComponentInstance,
8     ComponentMetadata,
9     FullComponentInstance,
10     PropertiesGroup,
11     PropertyModel,
12     InputsGroup,
13     InputModel
14 } from 'app/models';
15 import {ToscaGetFunctionType} from "app/models/tosca-get-function-type.enum";
16 import { CompositionService } from 'app/ng2/pages/composition/composition.service';
17 import { WorkspaceService } from 'app/ng2/pages/workspace/workspace.service';
18 import { GroupByPipe } from 'app/ng2/pipes/groupBy.pipe';
19 import { ResourceNamePipe } from 'app/ng2/pipes/resource-name.pipe';
20 import { TopologyTemplateService } from 'app/ng2/services/component-services/topology-template.service';
21 import { ComponentInstanceServiceNg2 } from "app/ng2/services/component-instance-services/component-instance.service";
22 import { DropdownValue } from 'app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component';
23 import { ComponentGenericResponse } from 'app/ng2/services/responses/component-generic-response';
24 import { TranslateService } from 'app/ng2/shared/translator/translate.service';
25 import { ModalsHandler } from 'app/utils';
26 import { SdcUiCommon, SdcUiComponents, SdcUiServices } from 'onap-ui-angular';
27 import {SelectedComponentType, TogglePanelLoadingAction} from "../../../common/store/graph.actions";
28
29 @Component({
30     selector: 'properties-tab',
31     templateUrl: './properties-tab.component.html',
32     styleUrls: ['./properties-tab.component.less']
33 })
34 export class PropertiesTabComponent implements OnInit {
35     attributes: AttributesGroup;
36     isComponentInstanceSelected: boolean;
37     properties: PropertiesGroup;
38     groupPropertiesByInstance: boolean;
39     propertiesMessage: string;
40     metadata: ComponentMetadata;
41     objectKeys = Object.keys;
42     isUnboundedChecked: boolean;
43     isOccurrencesEnabled: boolean = false;
44     inputs: InputsGroup;
45     selectInputs: DropdownValue[] = [];
46     isLoading: boolean;
47
48     @Input() isViewOnly: boolean;
49     @Input() componentType: SelectedComponentType;
50     @Input() component: FullComponentInstance | TopologyTemplate;
51     @Input() input: {title: string};
52
53     constructor(private store: Store,
54                 private workspaceService: WorkspaceService,
55                 private compositionService: CompositionService,
56                 private modalsHandler: ModalsHandler,
57                 private topologyTemplateService: TopologyTemplateService,
58                 private componentInstanceService: ComponentInstanceServiceNg2,
59                 private modalService: SdcUiServices.ModalService,
60                 private translateService: TranslateService,
61                 private groupByPipe: GroupByPipe) {
62     }
63
64     ngOnInit() {
65         this.metadata = this.workspaceService.metadata;
66         this.isComponentInstanceSelected = this.componentType === SelectedComponentType.COMPONENT_INSTANCE;
67         this.getComponentInstancesPropertiesAndAttributes();
68     }
69
70     public isPropertyOwner = (): boolean => {
71         return this.component instanceof TopologyTemplate && this.component.isResource();
72     }
73
74     public updateProperty = (property: PropertyModel): void => {
75         this.openEditPropertyModal(property);
76     }
77
78     public deleteProperty = (property: PropertyModel): void => {
79
80         const onOk: Function = (): void => {
81             this.store.dispatch(new TogglePanelLoadingAction({isLoading: true}));
82             this.topologyTemplateService.deleteProperty(this.component.componentType, this.component.uniqueId, property.uniqueId)
83                 .subscribe((response) => {
84                     this.store.dispatch(new TogglePanelLoadingAction({isLoading: false}));
85                     this.component.properties = this.component.properties.filter((prop) => prop.uniqueId !==  property.uniqueId);
86                     this.initComponentProperties();
87                 }, () => {
88                     this.store.dispatch(new TogglePanelLoadingAction({isLoading: false}));
89                 });
90         };
91
92         const title: string = this.translateService.translate('PROPERTY_VIEW_DELETE_MODAL_TITLE');
93         const message: string = this.translateService.translate('PROPERTY_VIEW_DELETE_MODAL_TEXT', {name: property.name});
94         const okButton = {
95             testId: 'OK',
96             text: 'OK',
97             type: SdcUiCommon.ButtonType.info,
98             callback: onOk,
99             closeModal: true} as SdcUiComponents.ModalButtonComponent;
100         this.modalService.openInfoModal(title, message, 'delete-modal', [okButton]);
101     }
102
103     public groupNameByKey = (key: string): string => {
104         switch (key) {
105             case 'derived':
106                 return 'Derived';
107
108             case this.metadata.uniqueId:
109                 return ResourceNamePipe.getDisplayName(this.metadata.name);
110
111             default:
112                 return this.getComponentInstanceNameFromInstanceByKey(key);
113         }
114     }
115
116     public getComponentInstanceNameFromInstanceByKey = (key: string): string => {
117         let instanceName: string = '';
118         const componentInstance = this.compositionService.getComponentInstances().find((item) => item.uniqueId === key);
119         if (key !== undefined && componentInstance) {
120
121             instanceName = ResourceNamePipe.getDisplayName(componentInstance.name);
122         }
123         return instanceName;
124     }
125
126     private getComponentInstancesPropertiesAndAttributes = () => {
127         this.topologyTemplateService.getComponentInstanceAttributesAndPropertiesAndInputs(
128             this.workspaceService.metadata.uniqueId,
129             this.workspaceService.metadata.componentType)
130             .subscribe((genericResponse: ComponentGenericResponse) => {
131                 this.compositionService.componentInstancesAttributes = genericResponse.componentInstancesAttributes || new AttributesGroup();
132                 this.compositionService.componentInstancesProperties = genericResponse.componentInstancesProperties;
133                 this.inputs = genericResponse.inputs;
134                 this.initPropertiesAndAttributes();
135             });
136     }
137
138     private initComponentProperties = (): void => {
139         let result: PropertiesGroup = {};
140
141         this.propertiesMessage = undefined;
142         this.groupPropertiesByInstance = false;
143         if (this.component instanceof FullComponentInstance) {
144             result[this.component.uniqueId] = _.orderBy(this.compositionService.componentInstancesProperties[this.component.uniqueId], ['name']);
145             if (this.component.originType === 'VF') {
146                 this.groupPropertiesByInstance = true;
147                 result[this.component.uniqueId] = Array.from(this.groupByPipe.transform(result[this.component.uniqueId], 'path'));
148             }
149         } else if (this.metadata.isService()) {
150             // Temporally fix to hide properties for service (UI stack when there are many properties)
151             result = this.compositionService.componentInstancesProperties;
152             this.propertiesMessage = 'Note: properties for service are disabled';
153         } else {
154             const componentUid = this.component.uniqueId;
155             result[componentUid] = Array<PropertyModel>();
156             const derived = Array<PropertyModel>();
157             _.forEach(this.component.properties, (property: PropertyModel) => {
158                 if (componentUid === property.parentUniqueId) {
159                     result[componentUid].push(property);
160                 } else {
161                     property.readonly = true;
162                     derived.push(property);
163                 }
164             });
165             if (derived.length) {
166                 result['derived'] = derived;
167             }
168             this.objectKeys(result).forEach((key) => { result[key] =  _.orderBy(result[key], ['name']); });
169         }
170         this.properties = result;
171     }
172
173     private initComponentAttributes = (): void => {
174         let result: AttributesGroup = {};
175
176         if (this.component) {
177             if (this.component instanceof FullComponentInstance) {
178                 result[this.component.uniqueId] = this.compositionService.componentInstancesAttributes[this.component.uniqueId] || [];
179             } else if (this.metadata.isService()) {
180                 result = this.compositionService.componentInstancesAttributes;
181             } else {
182                 result[this.component.uniqueId] = (this.component as TopologyTemplate).attributes;
183             }
184             this.attributes = result;
185             this.objectKeys(this.attributes).forEach((key) => {
186                 this.attributes[key] =  _.orderBy(this.attributes[key], ['name']);
187             });
188
189         }
190     }
191
192     private initComponentOccurrences = (): void => {
193         if (this.component instanceof FullComponentInstance) {
194             if(this.component.minOccurrences != null && this.component.maxOccurrences != null){
195                 this.isOccurrencesEnabled = true;
196             }
197             this.isUnboundedChecked = this.component.maxOccurrences == "UNBOUNDED" ? true: false;
198
199             if(!this.component.instanceCount){
200                 this.component.instanceCount = "";
201             }
202
203             _.forEach(this.inputs, (input: InputModel) => {
204                 if(input.type === "integer"){
205                     this.selectInputs.push(new DropdownValue('{' + ToscaGetFunctionType.GET_INPUT.toLowerCase() + ":" + input.name + '}', input.name));
206                 }
207             });
208
209             this.selectInputs.unshift(new DropdownValue('', 'Select Input...'));
210         }
211     }
212
213     /**
214      * This function is checking if the component is the value owner of the current property
215      * in order to notify the edit property modal which fields to disable
216      */
217     private isPropertyValueOwner = (): boolean => {
218         return this.metadata.isService() || !!this.component;
219     }
220
221     /**
222      *  The function opens the edit property modal.
223      *  It checks if the property is from the VF or from one of it's resource instances and sends the needed property list.
224      *  For create property reasons an empty array is transferd
225      *
226      * @param property the wanted property to edit/create
227      */
228     private openEditPropertyModal = (property: PropertyModel): void => {
229         this.modalsHandler.newOpenEditPropertyModal(property,
230             (this.isPropertyOwner() ?
231                 this.properties[property.parentUniqueId] :
232                 this.properties[property.resourceInstanceUniqueId]) || [],
233             this.isPropertyValueOwner(), 'component', property.resourceInstanceUniqueId).then((updatedProperty: PropertyModel) => {
234                 if (updatedProperty) {
235                     const oldProp = _.find(this.properties[updatedProperty.resourceInstanceUniqueId],
236                                  (prop: PropertyModel) => prop.uniqueId === updatedProperty.uniqueId);
237                     oldProp.value = updatedProperty.value;
238                 }
239         });
240     }
241
242     private initPropertiesAndAttributes = (): void => {
243         this.initComponentProperties();
244         this.initComponentAttributes();
245         this.initComponentOccurrences();
246     }
247
248     onUnboundedChanged(component: ComponentInstance) {
249         this.isUnboundedChecked = !this.isUnboundedChecked;
250         component.maxOccurrences = this.isUnboundedChecked ? "UNBOUNDED" : "1";
251     }
252
253     private updateComponentInstance(component: ComponentInstance) {
254         this.store.dispatch(new TogglePanelLoadingAction({isLoading: true}));
255
256         this.componentInstanceService.updateComponentInstance(this.workspaceService.metadata.componentType,
257                                                               this.workspaceService.metadata.uniqueId, component)
258                                                               .subscribe((updatedComponentInstance: ComponentInstance) => {
259             component = new ComponentInstance(updatedComponentInstance);
260             this.compositionService.getComponentInstances().find((item) => item.uniqueId === component.uniqueId).maxOccurrences = component.maxOccurrences;
261             this.compositionService.getComponentInstances().find((item) => item.uniqueId === component.uniqueId).minOccurrences = component.minOccurrences;
262             this.compositionService.getComponentInstances().find((item) => item.uniqueId === component.uniqueId).instanceCount = component.instanceCount;
263             this.store.dispatch(new TogglePanelLoadingAction({isLoading: false}));
264         }, (error:any) => {
265             this.store.dispatch(new TogglePanelLoadingAction({isLoading: false}));
266             if (error) {
267                 console.log(error);
268             }});
269     }
270
271     private enableOccurrences = () => {
272         if(this.component instanceof FullComponentInstance){
273             if(!this.isOccurrencesEnabled){
274                 this.component.minOccurrences = null;
275                 this.component.maxOccurrences = null;
276                 this.component.instanceCount = null;
277             } else {
278                 this.component.minOccurrences = "1";
279                 this.component.maxOccurrences = "1";
280                 this.component.instanceCount = "";
281             }
282         }
283     }
284
285     private isOccurrencesFormValid(component: FullComponentInstance) {
286         if(
287             (component.minOccurrences === null && component.maxOccurrences === null && !component.instanceCount) ||
288             (component.minOccurrences && parseInt(component.minOccurrences) >= 0 && component.maxOccurrences &&
289             (parseInt(component.maxOccurrences) >= parseInt(component.minOccurrences) || component.maxOccurrences === "UNBOUNDED") &&
290             component.instanceCount)
291         ) {
292             return true;
293         } else {
294             return false;
295         }
296     }
297
298     private saveOccurrences = () => {
299         if(this.component instanceof FullComponentInstance && this.isOccurrencesFormValid(this.component)) {
300             this.updateComponentInstance(this.component);
301         }
302     }
303 }