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 9c36aabf2c feat(#3992): Improve widget handling in dashboard (#4011)
9c36aabf2c is described below

commit 9c36aabf2cdb65d98f6e7cbf00e7d74203fb02cf
Author: Dominik Riemer <[email protected]>
AuthorDate: Wed Dec 3 21:21:17 2025 +0100

    feat(#3992): Improve widget handling in dashboard (#4011)
---
 .../streampipes/model/dashboard/DashboardItem.java |  37 +++
 .../management/DataExplorerResourceManager.java    |   3 +-
 .../datalake/KioskDashboardDataLakeResource.java   |   2 +-
 .../core/migrations/AvailableMigrations.java       |   4 +-
 .../v099/UniqueDashboardIdMigration.java           |  73 +++++
 ui/package-lock.json                               |  32 +--
 ui/package.json                                    |   2 +-
 .../streampipes/platform-services/package.json     |   3 +-
 .../src/lib/model/dashboard/dashboard.model.ts     |  15 +-
 .../static-free-input.component.ts                 |   1 -
 .../kiosk/dashboard-kiosk.component.html           |   4 +-
 .../kiosk/dashboard-kiosk.component.scss           |   1 +
 .../components/kiosk/dashboard-kiosk.component.ts  |   2 +-
 .../chart-view/abstract-chart-view.directive.ts    |  39 +--
 .../grid-view/dashboard-grid-view.component.html   |  70 +++--
 .../grid-view/dashboard-grid-view.component.scss   |  31 +--
 .../grid-view/dashboard-grid-view.component.ts     |  87 +++---
 .../slide-view/dashboard-slide-view.component.html |   6 +-
 .../slide-view/dashboard-slide-view.component.ts   |  33 +--
 .../dashboard-shared/dashboard-shared.module.ts    |   4 +-
 .../chart-selection-panel.component.html           |   5 -
 .../panel/dashboard-panel.component.scss           |   2 +-
 .../components/panel/dashboard-panel.component.ts  |  28 +-
 ui/src/app/dashboard/dashboard.module.ts           |   2 -
 .../data-explorer-chart-container.component.html   | 298 ++++++++++-----------
 .../data-explorer-chart-container.component.scss   |   4 +-
 .../data-explorer-chart-container.component.ts     |  98 ++++---
 .../base/base-data-explorer-widget.directive.ts    |  66 ++---
 .../charts/base/echarts-widget.component.html      |   2 +-
 .../charts/base/echarts-widget.component.ts        |  20 +-
 .../charts/gauge/gauge-renderer.service.ts         |  10 +-
 .../charts/heatmap/heatmap-renderer.service.ts     |   5 +-
 .../charts/image/image-widget.component.ts         |   5 +-
 .../charts/status/status-widget.component.html     |  19 +-
 .../charts/status/status-widget.component.scss     |  22 +-
 .../charts/status/status-widget.component.ts       |  11 +-
 .../charts/table/table-widget.component.ts         |   2 +-
 .../traffic-light-widget.component.html            |  40 +--
 .../traffic-light-widget.component.scss            |  37 ++-
 .../traffic-light-widget.component.ts              |  20 +-
 .../data-explorer-shared.module.ts                 |   2 -
 .../models/dataview-dashboard.model.ts             |  13 +-
 .../models/gridster-info.model.ts                  |   9 +-
 .../services/resize.service.ts                     |   6 +-
 .../data-explorer-chart-view.component.html        |   5 +-
 .../data-explorer-chart-view.component.ts          |  14 +-
 ui/src/app/data-explorer/data-explorer.module.ts   |   3 -
 ui/src/app/editor/editor.module.ts                 |   2 -
 ui/src/scss/main.scss                              |   2 +
 49 files changed, 587 insertions(+), 614 deletions(-)

diff --git 
a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java
 
b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java
index 81759642cb..108cfd68ef 100644
--- 
a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java
+++ 
b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java
@@ -25,6 +25,7 @@ public class DashboardItem {
   private String id;
   private String name;
   private String component;
+  private String dataViewElementId;
 
   private List<String> settings;
 
@@ -33,6 +34,9 @@ public class DashboardItem {
   private Integer x;
   private Integer y;
   private Map<String, Object> timeSettings;
+  private String widgetId;
+  private Integer w;
+  private Integer h;
 
   public DashboardItem() {
 
@@ -109,4 +113,37 @@ public class DashboardItem {
   public void setTimeSettings(Map<String, Object> timeSettings) {
     this.timeSettings = timeSettings;
   }
+
+  @Deprecated(since = "0.99.0", forRemoval = true)
+  public String getWidgetId() {
+    return widgetId;
+  }
+
+  public void setWidgetId(String widgetId) {
+    this.widgetId = widgetId;
+  }
+
+  public Integer getW() {
+    return w;
+  }
+
+  public void setW(Integer w) {
+    this.w = w;
+  }
+
+  public Integer getH() {
+    return h;
+  }
+
+  public void setH(Integer h) {
+    this.h = h;
+  }
+
+  public String getDataViewElementId() {
+    return dataViewElementId;
+  }
+
+  public void setDataViewElementId(String dataViewElementId) {
+    this.dataViewElementId = dataViewElementId;
+  }
 }
diff --git 
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
 
b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
index 6a2f8cf867..a55d0fb42e 100644
--- 
a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
+++ 
b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/DataExplorerResourceManager.java
@@ -40,7 +40,8 @@ public class DataExplorerResourceManager extends 
CrudResourceManager<DashboardMo
 
   public CompositeDashboardModel getCompositeDashboard(String dashboardId) {
     var dashboard = db.getElementById(dashboardId);
-    var widgets = dashboard.getWidgets().stream().map(w -> 
widgetStorage.getElementById(w.getId())).toList();
+    var widgets = dashboard.getWidgets().stream()
+        .map(w -> 
widgetStorage.getElementById(w.getDataViewElementId())).toList();
     var dataLakeMeasures = 
getMeasureNames(widgets).stream().map(dataLakeMeasureStorage::getByMeasureName).toList();
 
     return new CompositeDashboardModel(dashboard, widgets, dataLakeMeasures);
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/KioskDashboardDataLakeResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/KioskDashboardDataLakeResource.java
index 76f99977fd..885fd80dff 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/KioskDashboardDataLakeResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/KioskDashboardDataLakeResource.java
@@ -76,7 +76,7 @@ public class KioskDashboardDataLakeResource extends 
AbstractAuthGuardedRestResou
                                    @PathVariable("widgetId") String widgetId,
                                    @RequestBody Map<String, String> 
queryParams) {
     var dashboard = dashboardStorage.getElementById(dashboardId);
-    if (dashboard.getWidgets().stream().noneMatch(w -> 
w.getId().equals(widgetId))) {
+    if (dashboard.getWidgets().stream().noneMatch(w -> 
w.getDataViewElementId().equals(widgetId))) {
       return badRequest(String.format("Widget with id %s not found in 
dashboard", widgetId));
     }
     var widget = dataExplorerWidgetStorage.getElementById(widgetId);
diff --git 
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/AvailableMigrations.java
 
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/AvailableMigrations.java
index deedfd63ca..c1f72c466c 100644
--- 
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/AvailableMigrations.java
+++ 
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/AvailableMigrations.java
@@ -34,6 +34,7 @@ import 
org.apache.streampipes.service.core.migrations.v099.AddAssetManagementVie
 import 
org.apache.streampipes.service.core.migrations.v099.CreateAssetPermissionMigration;
 import 
org.apache.streampipes.service.core.migrations.v099.MoveAssetContentMigration;
 import 
org.apache.streampipes.service.core.migrations.v099.RemoveObsoletePrivilegesMigration;
+import 
org.apache.streampipes.service.core.migrations.v099.UniqueDashboardIdMigration;
 import 
org.apache.streampipes.service.core.migrations.v970.AddDataLakePipelineTemplateMigration;
 import 
org.apache.streampipes.service.core.migrations.v970.AddLinkSettingsMigration;
 import 
org.apache.streampipes.service.core.migrations.v970.AddRolesToUserDbMigration;
@@ -68,7 +69,8 @@ public class AvailableMigrations {
         new AddAssetManagementViewMigration(),
         new MoveAssetContentMigration(),
         new CreateAssetPermissionMigration(),
-        new RemoveObsoletePrivilegesMigration()
+        new RemoveObsoletePrivilegesMigration(),
+        new UniqueDashboardIdMigration()
     );
   }
 }
diff --git 
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/v099/UniqueDashboardIdMigration.java
 
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/v099/UniqueDashboardIdMigration.java
new file mode 100644
index 0000000000..4bdd2bfe6b
--- /dev/null
+++ 
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/v099/UniqueDashboardIdMigration.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.service.core.migrations.v099;
+
+import org.apache.streampipes.model.dashboard.DashboardModel;
+import org.apache.streampipes.service.core.migrations.Migration;
+import org.apache.streampipes.storage.api.CRUDStorage;
+import org.apache.streampipes.storage.management.StorageDispatcher;
+
+import org.apache.commons.lang3.RandomStringUtils;
+
+import java.io.IOException;
+import java.util.Objects;
+
+public class UniqueDashboardIdMigration implements Migration {
+
+  private final CRUDStorage<DashboardModel> dashboardStorage;
+  private static final String Prefix = "sp:dataexplorerwidgetmodel";
+
+  public UniqueDashboardIdMigration() {
+    this.dashboardStorage = 
StorageDispatcher.INSTANCE.getNoSqlStore().getDataExplorerDashboardStorage();
+  }
+
+  @Override
+  public boolean shouldExecute() {
+    return dashboardStorage
+        .findAll()
+        .stream()
+        .anyMatch(d -> d.getWidgets()
+            .stream()
+            .anyMatch(w -> Objects.nonNull(w.getId()) && 
w.getId().startsWith(Prefix)));
+  }
+
+  @Override
+  public void executeMigration() throws IOException {
+    var allDashboards = dashboardStorage.findAll();
+
+    allDashboards.forEach(d -> {
+      d.getWidgets().forEach(w -> {
+        if (Objects.nonNull(w.getId()) && w.getId().startsWith(Prefix)) {
+          w.setDataViewElementId(w.getId());
+          var uniqueDashboardWidgetId = Objects.nonNull(w.getId())
+              ? w.getId()
+              : RandomStringUtils.randomAlphanumeric(16);
+          w.setId(uniqueDashboardWidgetId);
+          w.setWidgetId(null);
+        }
+      });
+      dashboardStorage.updateElement(d);
+    });
+  }
+
+  @Override
+  public String getDescription() {
+    return "Moving dashboard widget IDs to dataViewElementId field and 
generating new unique IDs for widgets.";
+  }
+}
diff --git a/ui/package-lock.json b/ui/package-lock.json
index eba111ede7..1049ed3bb5 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -31,7 +31,6 @@
         "@ngx-translate/core": "^16.0.4",
         "@ngx-translate/http-loader": "^16.0.1",
         "@panzoom/panzoom": "^4.5.1",
-        "angular-gridster2": "^19.0.0",
         "codemirror": "^5.65.11",
         "console-browserify": "^1.2.0",
         "d3-array": "^3.2.4",
@@ -41,6 +40,7 @@
         "echarts": "^5.6.0",
         "echarts-simple-transform": "^1.0.0",
         "file-saver": "2.0.5",
+        "gridstack": "^12.3.3",
         "jquery": "^3.7.0",
         "jquery-ui-dist": "1.13.2",
         "jshint": "^2.13.6",
@@ -7857,20 +7857,6 @@
         "ajv": "^8.8.2"
       }
     },
-    "node_modules/angular-gridster2": {
-      "version": "19.0.0",
-      "resolved": 
"https://registry.npmjs.org/angular-gridster2/-/angular-gridster2-19.0.0.tgz";,
-      "integrity": 
"sha512-82SHZzwOmGRvR77VtbpV5Eh7CoTtxLslwOVzTYB3qNQIGGFaOsS8nRAuYpZOlZpVc+n6fBz1HU0yP0icnQ9ppg==",
-      "license": "MIT",
-      "dependencies": {
-        "tslib": "^2.4.0"
-      },
-      "peerDependencies": {
-        "@angular/common": "^19.0.0",
-        "@angular/core": "^19.0.0",
-        "rxjs": "^7.0.0"
-      }
-    },
     "node_modules/ansi-colors": {
       "version": "4.1.3",
       "resolved": 
"https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz";,
@@ -12581,6 +12567,22 @@
         "lodash": "^4.17.15"
       }
     },
+    "node_modules/gridstack": {
+      "version": "12.3.3",
+      "resolved": 
"https://registry.npmjs.org/gridstack/-/gridstack-12.3.3.tgz";,
+      "integrity": 
"sha512-Bboi4gj7HXGnx1VFXQNde4Nwi5srdUSuCCnOSszKhFjBs8EtMEWhsKX02BjIKkErq/FjQUkNUbXUYeQaVMQ0jQ==",
+      "funding": [
+        {
+          "type": "paypal",
+          "url": "https://www.paypal.me/alaind831";
+        },
+        {
+          "type": "venmo",
+          "url": "https://www.venmo.com/adumesny";
+        }
+      ],
+      "license": "MIT"
+    },
     "node_modules/hachure-fill": {
       "version": "0.5.2",
       "resolved": 
"https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz";,
diff --git a/ui/package.json b/ui/package.json
index a7fca186b3..de4d772674 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -52,7 +52,6 @@
     "@ngx-translate/core": "^16.0.4",
     "@ngx-translate/http-loader": "^16.0.1",
     "@panzoom/panzoom": "^4.5.1",
-    "angular-gridster2": "^19.0.0",
     "codemirror": "^5.65.11",
     "console-browserify": "^1.2.0",
     "d3-array": "^3.2.4",
@@ -61,6 +60,7 @@
     "date-fns": "^3.6.0",
     "echarts": "^5.6.0",
     "echarts-simple-transform": "^1.0.0",
+    "gridstack": "^12.3.3",
     "file-saver": "2.0.5",
     "jquery": "^3.7.0",
     "jquery-ui-dist": "1.13.2",
diff --git a/ui/projects/streampipes/platform-services/package.json 
b/ui/projects/streampipes/platform-services/package.json
index 9ed63a5dd7..49bd897560 100644
--- a/ui/projects/streampipes/platform-services/package.json
+++ b/ui/projects/streampipes/platform-services/package.json
@@ -6,8 +6,7 @@
     "@angular/core": "^19.2.13",
     "@angular/platform-browser": "^19.2.13",
     "@ngx-loading-bar/http-client": "6.0.2",
-    "rxjs": "^7.8.0",
-    "angular-gridster2": "^19.0.0"
+    "rxjs": "^7.8.0"
   },
   "dependencies": {
     "tslib": "^2.6.2"
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 70c2e3e3ef..7ae48ef399 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
@@ -16,23 +16,24 @@
  *
  */
 
-import { GridsterConfig, GridsterItem } from 'angular-gridster2';
 import { TimeSettings } from '../datalake/DateRange';
 import {
-    DashboardModel,
     DataExplorerWidgetModel,
     DataLakeMeasure,
     ResourceMetadata,
 } from '../gen/streampipes-model';
 
-// tslint:disable-next-line:no-empty-interface
-export interface DashboardConfig extends GridsterConfig {}
-
-export interface ClientDashboardItem extends GridsterItem {
-    widgetId: string;
+export interface ClientDashboardItem {
+    dataViewElementId: string;
     widgetType: string;
     timeSettings?: TimeSettings;
     id: string;
+    cols?: number;
+    rows?: number;
+    x: number;
+    y: number;
+    w?: number;
+    h?: number;
 }
 
 export interface DashboardLiveSettings {
diff --git 
a/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts
 
b/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts
index f5a963b626..1ca578e426 100644
--- 
a/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts
+++ 
b/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts
@@ -72,7 +72,6 @@ export class StaticFreeInputComponent
         this.addValidator(this.staticProperty.value, this.collectValidators());
         this.enableValidators();
         this.emitUpdate();
-        console.log(this.staticProperty);
     }
 
     collectValidators() {
diff --git 
a/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.html 
b/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.html
index c6550df07e..401e6e2b15 100644
--- a/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.html
+++ b/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.html
@@ -18,7 +18,7 @@
 
 <div
     fxLayout="column"
-    style="height: 100vh"
+    style="height: 100%"
     class="light-mode w-100 standalone-outer"
 >
     <mat-toolbar class="standalone-toolbar">
@@ -55,7 +55,7 @@
             </div>
         </div>
     </mat-toolbar>
-    <div fxLayout="column" style="height: calc(100vh - 40px)">
+    <div fxLayout="column" style="height: calc(100% - 40px)">
         @if (dashboard) {
             @if (dashboard?.widgets.length > 0) {
                 <sp-dashboard-grid-view
diff --git 
a/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.scss 
b/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.scss
index 0937b31c4c..76ab40d896 100644
--- a/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.scss
+++ b/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.scss
@@ -22,6 +22,7 @@
 
 .standalone-outer {
     background: var(--color-bg-1);
+    min-height: 100vh;
 }
 
 .dashboard-grid {
diff --git 
a/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.ts 
b/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.ts
index 1e7009994e..b4ccb7154a 100644
--- a/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.ts
+++ b/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.ts
@@ -63,7 +63,7 @@ export class DashboardKioskComponent implements OnInit, 
OnDestroy {
                 if (res.ok) {
                     const cd = res.body;
                     cd.dashboard.widgets.forEach(w => {
-                        w.widgetId ??=
+                        w.id ??=
                             
this.dataExplorerDashboardService.makeUniqueWidgetId();
                     });
                     const eTag = res.headers.get('ETag');
diff --git 
a/ui/src/app/dashboard-shared/components/chart-view/abstract-chart-view.directive.ts
 
b/ui/src/app/dashboard-shared/components/chart-view/abstract-chart-view.directive.ts
index 324bae85f1..0b18b81cc3 100644
--- 
a/ui/src/app/dashboard-shared/components/chart-view/abstract-chart-view.directive.ts
+++ 
b/ui/src/app/dashboard-shared/components/chart-view/abstract-chart-view.directive.ts
@@ -19,18 +19,17 @@
 import { Directive, EventEmitter, inject, Input, Output } from '@angular/core';
 import {
     ChartService,
+    ClientDashboardItem,
     Dashboard,
     DataExplorerWidgetModel,
     DataLakeMeasure,
     TimeSettings,
 } from '@streampipes/platform-services';
-import { ResizeService } from 
'../../../data-explorer-shared/services/resize.service';
 import { DataExplorerChartRegistry } from 
'../../../data-explorer-shared/registry/data-explorer-chart-registry';
 import { ObservableGenerator } from 
'../../../data-explorer-shared/models/dataview-dashboard.model';
 
 @Directive()
 export abstract class AbstractChartViewDirective {
-    protected resizeService = inject(ResizeService);
     protected dataViewDataExplorerService = inject(ChartService);
     protected widgetRegistryService = inject(DataExplorerChartRegistry);
 
@@ -43,9 +42,6 @@ export abstract class AbstractChartViewDirective {
     @Input()
     editMode: boolean;
 
-    @Input()
-    currentlyConfiguredWidgetId: string;
-
     @Input()
     observableGenerator: ObservableGenerator;
 
@@ -73,13 +69,14 @@ export abstract class AbstractChartViewDirective {
 
     startEditMode(value: DataExplorerWidgetModel) {
         this.startEditModeEmitter.emit(value);
-        this.currentlyConfiguredWidgetId = value.elementId;
     }
 
     loadWidgetConfigs() {
         this.dashboard.widgets.forEach(widgetConfig => {
+            widgetConfig.w ??= widgetConfig.cols;
+            widgetConfig.h ??= widgetConfig.rows;
             const availableWidget = this.widgets.find(
-                w => w.elementId === widgetConfig.id,
+                w => w.elementId === widgetConfig.dataViewElementId,
             );
             this.processWidget(availableWidget);
         });
@@ -87,23 +84,16 @@ export abstract class AbstractChartViewDirective {
         this.widgetsAvailable = true;
     }
 
-    loadWidgetConfig(widgetId: string, setCurrentlyConfigured?: boolean) {
+    loadWidgetConfig(dashboardItem: ClientDashboardItem) {
         if (!this.isGridView()) {
             this.widgetsAvailable = false;
         }
         this.dataViewDataExplorerService
-            .getChart(widgetId)
+            .getChart(dashboardItem.dataViewElementId)
             .subscribe(response => {
                 this.processWidget(response);
-                if (setCurrentlyConfigured) {
-                    this.propagateWidgetSelection(
-                        this.configuredWidgets.get(widgetId),
-                    );
-                    if (!this.isGridView()) {
-                        this.selectNewWidget(widgetId);
-                    }
-                }
                 if (!this.isGridView()) {
+                    this.selectNewWidget(dashboardItem.id);
                     this.widgetsVisible = true;
                 }
                 this.widgetsAvailable = true;
@@ -123,21 +113,6 @@ export abstract class AbstractChartViewDirective {
         }
     }
 
-    propagateItemRemoval(widgetIndex: number) {
-        this.deleteCallback.emit(widgetIndex);
-    }
-
-    propagateWidgetSelection(configuredWidget: DataExplorerWidgetModel) {
-        if (configuredWidget) {
-            this.currentlyConfiguredWidgetId = configuredWidget.elementId;
-        } else {
-            this.currentlyConfiguredWidgetId = undefined;
-        }
-        this.onOptionsChanged();
-    }
-
-    abstract onOptionsChanged(): void;
-
     abstract onWidgetsAvailable(): void;
 
     abstract isGridView(): boolean;
diff --git 
a/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.html
 
b/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.html
index cfa89e8de7..5929888514 100644
--- 
a/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.html
+++ 
b/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.html
@@ -22,41 +22,39 @@
         <h3>{{ dashboard.description }}</h3>
     </div>
 }
-<gridster
-    [options]="options"
-    [ngClass]="editMode ? 'edit' : ''"
-    class="custom-gridster-style"
+<gridstack
+    [options]="gridOptions"
+    (changeCB)="onGridChange($event)"
+    class="dashboard-outer"
+    #grid
 >
-    @for (item of dashboard.widgets; let i = $index; track item.widgetId) {
-        <ng-container>
-            <gridster-item
-                [item]="item"
-                #gridsterItemComponent
-                class="widget-outer"
-            >
-                @if (widgetsAvailable && configuredWidgets.has(item.id)) {
-                    <sp-data-explorer-chart-container
-                        [ngStyle]="{
-                            height: gridsterItemComponent.height - 13 + 'px'
-                        }"
-                        [timeSettings]="timeSettings"
-                        [globalTimeEnabled]="
-                            
dashboard.dashboardGeneralSettings.globalTimeEnabled
-                        "
-                        (deleteCallback)="propagateItemRemoval($event)"
-                        (startEditModeEmitter)="startEditMode($event)"
-                        [dashboardItem]="item"
-                        [configuredWidget]="configuredWidgets.get(item.id)"
-                        [dataLakeMeasure]="dataLakeMeasures.get(item.id)"
-                        [observableGenerator]="observableGenerator"
-                        [editMode]="editMode"
-                        [kioskMode]="kioskMode"
-                        [gridMode]="true"
-                        [widgetIndex]="i"
-                        [gridsterItemComponent]="gridsterItemComponent"
-                    ></sp-data-explorer-chart-container>
-                }
-            </gridster-item>
-        </ng-container>
+    @for (item of dashboard.widgets; let i = $index; track item.id) {
+        <gridstack-item [options]="item">
+            @if (
+                widgetsAvailable &&
+                configuredWidgets.has(item.dataViewElementId)
+            ) {
+                <sp-data-explorer-chart-container
+                    [timeSettings]="timeSettings"
+                    [globalTimeEnabled]="
+                        dashboard.dashboardGeneralSettings.globalTimeEnabled
+                    "
+                    (deleteCallback)="deleteCallback.emit($event)"
+                    (startEditModeEmitter)="startEditMode($event)"
+                    [dashboardItem]="item"
+                    [configuredWidget]="
+                        configuredWidgets.get(item.dataViewElementId)
+                    "
+                    [dataLakeMeasure]="
+                        dataLakeMeasures.get(item.dataViewElementId)
+                    "
+                    [observableGenerator]="observableGenerator"
+                    [editMode]="editMode"
+                    [kioskMode]="kioskMode"
+                    [gridMode]="true"
+                    [widgetIndex]="i"
+                ></sp-data-explorer-chart-container>
+            }
+        </gridstack-item>
     }
-</gridster>
+</gridstack>
diff --git 
a/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.scss
 
b/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.scss
index 77cf1cf14c..98b6560038 100644
--- 
a/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.scss
+++ 
b/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.scss
@@ -16,33 +16,10 @@
  *
  */
 
-gridster.custom-gridster-style ::ng-deep {
-    background: var(--color-bg-1);
-}
-
-gridster.custom-gridster-style.edit ::ng-deep {
-    background: var(--mat-color-bg-1);
-}
-
-gridster.scrollVertical ::ng-deep {
-    min-height: 100%;
-    display: flex;
-    flex: 1 1 100%;
-}
-
-::ng-deep gridster.custom-gridster-style > .gridster-row {
-    border-bottom: 1px solid var(--mat-sys-outline-variant);
-    border-top: 1px solid var(--mat-sys-outline-variant);
-}
-
-::ng-deep gridster.custom-gridster-style > div.gridster-column {
-    border-left: 1px solid var(--mat-sys-outline-variant);
-    border-right: 1px solid var(--mat-sys-outline-variant);
-}
-
 .widget-outer {
-    //box-shadow:
-    //    rgba(50, 50, 93, 0.25) 0px 2px 5px -1px,
-    //    rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
     border: 1px solid var(--color-bg-2);
 }
+
+.dashboard-outer {
+    margin: 5px;
+}
diff --git 
a/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.ts
 
b/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.ts
index 4e8d67e906..cf0d893425 100644
--- 
a/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.ts
+++ 
b/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.ts
@@ -17,22 +17,17 @@
  */
 
 import {
+    AfterViewInit,
     Component,
     Input,
     OnChanges,
     OnInit,
-    QueryList,
     SimpleChanges,
-    ViewChildren,
+    ViewChild,
 } from '@angular/core';
-import {
-    DisplayGrid,
-    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 { AbstractChartViewDirective } from '../abstract-chart-view.directive';
+import { GridStack, GridStackOptions } from 'gridstack';
+import { GridstackComponent, nodesCB } from 'gridstack/dist/angular';
 
 @Component({
     selector: 'sp-dashboard-grid-view',
@@ -42,60 +37,60 @@ import { AbstractChartViewDirective } from 
'../abstract-chart-view.directive';
 })
 export class DashboardGridViewComponent
     extends AbstractChartViewDirective
-    implements OnInit, OnChanges
+    implements OnInit, AfterViewInit, OnChanges
 {
     @Input()
     kioskMode = false;
 
-    options: IDataViewDashboardConfig;
     loaded = false;
 
-    @ViewChildren(GridsterItemComponent)
-    gridsterItemComponents: QueryList<GridsterItemComponent>;
+    @ViewChild('grid', { static: true })
+    gridComp: GridstackComponent;
+
+    grid: GridStack;
+
+    gridOptions: GridStackOptions = {};
+
+    ngAfterViewInit() {
+        this.grid = this.gridComp.grid;
+    }
 
     ngOnInit(): void {
         this.loadWidgetConfigs();
-        this.options = {
-            disablePushOnDrag: true,
-            draggable: { enabled: this.editMode },
-            gridType: GridType.VerticalFixed,
-            minCols: this.dashboard.gridColumns,
-            maxCols: this.dashboard.gridColumns,
-            minRows: 4,
-            fixedRowHeight: 100,
-            fixedColWidth: 100,
-            margin: 3,
-            displayGrid: this.editMode
-                ? DisplayGrid.OnDragAndResize
-                : DisplayGrid.None,
-            resizable: { enabled: this.editMode },
-            itemResizeCallback: (item, itemComponent) => {
-                this.resizeService.notify({
-                    gridsterItem: item,
-                    gridsterItemComponent: itemComponent,
-                } as GridsterInfo);
-            },
-            itemInitCallback: (item, itemComponent) => {
-                this.resizeService.notify({
-                    gridsterItem: item,
-                    gridsterItemComponent: itemComponent,
-                } as GridsterInfo);
-                window.dispatchEvent(new Event('resize'));
+        this.gridOptions = {
+            minRow: 5,
+            column: this.dashboard.gridColumns,
+            margin: 2,
+            cellHeight: 'initial',
+            disableResize: !this.editMode,
+            disableDrag: !this.editMode,
+            float: true,
+            resizable: {
+                handles: 'w,e,se',
             },
         };
     }
 
     ngOnChanges(changes: SimpleChanges): void {
-        if (changes['editMode'] && this.options) {
-            this.options.draggable.enabled = this.editMode;
-            this.options.resizable.enabled = this.editMode;
-            this.options.displayGrid = this.editMode ? 'always' : 'none';
-            this.options.api.optionsChanged();
+        if (changes['editMode'] && this.grid) {
+            this.gridOptions.disableResize = !this.editMode;
+            this.gridOptions.disableDrag = !this.editMode;
+            this.grid.updateOptions(this.gridOptions);
         }
     }
 
-    onOptionsChanged() {
-        this.options.api.optionsChanged();
+    onGridChange(data: nodesCB): void {
+        data.nodes.forEach(changed => {
+            const widget = this.dashboard.widgets.find(
+                w => w.id === (changed as any).id,
+            );
+            if (widget) {
+                widget.x = changed.x;
+                widget.y = changed.y;
+                widget.w = changed.w;
+                widget.h = changed.h;
+            }
+        });
     }
 
     onWidgetsAvailable(): void {}
diff --git 
a/ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.html
 
b/ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.html
index 660c84dd6c..2d35c6a182 100644
--- 
a/ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.html
+++ 
b/ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.html
@@ -55,14 +55,11 @@
                     widgetsVisible
                 ) {
                     <sp-data-explorer-chart-container
-                        [ngStyle]="{
-                            height: gridsterItemComponent.height - 15 + 'px'
-                        }"
                         [timeSettings]="timeSettings"
                         [globalTimeEnabled]="
                             
dashboard.dashboardGeneralSettings.globalTimeEnabled
                         "
-                        (deleteCallback)="propagateItemRemoval($event)"
+                        (deleteCallback)="deleteCallback.emit($event)"
                         (startEditModeEmitter)="startEditMode($event)"
                         [dashboardItem]="currentDashboardItem"
                         [configuredWidget]="currentWidget"
@@ -71,7 +68,6 @@
                         [editMode]="editMode"
                         [gridMode]="false"
                         [widgetIndex]="i"
-                        [gridsterItemComponent]="gridsterItemComponent"
                     ></sp-data-explorer-chart-container>
                 }
             </div>
diff --git 
a/ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.ts
 
b/ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.ts
index c8c76a1f6e..835fb2762d 100644
--- 
a/ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.ts
+++ 
b/ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.ts
@@ -16,17 +16,10 @@
  *
  */
 
-import {
-    AfterViewInit,
-    Component,
-    ElementRef,
-    OnInit,
-    ViewChild,
-} from '@angular/core';
+import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
 import { AbstractChartViewDirective } from '../abstract-chart-view.directive';
 import {
     ClientDashboardItem,
-    DashboardItem,
     DataExplorerWidgetModel,
     DataLakeMeasure,
 } from '@streampipes/platform-services';
@@ -39,12 +32,9 @@ import {
 })
 export class DashboardSlideViewComponent
     extends AbstractChartViewDirective
-    implements OnInit, AfterViewInit
+    implements OnInit
 {
     selectedWidgetIndex = 0;
-
-    gridsterItemComponent: any = { width: 100, height: 100 };
-
     currentWidget: DataExplorerWidgetModel;
     currentMeasure: DataLakeMeasure;
     currentDashboardItem: ClientDashboardItem;
@@ -64,29 +54,10 @@ export class DashboardSlideViewComponent
             this.currentWidget = this.configuredWidgets.get(widgetId);
             this.currentMeasure = this.dataLakeMeasures.get(widgetId);
             this.currentDashboardItem = this.dashboard.widgets[index];
-            this.currentlyConfiguredWidgetId = widgetId;
             this.displayWidget = true;
         });
     }
 
-    ngAfterViewInit(): void {
-        const obs = new ResizeObserver(entries => {
-            entries.forEach(entry => {
-                const cr = entry.contentRect;
-                this.gridsterItemComponent.width = cr.width;
-                this.gridsterItemComponent.height = cr.height;
-                this.resizeService.notify({
-                    gridsterItem:
-                        this.dashboard.widgets[this.selectedWidgetIndex],
-                    gridsterItemComponent: this.gridsterItemComponent,
-                });
-            });
-        });
-        obs.observe(document.getElementById('slideViewOuter'));
-    }
-
-    onOptionsChanged() {}
-
     onWidgetsAvailable(): void {
         this.selectWidget(0, this.dashboard.widgets[0].id);
     }
diff --git a/ui/src/app/dashboard-shared/dashboard-shared.module.ts 
b/ui/src/app/dashboard-shared/dashboard-shared.module.ts
index 0a4e008572..2ccc3f216e 100644
--- a/ui/src/app/dashboard-shared/dashboard-shared.module.ts
+++ b/ui/src/app/dashboard-shared/dashboard-shared.module.ts
@@ -19,7 +19,6 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FlexLayoutModule } from '@ngbracket/ngx-layout';
-import { GridsterModule } from 'angular-gridster2';
 import { MatTabsModule } from '@angular/material/tabs';
 import { FormsModule } from '@angular/forms';
 import { ColorPickerComponent } from 'ngx-color-picker';
@@ -60,6 +59,7 @@ import { DataExplorerSharedModule } from 
'../data-explorer-shared/data-explorer-
 import { DashboardGridViewComponent } from 
'./components/chart-view/grid-view/dashboard-grid-view.component';
 import { DashboardSlideViewComponent } from 
'./components/chart-view/slide-view/dashboard-slide-view.component';
 import { TranslateModule } from '@ngx-translate/core';
+import { GridstackModule } from 'gridstack/dist/angular';
 
 @NgModule({
     imports: [
@@ -88,7 +88,6 @@ import { TranslateModule } from '@ngx-translate/core';
         CommonModule,
         CoreUiModule,
         MatTabsModule,
-        GridsterModule,
         FlexLayoutModule,
         FormsModule,
         ColorPickerComponent,
@@ -103,6 +102,7 @@ import { TranslateModule } from '@ngx-translate/core';
         ServicesModule,
         SharedUiModule,
         DataExplorerSharedModule,
+        GridstackModule,
         TranslateModule.forChild(),
     ],
     declarations: [DashboardGridViewComponent, DashboardSlideViewComponent],
diff --git 
a/ui/src/app/dashboard/components/panel/chart-selection-panel/chart-selection-panel.component.html
 
b/ui/src/app/dashboard/components/panel/chart-selection-panel/chart-selection-panel.component.html
index 1c4f323cb4..37166e0a2e 100644
--- 
a/ui/src/app/dashboard/components/panel/chart-selection-panel/chart-selection-panel.component.html
+++ 
b/ui/src/app/dashboard/components/panel/chart-selection-panel/chart-selection-panel.component.html
@@ -17,11 +17,6 @@
   -->
 
 <div fxFlex="100" class="designer-panel-content" fxLayout="column">
-    <div fxLayout="row" class="sp-tab-bg designer-panel-header">
-        <div fxLayoutAlign="start center" class="designer-panel-title">
-            <span> {{ 'Configure dashboard' | translate }} </span>
-        </div>
-    </div>
     <div fxFlex="100" fxLayout="column" class="no-overflow">
         <mat-tab-group
             color="accent"
diff --git 
a/ui/src/app/dashboard/components/panel/dashboard-panel.component.scss 
b/ui/src/app/dashboard/components/panel/dashboard-panel.component.scss
index ad4770c30a..6b94dd13a0 100644
--- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.scss
+++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.scss
@@ -40,7 +40,7 @@
 }
 
 .designer-panel {
-    width: 450px;
+    width: 350px;
 }
 
 .edit-menu-btn {
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 69879120c9..50e88b20c2 100644
--- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
+++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
@@ -85,8 +85,8 @@ export class DashboardPanelComponent
     public items: Dashboard[];
 
     dataLakeMeasure: DataLakeMeasure;
-    authSubscription: Subscription;
-    refreshSubscription: Subscription;
+    auth$: Subscription;
+    refresh$: Subscription;
 
     private detectChangesService = inject(ChartDetectChangesService);
     private dialog = inject(MatDialog);
@@ -113,7 +113,7 @@ export class DashboardPanelComponent
 
         this.getDashboard(params.id, startTime, endTime);
 
-        this.authSubscription = this.currentUserService.user$.subscribe(_ => {
+        this.auth$ = this.currentUserService.user$.subscribe(_ => {
             this.hasDashboardWritePrivileges = this.authService.hasRole(
                 UserPrivilege.PRIVILEGE_WRITE_DASHBOARD,
             );
@@ -124,26 +124,28 @@ export class DashboardPanelComponent
     }
 
     ngOnDestroy() {
-        this.authSubscription?.unsubscribe();
-        this.refreshSubscription?.unsubscribe();
+        this.auth$?.unsubscribe();
+        this.refresh$?.unsubscribe();
     }
 
     addChartToDashboard(dataViewElementId: string) {
         // eslint-disable-next-line 
@typescript-eslint/consistent-type-assertions
         const dashboardItem = {} as ClientDashboardItem;
-        dashboardItem.id = dataViewElementId;
+        dashboardItem.id =
+            this.dataExplorerDashboardService.makeUniqueWidgetId();
         dashboardItem.cols = 3;
         dashboardItem.rows = 4;
+        dashboardItem.w = 3;
+        dashboardItem.h = 4;
         dashboardItem.x = 0;
         dashboardItem.y = 0;
-        dashboardItem.widgetId =
-            this.dataExplorerDashboardService.makeUniqueWidgetId();
+        dashboardItem.dataViewElementId = dataViewElementId;
         this.dashboard.widgets.push(dashboardItem);
         setTimeout(() => {
             if (this.viewMode === 'grid') {
-                this.dashboardGrid.loadWidgetConfig(dataViewElementId, true);
+                this.dashboardGrid.loadWidgetConfig(dashboardItem);
             } else {
-                this.dashboardSlide.loadWidgetConfig(dataViewElementId, true);
+                this.dashboardSlide.loadWidgetConfig(dashboardItem);
             }
         });
     }
@@ -231,7 +233,7 @@ export class DashboardPanelComponent
                 if (resp.ok) {
                     const compositeDashboard = resp.body;
                     compositeDashboard.dashboard.widgets.forEach(w => {
-                        w.widgetId ??=
+                        w.id ??=
                             
this.dataExplorerDashboardService.makeUniqueWidgetId();
                     });
                     this.dashboard = compositeDashboard.dashboard;
@@ -329,14 +331,14 @@ export class DashboardPanelComponent
 
     modifyRefreshInterval(liveSettings: DashboardLiveSettings): void {
         this.dashboard.dashboardLiveSettings = liveSettings;
-        this.refreshSubscription?.unsubscribe();
+        this.refresh$?.unsubscribe();
         if (this.dashboard.dashboardLiveSettings.refreshModeActive) {
             this.createQuerySubscription();
         }
     }
 
     createQuerySubscription() {
-        this.refreshSubscription = timer(
+        this.refresh$ = timer(
             0,
             this.dashboard.dashboardLiveSettings.refreshIntervalInSeconds *
                 1000,
diff --git a/ui/src/app/dashboard/dashboard.module.ts 
b/ui/src/app/dashboard/dashboard.module.ts
index 93e0fc7966..7382505c3f 100644
--- a/ui/src/app/dashboard/dashboard.module.ts
+++ b/ui/src/app/dashboard/dashboard.module.ts
@@ -19,7 +19,6 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FlexLayoutModule } from '@ngbracket/ngx-layout';
-import { GridsterModule } from 'angular-gridster2';
 import { MatTabsModule } from '@angular/material/tabs';
 import { FormsModule } from '@angular/forms';
 import { ColorPickerComponent } from 'ngx-color-picker';
@@ -99,7 +98,6 @@ import { MatProgressSpinnerModule } from 
'@angular/material/progress-spinner';
         CommonModule,
         CoreUiModule,
         MatTabsModule,
-        GridsterModule,
         FlexLayoutModule,
         FormsModule,
         ColorPickerComponent,
diff --git 
a/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.html
 
b/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.html
index b8997d02c8..bddbd7de47 100644
--- 
a/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.html
+++ 
b/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.html
@@ -16,181 +16,165 @@
 ~
 -->
 
-<div class="h-100">
-    <div
-        class="box"
-        [ngStyle]="{
-            background: configuredWidget.baseAppearanceConfig.backgroundColor,
-            color: configuredWidget.baseAppearanceConfig.textColor,
-            height: gridsterItemComponent.height - 13 + 'px',
-            border:
-                '2px solid ' +
-                configuredWidget.baseAppearanceConfig.backgroundColor
-        }"
-        [attr.data-cy]="
-            'widget-' + configuredWidget.baseAppearanceConfig.widgetTitle
-        "
-    >
-        @if (!previewMode) {
-            <div class="widget-header h-40 w-100">
-                <div fxFlex="100" fxLayout="row">
-                    <div
-                        fxFlex
-                        fxLayout="row"
-                        fxLayoutAlign="start center"
-                        class="widget-header-text"
-                    >
-                        {{ configuredWidget.baseAppearanceConfig.widgetTitle }}
-                    </div>
-                    @if (!kioskMode) {
-                        <div fxLayout="row" fxLayoutAlign="end center">
-                            @if (editMode) {
-                                @if (timerActive) {
-                                    <mat-spinner
-                                        [diameter]="20"
-                                        color="primary"
-                                        class="mr-10"
-                                    >
-                                    </mat-spinner>
-                                }
-                                <sp-label
-                                    size="small"
-                                    [labelBackground]="
-                                        configuredWidget.baseAppearanceConfig
-                                            .textColor
-                                    "
-                                    [labelText]="loadingTime + 's'"
+<div
+    class="box"
+    [ngStyle]="{
+        background: configuredWidget.baseAppearanceConfig.backgroundColor,
+        color: configuredWidget.baseAppearanceConfig.textColor,
+        height: '100%'
+    }"
+    [attr.data-cy]="
+        'widget-' + configuredWidget.baseAppearanceConfig.widgetTitle
+    "
+>
+    @if (!previewMode) {
+        <div class="widget-header h-40 w-100">
+            <div fxFlex="100" fxLayout="row">
+                <div
+                    fxFlex
+                    fxLayout="row"
+                    fxLayoutAlign="start center"
+                    class="widget-header-text"
+                >
+                    {{ configuredWidget.baseAppearanceConfig.widgetTitle }}
+                </div>
+                @if (!kioskMode) {
+                    <div fxLayout="row" fxLayoutAlign="end center">
+                        @if (editMode) {
+                            @if (timerActive) {
+                                <mat-spinner
+                                    [diameter]="20"
+                                    color="primary"
                                     class="mr-10"
-                                ></sp-label>
+                                >
+                                </mat-spinner>
                             }
-                            @if (!dataViewMode) {
+                            <sp-label
+                                size="small"
+                                [labelBackground]="
+                                    configuredWidget.baseAppearanceConfig
+                                        .textColor
+                                "
+                                [labelText]="loadingTime + 's'"
+                                class="mr-10"
+                            ></sp-label>
+                        }
+                        @if (!dataViewMode) {
+                            <button
+                                mat-icon-button
+                                [matMenuTriggerFor]="menu"
+                                [matTooltip]="'More options' | translate"
+                                [attr.data-cy]="
+                                    'more-options-' +
+                                    
configuredWidget.baseAppearanceConfig.widgetTitle.replaceAll(
+                                        ' ',
+                                        ''
+                                    )
+                                "
+                            >
+                                <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' | translate }}</span>
+                            </button>
+                            @if (hasDataExplorerWritePrivileges) {
                                 <button
-                                    mat-icon-button
-                                    [matMenuTriggerFor]="menu"
-                                    [matTooltip]="'More options' | translate"
+                                    mat-menu-item
+                                    (click)="startEditMode()"
                                     [attr.data-cy]="
-                                        'more-options-' +
+                                        'start-edit-' +
                                         
configuredWidget.baseAppearanceConfig.widgetTitle.replaceAll(
                                             ' ',
                                             ''
                                         )
                                     "
                                 >
-                                    <mat-icon>more_vert</mat-icon>
+                                    <mat-icon>edit</mat-icon>
+                                    <span>{{ 'Edit Chart' | translate }}</span>
                                 </button>
                             }
-                            <mat-menu #menu="matMenu">
-                                <button
-                                    mat-menu-item
-                                    (click)="downloadDataAsFile()"
+                        </mat-menu>
+                        @if (!globalTimeEnabled) {
+                            <button
+                                mat-icon-button
+                                [matMenuTriggerFor]="optMenu"
+                                data-cy="options-data-explorer"
+                                #menuTrigger="matMenuTrigger"
+                                [matTooltip]="tooltipText"
+                                matTooltipClass="no-wrap-tooltip"
+                            >
+                                <mat-icon
+                                    [color]="
+                                        timeSettingsModified
+                                            ? 'primary'
+                                            : 'default'
+                                    "
+                                    >alarm_clock</mat-icon
+                                >
+                            </button>
+                        }
+                        <mat-menu #optMenu="matMenu" class="large-menu">
+                            @if (quickSelections) {
+                                <sp-time-selector-menu
+                                    #timeSelectorMenu
+                                    [timeSettings]="clonedTimeSettings"
+                                    [quickSelections]="quickSelections"
+                                    [enableTimePicker]="enableTimePicker"
+                                    [maxDayRange]="maxDayRange"
+                                    [labels]="labels"
+                                    (timeSettingsEmitter)="
+                                        modifyWidgetTimeSettings($event)
+                                    "
+                                    class="w-100"
                                 >
-                                    <mat-icon>get_app</mat-icon>
-                                    <span>{{
-                                        'Download data' | translate
-                                    }}</span>
-                                </button>
-                                @if (hasDataExplorerWritePrivileges) {
                                     <button
-                                        mat-menu-item
-                                        (click)="startEditMode()"
-                                        [attr.data-cy]="
-                                            'start-edit-' +
-                                            
configuredWidget.baseAppearanceConfig.widgetTitle.replaceAll(
-                                                ' ',
-                                                ''
-                                            )
-                                        "
+                                        mat-flat-button
+                                        class="mat-basic"
+                                        (click)="resetWidgetTimeSettings()"
                                     >
-                                        <mat-icon>edit</mat-icon>
-                                        <span>{{
-                                            'Edit Chart' | translate
-                                        }}</span>
+                                        {{ 'Reset' | translate }}
                                     </button>
-                                }
-                            </mat-menu>
-                            @if (!globalTimeEnabled) {
-                                <button
-                                    mat-icon-button
-                                    [matMenuTriggerFor]="optMenu"
-                                    data-cy="options-data-explorer"
-                                    #menuTrigger="matMenuTrigger"
-                                    [matTooltip]="tooltipText"
-                                    matTooltipClass="no-wrap-tooltip"
-                                >
-                                    <mat-icon
-                                        [color]="
-                                            timeSettingsModified
-                                                ? 'primary'
-                                                : 'default'
-                                        "
-                                        >alarm_clock</mat-icon
-                                    >
-                                </button>
-                            }
-                            <mat-menu #optMenu="matMenu" class="large-menu">
-                                @if (quickSelections) {
-                                    <sp-time-selector-menu
-                                        #timeSelectorMenu
-                                        [timeSettings]="clonedTimeSettings"
-                                        [quickSelections]="quickSelections"
-                                        [enableTimePicker]="enableTimePicker"
-                                        [maxDayRange]="maxDayRange"
-                                        [labels]="labels"
-                                        (timeSettingsEmitter)="
-                                            modifyWidgetTimeSettings($event)
-                                        "
-                                        class="w-100"
-                                    >
-                                        <button
-                                            mat-flat-button
-                                            class="mat-basic"
-                                            (click)="resetWidgetTimeSettings()"
-                                        >
-                                            {{ 'Reset' | translate }}
-                                        </button>
-                                    </sp-time-selector-menu>
-                                }
-                            </mat-menu>
-                            @if (
-                                !dataViewMode &&
-                                editMode &&
-                                hasDashboardWritePrivileges
-                            ) {
-                                <button
-                                    mat-icon-button
-                                    (click)="removeWidget()"
-                                    [matTooltip]="'Delete Chart' | translate"
-                                    [attr.data-cy]="
-                                        'remove-' +
-                                        configuredWidget.baseAppearanceConfig
-                                            .widgetTitle
-                                    "
-                                >
-                                    <mat-icon>clear</mat-icon>
-                                </button>
+                                </sp-time-selector-menu>
                             }
-                        </div>
-                    }
-                </div>
+                        </mat-menu>
+                        @if (
+                            !dataViewMode &&
+                            editMode &&
+                            hasDashboardWritePrivileges
+                        ) {
+                            <button
+                                mat-icon-button
+                                (click)="removeWidget()"
+                                [matTooltip]="'Delete Chart' | translate"
+                                [attr.data-cy]="
+                                    'remove-' +
+                                    configuredWidget.baseAppearanceConfig
+                                        .widgetTitle
+                                "
+                            >
+                                <mat-icon>clear</mat-icon>
+                            </button>
+                        }
+                    </div>
+                }
             </div>
-        }
-        <div
-            fxLayout="column"
-            class="widget-content p-0 gridster-item-content ml-0 mr-0 h-100 
mw-100"
-        >
-            <ng-template spWidgetHost class="h-100 p-0"></ng-template>
-            @if (errorMessage) {
-                <div
-                    fxFlex="100"
-                    fxLayout="column"
-                    fxLayoutAlign="center center"
-                >
-                    <sp-exception-message
-                        [message]="errorMessage"
-                        [showDetails]="true"
-                    ></sp-exception-message>
-                </div>
-            }
         </div>
+    }
+    <div fxLayout="column" class="widget-content p-0 ml-0 mr-0 h-100 mw-100">
+        <ng-template spWidgetHost class="h-100 p-0"></ng-template>
+        @if (errorMessage) {
+            <div fxFlex="100" fxLayout="column" fxLayoutAlign="center center">
+                <sp-exception-message
+                    [message]="errorMessage"
+                    [showDetails]="true"
+                ></sp-exception-message>
+            </div>
+        }
     </div>
 </div>
diff --git 
a/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.scss
 
b/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.scss
index 592687545c..edbf29c51d 100644
--- 
a/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.scss
+++ 
b/ui/src/app/data-explorer-shared/components/chart-container/data-explorer-chart-container.component.scss
@@ -39,8 +39,7 @@
 .box {
     display: flex;
     flex-flow: column;
-    height: 100%;
-    padding-top: 5px;
+    max-height: 100%;
 }
 
 .box .row.content {
@@ -85,4 +84,5 @@
     max-width: 100%;
     width: 100%;
     overflow-x: hidden;
+    overflow-y: hidden;
 }
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 584696694a..1009b2037a 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
@@ -17,9 +17,11 @@
  */
 
 import {
+    AfterViewInit,
     Component,
     ComponentFactoryResolver,
     ComponentRef,
+    ElementRef,
     EventEmitter,
     Input,
     OnChanges,
@@ -29,7 +31,6 @@ import {
     SimpleChanges,
     ViewChild,
 } from '@angular/core';
-import { GridsterItemComponent } from 'angular-gridster2';
 import {
     ClientDashboardItem,
     DataExplorerWidgetModel,
@@ -53,12 +54,13 @@ import {
     TimeSelectionService,
     TimeSelectorLabel,
 } from '@streampipes/shared-ui';
+import { ChartSharedService } from '../../services/chart-shared.service';
 import {
     BaseWidgetData,
     ObservableGenerator,
 } from '../../models/dataview-dashboard.model';
-import { ChartSharedService } from '../../services/chart-shared.service';
 import { MatMenuTrigger } from '@angular/material/menu';
+import { ResizeService } from '../../services/resize.service';
 
 @Component({
     selector: 'sp-data-explorer-chart-container',
@@ -67,7 +69,7 @@ import { MatMenuTrigger } from '@angular/material/menu';
     standalone: false,
 })
 export class DataExplorerChartContainerComponent
-    implements OnInit, OnDestroy, OnChanges
+    implements OnInit, OnDestroy, OnChanges, AfterViewInit
 {
     @ViewChild('menuTrigger') menu: MatMenuTrigger;
     @ViewChild('timeSelectorMenu')
@@ -87,9 +89,6 @@ export class DataExplorerChartContainerComponent
     @Input()
     dataViewMode = false;
 
-    @Input()
-    gridsterItemComponent: GridsterItemComponent;
-
     @Input()
     previewMode = false;
 
@@ -140,9 +139,9 @@ export class DataExplorerChartContainerComponent
     hasDataExplorerWritePrivileges = false;
     hasDashboardWritePrivileges = false;
 
-    authSubscription: Subscription;
-    widgetTypeChangedSubscription: Subscription;
-    intervalSubscription: Subscription;
+    auth$: Subscription;
+    widgetTypeChanged$: Subscription;
+    interval$: Subscription;
 
     errorMessage: SpLogMessage;
 
@@ -158,8 +157,33 @@ export class DataExplorerChartContainerComponent
         private authService: AuthService,
         private currentUserService: CurrentUserService,
         private timeSelectionService: TimeSelectionService,
+        private el: ElementRef<HTMLDivElement>,
+        private resizeService: ResizeService,
     ) {}
 
+    resizeObserver: ResizeObserver;
+    resizeTimeout: any;
+
+    ngAfterViewInit(): void {
+        const container = this.el.nativeElement.querySelector(
+            '.widget-content',
+        ) as HTMLDivElement;
+        const obs = new ResizeObserver(entries => {
+            clearTimeout(this.resizeTimeout);
+            this.resizeTimeout = setTimeout(() => {
+                const { width, height } =
+                    entries[entries.length - 1].contentRect;
+
+                this.resizeService.notify({
+                    width,
+                    height,
+                    widgetId: this.dashboardItem?.id || undefined,
+                });
+            }, 100);
+        });
+        obs.observe(container);
+    }
+
     ngOnChanges(changes: SimpleChanges): void {
         if (changes.widgetIndex && this.componentRef?.instance) {
             this.componentRef.instance.widgetIndex =
@@ -171,19 +195,17 @@ export class DataExplorerChartContainerComponent
         this.quickSelections ??=
             this.timeSelectionService.defaultQuickTimeSelections;
         this.labels ??= this.timeSelectionService.defaultLabels;
-        this.authSubscription = this.currentUserService.user$.subscribe(
-            user => {
-                this.hasDataExplorerWritePrivileges = this.authService.hasRole(
-                    UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW,
-                );
-                this.hasDashboardWritePrivileges = this.authService.hasRole(
-                    UserPrivilege.PRIVILEGE_WRITE_DASHBOARD,
-                );
-            },
-        );
+        this.auth$ = this.currentUserService.user$.subscribe(user => {
+            this.hasDataExplorerWritePrivileges = this.authService.hasRole(
+                UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW,
+            );
+            this.hasDashboardWritePrivileges = this.authService.hasRole(
+                UserPrivilege.PRIVILEGE_WRITE_DASHBOARD,
+            );
+        });
         this.widgetLoaded = true;
         this.title = this.dataLakeMeasure.measureName;
-        this.widgetTypeChangedSubscription =
+        this.widgetTypeChanged$ =
             this.widgetTypeService.chartTypeChangeSubject.subscribe(
                 typeChange => {
                     if (
@@ -230,9 +252,11 @@ export class DataExplorerChartContainerComponent
     }
 
     ngOnDestroy() {
+        this.resizeObserver?.disconnect();
         this.componentRef?.destroy();
-        this.authSubscription?.unsubscribe();
-        this.widgetTypeChangedSubscription?.unsubscribe();
+        this.auth$?.unsubscribe();
+        this.widgetTypeChanged$?.unsubscribe();
+        this.interval$?.unsubscribe();
     }
 
     chooseWidget(widgetTypeId: string) {
@@ -244,6 +268,13 @@ export class DataExplorerChartContainerComponent
     }
 
     loadComponent(widgetToDisplay) {
+        const container = this.el.nativeElement.querySelector(
+            '.widget-content',
+        ) as HTMLDivElement;
+        const initialSize = {
+            width: container.clientWidth,
+            height: container.clientHeight,
+        };
         const componentFactory =
             this.componentFactoryResolver.resolveComponentFactory<
                 BaseWidgetData<any>
@@ -257,15 +288,14 @@ export class DataExplorerChartContainerComponent
                 componentFactory,
             );
         this.componentRef.instance.dataExplorerWidget = this.configuredWidget;
+        this.componentRef.instance.initialSize = initialSize;
         this.componentRef.instance.timeSettings = this.getTimeSettings();
         this.timeSelectionService.updateTimeSettings(
             this.quickSelections,
             this.getTimeSettings(),
             new Date(),
         );
-        this.componentRef.instance.gridsterItem = this.dashboardItem;
-        this.componentRef.instance.gridsterItemComponent =
-            this.gridsterItemComponent;
+        this.componentRef.instance.dataViewMode = this.dataViewMode;
         this.componentRef.instance.editMode = this.editMode;
         this.componentRef.instance.kioskMode = this.kioskMode;
         this.componentRef.instance.dataViewDashboardItem = this.dashboardItem;
@@ -275,22 +305,22 @@ export class DataExplorerChartContainerComponent
         this.componentRef.instance.widgetIndex = this.widgetIndex;
         this.componentRef.instance.observableGenerator =
             this.observableGenerator;
-        const removeSub =
+        const remove$ =
             this.componentRef.instance.removeWidgetCallback.subscribe(ev =>
                 this.removeWidget(),
             );
-        const timerSub = this.componentRef.instance.timerCallback.subscribe(
-            ev => this.handleTimer(ev),
+        const timer$ = this.componentRef.instance.timerCallback.subscribe(ev =>
+            this.handleTimer(ev),
         );
-        const errorSub = this.componentRef.instance.errorCallback.subscribe(
+        const error$ = this.componentRef.instance.errorCallback.subscribe(
             ev => (this.errorMessage = ev),
         );
 
         this.componentRef.onDestroy(destroy => {
             this.componentRef.instance.cleanupSubscriptions();
-            removeSub?.unsubscribe();
-            timerSub?.unsubscribe();
-            errorSub?.unsubscribe();
+            remove$?.unsubscribe();
+            timer$?.unsubscribe();
+            error$?.unsubscribe();
         });
     }
 
@@ -317,7 +347,7 @@ export class DataExplorerChartContainerComponent
 
     startLoadingTimer() {
         this.timerActive = true;
-        this.intervalSubscription = interval(100)
+        this.interval$ = interval(100)
             .pipe(takeWhile(() => this.timerActive))
             .subscribe(value => {
                 this.loadingTime = (value * 100) / 1000;
@@ -326,7 +356,7 @@ export class DataExplorerChartContainerComponent
 
     stopLoadingTimer() {
         this.timerActive = false;
-        this.intervalSubscription.unsubscribe();
+        this.interval$.unsubscribe();
     }
 
     handleTimer(start: boolean) {
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 e322d0fc06..c7c4cc0dd7 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
@@ -25,14 +25,12 @@ import {
     OnInit,
     Output,
 } from '@angular/core';
-import { GridsterItem, GridsterItemComponent } from 'angular-gridster2';
 import { ChartConfigurationService } from 
'../../../services/chart-configuration.service';
 import {
     ClientDashboardItem,
     DataExplorerDataConfig,
     DataExplorerField,
     DataExplorerWidgetModel,
-    DataViewQueryGeneratorService,
     SpLogMessage,
     SpQueryResult,
     TimeSettings,
@@ -49,6 +47,7 @@ import { catchError, switchMap } from 'rxjs/operators';
 import { DataExplorerChartRegistry } from 
'../../../registry/data-explorer-chart-registry';
 import { SpFieldUpdateService } from '../../../services/field-update.service';
 import { TimeSelectionService } from '@streampipes/shared-ui';
+import { WidgetSize } from '../../../models/dataset.model';
 
 @Directive()
 export abstract class BaseDataExplorerWidgetDirective<
@@ -68,10 +67,9 @@ export abstract class BaseDataExplorerWidgetDirective<
     errorCallback: EventEmitter<SpLogMessage> =
         new EventEmitter<SpLogMessage>();
 
-    @Input() gridsterItem: GridsterItem;
-    @Input() gridsterItemComponent: GridsterItemComponent;
     @Input() editMode: boolean;
     @Input() kioskMode: boolean;
+    @Input() dataViewMode: boolean;
     @Input() observableGenerator: ObservableGenerator;
 
     @Input() timeSettings: TimeSettings;
@@ -90,6 +88,12 @@ export abstract class BaseDataExplorerWidgetDirective<
 
     @HostBinding('class') className = 'h-100';
 
+    @Input()
+    initialSize: WidgetSize;
+
+    currentWidth: number;
+    currentHeight: number;
+
     public selectedProperties: string[];
 
     public showNoDataInDateRange: boolean;
@@ -101,12 +105,9 @@ export abstract class BaseDataExplorerWidgetDirective<
 
     fieldProvider: FieldProvider;
 
-    widgetConfigurationSub: Subscription;
-    resizeSub: Subscription;
-    timeSelectionSub: Subscription;
-
-    widthOffset: number;
-    heightOffset: number;
+    widgetConfiguration$: Subscription;
+    resize$: Subscription;
+    timeSelection$: Subscription;
 
     requestQueue$: Subject<Observable<SpQueryResult>[]> = new Subject<
         Observable<SpQueryResult>[]
@@ -114,17 +115,14 @@ export abstract class BaseDataExplorerWidgetDirective<
 
     protected widgetConfigurationService = inject(ChartConfigurationService);
     protected resizeService = inject(ResizeService);
-    protected dataViewQueryGeneratorService = inject(
-        DataViewQueryGeneratorService,
-    );
     protected timeSelectionService = inject(TimeSelectionService);
     protected widgetRegistryService = inject(DataExplorerChartRegistry);
     protected fieldUpdateService = inject(SpFieldUpdateService);
     public fieldService = inject(ChartFieldProviderService);
 
     ngOnInit(): void {
-        this.heightOffset = this.gridMode ? 70 : 65;
-        this.widthOffset = this.gridMode ? 10 : 10;
+        this.currentWidth = this.initialSize.width;
+        this.currentHeight = this.initialSize.height;
         this.showData = true;
         const sourceConfigs = this.dataExplorerWidget.dataConfig.sourceConfigs;
         this.fieldProvider =
@@ -153,7 +151,7 @@ export abstract class BaseDataExplorerWidgetDirective<
                 });
             });
 
-        this.widgetConfigurationSub =
+        this.widgetConfiguration$ =
             
this.widgetConfigurationService.configurationChangedSubject.subscribe(
                 refreshMessage => {
                     if (refreshMessage.refreshData) {
@@ -179,22 +177,18 @@ export abstract class BaseDataExplorerWidgetDirective<
                 },
             );
         if (!this.previewMode) {
-            this.resizeSub = this.resizeService.resizeSubject.subscribe(
-                info => {
-                    if (
-                        info.gridsterItem.id ===
-                        this.dataExplorerWidget.elementId
-                    ) {
-                        this.onResize(
-                            this.gridsterItemComponent.width - 
this.widthOffset,
-                            this.gridsterItemComponent.height -
-                                this.heightOffset,
-                        );
-                    }
-                },
-            );
+            this.resize$ = this.resizeService.resizeSubject.subscribe(info => {
+                if (
+                    this.dataViewMode ||
+                    info.widgetId === this.dataViewDashboardItem.id
+                ) {
+                    this.currentWidth = info.width;
+                    this.currentHeight = info.height;
+                    this.onResize(info.width, info.height);
+                }
+            });
         }
-        this.timeSelectionSub =
+        this.timeSelection$ =
             this.timeSelectionService.timeSelectionChangeSubject.subscribe(
                 widgetTimeSettings => {
                     if (
@@ -216,16 +210,12 @@ export abstract class BaseDataExplorerWidgetDirective<
                 },
             );
         this.updateData();
-        this.onResize(
-            this.gridsterItemComponent.width - this.widthOffset,
-            this.gridsterItemComponent.height - this.heightOffset,
-        );
     }
 
     public cleanupSubscriptions(): void {
-        this.widgetConfigurationSub?.unsubscribe();
-        this.resizeSub?.unsubscribe();
-        this.timeSelectionSub?.unsubscribe();
+        this.widgetConfiguration$?.unsubscribe();
+        this.resize$?.unsubscribe();
+        this.timeSelection$.unsubscribe();
         this.requestQueue$?.unsubscribe();
     }
 
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/base/echarts-widget.component.html
 
b/ui/src/app/data-explorer-shared/components/charts/base/echarts-widget.component.html
index f7d787b876..02753931c0 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/base/echarts-widget.component.html
+++ 
b/ui/src/app/data-explorer-shared/components/charts/base/echarts-widget.component.html
@@ -51,7 +51,7 @@
             [attr.data-cy]="dataExplorerWidget.widgetType"
             echarts
             [options]="option"
-            [ngStyle]="{ width: currentWidth, height: '100%' }"
+            [ngStyle]="{ width: currentWidth, height: 'calc(100% - 1px)' }"
             (chartInit)="onChartInit($event)"
         ></div>
     }
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/base/echarts-widget.component.ts
 
b/ui/src/app/data-explorer-shared/components/charts/base/echarts-widget.component.ts
index 375499beda..6561c5d527 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/base/echarts-widget.component.ts
+++ 
b/ui/src/app/data-explorer-shared/components/charts/base/echarts-widget.component.ts
@@ -41,9 +41,6 @@ export class SpEchartsWidgetComponent<T extends 
DataExplorerWidgetModel>
     implements OnInit
 {
     eChartsInstance: ECharts;
-    currentWidth: number;
-    currentHeight: number;
-
     option: EChartsOption;
 
     configReady = false;
@@ -63,8 +60,7 @@ export class SpEchartsWidgetComponent<T extends 
DataExplorerWidgetModel>
         this.renderer = this.getRenderer();
         this.resizeEcharts$ =
             this.resizeEchartsService.echartsResizeSubject.subscribe(width => {
-                this.currentWidth = width - this.widthOffset;
-                this.applySize(this.currentWidth, this.currentHeight);
+                this.currentWidth = width;
                 this.refreshView();
             });
         this.renderSubject$ = this.renderSubject
@@ -80,30 +76,20 @@ export class SpEchartsWidgetComponent<T extends 
DataExplorerWidgetModel>
     beforeDataFetched() {}
 
     onDataReceived(spQueryResult: SpQueryResult[]) {
-        this.renderChartOptions(spQueryResult);
         this.latestData = spQueryResult;
+        this.renderChartOptions(spQueryResult);
         this.setShownComponents(false, true, false, false);
     }
 
     onResize(width: number, height: number) {
-        this.currentWidth = width;
-        this.currentHeight = height;
         this.configReady = true;
-        this.applySize(width, height);
         if (this.latestData) {
-            this.renderSubject.next();
+            this.refreshView();
         }
     }
 
     onChartInit(ec: ECharts) {
         this.eChartsInstance = ec;
-        this.applySize(this.currentWidth, this.currentHeight);
-    }
-
-    applySize(width: number, height: number) {
-        if (this.eChartsInstance) {
-            this.eChartsInstance.resize({ width, height });
-        }
     }
 
     renderChartOptions(spQueryResult: SpQueryResult[]): void {
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/gauge/gauge-renderer.service.ts
 
b/ui/src/app/data-explorer-shared/components/charts/gauge/gauge-renderer.service.ts
index 376bbf2cbf..7be7324f64 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/gauge/gauge-renderer.service.ts
+++ 
b/ui/src/app/data-explorer-shared/components/charts/gauge/gauge-renderer.service.ts
@@ -46,18 +46,25 @@ export class SpGaugeRendererService
         fieldName: string,
         value: number,
         widgetConfig: GaugeWidgetModel,
+        widgetSize: WidgetSize,
     ): GaugeSeriesOption {
         const visConfig = widgetConfig.visualizationConfig;
+        const clamp = Math.min(Math.max(widgetSize.width / 400, 0.7), 1.4);
         return {
             name: seriesName,
             type: 'gauge',
             progress: {
                 show: true,
             },
+            axisLabel: {
+                fontSize: 10 * clamp,
+            },
             detail: {
                 show: true,
                 valueAnimation: false,
                 formatter: '{value}',
+                fontSize: 14 * clamp,
+                offsetCenter: [0, '70%'],
             },
             min: visConfig.min,
             max: visConfig.max,
@@ -87,7 +94,7 @@ export class SpGaugeRendererService
     render(
         queryResult: SpQueryResult[],
         widgetConfig: GaugeWidgetModel,
-        _widgetSize: WidgetSize,
+        widgetSize: WidgetSize,
     ): EChartsOption {
         const option = this.echartsBaseOptionsGenerator.makeBaseConfig(
             widgetConfig.baseAppearanceConfig as WidgetEchartsAppearanceConfig,
@@ -110,6 +117,7 @@ export class SpGaugeRendererService
                 selectedField.fullDbName,
                 data,
                 widgetConfig,
+                widgetSize,
             ),
         });
 
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/heatmap/heatmap-renderer.service.ts
 
b/ui/src/app/data-explorer-shared/components/charts/heatmap/heatmap-renderer.service.ts
index 08c87275b0..90abf4ee55 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/heatmap/heatmap-renderer.service.ts
+++ 
b/ui/src/app/data-explorer-shared/components/charts/heatmap/heatmap-renderer.service.ts
@@ -109,10 +109,7 @@ export class SpHeatmapRendererService extends 
SpBaseEchartsRenderer<HeatmapWidge
         options: EChartsOption,
         widgetConfig: HeatmapWidgetModel,
     ): void {
-        options.grid = {
-            height: '80%',
-            top: '80',
-        };
+        options.grid = {};
         options.xAxis = {
             type: 'category',
             splitArea: {
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 c66e0cbed2..6c2508e7c6 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
@@ -51,10 +51,7 @@ export class ImageWidgetComponent
 
     ngOnInit(): void {
         super.ngOnInit();
-        this.onResize(
-            this.gridsterItemComponent.width,
-            this.gridsterItemComponent.height - 53,
-        );
+        this.onResize(this.currentWidth, this.currentHeight - 53);
         this.imageBaseUrl = this.dataLakeRestService.dataLakeUrl + '/images/';
     }
 
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.html
 
b/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.html
index 24929b45c0..239fe7aad1 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.html
+++ 
b/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.html
@@ -31,24 +31,19 @@
         </sp-no-data-in-date-range>
     }
 
-    <div fxLayoutAlign="center center">
-        <div
-            class="tl-container"
-            [ngStyle]="{
-                width: containerWidth + 'px',
-                height: containerHeight + 'px'
-            }"
-        >
+    <div
+        class="status-light-wrapper"
+        fxFlex
+        fxLayout="column"
+        fxLayoutAlign="center center"
+    >
+        <div class="tl-container">
             <div
                 class="light"
                 [ngClass]="{
                     'light-red': !active,
                     'light-green': active
                 }"
-                [ngStyle]="{
-                    width: lightWidth + 'px',
-                    height: lightHeight + 'px'
-                }"
             ></div>
         </div>
     </div>
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.scss
 
b/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.scss
index ac656663e5..c18549cdc5 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.scss
+++ 
b/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.scss
@@ -19,19 +19,33 @@
     height: 100%;
 }
 
+.status-light-wrapper {
+    display: inline-flex;
+    flex-direction: column;
+    align-items: center;
+}
+
 .tl-container {
     background-color: #222;
     display: flex;
     align-items: center;
-    flex-direction: column;
-    padding: 20px;
+    padding: 10%;
     border-radius: 10px;
+    box-sizing: border-box;
+    height: 90%;
+    max-width: 100%;
+    aspect-ratio: 1 / 1;
+    flex-direction: column;
+    justify-content: space-between;
+    overflow: hidden;
 }
 
 .light {
+    width: 100%;
+    height: 100%;
+    aspect-ratio: 1 / 1;
     border-radius: 50%;
-    background-color: #3d3535;
-    background: repeating-linear-gradient(#333, #443 5px);
+    background: #3d3535 repeating-linear-gradient(#333, #443 5px);
 }
 
 .light-red,
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.ts
 
b/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.ts
index b62fcc18f0..220598544c 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.ts
+++ 
b/ui/src/app/data-explorer-shared/components/charts/status/status-widget.component.ts
@@ -58,10 +58,6 @@ export class StatusWidgetComponent
 
     ngOnInit(): void {
         super.ngOnInit();
-        this.onResize(
-            this.gridsterItemComponent.width - this.widthOffset,
-            this.gridsterItemComponent.height - this.heightOffset,
-        );
         this.updateSettings();
     }
 
@@ -134,12 +130,7 @@ export class StatusWidgetComponent
         }
     }
 
-    onResize(width: number, heigth: number): void {
-        this.containerHeight = heigth * 0.7;
-        this.containerWidth = this.containerHeight;
-        this.lightWidth = this.containerHeight;
-        this.lightHeight = this.lightWidth;
-    }
+    onResize(width: number, heigth: number): void {}
 
     handleUpdatedFields(
         addedFields: DataExplorerField[],
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/table/table-widget.component.ts
 
b/ui/src/app/data-explorer-shared/components/charts/table/table-widget.component.ts
index a125322eee..e922ad992e 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/table/table-widget.component.ts
+++ 
b/ui/src/app/data-explorer-shared/components/charts/table/table-widget.component.ts
@@ -142,7 +142,7 @@ export class TableWidgetComponent
         this.refreshColumns();
     }
 
-    onResize(width: number, height: number) {}
+    onResize(_width: number, _height: number) {}
 
     beforeDataFetched() {}
 
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.html
 
b/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.html
index aa6aad2576..d18e569eab 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.html
+++ 
b/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.html
@@ -30,49 +30,35 @@
         </sp-no-data-in-date-range>
     }
 
-    <div fxLayoutAlign="center center">
+    <div
+        class="traffic-light-wrapper"
+        fxFlex
+        fxLayout="column"
+        fxLayoutAlign="center center"
+    >
         <div
             class="tl-container"
             [ngClass]="selectedToShowValue ? 'no-border-container' : ''"
-            [ngStyle]="{
-                width: containerWidth + 'px',
-                height: containerHeight + 'px'
-            }"
         >
             <div
                 class="light"
                 [ngClass]="{ 'light-red': activeClass === 'red' }"
-                [ngStyle]="{
-                    width: lightWidth + 'px',
-                    height: lightHeight + 'px'
-                }"
             ></div>
             <div
                 class="light"
                 [ngClass]="{ 'light-yellow': activeClass === 'yellow' }"
-                [ngStyle]="{
-                    width: lightWidth + 'px',
-                    height: lightHeight + 'px'
-                }"
             ></div>
             <div
                 class="light"
                 [ngClass]="{ 'light-green': activeClass === 'green' }"
-                [ngStyle]="{
-                    width: lightWidth + 'px',
-                    height: lightHeight + 'px'
-                }"
             ></div>
         </div>
-    </div>
-    <div class="light-value-container">
-        @if (selectedToShowValue) {
-            <div
-                class="light-value"
-                [ngStyle]="{ width: containerWidth + 'px' }"
-            >
-                {{ displayed_value }}
-            </div>
-        }
+        <div class="light-value-container">
+            @if (selectedToShowValue) {
+                <div class="light-value">
+                    {{ displayed_value }}
+                </div>
+            }
+        </div>
     </div>
 </div>
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.scss
 
b/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.scss
index cc13ba4625..918f615ee5 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.scss
+++ 
b/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.scss
@@ -19,27 +19,40 @@
     height: 100%;
 }
 
-.tl-container {
-    background-color: #222;
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
+.traffic-light-wrapper {
+    display: inline-flex;
     flex-direction: column;
+    align-items: center;
+}
+
+.tl-container {
+    height: 90%;
+    aspect-ratio: 1 / 3;
+
+    box-sizing: border-box;
     padding: 10px;
     border-radius: 10px;
+    background: #222;
+
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    align-items: center;
 }
 
 .no-border-container {
-    border-bottom-left-radius: 0;
-    border-bottom-right-radius: 0;
-    border-top-left-radius: 10px;
-    border-top-right-radius: 10px;
+    border-radius: 10px 10px 0 0;
 }
 
 .light {
+    height: auto;
+    flex: 0 0 auto;
+
+    width: 96%;
+    aspect-ratio: 1 / 1;
     border-radius: 50%;
-    background-color: #3d3535;
-    background: repeating-linear-gradient(#333, #443 5px);
+
+    background: #3d3535 repeating-linear-gradient(#333, #443 5px);
 }
 
 .light-red,
@@ -73,6 +86,7 @@
 .light-value-container {
     background-color: #222;
     border-radius: 10px;
+    width: 100%;
 }
 
 .light-value {
@@ -82,6 +96,7 @@
     text-align: center;
     background-color: #222;
     padding: 10px;
+
     border-bottom-left-radius: 10px;
     border-bottom-right-radius: 10px;
     border-top-left-radius: 0;
diff --git 
a/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.ts
 
b/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.ts
index c7da1f2704..5720b0baec 100644
--- 
a/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.ts
+++ 
b/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.ts
@@ -38,15 +38,6 @@ export class TrafficLightWidgetComponent
     header: string[];
     fieldIndex: number;
 
-    width: number;
-    height: number;
-
-    containerWidth: number;
-    containerHeight: number;
-
-    lightWidth: number;
-    lightHeight: number;
-
     selectedWarningRange: number;
     selectedFieldToObserve: DataExplorerField;
     selectedUpperLimit: boolean;
@@ -58,10 +49,6 @@ export class TrafficLightWidgetComponent
 
     ngOnInit(): void {
         super.ngOnInit();
-        this.onResize(
-            this.gridsterItemComponent.width - this.widthOffset,
-            this.gridsterItemComponent.height - this.heightOffset,
-        );
         this.updateSettings();
     }
 
@@ -155,12 +142,7 @@ export class TrafficLightWidgetComponent
         }
     }
 
-    onResize(width: number, heigth: number) {
-        this.containerHeight = heigth * 0.8;
-        this.containerWidth = this.containerHeight / 3;
-        this.lightWidth = (this.containerHeight * 0.9) / 3;
-        this.lightHeight = this.lightWidth;
-    }
+    onResize(width: number, heigth: number) {}
 
     handleUpdatedFields(
         addedFields: DataExplorerField[],
diff --git a/ui/src/app/data-explorer-shared/data-explorer-shared.module.ts 
b/ui/src/app/data-explorer-shared/data-explorer-shared.module.ts
index 32b3580848..2e27da662a 100644
--- a/ui/src/app/data-explorer-shared/data-explorer-shared.module.ts
+++ b/ui/src/app/data-explorer-shared/data-explorer-shared.module.ts
@@ -43,7 +43,6 @@ import { CommonModule } from '@angular/common';
 import { LeafletModule } from '@bluehalo/ngx-leaflet';
 import { CoreUiModule } from '../core-ui/core-ui.module';
 import { MatTabsModule } from '@angular/material/tabs';
-import { GridsterModule } from 'angular-gridster2';
 import { FlexLayoutModule } from '@ngbracket/ngx-layout';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { ColorPickerComponent, ColorPickerDirective } from 'ngx-color-picker';
@@ -127,7 +126,6 @@ import { ColorMappingOptionsConfigComponent } from 
'./components/chart-config/co
         LeafletModule,
         CoreUiModule,
         MatTabsModule,
-        GridsterModule,
         FlexLayoutModule,
         FormsModule,
         ColorPickerComponent,
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 86c996c499..0340c63f46 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
@@ -16,11 +16,6 @@
  *
  */
 
-import {
-    GridsterConfig,
-    GridsterItem,
-    GridsterItemComponent,
-} from 'angular-gridster2';
 import {
     ClientDashboardItem,
     DataExplorerDataConfig,
@@ -37,24 +32,20 @@ import { FieldUpdateInfo } from './field-update.model';
 import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
 import { Observable } from 'rxjs';
 
-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-export type IDataViewDashboardConfig = GridsterConfig;
-
 export interface BaseWidgetData<T extends DataExplorerWidgetModel> {
     removeWidgetCallback: EventEmitter<boolean>;
     timerCallback: EventEmitter<boolean>;
     errorCallback: EventEmitter<SpLogMessage>;
 
-    gridsterItem: GridsterItem;
-    gridsterItemComponent: GridsterItemComponent;
     editMode: boolean;
     kioskMode: boolean;
     observableGenerator: ObservableGenerator;
-
+    initialSize: WidgetSize;
     timeSettings: TimeSettings;
 
     dataViewDashboardItem: ClientDashboardItem;
     dataExplorerWidget: T;
+    dataViewMode: boolean;
     previewMode: boolean;
     gridMode: boolean;
     widgetIndex?: number;
diff --git a/ui/src/app/data-explorer-shared/models/gridster-info.model.ts 
b/ui/src/app/data-explorer-shared/models/gridster-info.model.ts
index 58af6d1329..504306c32d 100644
--- a/ui/src/app/data-explorer-shared/models/gridster-info.model.ts
+++ b/ui/src/app/data-explorer-shared/models/gridster-info.model.ts
@@ -16,9 +16,8 @@
  *
  */
 
-import { GridsterItem, GridsterItemComponent } from 'angular-gridster2';
-
-export interface GridsterInfo {
-    gridsterItem: GridsterItem;
-    gridsterItemComponent: GridsterItemComponent;
+export interface ResizeInfo {
+    width: number;
+    height: number;
+    widgetId: string;
 }
diff --git a/ui/src/app/data-explorer-shared/services/resize.service.ts 
b/ui/src/app/data-explorer-shared/services/resize.service.ts
index f0821b9065..ead8ea0057 100644
--- a/ui/src/app/data-explorer-shared/services/resize.service.ts
+++ b/ui/src/app/data-explorer-shared/services/resize.service.ts
@@ -18,13 +18,13 @@
 
 import { Injectable } from '@angular/core';
 import { Subject } from 'rxjs';
-import { GridsterInfo } from '../models/gridster-info.model';
+import { ResizeInfo } from '../models/gridster-info.model';
 
 @Injectable({ providedIn: 'root' })
 export class ResizeService {
-    public resizeSubject: Subject<GridsterInfo> = new Subject<GridsterInfo>();
+    public resizeSubject: Subject<ResizeInfo> = new Subject<ResizeInfo>();
 
-    public notify(info: GridsterInfo): void {
+    public notify(info: ResizeInfo): void {
         this.resizeSubject.next(info);
     }
 }
diff --git 
a/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.html
 
b/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.html
index 15adc5ecbc..59931c9164 100644
--- 
a/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.html
+++ 
b/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.html
@@ -74,16 +74,13 @@
                         <div #panel fxFlex="100" fxLayout="column">
                             @if (
                                 dataView &&
-                                gridsterItemComponent &&
                                 dataView.dataConfig?.sourceConfigs?.length > 0
                             ) {
                                 <sp-data-explorer-chart-container
+                                    fxFlex
                                     [dataViewMode]="true"
                                     [editMode]="editMode"
                                     [configuredWidget]="dataView"
-                                    [gridsterItemComponent]="
-                                        gridsterItemComponent
-                                    "
                                     [timeSettings]="timeSettings"
                                     [observableGenerator]="observableGenerator"
                                     [dataLakeMeasure]="
diff --git 
a/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.ts
 
b/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.ts
index 4c033bedcc..04c836b948 100644
--- 
a/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.ts
+++ 
b/ui/src/app/data-explorer/components/chart-view/data-explorer-chart-view.component.ts
@@ -26,7 +26,6 @@ import {
 } from '@angular/core';
 import {
     ChartService,
-    DashboardConfig,
     DataExplorerWidgetModel,
     DataLakeMeasure,
     EventPropertyUnion,
@@ -60,8 +59,8 @@ import { ResizeEchartsService } from 
'../../../data-explorer-shared/services/res
 import { AssetDialogComponent } from '../../dialog/asset-dialog.component';
 import { AuthService } from '../../../services/auth.service';
 import { UserRole } from '../../../_enums/user-role.enum';
-import { Tuple2 } from 'src/app/core-model/base/Tuple2';
-import { ChartFieldProviderService } from 
'src/app/data-explorer-shared/services/chart-field-provider.service';
+import { ChartFieldProviderService } from 
'../../../data-explorer-shared/services/chart-field-provider.service';
+import { Tuple2 } from '../../../core-model/base/Tuple2';
 
 @Component({
     selector: 'sp-data-explorer-data-view',
@@ -79,7 +78,6 @@ export class DataExplorerChartViewComponent
     dataView: DataExplorerWidgetModel;
     originalDataView: DataExplorerWidgetModel;
     dataLakeMeasure: DataLakeMeasure;
-    gridsterItemComponent: any;
     drawerWidth = 450;
     panelWidth = '100%';
 
@@ -216,7 +214,6 @@ export class DataExplorerChartViewComponent
         setTimeout(() => {
             const width = this.outerPanel.nativeElement.offsetWidth;
             const height = this.outerPanel.nativeElement.offsetHeight;
-            this.gridsterItemComponent = { width, height };
             this.timeSelectionService.notify(this.timeSettings);
             this.updateQueryParams(this.timeSettings);
         });
@@ -402,10 +399,7 @@ export class DataExplorerChartViewComponent
         }, 100);
     }
 
-    private async saveAssets(
-        linkageData: LinkageData[],
-        data: DashboardConfig,
-    ): Promise<void> {
+    private async saveAssets(linkageData: LinkageData[]): Promise<void> {
         await this.assetSaveService.saveSelectedAssets(
             this.selectedAssets,
             linkageData,
@@ -419,7 +413,7 @@ export class DataExplorerChartViewComponent
         try {
             linkageData = this.createLinkageData(data);
 
-            this.saveAssets(linkageData, data);
+            this.saveAssets(linkageData);
         } catch (err) {
             console.error('Error in addToAsset:', err);
         }
diff --git a/ui/src/app/data-explorer/data-explorer.module.ts 
b/ui/src/app/data-explorer/data-explorer.module.ts
index e35f0a553a..2b16241630 100644
--- a/ui/src/app/data-explorer/data-explorer.module.ts
+++ b/ui/src/app/data-explorer/data-explorer.module.ts
@@ -29,8 +29,6 @@ import { MatSliderModule } from '@angular/material/slider';
 import { MatSnackBarModule } from '@angular/material/snack-bar';
 import { MatTabsModule } from '@angular/material/tabs';
 import { LeafletModule } from '@bluehalo/ngx-leaflet';
-
-import { GridsterModule } from 'angular-gridster2';
 import { ColorPickerComponent, ColorPickerDirective } from 'ngx-color-picker';
 import { PlatformServicesModule } from '@streampipes/platform-services';
 import { CoreUiModule } from '../core-ui/core-ui.module';
@@ -118,7 +116,6 @@ import { AssetDialogComponent } from 
'./dialog/asset-dialog.component';
         LeafletModule,
         CoreUiModule,
         MatTabsModule,
-        GridsterModule,
         FlexLayoutModule,
         FormsModule,
         ColorPickerComponent,
diff --git a/ui/src/app/editor/editor.module.ts 
b/ui/src/app/editor/editor.module.ts
index f78a1691c2..a6dc1cd36d 100644
--- a/ui/src/app/editor/editor.module.ts
+++ b/ui/src/app/editor/editor.module.ts
@@ -19,7 +19,6 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FlexLayoutModule } from '@ngbracket/ngx-layout';
-import { GridsterModule } from 'angular-gridster2';
 import { MatTabsModule } from '@angular/material/tabs';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { EditorComponent } from './editor.component';
@@ -117,7 +116,6 @@ import { TranslatePipe } from '@ngx-translate/core';
         CommonModule,
         MatTabsModule,
         MatListModule,
-        GridsterModule,
         FlexLayoutModule,
         FormsModule,
         MatProgressSpinnerModule,
diff --git a/ui/src/scss/main.scss b/ui/src/scss/main.scss
index 7541a2ee68..132079f868 100644
--- a/ui/src/scss/main.scss
+++ b/ui/src/scss/main.scss
@@ -62,3 +62,5 @@
 
 @use './sp/buttons-mat3';
 @use './sp/forms-mat3';
+
+@use 'gridstack/dist/gridstack.min.css';

Reply via email to