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

riemer pushed a commit to branch fix-permission-management-dashboard
in repository https://gitbox.apache.org/repos/asf/streampipes.git

commit 1a6612233a495b67f589f9fa3cc14846b3d6dccc
Author: Dominik Riemer <[email protected]>
AuthorDate: Tue Nov 25 10:45:08 2025 +0100

    fix: Align UI views with dashboard and data explorer permissions
---
 .../panel/dashboard-panel.component.html           |  4 +--
 .../components/panel/dashboard-panel.component.ts  |  8 +++---
 .../dashboard-toolbar.component.html               |  4 +--
 .../dashboard-toolbar.component.ts                 |  2 +-
 .../data-explorer-chart-container.component.html   | 32 ++++++++++++----------
 .../data-explorer-chart-container.component.ts     |  4 +++
 .../data-explorer-chart-view.component.ts          | 26 +++++++++++++++---
 .../data-explorer-overview-table.component.ts      |  5 +++-
 .../pipeline-details-toolbar.component.html        | 26 ++++++++++--------
 .../pipeline-details-toolbar.component.ts          |  3 ++
 .../pipeline-details.component.html                |  1 +
 .../pipeline-details/pipeline-details.component.ts | 12 ++++----
 12 files changed, 79 insertions(+), 48 deletions(-)

diff --git 
a/ui/src/app/dashboard/components/panel/dashboard-panel.component.html 
b/ui/src/app/dashboard/components/panel/dashboard-panel.component.html
index a2aca9c431..e7daf7b908 100644
--- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.html
+++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.html
@@ -31,9 +31,7 @@
                     [dashboard]="dashboard"
                     [editMode]="editMode"
                     [(viewMode)]="viewMode"
-                    [hasDataExplorerWritePrivileges]="
-                        hasDataExplorerWritePrivileges
-                    "
+                    [hasDashboardWritePrivileges]="hasDashboardWritePrivileges"
                     [timeRangeVisible]="timeRangeVisible"
                     [timeSettings]="timeSettings"
                     (saveDashboardEmitter)="persistDashboardChanges()"
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 0946164609..93ca7bb5fc 100644
--- a/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
+++ b/ui/src/app/dashboard/components/panel/dashboard-panel.component.ts
@@ -80,7 +80,7 @@ export class DashboardPanelComponent
     _dashboardGrid: DashboardGridViewComponent;
     _dashboardSlide: DashboardSlideViewComponent;
 
-    hasDataExplorerWritePrivileges = false;
+    hasDashboardWritePrivileges = false;
 
     public items: Dashboard[];
 
@@ -114,10 +114,10 @@ export class DashboardPanelComponent
         this.getDashboard(params.id, startTime, endTime);
 
         this.authSubscription = this.currentUserService.user$.subscribe(_ => {
-            this.hasDataExplorerWritePrivileges = this.authService.hasRole(
-                UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW,
+            this.hasDashboardWritePrivileges = this.authService.hasRole(
+                UserPrivilege.PRIVILEGE_WRITE_DASHBOARD,
             );
-            if (queryParams.editMode && this.hasDataExplorerWritePrivileges) {
+            if (queryParams.editMode && this.hasDashboardWritePrivileges) {
                 this.editMode = true;
             }
         });
diff --git 
a/ui/src/app/dashboard/components/panel/dashboard-toolbar/dashboard-toolbar.component.html
 
b/ui/src/app/dashboard/components/panel/dashboard-toolbar/dashboard-toolbar.component.html
index 22f0e0fcfb..0d85549398 100644
--- 
a/ui/src/app/dashboard/components/panel/dashboard-toolbar/dashboard-toolbar.component.html
+++ 
b/ui/src/app/dashboard/components/panel/dashboard-toolbar/dashboard-toolbar.component.html
@@ -100,7 +100,7 @@
             <mat-icon>more_vert</mat-icon>
         </button>
         <mat-menu #optMenu="matMenu">
-            @if (!editMode && hasDataExplorerWritePrivileges) {
+            @if (!editMode && hasDashboardWritePrivileges) {
                 <button
                     mat-menu-item
                     (click)="triggerEditModeEmitter.emit()"
@@ -122,7 +122,7 @@
                     <span>{{ 'Hide time range selector' | translate }}</span>
                 </button>
             }
-            @if (hasDataExplorerWritePrivileges) {
+            @if (hasDashboardWritePrivileges) {
                 <button mat-menu-item (click)="deleteDashboardEmitter.emit()">
                     <mat-icon>clear</mat-icon>
                     <span>{{ 'Delete dashboard' | translate }}</span>
diff --git 
a/ui/src/app/dashboard/components/panel/dashboard-toolbar/dashboard-toolbar.component.ts
 
b/ui/src/app/dashboard/components/panel/dashboard-toolbar/dashboard-toolbar.component.ts
index 21664ed1aa..9f979d9100 100644
--- 
a/ui/src/app/dashboard/components/panel/dashboard-toolbar/dashboard-toolbar.component.ts
+++ 
b/ui/src/app/dashboard/components/panel/dashboard-toolbar/dashboard-toolbar.component.ts
@@ -43,7 +43,7 @@ export class DashboardToolbarComponent {
     timeRangeVisible: boolean;
 
     @Input()
-    hasDataExplorerWritePrivileges: boolean;
+    hasDashboardWritePrivileges: boolean;
 
     @Input()
     timeSettings: TimeSettings;
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 6928d45086..f0fb79ee9e 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
@@ -146,21 +146,23 @@
                                 </sp-time-selector-menu>
                             }
                         </mat-menu>
-                        @if (!dataViewMode) {
-                            @if (editMode && hasDataExplorerWritePrivileges) {
-                                <button
-                                    mat-icon-button
-                                    (click)="removeWidget()"
-                                    [matTooltip]="'Delete Chart' | translate"
-                                    [attr.data-cy]="
-                                        'remove-' +
-                                        configuredWidget.baseAppearanceConfig
-                                            .widgetTitle
-                                    "
-                                >
-                                    <mat-icon>clear</mat-icon>
-                                </button>
-                            }
+                        @if (
+                            !dataViewMode &&
+                            editMode &&
+                            hasDashboardWritePrivileges
+                        ) {
+                            <button
+                                mat-icon-button
+                                (click)="removeWidget()"
+                                [matTooltip]="'Delete Chart' | translate"
+                                [attr.data-cy]="
+                                    'remove-' +
+                                    configuredWidget.baseAppearanceConfig
+                                        .widgetTitle
+                                "
+                            >
+                                <mat-icon>clear</mat-icon>
+                            </button>
                         }
                     </div>
                 }
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 de5144a8c3..4fb1bb090e 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
@@ -138,6 +138,7 @@ export class DataExplorerChartContainerComponent
     };
 
     hasDataExplorerWritePrivileges = false;
+    hasDashboardWritePrivileges = false;
 
     authSubscription: Subscription;
     widgetTypeChangedSubscription: Subscription;
@@ -175,6 +176,9 @@ export class DataExplorerChartContainerComponent
                 this.hasDataExplorerWritePrivileges = this.authService.hasRole(
                     UserPrivilege.PRIVILEGE_WRITE_DATA_EXPLORER_VIEW,
                 );
+                this.hasDashboardWritePrivileges = this.authService.hasRole(
+                    UserPrivilege.PRIVILEGE_WRITE_DASHBOARD,
+                );
             },
         );
         this.widgetLoaded = true;
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 4935fab6c6..0489ead3bc 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
@@ -20,6 +20,7 @@ import {
     Component,
     ElementRef,
     inject,
+    OnDestroy,
     OnInit,
     ViewChild,
 } from '@angular/core';
@@ -40,6 +41,7 @@ import {
 import {
     AssetSaveService,
     ConfirmDialogComponent,
+    CurrentUserService,
     DialogService,
     PanelType,
     TimeSelectionService,
@@ -48,12 +50,14 @@ import { DataExplorerRoutingService } from 
'../../../data-explorer-shared/servic
 import { DataExplorerSharedService } from 
'../../../data-explorer-shared/services/data-explorer-shared.service';
 import { DataExplorerDetectChangesService } from 
'../../services/data-explorer-detect-changes.service';
 import { SupportsUnsavedChangeDialog } from 
'../../../data-explorer-shared/models/dataview-dashboard.model';
-import { Observable, of } from 'rxjs';
+import { Observable, of, Subscription } from 'rxjs';
 import { MatDialog } from '@angular/material/dialog';
 import { catchError, map } from 'rxjs/operators';
 import { TranslateService } from '@ngx-translate/core';
 import { ResizeEchartsService } from 
'../../../data-explorer-shared/services/resize-echarts.service';
 import { AssetDialogComponent } from '../../dialog/asset-dialog.component';
+import { AuthService } from '../../../services/auth.service';
+import { UserRole } from '../../../_enums/user-role.enum';
 
 @Component({
     selector: 'sp-data-explorer-data-view',
@@ -62,7 +66,7 @@ import { AssetDialogComponent } from 
'../../dialog/asset-dialog.component';
     standalone: false,
 })
 export class DataExplorerChartViewComponent
-    implements OnInit, SupportsUnsavedChangeDialog
+    implements OnInit, OnDestroy, SupportsUnsavedChangeDialog
 {
     dataViewLoaded = false;
     timeSettings: TimeSettings;
@@ -91,9 +95,13 @@ export class DataExplorerChartViewComponent
     private timeSelectionService = inject(TimeSelectionService);
     private translateService = inject(TranslateService);
     private dialogService = inject(DialogService);
+    private currentUserService = inject(CurrentUserService);
+    private authService = inject(AuthService);
 
     private assetSaveService = inject(AssetSaveService);
 
+    currentUser$: Subscription;
+
     chartNotFound = false;
 
     observableGenerator =
@@ -103,7 +111,14 @@ export class DataExplorerChartViewComponent
 
     ngOnInit() {
         const dataViewId = this.route.snapshot.params.id;
-        this.editMode = this.route.snapshot.queryParams.editMode;
+
+        this.currentUser$ = this.currentUserService.user$.subscribe(user => {
+            if (!this.authService.hasRole(UserRole.ROLE_DATA_EXPLORER_ADMIN)) {
+                this.editMode = false;
+            } else {
+                this.editMode = this.route.snapshot.queryParams.editMode;
+            }
+        });
 
         if (dataViewId) {
             this.loadDataView(dataViewId);
@@ -342,7 +357,6 @@ export class DataExplorerChartViewComponent
             this.deselectedAssets,
             this.originalAssets,
         );
-        //this.dialogRef.close(true);
     }
 
     saveToAssets(data: DataExplorerWidgetModel): void {
@@ -364,4 +378,8 @@ export class DataExplorerChartViewComponent
             },
         ];
     }
+
+    ngOnDestroy() {
+        this.currentUser$?.unsubscribe();
+    }
 }
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 e28ddf8c81..0edf6c1cbf 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
@@ -87,7 +87,10 @@ export class SpDataExplorerDataViewOverviewComponent 
implements OnInit {
     }
 
     openDataView(dataView: DataExplorerWidgetModel, editMode: boolean): void {
-        this.routingService.navigateToDataView(editMode, dataView.elementId);
+        this.routingService.navigateToDataView(
+            editMode && this.hasDataExplorerWritePrivileges,
+            dataView.elementId,
+        );
     }
 
     showPermissionsDialog(chart: DataExplorerWidgetModel) {
diff --git 
a/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.html
 
b/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.html
index 1df6b32768..7acfa2659c 100644
--- 
a/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.html
+++ 
b/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.html
@@ -34,18 +34,20 @@
             >
         </div>
     </button>
-    <button
-        mat-button
-        color="accent"
-        [matTooltip]="'Pipeline as code' | translate"
-        [matTooltipPosition]="'above'"
-        (click)="openCodeDialogEmitter.emit()"
-    >
-        <div fxLayoutAlign="start center" fxLayout="row">
-            <i class="material-icons">code</i>
-            <span>&nbsp;{{ 'View pipeline as code' | translate }}</span>
-        </div>
-    </button>
+    @if (hasPipelineWritePrivileges) {
+        <button
+            mat-button
+            color="accent"
+            [matTooltip]="'Pipeline as code' | translate"
+            [matTooltipPosition]="'above'"
+            (click)="openCodeDialogEmitter.emit()"
+        >
+            <div fxLayoutAlign="start center" fxLayout="row">
+                <i class="material-icons">code</i>
+                <span>&nbsp;{{ 'View pipeline as code' | translate }}</span>
+            </div>
+        </button>
+    }
     <div fxFlex></div>
     <div fxLayoutAlign="end center">
         <button
diff --git 
a/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts
 
b/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts
index ede7f4eab4..c08ba9108a 100644
--- 
a/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts
+++ 
b/ui/src/app/pipeline-details/components/pipeline-details-toolbar/pipeline-details-toolbar.component.ts
@@ -27,6 +27,9 @@ export class PipelineDetailsToolbarComponent {
     @Input()
     autoRefresh: boolean;
 
+    @Input()
+    hasPipelineWritePrivileges: boolean;
+
     @Input()
     previewModeActive: boolean;
 
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.html 
b/ui/src/app/pipeline-details/pipeline-details.component.html
index e024d3d147..277b64b496 100644
--- a/ui/src/app/pipeline-details/pipeline-details.component.html
+++ b/ui/src/app/pipeline-details/pipeline-details.component.html
@@ -24,6 +24,7 @@
     <div nav fxFlex="100" fxLayoutAlign="start center" class="mr-5">
         <sp-pipeline-details-toolbar
             fxFlex="100"
+            [hasPipelineWritePrivileges]="hasPipelineWritePrivileges"
             [autoRefresh]="autoRefresh"
             [previewModeActive]="previewModeActive"
             (togglePreviewEmitter)="toggleLivePreview()"
diff --git a/ui/src/app/pipeline-details/pipeline-details.component.ts 
b/ui/src/app/pipeline-details/pipeline-details.component.ts
index 1cf208269c..b6edcbaaa8 100644
--- a/ui/src/app/pipeline-details/pipeline-details.component.ts
+++ b/ui/src/app/pipeline-details/pipeline-details.component.ts
@@ -66,8 +66,8 @@ export class SpPipelineDetailsComponent implements OnInit, 
OnDestroy {
     previewModeActive = false;
     pipelineNotFound = false;
 
-    currentUserSub: Subscription;
-    autoRefreshSub: Subscription;
+    currentUser$: Subscription;
+    autoRefresh$: Subscription;
 
     @ViewChild('pipelinePreviewComponent')
     pipelinePreviewComponent: PipelinePreviewComponent;
@@ -84,7 +84,7 @@ export class SpPipelineDetailsComponent implements OnInit, 
OnDestroy {
     ) {}
 
     ngOnInit(): void {
-        this.currentUserSub = this.currentUserService.user$.subscribe(user => {
+        this.currentUser$ = this.currentUserService.user$.subscribe(user => {
             this.hasPipelineWritePrivileges = this.authService.hasRole(
                 UserPrivilege.PRIVILEGE_WRITE_PIPELINE,
             );
@@ -147,7 +147,7 @@ export class SpPipelineDetailsComponent implements OnInit, 
OnDestroy {
     }
 
     setupAutoRefresh(): void {
-        this.autoRefreshSub = interval(5000)
+        this.autoRefresh$ = interval(5000)
             .pipe(
                 filter(() => this.autoRefresh),
                 switchMap(() => this.getMonitoringObservables(true)),
@@ -212,7 +212,7 @@ export class SpPipelineDetailsComponent implements OnInit, 
OnDestroy {
     }
 
     ngOnDestroy() {
-        this.currentUserSub?.unsubscribe();
-        this.autoRefreshSub?.unsubscribe();
+        this.currentUser$?.unsubscribe();
+        this.autoRefresh$?.unsubscribe();
     }
 }

Reply via email to