71455f5dcf7c7a11b2d7d6f7ddf4e1333bf1af09
[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         };
272     }
273
274     /**
275      * Lifecyle hook which get trigger on component destruction
276      */
277     public ngOnDestroy(): void {
278         this.generateDataSub.unsubscribe();
279     }
280
281     /** Fetching the data from server to Load in the smarttable @protected */
282     private generateData(): void {
283         this.isLoadingResults = true;
284         this.vimData = [];
285         this.getNSData().then((): void => {
286             this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimAccountsData: VimAccountDetails[]) => {
287                 this.locationData = vimAccountsData;
288                 vimAccountsData.forEach((vimAccountData: VimAccountDetails) => {
289                     const vimDataObj: VIMData = this.generateVIMData(vimAccountData);
290                     this.vimData.push(vimDataObj);
291                 });
292                 this.loadDatasource(this.vimData);
293                 this.removeLayersOverLay();
294                 this.arrayOfLocation();
295                 this.isLoadingResults = false;
296             }, (error: ERRORDATA) => {
297                 this.restService.handleError(error, 'get');
298                 this.isLoadingResults = false;
299             });
300         }).catch((error: ERRORDATA): void => {
301             this.restService.handleError(error, 'get');
302             this.isLoadingResults = false;
303         });
304     }
305
306     /** fetching the nsdata @private */
307     private async getNSData(): Promise<Boolean> {
308         return new Promise<Boolean>((resolve: Function, reject: Function): void => {
309             this.nsData = [];
310             this.restService.getResource(environment.NSDINSTANCES_URL).subscribe((nsdInstancesData: NSInstanceDetails[]) => {
311                 const nsRunningInstancesData: NSInstanceDetails[] = nsdInstancesData.filter((instancesData: NSInstanceDetails) =>
312                 instancesData['operational-status'] === this.nsinstancesoperationalStateRunning);
313                 this.nsData = nsRunningInstancesData;
314                 resolve(true);
315             }, (error: ERRORDATA) => {
316                 this.restService.handleError(error, 'get');
317                 resolve(true);
318             });
319         });
320     }
321
322     /** create map view @private */
323     private osmMapView(): void {
324         this.map = new Map({
325             target: 'map',
326             layers: [new TileLayer({
327                 source: new OSM()
328             })],
329             interactions: defaultInteractions({
330                 mouseWheelZoom: true
331             }),
332             view: new View({
333                 center: fromLonLat([CONSTANTNUMBER.osmapviewlong, CONSTANTNUMBER.osmapviewlat]),
334                 zoom: 3
335             })
336         });
337     }
338
339     /** remove the layers and overlay @private */
340     private removeLayersOverLay(): void {
341         this.layers.forEach((layer: VectorLayer) => {
342             this.map.removeLayer(layer);
343         });
344         this.overLay.forEach((lay: Overlay) => {
345             this.map.removeOverlay(lay);
346         });
347     }
348
349     /** filter locations from vimaccounts @private */
350     private arrayOfLocation(): void {
351         this.getLocation = [];
352         this.locationData.filter((item: VimAccountDetails) => {
353             if (item.hasOwnProperty('config')) {
354                 if (item.config.hasOwnProperty('location')) {
355                     this.getLocation.push({ name: item.name, location: item.config.location, id: item._id });
356                 }
357             }
358         });
359         if (this.getLocation !== []) {
360             this.getLocation.filter((loc: GetLocation) => {
361                 if (loc.location !== '') {
362                     const getLatLong: string[] = loc.location.split(',');
363                     this.lng = +getLatLong[CONSTANTNUMBER.splitLongitude];
364                     this.lat = +getLatLong[CONSTANTNUMBER.splitLatitude];
365                     this.addMarker(getLatLong[0], loc.id, loc.name);
366                 }
367             });
368         }
369     }
370     /** add markers on map @private */
371     private addMarker(loc: string, id: string, name: string): void {
372         const container: HTMLElement = document.getElementById('popup');
373         const closer: HTMLElement = document.getElementById('popup-closer');
374         this.popupShow = true;
375         const overlay: Overlay = this.addOverlay(container);
376         this.marker = this.addFeature(loc, id, name);
377         this.setStyleMarker();
378         this.setVectorSource();
379         this.setVectorLayer();
380         this.map.addLayer(this.vectorLayer);
381         this.layers.push(this.vectorLayer);
382         if (this.layers.length === 1) {
383             this.markerClickEvent(closer, overlay);
384         }
385     }
386     /** Create an overlay to anchor the popup to the map @private */
387     private addOverlay(container: HTMLElement): Overlay {
388         return new Overlay({
389             element: container,
390             autoPan: true,
391             autoPanAnimation: {
392                 duration: 250
393             }
394         });
395     }
396     /** Return the Feature of creating a marker in the map @private */
397     private addFeature(loc: string, id: string, name: string): Feature {
398         return new Feature({
399             geometry: new Point(fromLonLat([this.lng, this.lat])),
400             location: loc,
401             Id: id,
402             vimName: name
403         });
404     }
405     /** Set the style of the marker @private */
406     private setStyleMarker(): void {
407         this.marker.setStyle(new Style({
408             image: new Icon(({
409                 crossOrigin: 'anonymous',
410                 src: 'assets/images/map-icon.png'
411             }))
412         }));
413     }
414     /** Set the map vector source @private */
415     private setVectorSource(): void {
416         this.vectorSource = new VectorSource({
417             features: [this.marker]
418         });
419     }
420     /** Set the map vector layer @private */
421     private setVectorLayer(): void {
422         this.vectorLayer = new VectorLayer({
423             source: this.vectorSource
424         });
425     }
426     /** Add a click handler to the map to render the popup. @private */
427     private markerClickEvent(closer: HTMLElement, overlay: Overlay): void {
428         // tslint:disable-next-line: no-any
429         this.map.on('singleclick', (evt: any) => {
430             const feature: Feature = this.map.forEachFeatureAtPixel(evt.pixel,
431                 (f: Feature) => {
432                     return f;
433                 });
434             if (feature) {
435                 this.setCoordinates(feature, overlay);
436             } else {
437                 this.map.removeOverlay(overlay);
438             }
439         });
440         /** Handle close event for overlay */
441         closer.onclick = (): boolean => {
442             overlay.setPosition(undefined);
443             closer.blur();
444             return false;
445         };
446     }
447     /** Set the coordinates point if the feature is available @private */
448     // tslint:disable-next-line: no-any
449     private setCoordinates(feature: any, overlay: Overlay): void {
450         this.popupData = '';
451         this.popupData += '<h3 class="popover-header">' + feature.values_.vimName + '</h3>';
452         this.popupData += '<ul class="list-unstyled m-2">';
453         const instnaceData: NSInstanceDetails[] = this.nsData.filter((item: NSInstanceDetails) => {
454             if (item.datacenter === feature.values_.Id) {
455                 this.popupData += '<li class="m-2"><a class="d-block text-truncate" target="_parent" href="instances/ns/' + item._id + '">'
456                     + item.name + '</a></li>';
457                 return item;
458             }
459         });
460         if (instnaceData.length === 0) {
461             this.popupData += '<li class="m-2">' + this.translateService.instant('PAGE.DASHBOARD.NOINSTANCES') + '</li>';
462         }
463         this.popupData += '</ul>';
464         const coordinates: number[] = feature.getGeometry().getCoordinates();
465         overlay.setPosition(coordinates);
466         this.overLay.push(overlay);
467         this.map.addOverlay(overlay);
468     }
469 }
470
471 /** interface for get location */
472 interface GetLocation {
473     location: string;
474     id: string;
475     name?: string;
476 }