18dffa069d9cea9a2ae386ddac12f633292a06e8
[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             if (item.hasOwnProperty('config')) {
356                 if (item.config.hasOwnProperty('location')) {
357                     this.getLocation.push({ name: item.name, location: item.config.location, id: item._id });
358                 }
359             }
360         });
361         if (this.getLocation !== []) {
362             this.getLocation.filter((loc: GetLocation) => {
363                 if (loc.location !== '') {
364                     const getLatLong: string[] = loc.location.split(',');
365                     this.lng = +getLatLong[CONSTANTNUMBER.splitLongitude];
366                     this.lat = +getLatLong[CONSTANTNUMBER.splitLatitude];
367                     this.addMarker(getLatLong[0], loc.id, loc.name);
368                 }
369             });
370         }
371     }
372     /** add markers on map @private */
373     private addMarker(loc: string, id: string, name: string): void {
374         const container: HTMLElement = document.getElementById('popup');
375         const closer: HTMLElement = document.getElementById('popup-closer');
376         this.popupShow = true;
377         const overlay: Overlay = this.addOverlay(container);
378         this.marker = this.addFeature(loc, id, name);
379         this.setStyleMarker();
380         this.setVectorSource();
381         this.setVectorLayer();
382         this.map.addLayer(this.vectorLayer);
383         this.layers.push(this.vectorLayer);
384         if (this.layers.length === 1) {
385             this.markerClickEvent(closer, overlay);
386         }
387     }
388     /** Create an overlay to anchor the popup to the map @private */
389     private addOverlay(container: HTMLElement): Overlay {
390         return new Overlay({
391             element: container,
392             autoPan: true,
393             autoPanAnimation: {
394                 duration: 250
395             }
396         });
397     }
398     /** Return the Feature of creating a marker in the map @private */
399     private addFeature(loc: string, id: string, name: string): Feature {
400         return new Feature({
401             geometry: new Point(fromLonLat([this.lng, this.lat])),
402             location: loc,
403             Id: id,
404             vimName: name
405         });
406     }
407     /** Set the style of the marker @private */
408     private setStyleMarker(): void {
409         this.marker.setStyle(new Style({
410             image: new Icon(({
411                 crossOrigin: 'anonymous',
412                 src: 'assets/images/map-icon.png'
413             }))
414         }));
415     }
416     /** Set the map vector source @private */
417     private setVectorSource(): void {
418         this.vectorSource = new VectorSource({
419             features: [this.marker]
420         });
421     }
422     /** Set the map vector layer @private */
423     private setVectorLayer(): void {
424         this.vectorLayer = new VectorLayer({
425             source: this.vectorSource
426         });
427     }
428     /** Add a click handler to the map to render the popup. @private */
429     private markerClickEvent(closer: HTMLElement, overlay: Overlay): void {
430         // tslint:disable-next-line: no-any
431         this.map.on('singleclick', (evt: any) => {
432             const feature: Feature = this.map.forEachFeatureAtPixel(evt.pixel,
433                 (f: Feature) => {
434                     return f;
435                 });
436             if (feature) {
437                 this.setCoordinates(feature, overlay);
438             } else {
439                 this.map.removeOverlay(overlay);
440             }
441         });
442         /** Handle close event for overlay */
443         closer.onclick = (): boolean => {
444             overlay.setPosition(undefined);
445             closer.blur();
446             return false;
447         };
448     }
449     /** Set the coordinates point if the feature is available @private */
450     // tslint:disable-next-line: no-any
451     private setCoordinates(feature: any, overlay: Overlay): void {
452         this.popupData = '';
453         this.popupData += '<h3 class="popover-header">' + feature.values_.vimName + '- (' + feature.values_.location + ')</h3>';
454         this.popupData += '<ul class="list-unstyled m-2">';
455         const instnaceData: NSInstanceDetails[] = this.nsData.filter((item: NSInstanceDetails) => {
456             if (item.datacenter === feature.values_.Id) {
457                 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>'
458                     + item.name + '</a></li>';
459                 return item;
460             }
461         });
462         if (instnaceData.length === 0) {
463             this.popupData += '<li class="m-2">' + this.translateService.instant('PAGE.DASHBOARD.NOINSTANCES') + '</li>';
464         }
465         this.popupData += '</ul>';
466         const coordinates: number[] = feature.getGeometry().getCoordinates();
467         overlay.setPosition(coordinates);
468         this.overLay.push(overlay);
469         this.map.addOverlay(overlay);
470     }
471 }
472
473 /** interface for get location */
474 interface GetLocation {
475     location: string;
476     id: string;
477     name?: string;
478 }