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

zehnder 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 79cb92a1c0 Add / Edit Assets during Dashboard Creation Edit  (#3846)
79cb92a1c0 is described below

commit 79cb92a1c0262b9da6be8ddef7fc2d516bad8eea
Author: Jacqueline Höllig <[email protected]>
AuthorDate: Fri Oct 17 16:32:50 2025 +0200

    Add / Edit Assets during Dashboard Creation Edit  (#3846)
    
    Co-authored-by: Philipp Zehnder <[email protected]>
    Co-authored-by: Dominik Riemer <[email protected]>
---
 .../impl/dashboard/DataLakeDashboardResource.java  |  7 +-
 .../support/utils/dataExplorer/DataExplorerBtns.ts |  4 ++
 .../utils/dataExplorer/DataExplorerUtils.ts        | 60 ++++++++++++++++
 .../dataExplorer/addAssetToDashboard.smoke.spec.ts | 81 +++++++++++++++++++++
 .../dataExplorer/addAssetsToDataView.smoke.spec.ts | 61 ++++++++++++++++
 .../edit-dashboard-dialog.component.html           | 53 +++++++++++---
 .../edit-dashboard-dialog.component.ts             | 83 ++++++++++++++++++++--
 .../dialog/asset-dialog.component.html             |  2 +-
 8 files changed, 333 insertions(+), 18 deletions(-)

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 ec015f2390..b4944312be 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
@@ -104,11 +104,12 @@ public class DataLakeDashboardResource extends 
AbstractAuthGuardedRestResource {
 
   @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
   @PreAuthorize("this.hasWriteAuthority()")
-  public ResponseEntity<Void> createDashboard(@RequestBody DashboardModel 
dashboardModel) {
-    getResourceManager().create(dashboardModel, getAuthenticatedUserSid());
-    return ok();
+  public ResponseEntity<DashboardModel> createDashboard(@RequestBody 
DashboardModel dashboardModel) {
+    var response = getResourceManager().create(dashboardModel, 
getAuthenticatedUserSid());
+    return ok(response);
   }
 
+
   private DataExplorerResourceManager getResourceManager() {
     return getSpResourceManager().manageDataExplorer();
   }
diff --git a/ui/cypress/support/utils/dataExplorer/DataExplorerBtns.ts 
b/ui/cypress/support/utils/dataExplorer/DataExplorerBtns.ts
index 35b3ca1b66..429c785b04 100644
--- a/ui/cypress/support/utils/dataExplorer/DataExplorerBtns.ts
+++ b/ui/cypress/support/utils/dataExplorer/DataExplorerBtns.ts
@@ -27,6 +27,10 @@ export class DataLakeBtns {
         return cy.dataCy('save-data-view-btn').click();
     }
 
+    public static saveDashboard() {
+        return cy.dataCy('save-data-view').click();
+    }
+
     public static editDataViewButton(widgetName: string) {
         GeneralUtils.openMenuForRow(widgetName);
         return cy
diff --git a/ui/cypress/support/utils/dataExplorer/DataExplorerUtils.ts 
b/ui/cypress/support/utils/dataExplorer/DataExplorerUtils.ts
index 3bdaf3a855..db51364d14 100644
--- a/ui/cypress/support/utils/dataExplorer/DataExplorerUtils.ts
+++ b/ui/cypress/support/utils/dataExplorer/DataExplorerUtils.ts
@@ -114,7 +114,54 @@ export class DataExplorerUtils {
 
         cy.wait(1000);
     }
+    public static addAssetsToDashboard(assetNameList) {
+        cy.dataCy('sp-show-dashboard-asset-checkbox')
+            .find('input[type="checkbox"]')
+            .then($checkbox => {
+                if (!$checkbox.prop('checked')) {
+                    cy.wrap($checkbox).click();
+                }
+            });
 
+        cy.get('mat-tree.asset-tree', { timeout: 10000 }).should('exist');
+        assetNameList.forEach(assetName => {
+            console.log(assetName);
+            cy.get('mat-tree.asset-tree')
+                .find('.mat-tree-node')
+                .contains(assetName)
+                .click();
+        });
+    }
+
+    public static createDashboard(name) {
+        // Create new data view
+        cy.dataCy('open-new-dashboard-dialog').click();
+
+        // Configure data view
+        cy.dataCy('data-view-name').type(name);
+    }
+    public static createDashboardWithLinkedAssets(
+        dataView,
+        name,
+        assetNameList,
+    ) {
+        DataExplorerUtils.goToDatalake();
+
+        DataExplorerUtils.addDataViewAndTableWidget(dataView, 'Persist');
+
+        DataExplorerUtils.saveDataViewConfiguration();
+
+        DataExplorerUtils.goToDashboard();
+
+        //ADD Assets
+        DataExplorerUtils.createDashboard(name);
+        DataExplorerUtils.addAssetsToDashboard(assetNameList);
+        DataExplorerUtils.saveDashboard();
+    }
+
+    public static saveDashboard() {
+        return cy.dataCy('save-data-view').click();
+    }
     public static addDataViewAndTableWidget(
         dataViewName: string,
         dataSet: string,
@@ -144,6 +191,11 @@ export class DataExplorerUtils {
         );
     }
 
+    public static renameDashboard(newName: string) {
+        cy.dataCy('data-view-name').clear().type(newName);
+        cy.dataCy('data-view-name').should('have.value', newName);
+    }
+
     public static loadRandomDataSetIntoDataLake() {
         PrepareTestDataUtils.loadDataIntoDataLake('fileTest/random.csv');
     }
@@ -186,6 +238,11 @@ export class DataExplorerUtils {
         cy.dataCy('edit-dashboard-' + dashboardName).click();
     }
 
+    public static editDashboardSettings(dashboardName: string) {
+        GeneralUtils.openMenuForRow(dashboardName);
+        cy.dataCy('edit-dashboard-settings-' + dashboardName).click();
+    }
+
     public static editDataView(dataViewName: string) {
         // Click edit button
         // following only works if single view is available
@@ -225,7 +282,9 @@ export class DataExplorerUtils {
                 .contains(assetName)
                 .click();
         });
+    }
 
+    public static saveAssetLinkFromChart() {
         cy.dataCy('asset-dialog-confirm-delete', { timeout: 10000 }).click({
             force: true,
         });
@@ -606,5 +665,6 @@ export class DataExplorerUtils {
         //Save
         DataExplorerUtils.saveToAddAssets();
         DataExplorerUtils.addToAsset(assetNames);
+        DataExplorerUtils.saveAssetLinkFromChart();
     }
 }
diff --git a/ui/cypress/tests/dataExplorer/addAssetToDashboard.smoke.spec.ts 
b/ui/cypress/tests/dataExplorer/addAssetToDashboard.smoke.spec.ts
new file mode 100644
index 0000000000..defb473209
--- /dev/null
+++ b/ui/cypress/tests/dataExplorer/addAssetToDashboard.smoke.spec.ts
@@ -0,0 +1,81 @@
+/*
+ * 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 { AssetBtns } from '../../support/utils/asset/AssetBtns';
+import { AssetUtils } from '../../support/utils/asset/AssetUtils';
+import { DataExplorerUtils } from 
'../../support/utils/dataExplorer/DataExplorerUtils';
+
+describe('Test add Assets To Dashboard', () => {
+    const assetName1 = 'TestAsset1';
+    const assetName2 = 'TestAsset2';
+    const assetName3 = 'TestAsset3';
+    beforeEach('Setup Test', () => {
+        cy.initStreamPipesTest();
+        AssetUtils.goToAssets();
+        AssetUtils.addAndSaveAsset(assetName3);
+        AssetUtils.addAndSaveAsset(assetName2);
+        AssetUtils.addAndSaveAsset(assetName1);
+        DataExplorerUtils.loadDataIntoDataLake('datalake/sample.csv');
+    });
+
+    it('Create Dashboard and add Assets', () => {
+        const dataView = 'TestView';
+
+        const name = 'Dashboard1';
+
+        const assetNameList = [assetName1, assetName2];
+        DataExplorerUtils.createDashboardWithLinkedAssets(
+            dataView,
+            name,
+            assetNameList,
+        );
+
+        //Go Back to Asset
+        AssetUtils.goToAssets();
+        AssetUtils.checkAmountOfAssetsGreaterThan(0);
+
+        AssetUtils.editAsset(assetName1);
+        AssetBtns.assetLinksTab().click();
+
+        //Check if Link is there
+        AssetUtils.checkAmountOfLinkedResources(1);
+    });
+
+    it('Edit Dashboard and edit Asset Links', () => {
+        const dataView = 'TestView';
+
+        const name = 'Dashboard1';
+
+        const assetNameList = [assetName1, assetName2];
+        DataExplorerUtils.createDashboardWithLinkedAssets(
+            dataView,
+            name,
+            assetNameList,
+        );
+        DataExplorerUtils.editDashboardSettings(name);
+        DataExplorerUtils.renameDashboard('NEW');
+        const assetNameList2 = [assetName2, assetName3];
+        DataExplorerUtils.addToAsset(assetNameList2);
+        DataExplorerUtils.saveDashboard();
+
+        AssetUtils.checkAmountOfLinkedResourcesByAssetName(assetName1, 1);
+        AssetUtils.checkAmountOfLinkedResourcesByAssetName(assetName3, 1);
+
+        // Test Renaming
+        AssetUtils.checkResourceNamingByAssetName(assetName1, 'NEW');
+    });
+});
diff --git a/ui/cypress/tests/dataExplorer/addAssetsToDataView.smoke.spec.ts 
b/ui/cypress/tests/dataExplorer/addAssetsToDataView.smoke.spec.ts
new file mode 100644
index 0000000000..beb3d5f5c6
--- /dev/null
+++ b/ui/cypress/tests/dataExplorer/addAssetsToDataView.smoke.spec.ts
@@ -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.
+ *
+ */
+
+import { AssetUtils } from '../../support/utils/asset/AssetUtils';
+import { DataExplorerUtils } from 
'../../support/utils/dataExplorer/DataExplorerUtils';
+
+describe('Creates a new adapter with a linked asset', () => {
+    const assetName1 = 'TestAsset1';
+    const assetName2 = 'TestAsset2';
+    const assetName3 = 'TestAsset3';
+
+    beforeEach('Setup Test', () => {
+        cy.initStreamPipesTest();
+        AssetUtils.goToAssets();
+        AssetUtils.addAndSaveAsset(assetName3);
+        AssetUtils.addAndSaveAsset(assetName2);
+        AssetUtils.addAndSaveAsset(assetName1);
+    });
+
+    it('Add Assets during Chart generation', () => {
+        DataExplorerUtils.createDataViewWithAssets([assetName1, assetName2]);
+        //Test
+        AssetUtils.checkAmountOfLinkedResourcesByAssetName(assetName1, 1);
+        AssetUtils.checkAmountOfLinkedResourcesByAssetName(assetName2, 1);
+    });
+
+    it('Edit Assets during Chart generation', () => {
+        DataExplorerUtils.createDataViewWithAssets([assetName1, assetName2]);
+        //Test
+        AssetUtils.checkAmountOfLinkedResourcesByAssetName(assetName1, 1);
+        AssetUtils.checkAmountOfLinkedResourcesByAssetName(assetName2, 1);
+
+        // Go To Chart and Edit
+        DataExplorerUtils.goToDatalake();
+        DataExplorerUtils.editDataView('NewWidget');
+        DataExplorerUtils.renameWidget('Rename');
+
+        DataExplorerUtils.saveToAddAssets();
+        DataExplorerUtils.addToAsset([assetName1, assetName3]);
+        DataExplorerUtils.saveAssetLinkFromChart();
+
+        AssetUtils.checkAmountOfLinkedResourcesByAssetName(assetName2, 1);
+        AssetUtils.checkAmountOfLinkedResourcesByAssetName(assetName3, 1);
+        AssetUtils.checkResourceNamingByAssetName(assetName2, 'Rename');
+    });
+});
diff --git 
a/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.html
 
b/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.html
index 69d5054e40..3da870685e 100644
--- 
a/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.html
+++ 
b/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.html
@@ -97,20 +97,47 @@
                         }}
                     </mat-checkbox>
                 </div>
+
+                <div class="mt-10" fxLayout="column">
+                    <label>{{ 'Add Dashboard to Assets' | translate }}</label>
+
+                    <mat-checkbox
+                        [(ngModel)]="addToAssets"
+                        color="accent"
+                        data-cy="sp-show-dashboard-asset-checkbox"
+                    >
+                        {{
+                            'Add the current dashboard to an existing asset'
+                                | translate
+                        }}
+                    </mat-checkbox>
+
+                    @if (addToAssets) {
+                        <div class="mt-10">
+                            <sp-asset-link-configuration
+                                [isEdit]="!createMode"
+                                [itemId]="dashboard.elementId"
+                                (selectedAssetsChange)="
+                                    onSelectedAssetsChange($event)
+                                "
+                                (deselectedAssetsChange)="
+                                    onDeselectedAssetsChange($event)
+                                "
+                                (originalAssetsEmitter)="
+                                    onOriginalAssetsEmitted($event)
+                                "
+                            >
+                            </sp-asset-link-configuration>
+                        </div>
+                    }
+                </div>
+
                 <!--<mat-checkbox [(ngModel)]="dashboard.displayHeader">Show 
name and description in dashboard</mat-checkbox>-->
             </div>
         </div>
     </div>
     <mat-divider></mat-divider>
-    <div class="sp-dialog-actions actions-align-right">
-        <button
-            mat-button
-            mat-flat-button
-            class="mat-basic mr-10"
-            (click)="onCancel()"
-        >
-            {{ 'Close' | translate }}
-        </button>
+    <div class="sp-dialog-actions actions-align-left">
         <button
             [disabled]="dvname.invalid"
             mat-button
@@ -121,5 +148,13 @@
         >
             {{ (createMode ? 'Create' : 'Save') | translate }}
         </button>
+        <button
+            mat-button
+            mat-flat-button
+            class="mat-basic mr-10"
+            (click)="onCancel()"
+        >
+            {{ 'Close' | translate }}
+        </button>
     </div>
 </div>
diff --git 
a/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
 
b/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
index 112e70cc41..426b676362 100644
--- 
a/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
+++ 
b/ui/src/app/dashboard/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
@@ -16,9 +16,21 @@
  *
  */
 
-import { Component, inject, Input, OnInit } from '@angular/core';
-import { Dashboard, DashboardService } from '@streampipes/platform-services';
-import { DialogRef } from '@streampipes/shared-ui';
+import {
+    Component,
+    EventEmitter,
+    inject,
+    Input,
+    OnInit,
+    Output,
+} from '@angular/core';
+import {
+    Dashboard,
+    DashboardService,
+    LinkageData,
+    SpAssetTreeNode,
+} from '@streampipes/platform-services';
+import { AssetSaveService, DialogRef } from '@streampipes/shared-ui';
 
 @Component({
     selector: 'sp-edit-dashboard-dialog-component',
@@ -29,9 +41,19 @@ import { DialogRef } from '@streampipes/shared-ui';
 export class EditDashboardDialogComponent implements OnInit {
     @Input() createMode: boolean;
     @Input() dashboard: Dashboard;
+    @Input() selectedAssets: SpAssetTreeNode[];
+    @Input() deselectedAssets: SpAssetTreeNode[];
+    @Input() originalAssets: SpAssetTreeNode[];
+
+    @Output() selectedAssetsChange = new EventEmitter<SpAssetTreeNode[]>();
+    @Output() deselectedAssetsChange = new EventEmitter<SpAssetTreeNode[]>();
+    @Output() originalAssetsChange = new EventEmitter<SpAssetTreeNode[]>();
 
     private dialogRef = inject(DialogRef<EditDashboardDialogComponent>);
     private dashboardService = inject(DashboardService);
+    private assetSaveService = inject(AssetSaveService);
+
+    addToAssets: boolean = false;
 
     ngOnInit() {
         if (!this.dashboard.dashboardGeneralSettings.defaultViewMode) {
@@ -43,24 +65,75 @@ export class EditDashboardDialogComponent implements OnInit 
{
         ) {
             this.dashboard.dashboardGeneralSettings.globalTimeEnabled = true;
         }
+        if (!this.createMode) {
+            this.addToAssets = true;
+        }
     }
 
     onCancel(): void {
         this.dialogRef.close();
     }
 
+    onSelectedAssetsChange(updatedAssets: SpAssetTreeNode[]): void {
+        this.selectedAssets = updatedAssets;
+        this.selectedAssetsChange.emit(this.selectedAssets);
+    }
+
+    onDeselectedAssetsChange(updatedAssets: SpAssetTreeNode[]): void {
+        this.deselectedAssets = updatedAssets;
+        this.deselectedAssetsChange.emit(this.deselectedAssets);
+    }
+
+    onOriginalAssetsEmitted(updatedAssets: SpAssetTreeNode[]): void {
+        this.originalAssets = updatedAssets;
+        this.originalAssetsChange.emit(this.originalAssets);
+    }
+
+    saveToAssets(data): void {
+        let linkageData: LinkageData[];
+        try {
+            linkageData = this.createLinkageData(data);
+
+            this.saveAssets(linkageData);
+        } catch (err) {
+            console.error('Error in addToAsset:', err);
+        }
+    }
+
+    private createLinkageData(data): LinkageData[] {
+        return [
+            {
+                type: 'dashboard',
+                id: data.elementId,
+                name: data.name,
+            },
+        ];
+    }
+
+    private async saveAssets(linkageData: LinkageData[]): Promise<void> {
+        await this.assetSaveService.saveSelectedAssets(
+            this.selectedAssets,
+            linkageData,
+            this.deselectedAssets,
+            this.originalAssets,
+        );
+        this.dialogRef.close(true);
+    }
+
     onSave(): void {
         this.dashboard.metadata.lastModifiedEpochMs = Date.now();
         if (this.createMode) {
             this.dashboardService
                 .saveDashboard(this.dashboard)
-                .subscribe(() => {
+                .subscribe(data => {
+                    this.saveToAssets(data);
                     this.dialogRef.close();
                 });
         } else {
             this.dashboardService
                 .updateDashboard(this.dashboard)
-                .subscribe(() => {
+                .subscribe(data => {
+                    this.saveToAssets(data);
                     this.dialogRef.close();
                 });
         }
diff --git a/ui/src/app/data-explorer/dialog/asset-dialog.component.html 
b/ui/src/app/data-explorer/dialog/asset-dialog.component.html
index bab116961a..4f99200ef6 100644
--- a/ui/src/app/data-explorer/dialog/asset-dialog.component.html
+++ b/ui/src/app/data-explorer/dialog/asset-dialog.component.html
@@ -25,7 +25,7 @@
                 color="accent"
                 data-cy="sp-show-chart-asset-checkbox"
             >
-                Add Pipeline to Assets
+                Add Chart to Assets
             </mat-checkbox>
             @if (addToAssets) {
                 <div class="mt-10">

Reply via email to