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

riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new 291dc235dc feat(#3725): Add dashboard kiosk mode (#3729)
291dc235dc is described below

commit 291dc235dc946da1b5c48f1fe6cb7debdcb3e716
Author: Dominik Riemer <[email protected]>
AuthorDate: Mon Aug 18 20:39:32 2025 +0200

    feat(#3725): Add dashboard kiosk mode (#3729)
    
    * feat(#3725): Add dashboard kiosk mode to UI
    
    * Add auto-refresh for kiosk mode
    
    * Fix dashboard widget deletion behaviour
    
    * Remove loading bar
    
    * Add missing license header
---
 .../model/dashboard/CompositeDashboardModel.java   |  10 ++
 .../impl/dashboard/DataLakeDashboardResource.java  |  24 ++-
 ui/deployment/app-routing.module.mst               |   1 +
 .../src/lib/apis/dashboard.service.ts              |  14 +-
 .../src/lib/model/dashboard/dashboard.model.ts     |   1 +
 .../kiosk/dashboard-kiosk.component.html           |  73 ++++++++
 .../kiosk/dashboard-kiosk.component.scss           |  33 +++-
 .../components/kiosk/dashboard-kiosk.component.ts  | 133 ++++++++++++++
 .../app/dashboard-kiosk/dashboard-kiosk.module.ts  |  63 +++++++
 .../chart-view/abstract-chart-view.directive.ts    |   2 +-
 .../grid-view/dashboard-grid-view.component.html   |  61 +++++++
 .../grid-view/dashboard-grid-view.component.scss   |  11 +-
 .../grid-view/dashboard-grid-view.component.ts     |  16 +-
 .../slide-view/dashboard-slide-view.component.html |   4 +-
 .../slide-view/dashboard-slide-view.component.scss |   0
 .../slide-view/dashboard-slide-view.component.ts   |   0
 .../dashboard-shared.module.ts}                    |  48 +----
 .../services/dashboard.service.ts                  |   6 +-
 .../grid-view/dashboard-grid-view.component.html   |  49 ------
 .../dashboard-overview-table.component.html        |  20 ++-
 .../dashboard-overview-table.component.ts          |  36 ++--
 .../overview/dashboard-overview.component.ts       |   2 +-
 .../components/panel/dashboard-panel.component.ts  |  53 +++---
 ui/src/app/dashboard/dashboard.module.ts           |   6 +-
 .../data-explorer-chart-container.component.html   | 194 +++++++++++----------
 .../data-explorer-chart-container.component.ts     |   6 +-
 .../base/base-data-explorer-widget.directive.ts    |   1 +
 .../charts/base/echarts-widget.component.ts        |  18 ++
 .../models/dataview-dashboard.model.ts             |   1 +
 .../data-explorer-chart-view.component.html        |   4 +-
 .../data-explorer-overview-table.component.ts      |  21 +--
 .../overview/data-explorer-overview.component.ts   |  12 +-
 .../overview/data-explorer-overview.directive.ts   |  12 +-
 33 files changed, 633 insertions(+), 302 deletions(-)

diff --git 
a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/CompositeDashboardModel.java
 
b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/CompositeDashboardModel.java
index cb06527e42..cd14784aaa 100644
--- 
a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/CompositeDashboardModel.java
+++ 
b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/CompositeDashboardModel.java
@@ -22,8 +22,18 @@ import 
org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
 import org.apache.streampipes.model.datalake.DataLakeMeasure;
 
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 public record CompositeDashboardModel(DashboardModel dashboard,
                                       List<DataExplorerWidgetModel> widgets,
                                       List<DataLakeMeasure> dataLakeMeasures) {
+
+  public String getRevisionHash() {
+
+    return Stream.concat(
+        Stream.of(dashboard.getRev()),
+        widgets.stream().map(DashboardEntity::getRev)
+    ).collect(Collectors.joining("|"));
+  }
 }
diff --git 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java
 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java
index f97b7083a1..0fcb6e2162 100644
--- 
a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java
+++ 
b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DataLakeDashboardResource.java
@@ -20,11 +20,12 @@ package org.apache.streampipes.rest.impl.dashboard;
 
 
 import org.apache.streampipes.model.client.user.DefaultPrivilege;
-import org.apache.streampipes.model.dashboard.CompositeDashboardModel;
 import org.apache.streampipes.model.dashboard.DashboardModel;
 import org.apache.streampipes.resource.management.DataExplorerResourceManager;
 import 
org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
 
+import org.springframework.http.CacheControl;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PostFilter;
@@ -35,10 +36,12 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
+import java.util.Objects;
 
 @RestController
 @RequestMapping("/api/v3/datalake/dashboard")
@@ -59,8 +62,23 @@ public class DataLakeDashboardResource extends 
AbstractAuthGuardedRestResource {
 
   @GetMapping(path = "/{dashboardId}/composite", produces = 
MediaType.APPLICATION_JSON_VALUE)
   @PreAuthorize("this.hasReadAuthority() and hasPermission(#dashboardId, 
'READ')")
-  public CompositeDashboardModel 
getCompositeDashboardModel(@PathVariable("dashboardId") String dashboardId) {
-    return getResourceManager().getCompositeDashboard(dashboardId);
+  public ResponseEntity<?> 
getCompositeDashboardModel(@PathVariable("dashboardId") String dashboardId,
+                                                      @RequestHeader(value = 
"If-None-Match", required = false) String ifNoneMatch) {
+    var dashboard = getResourceManager().getCompositeDashboard(dashboardId);
+    var currentEtag = "\"" + dashboard.getRevisionHash() + "\"";
+    if (Objects.nonNull(ifNoneMatch)) {
+      if (currentEtag.equals(ifNoneMatch)) {
+        return ResponseEntity
+            .status(HttpStatus.NOT_MODIFIED)
+            .eTag(currentEtag)
+            .build();
+      }
+    }
+    return ResponseEntity
+        .ok()
+        .eTag(currentEtag)
+        .cacheControl(CacheControl.noCache())
+        .body(dashboard);
   }
 
   @PutMapping(path = "/{dashboardId}", produces = 
MediaType.APPLICATION_JSON_VALUE)
diff --git a/ui/deployment/app-routing.module.mst 
b/ui/deployment/app-routing.module.mst
index e0e69d4639..e3e44722fa 100644
--- a/ui/deployment/app-routing.module.mst
+++ b/ui/deployment/app-routing.module.mst
@@ -50,6 +50,7 @@ const routes: Routes = [
   { path: 'apidocs', component: ApidocsComponent, canActivate: 
[ConfiguredCanActivateGuard]},
   { path: 'login', component: LoginComponent, canActivate: 
[ConfiguredCanActivateGuard],
   data: {animation: 'LoginPage'}},
+  { path: 'dashboard-kiosk', loadChildren: () => 
import('./dashboard-kiosk/dashboard-kiosk.module').then(m => 
m.DashboardKioskModule), canActivate: [ConfiguredCanActivateGuard]},
   { path: 'register', component: RegisterComponent, canActivate: 
[RegistrationAllowedCanActivateGuard] },
   { path: 'activate-account', component: ActivateAccountComponent, 
canActivate: [RegistrationAllowedCanActivateGuard] },
   { path: 'restore-password', component: RestorePasswordComponent, 
canActivate: [RestorePasswordAllowedCanActivateGuard] },
diff --git 
a/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts 
b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
index 4a40b03218..cd0618bd8b 100644
--- 
a/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
+++ 
b/ui/projects/streampipes/platform-services/src/lib/apis/dashboard.service.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { HttpClient } from '@angular/common/http';
+import { HttpClient, HttpContext, HttpResponse } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
 import { SharedDatalakeRestService } from './shared-dashboard.service';
@@ -24,6 +24,7 @@ import {
     CompositeDashboard,
     Dashboard,
 } from '../model/dashboard/dashboard.model';
+import { NGX_LOADING_BAR_IGNORED } from '@ngx-loading-bar/http-client';
 
 @Injectable({
     providedIn: 'root',
@@ -42,9 +43,18 @@ export class DashboardService {
         return this.http.get<Dashboard>(`${this.dashboardUrl}/${dashboardId}`);
     }
 
-    getCompositeDashboard(dashboardId: string): Observable<CompositeDashboard> 
{
+    getCompositeDashboard(
+        dashboardId: string,
+        eTag = undefined,
+    ): Observable<HttpResponse<any>> {
+        const headers = eTag ? { 'If-None-Match': eTag } : {};
         return this.http.get<CompositeDashboard>(
             `${this.dashboardUrl}/${dashboardId}/composite`,
+            {
+                headers,
+                observe: 'response',
+                context: new HttpContext().set(NGX_LOADING_BAR_IGNORED, true),
+            },
         );
     }
 
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 927d1a1946..79bd32d7b6 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
@@ -59,4 +59,5 @@ export interface CompositeDashboard {
     dashboard: Dashboard;
     dataLakeMeasures: DataLakeMeasure[];
     widgets: DataExplorerWidgetModel[];
+    revisionHash: string;
 }
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
new file mode 100644
index 0000000000..c08275e9c7
--- /dev/null
+++ b/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.html
@@ -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.
+  ~
+  -->
+
+<div
+    fxLayout="column"
+    style="height: 100vh"
+    class="light-mode w-100 standalone-outer"
+>
+    <mat-toolbar class="standalone-toolbar">
+        <div class="md-toolbar-tools sp-toolbar">
+            <div fxFlex="100" fxLayout fxLayoutAlign="start center">
+                <div
+                    class="md-toolbar-tools"
+                    style="height: 60px; max-height: 60px"
+                    fxLayout="row"
+                    fxLayoutAlign="start center"
+                >
+                    <div
+                        style="
+                            padding: 5px;
+                            border-radius: 0px;
+                            margin-right: 15px;
+                            position: relative;
+                            left: 20px;
+                        "
+                    >
+                        <img
+                            alt="icon"
+                            src="../../../../assets/img/sp/logo.png"
+                            style="max-height: 45px; max-width: 250px"
+                        />
+                    </div>
+                    <span class="dashboard-title">{{ dashboard?.name }}</span>
+                    @if (dashboard?.description) {
+                        <span class="dashboard-description"
+                            >&nbsp;|&nbsp;{{ dashboard?.description }}</span
+                        >
+                    }
+                </div>
+            </div>
+        </div>
+    </mat-toolbar>
+    <div fxLayout="column" style="height: calc(100vh - 40px)">
+        @if (dashboard) {
+            <sp-dashboard-grid-view
+                #dashboardGrid
+                *ngIf="dashboard?.widgets.length > 0"
+                [editMode]="false"
+                [kioskMode]="true"
+                [dashboard]="dashboard"
+                [widgets]="widgets"
+                [timeSettings]="dashboard.dashboardTimeSettings"
+                class="dashboard-grid"
+            >
+            </sp-dashboard-grid-view>
+        }
+    </div>
+</div>
diff --git 
a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/CompositeDashboardModel.java
 b/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.scss
similarity index 65%
copy from 
streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/CompositeDashboardModel.java
copy to 
ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.scss
index cb06527e42..b8d6d190bd 100644
--- 
a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/CompositeDashboardModel.java
+++ b/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.scss
@@ -16,14 +16,33 @@
  *
  */
 
-package org.apache.streampipes.model.dashboard;
+@use '../../../../scss/_variables';
 
-import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
-import org.apache.streampipes.model.datalake.DataLakeMeasure;
+.h-100 {
+    height: 100%;
+}
+
+.standalone-outer {
+    background: var(--color-bg-1);
+}
+
+.dashboard-grid {
+    display: flex;
+    flex-direction: column;
+    flex: 1 1 100%;
+}
+
+.standalone-toolbar {
+    height: 60px;
+    background: var(--color-bg-1);
+}
 
-import java.util.List;
+.dashboard-title {
+    margin-left: 2rem;
+    font-size: 1.25rem;
+}
 
-public record CompositeDashboardModel(DashboardModel dashboard,
-                                      List<DataExplorerWidgetModel> widgets,
-                                      List<DataLakeMeasure> dataLakeMeasures) {
+.dashboard-description {
+    font-size: 1.25rem;
+    font-weight: normal;
 }
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
new file mode 100644
index 0000000000..871967aeb2
--- /dev/null
+++ b/ui/src/app/dashboard-kiosk/components/kiosk/dashboard-kiosk.component.ts
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ *
+ */
+
+import { Component, inject, OnDestroy, OnInit } from '@angular/core';
+import {
+    CompositeDashboard,
+    Dashboard,
+    DashboardService,
+    DataExplorerWidgetModel,
+    TimeSettings,
+} from '@streampipes/platform-services';
+import { ActivatedRoute } from '@angular/router';
+import { of, Subscription, timer } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
+import { TimeSelectionService } from '@streampipes/shared-ui';
+import { DataExplorerDashboardService } from 
'../../../dashboard-shared/services/dashboard.service';
+
+@Component({
+    selector: 'sp-dashboard-kiosk',
+    standalone: false,
+    templateUrl: './dashboard-kiosk.component.html',
+    styleUrl: './dashboard-kiosk.component.scss',
+})
+export class DashboardKioskComponent implements OnInit, OnDestroy {
+    private route = inject(ActivatedRoute);
+    private dashboardService = inject(DashboardService);
+    private timeSelectionService = inject(TimeSelectionService);
+    private dataExplorerDashboardService = 
inject(DataExplorerDashboardService);
+
+    dashboard: Dashboard;
+    widgets: DataExplorerWidgetModel[] = [];
+    refresh$: Subscription;
+    eTag: string;
+
+    ngOnInit() {
+        const dashboardId = this.route.snapshot.params.dashboardId;
+        this.dashboardService
+            .getCompositeDashboard(dashboardId)
+            .subscribe(res => {
+                if (res.ok) {
+                    const cd = res.body;
+                    cd.dashboard.widgets.forEach(w => {
+                        w.widgetId ??=
+                            
this.dataExplorerDashboardService.makeUniqueWidgetId();
+                    });
+                    const eTag = res.headers.get('ETag');
+                    this.initDashboard(cd, eTag);
+                }
+            });
+    }
+
+    initDashboard(cd: CompositeDashboard, eTag: string): void {
+        this.dashboard = cd.dashboard;
+        this.widgets = cd.widgets;
+        this.eTag = eTag;
+        if (this.dashboard.dashboardLiveSettings.refreshModeActive) {
+            this.createQuerySubscription();
+            this.createRefreshListener();
+        }
+    }
+
+    createQuerySubscription() {
+        this.refresh$ = timer(
+            0,
+            this.dashboard.dashboardLiveSettings.refreshIntervalInSeconds *
+                1000,
+        )
+            .pipe(
+                switchMap(() => {
+                    this.timeSelectionService.updateTimeSettings(
+                        this.timeSelectionService.defaultQuickTimeSelections,
+                        this.dashboard.dashboardTimeSettings,
+                        new Date(),
+                    );
+                    this.updateDateRange(this.dashboard.dashboardTimeSettings);
+                    return of(null);
+                }),
+            )
+            .subscribe();
+    }
+
+    createRefreshListener(): void {
+        this.dashboardService
+            .getCompositeDashboard(this.dashboard.elementId, this.eTag) // 
this should send If-None-Match
+            .subscribe({
+                next: res => {
+                    if (res.status === 200) {
+                        const newEtag = res.headers.get('ETag');
+                        if (newEtag) {
+                            this.eTag = newEtag;
+                        }
+                        this.dashboard = undefined;
+                        this.refresh$?.unsubscribe();
+                        setTimeout(() => {
+                            this.initDashboard(res.body, newEtag);
+                        });
+                    }
+                    setTimeout(() => this.createRefreshListener(), 5000);
+                },
+                error: err => {
+                    setTimeout(() => this.createRefreshListener(), 5000);
+                },
+            });
+    }
+
+    updateDateRange(timeSettings: TimeSettings) {
+        let ts = undefined;
+        if (this.dashboard.dashboardGeneralSettings.globalTimeEnabled) {
+            this.dashboard.dashboardTimeSettings = timeSettings;
+            ts = timeSettings;
+        }
+        this.timeSelectionService.notify(ts);
+    }
+
+    ngOnDestroy() {
+        this.refresh$?.unsubscribe();
+    }
+}
diff --git a/ui/src/app/dashboard-kiosk/dashboard-kiosk.module.ts 
b/ui/src/app/dashboard-kiosk/dashboard-kiosk.module.ts
new file mode 100644
index 0000000000..d9b1ade07e
--- /dev/null
+++ b/ui/src/app/dashboard-kiosk/dashboard-kiosk.module.ts
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { SharedUiModule } from '@streampipes/shared-ui';
+import { DataExplorerSharedModule } from 
'../data-explorer-shared/data-explorer-shared.module';
+import { TranslateModule } from '@ngx-translate/core';
+import { DashboardSharedModule } from 
'../dashboard-shared/dashboard-shared.module';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import {
+    DefaultFlexDirective,
+    DefaultLayoutAlignDirective,
+    DefaultLayoutDirective,
+} from '@ngbracket/ngx-layout';
+import { DashboardKioskComponent } from 
'./components/kiosk/dashboard-kiosk.component';
+
+@NgModule({
+    imports: [
+        CommonModule,
+        MatToolbarModule,
+        SharedUiModule,
+        DataExplorerSharedModule,
+        DashboardSharedModule,
+        TranslateModule.forChild(),
+        RouterModule.forChild([
+            {
+                path: '',
+                children: [
+                    {
+                        path: ':dashboardId',
+                        component: DashboardKioskComponent,
+                    },
+                ],
+            },
+        ]),
+        DefaultFlexDirective,
+        DefaultLayoutDirective,
+        DefaultLayoutAlignDirective,
+    ],
+    declarations: [DashboardKioskComponent],
+    providers: [],
+    exports: [],
+})
+export class DashboardKioskModule {
+    constructor() {}
+}
diff --git 
a/ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts 
b/ui/src/app/dashboard-shared/components/chart-view/abstract-chart-view.directive.ts
similarity index 99%
rename from 
ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts
rename to 
ui/src/app/dashboard-shared/components/chart-view/abstract-chart-view.directive.ts
index bf3adc6ad4..8a22e809f6 100644
--- 
a/ui/src/app/dashboard/components/chart-view/abstract-chart-view.directive.ts
+++ 
b/ui/src/app/dashboard-shared/components/chart-view/abstract-chart-view.directive.ts
@@ -85,7 +85,7 @@ export abstract class AbstractChartViewDirective {
 
     loadWidgetConfig(widgetId: string, setCurrentlyConfigured?: boolean) {
         if (!this.isGridView()) {
-            this.widgetsVisible = false;
+            this.widgetsAvailable = false;
         }
         this.dataViewDataExplorerService
             .getChart(widgetId)
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
new file mode 100644
index 0000000000..43f50a8dda
--- /dev/null
+++ 
b/ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.html
@@ -0,0 +1,61 @@
+<!--
+  ~ 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.
+  ~
+  -->
+
+@if (dashboard.displayHeader) {
+    <div class="text-center">
+        <h2>{{ dashboard.name }}</h2>
+        <h3>{{ dashboard.description }}</h3>
+    </div>
+}
+<gridster
+    [options]="options"
+    [ngClass]="editMode ? 'edit' : ''"
+    class="custom-gridster-style"
+>
+    @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)"
+                        [editMode]="editMode"
+                        [kioskMode]="kioskMode"
+                        [gridMode]="true"
+                        [widgetIndex]="i"
+                        [gridsterItemComponent]="gridsterItemComponent"
+                    ></sp-data-explorer-chart-container>
+                }
+            </gridster-item>
+        </ng-container>
+    }
+</gridster>
diff --git 
a/ui/src/app/dashboard/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
similarity index 86%
rename from 
ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.scss
rename to 
ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.scss
index cc372aac45..4c2294b9ad 100644
--- 
a/ui/src/app/dashboard/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
@@ -17,7 +17,7 @@
  */
 
 gridster.custom-gridster-style ::ng-deep {
-    background: var(--color-bg-0);
+    background: var(--color-bg-1);
 }
 
 gridster.custom-gridster-style.edit ::ng-deep {
@@ -40,8 +40,9 @@ gridster.scrollVertical ::ng-deep {
     border-right: 1px solid var(--color-bg-1);
 }
 
-.shadow {
-    box-shadow:
-        rgba(50, 50, 93, 0.25) 0px 2px 5px -1px,
-        rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
+.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);
 }
diff --git 
a/ui/src/app/dashboard/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
similarity index 91%
rename from 
ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.ts
rename to 
ui/src/app/dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component.ts
index 481454a769..d11558fe8e 100644
--- 
a/ui/src/app/dashboard/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
@@ -18,13 +18,18 @@
 
 import {
     Component,
+    Input,
     OnChanges,
     OnInit,
     QueryList,
     SimpleChanges,
     ViewChildren,
 } from '@angular/core';
-import { GridsterItemComponent, GridType } from 'angular-gridster2';
+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';
@@ -39,6 +44,9 @@ export class DashboardGridViewComponent
     extends AbstractChartViewDirective
     implements OnInit, OnChanges
 {
+    @Input()
+    kioskMode = false;
+
     options: IDataViewDashboardConfig;
     loaded = false;
 
@@ -56,8 +64,10 @@ export class DashboardGridViewComponent
             minRows: 4,
             fixedRowHeight: 100,
             fixedColWidth: 100,
-            margin: 5,
-            displayGrid: this.editMode ? 'always' : 'none',
+            margin: 3,
+            displayGrid: this.editMode
+                ? DisplayGrid.OnDragAndResize
+                : DisplayGrid.None,
             resizable: { enabled: this.editMode },
             itemResizeCallback: (item, itemComponent) => {
                 this.resizeService.notify({
diff --git 
a/ui/src/app/dashboard/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
similarity index 96%
rename from 
ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.html
rename to 
ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.html
index 4c73a94118..1640260e3a 100644
--- 
a/ui/src/app/dashboard/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
@@ -48,7 +48,7 @@
         </div>
         <div fxFlex="100">
             <div class="h-100 w-100 mw-100" id="slideViewOuter" fxFlex="100">
-                <sp-data-explorer-dashboard-widget
+                <sp-data-explorer-chart-container
                     [ngStyle]="{
                         height: gridsterItemComponent.height - 15 + 'px'
                     }"
@@ -71,7 +71,7 @@
                         currentWidget &&
                         widgetsVisible
                     "
-                ></sp-data-explorer-dashboard-widget>
+                ></sp-data-explorer-chart-container>
             </div>
         </div>
     </div>
diff --git 
a/ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.scss
 
b/ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.scss
similarity index 100%
rename from 
ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.scss
rename to 
ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.scss
diff --git 
a/ui/src/app/dashboard/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
similarity index 100%
rename from 
ui/src/app/dashboard/components/chart-view/slide-view/dashboard-slide-view.component.ts
rename to 
ui/src/app/dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component.ts
diff --git a/ui/src/app/dashboard/dashboard.module.ts 
b/ui/src/app/dashboard-shared/dashboard-shared.module.ts
similarity index 67%
copy from ui/src/app/dashboard/dashboard.module.ts
copy to ui/src/app/dashboard-shared/dashboard-shared.module.ts
index adc7211f38..0a4e008572 100644
--- a/ui/src/app/dashboard/dashboard.module.ts
+++ b/ui/src/app/dashboard-shared/dashboard-shared.module.ts
@@ -24,13 +24,11 @@ import { MatTabsModule } from '@angular/material/tabs';
 import { FormsModule } from '@angular/forms';
 import { ColorPickerComponent } from 'ngx-color-picker';
 import { MatGridListModule } from '@angular/material/grid-list';
-import { DashboardOverviewComponent } from 
'./components/overview/dashboard-overview.component';
 import { CdkTableModule } from '@angular/cdk/table';
 import { LeafletModule } from '@bluehalo/ngx-leaflet';
 import { CoreUiModule } from '../core-ui/core-ui.module';
 import { PlatformServicesModule } from '@streampipes/platform-services';
 import { ServicesModule } from '../services/services.module';
-import { RouterModule } from '@angular/router';
 import { SharedUiModule } from '@streampipes/shared-ui';
 import { MatDividerModule } from '@angular/material/divider';
 import { MatFormFieldModule } from '@angular/material/form-field';
@@ -59,16 +57,8 @@ import { MatButtonToggleModule } from 
'@angular/material/button-toggle';
 import { MatChipsModule } from '@angular/material/chips';
 import { MatSliderModule } from '@angular/material/slider';
 import { DataExplorerSharedModule } from 
'../data-explorer-shared/data-explorer-shared.module';
-import { DashboardPanelComponent } from 
'./components/panel/dashboard-panel.component';
-import { DataExplorerPanelCanDeactivateGuard } from 
'../data-explorer-shared/services/data-explorer-panel.can-deactivate.guard';
 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 { DashboardToolbarComponent } from 
'./components/panel/dashboard-toolbar/dashboard-toolbar.component';
-import { ChartSelectionPanelComponent } from 
'./components/panel/chart-selection-panel/chart-selection-panel.component';
-import { ChartPreviewComponent } from 
'./components/panel/chart-selection-panel/chart-selection/chart-preview/chart-preview.component';
-import { ChartSelectionComponent } from 
'./components/panel/chart-selection-panel/chart-selection/chart-selection.component';
-import { EditDashboardDialogComponent } from 
'./dialogs/edit-dashboard/edit-dashboard-dialog.component';
-import { DashboardOverviewTableComponent } from 
'./components/overview/dashboard-overview-table/dashboard-overview-table.component';
 import { TranslateModule } from '@ngx-translate/core';
 
 @NgModule({
@@ -114,43 +104,11 @@ import { TranslateModule } from '@ngx-translate/core';
         SharedUiModule,
         DataExplorerSharedModule,
         TranslateModule.forChild(),
-        RouterModule.forChild([
-            {
-                path: '',
-                children: [
-                    {
-                        path: '',
-                        component: DashboardOverviewComponent,
-                    },
-                    {
-                        path: ':id',
-                        component: DashboardPanelComponent,
-                        canDeactivate: [DataExplorerPanelCanDeactivateGuard],
-                    },
-                    {
-                        path: ':id/:startTime/:endTime',
-                        component: DashboardPanelComponent,
-                        canDeactivate: [DataExplorerPanelCanDeactivateGuard],
-                    },
-                ],
-            },
-        ]),
-    ],
-    declarations: [
-        DashboardOverviewComponent,
-        DashboardGridViewComponent,
-        DashboardPanelComponent,
-        DashboardSlideViewComponent,
-        DashboardToolbarComponent,
-        ChartSelectionPanelComponent,
-        ChartPreviewComponent,
-        ChartSelectionComponent,
-        EditDashboardDialogComponent,
-        DashboardOverviewTableComponent,
     ],
+    declarations: [DashboardGridViewComponent, DashboardSlideViewComponent],
     providers: [],
-    exports: [],
+    exports: [DashboardGridViewComponent, DashboardSlideViewComponent],
 })
-export class DashboardModule {
+export class DashboardSharedModule {
     constructor() {}
 }
diff --git a/ui/src/app/dashboard/services/dashboard.service.ts 
b/ui/src/app/dashboard-shared/services/dashboard.service.ts
similarity index 89%
rename from ui/src/app/dashboard/services/dashboard.service.ts
rename to ui/src/app/dashboard-shared/services/dashboard.service.ts
index e2f5b569fe..efa9ba8ab1 100644
--- a/ui/src/app/dashboard/services/dashboard.service.ts
+++ b/ui/src/app/dashboard-shared/services/dashboard.service.ts
@@ -17,7 +17,7 @@
  */
 
 import { Dashboard } from '@streampipes/platform-services';
-import { EditDashboardDialogComponent } from 
'../dialogs/edit-dashboard/edit-dashboard-dialog.component';
+import { EditDashboardDialogComponent } from 
'../../dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component';
 import { DialogService, PanelType } from '@streampipes/shared-ui';
 import { Injectable } from '@angular/core';
 import { TranslateService } from '@ngx-translate/core';
@@ -42,4 +42,8 @@ export class DataExplorerDashboardService {
             },
         });
     }
+
+    makeUniqueWidgetId(): string {
+        return Math.random().toString(36).slice(2, 12);
+    }
 }
diff --git 
a/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.html
 
b/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.html
deleted file mode 100644
index 46abe817da..0000000000
--- 
a/ui/src/app/dashboard/components/chart-view/grid-view/dashboard-grid-view.component.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!--
-  ~ 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.
-  ~
-  -->
-
-<div *ngIf="dashboard.displayHeader" class="text-center">
-    <h2>{{ dashboard.name }}</h2>
-    <h3>{{ dashboard.description }}</h3>
-</div>
-<gridster
-    [options]="options"
-    [ngClass]="editMode ? 'edit' : ''"
-    class="custom-gridster-style"
->
-    <ng-container *ngFor="let item of dashboard.widgets; let i = index">
-        <gridster-item [item]="item" #gridsterItemComponent class="shadow">
-            <sp-data-explorer-dashboard-widget
-                [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)"
-                [editMode]="editMode"
-                [gridMode]="true"
-                [widgetIndex]="i"
-                [gridsterItemComponent]="gridsterItemComponent"
-                *ngIf="widgetsAvailable && configuredWidgets.has(item.id)"
-            ></sp-data-explorer-dashboard-widget>
-        </gridster-item>
-    </ng-container>
-</gridster>
diff --git 
a/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.html
 
b/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.html
index ff0e0525df..112ba222b1 100644
--- 
a/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.html
+++ 
b/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.html
@@ -28,7 +28,7 @@
         >
             <ng-container matColumnDef="name">
                 <th
-                    fxFlex="60"
+                    fxFlex="40"
                     fxLayoutAlign="start center"
                     mat-header-cell
                     *matHeaderCellDef
@@ -36,7 +36,7 @@
                     {{ 'Dashboards' | translate }}
                 </th>
                 <td
-                    fxFlex="60"
+                    fxFlex="40"
                     fxLayoutAlign="center start"
                     mat-cell
                     data-cy="dashboard-table-overview"
@@ -54,7 +54,6 @@
 
             <ng-container matColumnDef="lastModified">
                 <th
-                    fxFlex="60"
                     fxLayoutAlign="start center"
                     mat-header-cell
                     *matHeaderCellDef
@@ -62,7 +61,6 @@
                     {{ 'Last modified' | translate }}
                 </th>
                 <td
-                    fxFlex="60"
                     fxLayoutAlign="center start"
                     mat-cell
                     *matCellDef="let element"
@@ -81,7 +79,6 @@
 
             <ng-container matColumnDef="createdAt">
                 <th
-                    fxFlex="60"
                     fxLayoutAlign="start center"
                     mat-header-cell
                     *matHeaderCellDef
@@ -89,7 +86,6 @@
                     {{ 'Created' | translate }}
                 </th>
                 <td
-                    fxFlex="60"
                     fxLayoutAlign="center start"
                     mat-cell
                     *matCellDef="let element"
@@ -104,13 +100,13 @@
 
             <ng-container matColumnDef="actions">
                 <th
-                    fxFlex="40"
+                    fxFlex
                     fxLayoutAlign="center center"
                     mat-header-cell
                     *matHeaderCellDef
                 ></th>
                 <td
-                    fxFlex="40"
+                    fxFlex
                     fxLayoutAlign="start center"
                     mat-cell
                     *matCellDef="let element"
@@ -134,6 +130,14 @@
                         >
                             <i class="material-icons">edit</i>
                         </button>
+                        <button
+                            mat-icon-button
+                            color="accent"
+                            [matTooltip]="'Kiosk mode' | translate"
+                            (click)="openDashboardInKioskMode(element)"
+                        >
+                            <i class="material-icons">open_in_new</i>
+                        </button>
                         <button
                             mat-icon-button
                             color="accent"
diff --git 
a/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.ts
 
b/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.ts
index ddb415b76e..b2c53014aa 100644
--- 
a/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.ts
+++ 
b/ui/src/app/dashboard/components/overview/dashboard-overview-table/dashboard-overview-table.component.ts
@@ -16,22 +16,19 @@
  *
  */
 
-import { Component, EventEmitter, Output } from '@angular/core';
+import { Component, EventEmitter, inject, Output } from '@angular/core';
 import { MatTableDataSource } from '@angular/material/table';
 import { Dashboard, DashboardService } from '@streampipes/platform-services';
 import {
     ConfirmDialogComponent,
-    CurrentUserService,
-    DialogService,
+    DateFormatService,
 } from '@streampipes/shared-ui';
-import { AuthService } from '../../../../services/auth.service';
 import { SpDataExplorerOverviewDirective } from 
'../../../../data-explorer/components/overview/data-explorer-overview.directive';
-import { DataExplorerRoutingService } from 
'../../../../data-explorer-shared/services/data-explorer-routing.service';
 import { MatDialog } from '@angular/material/dialog';
-import { DataExplorerDashboardService } from 
'../../../services/dashboard.service';
+import { DataExplorerDashboardService } from 
'../../../../dashboard-shared/services/dashboard.service';
 import { DataExplorerSharedService } from 
'../../../../data-explorer-shared/services/data-explorer-shared.service';
 import { TranslateService } from '@ngx-translate/core';
-import { DateFormatService } from '@streampipes/shared-ui';
+import { Router } from '@angular/router';
 
 @Component({
     selector: 'sp-dashboard-overview-table',
@@ -50,20 +47,13 @@ export class DashboardOverviewTableComponent extends 
SpDataExplorerOverviewDirec
     @Output()
     resourceCountEmitter: EventEmitter<number> = new EventEmitter();
 
-    constructor(
-        private dashboardService: DashboardService,
-        private dataExplorerDashboardService: DataExplorerDashboardService,
-        private dataExplorerSharedService: DataExplorerSharedService,
-        public dialogService: DialogService,
-        routingService: DataExplorerRoutingService,
-        authService: AuthService,
-        currentUserService: CurrentUserService,
-        private dialog: MatDialog,
-        protected translateService: TranslateService,
-        protected dateFormatService: DateFormatService,
-    ) {
-        super(dialogService, authService, currentUserService, routingService);
-    }
+    private dashboardService = inject(DashboardService);
+    private dataExplorerDashboardService = 
inject(DataExplorerDashboardService);
+    private dataExplorerSharedService = inject(DataExplorerSharedService);
+    private dialog = inject(MatDialog);
+    protected translateService = inject(TranslateService);
+    protected dateFormatService = inject(DateFormatService);
+    private router = inject(Router);
 
     afterInit(): void {
         this.displayedColumns = [
@@ -158,4 +148,8 @@ export class DashboardOverviewTableComponent extends 
SpDataExplorerOverviewDirec
     formatDate(timestamp?: number): string {
         return this.dateFormatService.formatDate(timestamp);
     }
+
+    openDashboardInKioskMode(dashboard: Dashboard) {
+        this.router.navigate(['dashboard-kiosk', dashboard.elementId]);
+    }
 }
diff --git 
a/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts 
b/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts
index d40ea058e4..7fb66fbdec 100644
--- a/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts
+++ b/ui/src/app/dashboard/components/overview/dashboard-overview.component.ts
@@ -27,7 +27,7 @@ import { AuthService } from '../../../services/auth.service';
 import { UserPrivilege } from '../../../_enums/user-privilege.enum';
 import { SpDashboardRoutes } from '../../dashboard.routes';
 import { Dashboard } from '@streampipes/platform-services';
-import { DataExplorerDashboardService } from 
'../../services/dashboard.service';
+import { DataExplorerDashboardService } from 
'../../../dashboard-shared/services/dashboard.service';
 import { DashboardOverviewTableComponent } from 
'./dashboard-overview-table/dashboard-overview-table.component';
 import { TranslateService } from '@ngx-translate/core';
 
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 4931bc6417..57aa4e6c35 100644
--- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
+++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
@@ -16,9 +16,9 @@
  *
  */
 
-import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import { Component, inject, OnDestroy, OnInit, ViewChild } from 
'@angular/core';
 import { Observable, of, Subscription, timer } from 'rxjs';
-import { DashboardGridViewComponent } from 
'../chart-view/grid-view/dashboard-grid-view.component';
+import { DashboardGridViewComponent } from 
'../../../dashboard-shared/components/chart-view/grid-view/dashboard-grid-view.component';
 import {
     ClientDashboardItem,
     Dashboard,
@@ -36,7 +36,7 @@ import {
     ActivatedRouteSnapshot,
     RouterStateSnapshot,
 } from '@angular/router';
-import { DashboardSlideViewComponent } from 
'../chart-view/slide-view/dashboard-slide-view.component';
+import { DashboardSlideViewComponent } from 
'../../../dashboard-shared/components/chart-view/slide-view/dashboard-slide-view.component';
 import {
     ConfirmDialogComponent,
     CurrentUserService,
@@ -50,6 +50,7 @@ import { DataExplorerRoutingService } from 
'../../../data-explorer-shared/servic
 import { DataExplorerDetectChangesService } from 
'../../../data-explorer/services/data-explorer-detect-changes.service';
 import { SupportsUnsavedChangeDialog } from 
'../../../data-explorer-shared/models/dataview-dashboard.model';
 import { TranslateService } from '@ngx-translate/core';
+import { DataExplorerDashboardService } from 
'../../../dashboard-shared/services/dashboard.service';
 
 @Component({
     selector: 'sp-dashboard-panel',
@@ -85,18 +86,17 @@ export class DashboardPanelComponent
     authSubscription: Subscription;
     refreshSubscription: Subscription;
 
-    constructor(
-        private detectChangesService: DataExplorerDetectChangesService,
-        private dialog: MatDialog,
-        private timeSelectionService: TimeSelectionService,
-        private authService: AuthService,
-        private currentUserService: CurrentUserService,
-        private dashboardService: DashboardService,
-        private route: ActivatedRoute,
-        private routingService: DataExplorerRoutingService,
-        private breadcrumbService: SpBreadcrumbService,
-        private translateService: TranslateService,
-    ) {}
+    private detectChangesService = inject(DataExplorerDetectChangesService);
+    private dialog = inject(MatDialog);
+    private timeSelectionService = inject(TimeSelectionService);
+    private authService = inject(AuthService);
+    private currentUserService = inject(CurrentUserService);
+    private dashboardService = inject(DashboardService);
+    private route = inject(ActivatedRoute);
+    private routingService = inject(DataExplorerRoutingService);
+    private breadcrumbService = inject(SpBreadcrumbService);
+    private translateService = inject(TranslateService);
+    private dataExplorerDashboardService = 
inject(DataExplorerDashboardService);
 
     public ngOnInit() {
         const params = this.route.snapshot.params;
@@ -130,10 +130,11 @@ export class DashboardPanelComponent
         dashboardItem.rows = 4;
         dashboardItem.x = 0;
         dashboardItem.y = 0;
+        dashboardItem.widgetId =
+            this.dataExplorerDashboardService.makeUniqueWidgetId();
         this.dashboard.widgets.push(dashboardItem);
         setTimeout(() => {
             if (this.viewMode === 'grid') {
-                console.log(this.dashboardGrid);
                 this.dashboardGrid.loadWidgetConfig(dataViewElementId, true);
             } else {
                 this.dashboardSlide.loadWidgetConfig(dataViewElementId, true);
@@ -181,6 +182,7 @@ export class DashboardPanelComponent
 
     removeChartFromDashboard(widgetIndex: number) {
         this.dashboard.widgets.splice(widgetIndex, 1);
+        this.widgets.splice(widgetIndex, 1);
     }
 
     updateDateRange(timeSettings: TimeSettings) {
@@ -210,12 +212,19 @@ export class DashboardPanelComponent
     getDashboard(dashboardId: string, startTime: number, endTime: number) {
         this.dashboardService
             .getCompositeDashboard(dashboardId)
-            .subscribe(compositeDashboard => {
-                this.dashboard = compositeDashboard.dashboard;
-                this.widgets = compositeDashboard.widgets;
-                this.originalDashboard = JSON.parse(
-                    JSON.stringify(compositeDashboard.dashboard),
-                );
+            .subscribe(resp => {
+                if (resp.ok) {
+                    const compositeDashboard = resp.body;
+                    compositeDashboard.dashboard.widgets.forEach(w => {
+                        w.widgetId ??=
+                            
this.dataExplorerDashboardService.makeUniqueWidgetId();
+                    });
+                    this.dashboard = compositeDashboard.dashboard;
+                    this.widgets = compositeDashboard.widgets;
+                    this.originalDashboard = JSON.parse(
+                        JSON.stringify(compositeDashboard.dashboard),
+                    );
+                }
                 this.breadcrumbService.updateBreadcrumb(
                     this.breadcrumbService.makeRoute(
                         [SpDashboardRoutes.BASE],
diff --git a/ui/src/app/dashboard/dashboard.module.ts 
b/ui/src/app/dashboard/dashboard.module.ts
index adc7211f38..e5a299417e 100644
--- a/ui/src/app/dashboard/dashboard.module.ts
+++ b/ui/src/app/dashboard/dashboard.module.ts
@@ -61,8 +61,6 @@ import { MatSliderModule } from '@angular/material/slider';
 import { DataExplorerSharedModule } from 
'../data-explorer-shared/data-explorer-shared.module';
 import { DashboardPanelComponent } from 
'./components/panel/dashboard-panel.component';
 import { DataExplorerPanelCanDeactivateGuard } from 
'../data-explorer-shared/services/data-explorer-panel.can-deactivate.guard';
-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 { DashboardToolbarComponent } from 
'./components/panel/dashboard-toolbar/dashboard-toolbar.component';
 import { ChartSelectionPanelComponent } from 
'./components/panel/chart-selection-panel/chart-selection-panel.component';
 import { ChartPreviewComponent } from 
'./components/panel/chart-selection-panel/chart-selection/chart-preview/chart-preview.component';
@@ -70,6 +68,7 @@ import { ChartSelectionComponent } from 
'./components/panel/chart-selection-pane
 import { EditDashboardDialogComponent } from 
'./dialogs/edit-dashboard/edit-dashboard-dialog.component';
 import { DashboardOverviewTableComponent } from 
'./components/overview/dashboard-overview-table/dashboard-overview-table.component';
 import { TranslateModule } from '@ngx-translate/core';
+import { DashboardSharedModule } from 
'../dashboard-shared/dashboard-shared.module';
 
 @NgModule({
     imports: [
@@ -113,6 +112,7 @@ import { TranslateModule } from '@ngx-translate/core';
         ServicesModule,
         SharedUiModule,
         DataExplorerSharedModule,
+        DashboardSharedModule,
         TranslateModule.forChild(),
         RouterModule.forChild([
             {
@@ -138,9 +138,7 @@ import { TranslateModule } from '@ngx-translate/core';
     ],
     declarations: [
         DashboardOverviewComponent,
-        DashboardGridViewComponent,
         DashboardPanelComponent,
-        DashboardSlideViewComponent,
         DashboardToolbarComponent,
         ChartSelectionPanelComponent,
         ChartPreviewComponent,
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 21edefca05..1dc6c0a031 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
@@ -40,112 +40,118 @@
             >
                 {{ configuredWidget.baseAppearanceConfig.widgetTitle }}
             </div>
-            <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
-                <mat-spinner
-                    [diameter]="20"
-                    color="primary"
-                    class="mr-10"
-                    *ngIf="timerActive"
-                >
-                </mat-spinner>
-                <div
-                    class="time-counter"
-                    *ngIf="editMode"
-                    [ngStyle]="{
-                        background:
-                            configuredWidget.baseAppearanceConfig.textColor,
-                        color: configuredWidget.baseAppearanceConfig
-                            .backgroundColor
-                    }"
-                >
-                    {{ loadingTime }}s
-                </div>
-                <button
-                    mat-icon-button
-                    [matMenuTriggerFor]="menu"
-                    [aria-label]="'More options' | translate"
-                    [matTooltip]="'More options' | translate"
-                    *ngIf="!dataViewMode"
-                    [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 (!kioskMode) {
+                <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
+                    <mat-spinner
+                        [diameter]="20"
+                        color="primary"
+                        class="mr-10"
+                        *ngIf="timerActive"
+                    >
+                    </mat-spinner>
+                    <div
+                        class="time-counter"
+                        *ngIf="editMode"
+                        [ngStyle]="{
+                            background:
+                                
configuredWidget.baseAppearanceConfig.textColor,
+                            color: configuredWidget.baseAppearanceConfig
+                                .backgroundColor
+                        }"
+                    >
+                        {{ loadingTime }}s
+                    </div>
                     <button
-                        mat-menu-item
-                        (click)="startEditMode()"
-                        *ngIf="hasDataExplorerWritePrivileges"
+                        mat-icon-button
+                        [matMenuTriggerFor]="menu"
+                        [aria-label]="'More options' | translate"
+                        [matTooltip]="'More options' | translate"
+                        *ngIf="!dataViewMode"
                         [attr.data-cy]="
-                            'start-edit-' +
+                            'more-options-' +
                             
configuredWidget.baseAppearanceConfig.widgetTitle.replaceAll(
                                 ' ',
                                 ''
                             )
                         "
                     >
-                        <mat-icon>edit</mat-icon>
-                        <span>{{ 'Edit Chart' | translate }}</span>
+                        <mat-icon>more_vert</mat-icon>
                     </button>
-                </mat-menu>
-                <button
-                    mat-icon-button
-                    [matMenuTriggerFor]="optMenu"
-                    *ngIf="!globalTimeEnabled"
-                    [aria-label]="'Options' | translate"
-                    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">
-                    <sp-time-selector-menu
-                        #timeSelectorMenu
-                        *ngIf="quickSelections"
-                        [timeSettings]="clonedTimeSettings"
-                        [quickSelections]="quickSelections"
-                        [enableTimePicker]="enableTimePicker"
-                        [maxDayRange]="maxDayRange"
-                        [labels]="labels"
-                        
(timeSettingsEmitter)="modifyWidgetTimeSettings($event)"
-                        class="w-100"
-                    >
+                    <mat-menu #menu="matMenu">
+                        <button mat-menu-item (click)="downloadDataAsFile()">
+                            <mat-icon>get_app</mat-icon>
+                            <span>{{ 'Download data' | translate }}</span>
+                        </button>
                         <button
-                            mat-raised-button
-                            class="mat-basic"
-                            (click)="resetWidgetTimeSettings()"
+                            mat-menu-item
+                            (click)="startEditMode()"
+                            *ngIf="hasDataExplorerWritePrivileges"
+                            [attr.data-cy]="
+                                'start-edit-' +
+                                
configuredWidget.baseAppearanceConfig.widgetTitle.replaceAll(
+                                    ' ',
+                                    ''
+                                )
+                            "
                         >
-                            {{ 'Reset' | translate }}
+                            <mat-icon>edit</mat-icon>
+                            <span>{{ 'Edit Chart' | translate }}</span>
                         </button>
-                    </sp-time-selector-menu>
-                </mat-menu>
-                <button
-                    mat-icon-button
-                    (click)="removeWidget()"
-                    [matTooltip]="'Delete Chart' | translate"
-                    *ngIf="editMode && hasDataExplorerWritePrivileges"
-                    [attr.data-cy]="
-                        'remove-' +
-                        configuredWidget.baseAppearanceConfig.widgetTitle
-                    "
-                >
-                    <mat-icon>clear</mat-icon>
-                </button>
-            </div>
+                    </mat-menu>
+                    <button
+                        mat-icon-button
+                        [matMenuTriggerFor]="optMenu"
+                        *ngIf="!globalTimeEnabled"
+                        [aria-label]="'Options' | translate"
+                        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">
+                        <sp-time-selector-menu
+                            #timeSelectorMenu
+                            *ngIf="quickSelections"
+                            [timeSettings]="clonedTimeSettings"
+                            [quickSelections]="quickSelections"
+                            [enableTimePicker]="enableTimePicker"
+                            [maxDayRange]="maxDayRange"
+                            [labels]="labels"
+                            (timeSettingsEmitter)="
+                                modifyWidgetTimeSettings($event)
+                            "
+                            class="w-100"
+                        >
+                            <button
+                                mat-raised-button
+                                class="mat-basic"
+                                (click)="resetWidgetTimeSettings()"
+                            >
+                                {{ 'Reset' | translate }}
+                            </button>
+                        </sp-time-selector-menu>
+                    </mat-menu>
+                    <button
+                        mat-icon-button
+                        (click)="removeWidget()"
+                        [matTooltip]="'Delete Chart' | translate"
+                        *ngIf="editMode && hasDataExplorerWritePrivileges"
+                        [attr.data-cy]="
+                            'remove-' +
+                            configuredWidget.baseAppearanceConfig.widgetTitle
+                        "
+                    >
+                        <mat-icon>clear</mat-icon>
+                    </button>
+                </div>
+            }
         </div>
         <div
             fxLayout="column"
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 fb13faf5bb..91f35ac40c 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
@@ -58,7 +58,7 @@ import { DataExplorerSharedService } from 
'../../services/data-explorer-shared.s
 import { MatMenuTrigger } from '@angular/material/menu';
 
 @Component({
-    selector: 'sp-data-explorer-dashboard-widget',
+    selector: 'sp-data-explorer-chart-container',
     templateUrl: './data-explorer-chart-container.component.html',
     styleUrls: ['./data-explorer-chart-container.component.scss'],
     standalone: false,
@@ -93,6 +93,9 @@ export class DataExplorerChartContainerComponent
     @Input()
     gridMode = true;
 
+    @Input()
+    kioskMode = false;
+
     @Input()
     widgetIndex: number;
 
@@ -252,6 +255,7 @@ export class DataExplorerChartContainerComponent
         this.componentRef.instance.gridsterItemComponent =
             this.gridsterItemComponent;
         this.componentRef.instance.editMode = this.editMode;
+        this.componentRef.instance.kioskMode = this.kioskMode;
         this.componentRef.instance.dataViewDashboardItem = this.dashboardItem;
         this.componentRef.instance.dataExplorerWidget = this.configuredWidget;
         this.componentRef.instance.previewMode = this.previewMode;
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 508dc62ff5..2eebe05707 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
@@ -70,6 +70,7 @@ export abstract class BaseDataExplorerWidgetDirective<
     @Input() gridsterItem: GridsterItem;
     @Input() gridsterItemComponent: GridsterItemComponent;
     @Input() editMode: boolean;
+    @Input() kioskMode: boolean;
 
     @Input() timeSettings: TimeSettings;
 
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 0ca75865a8..375499beda 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
@@ -124,6 +124,24 @@ export class SpEchartsWidgetComponent<T extends 
DataExplorerWidgetModel>
                     },
                 ),
             };
+            if (this.kioskMode) {
+                ['toolbox', 'visualMap'].forEach(key => {
+                    const item = this.option[key];
+                    if (item) {
+                        (Array.isArray(item) ? item : [item]).forEach(
+                            obj => (obj.show = false),
+                        );
+                    }
+                });
+                Object.assign(this.option, {
+                    grid: {
+                        left: 60,
+                        right: 60,
+                        top: 60,
+                        bottom: 60,
+                    },
+                });
+            }
         } else {
             this.showInvalidConfiguration = true;
         }
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 57f4089b1b..56fd261462 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
@@ -47,6 +47,7 @@ export interface BaseWidgetData<T extends 
DataExplorerWidgetModel> {
     gridsterItem: GridsterItem;
     gridsterItemComponent: GridsterItemComponent;
     editMode: boolean;
+    kioskMode: boolean;
 
     timeSettings: TimeSettings;
 
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 ac7c19b8c4..9bb81bf9b0 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
@@ -68,7 +68,7 @@
             </mat-drawer>
             <mat-drawer-content class="h-100 dashboard-grid">
                 <div #panel fxFlex="100" fxLayout="column">
-                    <sp-data-explorer-dashboard-widget
+                    <sp-data-explorer-chart-container
                         *ngIf="
                             dataView &&
                             gridsterItemComponent &&
@@ -83,7 +83,7 @@
                         "
                         (startEditModeEmitter)="editDataView()"
                     >
-                    </sp-data-explorer-dashboard-widget>
+                    </sp-data-explorer-chart-container>
                 </div>
             </mat-drawer-content>
         </mat-drawer-container>
diff --git 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.ts
 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.ts
index 5d8770f0a7..65e04ab49d 100644
--- 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.ts
+++ 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview-table/data-explorer-overview-table.component.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { Component, EventEmitter, Output } from '@angular/core';
+import { Component, EventEmitter, inject, Output } from '@angular/core';
 import { SpDataExplorerOverviewDirective } from 
'../data-explorer-overview.directive';
 import { MatTableDataSource } from '@angular/material/table';
 import {
@@ -34,6 +34,7 @@ import { DataExplorerRoutingService } from 
'../../../../data-explorer-shared/ser
 import { DataExplorerSharedService } from 
'../../../../data-explorer-shared/services/data-explorer-shared.service';
 import { MatDialog } from '@angular/material/dialog';
 import { TranslateService } from '@ngx-translate/core';
+import { DataExplorerDashboardService } from 
'../../../../dashboard-shared/services/dashboard.service';
 
 @Component({
     selector: 'sp-data-explorer-overview-table',
@@ -50,19 +51,11 @@ export class SpDataExplorerDataViewOverviewComponent 
extends SpDataExplorerOverv
     @Output()
     resourceCountEmitter: EventEmitter<number> = new EventEmitter();
 
-    constructor(
-        private dataViewService: ChartService,
-        private dataExplorerDashboardService: DataExplorerSharedService,
-        public dialogService: DialogService,
-        authService: AuthService,
-        currentUserService: CurrentUserService,
-        routingService: DataExplorerRoutingService,
-        private dialog: MatDialog,
-        private translateService: TranslateService,
-        protected dateFormatService: DateFormatService,
-    ) {
-        super(dialogService, authService, currentUserService, routingService);
-    }
+    private dataViewService = inject(ChartService);
+    private dataExplorerDashboardService = inject(DataExplorerSharedService);
+    private dialog = inject(MatDialog);
+    private translateService = inject(TranslateService);
+    private dateFormatService = inject(DateFormatService);
 
     afterInit(): void {
         this.displayedColumns = [
diff --git 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview.component.ts
 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview.component.ts
index 6ed6fa791c..8d9f50bcbf 100644
--- 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview.component.ts
+++ 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview.component.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { Component, ViewChild } from '@angular/core';
+import { Component, inject, ViewChild } from '@angular/core';
 import {
     CurrentUserService,
     DialogService,
@@ -41,15 +41,7 @@ export class DataExplorerOverviewComponent extends 
SpDataExplorerOverviewDirecti
     @ViewChild(SpDataExplorerDataViewOverviewComponent)
     chartsOverview: SpDataExplorerDataViewOverviewComponent;
 
-    constructor(
-        public dialogService: DialogService,
-        private breadcrumbService: SpBreadcrumbService,
-        authService: AuthService,
-        currentUserService: CurrentUserService,
-        routingService: DataExplorerRoutingService,
-    ) {
-        super(dialogService, authService, currentUserService, routingService);
-    }
+    private breadcrumbService = inject(SpBreadcrumbService);
 
     afterInit(): void {
         this.breadcrumbService.updateBreadcrumb(
diff --git 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview.directive.ts
 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview.directive.ts
index 2e80ab99d1..7a9a887c53 100644
--- 
a/ui/src/app/data-explorer/components/overview/data-explorer-overview.directive.ts
+++ 
b/ui/src/app/data-explorer/components/overview/data-explorer-overview.directive.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { Directive, OnDestroy, OnInit } from '@angular/core';
+import { Directive, inject, OnDestroy, OnInit } from '@angular/core';
 import { Subscription } from 'rxjs';
 import { UserPrivilege } from '../../../_enums/user-privilege.enum';
 import { UserRole } from '../../../_enums/user-role.enum';
@@ -34,12 +34,10 @@ export abstract class SpDataExplorerOverviewDirective
 
     authSubscription: Subscription;
 
-    protected constructor(
-        public dialogService: DialogService,
-        protected authService: AuthService,
-        protected currentUserService: CurrentUserService,
-        protected routingService: DataExplorerRoutingService,
-    ) {}
+    public dialogService = inject(DialogService);
+    protected authService = inject(AuthService);
+    protected currentUserService = inject(CurrentUserService);
+    protected routingService = inject(DataExplorerRoutingService);
 
     ngOnInit() {
         this.authSubscription = this.currentUserService.user$.subscribe(

Reply via email to