Fix Bug 2121: NG-UI uses unmaintained Chokidar version
[osm/NG-UI.git] / src / app / vim-accounts / vim-account-details / VimAccountDetailsComponent.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 { Component, Injector, OnInit } from '@angular/core';
22 import { Router } from '@angular/router';
23 import { TranslateService } from '@ngx-translate/core';
24 import { CONFIGCONSTANT, CONSTANTNUMBER, ERRORDATA, VIM_TYPES } from 'CommonModel';
25 import { DataService } from 'DataService';
26 import { environment } from 'environment';
27 import { LocalDataSource } from 'ng2-smart-table';
28 import { NSInstanceDetails } from 'NSInstanceModel';
29 import Feature from 'ol/Feature';
30 import Point from 'ol/geom/Point';
31 import { defaults as defaultInteractions } from 'ol/interaction';
32 import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
33 import Map from 'ol/Map';
34 import Overlay from 'ol/Overlay';
35 import { fromLonLat } from 'ol/proj.js';
36 import OSM from 'ol/source/OSM';
37 import VectorSource from 'ol/source/Vector';
38 import { Icon, Style } from 'ol/style';
39 import View from 'ol/View';
40 import { RestService } from 'RestService';
41 import { Subscription } from 'rxjs';
42 import { SharedService } from 'SharedService';
43 import { VimAccountDetails, VIMData } from 'VimAccountModel';
44 import { VimAccountsActionComponent } from 'VimAccountsAction';
45 /**
46  * Creating component
47  * @Component takes VimAccountDetailsComponent.html as template url
48  */
49 @Component({
50     selector: 'app-vim-account-details',
51     templateUrl: './VimAccountDetailsComponent.html',
52     styleUrls: ['./VimAccountDetailsComponent.scss']
53 })
54 /** Exporting a class @exports VimAccountDetailsComponent */
55 export class VimAccountDetailsComponent implements OnInit {
56     /** To inject services @public */
57     public injector: Injector;
58     /** handle translate @public */
59     public translateService: TranslateService;
60     /** initially show the map container@public */
61     public showMap: boolean;
62     /**  hide and show popup @public */
63     public popupShow: boolean = false;
64     /** Data of smarttable populate through LocalDataSource @public */
65     public dataSource: LocalDataSource = new LocalDataSource();
66     /** Columns list of the smart table @public */
67     public columnLists: object = {};
68     /** Settings for smarttable to populate the table with columns @public */
69     public settings: object = {};
70     /** initially hide the list@private */
71     public showList: boolean;
72     /** to store locations name @public */
73     public getLocation: GetLocation[];
74     /** Contains content for map popup @public */
75     public popupData: string;
76     /** Check the loading results @public */
77     public isLoadingResults: boolean = true;
78     /** Give the message for the loading @public */
79     public message: string = 'PLEASEWAIT';
80     /** Class for empty and present data @public */
81     public checkDataClass: string;
82     /** Formation of appropriate Data for LocalDatasource @public */
83     public vimData: VIMData[];
84     /** operational State init data @public */
85     public operationalStateFirstStep: string = CONFIGCONSTANT.vimOperationalStateFirstStep;
86     /** operational State running data @public */
87     public operationalStateSecondStep: string = CONFIGCONSTANT.vimOperationalStateStateSecondStep;
88     /** operational State failed data @public */
89     public operationalStateThirdStep: string = CONFIGCONSTANT.vimOperationalStateThirdStep;
90     /** NS Instances operational State failed data @public */
91     public nsinstancesoperationalStateRunning: string = CONFIGCONSTANT.operationalStateSecondStep;
92     /** Instance of the rest service @private */
93     private restService: RestService;
94     /** dataService to pass the data from one component to another @private */
95     private dataService: DataService;
96     /** Contains all methods related to shared @private */
97     private sharedService: SharedService;
98     /** Holds the instance of router class @private */
99     private router: Router;
100     /** ns INstance Data @private */
101     private nsData: NSInstanceDetails[];
102     /** map object @private */
103     private map: Map;
104     /**  used to bind marker @private */
105     private vectorSource: VectorSource;
106     /** used to bind vectorSource @private */
107     private vectorLayer: VectorLayer;
108     /** marker @private */
109     private marker: Feature;
110     /** latitude @private */
111     private lat: number;
112     /** longitude @private */
113     private lng: number;
114     /**  each vector layer of marker is pushed to layers array @private */
115     private layers: VectorLayer[] = [];
116     /** locationData @private */
117     private locationData: VimAccountDetails[];
118     /** popup array @private */
119     private overLay: Overlay[] = [];
120     /** Instance of subscriptions @private */
121     private generateDataSub: Subscription;
122
123     constructor(injector: Injector) {
124         this.injector = injector;
125         this.restService = this.injector.get(RestService);
126         this.dataService = this.injector.get(DataService);
127         this.sharedService = this.injector.get(SharedService);
128         this.router = this.injector.get(Router);
129         this.translateService = this.injector.get(TranslateService);
130     }
131     /** Lifecyle Hooks the trigger before component is instantiate @public */
132     public ngOnInit(): void {
133         this.osmMapView();
134         this.listView();
135         this.generateColumns();
136         this.generateSettings();
137         this.generateData();
138         this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
139     }
140
141     /** smart table Header Colums @public */
142     public generateColumns(): void {
143         this.columnLists = {
144             name: { title: this.translateService.instant('NAME'), width: '15%', sortDirection: 'asc' },
145             identifier: { title: this.translateService.instant('IDENTIFIER'), width: '25%' },
146             type: {
147                 title: this.translateService.instant('TYPE'), width: '15%',
148                 filter: {
149                     type: 'list',
150                     config: {
151                         selectText: 'Select',
152                         list: VIM_TYPES
153                     }
154                 }
155             },
156             operationalState: {
157                 title: this.translateService.instant('OPERATIONALSTATUS'), width: '15%', type: 'html',
158                 filter: {
159                     type: 'list',
160                     config: {
161                         selectText: 'Select',
162                         list: [
163                             { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep },
164                             { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep },
165                             { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep }
166                         ]
167                     }
168                 },
169                 valuePrepareFunction: (cell: VIMData, row: VIMData): string => {
170                     if (row.operationalState === this.operationalStateFirstStep) {
171                         return `<span class="icon-label" title="${row.operationalState}">
172                         <i class="fas fa-clock text-warning"></i>
173                         </span>`;
174                     } else if (row.operationalState === this.operationalStateSecondStep) {
175                         return `<span class="icon-label" title="${row.operationalState}">
176                         <i class="fas fa-check-circle text-success"></i>
177                         </span>`;
178                     } else if (row.operationalState === this.operationalStateThirdStep) {
179                         return `<span class="icon-label" title="${row.operationalState}">
180                         <i class="fas fa-times-circle text-danger"></i>
181                         </span>`;
182                     } else {
183                         return `<span>${row.operationalState}</span>`;
184                     }
185                 }
186             },
187             description: { title: this.translateService.instant('DESCRIPTION'), width: '25%' },
188             Actions: {
189                 name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom',
190                 valuePrepareFunction: (cell: VIMData, row: VIMData): VIMData => row,
191                 renderComponent: VimAccountsActionComponent
192             }
193         };
194     }
195
196     /** smart table Data Settings @public */
197     public generateSettings(): void {
198         this.settings = {
199             edit: {
200                 editButtonContent: '<i class="fa fa-edit" title="Edit"></i>',
201                 confirmSave: true
202             },
203             delete: {
204                 deleteButtonContent: '<i class="far fa-trash-alt" title="delete"></i>',
205                 confirmDelete: true
206             },
207             columns: this.columnLists,
208             actions: {
209                 add: false,
210                 edit: false,
211                 delete: false,
212                 position: 'right'
213             },
214             attr: this.sharedService.tableClassConfig(),
215             pager: this.sharedService.paginationPagerConfig(),
216             noDataMessage: this.translateService.instant('NODATAMSG')
217         };
218     }
219
220     /** smart table listing manipulation @public */
221     public onChange(perPageValue: number): void {
222         this.dataSource.setPaging(1, perPageValue, true);
223     }
224
225     /** smart table listing manipulation @public */
226     public onUserRowSelect(event: MessageEvent): void {
227         Object.assign(event.data, { page: 'vim-account' });
228         this.dataService.changeMessage(event.data);
229     }
230
231     /** on Navigate to Composer Page @public */
232     public composeVIM(): void {
233         this.router.navigate(['vim/new']).catch(() => {
234             //empty block
235         });
236     }
237
238     /** To show map conatainer @public */
239     public mapView(): void {
240         this.showList = true;
241         this.showMap = false;
242     }
243     /** To show listview @public */
244     public listView(): void {
245         this.showMap = true;
246         this.showList = false;
247     }
248     /** Load the datasource appropriatetype @public */
249     public loadDatasource(getdata: VIMData[]): void {
250         if (getdata.length > 0) {
251             this.checkDataClass = 'dataTables_present';
252         } else {
253             this.checkDataClass = 'dataTables_empty';
254         }
255         this.dataSource.load(getdata).then((data: boolean) => {
256             //empty block
257         }).catch(() => {
258             //empty block
259         });
260     }
261
262     /** Generate generateVIMData object from loop and return for the datasource @public */
263     public generateVIMData(vimAccountData: VimAccountDetails): VIMData {
264         return {
265             name: vimAccountData.name,
266             identifier: vimAccountData._id,
267             type: vimAccountData.vim_type,
268             operationalState: vimAccountData._admin.operationalState,
269             description: vimAccountData.description,
270             instancesData: this.nsData,
271             resources: vimAccountData.resources !== undefined ? vimAccountData.resources : null
272         };
273     }
274
275     /**
276      * Lifecyle hook which get trigger on component destruction
277      */
278     public ngOnDestroy(): void {
279         this.generateDataSub.unsubscribe();
280     }
281
282     /** Fetching the data from server to Load in the smarttable @protected */
283     private generateData(): void {
284         this.isLoadingResults = true;
285         this.vimData = [];
286         this.getNSData().then((): void => {
287             this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimAccountsData: VimAccountDetails[]) => {
288                 this.locationData = vimAccountsData;
289                 vimAccountsData.forEach((vimAccountData: VimAccountDetails) => {
290                     const vimDataObj: VIMData = this.generateVIMData(vimAccountData);
291                     this.vimData.push(vimDataObj);
292                 });
293                 this.loadDatasource(this.vimData);
294                 this.removeLayersOverLay();
295                 this.arrayOfLocation();
296                 this.isLoadingResults = false;
297             }, (error: ERRORDATA) => {
298                 this.restService.handleError(error, 'get');
299                 this.isLoadingResults = false;
300             });
301         }).catch((error: ERRORDATA): void => {
302             this.restService.handleError(error, 'get');
303             this.isLoadingResults = false;
304         });
305     }
306
307     /** fetching the nsdata @private */
308     private async getNSData(): Promise<Boolean> {
309         return new Promise<Boolean>((resolve: Function, reject: Function): void => {
310             this.nsData = [];
311             this.restService.getResource(environment.NSDINSTANCES_URL).subscribe((nsdInstancesData: NSInstanceDetails[]) => {
312                 const nsRunningInstancesData: NSInstanceDetails[] = nsdInstancesData.filter((instancesData: NSInstanceDetails) =>
313                     instancesData['operational-status'] === this.nsinstancesoperationalStateRunning);
314                 this.nsData = nsRunningInstancesData;
315                 resolve(true);
316             }, (error: ERRORDATA) => {
317                 this.restService.handleError(error, 'get');
318                 resolve(true);
319             });
320         });
321     }
322
323     /** create map view @private */
324     private osmMapView(): void {
325         this.map = new Map({
326             target: 'map',
327             layers: [new TileLayer({
328                 source: new OSM()
329             })],
330             interactions: defaultInteractions({
331                 mouseWheelZoom: true
332             }),
333             view: new View({
334                 center: fromLonLat([CONSTANTNUMBER.osmapviewlong, CONSTANTNUMBER.osmapviewlat]),
335                 zoom: 3,
336                 minZoom: 1.5
337             })
338         });
339     }
340
341     /** remove the layers and overlay @private */
342     private removeLayersOverLay(): void {
343         this.layers.forEach((layer: VectorLayer) => {
344             this.map.removeLayer(layer);
345         });
346         this.overLay.forEach((lay: Overlay) => {
347             this.map.removeOverlay(lay);
348         });
349     }
350
351     /** filter locations from vimaccounts @private */
352     private arrayOfLocation(): void {
353         this.getLocation = [];
354         this.locationData.filter((item: VimAccountDetails) => {
355             // eslint-disable-next-line no-prototype-builtins
356             if (item.hasOwnProperty('config')) {
357                 // eslint-disable-next-line no-prototype-builtins
358                 if (item.config.hasOwnProperty('location')) {
359                     this.getLocation.push({ name: item.name, location: item.config.location, id: item._id });
360                 }
361             }
362         });
363         if (this.getLocation !== []) {
364             this.getLocation.filter((loc: GetLocation) => {
365                 if (loc.location !== '') {
366                     if (loc.location !== ',,') {
367                         const getLatLong: string[] = loc.location.split(',');
368                         this.lng = +getLatLong[CONSTANTNUMBER.splitLongitude];
369                         this.lat = +getLatLong[CONSTANTNUMBER.splitLatitude];
370                         this.addMarker(getLatLong[0], loc.id, loc.name);
371                     }
372                 }
373             });
374         }
375     }
376     /** add markers on map @private */
377     private addMarker(loc: string, id: string, name: string): void {
378         const container: HTMLElement = document.getElementById('popup');
379         const closer: HTMLElement = document.getElementById('popup-closer');
380         this.popupShow = true;
381         const overlay: Overlay = this.addOverlay(container);
382         this.marker = this.addFeature(loc, id, name);
383         this.setStyleMarker();
384         this.setVectorSource();
385         this.setVectorLayer();
386         this.map.addLayer(this.vectorLayer);
387         this.layers.push(this.vectorLayer);
388         if (this.layers.length === 1) {
389             this.markerClickEvent(closer, overlay);
390         }
391     }
392     /** Create an overlay to anchor the popup to the map @private */
393     private addOverlay(container: HTMLElement): Overlay {
394         return new Overlay({
395             element: container,
396             autoPan: true,
397             autoPanAnimation: {
398                 duration: 250
399             }
400         });
401     }
402     /** Return the Feature of creating a marker in the map @private */
403     private addFeature(loc: string, id: string, name: string): Feature {
404         return new Feature({
405             geometry: new Point(fromLonLat([this.lng, this.lat])),
406             location: loc,
407             Id: id,
408             vimName: name
409         });
410     }
411     /** Set the style of the marker @private */
412     private setStyleMarker(): void {
413         this.marker.setStyle(new Style({
414             image: new Icon(({
415                 crossOrigin: 'anonymous',
416                 src: 'assets/images/map-icon.png'
417             }))
418         }));
419     }
420     /** Set the map vector source @private */
421     private setVectorSource(): void {
422         this.vectorSource = new VectorSource({
423             features: [this.marker]
424         });
425     }
426     /** Set the map vector layer @private */
427     private setVectorLayer(): void {
428         this.vectorLayer = new VectorLayer({
429             source: this.vectorSource
430         });
431     }
432     /** Add a click handler to the map to render the popup. @private */
433     private markerClickEvent(closer: HTMLElement, overlay: Overlay): void {
434         // eslint-disable-next-line @typescript-eslint/no-explicit-any
435         this.map.on('singleclick', (evt: any) => {
436             const feature: Feature = this.map.forEachFeatureAtPixel(evt.pixel,
437                 (f: Feature) => f);
438             if (feature) {
439                 this.setCoordinates(feature, overlay);
440             } else {
441                 this.map.removeOverlay(overlay);
442             }
443         });
444         /** Handle close event for overlay */
445         closer.onclick = (): boolean => {
446             overlay.setPosition(undefined);
447             closer.blur();
448             return false;
449         };
450     }
451     /** Set the coordinates point if the feature is available @private */
452     // eslint-disable-next-line @typescript-eslint/no-explicit-any
453     private setCoordinates(feature: any, overlay: Overlay): void {
454         this.popupData = '';
455         this.popupData += '<h3 class="popover-header">' + feature.values_.vimName + '- (' + feature.values_.location + ')</h3>';
456         this.popupData += '<ul class="list-unstyled m-2">';
457         const instnaceData: NSInstanceDetails[] = this.nsData.filter((item: NSInstanceDetails) => {
458             if (item.datacenter === feature.values_.Id) {
459                 this.popupData += '<li class="m-2"><a class="d-block text-truncate" target="_parent" href="instances/ns/' + item._id + '"><i class="fa-sitemap fas icons mr-1"></i>'
460                     + item.name + '</a></li>';
461                 return item;
462             }
463         });
464         if (instnaceData.length === 0) {
465             this.popupData += '<li class="m-2">' + this.translateService.instant('PAGE.DASHBOARD.NOINSTANCES') + '</li>';
466         }
467         this.popupData += '</ul>';
468         const coordinates: number[] = feature.getGeometry().getCoordinates();
469         overlay.setPosition(coordinates);
470         this.overLay.push(overlay);
471         this.map.addOverlay(overlay);
472     }
473 }
474
475 /** interface for get location */
476 interface GetLocation {
477     location: string;
478     id: string;
479     name?: string;
480 }