Fix for substitution filter properties
[sdc.git] / catalog-ui / src / app / ng2 / components / logic / substitution-filter / substitution-filter.component.ts
1 /*
2 * ============LICENSE_START=======================================================
3 *  Copyright (C) 2020 Nordix Foundation. All rights reserved.
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
8 *
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.
15 *
16 *  SPDX-License-Identifier: Apache-2.0
17 *  ============LICENSE_END=========================================================
18 */
19
20 import {Component, ComponentRef, EventEmitter, Input, Output} from '@angular/core';
21 import {
22   ButtonModel,
23   ComponentInstance,
24   InputBEModel,
25   ModalModel,
26   PropertyBEModel,
27 } from 'app/models';
28 import {ModalComponent} from 'app/ng2/components/ui/modal/modal.component';
29 import {ServiceDependenciesEditorComponent} from 'app/ng2/pages/service-dependencies-editor/service-dependencies-editor.component';
30 import {ModalService} from 'app/ng2/services/modal.service';
31 import {TranslateService} from 'app/ng2/shared/translator/translate.service';
32 import {ComponentMetadata} from '../../../../models/component-metadata';
33 import {ServiceInstanceObject} from '../../../../models/service-instance-properties-and-interfaces';
34 import {TopologyTemplateService} from '../../../services/component-services/topology-template.service';
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 export class ConstraintObjectUI extends ConstraintObject {
56   isValidValue: boolean;
57
58   constructor(input?: any) {
59     super(input);
60     if (input) {
61       this.isValidValue = input.isValidValue ? input.isValidValue : input.value !== '';
62     }
63   }
64
65   public updateValidity(isValidValue: boolean) {
66     this.isValidValue = isValidValue;
67   }
68
69   public isValidRule(isStatic) {
70     const isValidValue = isStatic ? this.isValidValue : true;
71     return this.servicePropertyName != null && this.servicePropertyName !== ''
72         && this.value != null && this.value !== '' && isValidValue;
73   }
74 }
75
76 export const OPERATOR_TYPES = {
77   EQUAL: 'equal',
78   GREATER_THAN: 'greater_than',
79   LESS_THAN: 'less_than'
80 };
81
82 class I18nTexts {
83   static addSubstitutionFilterTxt: string;
84   static updateSubstitutionFilterTxt: string;
85   static deleteSubstitutionFilterTxt: string;
86   static deleteSubstitutionFilterMsg: string;
87   static modalCancel: string;
88   static modalCreate: string;
89   static modalSave: string;
90   static modalDelete: string;
91
92   public static translateTexts(translateService) {
93     I18nTexts.modalCancel = translateService.translate('MODAL_CANCEL');
94     I18nTexts.modalCreate = translateService.translate('MODAL_CREATE');
95     I18nTexts.modalSave = translateService.translate('MODAL_SAVE');
96     I18nTexts.modalDelete = translateService.translate('MODAL_DELETE');
97
98     I18nTexts.addSubstitutionFilterTxt = translateService.translate('ADD_SUBSTITUTION_FILTER');
99     I18nTexts.updateSubstitutionFilterTxt = translateService.translate('UPDATE_SUBSTITUTION_FILTER');
100     I18nTexts.deleteSubstitutionFilterTxt = translateService.translate('DELETE_SUBSTITUTION_FILTER');
101     I18nTexts.deleteSubstitutionFilterMsg = translateService.translate('DELETE_SUBSTITUTION_FILTER_MSG');
102   }
103 }
104
105 @Component({
106   selector: 'substitution-filter',
107   templateUrl: './substitution-filter.component.html',
108   styleUrls: ['substitution-filter.component.less'],
109   providers: [ModalService, TranslateService]
110 })
111
112 export class SubstitutionFilterComponent {
113   modalInstance: ComponentRef<ModalComponent>;
114   isLoading: boolean;
115   parentServiceInputs: InputBEModel[] = [];
116   operatorTypes: any[];
117   constraintProperties: ConstraintObject[] = [];
118   PROPERTIES: string = ToscaFilterConstraintType.PROPERTIES;
119
120   @Input() readonly: boolean;
121   @Input() compositeService: ComponentMetadata;
122   @Input() currentServiceInstance: ComponentInstance;
123   @Input() selectedInstanceSiblings: ServiceInstanceObject[];
124   @Input() selectedInstanceConstraints: ConstraintObject[] = [];
125   @Input() selectedInstanceProperties: PropertyBEModel[] = [];
126   @Output() updateSubstitutionFilterProperties: EventEmitter<ConstraintObject[]> = new EventEmitter<ConstraintObject[]>();
127   @Output() updateConstraintListEvent: EventEmitter<ConstraintObject[]> = new EventEmitter<ConstraintObject[]>();
128   @Output() loadConstraintListEvent: EventEmitter<any> = new EventEmitter();
129   @Output() hasSubstitutionFilter = new EventEmitter<boolean>();
130
131   constructor(private topologyTemplateService: TopologyTemplateService, private modalServiceNg2: ModalService, private translateService: TranslateService) {
132   }
133
134   ngOnInit() {
135     this.isLoading = false;
136     this.operatorTypes = [
137       {label: '>', value: OPERATOR_TYPES.GREATER_THAN},
138       {label: '<', value: OPERATOR_TYPES.LESS_THAN},
139       {label: '=', value: OPERATOR_TYPES.EQUAL}
140     ];
141     this.loadSubstitutionFilter();
142     this.translateService.languageChangedObservable.subscribe((lang) => {
143       I18nTexts.translateTexts(this.translateService);
144     });
145   }
146
147   ngOnChanges(changes) {
148     if (changes.compositeService) {
149       this.compositeService = changes.compositeService.currentValue;
150     }
151     if (changes.selectedInstanceConstraints && changes.selectedInstanceConstraints.currentValue !== changes.selectedInstanceConstraints.previousValue) {
152       this.selectedInstanceConstraints = changes.selectedInstanceConstraints.currentValue;
153       this.loadSubstitutionFilter();
154     }
155   }
156
157   private loadSubstitutionFilter = (): void => {
158     this.topologyTemplateService.getSubstitutionFilterConstraints(this.compositeService.componentType, this.compositeService.uniqueId)
159     .subscribe((response) => {
160       if (response.substitutionFilterForTopologyTemplate && response.substitutionFilterForTopologyTemplate[this.compositeService.uniqueId]) {
161              this.constraintProperties = response.
162                  substitutionFilterForTopologyTemplate[this.compositeService.uniqueId].properties;
163       }
164     });
165   }
166
167   onAddSubstitutionFilter = (constraintType: string) => {
168     const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'outline white', this.modalServiceNg2.closeCurrentModal);
169     const saveButton: ButtonModel = new ButtonModel(I18nTexts.modalCreate, 'blue', () => this.createSubstitutionFilter(constraintType), this.getDisabled);
170     const modalModel: ModalModel = new ModalModel('l', I18nTexts.addSubstitutionFilterTxt, '', [saveButton, cancelButton], 'standard');
171     this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
172     this.modalServiceNg2.addDynamicContentToModal(
173         this.modalInstance,
174         ServiceDependenciesEditorComponent,
175         {
176           currentServiceName: this.currentServiceInstance.name,
177           operatorTypes: this.operatorTypes,
178           compositeServiceName: this.compositeService.name,
179           parentServiceInputs: this.parentServiceInputs,
180           selectedInstanceProperties: this.selectedInstanceProperties,
181           selectedInstanceSiblings: this.selectedInstanceSiblings
182         }
183     );
184     this.modalInstance.instance.open();
185   }
186
187   createSubstitutionFilter = (constraintType: string) => {
188     const newSubstitutionFilter: ConstraintObject = new ConstraintObject(this.modalInstance.instance.dynamicContent.instance.currentRule);
189     this.isLoading = true;
190     this.topologyTemplateService.createSubstitutionFilterConstraints(
191         this.compositeService.uniqueId,
192         newSubstitutionFilter,
193         this.compositeService.componentType,
194         constraintType
195     ).subscribe((response) => {
196       this.emitEventOnChanges(constraintType, response);
197       this.isLoading = false;
198     }, (err) => {
199       console.error("Failed to Create Substitution Filter on the component with id: ", this.compositeService.uniqueId);
200       this.isLoading = false;
201     });
202     this.modalServiceNg2.closeCurrentModal();
203   }
204
205   onSelectSubstitutionFilter(constraintType: string, index: number) {
206     const cancelButton: ButtonModel = new ButtonModel(I18nTexts.modalCancel, 'outline white', this.modalServiceNg2.closeCurrentModal);
207     const updateButton: ButtonModel = new ButtonModel(I18nTexts.modalSave, 'blue', () => this.updateSubstitutionFilter(constraintType), this.getDisabled);
208     const modalModel: ModalModel = new ModalModel('l', I18nTexts.updateSubstitutionFilterTxt, '', [updateButton, cancelButton], 'standard');
209     this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
210     this.modalServiceNg2.addDynamicContentToModal(
211         this.modalInstance,
212         ServiceDependenciesEditorComponent,
213         {
214           serviceRuleIndex: index,
215           serviceRules: _.map(this.constraintProperties, (constraint) => new ConstraintObjectUI(constraint)),
216           currentServiceName: this.currentServiceInstance.name,
217           operatorTypes: this.operatorTypes,
218           compositeServiceName: this.compositeService.name,
219           parentServiceInputs: this.parentServiceInputs,
220           selectedInstanceProperties: this.selectedInstanceProperties,
221           selectedInstanceSiblings: this.selectedInstanceSiblings
222         }
223     );
224     this.modalInstance.instance.open();
225   }
226
227   updateSubstitutionFilter = (constraintType: string): void => {
228     const constraintToUpdate: ConstraintObject[] = this.modalInstance.instance.dynamicContent.instance.serviceRulesList.map((rule) => new ConstraintObject(rule));
229     this.isLoading = true;
230     this.topologyTemplateService.updateSubstitutionFilterConstraints(
231         this.compositeService.uniqueId,
232         constraintToUpdate,
233         this.compositeService.componentType,
234         constraintType
235     ).subscribe((response) => {
236       this.emitEventOnChanges(constraintType, response);
237       this.isLoading = false;
238     }, () => {
239       console.error("Failed to Update Substitution Filter on the component with id: ", this.compositeService.uniqueId);
240       this.isLoading = false;
241     });
242     this.modalServiceNg2.closeCurrentModal();
243   }
244
245   onDeleteSubstitutionFilter = (constraintType: string, index: number) => {
246     this.isLoading = true;
247     this.topologyTemplateService.deleteSubstitutionFilterConstraints(
248         this.compositeService.uniqueId,
249         index,
250         this.compositeService.componentType,
251         constraintType
252     ).subscribe((response) => {
253       this.emitEventOnChanges(constraintType, response);
254       this.isLoading = false;
255     }, (error) => {
256       console.error("Failed to Delete Substitution Filter on the component with id: ",
257           this.compositeService.uniqueId, error);
258       this.isLoading = false;
259     });
260     this.modalServiceNg2.closeCurrentModal();
261   }
262
263   getDisabled = (): boolean => {
264     return !this.modalInstance.instance.dynamicContent.instance.checkFormValidForSubmit();
265   }
266
267   getSymbol(constraintOperator) {
268     switch (constraintOperator) {
269       case OPERATOR_TYPES.LESS_THAN:
270         return '<';
271       case OPERATOR_TYPES.EQUAL:
272         return '=';
273       case OPERATOR_TYPES.GREATER_THAN:
274         return '>';
275     }
276   }
277
278   openDeleteModal = (constraintType: string, index: number) => {
279     this.modalServiceNg2.createActionModal(I18nTexts.deleteSubstitutionFilterTxt, I18nTexts.deleteSubstitutionFilterMsg,
280         I18nTexts.modalDelete, () => this.onDeleteSubstitutionFilter(constraintType, index), I18nTexts.modalCancel).instance.open();
281   }
282
283   private emitEventOnChanges(constraintType: string, response) {
284       if (ToscaFilterConstraintType.PROPERTIES === constraintType) {
285               this.updateSubstitutionFilterProperties.emit(response.properties);
286               this.constraintProperties = response.properties;
287       }
288   }
289 }