You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2022/09/18 16:40:03 UTC
[incubator-streampipes] 03/03: [hotfix] Improve error handling in data explorer
This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git
commit 90bdcf422323a507ecb3fb412057862935d95bdc
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Sun Sep 18 18:39:50 2022 +0200
[hotfix] Improve error handling in data explorer
---
.../apache/streampipes/ps/DataLakeResourceV4.java | 25 +---
.../data-explorer-dashboard-widget.component.html | 139 +++++++++++----------
.../data-explorer-dashboard-widget.component.scss | 4 +
.../data-explorer-dashboard-widget.component.ts | 6 +
.../base/base-data-explorer-widget.directive.ts | 20 ++-
.../widgets/base/data-explorer-widget-data.ts | 7 +-
6 files changed, 108 insertions(+), 93 deletions(-)
diff --git a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java
index f825ae622..840e93933 100644
--- a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java
+++ b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeResourceV4.java
@@ -27,6 +27,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.apache.streampipes.dataexplorer.DataLakeManagementV4;
import org.apache.streampipes.dataexplorer.v4.ProvidedQueryParams;
+import org.apache.streampipes.model.StreamPipesErrorMessage;
import org.apache.streampipes.model.datalake.DataLakeConfiguration;
import org.apache.streampipes.model.datalake.DataLakeMeasure;
import org.apache.streampipes.rest.core.base.impl.AbstractRestResource;
@@ -160,8 +161,8 @@ public class DataLakeResourceV4 extends AbstractRestResource {
try {
SpQueryResult result = this.dataLakeManagement.getData(sanitizedParams);
return ok(result);
- } catch (IllegalArgumentException e) {
- return badRequest(e.getMessage());
+ } catch (RuntimeException e) {
+ return badRequest(StreamPipesErrorMessage.from(e));
}
}
}
@@ -242,25 +243,7 @@ public class DataLakeResourceV4 extends AbstractRestResource {
}
private boolean checkProvidedQueryParams(MultivaluedMap<String, String> providedParams) {
- if (supportedParams.containsAll(providedParams.keySet())) {
- return true;
- } else {
- return false;
- }
- }
-
- private boolean columnsEmpty(MultivaluedMap<String, String> providedParams) {
- if (providedParams.containsKey("columns")) {
- for (String column : providedParams.get("columns")) {
- if ("".equals(column)) {
- return true;
- }
- };
- } else {
- return true;
- }
-
- return false;
+ return supportedParams.containsAll(providedParams.keySet());
}
private ProvidedQueryParams populate(String measurementId, MultivaluedMap<String, String> rawParams) {
diff --git a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html
index ff7bb1f16..828fe498b 100644
--- a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html
+++ b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.html
@@ -17,75 +17,82 @@
-->
<div class="h-100">
- <div class="box"
- [ngStyle]="{background: configuredWidget.baseAppearanceConfig.backgroundColor,
+ <div class="box"
+ [ngStyle]="{background: configuredWidget.baseAppearanceConfig.backgroundColor,
color: configuredWidget.baseAppearanceConfig.textColor,
height: (gridsterItemComponent.height - 13) + 'px',
border: editMode && currentlyConfiguredWidgetId === configuredWidget._id ? '4px solid var(--color-accent)' : '2px solid ' + configuredWidget.baseAppearanceConfig.backgroundColor}"
- [attr.data-cy]="'widget-' + configuredWidget.baseAppearanceConfig.widgetTitle">
- <div class="widget-header h-40" *ngIf="!previewMode">
- <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center" class="widget-header-text">
- {{ configuredWidget.baseAppearanceConfig.widgetTitle }}
- </div>
- <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
- <mat-spinner [diameter]="20" color="primary" class="mr-10" *ngIf="timerActive">
- </mat-spinner>
- <div class="time-counter"
- *ngIf="editMode"
- [ngStyle]="{background: configuredWidget.baseAppearanceConfig.textColor, color: configuredWidget.baseAppearanceConfig.backgroundColor}">
- {{loadingTime}}s
- </div>
- <button mat-button
- mat-icon-button
- [matMenuTriggerFor]="menu"
- aria-label="More options"
- matTooltip="More options"
- *ngIf="!editMode"
- [attr.data-cy]="'more-options-' + configuredWidget.baseAppearanceConfig.widgetTitle">
- <mat-icon>more_vert</mat-icon>
- </button>
- <mat-menu #menu="matMenu">
- <button mat-menu-item
- (click)="downloadDataAsFile()">
- <mat-icon>get_app</mat-icon>
- <span>Download data</span>
- </button>
- <button mat-menu-item
- (click)="startEditMode()"
- *ngIf="hasDataExplorerWritePrivileges"
- [attr.data-cy]="'start-edit-' + configuredWidget.baseAppearanceConfig.widgetTitle">
- <mat-icon>edit</mat-icon>
- <span>Edit Widget</span>
- </button>
- </mat-menu>
- <button mat-button
- mat-icon-button
- *ngIf="editMode"
- (click)="downloadDataAsFile()">
- <mat-icon>get_app</mat-icon>
- </button>
- <button mat-button
- mat-icon-button
- [class.mat-raised-button]="currentlyConfiguredWidgetId === configuredWidget._id"
- (click)="triggerWidgetEditMode()"
- *ngIf="editMode"
- [color]="currentlyConfiguredWidgetId === configuredWidget._id ? 'accent' : ''"
- matTooltip="Edit widget"
- [attr.data-cy]="'edit-' + configuredWidget.baseAppearanceConfig.widgetTitle">
- <mat-icon>edit</mat-icon>
- </button>
- <button mat-button
- mat-icon-button
- (click)="removeWidget()"
- matTooltip="Delete widget"
- *ngIf="editMode && hasDataExplorerDeletePrivileges"
- [attr.data-cy]="'remove-' + configuredWidget.baseAppearanceConfig.widgetTitle">
- <mat-icon>clear</mat-icon>
- </button>
- </div>
- </div>
- <div class="widget-content p-0 gridster-item-content ml-0 mr-0 h-100">
- <ng-template widgetHost class="h-100 p-0"></ng-template>
+ [attr.data-cy]="'widget-' + configuredWidget.baseAppearanceConfig.widgetTitle">
+ <div class="widget-header h-40" *ngIf="!previewMode">
+ <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center" class="widget-header-text">
+ {{ configuredWidget.baseAppearanceConfig.widgetTitle }}
+ </div>
+ <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
+ <mat-spinner [diameter]="20" color="primary" class="mr-10" *ngIf="timerActive">
+ </mat-spinner>
+ <div class="time-counter"
+ *ngIf="editMode"
+ [ngStyle]="{background: configuredWidget.baseAppearanceConfig.textColor, color: configuredWidget.baseAppearanceConfig.backgroundColor}">
+ {{loadingTime}}s
</div>
+ <button mat-button
+ mat-icon-button
+ [matMenuTriggerFor]="menu"
+ aria-label="More options"
+ matTooltip="More options"
+ *ngIf="!editMode"
+ [attr.data-cy]="'more-options-' + configuredWidget.baseAppearanceConfig.widgetTitle">
+ <mat-icon>more_vert</mat-icon>
+ </button>
+ <mat-menu #menu="matMenu">
+ <button mat-menu-item
+ (click)="downloadDataAsFile()">
+ <mat-icon>get_app</mat-icon>
+ <span>Download data</span>
+ </button>
+ <button mat-menu-item
+ (click)="startEditMode()"
+ *ngIf="hasDataExplorerWritePrivileges"
+ [attr.data-cy]="'start-edit-' + configuredWidget.baseAppearanceConfig.widgetTitle">
+ <mat-icon>edit</mat-icon>
+ <span>Edit Widget</span>
+ </button>
+ </mat-menu>
+ <button mat-button
+ mat-icon-button
+ *ngIf="editMode"
+ (click)="downloadDataAsFile()">
+ <mat-icon>get_app</mat-icon>
+ </button>
+ <button mat-button
+ mat-icon-button
+ [class.mat-raised-button]="currentlyConfiguredWidgetId === configuredWidget._id"
+ (click)="triggerWidgetEditMode()"
+ *ngIf="editMode"
+ [color]="currentlyConfiguredWidgetId === configuredWidget._id ? 'accent' : ''"
+ matTooltip="Edit widget"
+ [attr.data-cy]="'edit-' + configuredWidget.baseAppearanceConfig.widgetTitle">
+ <mat-icon>edit</mat-icon>
+ </button>
+ <button mat-button
+ mat-icon-button
+ (click)="removeWidget()"
+ matTooltip="Delete widget"
+ *ngIf="editMode && hasDataExplorerDeletePrivileges"
+ [attr.data-cy]="'remove-' + configuredWidget.baseAppearanceConfig.widgetTitle">
+ <mat-icon>clear</mat-icon>
+ </button>
+ </div>
+ </div>
+ <div class="widget-content p-0 gridster-item-content ml-0 mr-0 h-100">
+ <ng-template widgetHost class="h-100 p-0"></ng-template>
+ <div fxFlex="100"
+ fxLayout="column"
+ fxLayoutAlign="center center"
+ *ngIf="errorMessage">
+ <sp-exception-message [message]="errorMessage"
+ [showDetails]="true"></sp-exception-message>
+ </div>
</div>
+ </div>
</div>
diff --git a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.scss b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.scss
index c7b8cbec6..2128ace62 100644
--- a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.scss
+++ b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.scss
@@ -92,3 +92,7 @@
text-align: center;
}
+.h-0 {
+ height: 0px;
+}
+
diff --git a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts
index 4b25aa970..16dd074e9 100644
--- a/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts
+++ b/ui/src/app/data-explorer/components/widget/data-explorer-dashboard-widget.component.ts
@@ -45,6 +45,7 @@ import { WidgetTypeService } from '../../services/widget-type.service';
import { AuthService } from '../../../services/auth.service';
import { UserPrivilege } from '../../../_enums/user-privilege.enum';
import { DialogService, PanelType } from '@streampipes/shared-ui';
+import { StreamPipesErrorMessage } from '../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
@Component({
selector: 'sp-data-explorer-dashboard-widget',
@@ -103,6 +104,8 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
widgetTypeChangedSubscription: Subscription;
intervalSubscription: Subscription;
+ errorMessage: StreamPipesErrorMessage;
+
@ViewChild(WidgetDirective, {static: true}) widgetHost!: WidgetDirective;
constructor(private dataViewDataExplorerService: DataViewDataExplorerService,
@@ -160,10 +163,12 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
componentRef.instance.gridMode = this.gridMode;
const removeSub = componentRef.instance.removeWidgetCallback.subscribe(ev => this.removeWidget());
const timerSub = componentRef.instance.timerCallback.subscribe(ev => this.handleTimer(ev));
+ const errorSub = componentRef.instance.errorCallback.subscribe(ev => this.errorMessage = ev);
componentRef.onDestroy(destroy => {
removeSub.unsubscribe();
timerSub.unsubscribe();
+ errorSub.unsubscribe();
});
}
@@ -212,4 +217,5 @@ export class DataExplorerDashboardWidgetComponent implements OnInit, OnDestroy {
handleTimer(start: boolean) {
start ? this.startLoadingTimer() : this.stopLoadingTimer();
}
+
}
diff --git a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
index dbd5e90c0..151b50362 100644
--- a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
+++ b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.directive.ts
@@ -27,6 +27,7 @@ import {
DatalakeRestService,
DataViewQueryGeneratorService,
SpQueryResult,
+ StreamPipesErrorMessage,
TimeSettings
} from '@streampipes/platform-services';
import { ResizeService } from '../../../services/resize.service';
@@ -35,7 +36,7 @@ import { Observable, Subject, Subscription, zip } from 'rxjs';
import { DataExplorerFieldProviderService } from '../../../services/data-explorer-field-provider-service';
import { BaseWidgetData } from './data-explorer-widget-data';
import { TimeSelectionService } from '../../../services/time-selection.service';
-import { switchMap } from 'rxjs/operators';
+import { catchError, switchMap } from 'rxjs/operators';
@Directive()
export abstract class BaseDataExplorerWidgetDirective<T extends DataExplorerWidgetModel> implements BaseWidgetData<T>, OnInit, OnDestroy {
@@ -48,6 +49,9 @@ export abstract class BaseDataExplorerWidgetDirective<T extends DataExplorerWidg
@Output()
timerCallback: EventEmitter<boolean> = new EventEmitter();
+ @Output()
+ errorCallback: EventEmitter<StreamPipesErrorMessage> = new EventEmitter<StreamPipesErrorMessage>();
+
@Input() gridsterItem: GridsterItem;
@Input() gridsterItemComponent: GridsterItemComponent;
@Input() editMode: boolean;
@@ -96,9 +100,16 @@ export abstract class BaseDataExplorerWidgetDirective<T extends DataExplorerWidg
const sourceConfigs = this.dataExplorerWidget.dataConfig.sourceConfigs;
this.fieldProvider = this.fieldService.generateFieldLists(sourceConfigs);
- this.requestQueue$.pipe(switchMap((observables) => {
- return zip(...observables);
- })).subscribe(results => {
+ this.requestQueue$
+ .pipe(switchMap((observables) => {
+ this.errorCallback.emit(undefined);
+ return zip(...observables).pipe(catchError((err) => {
+ this.timerCallback.emit(false);
+ this.errorCallback.emit(err.error);
+ return [];
+ }));
+ }))
+ .subscribe(results => {
results.forEach((result, index) => result.sourceIndex = index);
this.validateReceivedData(results);
this.refreshView();
@@ -167,7 +178,6 @@ export abstract class BaseDataExplorerWidgetDirective<T extends DataExplorerWidg
}
private loadData(includeTooMuchEventsParameter: boolean) {
-
let observables: Observable<SpQueryResult>[];
if (includeTooMuchEventsParameter && !this.dataExplorerWidget.dataConfig.ignoreTooMuchDataWarning) {
observables = this
diff --git a/ui/src/app/data-explorer/components/widgets/base/data-explorer-widget-data.ts b/ui/src/app/data-explorer/components/widgets/base/data-explorer-widget-data.ts
index 4c2d109aa..1a75781ce 100644
--- a/ui/src/app/data-explorer/components/widgets/base/data-explorer-widget-data.ts
+++ b/ui/src/app/data-explorer/components/widgets/base/data-explorer-widget-data.ts
@@ -18,11 +18,16 @@
import { EventEmitter } from '@angular/core';
import { GridsterItem, GridsterItemComponent } from 'angular-gridster2';
-import { DashboardItem, DataExplorerWidgetModel, TimeSettings } from '@streampipes/platform-services';
+import {
+ DashboardItem,
+ DataExplorerWidgetModel,
+ StreamPipesErrorMessage,
+ TimeSettings } from '@streampipes/platform-services';
export interface BaseWidgetData<T extends DataExplorerWidgetModel> {
removeWidgetCallback: EventEmitter<boolean>;
timerCallback: EventEmitter<boolean>;
+ errorCallback: EventEmitter<StreamPipesErrorMessage>;
gridsterItem: GridsterItem;
gridsterItemComponent: GridsterItemComponent;