cdb1cd84e5aaab980bc5fdab8880eb5a521e1f9c
[sdc.git] / catalog-ui / src / app / ng2 / components / logic / service-dependencies / service-dependencies.component.ts
1 /*!
2  * Copyright © 2016-2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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
13  * or implied. See the License for the specific language governing
14  * permissions and limitations under the License.
15  */
16 import {Component, ComponentRef, EventEmitter, Input, Output} from '@angular/core';
17 import {
18     ButtonModel,
19     ComponentInstance,
20     InputBEModel,
21     ModalModel,
22     PropertyBEModel,
23     PropertyModel,
24 } from 'app/models';
25 import { ModalComponent } from 'app/ng2/components/ui/modal/modal.component';
26 import { ServiceDependenciesEditorComponent } from 'app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component';
27 import { ModalService } from 'app/ng2/services/modal.service';
28 import { ComponentGenericResponse } from 'app/ng2/services/responses/component-generic-response';
29 import { TranslateService } from 'app/ng2/shared/translator/translate.service';
30 import { ComponentMetadata } from '../../../../models/component-metadata';
31 import { ServiceInstanceObject } from '../../../../models/service-instance-properties-and-interfaces';
32 import { TopologyTemplateService } from '../../../services/component-services/topology-template.service';
33 import {CapabilitiesFilterPropertiesEditorComponent} from "../../../pages/composition/capabilities-filter-properties-editor/capabilities-filter-properties-editor.component";
34 import { CapabilitiesConstraintObjectUI} from "../capabilities-constraint/capabilities-constraint.component";
35 import {ToscaFilterConstraintType} from "../../../../models/tosca-filter-constraint-type.enum";
36
37 export class ConstraintObject {
38     servicePropertyName: string;
39     constraintOperator: string;
40     sourceType: string;
41     sourceName: string;
42     value: string;
43
44     constructor(input?: any) {
45         if (input) {
46             this.servicePropertyName = input.servicePropertyName;
47             this.constraintOperator = input.constraintOperator;
48             this.sourceType = input.sourceType;
49             this.sourceName = input.sourceName;
50             this.value = input.value;
51         }
52     }
53 }
54
55 // tslint:disable-next-line:max-classes-per-file
56 export class ConstraintObjectUI extends ConstraintObject{
57     isValidValue: boolean;
58
59     constructor(input?: any) {
60         super(input);
61         if (input) {
62             this.isValidValue = input.isValidValue ? input.isValidValue : input.value !== '';
63         }
64     }
65
66     public updateValidity(isValidValue: boolean) {
67         this.isValidValue = isValidValue;
68     }
69
70     public isValidRule(isStatic) {
71         const isValidValue = isStatic ? this.isValidValue : true;
72         return this.servicePropertyName != null && this.servicePropertyName !== ''
73             && this.value != null && this.value !== '' && isValidValue;
74     }
75 }
76
77 export const OPERATOR_TYPES = {
78     EQUAL: 'equal',
79     GREATER_THAN: 'greater_than',
80     LESS_THAN: 'less_than'
81 };
82
83 // tslint:disable-next-line:max-classes-per-file
84 class I18nTexts {
85     static removeDirectiveModalTitle: string;
86     static removeDirectiveModalText: string;
87     static updateDirectiveModalTitle: string;
88     static updateDirectiveModalText: string;
89     static modalApprove: string;
90     static modalCancel: string;
91     static modalCreate: string;
92     static modalSave: string;
93     static modalDelete: string;
94     static addNodeFilterTxt: string;
95     static updateNodeFilterTxt: string;
96     static deleteNodeFilterTxt: string;
97     static deleteNodeFilterMsg: string;
98     static validateCapabilitiesTxt: string
99     static validateCapabilitiesMsg: string
100     static validateNodePropertiesTxt: string
101     static validateNodePropertiesMsg: string
102
103     public static translateTexts(translateService) {
104             I18nTexts.removeDirectiveModalTitle = translateService.translate('DIRECTIVES_AND_NODE_FILTER_REMOVE_TITLE');
105             I18nTexts.removeDirectiveModalText = translateService.translate('DIRECTIVES_AND_NODE_FILTER_REMOVE_TEXT');
106             I18nTexts.updateDirectiveModalTitle = translateService.translate('DIRECTIVES_AND_NODE_FILTER_UPDATE_TITLE');
107             I18nTexts.updateDirectiveModalText = translateService.translate('DIRECTIVES_AND_NODE_FILTER_UPDATE_TEXT');
108             I18nTexts.modalApprove = translateService.translate('MODAL_APPROVE');
109             I18nTexts.modalCancel = translateService.translate('MODAL_CANCEL');
110             I18nTexts.modalCreate = translateService.translate('MODAL_CREATE');
111             I18nTexts.modalSave = translateService.translate('MODAL_SAVE');
112             I18nTexts.modalDelete = translateService.translate('MODAL_DELETE');
113             I18nTexts.addNodeFilterTxt = translateService.translate('DIRECTIVES_AND_NODE_FILTER_ADD_NODE_FILTER');
114             I18nTexts.updateNodeFilterTxt = translateService.translate('DIRECTIVES_AND_NODE_FILTER_UPDATE_NODE_FILTER');
115             I18nTexts.deleteNodeFilterTxt = translateService.translate('DIRECTIVES_AND_NODE_FILTER_DELETE_NODE_FILTER');
116             I18nTexts.deleteNodeFilterMsg = translateService.translate('DIRECTIVES_AND_NODE_FILTER_DELETE_NODE_FILTER_MSG');
117             I18nTexts.validateCapabilitiesTxt = translateService.translate('VALIDATE_CAPABILITIES_TXT');
118             I18nTexts.validateCapabilitiesMsg = translateService.translate('VALIDATE_CAPABILITIES_MSG');
119             I18nTexts.validateNodePropertiesTxt = translateService.translate('VALIDATE_NODE_PROPERTIES_TXT');
120             I18nTexts.validateNodePropertiesMsg = translateService.translate('VALIDATE_NODE_PROPERTIES_MSG');
121     }
122 }
123
124 // tslint:disable-next-line:max-classes-per-file
125 @Component({
126     selector: 'service-dependencies',
127     templateUrl: './service-dependencies.component.html',
128     styleUrls: ['service-dependencies.component.less'],
129     providers: [ModalService, TranslateService]
130 })
131
132 export class ServiceDependenciesComponent {
133     modalInstance: ComponentRef<ModalComponent>;
134     isDependent: boolean;
135     isLoading: boolean;
136     parentServiceInputs: InputBEModel[] = [];
137     parentServiceProperties: PropertyBEModel[] = [];
138     constraintProperties: ConstraintObject[] = [];
139     constraintCapabilities: CapabilitiesConstraintObjectUI[] = [];
140     operatorTypes: any[];
141     capabilities: string = ToscaFilterConstraintType.CAPABILITIES;
142     properties: string = ToscaFilterConstraintType.PROPERTIES;
143     private componentInstancesConstraints: ConstraintObject[] = [];
144     isEditable: boolean;
145
146     @Input() readonly: boolean;
147     @Input() compositeService: ComponentMetadata;
148     @Input() currentServiceInstance: ComponentInstance;
149     @Input() selectedInstanceSiblings: ServiceInstanceObject[];
150     @Input() selectedInstanceConstraints: ConstraintObject[] = [];
151     @Input() selectedInstanceProperties: PropertyBEModel[] = [];
152     @Output() updateRulesListEvent: EventEmitter<ConstraintObject[]> = new EventEmitter<ConstraintObject[]>();
153     @Output() updateNodeFilterProperties: EventEmitter<ConstraintObject[]> = new EventEmitter<ConstraintObject[]>();
154     @Output() updateNodeFilterCapabilities: EventEmitter<CapabilitiesConstraintObjectUI[]> = new EventEmitter<CapabilitiesConstraintObjectUI[]>();
155     @Output() loadRulesListEvent:EventEmitter<any> = new EventEmitter();
156     @Output() dependencyStatus = new EventEmitter<boolean>();
157
158     @Input() componentInstanceCapabilitiesMap: Map<string, PropertyModel[]>;
159
160     constructor(private topologyTemplateService: TopologyTemplateService, private modalServiceNg2: ModalService, private translateService: TranslateService) {
161     }
162
163     ngOnInit() {
164         this.isLoading = false;
165         this.operatorTypes = [
166             {label: '>', value: OPERATOR_TYPES.GREATER_THAN},
167             {label: '<', value: OPERATOR_TYPES.LESS_THAN},
168             {label: '=', value: OPERATOR_TYPES.EQUAL}
169         ];
170         this.topologyTemplateService.getComponentInputsWithProperties(this.compositeService.componentType, this.compositeService.uniqueId)
171         .subscribe((result: ComponentGenericResponse) => {
172             this.parentServiceInputs = result.inputs;
173             this.parentServiceProperties = result.properties;
174         });
175         this.loadNodeFilter();
176         this.translateService.languageChangedObservable.subscribe((lang) => {
177             I18nTexts.translateTexts(this.translateService);
178         });
179     }
180
181     ngOnChanges(changes) {
182         if (changes.currentServiceInstance) {
183             this.currentServiceInstance = changes.currentServiceInstance.currentValue;
184             this.isDependent = this.currentServiceInstance.isDependent();
185         }
186         if (changes.selectedInstanceConstraints && changes.selectedInstanceConstraints.currentValue !== changes.selectedInstanceConstraints.previousValue) {
187             this.selectedInstanceConstraints = changes.selectedInstanceConstraints.currentValue;
188             this.loadNodeFilter();
189         }
190     }
191
192     private getActualDirectiveValue = (): string[] => {
193         return this.currentServiceInstance.directives.length > 0 ? this.currentServiceInstance.directives : [];
194     }
195
196     public openRemoveDependencyModal = (): ComponentRef<ModalComponent> => {
197         const actionButton: ButtonModel = new ButtonModel(I18nTexts.modalApprove, 'blue', this.onUncheckDependency);
198         const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'grey', this.onCloseRemoveDependencyModal);
199         const modalModel: ModalModel = new ModalModel('sm', I18nTexts.removeDirectiveModalTitle,
200             I18nTexts.removeDirectiveModalText, [actionButton, cancelButton]);
201         this.loadNodeFilter();
202         return this.modalServiceNg2.createCustomModal(modalModel);
203     }
204
205     public openUpdateDependencyModal = (): ComponentRef<ModalComponent> => {
206         const actionButton: ButtonModel = new ButtonModel(I18nTexts.modalApprove, 'blue', this.onUncheckDependency);
207         const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'grey', this.onCloseRemoveDependencyModal);
208         const modalModel: ModalModel = new ModalModel('sm', I18nTexts.updateDirectiveModalTitle,
209             I18nTexts.updateDirectiveModalText, [actionButton, cancelButton]);
210         return this.modalServiceNg2.createCustomModal(modalModel);
211     }
212
213     private loadNodeFilter = (): void => {
214         this.topologyTemplateService.getServiceFilterConstraints(this.compositeService.componentType, this.compositeService.uniqueId).subscribe((response) => {
215             if (response.nodeFilterforNode && response.nodeFilterforNode[this.currentServiceInstance.uniqueId]) {
216                 this.componentInstancesConstraints = response.nodeFilterforNode;
217                 const nodeFilterPropertiesResponse: ConstraintObject[] = response.nodeFilterforNode[this.currentServiceInstance.uniqueId].properties;
218                 this.constraintProperties = nodeFilterPropertiesResponse;
219                 const nodeFilterCapabilitiesResponse: CapabilitiesConstraintObjectUI[] = response.nodeFilterforNode[this.currentServiceInstance.uniqueId].capabilities;
220                 this.constraintCapabilities = nodeFilterCapabilitiesResponse;
221             }
222         });
223     }
224
225     onUncheckDependency = () => {
226         this.modalServiceNg2.closeCurrentModal();
227         this.isLoading = true;
228         const isDepOrig = this.isDependent;
229         const rulesListOrig = this.componentInstancesConstraints;
230         this.currentServiceInstance.unmarkAsDependent(this.getActualDirectiveValue());
231         this.updateComponentInstance(isDepOrig, rulesListOrig);
232     }
233
234     onCloseRemoveDependencyModal = () => {
235         this.isDependent = true;
236         this.modalServiceNg2.closeCurrentModal();
237     }
238
239     onAddDirectives(directives: string[]) {
240         this.isEditable = false;
241         this.setDirectiveValue(directives);
242         const rulesListOrig = this.componentInstancesConstraints;
243         this.constraintProperties = [];
244         this.constraintCapabilities = [];
245         this.loadNodeFilter();
246         this.updateComponentInstance(this.isDependent, rulesListOrig);
247     }
248
249     private onRemoveDirective() {
250         this.openRemoveDependencyModal().instance.open();
251         this.constraintProperties = [];
252         this.constraintCapabilities = [];
253     }
254
255     private onEditDirectives() {
256         this.isEditable = true;
257     }
258
259     private setDirectiveValue(newDirectiveValues: string[]) {
260         this.currentServiceInstance.setDirectiveValue(newDirectiveValues);
261     }
262
263     updateComponentInstance(isDependentOrigVal: boolean, rulesListOrig: ConstraintObject[]) {
264         this.isLoading = true;
265         this.topologyTemplateService.updateComponentInstance(this.compositeService.uniqueId,
266                                                              this.compositeService.componentType,
267                                                              this.currentServiceInstance)
268                                                              .subscribe((updatedServiceIns: ComponentInstance) => {
269             this.currentServiceInstance = new ComponentInstance(updatedServiceIns);
270             this.isDependent = this.currentServiceInstance.isDependent();
271             this.dependencyStatus.emit(this.isDependent);
272             if (this.isDependent) {
273                 this.loadRulesListEvent.emit();
274             }
275             this.isLoading = false;
276         }, (err) => {
277             this.isDependent = isDependentOrigVal;
278             this.componentInstancesConstraints = rulesListOrig;
279             this.isLoading = false;
280             console.log('An error has occurred.');
281         });
282     }
283
284     onAddNodeFilter = () => {
285         if (!this.selectedInstanceProperties) {
286             this.modalServiceNg2.openAlertModal(I18nTexts.validateNodePropertiesTxt, I18nTexts.validateNodePropertiesMsg);
287         } else {
288             const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'outline white', this.modalServiceNg2.closeCurrentModal);
289             const saveButton: ButtonModel = new ButtonModel(I18nTexts.modalCreate, 'blue', () => this.createNodeFilter(this.properties), this.getDisabled);
290             const modalModel: ModalModel = new ModalModel('l', I18nTexts.addNodeFilterTxt, '', [saveButton, cancelButton], 'standard');
291             this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
292             this.modalServiceNg2.addDynamicContentToModal(
293                 this.modalInstance,
294                 ServiceDependenciesEditorComponent,
295                 {
296                     currentServiceName: this.currentServiceInstance.name,
297                     operatorTypes: this.operatorTypes,
298                     compositeServiceName: this.compositeService.name,
299                     parentServiceInputs: this.parentServiceInputs,
300                     parentServiceProperties: this.parentServiceProperties,
301                     selectedInstanceProperties: this.selectedInstanceProperties,
302                     selectedInstanceSiblings: this.selectedInstanceSiblings
303                 }
304             );
305             this.modalInstance.instance.open();
306         }
307     }
308
309     onAddNodeFilterCapabilities = () => {
310         if (this.componentInstanceCapabilitiesMap.size == 0) {
311             this.modalServiceNg2.openAlertModal(I18nTexts.validateCapabilitiesTxt, I18nTexts.validateCapabilitiesMsg);
312         } else {
313             const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'outline white', this.modalServiceNg2.closeCurrentModal);
314             const saveButton: ButtonModel = new ButtonModel(I18nTexts.modalCreate, 'blue', () => this.createNodeFilterCapabilities(this.capabilities), this.getDisabled);
315             const modalModel: ModalModel = new ModalModel('l', I18nTexts.addNodeFilterTxt, '', [saveButton, cancelButton], 'standard');
316             this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
317             this.modalServiceNg2.addDynamicContentToModal(
318                 this.modalInstance,
319                 CapabilitiesFilterPropertiesEditorComponent,
320                 {
321                     currentServiceName: this.currentServiceInstance.name,
322                     operatorTypes: this.operatorTypes,
323                     compositeServiceName: this.compositeService.name,
324                     parentServiceInputs: this.parentServiceInputs,
325                     selectedInstanceProperties: this.selectedInstanceProperties,
326                     selectedInstanceSiblings: this.selectedInstanceSiblings,
327                     componentInstanceCapabilitiesMap: this.componentInstanceCapabilitiesMap
328                 }
329             );
330             this.modalInstance.instance.open();
331         }
332     }
333
334     createNodeFilter = (constraintType: string) => {
335         this.isLoading = true;
336         this.topologyTemplateService.createServiceFilterConstraints(
337             this.compositeService.uniqueId,
338             this.currentServiceInstance.uniqueId,
339             new ConstraintObject(this.modalInstance.instance.dynamicContent.instance.currentRule),
340             this.compositeService.componentType,
341             constraintType
342         ).subscribe( (response) => {
343             this.emitEventOnChanges(constraintType, response);
344             this.isLoading = false;
345         }, (err) => {
346             this.isLoading = false;
347         });
348         this.modalServiceNg2.closeCurrentModal();
349     }
350
351     createNodeFilterCapabilities = (constraintType: string) => {
352         this.isLoading = true;
353         this.topologyTemplateService.createServiceFilterCapabilitiesConstraints(
354             this.compositeService.uniqueId,
355             this.currentServiceInstance.uniqueId,
356             new CapabilitiesConstraintObjectUI(this.modalInstance.instance.dynamicContent.instance.currentRule),
357             this.compositeService.componentType,
358             constraintType
359         ).subscribe( (response) => {
360             this.emitEventOnChanges(constraintType, response);
361             this.isLoading = false;
362         }, (err) => {
363             this.isLoading = false;
364         });
365         this.modalServiceNg2.closeCurrentModal();
366     }
367
368     onSelectNodeFilterCapability(constraintType: string, index: number) {
369         const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'outline white', this.modalServiceNg2.closeCurrentModal);
370         const saveButton: ButtonModel = new ButtonModel(I18nTexts.modalSave, 'blue', () => this.updateNodeFilterCapability(constraintType, index), this.getDisabled);
371         const modalModel: ModalModel = new ModalModel('l', I18nTexts.updateNodeFilterTxt, '', [saveButton, cancelButton], 'standard');
372         this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
373
374         this.modalServiceNg2.addDynamicContentToModal(
375             this.modalInstance,
376             CapabilitiesFilterPropertiesEditorComponent,
377             {
378                 serviceRuleIndex: index,
379                 serviceRules: _.map(this.constraintCapabilities, (rule) => new CapabilitiesConstraintObjectUI(rule)),
380                 currentServiceName: this.currentServiceInstance.name,
381                 operatorTypes: this.operatorTypes,
382                 compositeServiceName: this.compositeService.name,
383                 parentServiceInputs: this.parentServiceInputs,
384                 selectedInstanceProperties: this.selectedInstanceProperties,
385                 selectedInstanceSiblings: this.selectedInstanceSiblings,
386                 componentInstanceCapabilitiesMap: this.componentInstanceCapabilitiesMap
387             }
388         );
389         this.modalInstance.instance.open();
390     }
391
392     onSelectNodeFilter(constraintType: string, index: number) {
393         const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'outline white', this.modalServiceNg2.closeCurrentModal);
394         const saveButton: ButtonModel = new ButtonModel(I18nTexts.modalSave, 'blue', () => this.updateNodeFilter(constraintType, index), this.getDisabled);
395         const modalModel: ModalModel = new ModalModel('l', I18nTexts.updateNodeFilterTxt, '', [saveButton, cancelButton], 'standard');
396         this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
397         this.modalServiceNg2.addDynamicContentToModal(
398             this.modalInstance,
399             ServiceDependenciesEditorComponent,
400             {
401                 serviceRuleIndex: index,
402                 serviceRules: _.map(this.constraintProperties, (rule) => new ConstraintObjectUI(rule)),
403                 currentServiceName: this.currentServiceInstance.name,
404                 operatorTypes: this.operatorTypes,
405                 compositeServiceName: this.compositeService.name,
406                 parentServiceInputs: this.parentServiceInputs,
407                 parentServiceProperties: this.parentServiceProperties,
408                 selectedInstanceProperties: this.selectedInstanceProperties,
409                 selectedInstanceSiblings: this.selectedInstanceSiblings
410             }
411         );
412         this.modalInstance.instance.open();
413     }
414
415     getDisabled = (): boolean =>  {
416         return !this.modalInstance.instance.dynamicContent.instance.checkFormValidForSubmit();
417     }
418
419     updateNodeFilter = (constraintType: string, index: number) => {
420         this.isLoading = true;
421         this.topologyTemplateService.updateServiceFilterConstraints(
422             this.compositeService.uniqueId,
423             this.currentServiceInstance.uniqueId,
424             new ConstraintObject(this.modalInstance.instance.dynamicContent.instance.currentRule),
425             this.compositeService.componentType,
426             constraintType,
427             index
428         ).subscribe((response) => {
429             this.emitEventOnChanges(constraintType, response);
430             this.isLoading = false;
431         }, (err) => {
432             this.isLoading = false;
433         });
434         this.modalServiceNg2.closeCurrentModal();
435     }
436
437     updateNodeFilterCapability= (constraintType: string, index: number) => {
438         this.isLoading = true;
439         this.topologyTemplateService.updateServiceFilterCapabilitiesConstraint(
440             this.compositeService.uniqueId,
441             this.currentServiceInstance.uniqueId,
442             new CapabilitiesConstraintObjectUI(this.modalInstance.instance.dynamicContent.instance.currentRule),
443             this.compositeService.componentType,
444             constraintType,
445             index
446         ).subscribe((response) => {
447             this.emitEventOnChanges(constraintType, response);
448             this.isLoading = false;
449         }, (err) => {
450             this.isLoading = false;
451         });
452         this.modalServiceNg2.closeCurrentModal();
453     }
454
455     getSymbol(constraintOperator) {
456         switch (constraintOperator) {
457             case OPERATOR_TYPES.LESS_THAN: return '<';
458             case OPERATOR_TYPES.EQUAL: return '=';
459             case OPERATOR_TYPES.GREATER_THAN: return '>';
460         }
461     }
462
463     onDeleteNodeFilter = (constraintType: string, index: number) => {
464         this.isLoading = true;
465         this.topologyTemplateService.deleteServiceFilterConstraints(
466             this.compositeService.uniqueId,
467             this.currentServiceInstance.uniqueId,
468             index,
469             this.compositeService.componentType,
470             constraintType
471         ).subscribe( (response) => {
472             this.emitEventOnChanges(constraintType, response);
473             this.isLoading = false;
474         }, (err) => {
475             this.isLoading = false;
476         });
477         this.modalServiceNg2.closeCurrentModal();
478     }
479
480     private emitEventOnChanges(constraintType: string, response) {
481         if (this.properties === constraintType) {
482             this.updateNodeFilterProperties.emit(response.properties);
483             this.constraintProperties = response.properties;
484         } else {
485             this.updateNodeFilterCapabilities.emit(response.capabilities);
486             this.constraintCapabilities = response.capabilities;
487         }
488     }
489
490     openDeleteModal = (constraintType: string, index: number) => {
491         this.modalServiceNg2.createActionModal(I18nTexts.deleteNodeFilterTxt, I18nTexts.deleteNodeFilterMsg,
492             I18nTexts.modalDelete, () => this.onDeleteNodeFilter(constraintType, index), I18nTexts.modalCancel).instance.open();
493     }
494
495 }