This is an automated email from the ASF dual-hosted git repository. riemer pushed a commit to branch load-dashboard-in-single-request in repository https://gitbox.apache.org/repos/asf/streampipes.git
commit b920d0b989be89c84fe4c44ee69f957e0d27b3b0 Author: Dominik Riemer <[email protected]> AuthorDate: Tue Aug 5 13:20:54 2025 +0200 Improve widget loading in dashboard --- .../impl/dashboard/DataLakeDashboardResource.java | 2 +- .../src/lib/apis/dashboard.service.ts | 16 ++- .../src/lib/model/dashboard/dashboard.model.ts | 13 ++- .../chart-view/abstract-chart-view.directive.ts | 47 +++----- .../grid-view/dashboard-grid-view.component.ts | 16 +-- .../slide-view/dashboard-slide-view.component.ts | 25 ++--- .../panel/dashboard-panel.component.html | 14 ++- .../components/panel/dashboard-panel.component.ts | 120 +++++++++++++-------- .../data-explorer-chart-container.component.ts | 4 +- .../base/base-data-explorer-widget.directive.ts | 7 +- .../charts/image/image-widget.component.ts | 8 +- .../models/dataview-dashboard.model.ts | 4 +- 12 files changed, 146 insertions(+), 130 deletions(-) diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java index 38f6f72177..f97b7083a1 100644 --- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java +++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java @@ -57,7 +57,7 @@ public class DataLakeDashboardResource extends AbstractAuthGuardedRestResource { return getResourceManager().find(dashboardId); } - @GetMapping(path = "/{dashboardId}/full", produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping(path = "/{dashboardId}/composite", produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("this.hasReadAuthority() and hasPermission(#dashboardId, 'READ')") public CompositeDashboardModel getCompositeDashboardModel(@PathVariable("dashboardId") String dashboardId) { return getResourceManager().getCompositeDashboard(dashboardId); diff --git a/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts index 5e7753e257..4a40b03218 100644 --- a/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts +++ b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts @@ -19,9 +19,11 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; import { SharedDatalakeRestService } from './shared-dashboard.service'; -import { Dashboard } from '../model/dashboard/dashboard.model'; +import { + CompositeDashboard, + Dashboard, +} from '../model/dashboard/dashboard.model'; @Injectable({ providedIn: 'root', @@ -37,9 +39,13 @@ export class DashboardService { } getDashboard(dashboardId: string): Observable<Dashboard> { - return this.http - .get(`${this.dashboardUrl}/${dashboardId}`) - .pipe(map(data => data as Dashboard)); + return this.http.get<Dashboard>(`${this.dashboardUrl}/${dashboardId}`); + } + + getCompositeDashboard(dashboardId: string): Observable<CompositeDashboard> { + return this.http.get<CompositeDashboard>( + `${this.dashboardUrl}/${dashboardId}/composite`, + ); } updateDashboard(dashboard: Dashboard): Observable<Dashboard> { diff --git a/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts b/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts index 134490d0ce..927d1a1946 100644 --- a/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts +++ b/ui/projects/streampipes/platform-services/src/lib/model/dashboard/dashboard.model.ts @@ -18,7 +18,12 @@ import { GridsterConfig, GridsterItem } from 'angular-gridster2'; import { TimeSettings } from '../datalake/DateRange'; -import { ResourceMetadata } from '../gen/streampipes-model'; +import { + DashboardModel, + DataExplorerWidgetModel, + DataLakeMeasure, + ResourceMetadata, +} from '../gen/streampipes-model'; // tslint:disable-next-line:no-empty-interface export interface DashboardConfig extends GridsterConfig {} @@ -49,3 +54,9 @@ export interface Dashboard { metadata: ResourceMetadata; rev?: string; } + +export interface CompositeDashboard { + dashboard: Dashboard; + dataLakeMeasures: DataLakeMeasure[]; + widgets: DataExplorerWidgetModel[]; +} diff --git a/ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts b/ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts index f75ab2f283..bf3adc6ad4 100644 --- a/ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts +++ b/ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts @@ -16,7 +16,7 @@ * */ -import { Directive, EventEmitter, Input, Output } from '@angular/core'; +import { Directive, EventEmitter, inject, Input, Output } from '@angular/core'; import { ChartService, Dashboard, @@ -25,13 +25,19 @@ import { TimeSettings, } from '@streampipes/platform-services'; import { ResizeService } from '../../../data-explorer-shared/services/resize.service'; -import { of, zip } from 'rxjs'; import { DataExplorerChartRegistry } from '../../../data-explorer-shared/registry/data-explorer-chart-registry'; -import { catchError } from 'rxjs/operators'; @Directive() export abstract class AbstractChartViewDirective { - _dashboard: Dashboard; + protected resizeService = inject(ResizeService); + protected dataViewDataExplorerService = inject(ChartService); + protected widgetRegistryService = inject(DataExplorerChartRegistry); + + @Input() + dashboard: Dashboard; + + @Input() + widgets: DataExplorerWidgetModel[] = []; @Input() editMode: boolean; @@ -61,39 +67,20 @@ export abstract class AbstractChartViewDirective { @Output() startEditModeEmitter: EventEmitter<DataExplorerWidgetModel> = new EventEmitter<DataExplorerWidgetModel>(); - constructor( - protected resizeService: ResizeService, - protected dataViewDataExplorerService: ChartService, - protected widgetRegistryService: DataExplorerChartRegistry, - ) {} - startEditMode(value: DataExplorerWidgetModel) { this.startEditModeEmitter.emit(value); this.currentlyConfiguredWidgetId = value.elementId; } - @Input() set dashboard(dashboard: Dashboard) { - this._dashboard = dashboard; - this.loadWidgetConfigs(); - } - - get dashboard() { - return this._dashboard; - } - loadWidgetConfigs() { - const observables = this.dashboard.widgets.map(w => - this.dataViewDataExplorerService - .getChart(w.id) - .pipe(catchError(() => of(undefined))), - ); - zip(...observables).subscribe(results => { - results.forEach(r => { - this.processWidget(r); - this.onWidgetsAvailable(); - this.widgetsAvailable = true; - }); + this.dashboard.widgets.forEach(widgetConfig => { + const availableWidget = this.widgets.find( + w => w.elementId === widgetConfig.id, + ); + this.processWidget(availableWidget); }); + this.onWidgetsAvailable(); + this.widgetsAvailable = true; } loadWidgetConfig(widgetId: string, setCurrentlyConfigured?: boolean) { diff --git a/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.ts b/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.ts index 43f8a6a37c..481454a769 100644 --- a/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.ts +++ b/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.ts @@ -27,10 +27,7 @@ import { import { GridsterItemComponent, GridType } from 'angular-gridster2'; import { GridsterInfo } from '../../../../data-explorer-shared/models/gridster-info.model'; import { IDataViewDashboardConfig } from '../../../../data-explorer-shared/models/dataview-dashboard.model'; -import { ResizeService } from '../../../../data-explorer-shared/services/resize.service'; -import { ChartService } from '@streampipes/platform-services'; import { AbstractChartViewDirective } from '../abstract-chart-view.directive'; -import { DataExplorerChartRegistry } from '../../../../data-explorer-shared/registry/data-explorer-chart-registry'; @Component({ selector: 'sp-dashboard-grid-view', @@ -48,19 +45,8 @@ export class DashboardGridViewComponent @ViewChildren(GridsterItemComponent) gridsterItemComponents: QueryList<GridsterItemComponent>; - constructor( - protected resizeService: ResizeService, - protected dataViewDataExplorerService: ChartService, - protected widgetRegistryService: DataExplorerChartRegistry, - ) { - super( - resizeService, - dataViewDataExplorerService, - widgetRegistryService, - ); - } - ngOnInit(): void { + this.loadWidgetConfigs(); this.options = { disablePushOnDrag: true, draggable: { enabled: this.editMode }, diff --git a/ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.ts b/ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.ts index d5169600c6..7d6dd7b283 100644 --- a/ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.ts +++ b/ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.ts @@ -16,16 +16,19 @@ * */ -import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core'; +import { + AfterViewInit, + Component, + ElementRef, + OnInit, + ViewChild, +} from '@angular/core'; import { AbstractChartViewDirective } from '../abstract-chart-view.directive'; -import { ResizeService } from '../../../../data-explorer-shared/services/resize.service'; import { - ChartService, DashboardItem, DataExplorerWidgetModel, DataLakeMeasure, } from '@streampipes/platform-services'; -import { DataExplorerChartRegistry } from '../../../../data-explorer-shared/registry/data-explorer-chart-registry'; @Component({ selector: 'sp-dashboard-slide-view', @@ -35,7 +38,7 @@ import { DataExplorerChartRegistry } from '../../../../data-explorer-shared/regi }) export class DashboardSlideViewComponent extends AbstractChartViewDirective - implements AfterViewInit + implements OnInit, AfterViewInit { selectedWidgetIndex = 0; @@ -49,16 +52,8 @@ export class DashboardSlideViewComponent @ViewChild('slideViewOuter') slideViewOuter: ElementRef; - constructor( - protected resizeService: ResizeService, - protected dataViewDataExplorerService: ChartService, - protected widgetRegistryService: DataExplorerChartRegistry, - ) { - super( - resizeService, - dataViewDataExplorerService, - widgetRegistryService, - ); + ngOnInit() { + this.loadWidgetConfigs(); } selectWidget(index: number, widgetId: string): void { diff --git a/ui/src/app/dashboard/components/panel/dashboard-panel.component.html b/ui/src/app/dashboard/components/panel/dashboard-panel.component.html index ad1f0e154e..d2627f69c7 100644 --- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.html +++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.html @@ -50,11 +50,13 @@ class="designer-panel" > <div fxLayout="column" fxFlex="100"> - <sp-dashboard-chart-selection-panel - (addChartEmitter)="addChartToDashboard($event)" - fxFlex="100" - > - </sp-dashboard-chart-selection-panel> + @if (editMode) { + <sp-dashboard-chart-selection-panel + (addChartEmitter)="addChartToDashboard($event)" + fxFlex="100" + > + </sp-dashboard-chart-selection-panel> + } </div> </mat-drawer> <mat-drawer-content class="h-100 dashboard-grid"> @@ -77,6 +79,7 @@ *ngIf="dashboard.widgets.length > 0 && viewMode === 'grid'" [editMode]="editMode" [dashboard]="dashboard" + [widgets]="widgets" [timeSettings]="timeSettings" (deleteCallback)="removeChartFromDashboard($event)" (startEditModeEmitter)="startEditMode($event)" @@ -88,6 +91,7 @@ #dashboardSlide [editMode]="editMode" [dashboard]="dashboard" + [widgets]="widgets" [timeSettings]="timeSettings" (deleteCallback)="removeChartFromDashboard($event)" (startEditModeEmitter)="startEditMode($event)" diff --git a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts index 5245ab3706..4931bc6417 100644 --- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts +++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts @@ -63,6 +63,7 @@ export class DashboardPanelComponent dashboardLoaded = false; originalDashboard: Dashboard; dashboard: Dashboard; + widgets: DataExplorerWidgetModel[] = []; /** * This is the date range (start, end) to view the data and is set in data-explorer.ts @@ -73,11 +74,8 @@ export class DashboardPanelComponent editMode = false; timeRangeVisible = true; - @ViewChild('dashboardGrid') - dashboardGrid: DashboardGridViewComponent; - - @ViewChild('dashboardSlide') - dashboardSlide: DashboardSlideViewComponent; + _dashboardGrid: DashboardGridViewComponent; + _dashboardSlide: DashboardSlideViewComponent; hasDataExplorerWritePrivileges = false; @@ -133,11 +131,14 @@ export class DashboardPanelComponent dashboardItem.x = 0; dashboardItem.y = 0; this.dashboard.widgets.push(dashboardItem); - if (this.viewMode === 'grid') { - this.dashboardGrid.loadWidgetConfig(dataViewElementId, true); - } else { - this.dashboardSlide.loadWidgetConfig(dataViewElementId, true); - } + setTimeout(() => { + if (this.viewMode === 'grid') { + console.log(this.dashboardGrid); + this.dashboardGrid.loadWidgetConfig(dataViewElementId, true); + } else { + this.dashboardSlide.loadWidgetConfig(dataViewElementId, true); + } + }); } setShouldShowConfirm(): boolean { @@ -207,42 +208,49 @@ export class DashboardPanelComponent } getDashboard(dashboardId: string, startTime: number, endTime: number) { - this.dashboardService.getDashboard(dashboardId).subscribe(dashboard => { - this.dashboard = dashboard; - this.originalDashboard = JSON.parse(JSON.stringify(dashboard)); - this.breadcrumbService.updateBreadcrumb( - this.breadcrumbService.makeRoute( - [SpDashboardRoutes.BASE], - this.dashboard.name, - ), - ); - this.viewMode = - this.dashboard.dashboardGeneralSettings.defaultViewMode || - 'grid'; - if ( - this.dashboard.dashboardGeneralSettings.globalTimeEnabled === - undefined - ) { - this.dashboard.dashboardGeneralSettings.globalTimeEnabled = - true; - } - if (!this.dashboard.dashboardTimeSettings.startTime) { - this.dashboard.dashboardTimeSettings = - this.timeSelectionService.getDefaultTimeSettings(); - } else { - this.timeSelectionService.updateTimeSettings( - this.timeSelectionService.defaultQuickTimeSelections, - this.dashboard.dashboardTimeSettings, - new Date(), + this.dashboardService + .getCompositeDashboard(dashboardId) + .subscribe(compositeDashboard => { + this.dashboard = compositeDashboard.dashboard; + this.widgets = compositeDashboard.widgets; + this.originalDashboard = JSON.parse( + JSON.stringify(compositeDashboard.dashboard), ); - } - this.timeSettings = - startTime && endTime - ? this.overrideTime(+startTime, +endTime) - : this.dashboard.dashboardTimeSettings; - this.dashboardLoaded = true; - this.modifyRefreshInterval(this.dashboard.dashboardLiveSettings); - }); + this.breadcrumbService.updateBreadcrumb( + this.breadcrumbService.makeRoute( + [SpDashboardRoutes.BASE], + this.dashboard.name, + ), + ); + this.viewMode = + this.dashboard.dashboardGeneralSettings.defaultViewMode || + 'grid'; + if ( + this.dashboard.dashboardGeneralSettings + .globalTimeEnabled === undefined + ) { + this.dashboard.dashboardGeneralSettings.globalTimeEnabled = + true; + } + if (!this.dashboard.dashboardTimeSettings.startTime) { + this.dashboard.dashboardTimeSettings = + this.timeSelectionService.getDefaultTimeSettings(); + } else { + this.timeSelectionService.updateTimeSettings( + this.timeSelectionService.defaultQuickTimeSelections, + this.dashboard.dashboardTimeSettings, + new Date(), + ); + } + this.timeSettings = + startTime && endTime + ? this.overrideTime(+startTime, +endTime) + : this.dashboard.dashboardTimeSettings; + this.dashboardLoaded = true; + this.modifyRefreshInterval( + this.dashboard.dashboardLiveSettings, + ); + }); } overrideTime(startTime: number, endTime: number): TimeSettings { @@ -322,4 +330,26 @@ export class DashboardPanelComponent ) .subscribe(); } + + @ViewChild('dashboardGrid', { static: false }) + set dashboardGrid(v: DashboardGridViewComponent) { + if (v) { + this._dashboardGrid = v; + } + } + + get dashboardGrid(): DashboardGridViewComponent { + return this._dashboardGrid; + } + + @ViewChild('dashboardSlide', { static: false }) + set dashboardSlide(v: DashboardSlideViewComponent) { + if (v) { + this._dashboardSlide = v; + } + } + + get dashboardSlide(): DashboardSlideViewComponent { + return this._dashboardSlide; + } } diff --git a/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.ts b/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.ts index 373774462a..fb13faf5bb 100644 --- a/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.ts +++ b/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.ts @@ -31,7 +31,7 @@ import { } from '@angular/core'; import { GridsterItemComponent } from 'angular-gridster2'; import { - DashboardItem, + ClientDashboardItem, DataExplorerWidgetModel, DataLakeMeasure, ExtendedTimeSettings, @@ -70,7 +70,7 @@ export class DataExplorerChartContainerComponent @ViewChild('timeSelectorMenu') timeSelectorMenu: TimeRangeSelectorMenuComponent; @Input() - dashboardItem: DashboardItem; + dashboardItem: ClientDashboardItem; @Input() configuredWidget: DataExplorerWidgetModel; diff --git a/ui/src/app/data-explorer-shared/components/charts/base/base-data-explorer-widget.directive.ts b/ui/src/app/data-explorer-shared/components/charts/base/base-data-explorer-widget.directive.ts index 5db3fea62a..508dc62ff5 100644 --- a/ui/src/app/data-explorer-shared/components/charts/base/base-data-explorer-widget.directive.ts +++ b/ui/src/app/data-explorer-shared/components/charts/base/base-data-explorer-widget.directive.ts @@ -28,11 +28,10 @@ import { import { GridsterItem, GridsterItemComponent } from 'angular-gridster2'; import { ChartConfigurationService } from '../../../services/chart-configuration.service'; import { - DashboardItem, + ClientDashboardItem, DataExplorerDataConfig, DataExplorerField, DataExplorerWidgetModel, - DatalakeRestService, DataViewQueryGeneratorService, SpLogMessage, SpQueryResult, @@ -80,7 +79,7 @@ export abstract class BaseDataExplorerWidgetDirective< @Input() gridMode = true; - @Input() dataViewDashboardItem: DashboardItem; + @Input() dataViewDashboardItem: ClientDashboardItem; @Input() dataExplorerWidget: T; @Input() @@ -110,8 +109,6 @@ export abstract class BaseDataExplorerWidgetDirective< Observable<SpQueryResult>[] >(); - // inject services to avoid constructor overload - protected dataLakeRestService = inject(DatalakeRestService); protected widgetConfigurationService = inject(ChartConfigurationService); protected resizeService = inject(ResizeService); protected dataViewQueryGeneratorService = inject( diff --git a/ui/src/app/data-explorer-shared/components/charts/image/image-widget.component.ts b/ui/src/app/data-explorer-shared/components/charts/image/image-widget.component.ts index 79875aae08..c66e0cbed2 100644 --- a/ui/src/app/data-explorer-shared/components/charts/image/image-widget.component.ts +++ b/ui/src/app/data-explorer-shared/components/charts/image/image-widget.component.ts @@ -16,11 +16,12 @@ * */ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, inject, OnInit, ViewChild } from '@angular/core'; import { MatSort } from '@angular/material/sort'; import { BaseDataExplorerWidgetDirective } from '../base/base-data-explorer-widget.directive'; import { DataExplorerField, + DatalakeRestService, SpQueryResult, } from '@streampipes/platform-services'; import { ImageWidgetModel } from './model/image-widget.model'; @@ -45,9 +46,8 @@ export class ImageWidgetComponent canvasWidth; imagePreviewHeight; - constructor(private securePipe: SecurePipe) { - super(); - } + private securePipe = inject(SecurePipe); + private dataLakeRestService = inject(DatalakeRestService); ngOnInit(): void { super.ngOnInit(); diff --git a/ui/src/app/data-explorer-shared/models/dataview-dashboard.model.ts b/ui/src/app/data-explorer-shared/models/dataview-dashboard.model.ts index ca0d5b9b62..57f4089b1b 100644 --- a/ui/src/app/data-explorer-shared/models/dataview-dashboard.model.ts +++ b/ui/src/app/data-explorer-shared/models/dataview-dashboard.model.ts @@ -22,7 +22,7 @@ import { GridsterItemComponent, } from 'angular-gridster2'; import { - DashboardItem, + ClientDashboardItem, DataExplorerField, DataExplorerWidgetModel, SpLogMessage, @@ -50,7 +50,7 @@ export interface BaseWidgetData<T extends DataExplorerWidgetModel> { timeSettings: TimeSettings; - dataViewDashboardItem: DashboardItem; + dataViewDashboardItem: ClientDashboardItem; dataExplorerWidget: T; previewMode: boolean; gridMode: boolean;
