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 { 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';
47 * @Component takes VimAccountDetailsComponent.html as template url
50 selector: 'app-vim-account-details',
51 templateUrl: './VimAccountDetailsComponent.html',
52 styleUrls: ['./VimAccountDetailsComponent.scss']
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 */
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 */
112 /** longitude @private */
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;
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);
131 /** Lifecyle Hooks the trigger before component is instantiate @public */
132 public ngOnInit(): void {
135 this.generateColumns();
136 this.generateSettings();
138 this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
141 /** smart table Header Colums @public */
142 public generateColumns(): void {
144 name: { title: this.translateService.instant('NAME'), width: '15%', sortDirection: 'asc' },
145 identifier: { title: this.translateService.instant('IDENTIFIER'), width: '25%' },
147 title: this.translateService.instant('TYPE'), width: '15%',
151 selectText: 'Select',
157 title: this.translateService.instant('OPERATIONALSTATUS'), width: '15%', type: 'html',
161 selectText: 'Select',
163 { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep },
164 { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep },
165 { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep }
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>
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>
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>
183 return `<span>${row.operationalState}</span>`;
187 description: { title: this.translateService.instant('DESCRIPTION'), width: '25%' },
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
196 /** smart table Data Settings @public */
197 public generateSettings(): void {
200 editButtonContent: '<i class="fa fa-edit" title="Edit"></i>',
204 deleteButtonContent: '<i class="far fa-trash-alt" title="delete"></i>',
207 columns: this.columnLists,
214 attr: this.sharedService.tableClassConfig(),
215 pager: this.sharedService.paginationPagerConfig(),
216 noDataMessage: this.translateService.instant('NODATAMSG')
220 /** smart table listing manipulation @public */
221 public onChange(perPageValue: number): void {
222 this.dataSource.setPaging(1, perPageValue, true);
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);
231 /** on Navigate to Composer Page @public */
232 public composeVIM(): void {
233 this.router.navigate(['vim/new']).catch(() => {
238 /** To show map conatainer @public */
239 public mapView(): void {
240 this.showList = true;
241 this.showMap = false;
243 /** To show listview @public */
244 public listView(): void {
246 this.showList = false;
248 /** Load the datasource appropriatetype @public */
249 public loadDatasource(getdata: VIMData[]): void {
250 if (getdata.length > 0) {
251 this.checkDataClass = 'dataTables_present';
253 this.checkDataClass = 'dataTables_empty';
255 this.dataSource.load(getdata).then((data: boolean) => {
262 /** Generate generateVIMData object from loop and return for the datasource @public */
263 public generateVIMData(vimAccountData: VimAccountDetails): VIMData {
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
276 * Lifecyle hook which get trigger on component destruction
278 public ngOnDestroy(): void {
279 this.generateDataSub.unsubscribe();
282 /** Fetching the data from server to Load in the smarttable @protected */
283 private generateData(): void {
284 this.isLoadingResults = true;
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);
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;
301 }).catch((error: ERRORDATA): void => {
302 this.restService.handleError(error, 'get');
303 this.isLoadingResults = false;
307 /** fetching the nsdata @private */
308 private async getNSData(): Promise<Boolean> {
309 return new Promise<Boolean>((resolve: Function, reject: Function): void => {
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;
316 }, (error: ERRORDATA) => {
317 this.restService.handleError(error, 'get');
323 /** create map view @private */
324 private osmMapView(): void {
327 layers: [new TileLayer({
330 interactions: defaultInteractions({
334 center: fromLonLat([CONSTANTNUMBER.osmapviewlong, CONSTANTNUMBER.osmapviewlat]),
341 /** remove the layers and overlay @private */
342 private removeLayersOverLay(): void {
343 this.layers.forEach((layer: VectorLayer) => {
344 this.map.removeLayer(layer);
346 this.overLay.forEach((lay: Overlay) => {
347 this.map.removeOverlay(lay);
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 });
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);
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);
392 /** Create an overlay to anchor the popup to the map @private */
393 private addOverlay(container: HTMLElement): Overlay {
402 /** Return the Feature of creating a marker in the map @private */
403 private addFeature(loc: string, id: string, name: string): Feature {
405 geometry: new Point(fromLonLat([this.lng, this.lat])),
411 /** Set the style of the marker @private */
412 private setStyleMarker(): void {
413 this.marker.setStyle(new Style({
415 crossOrigin: 'anonymous',
416 src: 'assets/images/map-icon.png'
420 /** Set the map vector source @private */
421 private setVectorSource(): void {
422 this.vectorSource = new VectorSource({
423 features: [this.marker]
426 /** Set the map vector layer @private */
427 private setVectorLayer(): void {
428 this.vectorLayer = new VectorLayer({
429 source: this.vectorSource
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,
439 this.setCoordinates(feature, overlay);
441 this.map.removeOverlay(overlay);
444 /** Handle close event for overlay */
445 closer.onclick = (): boolean => {
446 overlay.setPosition(undefined);
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 {
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>';
464 if (instnaceData.length === 0) {
465 this.popupData += '<li class="m-2">' + this.translateService.instant('PAGE.DASHBOARD.NOINSTANCES') + '</li>';
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);
475 /** interface for get location */
476 interface GetLocation {