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 { 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';
44 APIURLHEADER, CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA, TYPEAWS, TYPEAZURE, TYPEOPENSTACK, TYPEOPENVIMNEBULA, TYPEOTERS,
45 TYPESECTION, TYPEVMWARE, VIM_TYPES
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';
55 * @Component takes NewVimaccountComponent.html as template url
58 selector: 'app-new-vimaccount',
59 templateUrl: './NewVimaccountComponent.html',
60 styleUrls: ['./NewVimaccountComponent.scss']
62 /** Exporting a class @exports NewVimaccountComponent */
63 export class NewVimaccountComponent implements OnInit {
64 /** To inject services @public */
65 public injector: Injector;
67 /** FormGroup vim New Account added to the form @ html @public */
68 public vimNewAccountForm: FormGroup;
70 /** Supported Vim type for the dropdown */
71 public vimType: TYPESECTION[];
73 /** Supported Vim type for the dropdown */
74 public selectedVimType: string;
76 /** Form submission Add */
77 public submitted: boolean = false;
79 /** Showing more details of collapase */
80 public isCollapsed: boolean = false;
82 /** Check the Projects loading results @public */
83 public isLocationLoadingResults: boolean = false;
85 /** Give the message for the loading @public */
86 public message: string = 'PLEASEWAIT';
88 /** Set the check value @public */
89 public check: boolean = false;
91 /** Handle the formate Change @public */
92 public defaults: {} = {
96 /** To Set Mode @public */
97 public mode: string = 'text/x-yaml';
99 /** To Set Mode @public */
100 public modeDefault: string = 'yaml';
102 /** options @public */
103 public options: {} = {
104 // eslint-disable-next-line no-invalid-this
105 mode: this.modeDefault,
106 showCursorWhenSelecting: true,
112 gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
113 autoCloseBrackets: true,
120 public data: string = '';
122 /** contains vim ID @public */
123 public vimID: string;
125 /** Element ref for fileInput @public */
126 @ViewChild('fileInput', { static: true }) public fileInput: ElementRef;
128 /** Element ref for fileInput @public */
129 @ViewChild('fileInputLabel', { static: true }) public fileInputLabel: ElementRef;
131 /** Contains all methods related to shared @private */
132 public sharedService: SharedService;
134 /** Check key for the Edit form @public */
135 public checkFormKeys: string[] =
151 /** Contains config details in edit @public */
154 /** Contains latitude value @public */
155 public latitude: string;
157 /** Contains longitude value @public */
158 public longitude: string;
160 /** Contains location value @public */
161 public locationName: string;
163 /** Contains VIMAccount Details @private */
164 private details: VimAccountDetails;
166 /** Contains config with location @private */
167 private configLocation: string;
169 /** Check for config length @private */
170 // eslint-disable-next-line @typescript-eslint/no-magic-numbers
171 private configLength: number = 3;
173 /** Contains config length from get api @private */
174 private getConfigLength: number;
176 /** Contains config when update @private */
177 private updateConfig: object;
179 /** Contains config length when update @private */
180 private updateConfigLength: number;
182 /** Instance of the rest service @private */
183 private restService: RestService;
185 /** Holds the instance of router class @private */
186 private router: Router;
188 /** Controls the header form @private */
189 private headers: HttpHeaders;
191 /** FormBuilder instance added to the formBuilder @private */
192 private formBuilder: FormBuilder;
194 /** Notifier service to popup notification @private */
195 private notifierService: NotifierService;
197 /** Contains tranlsate instance @private */
198 private translateService: TranslateService;
200 /** Holds teh instance of AuthService class of type AuthService @private */
201 private activatedRoute: ActivatedRoute;
203 /** Instance of the modal service @private */
204 private modalService: NgbModal;
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);
218 /** convenience getter for easy access to form fields */
219 get f(): FormGroup['controls'] { return this.vimNewAccountForm.controls; }
222 * Lifecyle Hooks the trigger before component is instantiate
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'
232 this.initializeForm();
233 if (!isNullOrUndefined(this.vimID)) {
234 this.getVIMDetails(this.vimID);
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],
245 vim_url: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_URL_PATTERN)]],
247 vim_user: [null, Validators.required],
248 vim_password: [null, Validators.required],
250 latitude: ['', Validators.pattern(this.sharedService.REGX_LAT_PATTERN)],
251 longitude: ['', Validators.pattern(this.sharedService.REGX_LONG_PATTERN)],
252 config: this.paramsBuilder()
256 /** Generate params for config @public */
257 public paramsBuilder(): FormGroup {
258 return this.formBuilder.group({
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];
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;
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') {
297 this.getFormControl('locationName').patchValue(this.locationName);
298 this.getFormControl('latitude').patchValue(this.latitude);
299 this.getFormControl('longitude').patchValue(this.longitude);
302 // eslint-disable-next-line security/detect-object-injection
303 this.getFormControl(name).setValue(formValues[name], { onlySelf: true });
304 this.getFormControl(name).updateValueAndValidity();
310 /** On modal submit newVimAccountSubmit will called @public */
311 public newVimAccountSubmit(): void {
312 this.submitted = true;
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 }));
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];
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;
333 if (isNullOrUndefined(this.vimNewAccountForm.value.config.location)) {
334 delete this.vimNewAccountForm.value.config.location;
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];
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;
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;
358 if (!isNullOrUndefined(this.vimID) && ((this.getConfigLength <= this.updateConfigLength))) {
360 } else if (isNullOrUndefined(this.vimID)) {
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 }
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 => {
382 }, (error: ERRORDATA): void => {
383 this.restService.handleError(error, 'post');
384 this.isLocationLoadingResults = false;
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 }
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 => {
404 }, (error: ERRORDATA): void => {
405 this.restService.handleError(error, 'post');
406 this.isLocationLoadingResults = false;
409 /** HandleChange function @public */
410 public handleChange($event: string): void {
414 /** Routing to VIM Account Details Page @public */
415 public onVimAccountBack(): void {
416 this.router.navigate(['vim/details']).catch((): void => {
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'));
432 this.notifierService.notify('error', this.translateService.instant('ERROR'));
434 this.fileInputLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
435 this.fileInput.nativeElement.value = null;
437 } else if (files && files.length > 1) {
438 this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
440 this.fileInputLabel.nativeElement.innerText = files[0].name;
441 this.fileInput.nativeElement.value = null;
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();
456 }).catch((): void => {
457 // Catch Navigation Error
459 } else if (this.data.length < this.configLength || this.data === '') {
460 this.loadSampleConfig();
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');
482 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEOTERS);
483 this.data = JSON.stringify(TYPEOTERS, null, '\t');
487 /** Load sample config based on VIM type in edit @public */
488 public loadConfig(): void {
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');
506 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
507 this.data = JSON.stringify(this.config, null, '\t');
511 /** Clear config parameters @public */
512 public clearConfig(): void {
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'] = '';
524 this.fileInput.nativeElement.value = null;
526 }).catch((): void => {
527 // Catch Navigation Error
530 this.defaults['text/x-yaml'] = '';
532 this.fileInput.nativeElement.value = null;
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];