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/streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new c5325ed665 fix(#3182): Remove data views from dashboards after
deletion (#3185)
c5325ed665 is described below
commit c5325ed665065b69b7e9cb9a4ffc48aaa6a4c070
Author: Dominik Riemer <[email protected]>
AuthorDate: Thu Aug 29 15:41:16 2024 +0200
fix(#3182): Remove data views from dashboards after deletion (#3185)
* fix(#3182): Remove data views from dashboards after deletion
* fix(#3182): Adapt deleteViewAndDashboard test to validate data view is
removed from dashboard
* fix(#3182): Remove unused parameter
* fix(#3182): Fix linting
---------
Co-authored-by: Philipp Zehnder <[email protected]>
---
.../DataExplorerWidgetResourceManager.java | 18 +++++++++++++-
.../resource/management/SpResourceManager.java | 5 ++--
.../rest/impl/datalake/DataLakeWidgetResource.java | 10 +++++++-
ui/cypress/support/utils/datalake/DataLakeUtils.ts | 21 +++++++++++-----
.../tests/datalake/deleteViewAndDashboard.spec.ts | 28 +++++++++++++++-------
.../tests/datalake/timeOrderDataView.spec.ts | 2 +-
.../tests/datalake/timeRangeSelectors.spec.ts | 2 +-
.../lib/apis/data-view-data-explorer.service.ts | 7 ++++--
.../data-explorer-dashboard-panel.component.html | 3 ++-
.../data-explorer-data-view.component.html | 6 ++++-
.../data-view/data-explorer-data-view.component.ts | 1 -
.../data-explorer-dashboard-overview.component.ts | 2 +-
.../data-explorer-data-view-overview.component.ts | 3 ++-
.../widget-view/abstract-widget-view.directive.ts | 25 +++++++++++--------
14 files changed, 96 insertions(+), 37 deletions(-)
diff --git
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerWidgetResourceManager.java
b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerWidgetResourceManager.java
index 9176b3bf43..9ec75d026e 100644
---
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerWidgetResourceManager.java
+++
b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerWidgetResourceManager.java
@@ -23,7 +23,23 @@ import org.apache.streampipes.storage.api.CRUDStorage;
public class DataExplorerWidgetResourceManager extends
AbstractCRUDResourceManager<DataExplorerWidgetModel> {
- public
DataExplorerWidgetResourceManager(CRUDStorage<DataExplorerWidgetModel> db) {
+ private final DataExplorerResourceManager dashboardManager;
+
+ public DataExplorerWidgetResourceManager(DataExplorerResourceManager
dashboardManager,
+
CRUDStorage<DataExplorerWidgetModel> db) {
super(db, DataExplorerWidgetModel.class);
+ this.dashboardManager = dashboardManager;
+ }
+
+ @Override
+ public void delete(String elementId) {
+ deleteDataViewsFromDashboard(elementId);
+ super.delete(elementId);
+ }
+
+ private void deleteDataViewsFromDashboard(String widgetElementId) {
+ dashboardManager.findAll().stream()
+ .filter(dashboard -> dashboard.getWidgets().removeIf(w ->
w.getId().equals(widgetElementId)))
+ .forEach(dashboardManager::update);
}
}
diff --git
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/SpResourceManager.java
b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/SpResourceManager.java
index 5f202f4b81..9e080dfa65 100644
---
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/SpResourceManager.java
+++
b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/SpResourceManager.java
@@ -38,8 +38,9 @@ public class SpResourceManager {
return new DataExplorerResourceManager();
}
- public DataExplorerWidgetResourceManager
manageDataExplorerWidget(CRUDStorage<DataExplorerWidgetModel> db) {
- return new DataExplorerWidgetResourceManager(db);
+ public DataExplorerWidgetResourceManager
manageDataExplorerWidget(DataExplorerResourceManager dashboardManager,
+
CRUDStorage<DataExplorerWidgetModel> db) {
+ return new DataExplorerWidgetResourceManager(dashboardManager, db);
}
public DataProcessorResourceManager manageDataProcessors() {
diff --git
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java
index e8743a93a7..099a7502de 100644
---
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java
+++
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java
@@ -20,10 +20,12 @@ package org.apache.streampipes.rest.impl.datalake;
import org.apache.streampipes.model.client.user.Privilege;
import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
+import org.apache.streampipes.resource.management.DataExplorerResourceManager;
import
org.apache.streampipes.resource.management.DataExplorerWidgetResourceManager;
import org.apache.streampipes.resource.management.SpResourceManager;
import
org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
import org.apache.streampipes.rest.security.AuthConstants;
+import org.apache.streampipes.rest.shared.exception.BadRequestException;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -48,6 +50,7 @@ public class DataLakeWidgetResource extends
AbstractAuthGuardedRestResource {
public DataLakeWidgetResource() {
this.resourceManager = new SpResourceManager().manageDataExplorerWidget(
+ new DataExplorerResourceManager(),
getNoSqlStorage().getDataExplorerWidgetStorage()
);
}
@@ -62,7 +65,12 @@ public class DataLakeWidgetResource extends
AbstractAuthGuardedRestResource {
@GetMapping(path = "/{widgetId}", produces =
MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("this.hasReadAuthority() and hasPermission(#elementId,
'READ')")
public ResponseEntity<DataExplorerWidgetModel>
getDataExplorerWidget(@PathVariable("widgetId") String elementId) {
- return ok(resourceManager.find(elementId));
+ var widget = resourceManager.find(elementId);
+ if (widget != null) {
+ return ok(widget);
+ } else {
+ throw new BadRequestException("Could not find widget");
+ }
}
@PutMapping(
diff --git a/ui/cypress/support/utils/datalake/DataLakeUtils.ts
b/ui/cypress/support/utils/datalake/DataLakeUtils.ts
index 396b4c40b8..de72c60baa 100644
--- a/ui/cypress/support/utils/datalake/DataLakeUtils.ts
+++ b/ui/cypress/support/utils/datalake/DataLakeUtils.ts
@@ -147,15 +147,20 @@ export class DataLakeUtils {
this.editDashboard(name);
}
- public static addDataViewToDashboard(dataViewName: string) {
- this.selectTimeRange(
- new Date(2020, 10, 20, 22, 44),
- this.getFutureDate(),
- );
+ public static addDataViewToDashboard(
+ dataViewName: string,
+ ignoreTimeRange = false,
+ ) {
+ if (!ignoreTimeRange) {
+ this.selectTimeRange(
+ new Date(2020, 10, 20, 22, 44),
+ this.getFutureDate(),
+ );
+ }
cy.dataCy('add-data-view-btn-' + dataViewName).click();
}
- public static createAndEditDataView(name: string) {
+ public static createAndEditDataView() {
// Create new data view
cy.dataCy('open-new-data-view').click();
}
@@ -184,6 +189,10 @@ export class DataLakeUtils {
cy.dataCy('save-dashboard-btn', { timeout: 10000 }).click();
}
+ public static getEmptyDashboardInformation() {
+ return cy.dataCy('empty-dashboard');
+ }
+
public static deleteDashboard(dashboardName: string) {
cy.dataCy('delete-dashboard-' + dashboardName, {
timeout: 10000,
diff --git a/ui/cypress/tests/datalake/deleteViewAndDashboard.spec.ts
b/ui/cypress/tests/datalake/deleteViewAndDashboard.spec.ts
index 742a576813..fb4526f187 100644
--- a/ui/cypress/tests/datalake/deleteViewAndDashboard.spec.ts
+++ b/ui/cypress/tests/datalake/deleteViewAndDashboard.spec.ts
@@ -24,13 +24,18 @@ describe('Test Deletion of Data View and Dashboard', () => {
});
it('Perform Test', () => {
+ const dashboard = 'TestDashboard';
+ const dataView = 'TestView';
+
DataLakeUtils.goToDatalake();
- DataLakeUtils.addDataViewAndTableWidget('TestView', 'Persist');
+ DataLakeUtils.addDataViewAndTableWidget(dataView, 'Persist');
DataLakeUtils.saveDataViewConfiguration();
- DataLakeUtils.createAndEditDashboard('TestDashboard');
+ DataLakeUtils.createAndEditDashboard(dashboard);
+
+ DataLakeUtils.addDataViewToDashboard(dataView, true);
DataLakeUtils.saveDashboardConfiguration();
@@ -39,20 +44,27 @@ describe('Test Deletion of Data View and Dashboard', () => {
DataLakeUtils.checkRowsViewsTable(1);
// Click "Delete" but cancel action and check if dashboard and view
are still displayed
- DataLakeUtils.cancelDeleteDashboard('TestDashboard');
+ DataLakeUtils.cancelDeleteDashboard(dashboard);
DataLakeUtils.checkRowsDashboardTable(1);
- DataLakeUtils.cancelDeleteDataView('TestView');
+ DataLakeUtils.cancelDeleteDataView(dataView);
DataLakeUtils.checkRowsViewsTable(1);
- DataLakeUtils.deleteDashboard('TestDashboard');
+ DataLakeUtils.deleteDataView(dataView);
- DataLakeUtils.deleteDataView('TestView');
+ DataLakeUtils.checkRowsViewsTable(0);
- DataLakeUtils.checkRowsDashboardTable(0);
+ DataLakeUtils.editDashboard(dashboard);
- DataLakeUtils.checkRowsViewsTable(0);
+ // Validate that data view is removed from dashboard
+ DataLakeUtils.getEmptyDashboardInformation().should('be.visible');
+
+ DataLakeUtils.saveDashboardConfiguration();
+
+ DataLakeUtils.deleteDashboard(dashboard);
+
+ DataLakeUtils.checkRowsDashboardTable(0);
});
});
diff --git a/ui/cypress/tests/datalake/timeOrderDataView.spec.ts
b/ui/cypress/tests/datalake/timeOrderDataView.spec.ts
index ded730c5df..1b1ee0f222 100644
--- a/ui/cypress/tests/datalake/timeOrderDataView.spec.ts
+++ b/ui/cypress/tests/datalake/timeOrderDataView.spec.ts
@@ -24,7 +24,7 @@ describe('Test Time Order in Data Explorer', () => {
cy.initStreamPipesTest();
DataLakeUtils.loadDataIntoDataLake('datalake/sample.csv', false);
DataLakeUtils.goToDatalake();
- DataLakeUtils.createAndEditDataView('TestView');
+ DataLakeUtils.createAndEditDataView();
});
it('Perform Test with ascending and descending order', () => {
diff --git a/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
b/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
index 68525a5f24..e2a8faff84 100644
--- a/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
+++ b/ui/cypress/tests/datalake/timeRangeSelectors.spec.ts
@@ -45,7 +45,7 @@ describe('Test Time Range Selectors in Data Explorer', () => {
cy.initStreamPipesTest();
DataLakeUtils.loadDataIntoDataLake('datalake/sample.csv', false);
DataLakeUtils.goToDatalake();
- DataLakeUtils.createAndEditDataView('TestView');
+ DataLakeUtils.createAndEditDataView();
});
it('Perform Test', () => {
diff --git
a/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts
b/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts
index 320432ad4a..51e71213c6 100644
---
a/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts
+++
b/ui/projects/streampipes/platform-services/src/lib/apis/data-view-data-explorer.service.ts
@@ -16,8 +16,8 @@
*
*/
-import { HttpClient } from '@angular/common/http';
-import { Observable } from 'rxjs';
+import { HttpClient, HttpErrorResponse } from '@angular/common/http';
+import { catchError, Observable, throwError } from 'rxjs';
import { map } from 'rxjs/operators';
import { Dashboard } from '../model/dashboard/dashboard.model';
import { Injectable } from '@angular/core';
@@ -91,6 +91,9 @@ export class DataViewDataExplorerService {
getWidget(widgetId: string): Observable<DataExplorerWidgetModel> {
return this.http.get(this.dashboardWidgetUrl + '/' + widgetId).pipe(
+ catchError(() => {
+ return throwError(() => new Error('Failed to get widget
data'));
+ }),
map(response => {
return DataExplorerWidgetModel.fromData(
response as DataExplorerWidgetModel,
diff --git
a/ui/src/app/data-explorer/components/dashboard/data-explorer-dashboard-panel.component.html
b/ui/src/app/data-explorer/components/dashboard/data-explorer-dashboard-panel.component.html
index b98fe933a4..437e4004b4 100644
---
a/ui/src/app/data-explorer/components/dashboard/data-explorer-dashboard-panel.component.html
+++
b/ui/src/app/data-explorer/components/dashboard/data-explorer-dashboard-panel.component.html
@@ -63,9 +63,10 @@
fxFlex="100"
fxLayout="column"
fxLayoutAlign="center center"
+ data-cy="empty-dashboard"
>
<h4>
- This data view is empty and doesn't contain any
widgets.
+ This dashboard is empty and doesn't contain any
widgets.
</h4>
</div>
<sp-data-explorer-dashboard-grid
diff --git
a/ui/src/app/data-explorer/components/data-view/data-explorer-data-view.component.html
b/ui/src/app/data-explorer/components/data-view/data-explorer-data-view.component.html
index 52212aeeba..2c8ec433c8 100644
---
a/ui/src/app/data-explorer/components/data-view/data-explorer-data-view.component.html
+++
b/ui/src/app/data-explorer/components/data-view/data-explorer-data-view.component.html
@@ -61,7 +61,11 @@
<mat-drawer-content class="h-100 dashboard-grid">
<div #panel fxFlex="100" fxLayout="column">
<sp-data-explorer-dashboard-widget
- *ngIf="dataView && gridsterItemComponent"
+ *ngIf="
+ dataView &&
+ gridsterItemComponent &&
+ dataView.dataConfig?.sourceConfigs?.length > 0
+ "
[dataViewMode]="true"
[configuredWidget]="dataView"
[gridsterItemComponent]="gridsterItemComponent"
diff --git
a/ui/src/app/data-explorer/components/data-view/data-explorer-data-view.component.ts
b/ui/src/app/data-explorer/components/data-view/data-explorer-data-view.component.ts
index 5a7962aa29..202946c582 100644
---
a/ui/src/app/data-explorer/components/data-view/data-explorer-data-view.component.ts
+++
b/ui/src/app/data-explorer/components/data-view/data-explorer-data-view.component.ts
@@ -133,7 +133,6 @@ export class DataExplorerDataViewComponent
}
createWidget() {
- this.dataLakeMeasure = new DataLakeMeasure();
this.dataView = new DataExplorerWidgetModel();
this.dataView['@class'] =
'org.apache.streampipes.model.datalake.DataExplorerWidgetModel';
diff --git
a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview/data-explorer-dashboard-overview.component.ts
b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview/data-explorer-dashboard-overview.component.ts
index bdd1775596..0bd4507a47 100644
---
a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview/data-explorer-dashboard-overview.component.ts
+++
b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview/data-explorer-dashboard-overview.component.ts
@@ -96,7 +96,7 @@ export class SpDataExplorerDashboardOverviewComponent extends
SpDataExplorerOver
width: '600px',
data: {
title: 'Are you sure you want to delete this dashboard?',
- subtitle: 'This action cannot be reversed!',
+ subtitle: 'This action cannot be undone!',
cancelTitle: 'Cancel',
okTitle: 'Delete Dashboard',
confirmAndCancel: true,
diff --git
a/ui/src/app/data-explorer/components/overview/data-explorer-data-view-overview/data-explorer-data-view-overview.component.ts
b/ui/src/app/data-explorer/components/overview/data-explorer-data-view-overview/data-explorer-data-view-overview.component.ts
index 41908f3519..8c2f128fb3 100644
---
a/ui/src/app/data-explorer/components/overview/data-explorer-data-view-overview/data-explorer-data-view-overview.component.ts
+++
b/ui/src/app/data-explorer/components/overview/data-explorer-data-view-overview/data-explorer-data-view-overview.component.ts
@@ -95,7 +95,8 @@ export class SpDataExplorerDataViewOverviewComponent extends
SpDataExplorerOverv
width: '600px',
data: {
title: 'Are you sure you want to delete this data view?',
- subtitle: 'This action cannot be reversed!',
+ subtitle:
+ 'The data view will be removed from all dashboards as
well. This action cannot be undone!',
cancelTitle: 'Cancel',
okTitle: 'Delete Data View',
confirmAndCancel: true,
diff --git
a/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts
b/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts
index 013b4ae9b9..e5c41221d7 100644
---
a/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts
+++
b/ui/src/app/data-explorer/components/widget-view/abstract-widget-view.directive.ts
@@ -25,8 +25,9 @@ import {
TimeSettings,
} from '@streampipes/platform-services';
import { ResizeService } from '../../services/resize.service';
-import { zip } from 'rxjs';
+import { of, zip } from 'rxjs';
import { DataExplorerWidgetRegistry } from
'../../registry/data-explorer-widget-registry';
+import { catchError } from 'rxjs/operators';
@Directive()
export abstract class AbstractWidgetViewDirective {
@@ -82,7 +83,9 @@ export abstract class AbstractWidgetViewDirective {
loadWidgetConfigs() {
const observables = this.dashboard.widgets.map(w =>
- this.dataViewDataExplorerService.getWidget(w.id),
+ this.dataViewDataExplorerService
+ .getWidget(w.id)
+ .pipe(catchError(() => of(undefined))),
);
zip(...observables).subscribe(results => {
results.forEach(r => {
@@ -117,14 +120,16 @@ export abstract class AbstractWidgetViewDirective {
}
processWidget(widget: DataExplorerWidgetModel) {
- widget.widgetType = this.widgetRegistryService.getWidgetType(
- widget.widgetType,
- );
- this.configuredWidgets.set(widget.elementId, widget);
- this.dataLakeMeasures.set(
- widget.elementId,
- widget.dataConfig.sourceConfigs[0].measure,
- );
+ if (widget !== undefined) {
+ widget.widgetType = this.widgetRegistryService.getWidgetType(
+ widget.widgetType,
+ );
+ this.configuredWidgets.set(widget.elementId, widget);
+ this.dataLakeMeasures.set(
+ widget.elementId,
+ widget.dataConfig.sourceConfigs[0].measure,
+ );
+ }
}
propagateItemRemoval(widgetIndex: number) {