Skip to content

Commit a718aea

Browse files
committed
feat: enhance chart components with refresh service integration and async data handling
1 parent 8e01af2 commit a718aea

21 files changed

+764
-161
lines changed

frontend/src/app/dashboard/dashboard-render/dashboard-render.component.html

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ <h5 class="card-title mb-0 label-header">{{dashboard.name}}
44
</h5>
55
<div class="header-elements d-flex justify-content-end align-items-center">
66
<app-dashboard-filter-view [filters]="filters"></app-dashboard-filter-view>
7+
<app-refresh-filter></app-refresh-filter>
78
<app-elastic-filter-time [invertContent]="true"
89
[isEmitter]="true"
9-
class="ml-3"
1010
container="body"></app-elastic-filter-time>
11-
<button (click)="exportToPdf()" [disabled]="pdfExport || !visualizationRender || loadingVisualizations"
11+
<button (click)="exportToPdf()" [disabled]="pdfExport || loadingVisualizations"
1212
class="btn utm-button utm-button-primary ml-2">
1313
<i [ngClass]="pdfExport?'icon-download10':'icon-file-pdf'" class="mr-1"></i>
1414
{{pdfExport ? 'Generating...' : 'Save to PDF'}}
@@ -17,21 +17,20 @@ <h5 class="card-title mb-0 label-header">{{dashboard.name}}
1717
</div>
1818
</div>
1919
<div class="w-100 h-100 mb-3">
20-
<gridster *ngIf="layout.length>0 && !loadingVisualizations"
21-
[options]="options" style="background-color: #f1f1f1;z-index: 0; margin-bottom: 15px">
20+
<gridster [options]="options" style="background-color: #f1f1f1;z-index: 0; margin-bottom: 15px">
2221
<gridster-item #gridsterItem
23-
*ngFor="let item of layout; let index = index" [item]="item.grid"
22+
*ngFor="let item of layout$ | async; trackBy: trackByFn; let index = index" [item]="item.grid"
2423
(mouseenter)="activeTimeGridster=item.visualization.id"
2524
[ngStyle]="{'z-index':(activeTimeGridster===item.visualization.id?100:0)+''}">
26-
<app-utm-viewer [building]="false"
27-
style="z-index: 10"
28-
[chart]="item.visualization.chartType"
29-
[chartId]="item.visualization.id"
30-
[height]="(gridsterItem.height-38)+'px'"
31-
[showTime]="timeEnable.includes(item.visualization.id)"
32-
[visualization]="item.visualization"
33-
[width]="gridsterItem.width+'px'">
34-
</app-utm-viewer>
25+
<app-utm-viewer [building]="false"
26+
style="z-index: 10"
27+
[chart]="item.visualization.chartType"
28+
[chartId]="item.visualization.id"
29+
[height]="(gridsterItem.height-38)+'px'"
30+
[showTime]="item.visualization.showTime"
31+
[visualization]="item.visualization"
32+
[width]="gridsterItem.width+'px'">
33+
</app-utm-viewer>
3534
</gridster-item>
3635
</gridster>
3736
<div style="height: 15px"></div>

frontend/src/app/dashboard/dashboard-render/dashboard-render.component.ts

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import {AfterViewInit, ChangeDetectorRef, Component, OnDestroy, OnInit} from '@angular/core';
2-
import {ActivatedRoute} from '@angular/router';
3-
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
1+
import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit} from '@angular/core';
2+
import {ActivatedRoute, Router} from '@angular/router';
43
import {CompactType, GridsterConfig, GridsterItem, GridType} from 'angular-gridster2';
54
import {UUID} from 'angular2-uuid';
5+
import {NgxSpinnerService} from 'ngx-spinner';
6+
import {Observable} from 'rxjs';
7+
import {map, tap} from 'rxjs/operators';
68
import {IComponent} from '../../graphic-builder/dashboard-builder/shared/services/layout.service';
79
import {rebuildVisualizationFilterTime} from '../../graphic-builder/shared/util/chart-filter/chart-filter.util';
810
import {DashboardBehavior} from '../../shared/behaviors/dashboard.behavior';
@@ -11,20 +13,20 @@ import {UtmDashboardVisualizationType} from '../../shared/chart/types/dashboard/
1113
import {UtmDashboardType} from '../../shared/chart/types/dashboard/utm-dashboard.type';
1214
import {VisualizationType} from '../../shared/chart/types/visualization.type';
1315
import {ChartTypeEnum} from '../../shared/enums/chart-type.enum';
16+
import {ExportPdfService} from '../../shared/services/util/export-pdf.service';
17+
import {RefreshService} from '../../shared/services/util/refresh.service';
1418
import {DashboardFilterType} from '../../shared/types/filter/dashboard-filter.type';
1519
import {ElasticFilterType} from '../../shared/types/filter/elastic-filter.type';
1620
import {mergeParams, sanitizeFilters} from '../../shared/util/elastic-filter.util';
1721
import {filtersToStringParam} from '../../shared/util/query-params-to-filter.util';
1822
import {normalizeString} from '../../shared/util/string-util';
1923
import {RenderLayoutService} from '../shared/services/render-layout.service';
20-
import {UtmRenderVisualization} from '../shared/services/utm-render-visualization.service';
21-
import {ExportPdfService} from "../../shared/services/util/export-pdf.service";
22-
import {NgxSpinnerService} from "ngx-spinner";
2324

2425
@Component({
2526
selector: 'app-dashboard-render',
2627
templateUrl: './dashboard-render.component.html',
27-
styleUrls: ['./dashboard-render.component.scss']
28+
styleUrls: ['./dashboard-render.component.scss'],
29+
changeDetection: ChangeDetectionStrategy.OnPush
2830
})
2931
export class DashboardRenderComponent implements OnInit, OnDestroy, AfterViewInit {
3032
dashboardId: number;
@@ -59,25 +61,37 @@ export class DashboardRenderComponent implements OnInit, OnDestroy, AfterViewIni
5961
swap: false
6062
};
6163
filtersValues: ElasticFilterType[] = [];
62-
timeEnable: number[] = [];
64+
layout$: Observable<{ grid: GridsterItem, visualization: VisualizationType } []>;
6365

6466
constructor(private activatedRoute: ActivatedRoute,
6567
private layoutService: RenderLayoutService,
6668
private cdr: ChangeDetectorRef,
67-
private modalService: NgbModal,
6869
private dashboardBehavior: DashboardBehavior,
6970
private timeFilterBehavior: TimeFilterBehavior,
70-
private utmRenderVisualization: UtmRenderVisualization,
7171
private exportPdfService: ExportPdfService,
72-
private spinner: NgxSpinnerService) {
72+
private spinner: NgxSpinnerService,
73+
private refreshService: RefreshService,
74+
private router: Router) {
7375
}
7476

7577
ngOnInit() {
76-
console.log('Init dashboard');
77-
7878
document.body.classList.add('overflow-hidden');
7979
this.loadingVisualizations = true;
80-
this.activatedRoute.params.subscribe(params => {
80+
this.layout$ = this.activatedRoute.data
81+
.pipe(
82+
tap((visualizations) => {
83+
this.dashboard = this.layoutService.dashboard;
84+
this.filters = this.dashboard && this.dashboard.filters ? JSON.parse(this.dashboard.filters) : [];
85+
/* if (this.dashboard.refreshTime) {
86+
console.log(this.dashboard.refreshTime);
87+
this.onRefreshTime(this.dashboard.refreshTime);
88+
}*/
89+
this.loadingVisualizations = false;
90+
}),
91+
map(data => data.response)
92+
);
93+
94+
/*this.activatedRoute.params.subscribe(params => {
8195
this.dashboardId = params.id;
8296
if (this.dashboardId) {
8397
const request = {
@@ -105,14 +119,15 @@ export class DashboardRenderComponent implements OnInit, OnDestroy, AfterViewIni
105119
this.loadingVisualizations = false;
106120
});
107121
}
108-
});
122+
});*/
109123
this.dashboardBehavior.$filterDashboard.subscribe(dashboardFilter => {
110124
if (dashboardFilter) {
111125
mergeParams(dashboardFilter.filter, this.filtersValues).then(newFilters => {
112126
this.filtersValues = sanitizeFilters(newFilters);
113127
});
114128
}
115129
});
130+
116131
this.timeFilterBehavior.$time.subscribe(time => {
117132
if (time) {
118133
rebuildVisualizationFilterTime({timeFrom: time.from, timeTo: time.to}, this.filtersValues).then(filters => {
@@ -146,9 +161,7 @@ export class DashboardRenderComponent implements OnInit, OnDestroy, AfterViewIni
146161
ngOnDestroy(): void {
147162
document.body.classList.remove('overflow-hidden');
148163
clearInterval(this.interval);
149-
this.visualizationRender = [];
150-
this.layoutService.layout = [];
151-
this.timeEnable = [];
164+
this.layoutService.clearLayout();
152165
this.dashboardBehavior.$filterDashboard.next(null);
153166
}
154167

@@ -164,7 +177,7 @@ export class DashboardRenderComponent implements OnInit, OnDestroy, AfterViewIni
164177
exportToPdf() {
165178
filtersToStringParam(this.filtersValues).then(queryParams => {
166179
this.spinner.show('buildPrintPDF');
167-
const url = '/dashboard/export/' + this.dashboardId + '/' + normalizeString(this.dashboard.name) + '?' + queryParams;
180+
const url = '/dashboard/export/' + this.dashboard.id + '/' + normalizeString(this.dashboard.name) + '?' + queryParams;
168181
// window.open('/dashboard/export/' + this.dashboardId + '/' + normalizeString(this.dashboard.name) + '?' + queryParams, '_blank');
169182
this.exportPdfService.getPdf(url, this.dashboard.name, 'PDF_TYPE_TOKEN').subscribe(response => {
170183
this.spinner.hide('buildPrintPDF').then(() =>
@@ -175,5 +188,9 @@ export class DashboardRenderComponent implements OnInit, OnDestroy, AfterViewIni
175188
});
176189
});
177190
}
191+
192+
trackByFn(index: number, item: { grid: GridsterItem, visualization: VisualizationType }) {
193+
return item.visualization.id;
194+
}
178195
}
179196

frontend/src/app/dashboard/dashboard-routing.module.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {DashboardOverviewComponent} from './dashboard-overview/dashboard-overvie
1010
import {DashboardRenderComponent} from './dashboard-render/dashboard-render.component';
1111
import {DashboardViewComponent} from './dashboard-view/dashboard-view.component';
1212
import {ReportExportComponent} from './report-export/report-export.component';
13+
import {DashboardResolverService} from './shared/services/dashboard-resolver.service';
1314

1415
const routes: Routes = [
1516
{path: '', redirectTo: 'overview', pathMatch: 'full'},
@@ -35,7 +36,10 @@ const routes: Routes = [
3536
path: 'render/:id/:dashboard',
3637
component: DashboardRenderComponent,
3738
canActivate: [UserRouteAccessService],
38-
data: {authorities: [USER_ROLE, ADMIN_ROLE]}
39+
data: {authorities: [USER_ROLE, ADMIN_ROLE]},
40+
resolve: {
41+
response: DashboardResolverService
42+
}
3943
},
4044
{
4145
path: 'export/:id/:dashboard',

frontend/src/app/dashboard/dashboard.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {DashboardRoutingModule} from './dashboard-routing.module';
1919
import {DashboardViewComponent} from './dashboard-view/dashboard-view.component';
2020
import {ReportExportComponent} from './report-export/report-export.component';
2121
import {UtmDashboardSharedModule} from './shared/utm-dashboard-shared.module';
22+
import {DashboardResolverService} from "./shared/services/dashboard-resolver.service";
2223

2324
@NgModule({
2425
declarations: [DashboardViewComponent,
@@ -43,6 +44,9 @@ import {UtmDashboardSharedModule} from './shared/utm-dashboard-shared.module';
4344
VulnerabilitySharedModule,
4445
GridsterModule
4546
],
47+
providers: [
48+
DashboardResolverService
49+
],
4650
entryComponents: [DashboardExportPreviewComponent],
4751
exports: [
4852
DashboardViewComponent
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import {Injectable, Type} from '@angular/core';
2+
import {ActivatedRouteSnapshot, Resolve, RouterStateSnapshot} from '@angular/router';
3+
import {GridsterItem} from 'angular-gridster2';
4+
import {NgxSpinnerService} from 'ngx-spinner';
5+
import {Observable} from 'rxjs';
6+
import {map, tap} from 'rxjs/operators';
7+
import {VisualizationType} from '../../../shared/chart/types/visualization.type';
8+
import {RenderLayoutService} from './render-layout.service';
9+
import {UtmRenderVisualization} from './utm-render-visualization.service';
10+
11+
@Injectable()
12+
export class DashboardResolverService implements Resolve<{ grid: GridsterItem, visualization: VisualizationType } []> {
13+
14+
constructor(private spinner: NgxSpinnerService,
15+
private utmRenderVisualization: UtmRenderVisualization,
16+
private layoutService: RenderLayoutService) {
17+
}
18+
19+
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
20+
Observable<{ grid: GridsterItem, visualization: VisualizationType } []> {
21+
const request = {
22+
page: 0,
23+
size: 10000,
24+
'idDashboard.equals': route.params.id,
25+
sort: 'order,asc'
26+
};
27+
this.spinner.show('loadingSpinner');
28+
return this.utmRenderVisualization.query(request)
29+
.pipe(
30+
map((response) => {
31+
this.layoutService.clearLayout();
32+
const visualizations = response.body;
33+
this.layoutService.dashboard = visualizations.length > 0 ? visualizations[0].dashboard : null;
34+
35+
visualizations.forEach((vis) => {
36+
const visualization: VisualizationType = {...vis.visualization, showTime: vis.showTimeFilter};
37+
this.layoutService.addItem(visualization, JSON.parse(vis.gridInfo));
38+
});
39+
40+
return this.layoutService.layout;
41+
}
42+
),
43+
tap(() => {
44+
this.spinner.hide('loadingSpinner');
45+
}));
46+
}
47+
}

frontend/src/app/dashboard/shared/services/render-layout.service.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {Injectable} from '@angular/core';
22
import {GridsterItem} from 'angular-gridster2';
33
import {UUID} from 'angular2-uuid';
4+
import {UtmDashboardType} from '../../../shared/chart/types/dashboard/utm-dashboard.type';
45
import {VisualizationType} from '../../../shared/chart/types/visualization.type';
56

67

@@ -13,8 +14,9 @@ export interface IComponent {
1314
providedIn: 'root'
1415
})
1516
export class RenderLayoutService {
16-
public layout: { grid: GridsterItem, visualization: VisualizationType } [] = [];
17+
private _layout: { grid: GridsterItem, visualization: VisualizationType } [] = [];
1718
public components: IComponent[] = [];
19+
private _dashboard: UtmDashboardType;
1820

1921
dropId: string;
2022

@@ -25,7 +27,7 @@ export class RenderLayoutService {
2527
}
2628

2729
addItem(vis: VisualizationType, grid?: GridsterItem): void {
28-
this.layout.push({
30+
this._layout.push({
2931
grid: grid ? grid : {
3032
cols: 10,
3133
id: UUID.UUID(),
@@ -37,4 +39,20 @@ export class RenderLayoutService {
3739
});
3840
}
3941

42+
get layout() {
43+
return [...this._layout];
44+
}
45+
46+
get dashboard() {
47+
return this._dashboard;
48+
}
49+
50+
set dashboard(dashboard: UtmDashboardType) {
51+
this._dashboard = {...dashboard };
52+
}
53+
54+
clearLayout() {
55+
this._layout = [];
56+
this._dashboard = null;
57+
}
4058
}

frontend/src/app/dashboard/shared/services/utm-render-visualization.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import {Injectable} from '@angular/core';
33
import {Observable} from 'rxjs';
44
import {SERVER_API_URL} from '../../../app.constants';
55
import {UtmDashboardVisualizationType} from '../../../shared/chart/types/dashboard/utm-dashboard-visualization.type';
6-
import {createRequestOption} from '../../../shared/util/request-util';
76
import {RefreshDataService} from '../../../shared/services/util/refresh-data.service';
7+
import {createRequestOption} from '../../../shared/util/request-util';
88

99

1010
@Injectable({

frontend/src/app/graphic-builder/shared/components/viewer/chart-view/chart-view.component.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
[invertContent]="true">
1212
</app-elastic-filter-time>
1313
</div>
14-
<div [ngStyle]="{'height':height,'width':width}" class="card-body p-0 chart-container">
14+
<div *ngIf="data$ | async as data"
15+
[ngStyle]="{'height':height,'width':width}"
16+
class="card-body p-0 chart-container">
1517
<div *ngIf="loadingOption"
1618
class="loading-chart w-100 h-100
1719
d-flex justify-content-center
@@ -24,7 +26,7 @@
2426
class="h-100 w-100">
2527
<app-no-data-chart [error]="runWithError" [typeChart]="chart"></app-no-data-chart>
2628
</div>
27-
<div (chartClick)="chartEvent($event)"
29+
<div (chartClick)="chartEvent($event, data)"
2830
*ngIf="!loadingOption && data && echartOption && data.length>0"
2931
[autoResize]="true"
3032
[ngStyle]="{'height':height}"

0 commit comments

Comments
 (0)