Angular upgrade
[osm/NG-UI.git] / src / app / vim-accounts / new-vimaccount / NewVimaccountComponent.ts
1 /*
2  Copyright 2020 TATA ELXSI
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 or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15
16  Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
17 */
18 /**
19  * @file Vim Account Component.
20  */
21 import { HttpHeaders } from '@angular/common/http';
22 import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
23 import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
24 import { ActivatedRoute, Router } from '@angular/router';
25 import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
26 import { TranslateService } from '@ngx-translate/core';
27 import { NotifierService } from 'angular-notifier';
28 import 'codemirror/addon/dialog/dialog';
29 import 'codemirror/addon/display/autorefresh';
30 import 'codemirror/addon/display/fullscreen';
31 import 'codemirror/addon/edit/closebrackets';
32 import 'codemirror/addon/edit/matchbrackets';
33 import 'codemirror/addon/fold/brace-fold';
34 import 'codemirror/addon/fold/foldcode';
35 import 'codemirror/addon/fold/foldgutter';
36 import 'codemirror/addon/search/search';
37 import 'codemirror/addon/search/searchcursor';
38 import 'codemirror/keymap/sublime';
39 import 'codemirror/lib/codemirror';
40 import 'codemirror/mode/javascript/javascript';
41 import 'codemirror/mode/markdown/markdown';
42 import 'codemirror/mode/yaml/yaml';
43 import {
44   APIURLHEADER, CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA, TYPEAWS, TYPEAZURE, TYPEOPENSTACK, TYPEOPENVIMNEBULA, TYPEOTERS,
45   TYPESECTION, TYPEVMWARE, VIM_TYPES
46 } from 'CommonModel';
47 import { environment } from 'environment';
48 import * as jsyaml from 'js-yaml';
49 import { RestService } from 'RestService';
50 import { SharedService, isNullOrUndefined } from 'SharedService';
51 import { VimAccountDetails } from 'VimAccountModel';
52 import { WarningComponent } from 'WarningComponent';
53 /**
54  * Creating component
55  * @Component takes NewVimaccountComponent.html as template url
56  */
57 @Component({
58   selector: 'app-new-vimaccount',
59   templateUrl: './NewVimaccountComponent.html',
60   styleUrls: ['./NewVimaccountComponent.scss']
61 })
62 /** Exporting a class @exports NewVimaccountComponent */
63 export class NewVimaccountComponent implements OnInit {
64   /** To inject services @public */
65   public injector: Injector;
66
67   /** FormGroup vim New Account added to the form @ html @public */
68   public vimNewAccountForm: FormGroup;
69
70   /** Supported Vim type for the dropdown */
71   public vimType: TYPESECTION[];
72
73   /** Supported Vim type for the dropdown */
74   public selectedVimType: string;
75
76   /** Form submission Add */
77   public submitted: boolean = false;
78
79   /** Showing more details of collapase */
80   public isCollapsed: boolean = false;
81
82   /** Check the Projects loading results @public */
83   public isLocationLoadingResults: boolean = false;
84
85   /** Give the message for the loading @public */
86   public message: string = 'PLEASEWAIT';
87
88   /** Set the check value  @public */
89   public check: boolean = false;
90
91   /** Handle the formate Change @public */
92   public defaults: {} = {
93     'text/x-yaml': ''
94   };
95
96   /** To Set Mode @public */
97   public mode: string = 'text/x-yaml';
98
99   /** To Set Mode @public */
100   public modeDefault: string = 'yaml';
101
102   /** options @public */
103   public options: {} = {
104     // eslint-disable-next-line no-invalid-this
105     mode: this.modeDefault,
106     showCursorWhenSelecting: true,
107     autofocus: false,
108     autoRefresh: true,
109     lineNumbers: true,
110     lineWrapping: true,
111     foldGutter: true,
112     gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
113     autoCloseBrackets: true,
114     matchBrackets: true,
115     theme: 'neat',
116     keyMap: 'sublime'
117   };
118
119   /** Data @public */
120   public data: string = '';
121
122   /** contains vim ID @public */
123   public vimID: string;
124
125   /** Element ref for fileInput @public */
126   @ViewChild('fileInput', { static: true }) public fileInput: ElementRef;
127
128   /** Element ref for fileInput @public */
129   @ViewChild('fileInputLabel', { static: true }) public fileInputLabel: ElementRef;
130
131   /** Contains all methods related to shared @private */
132   public sharedService: SharedService;
133
134   /** Check key for the Edit form @public */
135   public checkFormKeys: string[] =
136     [
137       'name',
138       'vim_type',
139       'vim_tenant_name',
140       'description',
141       'vim_url',
142       'schema_type',
143       'vim_user',
144       'vim_password',
145       'locationName',
146       'latitude',
147       'longitude',
148       'config'
149     ];
150
151   /** Contains config details in edit @public */
152   public config: {};
153
154   /** Contains latitude value @public  */
155   public latitude: string;
156
157   /** Contains longitude value @public  */
158   public longitude: string;
159
160   /** Contains location value @public */
161   public locationName: string;
162
163   /** Contains VIMAccount Details @private */
164   private details: VimAccountDetails;
165
166   /** Contains config with location @private */
167   private configLocation: string;
168
169   /** Check for config length @private */
170   // eslint-disable-next-line @typescript-eslint/no-magic-numbers
171   private configLength: number = 3;
172
173   /** Contains config length from get api @private */
174   private getConfigLength: number;
175
176   /** Contains config when update @private */
177   private updateConfig: object;
178
179   /** Contains config length when update @private */
180   private updateConfigLength: number;
181
182   /** Instance of the rest service @private */
183   private restService: RestService;
184
185   /** Holds the instance of router class @private */
186   private router: Router;
187
188   /** Controls the header form @private */
189   private headers: HttpHeaders;
190
191   /** FormBuilder instance added to the formBuilder @private */
192   private formBuilder: FormBuilder;
193
194   /** Notifier service to popup notification @private */
195   private notifierService: NotifierService;
196
197   /** Contains tranlsate instance @private */
198   private translateService: TranslateService;
199
200   /** Holds teh instance of AuthService class of type AuthService @private */
201   private activatedRoute: ActivatedRoute;
202
203   /** Instance of the modal service @private */
204   private modalService: NgbModal;
205
206   constructor(injector: Injector) {
207     this.injector = injector;
208     this.restService = this.injector.get(RestService);
209     this.formBuilder = this.injector.get(FormBuilder);
210     this.router = this.injector.get(Router);
211     this.notifierService = this.injector.get(NotifierService);
212     this.translateService = this.injector.get(TranslateService);
213     this.sharedService = this.injector.get(SharedService);
214     this.activatedRoute = this.injector.get(ActivatedRoute);
215     this.modalService = this.injector.get(NgbModal);
216   }
217
218   /** convenience getter for easy access to form fields */
219   get f(): FormGroup['controls'] { return this.vimNewAccountForm.controls; }
220
221   /**
222    * Lifecyle Hooks the trigger before component is instantiate
223    */
224   public ngOnInit(): void {
225     this.vimID = this.activatedRoute.snapshot.paramMap.get('id');
226     this.vimType = VIM_TYPES;
227     this.headers = new HttpHeaders({
228       Accept: 'application/json',
229       'Content-Type': 'application/json',
230       'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
231     });
232     this.initializeForm();
233     if (!isNullOrUndefined(this.vimID)) {
234       this.getVIMDetails(this.vimID);
235     }
236   }
237
238   /** VIM Initialize Forms @public */
239   public initializeForm(): void {
240     this.vimNewAccountForm = this.formBuilder.group({
241       name: [null, Validators.required],
242       vim_type: [null, Validators.required],
243       vim_tenant_name: [null, Validators.required],
244       description: [null],
245       vim_url: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_URL_PATTERN)]],
246       schema_type: [''],
247       vim_user: [null, Validators.required],
248       vim_password: [null, Validators.required],
249       locationName: [''],
250       latitude: ['', Validators.pattern(this.sharedService.REGX_LAT_PATTERN)],
251       longitude: ['', Validators.pattern(this.sharedService.REGX_LONG_PATTERN)],
252       config: this.paramsBuilder()
253     });
254   }
255
256   /** Generate params for config @public */
257   public paramsBuilder(): FormGroup {
258     return this.formBuilder.group({
259       location: [null]
260     });
261   }
262
263   /** Fetching the vim details from get api @protected */
264   private getVIMDetails(id: string): void {
265     this.isLocationLoadingResults = true;
266     this.restService.getResource(environment.VIMACCOUNTS_URL + '/' + id).subscribe((vimAccountsData: VimAccountDetails) => {
267       this.details = vimAccountsData;
268       if (!isNullOrUndefined(this.details.config.location)) {
269         this.configLocation = this.details.config.location;
270         if (this.configLocation.indexOf(',') !== -1) {
271           this.locationName = this.configLocation.split(',')[0];
272           this.latitude = this.configLocation.split(',')[1];
273           this.longitude = this.configLocation.split(',')[2];
274         }
275       }
276       delete this.details.config.location;
277       this.getConfigLength = Object.keys(this.details.config).length;
278       this.getFormControl('schema_type').disable();
279       this.getFormControl('vim_url').disable();
280       this.getFormControl('vim_type').disable();
281       this.config = { ...this.details.config };
282       this.details.vim_password = '';
283       this.setEditValue(this.details, this.checkFormKeys);
284       this.isLocationLoadingResults = false;
285     }, (error: ERRORDATA) => {
286       this.restService.handleError(error, 'get');
287       this.isLocationLoadingResults = false;
288     });
289   }
290
291   /** Set the value for the Edit Section @public */
292   public setEditValue(formValues: VimAccountDetails, checkKey: string[]): void {
293     Object.keys(formValues).forEach((name: string): void => {
294       if (checkKey.includes(name)) {
295         if (name === 'config') {
296           this.loadConfig();
297           this.getFormControl('locationName').patchValue(this.locationName);
298           this.getFormControl('latitude').patchValue(this.latitude);
299           this.getFormControl('longitude').patchValue(this.longitude);
300         }
301         else {
302           // eslint-disable-next-line security/detect-object-injection
303           this.getFormControl(name).setValue(formValues[name], { onlySelf: true });
304           this.getFormControl(name).updateValueAndValidity();
305         }
306       }
307     });
308   }
309
310   /** On modal submit newVimAccountSubmit will called @public */
311   public newVimAccountSubmit(): void {
312     this.submitted = true;
313
314     if (!this.vimNewAccountForm.invalid) {
315       this.isLocationLoadingResults = true;
316       this.sharedService.cleanForm(this.vimNewAccountForm, 'vim');
317       if (!isNullOrUndefined(this.data) && this.data !== '') {
318         Object.assign(this.vimNewAccountForm.value.config, jsyaml.load(this.data.toString(), { json: true }));
319       } else {
320         Object.keys(this.vimNewAccountForm.value.config).forEach((res: string): void => {
321           if (res !== 'location') {
322             // eslint-disable-next-line @typescript-eslint/no-dynamic-delete, security/detect-object-injection
323             delete this.vimNewAccountForm.value.config[res];
324           }
325         });
326       }
327       if (!isNullOrUndefined(this.vimNewAccountForm.value.latitude) && !isNullOrUndefined(this.vimNewAccountForm.value.longitude)) {
328         this.vimNewAccountForm.value.config.location = this.vimNewAccountForm.value.locationName + ',' +
329           this.vimNewAccountForm.value.longitude + ',' +
330           this.vimNewAccountForm.value.latitude;
331       }
332
333       if (isNullOrUndefined(this.vimNewAccountForm.value.config.location)) {
334         delete this.vimNewAccountForm.value.config.location;
335       }
336
337       Object.keys(this.vimNewAccountForm.value.config).forEach((res: string): void => {
338         // eslint-disable-next-line security/detect-object-injection
339         if (isNullOrUndefined(this.vimNewAccountForm.value.config[res]) || this.vimNewAccountForm.value.config[res] === '') {
340           // eslint-disable-next-line @typescript-eslint/no-dynamic-delete, security/detect-object-injection
341           delete this.vimNewAccountForm.value.config[res];
342         }
343       });
344       delete this.vimNewAccountForm.value.config.location;
345       if (!isNullOrUndefined(this.data)) {
346         this.updateConfig = jsyaml.load(this.data, { json: true });
347         if (!isNullOrUndefined(this.updateConfig)) {
348           this.updateConfigLength = Object.keys(this.updateConfig).length;
349         }
350       }
351       if (this.updateConfig === undefined) {
352         this.notifierService.notify('warning', this.translateService.instant('PAGE.VIMDETAILS.VIMDELETE'));
353         this.isLocationLoadingResults = false;
354       } else if (this.getConfigLength > this.updateConfigLength) {
355         this.notifierService.notify('warning', this.translateService.instant('PAGE.VIMDETAILS.VIMEMPTY'));
356         this.isLocationLoadingResults = false;
357       }
358       if (!isNullOrUndefined(this.vimID) && ((this.getConfigLength <= this.updateConfigLength))) {
359         this.editVIM();
360       } else if (isNullOrUndefined(this.vimID)) {
361         this.createNewVIM();
362       }
363     }
364   }
365
366   /** Create a new VIM Account @public */
367   public createNewVIM(): void {
368     const apiURLHeader: APIURLHEADER = {
369       url: environment.VIMACCOUNTS_URL,
370       httpOptions: { headers: this.headers }
371     };
372     delete this.vimNewAccountForm.value.locationName;
373     delete this.vimNewAccountForm.value.latitude;
374     delete this.vimNewAccountForm.value.longitude;
375     this.restService.postResource(apiURLHeader, this.vimNewAccountForm.value)
376       .subscribe((result: { id: string }): void => {
377         this.notifierService.notify('success', this.translateService.instant('PAGE.VIM.CREATEDSUCCESSFULLY'));
378         this.isLocationLoadingResults = false;
379         this.router.navigate(['vim/info/' + result.id]).catch((): void => {
380           // Error Cached;
381         });
382       }, (error: ERRORDATA): void => {
383         this.restService.handleError(error, 'post');
384         this.isLocationLoadingResults = false;
385       });
386   }
387
388   /** Create a edit VIM Account @public */
389   public editVIM(): void {
390     const apiURLHeader: APIURLHEADER = {
391       url: environment.VIMACCOUNTS_URL + '/' + this.vimID,
392       httpOptions: { headers: this.headers }
393     };
394     delete this.vimNewAccountForm.value.locationName;
395     delete this.vimNewAccountForm.value.latitude;
396     delete this.vimNewAccountForm.value.longitude;
397     this.restService.patchResource(apiURLHeader, this.vimNewAccountForm.value)
398       .subscribe((result: { id: string }): void => {
399         this.notifierService.notify('success', this.translateService.instant('PAGE.VIM.UPDATEDSUCCESSFULLY'));
400         this.isLocationLoadingResults = false;
401         this.router.navigate(['vim/info/' + this.vimID]).catch((): void => {
402           // Error Cached;
403         });
404       }, (error: ERRORDATA): void => {
405         this.restService.handleError(error, 'post');
406         this.isLocationLoadingResults = false;
407       });
408   }
409   /** HandleChange function @public */
410   public handleChange($event: string): void {
411     this.data = $event;
412   }
413
414   /** Routing to VIM Account Details Page @public */
415   public onVimAccountBack(): void {
416     this.router.navigate(['vim/details']).catch((): void => {
417       // Error Cached
418     });
419   }
420
421   /** Drag and drop feature and fetchind the details of files  @private */
422   public filesDropped(files: FileList): void {
423     if (files && files.length === 1) {
424       this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => {
425         const getJson: string = jsyaml.load(fileContent, { json: true });
426         this.defaults['text/x-yaml'] = fileContent;
427         this.data = fileContent;
428       }).catch((err: string): void => {
429         if (err === 'typeError') {
430           this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
431         } else {
432           this.notifierService.notify('error', this.translateService.instant('ERROR'));
433         }
434         this.fileInputLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
435         this.fileInput.nativeElement.value = null;
436       });
437     } else if (files && files.length > 1) {
438       this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
439     }
440     this.fileInputLabel.nativeElement.innerText = files[0].name;
441     this.fileInput.nativeElement.value = null;
442   }
443
444   /** Check data is empty or not to load config @public */
445   public checkData(): void {
446     if (this.data !== '' && this.data.length > this.configLength) {
447       // eslint-disable-next-line security/detect-non-literal-fs-filename
448       const modalRef: NgbModalRef = this.modalService.open(WarningComponent, { backdrop: 'static' });
449       modalRef.componentInstance.heading = this.translateService.instant('PAGE.VIMDETAILS.VIMHEADER');
450       modalRef.componentInstance.confirmationMessage = this.translateService.instant('PAGE.VIMDETAILS.VIMCONTENT');
451       modalRef.componentInstance.submitMessage = this.translateService.instant('PAGE.VIMDETAILS.VIMSUBMIT');
452       modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
453         if (result.message === CONFIGCONSTANT.done) {
454           this.loadSampleConfig();
455         }
456       }).catch((): void => {
457         // Catch Navigation Error
458       });
459     } else if (this.data.length < this.configLength || this.data === '') {
460       this.loadSampleConfig();
461     }
462   }
463
464   /** Load sample config based on VIM type @public */
465   public loadSampleConfig(): void {
466     if (this.selectedVimType === 'openstack') {
467       this.defaults['text/x-yaml'] = jsyaml.dump(TYPEOPENSTACK);
468       this.data = JSON.stringify(TYPEOPENSTACK, null, '\t');
469     } else if (this.selectedVimType === 'aws') {
470       this.defaults['text/x-yaml'] = jsyaml.dump(TYPEAWS);
471       this.data = JSON.stringify(TYPEAWS, null, '\t');
472     } else if (this.selectedVimType === 'vmware') {
473       this.defaults['text/x-yaml'] = jsyaml.dump(TYPEVMWARE);
474       this.data = JSON.stringify(TYPEVMWARE, null, '\t');
475     } else if (this.selectedVimType === 'openvim' || this.selectedVimType === 'opennebula') {
476       this.defaults['text/x-yaml'] = jsyaml.dump(TYPEOPENVIMNEBULA);
477       this.data = JSON.stringify(TYPEOPENVIMNEBULA, null, '\t');
478     } else if (this.selectedVimType === 'azure' || this.selectedVimType === 'opennebula') {
479       this.defaults['text/x-yaml'] = jsyaml.dump(TYPEAZURE);
480       this.data = JSON.stringify(TYPEAZURE, null, '\t');
481     } else {
482       this.defaults['text/x-yaml'] = jsyaml.dump(TYPEOTERS);
483       this.data = JSON.stringify(TYPEOTERS, null, '\t');
484     }
485   }
486
487   /** Load sample config based on VIM type in edit @public */
488   public loadConfig(): void {
489     this.clearConfig();
490     if (this.details.vim_type === 'openstack') {
491       this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
492       this.data = JSON.stringify(this.config, null, '\t');
493     } else if (this.details.vim_type === 'aws') {
494       this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
495       this.data = JSON.stringify(this.config, null, '\t');
496     } else if (this.details.vim_type === 'vmware') {
497       this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
498       this.data = JSON.stringify(this.config, null, '\t');
499     } else if (this.details.vim_type === 'openvim' || this.details.vim_type === 'opennebula') {
500       this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
501       this.data = JSON.stringify(this.config, null, '\t');
502     } else if (this.details.vim_type === 'azure' || this.details.vim_type === 'opennebula') {
503       this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
504       this.data = JSON.stringify(this.config, null, '\t');
505     } else {
506       this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
507       this.data = JSON.stringify(this.config, null, '\t');
508     }
509   }
510
511   /** Clear config parameters @public */
512   public clearConfig(): void {
513     this.check = true;
514     if (this.data !== '' && this.data.length > this.configLength) {
515       // eslint-disable-next-line security/detect-non-literal-fs-filename
516       const modalRef: NgbModalRef = this.modalService.open(WarningComponent, { backdrop: 'static' });
517       modalRef.componentInstance.heading = this.translateService.instant('PAGE.VIMDETAILS.VIMHEADER');
518       modalRef.componentInstance.confirmationMessage = this.translateService.instant('PAGE.VIMDETAILS.CLEARCONTENT');
519       modalRef.componentInstance.submitMessage = this.translateService.instant('PAGE.VIMDETAILS.VIMSUBMIT');
520       modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
521         if (result.message === CONFIGCONSTANT.done) {
522           this.defaults['text/x-yaml'] = '';
523           this.data = '';
524           this.fileInput.nativeElement.value = null;
525         }
526       }).catch((): void => {
527         // Catch Navigation Error
528       });
529     } else {
530       this.defaults['text/x-yaml'] = '';
531       this.data = '';
532       this.fileInput.nativeElement.value = null;
533     }
534   }
535
536   /** Used to get the AbstractControl of controlName passed @private */
537   private getFormControl(controlName: string): AbstractControl {
538     // eslint-disable-next-line security/detect-object-injection
539     return this.vimNewAccountForm.controls[controlName];
540   }
541 }