[SDC-29] rebase continue work to align source
[sdc.git] / catalog-ui / src / app / view-models / forms / property-forms / component-property-form / property-form-view-model.ts
1 'use strict';
2 import {
3     PROPERTY_TYPES, ModalsHandler, ValidationUtils, PROPERTY_VALUE_CONSTRAINTS, FormState, PROPERTY_DATA} from "app/utils";
4 import {DataTypesService} from "app/services";
5 import {PropertyModel, DataTypesMap, Component} from "app/models";
6
7 export interface IEditPropertyModel {
8     property:PropertyModel;
9     types:Array<string>;
10     simpleTypes:Array<string>;
11 }
12
13 interface IPropertyFormViewModelScope extends ng.IScope {
14     forms:any;
15     editForm:ng.IFormController;
16     footerButtons:Array<any>;
17     isNew:boolean;
18     isLoading:boolean;
19     isService:boolean;
20     validationPattern:RegExp;
21     propertyNameValidationPattern:RegExp;
22     commentValidationPattern:RegExp;
23     editPropertyModel:IEditPropertyModel;
24     modalInstanceProperty:ng.ui.bootstrap.IModalServiceInstance;
25     currentPropertyIndex:number;
26     isLastProperty:boolean;
27     myValue:any;
28     nonPrimitiveTypes:Array<string>;
29     dataTypes:DataTypesMap;
30     isTypeDataType:boolean;
31     maxLength:number;
32     isPropertyValueOwner:boolean;
33
34     validateJson(json:string):boolean;
35     save(doNotCloseModal?:boolean):void;
36     getValidationPattern(type:string):RegExp;
37     validateIntRange(value:string):boolean;
38     close():void;
39     onValueChange():void;
40     onSchemaTypeChange():void;
41     onTypeChange(resetSchema:boolean):void;
42     showSchema():boolean;
43     delete(property:PropertyModel):void;
44     getPrev():void;
45     getNext():void;
46     isSimpleType(typeName:string):boolean;
47     getDefaultValue():any;
48 }
49
50 export class PropertyFormViewModel {
51
52     static '$inject' = [
53         '$scope',
54         'Sdc.Services.DataTypesService',
55         '$uibModalInstance',
56         'property',
57         'ValidationPattern',
58         'PropertyNameValidationPattern',
59         'CommentValidationPattern',
60         'ValidationUtils',
61         'component',
62         '$filter',
63         'ModalsHandler',
64         'filteredProperties',
65         '$timeout',
66         'isPropertyValueOwner'
67     ];
68
69     private formState:FormState;
70
71     constructor(private $scope:IPropertyFormViewModelScope,
72                 private DataTypesService:DataTypesService,
73                 private $uibModalInstance:ng.ui.bootstrap.IModalServiceInstance,
74                 private property:PropertyModel,
75                 private ValidationPattern:RegExp,
76                 private PropertyNameValidationPattern:RegExp,
77                 private CommentValidationPattern:RegExp,
78                 private ValidationUtils:ValidationUtils,
79                 private component:Component,
80                 private $filter:ng.IFilterService,
81                 private ModalsHandler:ModalsHandler,
82                 private filteredProperties:Array<PropertyModel>,
83                 private $timeout:ng.ITimeoutService,
84                 private isPropertyValueOwner:boolean) {
85
86         this.formState = angular.isDefined(property.name) ? FormState.UPDATE : FormState.CREATE;
87         this.initScope();
88     }
89
90     private initResource = ():void => {
91         this.$scope.editPropertyModel.property = new PropertyModel(this.property);
92         this.$scope.editPropertyModel.property.type = this.property.type ? this.property.type : null;
93         this.setMaxLength();
94         this.initAddOnLabels();
95     };
96
97     //init property add-ons labels that show up at the left side of the input.
98     private initAddOnLabels = () => {
99         if (this.$scope.editPropertyModel.property.name == 'network_role' && this.$scope.isService) {
100             //the server sends back the normalized name. Remove it (to prevent interference with validation) and set the addon label to the component name directly.
101             //Note: this cant be done in properties.ts because we dont have access to the component
102             if (this.$scope.editPropertyModel.property.value) {
103                 let splitProp = this.$scope.editPropertyModel.property.value.split(new RegExp(this.component.normalizedName + '.', "gi"));
104                 this.$scope.editPropertyModel.property.value = splitProp.pop();
105             }
106             this.$scope.editPropertyModel.property.addOn = this.component.name;
107         }
108     }
109
110     private initEditPropertyModel = ():void => {
111         this.$scope.editPropertyModel = {
112             property: null,
113             types: PROPERTY_DATA.TYPES,
114             simpleTypes: PROPERTY_DATA.SIMPLE_TYPES
115         };
116
117         this.initResource();
118     };
119
120     private initForNotSimpleType = ():void => {
121         let property = this.$scope.editPropertyModel.property;
122         this.$scope.isTypeDataType = this.DataTypesService.isDataTypeForPropertyType(this.$scope.editPropertyModel.property);
123         if (property.type && this.$scope.editPropertyModel.simpleTypes.indexOf(property.type) == -1) {
124             if (!(property.value || property.defaultValue)) {
125                 switch (property.type) {
126                     case PROPERTY_TYPES.MAP:
127                         this.$scope.myValue = {'': null};
128                         break;
129                     case PROPERTY_TYPES.LIST:
130                         this.$scope.myValue = [];
131                         break;
132                     default:
133                         this.$scope.myValue = {};
134                 }
135             } else {
136                 this.$scope.myValue = JSON.parse(property.value || property.defaultValue);
137             }
138         }
139     };
140
141     private setMaxLength = ():void => {
142         switch (this.$scope.editPropertyModel.property.type) {
143             case PROPERTY_TYPES.MAP:
144             case PROPERTY_TYPES.LIST:
145                 this.$scope.maxLength = this.$scope.editPropertyModel.property.schema.property.type == PROPERTY_TYPES.JSON ?
146                     PROPERTY_VALUE_CONSTRAINTS.JSON_MAX_LENGTH :
147                     PROPERTY_VALUE_CONSTRAINTS.MAX_LENGTH;
148                 break;
149             case PROPERTY_TYPES.JSON:
150                 this.$scope.maxLength = PROPERTY_VALUE_CONSTRAINTS.JSON_MAX_LENGTH;
151                 break;
152             default:
153                 this.$scope.maxLength =PROPERTY_VALUE_CONSTRAINTS.MAX_LENGTH;
154         }
155     };
156
157
158     private initScope = ():void => {
159
160         //scope properties
161         this.$scope.forms = {};
162         this.$scope.validationPattern = this.ValidationPattern;
163         this.$scope.propertyNameValidationPattern = this.PropertyNameValidationPattern;
164         this.$scope.commentValidationPattern = this.CommentValidationPattern;
165         this.$scope.isLoading = false;
166         this.$scope.isNew = (this.formState === FormState.CREATE);
167         this.$scope.isService = this.component.isService();
168         this.$scope.modalInstanceProperty = this.$uibModalInstance;
169         this.$scope.currentPropertyIndex = _.findIndex(this.filteredProperties, i=> i.name == this.property.name);
170         this.$scope.isLastProperty = this.$scope.currentPropertyIndex == (this.filteredProperties.length - 1);
171         this.$scope.dataTypes = this.DataTypesService.getAllDataTypes();
172         this.$scope.isPropertyValueOwner = this.isPropertyValueOwner;
173         this.initEditPropertyModel();
174
175         this.$scope.nonPrimitiveTypes = _.filter(Object.keys(this.$scope.dataTypes), (type:string)=> {
176             return this.$scope.editPropertyModel.types.indexOf(type) == -1;
177         });
178         this.initForNotSimpleType();
179
180
181         this.$scope.validateJson = (json:string):boolean => {
182             if (!json) {
183                 return true;
184             }
185             return this.ValidationUtils.validateJson(json);
186         };
187
188
189         //scope methods
190         this.$scope.save = (doNotCloseModal?:boolean):void => {
191             let property:PropertyModel = this.$scope.editPropertyModel.property;
192             this.$scope.editPropertyModel.property.description = this.ValidationUtils.stripAndSanitize(this.$scope.editPropertyModel.property.description);
193             //if read only - or no changes made - just closes the modal
194             //need to check for property.value changes manually to detect if map properties deleted
195             if ((this.$scope.editPropertyModel.property.readonly && !this.$scope.isPropertyValueOwner)
196                 || (!this.$scope.forms.editForm.$dirty && angular.equals(JSON.stringify(this.$scope.myValue), this.$scope.editPropertyModel.property.value))) {
197                 this.$uibModalInstance.close();
198                 return;
199             }
200
201             this.$scope.isLoading = true;
202
203             let onPropertyFaild = (response):void => {
204                 console.info('onFaild', response);
205                 this.$scope.isLoading = false;
206             };
207
208             let onPropertySuccess = (propertyFromBE:PropertyModel):void => {
209                 console.info('onPropertyResourceSuccess : ', propertyFromBE);
210                 this.$scope.isLoading = false;
211
212                 if (!doNotCloseModal) {
213                     this.$uibModalInstance.close(propertyFromBE);
214                 } else {
215                     this.$scope.forms.editForm.$setPristine();
216                     this.$scope.editPropertyModel.property = new PropertyModel();
217                 }
218             };
219
220             //in case we have uniqueId we call update method
221             if (this.$scope.isPropertyValueOwner) {
222                 if (!this.$scope.editPropertyModel.property.simpleType && !this.$scope.isSimpleType(property.type)) {
223                     let myValueString:string = JSON.stringify(this.$scope.myValue);
224                     property.value = myValueString;
225                 }
226                 this.component.updateInstanceProperty(property).then(onPropertySuccess, onPropertyFaild);
227             } else {
228                 if (!this.$scope.editPropertyModel.property.simpleType && !this.$scope.isSimpleType(property.type)) {
229                     let myValueString:string = JSON.stringify(this.$scope.myValue);
230                     property.defaultValue = myValueString;
231                 } else {
232                     this.$scope.editPropertyModel.property.defaultValue = this.$scope.editPropertyModel.property.value;
233                 }
234                 this.component.addOrUpdateProperty(property).then(onPropertySuccess, onPropertyFaild);
235             }
236         };
237
238         this.$scope.getPrev = ():void=> {
239             this.property = this.filteredProperties[--this.$scope.currentPropertyIndex];
240             this.initResource();
241             this.initForNotSimpleType();
242             this.$scope.isLastProperty = false;
243         };
244
245         this.$scope.getNext = ():void=> {
246             this.property = this.filteredProperties[++this.$scope.currentPropertyIndex];
247             this.initResource();
248             this.initForNotSimpleType();
249             this.$scope.isLastProperty = this.$scope.currentPropertyIndex == (this.filteredProperties.length - 1);
250         };
251
252         this.$scope.isSimpleType = (typeName:string):boolean=> {
253             return typeName && this.$scope.editPropertyModel.simpleTypes.indexOf(typeName) != -1;
254         };
255
256         this.$scope.showSchema = ():boolean => {
257             return [PROPERTY_TYPES.LIST, PROPERTY_TYPES.MAP].indexOf(this.$scope.editPropertyModel.property.type) > -1;
258         };
259
260         this.$scope.getValidationPattern = (type:string):RegExp => {
261             return this.ValidationUtils.getValidationPattern(type);
262         };
263
264         this.$scope.validateIntRange = (value:string):boolean => {
265             return !value || this.ValidationUtils.validateIntRange(value);
266         };
267
268         this.$scope.close = ():void => {
269             this.$uibModalInstance.close();
270         };
271
272         // put default value when instance value is empty
273         this.$scope.onValueChange = ():void => {
274             if (!this.$scope.editPropertyModel.property.value) {
275                 if (this.$scope.isPropertyValueOwner) {
276                     this.$scope.editPropertyModel.property.value = this.$scope.editPropertyModel.property.defaultValue;
277                 }
278             }
279         };
280
281         // Add the done button at the footer.
282         this.$scope.footerButtons = [
283             {'name': 'Save', 'css': 'blue', 'callback': this.$scope.save},
284             {'name': 'Cancel', 'css': 'grey', 'callback': this.$scope.close}
285         ];
286
287         this.$scope.$watch("forms.editForm.$invalid", (newVal, oldVal) => {
288             this.$scope.footerButtons[0].disabled = this.$scope.forms.editForm.$invalid;
289         });
290
291         this.$scope.getDefaultValue = ():any => {
292             return this.$scope.isPropertyValueOwner ? this.$scope.editPropertyModel.property.defaultValue : null;
293         };
294
295         this.$scope.onTypeChange = ():void => {
296             this.$scope.editPropertyModel.property.value = '';
297             this.$scope.editPropertyModel.property.defaultValue = '';
298             this.setMaxLength();
299             this.initForNotSimpleType();
300         };
301
302         this.$scope.onSchemaTypeChange = ():void => {
303             if (this.$scope.editPropertyModel.property.type == PROPERTY_TYPES.MAP) {
304                 this.$scope.myValue = {'': null};
305             } else if (this.$scope.editPropertyModel.property.type == PROPERTY_TYPES.LIST) {
306                 this.$scope.myValue = [];
307             }
308             this.setMaxLength();
309         };
310
311         this.$scope.delete = (property:PropertyModel):void => {
312             let onOk = ():void => {
313                 this.component.deleteProperty(property.uniqueId).then(
314                     this.$scope.close
315                 );
316             };
317             let title:string = this.$filter('translate')("PROPERTY_VIEW_DELETE_MODAL_TITLE");
318             let message:string = this.$filter('translate')("PROPERTY_VIEW_DELETE_MODAL_TEXT", "{'name': '" + property.name + "'}");
319             this.ModalsHandler.openConfirmationModal(title, message, false).then(onOk);
320         };
321     }
322 }