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

commit 62ddf7171e0a64a7d6e2b65e0766545b696f34cb
Author: Dominik Riemer <[email protected]>
AuthorDate: Tue Dec 2 15:58:21 2025 +0100

    Fix size management of widgets
---
 .../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                               | 298 ++++++++++++++++-----
 .../src/lib/model/dashboard/dashboard.model.ts     |   2 +-
 .../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    |  34 +--
 .../grid-view/dashboard-grid-view.component.html   |  24 +-
 .../grid-view/dashboard-grid-view.component.ts     |  21 +-
 .../slide-view/dashboard-slide-view.component.html |   2 +-
 .../slide-view/dashboard-slide-view.component.ts   |  18 --
 .../chart-selection-panel.component.html           |   5 -
 .../panel/dashboard-panel.component.scss           |   2 +-
 .../components/panel/dashboard-panel.component.ts  |  26 +-
 .../data-explorer-chart-container.component.html   |   7 +-
 .../data-explorer-chart-container.component.scss   |   4 +-
 .../data-explorer-chart-container.component.ts     |  61 +++--
 .../base/base-data-explorer-widget.directive.ts    |  49 ++--
 .../charts/base/echarts-widget.component.html      |   2 +-
 .../charts/base/echarts-widget.component.ts        |  18 +-
 .../charts/gauge/gauge-renderer.service.ts         |  10 +-
 .../charts/heatmap/heatmap-renderer.service.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.scss            |   2 +-
 .../models/dataview-dashboard.model.ts             |   2 +-
 .../data-explorer-chart-view.component.ts          |   4 +-
 34 files changed, 518 insertions(+), 259 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..d874e11567 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
+  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..86cde709b2 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
@@ -32,6 +32,7 @@ import 
org.apache.streampipes.service.core.migrations.v0980.ModifyAssetLinkTypes
 import 
org.apache.streampipes.service.core.migrations.v0980.ModifyAssetLinksMigration;
 import 
org.apache.streampipes.service.core.migrations.v099.AddAssetManagementViewMigration;
 import 
org.apache.streampipes.service.core.migrations.v099.CreateAssetPermissionMigration;
+import 
org.apache.streampipes.service.core.migrations.v099.UniqueDashboardIdMigration;
 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.v970.AddDataLakePipelineTemplateMigration;
@@ -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 7799d762c8..1049ed3bb5 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -182,6 +182,24 @@
         }
       }
     },
+    "node_modules/@angular-devkit/architect/node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz";,
+      "integrity": 
"sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/";
+      }
+    },
     "node_modules/@angular-devkit/architect/node_modules/readdirp": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz";,
@@ -189,6 +207,7 @@
       "dev": true,
       "license": "MIT",
       "optional": true,
+      "peer": true,
       "engines": {
         "node": ">= 14.18.0"
       },
@@ -392,6 +411,24 @@
         "semver": "bin/semver.js"
       }
     },
+    "node_modules/@angular-devkit/build-angular/node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz";,
+      "integrity": 
"sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/";
+      }
+    },
     
"node_modules/@angular-devkit/build-angular/node_modules/convert-source-map": {
       "version": "2.0.0",
       "resolved": 
"https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz";,
@@ -435,6 +472,7 @@
       "dev": true,
       "license": "MIT",
       "optional": true,
+      "peer": true,
       "engines": {
         "node": ">= 14.18.0"
       },
@@ -510,6 +548,24 @@
         }
       }
     },
+    "node_modules/@angular-devkit/schematics/node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz";,
+      "integrity": 
"sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/";
+      }
+    },
     "node_modules/@angular-devkit/schematics/node_modules/readdirp": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz";,
@@ -517,6 +573,7 @@
       "dev": true,
       "license": "MIT",
       "optional": true,
+      "peer": true,
       "engines": {
         "node": ">= 14.18.0"
       },
@@ -568,6 +625,24 @@
         }
       }
     },
+    "node_modules/@angular-eslint/builder/node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz";,
+      "integrity": 
"sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/";
+      }
+    },
     "node_modules/@angular-eslint/builder/node_modules/readdirp": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz";,
@@ -575,6 +650,7 @@
       "dev": true,
       "license": "MIT",
       "optional": true,
+      "peer": true,
       "engines": {
         "node": ">= 14.18.0"
       },
@@ -669,6 +745,24 @@
         }
       }
     },
+    "node_modules/@angular-eslint/schematics/node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz";,
+      "integrity": 
"sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/";
+      }
+    },
     "node_modules/@angular-eslint/schematics/node_modules/readdirp": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz";,
@@ -676,6 +770,7 @@
       "dev": true,
       "license": "MIT",
       "optional": true,
+      "peer": true,
       "engines": {
         "node": ">= 14.18.0"
       },
@@ -719,7 +814,6 @@
       "resolved": 
"https://registry.npmjs.org/@angular/animations/-/animations-19.2.13.tgz";,
       "integrity": 
"sha512-x9LYcSndY9BdwuRxTx0gXvlLrvJyzjnWoaIoVLrAZWZbKfQh2+HK4XkclbzNvn8RMeoBpZZatcC3ZBC1TffjtA==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "tslib": "^2.3.0"
       },
@@ -942,7 +1036,6 @@
       "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-19.2.17.tgz";,
       "integrity": 
"sha512-3jG33S+5+kqymCRwQlcSEWlY5rYwkKxe0onln+NXxT0/kteR02vWvv1+Li4/QqSr5JvsGHEhAFsZaR9QtOzbdA==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "parse5": "^7.1.2",
         "tslib": "^2.3.0"
@@ -1015,6 +1108,24 @@
         }
       }
     },
+    "node_modules/@angular/cli/node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz";,
+      "integrity": 
"sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/";
+      }
+    },
     "node_modules/@angular/cli/node_modules/readdirp": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz";,
@@ -1022,6 +1133,7 @@
       "dev": true,
       "license": "MIT",
       "optional": true,
+      "peer": true,
       "engines": {
         "node": ">= 14.18.0"
       },
@@ -1035,7 +1147,6 @@
       "resolved": 
"https://registry.npmjs.org/@angular/common/-/common-19.2.13.tgz";,
       "integrity": 
"sha512-k7I4bLH+bgI02VL81MaL0NcZPfVl153KAiARwk+ZlkmQjMnWlmsAHQ6054SWoNEXwP855ATR6YYDVqJh8TZaqw==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "tslib": "^2.3.0"
       },
@@ -1052,7 +1163,6 @@
       "resolved": 
"https://registry.npmjs.org/@angular/compiler/-/compiler-19.2.13.tgz";,
       "integrity": 
"sha512-xAj1peVrQtb65NsULmz8ocH4QZ4ESG5YiiVzJ0tLz8t280xY+QhJiM6C0+jaCVHLXvZp0c7GEzsYjL6x1HmabQ==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "tslib": "^2.3.0"
       },
@@ -1066,7 +1176,6 @@
       "integrity": 
"sha512-SSuzKMcktvd6VexivDwhP7ctQBD6yyoo5E91I7Frn5nrvYNM+TIyYcXmJ4dgby5/GrPZGfm2sWl3ARr2vbCgtA==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "@babel/core": "7.26.9",
         "@jridgewell/sourcemap-codec": "^1.4.14",
@@ -1125,7 +1234,6 @@
       "resolved": 
"https://registry.npmjs.org/@angular/core/-/core-19.2.13.tgz";,
       "integrity": 
"sha512-HpzDI3TSQzVV2mmQ8KwH0JSLNlYNemNrEo3L3hcqqYwTzqFgAK4y1Q2Xym3yiRSLTenYhW5D4CQqOHUQ26HxwQ==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "tslib": "^2.3.0"
       },
@@ -1142,7 +1250,6 @@
       "resolved": 
"https://registry.npmjs.org/@angular/forms/-/forms-19.2.13.tgz";,
       "integrity": 
"sha512-g46KQFrBJhmknczlGEYvWVsPhk7ZI8WOuWkzWEl81Lf3ojEVA/OF8w4VwKZL7wOMKRxOUhuYq6tNPm8tBjtryw==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "tslib": "^2.3.0"
       },
@@ -1178,7 +1285,6 @@
       "resolved": 
"https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-19.2.13.tgz";,
       "integrity": 
"sha512-YeuRfGbo8qFepoAUoubk/1079wOown5Qgr9eAhgCXxoXb2rt87xbJF3YCSSim38SP3kK1rJQqP+Sr8n7ef+n5Q==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "tslib": "^2.3.0"
       },
@@ -1299,7 +1405,6 @@
       "integrity": 
"sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "@ampproject/remapping": "^2.2.0",
         "@babel/code-frame": "^7.26.2",
@@ -4164,7 +4269,6 @@
       "integrity": 
"sha512-G1ytyOoHh5BphmEBxSwALin3n1KGNYB6yImbICcRQdzXfOGbuJ9Jske/Of5Sebk339NSGGNfUshnzK8YWkTPsQ==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "@inquirer/checkbox": "^4.1.2",
         "@inquirer/confirm": "^5.1.6",
@@ -5099,7 +5203,6 @@
       "resolved": 
"https://registry.npmjs.org/@ngx-loading-bar/core/-/core-6.0.2.tgz";,
       "integrity": 
"sha512-8r+OQEYXwvU+2ZXK6CY3Guh2yJuG8pQ2XNryHVbPZB2Ub3VmzhGWqjxXAQgxmsi+GxrD4m+nGmGZPeOrNH1ztA==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "tslib": "^2.0.0"
       },
@@ -6014,7 +6117,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/@rollup/rollup-linux-s390x-gnu": {
       "version": "4.34.8",
@@ -6172,6 +6276,24 @@
         }
       }
     },
+    "node_modules/@schematics/angular/node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz";,
+      "integrity": 
"sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/";
+      }
+    },
     "node_modules/@schematics/angular/node_modules/readdirp": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz";,
@@ -6179,6 +6301,7 @@
       "dev": true,
       "license": "MIT",
       "optional": true,
+      "peer": true,
       "engines": {
         "node": ">= 14.18.0"
       },
@@ -6828,7 +6951,6 @@
       "integrity": 
"sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "undici-types": "~6.19.2"
       }
@@ -7154,7 +7276,6 @@
       "integrity": 
"sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "@typescript-eslint/scope-manager": "8.46.1",
         "@typescript-eslint/types": "8.46.1",
@@ -7262,7 +7383,6 @@
       "integrity": 
"sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       },
@@ -7306,7 +7426,6 @@
       "integrity": 
"sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.7.0",
         "@typescript-eslint/scope-manager": "8.46.1",
@@ -7620,7 +7739,6 @@
       "integrity": 
"sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
       "devOptional": true,
       "license": "MIT",
-      "peer": true,
       "bin": {
         "acorn": "bin/acorn"
       },
@@ -7697,7 +7815,6 @@
       "integrity": 
"sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "fast-deep-equal": "^3.1.3",
         "fast-uri": "^3.0.1",
@@ -8355,7 +8472,8 @@
       "resolved": 
"https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz";,
       "integrity": 
"sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
       "devOptional": true,
-      "license": "ISC"
+      "license": "ISC",
+      "peer": true
     },
     "node_modules/browserslist": {
       "version": "4.24.4",
@@ -8377,7 +8495,6 @@
         }
       ],
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "caniuse-lite": "^1.0.30001688",
         "electron-to-chromium": "^1.5.73",
@@ -8633,6 +8750,7 @@
       "integrity": 
"sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
       "devOptional": true,
       "license": "MIT",
+      "peer": true,
       "engines": {
         "node": ">=10"
       },
@@ -8702,6 +8820,21 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/chevrotain": {
+      "version": "11.0.3",
+      "resolved": 
"https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz";,
+      "integrity": 
"sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==",
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "@chevrotain/cst-dts-gen": "11.0.3",
+        "@chevrotain/gast": "11.0.3",
+        "@chevrotain/regexp-to-ast": "11.0.3",
+        "@chevrotain/types": "11.0.3",
+        "@chevrotain/utils": "11.0.3",
+        "lodash-es": "4.17.21"
+      }
+    },
     "node_modules/chevrotain-allstar": {
       "version": "0.3.1",
       "resolved": 
"https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz";,
@@ -9065,8 +9198,7 @@
       "version": "5.65.18",
       "resolved": 
"https://registry.npmjs.org/codemirror/-/codemirror-5.65.18.tgz";,
       "integrity": 
"sha512-Gaz4gHnkbHMGgahNt3CA5HBk5lLQBqmD/pBgeB4kQU6OedZmqMBjlRF0LSrp2tJ4wlLNPm2FfaUd1pDy0mdlpA==",
-      "license": "MIT",
-      "peer": true
+      "license": "MIT"
     },
     "node_modules/color-convert": {
       "version": "2.0.1",
@@ -9753,6 +9885,16 @@
         "node": ">= 10.0.0"
       }
     },
+    "node_modules/cytoscape": {
+      "version": "3.33.1",
+      "resolved": 
"https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz";,
+      "integrity": 
"sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
     "node_modules/cytoscape-cose-bilkent": {
       "version": "4.1.0",
       "resolved": 
"https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz";,
@@ -10198,6 +10340,16 @@
         "node": ">=12"
       }
     },
+    "node_modules/d3-selection": {
+      "version": "3.0.0",
+      "resolved": 
"https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz";,
+      "integrity": 
"sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
+      "license": "ISC",
+      "optional": true,
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/d3-shape": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz";,
@@ -10374,6 +10526,7 @@
       "integrity": 
"sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
       "devOptional": true,
       "license": "MIT",
+      "peer": true,
       "engines": {
         "node": ">=10"
       },
@@ -10611,6 +10764,7 @@
       "integrity": 
"sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==",
       "devOptional": true,
       "license": "BSD-3-Clause",
+      "peer": true,
       "engines": {
         "node": ">=0.3.1"
       }
@@ -10931,7 +11085,6 @@
       "integrity": 
"sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "ansi-colors": "^4.1.1",
         "strip-ansi": "^6.0.1"
@@ -11168,7 +11321,6 @@
       "integrity": 
"sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
         "@eslint-community/regexpp": "^4.12.1",
@@ -12516,6 +12668,7 @@
       "integrity": 
"sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
       "devOptional": true,
       "license": "MIT",
+      "peer": true,
       "bin": {
         "he": "bin/he"
       }
@@ -13589,8 +13742,7 @@
       "resolved": 
"https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.6.0.tgz";,
       "integrity": 
"sha512-niVlkeYVRwKFpmfWg6suo6H9CrNnydfBLEqefM5UjibYS+UoTjZdmvPJSiuyrRLGnFj1eYRhFd/ch+5hSlsFVA==",
       "dev": true,
-      "license": "MIT",
-      "peer": true
+      "license": "MIT"
     },
     "node_modules/jest-worker": {
       "version": "27.5.1",
@@ -13629,7 +13781,6 @@
       "integrity": 
"sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "bin": {
         "jiti": "bin/jiti.js"
       }
@@ -13943,7 +14094,6 @@
       "integrity": 
"sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "@colors/colors": "1.5.0",
         "body-parser": "^1.19.0",
@@ -14439,8 +14589,7 @@
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.3.tgz";,
       "integrity": 
"sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==",
-      "license": "BSD-2-Clause",
-      "peer": true
+      "license": "BSD-2-Clause"
     },
     "node_modules/less": {
       "version": "4.2.2",
@@ -14448,7 +14597,6 @@
       "integrity": 
"sha512-tkuLHQlvWUTeQ3doAqnHbNn8T6WX1KA8yvbKG9x4VtKtIjHsVKQZCH11zRgAfbDAXC2UNIg/K9BYAAcEzUIrNg==",
       "dev": true,
       "license": "Apache-2.0",
-      "peer": true,
       "dependencies": {
         "copy-anything": "^2.0.1",
         "parse-node-version": "^1.0.1",
@@ -15344,7 +15492,6 @@
       "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz";,
       "integrity": 
"sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==",
       "license": "MIT",
-      "peer": true,
       "bin": {
         "marked": "bin/marked.js"
       },
@@ -15859,6 +16006,7 @@
       "integrity": 
"sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
       "devOptional": true,
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "readdirp": "^4.0.1"
       },
@@ -15875,6 +16023,7 @@
       "integrity": 
"sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
       "devOptional": true,
       "license": "MIT",
+      "peer": true,
       "engines": {
         "node": ">= 14.18.0"
       },
@@ -15889,6 +16038,7 @@
       "integrity": 
"sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
       "devOptional": true,
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "has-flag": "^4.0.0"
       },
@@ -16078,7 +16228,6 @@
       "integrity": 
"sha512-dFuwFsDJMBSd1YtmLLcX5bNNUCQUlRqgf34aXA+79PmkOP+0eF8GP2949wq3+jMjmFTNm80Oo8IUYiSLwklKCQ==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "@rollup/plugin-json": "^6.1.0",
         "@rollup/wasm-node": "^4.24.0",
@@ -17466,7 +17615,6 @@
         }
       ],
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "nanoid": "^3.3.8",
         "picocolors": "^1.1.1",
@@ -17798,7 +17946,6 @@
       "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz";,
       "integrity": 
"sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==",
       "license": "BSD-3-Clause",
-      "peer": true,
       "dependencies": {
         "eventemitter3": "^5.0.1",
         "lodash-es": "^4.17.21",
@@ -18340,7 +18487,6 @@
       "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz";,
       "integrity": 
"sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
       "license": "Apache-2.0",
-      "peer": true,
       "dependencies": {
         "tslib": "^2.1.0"
       }
@@ -18396,7 +18542,6 @@
       "integrity": 
"sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "chokidar": "^4.0.0",
         "immutable": "^5.0.2",
@@ -19721,7 +19866,6 @@
       "integrity": 
"sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==",
       "dev": true,
       "license": "BSD-2-Clause",
-      "peer": true,
       "dependencies": {
         "@jridgewell/source-map": "^0.3.3",
         "acorn": "^8.8.2",
@@ -19988,8 +20132,7 @@
       "version": "2.8.1",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz";,
       "integrity": 
"sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
-      "license": "0BSD",
-      "peer": true
+      "license": "0BSD"
     },
     "node_modules/tuf-js": {
       "version": "3.0.1",
@@ -20079,7 +20222,6 @@
       "integrity": 
"sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
       "dev": true,
       "license": "Apache-2.0",
-      "peer": true,
       "bin": {
         "tsc": "bin/tsc",
         "tsserver": "bin/tsserver"
@@ -20358,6 +20500,7 @@
       "integrity": 
"sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
       "dev": true,
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "esbuild": "^0.25.0",
         "fdir": "^6.4.4",
@@ -20439,7 +20582,8 @@
       "optional": true,
       "os": [
         "android"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-android-arm64": {
       "version": "4.41.1",
@@ -20453,7 +20597,8 @@
       "optional": true,
       "os": [
         "android"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-darwin-arm64": {
       "version": "4.41.1",
@@ -20467,7 +20612,8 @@
       "optional": true,
       "os": [
         "darwin"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-darwin-x64": {
       "version": "4.41.1",
@@ -20481,7 +20627,8 @@
       "optional": true,
       "os": [
         "darwin"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-freebsd-arm64": {
       "version": "4.41.1",
@@ -20495,7 +20642,8 @@
       "optional": true,
       "os": [
         "freebsd"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-freebsd-x64": {
       "version": "4.41.1",
@@ -20509,7 +20657,8 @@
       "optional": true,
       "os": [
         "freebsd"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-linux-arm-gnueabihf": {
       "version": "4.41.1",
@@ -20523,7 +20672,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-linux-arm-musleabihf": {
       "version": "4.41.1",
@@ -20537,7 +20687,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-linux-arm64-gnu": {
       "version": "4.41.1",
@@ -20551,7 +20702,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-linux-arm64-musl": {
       "version": "4.41.1",
@@ -20565,7 +20717,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-linux-loongarch64-gnu": {
       "version": "4.41.1",
@@ -20579,7 +20732,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
       "version": "4.41.1",
@@ -20593,7 +20747,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-linux-riscv64-gnu": {
       "version": "4.41.1",
@@ -20607,7 +20762,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-linux-s390x-gnu": {
       "version": "4.41.1",
@@ -20621,7 +20777,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-linux-x64-gnu": {
       "version": "4.41.1",
@@ -20635,7 +20792,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-linux-x64-musl": {
       "version": "4.41.1",
@@ -20649,7 +20807,8 @@
       "optional": true,
       "os": [
         "linux"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-win32-arm64-msvc": {
       "version": "4.41.1",
@@ -20663,7 +20822,8 @@
       "optional": true,
       "os": [
         "win32"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-win32-ia32-msvc": {
       "version": "4.41.1",
@@ -20677,7 +20837,8 @@
       "optional": true,
       "os": [
         "win32"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@rollup/rollup-win32-x64-msvc": {
       "version": "4.41.1",
@@ -20691,14 +20852,16 @@
       "optional": true,
       "os": [
         "win32"
-      ]
+      ],
+      "peer": true
     },
     "node_modules/vite/node_modules/@types/estree": {
       "version": "1.0.7",
       "resolved": 
"https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz";,
       "integrity": 
"sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
       "dev": true,
-      "license": "MIT"
+      "license": "MIT",
+      "peer": true
     },
     "node_modules/vite/node_modules/rollup": {
       "version": "4.41.1",
@@ -20706,6 +20869,7 @@
       "integrity": 
"sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==",
       "dev": true,
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "@types/estree": "1.0.7"
       },
@@ -20853,7 +21017,6 @@
       "integrity": 
"sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "@types/eslint-scope": "^3.7.7",
         "@types/estree": "^1.0.6",
@@ -20944,7 +21107,6 @@
       "integrity": 
"sha512-90SqqYXA2SK36KcT6o1bvwvZfJFcmoamqeJY7+boioffX9g9C0wjjJRGUrQIuh43pb0ttX7+ssavmj/WN2RHtA==",
       "dev": true,
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "@types/bonjour": "^3.5.13",
         "@types/connect-history-api-fallback": "^1.5.4",
@@ -21225,7 +21387,8 @@
       "resolved": 
"https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz";,
       "integrity": 
"sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==",
       "devOptional": true,
-      "license": "Apache-2.0"
+      "license": "Apache-2.0",
+      "peer": true
     },
     "node_modules/wrap-ansi": {
       "version": "6.2.0",
@@ -21312,7 +21475,6 @@
       "integrity": 
"sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==",
       "dev": true,
       "license": "ISC",
-      "peer": true,
       "bin": {
         "yaml": "bin.mjs"
       },
@@ -21355,6 +21517,7 @@
       "integrity": 
"sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
       "devOptional": true,
       "license": "MIT",
+      "peer": true,
       "dependencies": {
         "camelcase": "^6.0.0",
         "decamelize": "^4.0.0",
@@ -21371,6 +21534,7 @@
       "integrity": 
"sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
       "devOptional": true,
       "license": "BSD-3-Clause",
+      "peer": true,
       "bin": {
         "flat": "cli.js"
       }
@@ -21381,6 +21545,7 @@
       "integrity": 
"sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
       "devOptional": true,
       "license": "MIT",
+      "peer": true,
       "engines": {
         "node": ">=8"
       }
@@ -21426,8 +21591,7 @@
       "version": "0.15.1",
       "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz";,
       "integrity": 
"sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==",
-      "license": "MIT",
-      "peer": true
+      "license": "MIT"
     },
     "node_modules/zrender": {
       "version": "5.6.1",
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 112976b16b..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
@@ -24,7 +24,7 @@ import {
 } from '../gen/streampipes-model';
 
 export interface ClientDashboardItem {
-    widgetId: string;
+    dataViewElementId: string;
     widgetType: string;
     timeSettings?: TimeSettings;
     id: string;
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 4409e749b4..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,7 +69,6 @@ export abstract class AbstractChartViewDirective {
 
     startEditMode(value: DataExplorerWidgetModel) {
         this.startEditModeEmitter.emit(value);
-        this.currentlyConfiguredWidgetId = value.elementId;
     }
 
     loadWidgetConfigs() {
@@ -81,7 +76,7 @@ export abstract class AbstractChartViewDirective {
             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);
         });
@@ -89,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;
@@ -125,18 +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;
-        }
-    }
-
     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 0f38edfc20..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,20 +22,32 @@
         <h3>{{ dashboard.description }}</h3>
     </div>
 }
-<gridstack [options]="gridOptions" class="dashboard-outer" #grid>
-    @for (item of dashboard.widgets; let i = $index; track item.widgetId) {
+<gridstack
+    [options]="gridOptions"
+    (changeCB)="onGridChange($event)"
+    class="dashboard-outer"
+    #grid
+>
+    @for (item of dashboard.widgets; let i = $index; track item.id) {
         <gridstack-item [options]="item">
-            @if (widgetsAvailable && configuredWidgets.has(item.id)) {
+            @if (
+                widgetsAvailable &&
+                configuredWidgets.has(item.dataViewElementId)
+            ) {
                 <sp-data-explorer-chart-container
                     [timeSettings]="timeSettings"
                     [globalTimeEnabled]="
                         dashboard.dashboardGeneralSettings.globalTimeEnabled
                     "
-                    (deleteCallback)="propagateItemRemoval($event)"
+                    (deleteCallback)="deleteCallback.emit($event)"
                     (startEditModeEmitter)="startEditMode($event)"
                     [dashboardItem]="item"
-                    [configuredWidget]="configuredWidgets.get(item.id)"
-                    [dataLakeMeasure]="dataLakeMeasures.get(item.id)"
+                    [configuredWidget]="
+                        configuredWidgets.get(item.dataViewElementId)
+                    "
+                    [dataLakeMeasure]="
+                        dataLakeMeasures.get(item.dataViewElementId)
+                    "
                     [observableGenerator]="observableGenerator"
                     [editMode]="editMode"
                     [kioskMode]="kioskMode"
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 ddc0b947cb..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
@@ -27,7 +27,7 @@ import {
 } from '@angular/core';
 import { AbstractChartViewDirective } from '../abstract-chart-view.directive';
 import { GridStack, GridStackOptions } from 'gridstack';
-import { GridstackComponent } from 'gridstack/dist/angular';
+import { GridstackComponent, nodesCB } from 'gridstack/dist/angular';
 
 @Component({
     selector: 'sp-dashboard-grid-view',
@@ -61,10 +61,13 @@ export class DashboardGridViewComponent
             minRow: 5,
             column: this.dashboard.gridColumns,
             margin: 2,
-            cellHeight: 'auto',
+            cellHeight: 'initial',
             disableResize: !this.editMode,
             disableDrag: !this.editMode,
             float: true,
+            resizable: {
+                handles: 'w,e,se',
+            },
         };
     }
 
@@ -76,6 +79,20 @@ export class DashboardGridViewComponent
         }
     }
 
+    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 {}
 
     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 5fa0ade591..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
@@ -59,7 +59,7 @@
                         [globalTimeEnabled]="
                             
dashboard.dashboardGeneralSettings.globalTimeEnabled
                         "
-                        (deleteCallback)="propagateItemRemoval($event)"
+                        (deleteCallback)="deleteCallback.emit($event)"
                         (startEditModeEmitter)="startEditMode($event)"
                         [dashboardItem]="currentDashboardItem"
                         [configuredWidget]="currentWidget"
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 d6fa8ffcda..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
@@ -54,28 +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;
-    //             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/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 6520f4f1f0..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,28 +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);
             }
         });
     }
@@ -233,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;
@@ -331,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/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 175a31dbd1..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
@@ -21,7 +21,7 @@
     [ngStyle]="{
         background: configuredWidget.baseAppearanceConfig.backgroundColor,
         color: configuredWidget.baseAppearanceConfig.textColor,
-        height: 'calc(100% - 4px)'
+        height: '100%'
     }"
     [attr.data-cy]="
         'widget-' + configuredWidget.baseAppearanceConfig.widgetTitle
@@ -166,10 +166,7 @@
             </div>
         </div>
     }
-    <div
-        fxLayout="column"
-        class="widget-content p-0 gridster-item-content ml-0 mr-0 h-100 mw-100"
-    >
+    <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">
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 f6bf324699..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%;
-    border: 1px solid var(--color-bg-2);
+    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 f7ab3ae907..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
@@ -139,9 +139,9 @@ export class DataExplorerChartContainerComponent
     hasDataExplorerWritePrivileges = false;
     hasDashboardWritePrivileges = false;
 
-    authSubscription: Subscription;
-    widgetTypeChangedSubscription: Subscription;
-    intervalSubscription: Subscription;
+    auth$: Subscription;
+    widgetTypeChanged$: Subscription;
+    interval$: Subscription;
 
     errorMessage: SpLogMessage;
 
@@ -177,9 +177,9 @@ export class DataExplorerChartContainerComponent
                 this.resizeService.notify({
                     width,
                     height,
-                    widgetId: this.dashboardItem?.widgetId || undefined,
+                    widgetId: this.dashboardItem?.id || undefined,
                 });
-            }, 150);
+            }, 100);
         });
         obs.observe(container);
     }
@@ -195,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 (
@@ -256,8 +254,9 @@ 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) {
@@ -269,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>
@@ -282,6 +288,7 @@ 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,
@@ -298,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();
         });
     }
 
@@ -340,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;
@@ -349,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 5cc4905a67..0025e2c6c7 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
@@ -31,7 +31,6 @@ import {
     DataExplorerDataConfig,
     DataExplorerField,
     DataExplorerWidgetModel,
-    DataViewQueryGeneratorService,
     SpLogMessage,
     SpQueryResult,
     TimeSettings,
@@ -48,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<
@@ -88,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;
@@ -99,9 +105,9 @@ export abstract class BaseDataExplorerWidgetDirective<
 
     fieldProvider: FieldProvider;
 
-    widgetConfigurationSub: Subscription;
-    resizeSub: Subscription;
-    timeSelectionSub: Subscription;
+    widgetConfiguration$: Subscription;
+    resize$: Subscription;
+    timeSelection$: Subscription;
 
     widthOffset: number;
     heightOffset: number;
@@ -112,9 +118,6 @@ 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);
@@ -123,6 +126,8 @@ export abstract class BaseDataExplorerWidgetDirective<
     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 =
@@ -151,7 +156,7 @@ export abstract class BaseDataExplorerWidgetDirective<
                 });
             });
 
-        this.widgetConfigurationSub =
+        this.widgetConfiguration$ =
             
this.widgetConfigurationService.configurationChangedSubject.subscribe(
                 refreshMessage => {
                     if (refreshMessage.refreshData) {
@@ -177,18 +182,18 @@ export abstract class BaseDataExplorerWidgetDirective<
                 },
             );
         if (!this.previewMode) {
-            this.resizeSub = this.resizeService.resizeSubject.subscribe(
-                info => {
-                    if (
-                        this.dataViewMode ||
-                        info.widgetId === this.dataViewDashboardItem.widgetId
-                    ) {
-                        this.onResize(info.width, info.height);
-                    }
-                },
-            );
+            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 (
@@ -213,9 +218,9 @@ export abstract class BaseDataExplorerWidgetDirective<
     }
 
     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..2e090060ca 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;
@@ -64,7 +61,6 @@ export class SpEchartsWidgetComponent<T extends 
DataExplorerWidgetModel>
         this.resizeEcharts$ =
             this.resizeEchartsService.echartsResizeSubject.subscribe(width => {
                 this.currentWidth = width - this.widthOffset;
-                this.applySize(this.currentWidth, this.currentHeight);
                 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/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 2681bc225d..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.scss
 
b/ui/src/app/data-explorer-shared/components/charts/traffic-light/traffic-light-widget.component.scss
index 0da8e49f0c..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
@@ -48,7 +48,7 @@
     height: auto;
     flex: 0 0 auto;
 
-    width: 90%;
+    width: 96%;
     aspect-ratio: 1 / 1;
     border-radius: 50%;
 
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 b6e15d442b..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
@@ -40,7 +40,7 @@ export interface BaseWidgetData<T extends 
DataExplorerWidgetModel> {
     editMode: boolean;
     kioskMode: boolean;
     observableGenerator: ObservableGenerator;
-
+    initialSize: WidgetSize;
     timeSettings: TimeSettings;
 
     dataViewDashboardItem: ClientDashboardItem;
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 5719774686..c272329388 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
@@ -59,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',

Reply via email to