2 Copyright 2020 TATA ELXSI
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
8 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.
16 Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
19 * @file Vim Account Component.
21 import { isNullOrUndefined } from 'util';
22 import { HttpHeaders } from '@angular/common/http';
23 import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core';
24 import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
25 import { ActivatedRoute, Router } from '@angular/router';
26 import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
27 import { TranslateService } from '@ngx-translate/core';
28 import { NotifierService } from 'angular-notifier';
29 import 'codemirror/addon/dialog/dialog';
30 import 'codemirror/addon/display/autorefresh';
31 import 'codemirror/addon/display/fullscreen';
32 import 'codemirror/addon/edit/closebrackets';
33 import 'codemirror/addon/edit/matchbrackets';
34 import 'codemirror/addon/fold/brace-fold';
35 import 'codemirror/addon/fold/foldcode';
36 import 'codemirror/addon/fold/foldgutter';
37 import 'codemirror/addon/search/search';
38 import 'codemirror/addon/search/searchcursor';
39 import 'codemirror/keymap/sublime';
40 import 'codemirror/lib/codemirror';
41 import 'codemirror/mode/javascript/javascript';
42 import 'codemirror/mode/markdown/markdown';
43 import 'codemirror/mode/yaml/yaml';
45 APIURLHEADER, CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA, TYPEAWS, TYPEAZURE, TYPEOPENSTACK, TYPEOPENVIMNEBULA, TYPEOTERS,
46 TYPESECTION, TYPEVMWARE, VIM_TYPES
48 import { environment } from 'environment';
49 import * as jsyaml from 'js-yaml';
50 import { RestService } from 'RestService';
51 import { SharedService } from 'SharedService';
52 import { VimAccountDetails } from 'VimAccountModel';
53 import { WarningComponent } from 'WarningComponent';
56 * @Component takes NewVimaccountComponent.html as template url
59 selector: 'app-new-vimaccount',
60 templateUrl: './NewVimaccountComponent.html',
61 styleUrls: ['./NewVimaccountComponent.scss']
63 /** Exporting a class @exports NewVimaccountComponent */
64 export class NewVimaccountComponent implements OnInit {
65 /** To inject services @public */
66 public injector: Injector;
68 /** FormGroup vim New Account added to the form @ html @public */
69 public vimNewAccountForm: FormGroup;
71 /** Supported Vim type for the dropdown */
72 public vimType: TYPESECTION[];
74 /** Supported Vim type for the dropdown */
75 public selectedVimType: string;
77 /** Form submission Add */
78 public submitted: boolean = false;
80 /** Showing more details of collapase */
81 public isCollapsed: boolean = false;
83 /** Check the Projects loading results @public */
84 public isLocationLoadingResults: boolean = false;
86 /** Give the message for the loading @public */
87 public message: string = 'PLEASEWAIT';
89 /** Set the check value @public */
90 public check: boolean = false;
92 /** Handle the formate Change @public */
93 public defaults: {} = {
97 /** To Set Mode @public */
98 public mode: string = 'text/x-yaml';
100 /** To Set Mode @public */
101 public modeDefault: string = 'yaml';
103 /** options @public */
104 public options: {} = {
105 // eslint-disable-next-line no-invalid-this
106 mode: this.modeDefault,
107 showCursorWhenSelecting: true,
113 gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
114 autoCloseBrackets: true,
121 public data: string = '';
123 /** contains vim ID @public */
124 public vimID: string;
126 /** Element ref for fileInput @public */
127 @ViewChild('fileInput', { static: true }) public fileInput: ElementRef;
129 /** Element ref for fileInput @public */
130 @ViewChild('fileInputLabel', { static: true }) public fileInputLabel: ElementRef;
132 /** Contains all methods related to shared @private */
133 public sharedService: SharedService;
135 /** Check key for the Edit form @public */
136 public checkFormKeys: string[] =
152 /** Contains config details in edit @public */
155 /** Contains latitude value @public */
156 public latitude: string;
158 /** Contains longitude value @public */
159 public longitude: string;
161 /** Contains location value @public */
162 public locationName: string;
164 /** Contains VIMAccount Details @private */
165 private details: VimAccountDetails;
167 /** Contains config with location @private */
168 private configLocation: string;
170 /** Check for config length @private */
171 // eslint-disable-next-line @typescript-eslint/no-magic-numbers
172 private configLength: number = 3;
174 /** Instance of the rest service @private */
175 private restService: RestService;
177 /** Holds the instance of router class @private */
178 private router: Router;
180 /** Controls the header form @private */
181 private headers: HttpHeaders;
183 /** FormBuilder instance added to the formBuilder @private */
184 private formBuilder: FormBuilder;
186 /** Notifier service to popup notification @private */
187 private notifierService: NotifierService;
189 /** Contains tranlsate instance @private */
190 private translateService: TranslateService;
192 /** Holds teh instance of AuthService class of type AuthService @private */
193 private activatedRoute: ActivatedRoute;
195 /** Instance of the modal service @private */
196 private modalService: NgbModal;
198 constructor(injector: Injector) {
199 this.injector = injector;
200 this.restService = this.injector.get(RestService);
201 this.formBuilder = this.injector.get(FormBuilder);
202 this.router = this.injector.get(Router);
203 this.notifierService = this.injector.get(NotifierService);
204 this.translateService = this.injector.get(TranslateService);
205 this.sharedService = this.injector.get(SharedService);
206 this.activatedRoute = this.injector.get(ActivatedRoute);
207 this.modalService = this.injector.get(NgbModal);
210 /** convenience getter for easy access to form fields */
211 get f(): FormGroup['controls'] { return this.vimNewAccountForm.controls; }
214 * Lifecyle Hooks the trigger before component is instantiate
216 public ngOnInit(): void {
217 this.vimID = this.activatedRoute.snapshot.paramMap.get('id');
218 this.vimType = VIM_TYPES;
219 this.headers = new HttpHeaders({
220 Accept: 'application/json',
221 'Content-Type': 'application/json',
222 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
224 this.initializeForm();
225 if (!isNullOrUndefined(this.vimID)) {
226 this.getVIMDetails(this.vimID);
230 /** VIM Initialize Forms @public */
231 public initializeForm(): void {
232 this.vimNewAccountForm = this.formBuilder.group({
233 name: [null, Validators.required],
234 vim_type: [null, Validators.required],
235 vim_tenant_name: [null, Validators.required],
237 vim_url: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_URL_PATTERN)]],
239 vim_user: [null, Validators.required],
240 vim_password: [null, Validators.required],
242 latitude: ['', Validators.pattern(this.sharedService.REGX_LAT_PATTERN)],
243 longitude: ['', Validators.pattern(this.sharedService.REGX_LONG_PATTERN)],
244 config: this.paramsBuilder()
248 /** Generate params for config @public */
249 public paramsBuilder(): FormGroup {
250 return this.formBuilder.group({
255 /** Fetching the vim details from get api @protected */
256 private getVIMDetails(id: string): void {
257 this.isLocationLoadingResults = true;
258 this.restService.getResource(environment.VIMACCOUNTS_URL + '/' + id).subscribe((vimAccountsData: VimAccountDetails) => {
259 this.details = vimAccountsData;
260 if (!isNullOrUndefined(this.details.config.location)) {
261 this.configLocation = this.details.config.location;
262 if (this.configLocation.indexOf(',') !== -1) {
263 this.locationName = this.configLocation.split(',')[0];
264 this.latitude = this.configLocation.split(',')[1];
265 this.longitude = this.configLocation.split(',')[2];
268 delete this.details.config.location;
269 this.getFormControl('schema_type').disable();
270 this.getFormControl('vim_url').disable();
271 this.getFormControl('vim_type').disable();
272 this.config = { ...this.details.config };
273 this.details.vim_password = '';
274 this.setEditValue(this.details, this.checkFormKeys);
275 this.isLocationLoadingResults = false;
276 }, (error: ERRORDATA) => {
277 this.restService.handleError(error, 'get');
278 this.isLocationLoadingResults = false;
282 /** Set the value for the Edit Section @public */
283 public setEditValue(formValues: VimAccountDetails, checkKey: string[]): void {
284 Object.keys(formValues).forEach((name: string): void => {
285 if (checkKey.includes(name)) {
286 if (name === 'config') {
288 this.getFormControl('locationName').patchValue(this.locationName);
289 this.getFormControl('latitude').patchValue(this.latitude);
290 this.getFormControl('longitude').patchValue(this.longitude);
293 // eslint-disable-next-line security/detect-object-injection
294 this.getFormControl(name).setValue(formValues[name], { onlySelf: true });
295 this.getFormControl(name).updateValueAndValidity();
301 /** On modal submit newVimAccountSubmit will called @public */
302 public newVimAccountSubmit(): void {
303 this.submitted = true;
305 if (!this.vimNewAccountForm.invalid) {
306 this.isLocationLoadingResults = true;
307 this.sharedService.cleanForm(this.vimNewAccountForm, 'vim');
308 if (!isNullOrUndefined(this.data) && this.data !== '') {
309 Object.assign(this.vimNewAccountForm.value.config, jsyaml.load(this.data.toString(), { json: true }));
311 Object.keys(this.vimNewAccountForm.value.config).forEach((res: string): void => {
312 if (res !== 'location') {
313 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete, security/detect-object-injection
314 delete this.vimNewAccountForm.value.config[res];
318 if (!isNullOrUndefined(this.vimNewAccountForm.value.latitude) && !isNullOrUndefined(this.vimNewAccountForm.value.longitude)) {
319 this.vimNewAccountForm.value.config.location = this.vimNewAccountForm.value.locationName + ',' +
320 this.vimNewAccountForm.value.longitude + ',' +
321 this.vimNewAccountForm.value.latitude;
324 if (isNullOrUndefined(this.vimNewAccountForm.value.config.location)) {
325 delete this.vimNewAccountForm.value.config.location;
328 Object.keys(this.vimNewAccountForm.value.config).forEach((res: string): void => {
329 // eslint-disable-next-line security/detect-object-injection
330 if (isNullOrUndefined(this.vimNewAccountForm.value.config[res]) || this.vimNewAccountForm.value.config[res] === '') {
331 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete, security/detect-object-injection
332 delete this.vimNewAccountForm.value.config[res];
335 if (!isNullOrUndefined(this.vimID)) {
343 /** Create a new VIM Account @public */
344 public createNewVIM(): void {
345 const apiURLHeader: APIURLHEADER = {
346 url: environment.VIMACCOUNTS_URL,
347 httpOptions: { headers: this.headers }
349 delete this.vimNewAccountForm.value.locationName;
350 delete this.vimNewAccountForm.value.latitude;
351 delete this.vimNewAccountForm.value.longitude;
352 this.restService.postResource(apiURLHeader, this.vimNewAccountForm.value)
353 .subscribe((result: { id: string }): void => {
354 this.notifierService.notify('success', this.translateService.instant('PAGE.VIM.CREATEDSUCCESSFULLY'));
355 this.isLocationLoadingResults = false;
356 this.router.navigate(['vim/info/' + result.id]).catch((): void => {
359 }, (error: ERRORDATA): void => {
360 this.restService.handleError(error, 'post');
361 this.isLocationLoadingResults = false;
365 /** Create a edit VIM Account @public */
366 public editVIM(): void {
367 const apiURLHeader: APIURLHEADER = {
368 url: environment.VIMACCOUNTS_URL + '/' + this.vimID,
369 httpOptions: { headers: this.headers }
371 delete this.vimNewAccountForm.value.locationName;
372 delete this.vimNewAccountForm.value.latitude;
373 delete this.vimNewAccountForm.value.longitude;
374 this.restService.patchResource(apiURLHeader, this.vimNewAccountForm.value)
375 .subscribe((result: { id: string }): void => {
376 this.notifierService.notify('success', this.translateService.instant('PAGE.VIM.UPDATEDSUCCESSFULLY'));
377 this.isLocationLoadingResults = false;
378 this.router.navigate(['vim/info/' + this.vimID]).catch((): void => {
381 }, (error: ERRORDATA): void => {
382 this.restService.handleError(error, 'post');
383 this.isLocationLoadingResults = false;
386 /** HandleChange function @public */
387 public handleChange($event: string): void {
391 /** Routing to VIM Account Details Page @public */
392 public onVimAccountBack(): void {
393 this.router.navigate(['vim/details']).catch((): void => {
398 /** Drag and drop feature and fetchind the details of files @private */
399 public filesDropped(files: FileList): void {
400 if (files && files.length === 1) {
401 this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => {
402 const getJson: string = jsyaml.load(fileContent, { json: true });
403 this.defaults['text/x-yaml'] = fileContent;
404 this.data = fileContent;
405 }).catch((err: string): void => {
406 if (err === 'typeError') {
407 this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
409 this.notifierService.notify('error', this.translateService.instant('ERROR'));
411 this.fileInputLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
412 this.fileInput.nativeElement.value = null;
414 } else if (files && files.length > 1) {
415 this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
417 this.fileInputLabel.nativeElement.innerText = files[0].name;
418 this.fileInput.nativeElement.value = null;
421 /** Check data is empty or not to load config @public */
422 public checkData(): void {
423 if (this.data !== '' && this.data.length > this.configLength) {
424 // eslint-disable-next-line security/detect-non-literal-fs-filename
425 const modalRef: NgbModalRef = this.modalService.open(WarningComponent, { backdrop: 'static' });
426 modalRef.componentInstance.heading = this.translateService.instant('PAGE.VIMDETAILS.VIMHEADER');
427 modalRef.componentInstance.confirmationMessage = this.translateService.instant('PAGE.VIMDETAILS.VIMCONTENT');
428 modalRef.componentInstance.submitMessage = this.translateService.instant('PAGE.VIMDETAILS.VIMSUBMIT');
429 modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
430 if (result.message === CONFIGCONSTANT.done) {
431 this.loadSampleConfig();
433 }).catch((): void => {
434 // Catch Navigation Error
436 } else if (this.data.length < this.configLength || this.data === '') {
437 this.loadSampleConfig();
441 /** Load sample config based on VIM type @public */
442 public loadSampleConfig(): void {
443 if (this.selectedVimType === 'openstack') {
444 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEOPENSTACK);
445 this.data = JSON.stringify(TYPEOPENSTACK, null, '\t');
446 } else if (this.selectedVimType === 'aws') {
447 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEAWS);
448 this.data = JSON.stringify(TYPEAWS, null, '\t');
449 } else if (this.selectedVimType === 'vmware') {
450 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEVMWARE);
451 this.data = JSON.stringify(TYPEVMWARE, null, '\t');
452 } else if (this.selectedVimType === 'openvim' || this.selectedVimType === 'opennebula') {
453 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEOPENVIMNEBULA);
454 this.data = JSON.stringify(TYPEOPENVIMNEBULA, null, '\t');
455 } else if (this.selectedVimType === 'azure' || this.selectedVimType === 'opennebula') {
456 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEAZURE);
457 this.data = JSON.stringify(TYPEAZURE, null, '\t');
459 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEOTERS);
460 this.data = JSON.stringify(TYPEOTERS, null, '\t');
464 /** Load sample config based on VIM type in edit @public */
465 public loadConfig(): void {
467 if (this.details.vim_type === 'openstack') {
468 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
469 this.data = JSON.stringify(this.config, null, '\t');
470 } else if (this.details.vim_type === 'aws') {
471 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
472 this.data = JSON.stringify(this.config, null, '\t');
473 } else if (this.details.vim_type === 'vmware') {
474 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
475 this.data = JSON.stringify(this.config, null, '\t');
476 } else if (this.details.vim_type === 'openvim' || this.details.vim_type === 'opennebula') {
477 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
478 this.data = JSON.stringify(this.config, null, '\t');
479 } else if (this.details.vim_type === 'azure' || this.details.vim_type === 'opennebula') {
480 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
481 this.data = JSON.stringify(this.config, null, '\t');
483 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
484 this.data = JSON.stringify(this.config, null, '\t');
488 /** Clear config parameters @public */
489 public clearConfig(): void {
491 if (this.data !== '' && this.data.length > this.configLength) {
492 // eslint-disable-next-line security/detect-non-literal-fs-filename
493 const modalRef: NgbModalRef = this.modalService.open(WarningComponent, { backdrop: 'static' });
494 modalRef.componentInstance.heading = this.translateService.instant('PAGE.VIMDETAILS.VIMHEADER');
495 modalRef.componentInstance.confirmationMessage = this.translateService.instant('PAGE.VIMDETAILS.CLEARCONTENT');
496 modalRef.componentInstance.submitMessage = this.translateService.instant('PAGE.VIMDETAILS.VIMSUBMIT');
497 modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
498 if (result.message === CONFIGCONSTANT.done) {
499 this.defaults['text/x-yaml'] = '';
501 this.fileInput.nativeElement.value = null;
503 }).catch((): void => {
504 // Catch Navigation Error
507 this.defaults['text/x-yaml'] = '';
509 this.fileInput.nativeElement.value = null;
513 /** Used to get the AbstractControl of controlName passed @private */
514 private getFormControl(controlName: string): AbstractControl {
515 // eslint-disable-next-line security/detect-object-injection
516 return this.vimNewAccountForm.controls[controlName];