You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2021/10/13 07:56:46 UTC

[incubator-streampipes] 01/04: [STREAMPIPES-444] Allow modification of asset dashboards

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/incubator-streampipes.git

commit e1f215deb93d6243fd139c5ff62ccb8b4960c98e
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Tue Oct 12 22:07:57 2021 +0200

    [STREAMPIPES-444] Allow modification of asset dashboards
---
 .../streampipes/rest/impl/AssetDashboard.java      |  17 +++
 .../storage/api/IAssetDashboardStorage.java        |   2 +
 .../couchdb/impl/AssetDashboardStorageImpl.java    |   5 +
 .../app-asset-monitoring.component.html            |   4 +-
 .../app-asset-monitoring.component.ts              |  11 +-
 .../create-asset/create-asset.component.ts         | 154 +++++++++++++++------
 .../components/view-asset/view-asset.component.css |   7 +-
 .../view-asset/view-asset.component.html           |   1 +
 .../components/view-asset/view-asset.component.ts  |   5 +
 .../save-dashboard-dialog.component.html           |   2 +-
 .../save-dashboard-dialog.component.ts             |  37 ++++-
 .../app-asset-monitoring/model/image-info.model.ts |   4 +-
 .../app-asset-monitoring/services/rest.service.ts  |   4 +
 13 files changed, 192 insertions(+), 61 deletions(-)

diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AssetDashboard.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AssetDashboard.java
index 6114d20..bc00199 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AssetDashboard.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AssetDashboard.java
@@ -20,6 +20,8 @@ package org.apache.streampipes.rest.impl;
 import org.apache.commons.io.FileUtils;
 import org.apache.streampipes.model.client.assetdashboard.AssetDashboardConfig;
 import org.apache.streampipes.rest.core.base.impl.AbstractRestResource;
+import org.apache.streampipes.storage.api.IAssetDashboardStorage;
+import org.apache.streampipes.storage.management.StorageDispatcher;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
 import org.glassfish.jersey.media.multipart.FormDataParam;
 
@@ -46,6 +48,17 @@ public class AssetDashboard extends AbstractRestResource {
     return ok(getNoSqlStorage().getAssetDashboardStorage().getAssetDashboard(dashboardId));
   }
 
+  @PUT
+  @Produces(MediaType.APPLICATION_JSON)
+  @Path("/{dashboardId}")
+  public Response updateAssetDashboard(@PathParam("dashboardId") String dashboardId,
+                                       AssetDashboardConfig dashboardConfig) {
+    AssetDashboardConfig dashboard = getAssetDashboardStorage().getAssetDashboard(dashboardId);
+    dashboardConfig.setRev(dashboard.getRev());
+    getNoSqlStorage().getAssetDashboardStorage().updateAssetDashboard(dashboardConfig);
+    return ok();
+  }
+
   @GET
   @Produces(MediaType.APPLICATION_JSON)
   public Response getAllDashboards() {
@@ -112,4 +125,8 @@ public class AssetDashboard extends AbstractRestResource {
   private String getTargetFile(String filename) {
     return getTargetDirectory() + File.separator + filename;
   }
+
+  private IAssetDashboardStorage getAssetDashboardStorage() {
+    return StorageDispatcher.INSTANCE.getNoSqlStore().getAssetDashboardStorage();
+  }
 }
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAssetDashboardStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAssetDashboardStorage.java
index e1759bb..69d6627 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAssetDashboardStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAssetDashboardStorage.java
@@ -29,5 +29,7 @@ public interface IAssetDashboardStorage {
 
   void storeAssetDashboard(AssetDashboardConfig assetDashboardConfig);
 
+  void updateAssetDashboard(AssetDashboardConfig assetDashboardConfig);
+
   void deleteAssetDashboard(String dashboardId);
 }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AssetDashboardStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AssetDashboardStorageImpl.java
index 9d11b76..665259c 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AssetDashboardStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AssetDashboardStorageImpl.java
@@ -46,6 +46,11 @@ public class AssetDashboardStorageImpl extends AbstractDao<AssetDashboardConfig>
   }
 
   @Override
+  public void updateAssetDashboard(AssetDashboardConfig assetDashboardConfig) {
+    update(assetDashboardConfig);
+  }
+
+  @Override
   public void deleteAssetDashboard(String dashboardId) {
     delete(dashboardId);
   }
diff --git a/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.html b/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.html
index f3d5d2c..a51fd85 100644
--- a/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.html
+++ b/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.html
@@ -30,7 +30,7 @@
 
     <div fxLayout="column" fxFlex="100">
         <asset-dashboard-overview *ngIf="selectedIndex == 0 && !dashboardSelected" fxFlex="100" (selectedDashboard)="openDashboard($event)"></asset-dashboard-overview>
-        <view-asset fxFlex="100" *ngIf="selectedIndex == 0 && dashboardSelected" [dashboardConfig]="selectedDashboard" (dashboardClosed)="closeDashboard($event)"></view-asset>
-        <create-asset *ngIf="selectedIndex == 1" fxFlex="100" (dashboardClosed)="closeDashboard($event)"></create-asset>
+        <view-asset fxFlex="100" *ngIf="selectedIndex == 0 && dashboardSelected" [dashboardConfig]="selectedDashboard" (dashboardClosed)="closeDashboard($event)" (editDashboardEmitter)="editDashboard($event)"></view-asset>
+        <create-asset *ngIf="selectedIndex == 1" fxFlex="100" (dashboardClosed)="closeDashboard($event)" [dashboardConfig]="selectedDashboard"></create-asset>
     </div>
 </div>
diff --git a/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.ts b/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.ts
index e9bef92..e692078 100644
--- a/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.ts
+++ b/ui/src/app/app-asset-monitoring/app-asset-monitoring.component.ts
@@ -16,8 +16,8 @@
  *
  */
 
-import {Component, EventEmitter, Output} from '@angular/core';
-import {DashboardConfiguration} from "./model/dashboard-configuration.model";
+import { Component, EventEmitter, Output } from '@angular/core';
+import { DashboardConfiguration } from "./model/dashboard-configuration.model";
 
 @Component({
     selector: 'app-asset-monitoring',
@@ -54,4 +54,9 @@ export class AppAssetMonitoringComponent {
         this.selectedIndex = 0;
     }
 
-}
\ No newline at end of file
+    editDashboard(dashboardConfig: DashboardConfiguration) {
+        this.selectedDashboard = dashboardConfig;
+        this.selectedIndex = 1;
+    }
+
+}
diff --git a/ui/src/app/app-asset-monitoring/components/create-asset/create-asset.component.ts b/ui/src/app/app-asset-monitoring/components/create-asset/create-asset.component.ts
index 5da1236..b4dd597 100644
--- a/ui/src/app/app-asset-monitoring/components/create-asset/create-asset.component.ts
+++ b/ui/src/app/app-asset-monitoring/components/create-asset/create-asset.component.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { Component, EventEmitter, HostListener, Output } from '@angular/core';
+import { AfterViewInit, Component, EventEmitter, HostListener, Input, Output } from '@angular/core';
 import Konva from 'konva';
 import { AddPipelineDialogComponent } from '../../dialog/add-pipeline/add-pipeline-dialog.component';
 import { MatDialog } from '@angular/material/dialog';
@@ -25,6 +25,8 @@ import { SelectedVisualizationData } from '../../model/selected-visualization-da
 import { SaveDashboardDialogComponent } from '../../dialog/save-dashboard/save-dashboard-dialog.component';
 import { PanelType } from '../../../core-ui/dialog/base-dialog/base-dialog.model';
 import { DialogService } from '../../../core-ui/dialog/base-dialog/base-dialog.service';
+import { DashboardConfiguration } from '../../model/dashboard-configuration.model';
+import { RestService } from '../../services/rest.service';
 
 interface Window {
     Image: any;
@@ -37,7 +39,7 @@ declare const window: Window;
     templateUrl: './create-asset.component.html',
     styleUrls: ['./create-asset.component.css']
 })
-export class CreateAssetComponent {
+export class CreateAssetComponent implements AfterViewInit {
 
     fileName: any;
     selectedUploadFile: File;
@@ -53,33 +55,72 @@ export class CreateAssetComponent {
 
     backgroundImagePresent = false;
     measurementPresent = false;
+    editMode = false;
+
+    @Input()
+    dashboardConfig: DashboardConfiguration;
 
     @Output() dashboardClosed = new EventEmitter<boolean>();
 
+    keyboardListenerActive = true;
+
     constructor(public dialog: MatDialog,
                 public shapeService: ShapeService,
-                private dialogService: DialogService) {
+                private dialogService: DialogService,
+                private restService: RestService) {
     }
 
     ngAfterViewInit() {
         const width = 1400;
         const height = 900;
-        this.mainCanvasStage = new Konva.Stage({
-            container: 'asset-configuration-board-canvas',
-            width,
-            height
-        });
+        if (!this.dashboardConfig) {
+            this.mainCanvasStage = new Konva.Stage({
+                container: 'asset-configuration-board-canvas',
+                width,
+                height
+            });
+            this.initLayers();
+        } else {
+            this.editMode = true;
+            this.makeEditable();
+            this.mainCanvasStage = Konva.Node.create(this.dashboardConfig, 'asset-configuration-board-canvas');
+            this.mainCanvasStage.draw();
+
+            this.backgroundImageLayer = this.mainCanvasStage.children[0];
+            this.mainLayer = this.mainCanvasStage.children[1];
+            const groups = this.mainLayer.getChildren().find('Group');
+            groups.forEach(g => {
+               const id = this.makeId();
+               g.id(id);
+               g.setDraggable(true);
+               this.addTransformerToShape(id, g);
+            });
+            this.makeClickable();
+            this.showImage();
+            this.backgroundImageLayer.moveToBottom();
+            this.mainCanvasStage.draw();
+            this.measurementPresent = true;
+        }
 
         const container = this.mainCanvasStage.container();
         container.focus();
+    }
 
-        this.initLayers();
+    makeEditable() {
+        this.dashboardConfig.imageInfo.draggable = true;
+        this.dashboardConfig.imageInfo.id = this.IMAGE_ID;
     }
 
     initLayers() {
         this.mainLayer = new Konva.Layer();
         this.backgroundImageLayer = new Konva.Layer();
 
+        this.makeClickable();
+        this.mainCanvasStage.add(this.backgroundImageLayer);
+        this.mainCanvasStage.add(this.mainLayer);
+    }
+
+    makeClickable() {
         this.backgroundImageLayer.on('click', evt => {
             this.currentlySelectedShape = evt.target;
         });
@@ -90,8 +131,6 @@ export class CreateAssetComponent {
             }
             this.currentlySelectedShape = parentElement;
         });
-        this.mainCanvasStage.add(this.backgroundImageLayer);
-        this.mainCanvasStage.add(this.mainLayer);
     }
 
     handleFileInput(event: any) {
@@ -103,7 +142,7 @@ export class CreateAssetComponent {
         image.onload = () => {
             const desiredWidth = Math.min(this.mainCanvasStage.width(), image.width);
             const aspectRatio = image.width / image.height;
-            const desiredHeight = desiredWidth * aspectRatio;
+            const desiredHeight = image.width > image.height ? desiredWidth / aspectRatio : desiredWidth * aspectRatio;
             const imageCanvas = new Konva.Image({
                 image,
                 width: desiredWidth,
@@ -114,13 +153,7 @@ export class CreateAssetComponent {
                 id: this.IMAGE_ID
             });
 
-            this.backgroundImageLayer.add(imageCanvas);
-            this.backgroundImageLayer.draw();
-
-            const tr = this.getNewTransformer(this.IMAGE_ID);
-            this.backgroundImageLayer.add(tr);
-            tr.attachTo(imageCanvas);
-            this.backgroundImageLayer.draw();
+            this.addImageTransformer(imageCanvas);
             this.currentlySelectedShape = imageCanvas;
         };
 
@@ -129,10 +162,21 @@ export class CreateAssetComponent {
 
         reader.readAsDataURL(this.selectedUploadFile);
         event.target.value = null;
-        this.backgroundImagePresent = true;
 
     }
 
+    addImageTransformer(imageCanvas: any) {
+        this.backgroundImageLayer.add(imageCanvas);
+        this.backgroundImageLayer.draw();
+
+        const tr = this.getNewTransformer(this.IMAGE_ID);
+        this.backgroundImageLayer.add(tr);
+        tr.attachTo(imageCanvas);
+        this.backgroundImageLayer.moveToBottom();
+        this.backgroundImageLayer.draw();
+        this.backgroundImagePresent = true;
+    }
+
     prepareDashboard() {
         const dialogRef = this.dialogService.open(SaveDashboardDialogComponent, {
             panelType: PanelType.SLIDE_IN_PANEL,
@@ -140,11 +184,12 @@ export class CreateAssetComponent {
             width: '50vw',
             data: {
                 dashboardCanvas: this.mainCanvasStage as any,
-                file: this.selectedUploadFile
+                file: this.selectedUploadFile,
+                editMode: this.editMode,
+                dashboardConfig: this.dashboardConfig
             }
         });
         dialogRef.afterClosed().subscribe(closed => {
-            console.log('close');
             this.dashboardClosed.emit(true);
         });
     }
@@ -158,6 +203,7 @@ export class CreateAssetComponent {
     }
 
     openAddPipelineDialog(): void {
+        this.keyboardListenerActive = false;
         const dialogRef = this.dialogService.open(AddPipelineDialogComponent, {
             panelType: PanelType.SLIDE_IN_PANEL,
             title: 'Add visualization',
@@ -167,41 +213,43 @@ export class CreateAssetComponent {
         });
 
         dialogRef.afterClosed().subscribe(result => {
-            console.log(result);
             if (result) {
                 this.addNewVisulizationItem(result);
                 this.measurementPresent = true;
                 this.mainLayer.draw();
             }
+            this.keyboardListenerActive = true;
         });
     }
 
     @HostListener('document:keydown', ['$event'])
     handleKeyboardEvent(event: KeyboardEvent) {
-        const delta = 4;
-        if (event.code === 'Delete') {
-            const id = this.currentlySelectedShape.id();
-            this.mainCanvasStage.findOne('#' + id + '-transformer').destroy();
-            this.currentlySelectedShape.destroy();
-            if (id === this.IMAGE_ID) {
-                this.backgroundImagePresent = false;
-            } else {
-                const remainingElementIds = this.mainLayer.find('Group');
-                if (remainingElementIds.length === 0) {
-                    this.measurementPresent = false;
+        if (this.keyboardListenerActive) {
+            const delta = 4;
+            if (event.code === 'Delete') {
+                const id = this.currentlySelectedShape.id();
+                this.mainCanvasStage.findOne('#' + id + '-transformer').destroy();
+                this.currentlySelectedShape.destroy();
+                if (id === this.IMAGE_ID) {
+                    this.backgroundImagePresent = false;
+                } else {
+                    const remainingElementIds = this.mainLayer.find('Group');
+                    if (remainingElementIds.length === 0) {
+                        this.measurementPresent = false;
+                    }
                 }
+            } else if (event.code === 'ArrowLeft') {
+                this.currentlySelectedShape.x(this.currentlySelectedShape.x() - delta);
+            } else if (event.code === 'ArrowRight') {
+                this.currentlySelectedShape.x(this.currentlySelectedShape.x() + delta);
+            } else if (event.code === 'ArrowDown') {
+                this.currentlySelectedShape.y(this.currentlySelectedShape.y() + delta);
+            } else if (event.code === 'ArrowUp') {
+                this.currentlySelectedShape.y(this.currentlySelectedShape.y() - delta);
             }
-        } else if (event.code === 'ArrowLeft') {
-            this.currentlySelectedShape.x(this.currentlySelectedShape.x() - delta);
-        } else if (event.code === 'ArrowRight') {
-            this.currentlySelectedShape.x(this.currentlySelectedShape.x() + delta);
-        } else if (event.code === 'ArrowDown') {
-            this.currentlySelectedShape.y(this.currentlySelectedShape.y() + delta);
-        } else if (event.code === 'ArrowUp') {
-            this.currentlySelectedShape.y(this.currentlySelectedShape.y() - delta);
+            this.backgroundImageLayer.draw();
+            this.mainLayer.draw();
         }
-        this.backgroundImageLayer.draw();
-        this.mainLayer.draw();
     }
 
     addNewVisulizationItem(visualizationConfig) {
@@ -209,11 +257,15 @@ export class CreateAssetComponent {
         const id = this.makeId();
         visGroup.id(id);
         this.mainLayer.add(visGroup);
+        this.addTransformerToShape(id, visGroup);
+    }
+
+    addTransformerToShape(id: string, visGroup: any) {
         const tr = this.getNewTransformer(id);
         this.mainLayer.add(tr);
         tr.attachTo(visGroup);
-        this.mainLayer.draw();
-        this.currentlySelectedShape = visGroup;
+        //this.mainLayer.draw();
+        //this.currentlySelectedShape = visGroup;
     }
 
     getNewTransformer(id: string): Konva.Transformer {
@@ -239,4 +291,14 @@ export class CreateAssetComponent {
         return text;
     }
 
+    showImage() {
+        const image = new window.Image();
+        image.src = this.restService.getImageUrl(this.dashboardConfig.imageInfo.imageName);
+        this.dashboardConfig.imageInfo.image = image;
+        image.onload = () => {
+            const imageCanvas = new Konva.Image(this.dashboardConfig.imageInfo);
+            this.addImageTransformer(imageCanvas);
+        };
+    }
+
 }
diff --git a/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.css b/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.css
index 4447b41..0fe1fc6 100644
--- a/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.css
+++ b/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.css
@@ -17,9 +17,12 @@
  */
 
 .asset-view-canvas {
-    width:1200px;
+    width:1400px;
     height:900px;
     border: 2px solid rgb(27, 20, 100);
     margin: 20px auto;
+}
 
-}
\ No newline at end of file
+.mr-10 {
+    margin-right: 10px;
+}
diff --git a/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.html b/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.html
index 35cd662..df343f2 100644
--- a/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.html
+++ b/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.html
@@ -22,6 +22,7 @@
             <h1>{{dashboardConfig.dashboardName}}</h1>
         </div>
         <div fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
+            <button mat-button mat-raised-button color="accent" (click)="editDashboard()" class="mr-10">Edit dashboard</button>
             <button mat-button mat-raised-button class="mat-basic" (click)="closeDashboard()">Close dashboard</button>
         </div>
     </div>
diff --git a/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.ts b/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.ts
index bbd0c80..674deff 100644
--- a/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.ts
+++ b/ui/src/app/app-asset-monitoring/components/view-asset/view-asset.component.ts
@@ -38,6 +38,7 @@ export class ViewAssetComponent {
 
     @Input() dashboardConfig: DashboardConfiguration;
     @Output() dashboardClosed = new EventEmitter<boolean>();
+    @Output() editDashboardEmitter = new EventEmitter<DashboardConfiguration>();
 
     mainCanvasStage: any;
     mainLayer: any;
@@ -86,4 +87,8 @@ export class ViewAssetComponent {
         this.dashboardClosed.emit(true);
     }
 
+    editDashboard() {
+        this.editDashboardEmitter.emit(this.dashboardConfig);
+    }
+
 }
diff --git a/ui/src/app/app-asset-monitoring/dialog/save-dashboard/save-dashboard-dialog.component.html b/ui/src/app/app-asset-monitoring/dialog/save-dashboard/save-dashboard-dialog.component.html
index 11a4194..9f743fd 100644
--- a/ui/src/app/app-asset-monitoring/dialog/save-dashboard/save-dashboard-dialog.component.html
+++ b/ui/src/app/app-asset-monitoring/dialog/save-dashboard/save-dashboard-dialog.component.html
@@ -41,7 +41,7 @@
             Cancel
         </button>
         <button mat-button mat-raised-button color="accent" (click)="save()">
-            Next
+            Save
         </button>
     </div>
 </div>
diff --git a/ui/src/app/app-asset-monitoring/dialog/save-dashboard/save-dashboard-dialog.component.ts b/ui/src/app/app-asset-monitoring/dialog/save-dashboard/save-dashboard-dialog.component.ts
index 413a344..8f2a078 100644
--- a/ui/src/app/app-asset-monitoring/dialog/save-dashboard/save-dashboard-dialog.component.ts
+++ b/ui/src/app/app-asset-monitoring/dialog/save-dashboard/save-dashboard-dialog.component.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { Component, Input } from '@angular/core';
+import { Component, Input, OnInit } from '@angular/core';
 import { RestService } from '../../services/rest.service';
 import { DashboardConfiguration } from '../../model/dashboard-configuration.model';
 import { ImageInfo } from '../../model/image-info.model';
@@ -29,7 +29,7 @@ import Stage = Konva.Stage;
     templateUrl: 'save-dashboard-dialog.component.html',
     styleUrls: ['./save-dashboard-dialog.component.scss'],
 })
-export class SaveDashboardDialogComponent {
+export class SaveDashboardDialogComponent implements OnInit {
 
     dashboardName: string;
     dashboardDescription: string;
@@ -40,19 +40,34 @@ export class SaveDashboardDialogComponent {
     @Input()
     file: File;
 
+    @Input()
+    editMode: boolean;
+
+    @Input()
+    dashboardConfig: DashboardConfiguration;
+
     constructor(
         private dialogRef: DialogRef<SaveDashboardDialogComponent>,
         private restService: RestService) {
     }
 
+    ngOnInit() {
+        if (this.editMode) {
+            this.dashboardName = this.dashboardConfig.dashboardName;
+            this.dashboardDescription = this.dashboardConfig.dashboardDescription;
+        }
+    }
+
     cancel() {
         this.dialogRef.close();
     }
 
     save() {
         // save image
-        this.restService.storeImage(this.file).subscribe(response => {
-        });
+        if (this.file) {
+            this.restService.storeImage(this.file).subscribe(response => {
+            });
+        }
 
         // save dashboard
         const imageInfo = this.makeImageInfo();
@@ -60,9 +75,19 @@ export class SaveDashboardDialogComponent {
         dashboardConfig.dashboardName = this.dashboardName;
         dashboardConfig.dashboardDescription = this.dashboardDescription;
         dashboardConfig.imageInfo = imageInfo;
-        dashboardConfig.imageInfo.imageName = this.file.name;
+        dashboardConfig.imageInfo.draggable = false;
+        if (this.file) {
+            dashboardConfig.imageInfo.imageName = this.file.name;
+        }
+
+        if (this.editMode) {
+            dashboardConfig.dashboardId = this.dashboardConfig.dashboardId;
+        }
 
-        this.restService.storeDashboard(dashboardConfig).subscribe(response => {
+        const observable = this.editMode ?
+            this.restService.updateDashboard(dashboardConfig) :
+            this.restService.storeDashboard(dashboardConfig);
+        observable.subscribe(response => {
             this.dialogRef.close();
         });
     }
diff --git a/ui/src/app/app-asset-monitoring/model/image-info.model.ts b/ui/src/app/app-asset-monitoring/model/image-info.model.ts
index a1e5e46..ca011eb 100644
--- a/ui/src/app/app-asset-monitoring/model/image-info.model.ts
+++ b/ui/src/app/app-asset-monitoring/model/image-info.model.ts
@@ -26,4 +26,6 @@ export interface ImageInfo {
     scaleY: number;
     rotation: number;
     image: any;
-}
\ No newline at end of file
+    draggable: boolean;
+    id: string;
+}
diff --git a/ui/src/app/app-asset-monitoring/services/rest.service.ts b/ui/src/app/app-asset-monitoring/services/rest.service.ts
index 2797cc5..e21427c 100644
--- a/ui/src/app/app-asset-monitoring/services/rest.service.ts
+++ b/ui/src/app/app-asset-monitoring/services/rest.service.ts
@@ -57,6 +57,10 @@ export class RestService {
     return this.http.post(this.url, dashboardConfig);
   }
 
+  updateDashboard(dashboardConfig: DashboardConfiguration) {
+    return this.http.put(this.url + '/' + dashboardConfig.dashboardId, dashboardConfig);
+  }
+
   getDashboards(): Observable<DashboardConfiguration[]> {
     return this.http.get(this.url).pipe(map(response => {
       return response as DashboardConfiguration[];