diff --git a/docker/.env b/docker/.env index 61b84f1d..070e69aa 100644 --- a/docker/.env +++ b/docker/.env @@ -190,3 +190,6 @@ MF_TWINS_CHANNEL_ID= MF_TWINS_CACHE_URL=es-redis:6379 MF_TWINS_CACHE_PASS= MF_TWINS_CACHE_DB=0 + +# Grafana +GF_SERVER_ROOT_URL=http://localhost/grafana/ diff --git a/docker/configs/grafana-defaults.ini b/docker/configs/grafana-defaults.ini index 2098edf4..6180c595 100644 --- a/docker/configs/grafana-defaults.ini +++ b/docker/configs/grafana-defaults.ini @@ -45,13 +45,13 @@ domain = localhost enforce_domain = false # The full public facing url -root_url = %(protocol)s://%(domain)s:%(http_port)s/ +root_url = %(protocol)s://%(domain)s:%(http_port)s/grafana # Serve Grafana from subpath specified in `root_url` setting. By default it is set to `false` for compatibility reasons. -serve_from_sub_path = false +serve_from_sub_path = true # Log web requests -router_logging = false +router_logging = true # the path relative working path static_root_path = public @@ -124,7 +124,7 @@ connstr = [dataproxy] # This enables data proxy logging, default is false -logging = false +logging = true # How long the data proxy waits before timing out, default is 30 seconds. # This setting also applies to core backend HTTP data sources where query requests use an HTTP client with timeout set. @@ -202,7 +202,7 @@ cookie_secure = false cookie_samesite = lax # set to true if you want to allow browsers to render Grafana in a , diff --git a/src/app/pages/things/grafana/grafana.details.component.scss b/src/app/pages/things/grafana/grafana.details.component.scss new file mode 100644 index 00000000..7914022d --- /dev/null +++ b/src/app/pages/things/grafana/grafana.details.component.scss @@ -0,0 +1,4 @@ +iframe { + height: 720px; + width: 100%; + } \ No newline at end of file diff --git a/src/app/pages/things/grafana/grafana.details.component.ts b/src/app/pages/things/grafana/grafana.details.component.ts new file mode 100644 index 00000000..02a5964b --- /dev/null +++ b/src/app/pages/things/grafana/grafana.details.component.ts @@ -0,0 +1,76 @@ +import { HttpClient } from '@angular/common/http'; +import { NotificationsService } from './../../../common/services/notifications/notifications.service'; +import { ThingsService } from 'app/common/services/things/things.service'; +import { Thing, Grafana} from 'app/common/interfaces/mainflux.interface'; +import { Component, OnInit,AfterViewInit, ViewChild, ElementRef } from '@angular/core'; +import { DomSanitizer } from '@angular/platform-browser'; +import { environment } from 'environments/environment'; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + selector: 'ngx-grafana-details', + templateUrl: './grafana.details.component.html', + // template:'', + styleUrls: ['./grafana.details.component.scss'], +}) +export class GrafanaDetailsComponent implements OnInit, AfterViewInit { + @ViewChild('iframe', { static: true }) iframeDoc: ElementRef; + grafana: Grafana; + orgId = '1' + iframeGrafana: any; + constructor( + private route: ActivatedRoute, + private domSanitizer: DomSanitizer, + private thingsService: ThingsService, + private http: HttpClient, + private notificationsService: NotificationsService, + ) { + + } + + + ngOnInit() { + // const id = this.route.snapshot.paramMap.get('id'); + // this.thingsService.getThing(id) + // this.thingsService.getThing(id).subscribe( + // (th: Thing) => { + // this.grafana = th.metadata.grafana; + // if (this.grafana !== undefined ){ + // this.http.get(`${environment.grafanaUrl}/${this.grafana.dashboard}?orgId=${this.grafana.orgId}&var-thing=${id}&kiosk`, {responseType: 'text', observe: 'body' }) + // .subscribe(blob => { + // this.iframeGrafana = this.domSanitizer.bypassSecurityTrustHtml(blob); + // }); + + // } else { + // this.notificationsService.warn('No grafana dashboard configured',''); + // } + // }, + // ); + } + + +ngAfterViewInit() { + const id = this.route.snapshot.paramMap.get('id'); + this.thingsService.getThing(id) + this.thingsService.getThing(id).subscribe( + (th: Thing) => { + this.grafana = th.metadata.grafana; + if (this.grafana !== undefined ){ + this.iframeGrafana = this.domSanitizer.bypassSecurityTrustResourceUrl(`${environment.grafanaUrl}/${this.grafana.dashboard}?orgId=${this.grafana.orgId}&var-thing=${id}&kiosk`) + + // this.http.get(`${environment.grafanaUrl}/${this.grafana.dashboard}?orgId=${this.grafana.orgId}&var-thing=${id}&kiosk`, {responseType: 'text', observe: 'body' }) + // .subscribe(blob => { + // let doc = this.iframeDoc.nativeElement.contentDocument || this.iframeDoc.nativeElement.contentWindow; + // doc.open(); + // doc.write(blob); + // doc.close(); + // }); + + } else { + this.notificationsService.warn('No grafana dashboard configured',''); + } + }, + ); + +} +} diff --git a/src/app/pages/things/things.component.html b/src/app/pages/things/things.component.html index e3cf5099..1323eff1 100644 --- a/src/app/pages/things/things.component.html +++ b/src/app/pages/things/things.component.html @@ -37,7 +37,8 @@ [page]="page" (editEvent)=openEditModal($event) (delEvent)=openDeleteModal($event) - (detailsEvent)=onOpenDetails($event)> + (detailsEvent)=onOpenDetails($event) + (grafanaEvent)=onOpenGrafana($event)> diff --git a/src/app/pages/things/things.component.ts b/src/app/pages/things/things.component.ts index 7e74bf10..50fdbe14 100644 --- a/src/app/pages/things/things.component.ts +++ b/src/app/pages/things/things.component.ts @@ -18,8 +18,8 @@ const defSearchBarMs: number = 100; }) export class ThingsComponent implements OnInit { tableConfig: TableConfig = { - colNames: ['', '', '', 'Name', 'Type', 'ID', 'Key'], - keys: ['edit', 'delete', 'details', 'name', 'type', 'id', 'key'], + colNames: ['', '', '', '', 'Name', 'Type', 'ID', 'Key'], + keys: ['edit', 'delete', 'details', 'grafana', 'name', 'type', 'id', 'key'], }; page: TablePage = {}; pageFilters: PageFilters = {}; @@ -114,6 +114,13 @@ export class ThingsComponent implements OnInit { } } + onOpenGrafana(row: any) { + if (row.id) { + this.router.navigate([`${this.router.routerState.snapshot.url}/details/grafana/${row.id}`]); + } + } + + searchThing(input) { const t = new Date().getTime(); if ((t - this.searchTime) > defSearchBarMs) { diff --git a/src/app/pages/user-groups/user-groups.component.html b/src/app/pages/user-groups/user-groups.component.html index 295f4d4d..11f27195 100644 --- a/src/app/pages/user-groups/user-groups.component.html +++ b/src/app/pages/user-groups/user-groups.component.html @@ -12,7 +12,7 @@
+ (input)="searchUserGroupsByName($event.target.value)">
+
+ + +
diff --git a/src/app/shared/components/table/table.component.ts b/src/app/shared/components/table/table.component.ts index 822ad2d7..7daf1c81 100644 --- a/src/app/shared/components/table/table.component.ts +++ b/src/app/shared/components/table/table.component.ts @@ -15,6 +15,7 @@ export class TableComponent { @Output() editEvent: EventEmitter = new EventEmitter(); @Output() delEvent: EventEmitter = new EventEmitter(); @Output() detailsEvent: EventEmitter = new EventEmitter(); + @Output() grafanaEvent: EventEmitter = new EventEmitter(); @Output() checkEvent: EventEmitter = new EventEmitter(); constructor( ) { } @@ -23,6 +24,10 @@ export class TableComponent { this.detailsEvent.emit(row); } + onGrafanaOpen(row: any) { + this.grafanaEvent.emit(row); + } + onEdit(row: any) { this.editEvent.emit(row); } diff --git a/src/environments/environment.defaults.ts b/src/environments/environment.defaults.ts index 60e9b260..26b5058a 100644 --- a/src/environments/environment.defaults.ts +++ b/src/environments/environment.defaults.ts @@ -18,6 +18,7 @@ export const environment = { httpAdapterUrl: '/http', readerUrl: '/reader', + grafanaUrl:'/grafana', readerPrefix: 'channels', readerSuffix: 'messages',