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 /** Contains config length from get api @private */
175 private getConfigLength: number;
177 /** Contains config when update @private */
178 private updateConfig: object;
180 /** Contains config length when update @private */
181 private updateConfigLength: number;
183 /** Instance of the rest service @private */
184 private restService: RestService;
186 /** Holds the instance of router class @private */
187 private router: Router;
189 /** Controls the header form @private */
190 private headers: HttpHeaders;
192 /** FormBuilder instance added to the formBuilder @private */
193 private formBuilder: FormBuilder;
195 /** Notifier service to popup notification @private */
196 private notifierService: NotifierService;
198 /** Contains tranlsate instance @private */
199 private translateService: TranslateService;
201 /** Holds teh instance of AuthService class of type AuthService @private */
202 private activatedRoute: ActivatedRoute;
204 /** Instance of the modal service @private */
205 private modalService: NgbModal;
207 constructor(injector: Injector) {
208 this.injector = injector;
209 this.restService = this.injector.get(RestService);
210 this.formBuilder = this.injector.get(FormBuilder);
211 this.router = this.injector.get(Router);
212 this.notifierService = this.injector.get(NotifierService);
213 this.translateService = this.injector.get(TranslateService);
214 this.sharedService = this.injector.get(SharedService);
215 this.activatedRoute = this.injector.get(ActivatedRoute);
216 this.modalService = this.injector.get(NgbModal);
219 /** convenience getter for easy access to form fields */
220 get f(): FormGroup['controls'] { return this.vimNewAccountForm.controls; }
223 * Lifecyle Hooks the trigger before component is instantiate
225 public ngOnInit(): void {
226 this.vimID = this.activatedRoute.snapshot.paramMap.get('id');
227 this.vimType = VIM_TYPES;
228 this.headers = new HttpHeaders({
229 Accept: 'application/json',
230 'Content-Type': 'application/json',
231 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
233 this.initializeForm();
234 if (!isNullOrUndefined(this.vimID)) {
235 this.getVIMDetails(this.vimID);
239 /** VIM Initialize Forms @public */
240 public initializeForm(): void {
241 this.vimNewAccountForm = this.formBuilder.group({
242 name: [null, Validators.required],
243 vim_type: [null, Validators.required],
244 vim_tenant_name: [null, Validators.required],
246 vim_url: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_URL_PATTERN)]],
248 vim_user: [null, Validators.required],
249 vim_password: [null, Validators.required],
251 latitude: ['', Validators.pattern(this.sharedService.REGX_LAT_PATTERN)],
252 longitude: ['', Validators.pattern(this.sharedService.REGX_LONG_PATTERN)],
253 config: this.paramsBuilder()
257 /** Generate params for config @public */
258 public paramsBuilder(): FormGroup {
259 return this.formBuilder.group({
264 /** Fetching the vim details from get api @protected */
265 private getVIMDetails(id: string): void {
266 this.isLocationLoadingResults = true;
267 this.restService.getResource(environment.VIMACCOUNTS_URL + '/' + id).subscribe((vimAccountsData: VimAccountDetails) => {
268 this.details = vimAccountsData;
269 if (!isNullOrUndefined(this.details.config.location)) {
270 this.configLocation = this.details.config.location;
271 if (this.configLocation.indexOf(',') !== -1) {
272 this.locationName = this.configLocation.split(',')[0];
273 this.latitude = this.configLocation.split(',')[1];
274 this.longitude = this.configLocation.split(',')[2];
277 delete this.details.config.location;
278 this.getConfigLength = Object.keys(this.details.config).length;
279 this.getFormControl('schema_type').disable();
280 this.getFormControl('vim_url').disable();
281 this.getFormControl('vim_type').disable();
282 this.config = { ...this.details.config };
283 this.details.vim_password = '';
284 this.setEditValue(this.details, this.checkFormKeys);
285 this.isLocationLoadingResults = false;
286 }, (error: ERRORDATA) => {
287 this.restService.handleError(error, 'get');
288 this.isLocationLoadingResults = false;
292 /** Set the value for the Edit Section @public */
293 public setEditValue(formValues: VimAccountDetails, checkKey: string[]): void {
294 Object.keys(formValues).forEach((name: string): void => {
295 if (checkKey.includes(name)) {
296 if (name === 'config') {
298 this.getFormControl('locationName').patchValue(this.locationName);
299 this.getFormControl('latitude').patchValue(this.latitude);
300 this.getFormControl('longitude').patchValue(this.longitude);
303 // eslint-disable-next-line security/detect-object-injection
304 this.getFormControl(name).setValue(formValues[name], { onlySelf: true });
305 this.getFormControl(name).updateValueAndValidity();
311 /** On modal submit newVimAccountSubmit will called @public */
312 public newVimAccountSubmit(): void {
313 this.submitted = true;
315 if (!this.vimNewAccountForm.invalid) {
316 this.isLocationLoadingResults = true;
317 this.sharedService.cleanForm(this.vimNewAccountForm, 'vim');
318 if (!isNullOrUndefined(this.data) && this.data !== '') {
319 Object.assign(this.vimNewAccountForm.value.config, jsyaml.load(this.data.toString(), { json: true }));
321 Object.keys(this.vimNewAccountForm.value.config).forEach((res: string): void => {
322 if (res !== 'location') {
323 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete, security/detect-object-injection
324 delete this.vimNewAccountForm.value.config[res];
328 if (!isNullOrUndefined(this.vimNewAccountForm.value.latitude) && !isNullOrUndefined(this.vimNewAccountForm.value.longitude)) {
329 this.vimNewAccountForm.value.config.location = this.vimNewAccountForm.value.locationName + ',' +
330 this.vimNewAccountForm.value.longitude + ',' +
331 this.vimNewAccountForm.value.latitude;
334 if (isNullOrUndefined(this.vimNewAccountForm.value.config.location)) {
335 delete this.vimNewAccountForm.value.config.location;
338 Object.keys(this.vimNewAccountForm.value.config).forEach((res: string): void => {
339 // eslint-disable-next-line security/detect-object-injection
340 if (isNullOrUndefined(this.vimNewAccountForm.value.config[res]) || this.vimNewAccountForm.value.config[res] === '') {
341 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete, security/detect-object-injection
342 delete this.vimNewAccountForm.value.config[res];
345 delete this.vimNewAccountForm.value.config.location;
346 if (!isNullOrUndefined(this.data)) {
347 this.updateConfig = jsyaml.load(this.data, { json: true });
348 if (!isNullOrUndefined(this.updateConfig)) {
349 this.updateConfigLength = Object.keys(this.updateConfig).length;
352 if (this.updateConfig === undefined) {
353 this.notifierService.notify('warning', this.translateService.instant('PAGE.VIMDETAILS.VIMDELETE'));
354 this.isLocationLoadingResults = false;
355 } else if (this.getConfigLength > this.updateConfigLength) {
356 this.notifierService.notify('warning', this.translateService.instant('PAGE.VIMDETAILS.VIMEMPTY'));
357 this.isLocationLoadingResults = false;
359 if (!isNullOrUndefined(this.vimID) && ((this.getConfigLength <= this.updateConfigLength))) {
361 } else if (isNullOrUndefined(this.vimID)) {
367 /** Create a new VIM Account @public */
368 public createNewVIM(): void {
369 const apiURLHeader: APIURLHEADER = {
370 url: environment.VIMACCOUNTS_URL,
371 httpOptions: { headers: this.headers }
373 delete this.vimNewAccountForm.value.locationName;
374 delete this.vimNewAccountForm.value.latitude;
375 delete this.vimNewAccountForm.value.longitude;
376 this.restService.postResource(apiURLHeader, this.vimNewAccountForm.value)
377 .subscribe((result: { id: string }): void => {
378 this.notifierService.notify('success', this.translateService.instant('PAGE.VIM.CREATEDSUCCESSFULLY'));
379 this.isLocationLoadingResults = false;
380 this.router.navigate(['vim/info/' + result.id]).catch((): void => {
383 }, (error: ERRORDATA): void => {
384 this.restService.handleError(error, 'post');
385 this.isLocationLoadingResults = false;
389 /** Create a edit VIM Account @public */
390 public editVIM(): void {
391 const apiURLHeader: APIURLHEADER = {
392 url: environment.VIMACCOUNTS_URL + '/' + this.vimID,
393 httpOptions: { headers: this.headers }
395 delete this.vimNewAccountForm.value.locationName;
396 delete this.vimNewAccountForm.value.latitude;
397 delete this.vimNewAccountForm.value.longitude;
398 this.restService.patchResource(apiURLHeader, this.vimNewAccountForm.value)
399 .subscribe((result: { id: string }): void => {
400 this.notifierService.notify('success', this.translateService.instant('PAGE.VIM.UPDATEDSUCCESSFULLY'));
401 this.isLocationLoadingResults = false;
402 this.router.navigate(['vim/info/' + this.vimID]).catch((): void => {
405 }, (error: ERRORDATA): void => {
406 this.restService.handleError(error, 'post');
407 this.isLocationLoadingResults = false;
410 /** HandleChange function @public */
411 public handleChange($event: string): void {
415 /** Routing to VIM Account Details Page @public */
416 public onVimAccountBack(): void {
417 this.router.navigate(['vim/details']).catch((): void => {
422 /** Drag and drop feature and fetchind the details of files @private */
423 public filesDropped(files: FileList): void {
424 if (files && files.length === 1) {
425 this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => {
426 const getJson: string = jsyaml.load(fileContent, { json: true });
427 this.defaults['text/x-yaml'] = fileContent;
428 this.data = fileContent;
429 }).catch((err: string): void => {
430 if (err === 'typeError') {
431 this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
433 this.notifierService.notify('error', this.translateService.instant('ERROR'));
435 this.fileInputLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
436 this.fileInput.nativeElement.value = null;
438 } else if (files && files.length > 1) {
439 this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
441 this.fileInputLabel.nativeElement.innerText = files[0].name;
442 this.fileInput.nativeElement.value = null;
445 /** Check data is empty or not to load config @public */
446 public checkData(): void {
447 if (this.data !== '' && this.data.length > this.configLength) {
448 // eslint-disable-next-line security/detect-non-literal-fs-filename
449 const modalRef: NgbModalRef = this.modalService.open(WarningComponent, { backdrop: 'static' });
450 modalRef.componentInstance.heading = this.translateService.instant('PAGE.VIMDETAILS.VIMHEADER');
451 modalRef.componentInstance.confirmationMessage = this.translateService.instant('PAGE.VIMDETAILS.VIMCONTENT');
452 modalRef.componentInstance.submitMessage = this.translateService.instant('PAGE.VIMDETAILS.VIMSUBMIT');
453 modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
454 if (result.message === CONFIGCONSTANT.done) {
455 this.loadSampleConfig();
457 }).catch((): void => {
458 // Catch Navigation Error
460 } else if (this.data.length < this.configLength || this.data === '') {
461 this.loadSampleConfig();
465 /** Load sample config based on VIM type @public */
466 public loadSampleConfig(): void {
467 if (this.selectedVimType === 'openstack') {
468 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEOPENSTACK);
469 this.data = JSON.stringify(TYPEOPENSTACK, null, '\t');
470 } else if (this.selectedVimType === 'aws') {
471 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEAWS);
472 this.data = JSON.stringify(TYPEAWS, null, '\t');
473 } else if (this.selectedVimType === 'vmware') {
474 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEVMWARE);
475 this.data = JSON.stringify(TYPEVMWARE, null, '\t');
476 } else if (this.selectedVimType === 'openvim' || this.selectedVimType === 'opennebula') {
477 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEOPENVIMNEBULA);
478 this.data = JSON.stringify(TYPEOPENVIMNEBULA, null, '\t');
479 } else if (this.selectedVimType === 'azure' || this.selectedVimType === 'opennebula') {
480 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEAZURE);
481 this.data = JSON.stringify(TYPEAZURE, null, '\t');
483 this.defaults['text/x-yaml'] = jsyaml.dump(TYPEOTERS);
484 this.data = JSON.stringify(TYPEOTERS, null, '\t');
488 /** Load sample config based on VIM type in edit @public */
489 public loadConfig(): void {
491 if (this.details.vim_type === 'openstack') {
492 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
493 this.data = JSON.stringify(this.config, null, '\t');
494 } else if (this.details.vim_type === 'aws') {
495 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
496 this.data = JSON.stringify(this.config, null, '\t');
497 } else if (this.details.vim_type === 'vmware') {
498 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
499 this.data = JSON.stringify(this.config, null, '\t');
500 } else if (this.details.vim_type === 'openvim' || this.details.vim_type === 'opennebula') {
501 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
502 this.data = JSON.stringify(this.config, null, '\t');
503 } else if (this.details.vim_type === 'azure' || this.details.vim_type === 'opennebula') {
504 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
505 this.data = JSON.stringify(this.config, null, '\t');
507 this.defaults['text/x-yaml'] = jsyaml.dump(this.config);
508 this.data = JSON.stringify(this.config, null, '\t');
512 /** Clear config parameters @public */
513 public clearConfig(): void {
515 if (this.data !== '' && this.data.length > this.configLength) {
516 // eslint-disable-next-line security/detect-non-literal-fs-filename
517 const modalRef: NgbModalRef = this.modalService.open(WarningComponent, { backdrop: 'static' });
518 modalRef.componentInstance.heading = this.translateService.instant('PAGE.VIMDETAILS.VIMHEADER');
519 modalRef.componentInstance.confirmationMessage = this.translateService.instant('PAGE.VIMDETAILS.CLEARCONTENT');
520 modalRef.componentInstance.submitMessage = this.translateService.instant('PAGE.VIMDETAILS.VIMSUBMIT');
521 modalRef.result.then((result: MODALCLOSERESPONSEDATA): void => {
522 if (result.message === CONFIGCONSTANT.done) {
523 this.defaults['text/x-yaml'] = '';
525 this.fileInput.nativeElement.value = null;
527 }).catch((): void => {
528 // Catch Navigation Error
531 this.defaults['text/x-yaml'] = '';
533 this.fileInput.nativeElement.value = null;
537 /** Used to get the AbstractControl of controlName passed @private */
538 private getFormControl(controlName: string): AbstractControl {
539 // eslint-disable-next-line security/detect-object-injection
540 return this.vimNewAccountForm.controls[controlName];