This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch 3992-improve-widget-handling-in-dashboard
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to 
refs/heads/3992-improve-widget-handling-in-dashboard by this push:
     new 9d9b63d38a feat: Replace gridster with gridstack in dashboard
9d9b63d38a is described below

commit 9d9b63d38a9de1d50abfb0b69cffb354995a999b
Author: Dominik Riemer <[email protected]>
AuthorDate: Fri Nov 28 14:26:56 2025 +0100

    feat: Replace gridster with gridstack in dashboard
---
 ui/package-lock.json                               |  32 ++-
 ui/package.json                                    |   2 +-
 .../streampipes/platform-services/package.json     |   3 +-
 .../src/lib/model/dashboard/dashboard.model.ts     |  13 +-
 .../chart-view/abstract-chart-view.directive.ts    |   5 +-
 .../grid-view/dashboard-grid-view.component.html   |  58 ++--
 .../grid-view/dashboard-grid-view.component.scss   |  31 +--
 .../grid-view/dashboard-grid-view.component.ts     |  76 ++----
 .../slide-view/dashboard-slide-view.component.html |   4 -
 .../slide-view/dashboard-slide-view.component.ts   |  47 ++--
 .../dashboard-shared/dashboard-shared.module.ts    |   4 +-
 .../components/panel/dashboard-panel.component.ts  |   2 +
 ui/src/app/dashboard/dashboard.module.ts           |   2 -
 .../data-explorer-chart-container.component.html   | 301 ++++++++++-----------
 .../data-explorer-chart-container.component.scss   |   2 +-
 .../data-explorer-chart-container.component.ts     |  41 ++-
 .../base/base-data-explorer-widget.directive.ts    |  18 +-
 .../charts/image/image-widget.component.ts         |   8 +-
 .../charts/status/status-widget.component.ts       |   8 +-
 .../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             |  11 +-
 .../models/gridster-info.model.ts                  |   9 +-
 .../services/resize.service.ts                     |   6 +-
 .../data-explorer-chart-view.component.html        |   5 +-
 .../data-explorer-chart-view.component.ts          |  10 +-
 ui/src/app/data-explorer/data-explorer.module.ts   |   3 -
 ui/src/app/editor/editor.module.ts                 |   2 -
 ui/src/scss/main.scss                              |   2 +
 31 files changed, 345 insertions(+), 459 deletions(-)

diff --git a/ui/package-lock.json b/ui/package-lock.json
index 712dbb314a..84c1556a0f 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..112976b16b 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 {
+export interface ClientDashboardItem {
     widgetId: 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/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..4409e749b4 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
@@ -78,6 +78,8 @@ export abstract class AbstractChartViewDirective {
 
     loadWidgetConfigs() {
         this.dashboard.widgets.forEach(widgetConfig => {
+            widgetConfig.w ??= widgetConfig.cols;
+            widgetConfig.h ??= widgetConfig.rows;
             const availableWidget = this.widgets.find(
                 w => w.elementId === widgetConfig.id,
             );
@@ -133,11 +135,8 @@ export abstract class AbstractChartViewDirective {
         } 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..0f38edfc20 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,27 @@
         <h3>{{ dashboard.description }}</h3>
     </div>
 }
-<gridster
-    [options]="options"
-    [ngClass]="editMode ? 'edit' : ''"
-    class="custom-gridster-style"
->
+<gridstack [options]="gridOptions" 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>
+        <gridstack-item [options]="item">
+            @if (widgetsAvailable && configuredWidgets.has(item.id)) {
+                <sp-data-explorer-chart-container
+                    [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"
+                ></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..ddc0b947cb 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 } from 'gridstack/dist/angular';
 
 @Component({
     selector: 'sp-dashboard-grid-view',
@@ -42,62 +37,45 @@ 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: 'auto',
+            disableResize: !this.editMode,
+            disableDrag: !this.editMode,
+            float: true,
         };
     }
 
     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();
-    }
-
     onWidgetsAvailable(): void {}
 
     isGridView(): boolean {
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..5fa0ade591 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,9 +55,6 @@
                     widgetsVisible
                 ) {
                     <sp-data-explorer-chart-container
-                        [ngStyle]="{
-                            height: gridsterItemComponent.height - 15 + 'px'
-                        }"
                         [timeSettings]="timeSettings"
                         [globalTimeEnabled]="
                             
dashboard.dashboardGeneralSettings.globalTimeEnabled
@@ -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..d6fa8ffcda 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;
@@ -69,23 +59,22 @@ export class DashboardSlideViewComponent
         });
     }
 
-    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() {}
+    // ngAfterViewInit(): void {
+    //     const obs = new ResizeObserver(entries => {
+    //         entries.forEach(entry => {
+    //             const cr = entry.contentRect;
+    //             this.gridsterItemComponent.width = cr.width;
+    //             this.gridsterItemComponent.height = cr.height;
+    //             console.log(entry);
+    //             this.resizeService.notify({
+    //                 gridsterItem:
+    //                     this.dashboard.widgets[this.selectedWidgetIndex],
+    //                 gridsterItemComponent: this.gridsterItemComponent,
+    //             });
+    //         });
+    //     });
+    //     obs.observe(document.getElementById('slideViewOuter'));
+    // }
 
     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/dashboard-panel.component.ts 
b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
index 69879120c9..6520f4f1f0 100644
--- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
+++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
@@ -134,6 +134,8 @@ export class DashboardPanelComponent
         dashboardItem.id = dataViewElementId;
         dashboardItem.cols = 3;
         dashboardItem.rows = 4;
+        dashboardItem.w = 3;
+        dashboardItem.h = 4;
         dashboardItem.x = 0;
         dashboardItem.y = 0;
         dashboardItem.widgetId =
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..175a31dbd1 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,168 @@
 ~
 -->
 
-<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: 'calc(100% - 4px)'
+    }"
+    [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>
+                                </sp-time-selector-menu>
                             }
-                            <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>
-                            }
-                        </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 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>
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..f6bf324699 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
@@ -40,7 +40,7 @@
     display: flex;
     flex-flow: column;
     height: 100%;
-    padding-top: 5px;
+    border: 1px solid var(--color-bg-2);
 }
 
 .box .row.content {
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 8c5c007a1b..0a234cd986 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;
 
@@ -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?.widgetId || undefined,
+                });
+            }, 150);
+        });
+        obs.observe(container);
+    }
+
     ngOnChanges(changes: SimpleChanges): void {
         if (changes.widgetIndex && this.componentRef?.instance) {
             this.componentRef.instance.widgetIndex =
@@ -230,6 +254,7 @@ export class DataExplorerChartContainerComponent
     }
 
     ngOnDestroy() {
+        this.resizeObserver?.disconnect();
         this.componentRef?.destroy();
         this.authSubscription?.unsubscribe();
         this.widgetTypeChangedSubscription?.unsubscribe();
@@ -261,9 +286,7 @@ export class DataExplorerChartContainerComponent
             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;
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..5cc4905a67 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,7 +25,6 @@ import {
     OnInit,
     Output,
 } from '@angular/core';
-import { GridsterItem, GridsterItemComponent } from 'angular-gridster2';
 import { ChartConfigurationService } from 
'../../../services/chart-configuration.service';
 import {
     ClientDashboardItem,
@@ -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;
@@ -182,14 +180,10 @@ export abstract class BaseDataExplorerWidgetDirective<
             this.resizeSub = this.resizeService.resizeSubject.subscribe(
                 info => {
                     if (
-                        info.gridsterItem.id ===
-                        this.dataExplorerWidget.elementId
+                        this.dataViewMode ||
+                        info.widgetId === this.dataViewDashboardItem.widgetId
                     ) {
-                        this.onResize(
-                            this.gridsterItemComponent.width - 
this.widthOffset,
-                            this.gridsterItemComponent.height -
-                                this.heightOffset,
-                        );
+                        this.onResize(info.width, info.height);
                     }
                 },
             );
@@ -216,10 +210,6 @@ export abstract class BaseDataExplorerWidgetDirective<
                 },
             );
         this.updateData();
-        this.onResize(
-            this.gridsterItemComponent.width - this.widthOffset,
-            this.gridsterItemComponent.height - this.heightOffset,
-        );
     }
 
     public cleanupSubscriptions(): void {
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..a29857b5e2 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,10 @@ export class ImageWidgetComponent
 
     ngOnInit(): void {
         super.ngOnInit();
-        this.onResize(
-            this.gridsterItemComponent.width,
-            this.gridsterItemComponent.height - 53,
-        );
+        // this.onResize(
+        //     this.gridsterItemComponent.width,
+        //     this.gridsterItemComponent.height - 53,
+        // );
         this.imageBaseUrl = this.dataLakeRestService.dataLakeUrl + '/images/';
     }
 
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..2681bc225d 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,10 @@ export class StatusWidgetComponent
 
     ngOnInit(): void {
         super.ngOnInit();
-        this.onResize(
-            this.gridsterItemComponent.width - this.widthOffset,
-            this.gridsterItemComponent.height - this.heightOffset,
-        );
+        // this.onResize(
+        //     this.gridsterItemComponent.width - this.widthOffset,
+        //     this.gridsterItemComponent.height - this.heightOffset,
+        // );
         this.updateSettings();
     }
 
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..0da8e49f0c 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: 90%;
+    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..b6e15d442b 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,16 +32,11 @@ 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;
@@ -55,6 +45,7 @@ export interface BaseWidgetData<T extends 
DataExplorerWidgetModel> {
 
     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 1273803b2b..59b9f1a9cc 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
@@ -73,16 +73,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 e32fe3cc06..c3dfd73afc 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,
     LinkageData,
@@ -75,7 +74,6 @@ export class DataExplorerChartViewComponent
     dataView: DataExplorerWidgetModel;
     originalDataView: DataExplorerWidgetModel;
     dataLakeMeasure: DataLakeMeasure;
-    gridsterItemComponent: any;
     drawerWidth = 450;
     panelWidth = '100%';
 
@@ -168,7 +166,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);
         });
@@ -347,10 +344,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,
@@ -364,7 +358,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 87f584497f..b845c230cb 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