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 2020/02/08 22:40:13 UTC

[incubator-streampipes] branch new_dashboard updated: STREAMPIPES-58: Add dashboard overview

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

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


The following commit(s) were added to refs/heads/new_dashboard by this push:
     new 98af3b1  STREAMPIPES-58: Add dashboard overview
98af3b1 is described below

commit 98af3b19d172054b87c56c77f2f151ba265c2fdf
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Sat Feb 8 23:39:58 2020 +0100

    STREAMPIPES-58: Add dashboard overview
---
 .../streampipes/model/dashboard/DashboardItem.java | 90 ++++++++++++++++++++++
 .../model/dashboard/DashboardModel.java            | 62 ++++++++++++++-
 .../streampipes/rest/impl/dashboard/Dashboard.java |  6 --
 .../rest/impl/dashboard/DashboardWidget.java       |  4 +-
 .../jsonld/CustomAnnotationProvider.java           |  2 -
 .../storage/api/IDashboardWidgetStorage.java       |  2 +-
 .../storage/couchdb/dao/AbstractDao.java           |  7 +-
 .../storage/couchdb/dao/PersistCommand.java        |  7 +-
 .../storage/couchdb/impl/DashboardStorageImpl.java |  2 +-
 .../couchdb/impl/DashboardWidgetStorageImpl.java   |  4 +-
 .../storage/couchdb/impl/DataLakeStorageImpl.java  |  2 +-
 .../couchdb/impl/MonitoringDataStorageImpl.java    |  2 +-
 .../couchdb/impl/PipelineCategoryStorageImpl.java  |  2 +-
 .../overview/dashboard-overview.component.css      |  7 ++
 .../overview/dashboard-overview.component.html     | 73 ++++++++++++++++++
 .../overview/dashboard-overview.component.ts       | 62 +++++++++++++++
 .../components/panel/dashboard-panel.component.css |  3 +
 .../panel/dashboard-panel.component.html           | 26 +++----
 .../components/panel/dashboard-panel.component.ts  |  3 +-
 ui/src/app/dashboard-v2/dashboard.component.html   |  8 +-
 ui/src/app/dashboard-v2/dashboard.component.ts     | 23 +++---
 ui/src/app/dashboard-v2/dashboard.module.ts        | 15 ++--
 .../add-visualization-dialog.component.css         |  0
 .../add-visualization-dialog.component.html        |  0
 .../add-visualization-dialog.component.ts          | 50 ++++++------
 .../edit-dashboard-dialog.component.css}           |  0
 .../edit-dashboard-dialog.component.html           | 54 +++++++++++++
 .../edit-dashboard-dialog.component.ts             | 60 +++++++++++++++
 ui/src/app/dashboard-v2/models/dashboard.model.ts  |  6 +-
 .../app/dashboard-v2/services/dashboard.service.ts | 37 ++++-----
 ui/src/assets/dashboards.json                      |  2 +-
 31 files changed, 512 insertions(+), 109 deletions(-)

diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java
index 706f1dc..f33485e 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardItem.java
@@ -17,5 +17,95 @@
  */
 package org.apache.streampipes.model.dashboard;
 
+import java.util.List;
+
 public class DashboardItem {
+
+  private String id;
+  private String name;
+  private String component;
+  private String widgetType;
+
+  private List<String> settings;
+
+  private Integer cols;
+  private Integer rows;
+  private Integer x;
+  private Integer y;
+
+  public DashboardItem() {
+
+  }
+
+  public String getId() {
+    return id;
+  }
+
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getComponent() {
+    return component;
+  }
+
+  public void setComponent(String component) {
+    this.component = component;
+  }
+
+  public String getWidgetType() {
+    return widgetType;
+  }
+
+  public void setWidgetType(String widgetType) {
+    this.widgetType = widgetType;
+  }
+
+  public List<String> getSettings() {
+    return settings;
+  }
+
+  public void setSettings(List<String> settings) {
+    this.settings = settings;
+  }
+
+  public Integer getCols() {
+    return cols;
+  }
+
+  public void setCols(Integer cols) {
+    this.cols = cols;
+  }
+
+  public Integer getRows() {
+    return rows;
+  }
+
+  public void setRows(Integer rows) {
+    this.rows = rows;
+  }
+
+  public Integer getX() {
+    return x;
+  }
+
+  public void setX(Integer x) {
+    this.x = x;
+  }
+
+  public Integer getY() {
+    return y;
+  }
+
+  public void setY(Integer y) {
+    this.y = y;
+  }
 }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
index 4a5a138..7fcba5c 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
@@ -18,18 +18,78 @@
 
 package org.apache.streampipes.model.dashboard;
 
+import com.google.gson.annotations.SerializedName;
 import org.apache.streampipes.vocabulary.StreamPipes;
 import org.streampipes.empire.annotations.RdfsClass;
 
+import java.util.List;
+
 import javax.persistence.Entity;
 import javax.persistence.MappedSuperclass;
 
 @RdfsClass(StreamPipes.DASHBOARD_MODEL)
 @MappedSuperclass
 @Entity
-public class DashboardModel extends DashboardEntity {
+public class DashboardModel {
+
+  private @SerializedName("_id") String couchDbId;
+  private @SerializedName("_rev") String couchDbRev;
+
+  private String id;
+  private String name;
+  private String description;
+
+  private List<DashboardItem> widgets;
 
   public DashboardModel() {
 
   }
+
+  public String getCouchDbId() {
+    return couchDbId;
+  }
+
+  public void setCouchDbId(String couchDbId) {
+    this.couchDbId = couchDbId;
+  }
+
+  public String getCouchDbRev() {
+    return couchDbRev;
+  }
+
+  public void setCouchDbRev(String couchDbRev) {
+    this.couchDbRev = couchDbRev;
+  }
+
+  public String getId() {
+    return id;
+  }
+
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(String description) {
+    this.description = description;
+  }
+
+  public List<DashboardItem> getWidgets() {
+    return widgets;
+  }
+
+  public void setWidgets(List<DashboardItem> widgets) {
+    this.widgets = widgets;
+  }
 }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/Dashboard.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/Dashboard.java
index 127e231..cf97738 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/Dashboard.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/Dashboard.java
@@ -21,7 +21,6 @@ package org.apache.streampipes.rest.impl.dashboard;
 import org.apache.streampipes.model.dashboard.DashboardModel;
 import org.apache.streampipes.rest.api.dashboard.IDashboard;
 import org.apache.streampipes.rest.impl.AbstractRestInterface;
-import org.apache.streampipes.rest.shared.annotation.JsonLdSerialized;
 import org.apache.streampipes.storage.api.IDashboardStorage;
 
 import javax.ws.rs.DELETE;
@@ -38,7 +37,6 @@ import javax.ws.rs.core.Response;
 public class Dashboard extends AbstractRestInterface implements IDashboard {
 
   @GET
-  @JsonLdSerialized
   @Produces(MediaType.APPLICATION_JSON)
   @Override
   public Response getAllDashboards() {
@@ -46,7 +44,6 @@ public class Dashboard extends AbstractRestInterface implements IDashboard {
   }
 
   @GET
-  @JsonLdSerialized
   @Produces(MediaType.APPLICATION_JSON)
   @Path("/{dashboardId}")
   @Override
@@ -55,7 +52,6 @@ public class Dashboard extends AbstractRestInterface implements IDashboard {
   }
 
   @PUT
-  @JsonLdSerialized
   @Produces(MediaType.APPLICATION_JSON)
   @Path("/{dashboardId}")
   @Override
@@ -65,7 +61,6 @@ public class Dashboard extends AbstractRestInterface implements IDashboard {
   }
 
   @DELETE
-  @JsonLdSerialized
   @Produces(MediaType.APPLICATION_JSON)
   @Path("/{dashboardId}")
   @Override
@@ -75,7 +70,6 @@ public class Dashboard extends AbstractRestInterface implements IDashboard {
   }
 
   @POST
-  @JsonLdSerialized
   @Produces(MediaType.APPLICATION_JSON)
   @Override
   public Response createDashboard(DashboardModel dashboardModel) {
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java
index b919e07..947d43b 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java
@@ -81,8 +81,8 @@ public class DashboardWidget extends AbstractRestInterface implements IDashboard
   @Consumes(SpMediaType.JSONLD)
   @Override
   public Response createDashboardWidget(DashboardWidgetModel dashboardWidgetModel) {
-    getDashboardWidgetStorage().storeDashboardWidget(dashboardWidgetModel);
-    return ok();
+    String widgetId = getDashboardWidgetStorage().storeDashboardWidget(dashboardWidgetModel);
+    return ok(getDashboardWidgetStorage().getDashboardWidget(widgetId));
   }
 
   private IDashboardWidgetStorage getDashboardWidgetStorage() {
diff --git a/streampipes-serializers/src/main/java/org/apache/streampipes/serializers/jsonld/CustomAnnotationProvider.java b/streampipes-serializers/src/main/java/org/apache/streampipes/serializers/jsonld/CustomAnnotationProvider.java
index 3b2294c..b774052 100644
--- a/streampipes-serializers/src/main/java/org/apache/streampipes/serializers/jsonld/CustomAnnotationProvider.java
+++ b/streampipes-serializers/src/main/java/org/apache/streampipes/serializers/jsonld/CustomAnnotationProvider.java
@@ -50,7 +50,6 @@ import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRu
 import org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription;
 import org.apache.streampipes.model.connect.worker.ConnectWorkerContainer;
-import org.apache.streampipes.model.dashboard.DashboardModel;
 import org.apache.streampipes.model.dashboard.DashboardWidgetModel;
 import org.apache.streampipes.model.dashboard.VisualizablePipeline;
 import org.apache.streampipes.model.graph.DataProcessorDescription;
@@ -244,7 +243,6 @@ public class CustomAnnotationProvider implements EmpireAnnotationProvider {
             EventRateTransformationRuleDescription.class,
             SecretStaticProperty.class,
             DashboardWidgetModel.class,
-            DashboardModel.class,
             VisualizablePipeline.class,
             StreamPipesJsonLdContainer.class
 
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDashboardWidgetStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDashboardWidgetStorage.java
index 718ff81..0d9bf2c 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDashboardWidgetStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDashboardWidgetStorage.java
@@ -26,7 +26,7 @@ public interface IDashboardWidgetStorage {
 
   List<DashboardWidgetModel> getAllDashboardWidgets();
 
-  void storeDashboardWidget(DashboardWidgetModel dashboardWidgetModel);
+  String storeDashboardWidget(DashboardWidgetModel dashboardWidgetModel);
 
   void updateDashboardWidget(DashboardWidgetModel dashboardWidgetModel);
 
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java
index 2e0b0ef..282fe7d 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/AbstractDao.java
@@ -18,6 +18,7 @@
 package org.apache.streampipes.storage.couchdb.dao;
 
 import org.lightcouch.CouchDbClient;
+import org.mapdb.Fun;
 
 import java.util.List;
 import java.util.Optional;
@@ -33,8 +34,10 @@ public class AbstractDao<T> {
     this.clazz = clazz;
   }
 
-  public Boolean persist(T objToPersist) {
-    DbCommand<Boolean, T> cmd = new PersistCommand<>(couchDbClientSupplier, objToPersist, clazz);
+  public Fun.Tuple2<Boolean, String> persist(T objToPersist) {
+    DbCommand<Fun.Tuple2<Boolean, String>, T> cmd = new PersistCommand<>(couchDbClientSupplier,
+            objToPersist,
+            clazz);
     return cmd.execute();
   }
 
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/PersistCommand.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/PersistCommand.java
index 6772d81..28d8315 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/PersistCommand.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/dao/PersistCommand.java
@@ -19,10 +19,11 @@ package org.apache.streampipes.storage.couchdb.dao;
 
 import org.lightcouch.CouchDbClient;
 import org.lightcouch.Response;
+import org.mapdb.Fun;
 
 import java.util.function.Supplier;
 
-public class PersistCommand<T> extends DbCommand<Boolean, T> {
+public class PersistCommand<T> extends DbCommand<Fun.Tuple2<Boolean, String>, T> {
 
   private T objectToPersist;
 
@@ -32,10 +33,10 @@ public class PersistCommand<T> extends DbCommand<Boolean, T> {
   }
 
   @Override
-  protected Boolean executeCommand(CouchDbClient couchDbClient) {
+  protected Fun.Tuple2<Boolean, String> executeCommand(CouchDbClient couchDbClient) {
     Response response = couchDbClient.save(objectToPersist);
 
-    return response.getError() == null;
+    return new Fun.Tuple2<>(response.getError() == null, response.getId());
 
   }
 }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardStorageImpl.java
index 11ffaba..74e5e29 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardStorageImpl.java
@@ -53,6 +53,6 @@ public class DashboardStorageImpl extends AbstractDao<DashboardModel> implements
 
   @Override
   public void deleteDashboard(String dashboardId) {
-
+    delete(dashboardId);
   }
 }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardWidgetStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardWidgetStorageImpl.java
index 883ae9d..bc226c9 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardWidgetStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DashboardWidgetStorageImpl.java
@@ -37,8 +37,8 @@ public class DashboardWidgetStorageImpl extends AbstractDao<DashboardWidgetModel
   }
 
   @Override
-  public void storeDashboardWidget(DashboardWidgetModel dashboardWidgetModel) {
-    persist(dashboardWidgetModel);
+  public String storeDashboardWidget(DashboardWidgetModel dashboardWidgetModel) {
+    return persist(dashboardWidgetModel).b;
   }
 
   @Override
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java
index 92f2426..60a7559 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DataLakeStorageImpl.java
@@ -33,7 +33,7 @@ public class DataLakeStorageImpl extends AbstractDao<DataLakeMeasure> implements
 
     @Override
     public boolean storeDataLakeMeasure(DataLakeMeasure measure) {
-        return persist(measure);
+        return persist(measure).a;
     }
 
     @Override
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/MonitoringDataStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/MonitoringDataStorageImpl.java
index fa59b45..9597c6d 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/MonitoringDataStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/MonitoringDataStorageImpl.java
@@ -63,7 +63,7 @@ public class MonitoringDataStorageImpl extends AbstractDao<JobReport> implements
 
 	@Override
 	public boolean storeJobReport(JobReport jobReport) {
-		return persist(jobReport);
+		return persist(jobReport).a;
 	}
 
 }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineCategoryStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineCategoryStorageImpl.java
index 0b48ea1..3480d94 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineCategoryStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineCategoryStorageImpl.java
@@ -38,7 +38,7 @@ public class PipelineCategoryStorageImpl extends AbstractDao<PipelineCategory> i
 
 	@Override
 	public boolean addPipelineCategory(PipelineCategory pipelineCategory) {
-		return persist(pipelineCategory);
+		return persist(pipelineCategory).a;
 	}
 
 	@Override
diff --git a/ui/src/app/dashboard-v2/components/overview/dashboard-overview.component.css b/ui/src/app/dashboard-v2/components/overview/dashboard-overview.component.css
new file mode 100644
index 0000000..fc50ea8
--- /dev/null
+++ b/ui/src/app/dashboard-v2/components/overview/dashboard-overview.component.css
@@ -0,0 +1,7 @@
+table {
+    width:100%;
+}
+
+.m-20 {
+    margin: 20px;
+}
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/overview/dashboard-overview.component.html b/ui/src/app/dashboard-v2/components/overview/dashboard-overview.component.html
new file mode 100644
index 0000000..b254d0a
--- /dev/null
+++ b/ui/src/app/dashboard-v2/components/overview/dashboard-overview.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 fxFlex="100" fxLayout="column" class="m-20">
+    <div fxLayout="row wrap">
+        <button mat-button mat-raised-button color="primary" (click)="openNewDashboardDialog()">
+            New dashboard
+        </button>
+    </div>
+    <div fxFlex="100" fxLayout="row wrap" fxLayoutAlign="start stretch">
+        <div fxFlex="100" class="assemblyOptions sp-blue-bg" style="padding:5px;">
+            <div fxLayout="row" fxLayoutAlign="start center" fxFlex="100">
+                <h4>My dashboards</h4>
+                <span flex></span>
+            </div>
+        </div>
+        <div fxFlex="100" fxLayout="column" fxLayoutAlign="start start" class="sp-blue-border">
+            <table fxFlex="95" mat-table [dataSource]="dataSource" multiTemplateDataRows>
+
+                <ng-container matColumnDef="name">
+                    <th fxFlex="80" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Dashboard</th>
+                    <td fxFlex="80" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
+                        {{element.name}}<br/>
+                        {{element.description}}
+                    </td>
+                </ng-container>
+
+                <ng-container matColumnDef="edit">
+                    <th fxFlex="10" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Edit</th>
+                    <td fxFlex="10" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
+                        <div fxLayout="row">
+                            <button mat-button mat-icon-button color="primary"
+                                    (click)="openEditDashboardDialog(element)">
+                                <i class="material-icons">edit</i>
+                            </button>
+                        </div>
+                    </td>
+                </ng-container>
+
+                <ng-container matColumnDef="delete">
+                    <th fxFlex="10" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Delete</th>
+                    <td fxFlex="10" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
+                        <div fxLayout="row">
+                            <button mat-button mat-icon-button color="primary"
+                                    (click)="openDeleteDashboardDialog(element)">
+                                <i class="material-icons">delete</i>
+                            </button>
+                        </div>
+                    </td>
+                </ng-container>
+
+                <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+                <tr mat-row *matRowDef="let element; columns: displayedColumns;">
+                </tr>
+            </table>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/overview/dashboard-overview.component.ts b/ui/src/app/dashboard-v2/components/overview/dashboard-overview.component.ts
new file mode 100644
index 0000000..f492f9d
--- /dev/null
+++ b/ui/src/app/dashboard-v2/components/overview/dashboard-overview.component.ts
@@ -0,0 +1,62 @@
+import {Component, EventEmitter, Input, OnInit, Output} from "@angular/core";
+import {Dashboard} from "../../models/dashboard.model";
+import {MatTableDataSource} from "@angular/material/table";
+import {MatDialog} from "@angular/material/dialog";
+import {DashboardService} from "../../services/dashboard.service";
+import {AddVisualizationDialogComponent} from "../../dialogs/add-widget/add-visualization-dialog.component";
+import {EditDashboardDialogComponent} from "../../dialogs/edit-dashboard/edit-dashboard-dialog.component";
+
+@Component({
+    selector: 'dashboard-overview',
+    templateUrl: './dashboard-overview.component.html',
+    styleUrls: ['./dashboard-overview.component.css']
+})
+export class DashboardOverviewComponent implements OnInit {
+
+    @Input() dashboards: Array<Dashboard>;
+    @Output() reloadDashboardsEmitter = new EventEmitter<boolean>();
+
+    dataSource = new MatTableDataSource<Dashboard>();
+    displayedColumns: string[] = ['name', 'edit', 'delete'];
+
+    constructor(private dashboardService: DashboardService,
+                public dialog: MatDialog) {
+
+    }
+
+    ngOnInit(): void {
+        this.dataSource.data = this.dashboards;
+    }
+
+    openNewDashboardDialog() {
+        let dashboard = {} as Dashboard;
+        dashboard.widgets = [];
+
+        this.openDashboardModificationDialog(true, dashboard);
+    }
+
+    openDashboardModificationDialog(createMode: boolean, dashboard: Dashboard) {
+        const dialogRef = this.dialog.open(EditDashboardDialogComponent, {
+            width: '70%',
+            panelClass: 'custom-dialog-container'
+        });
+        dialogRef.componentInstance.createMode = createMode;
+        dialogRef.componentInstance.dashboard = dashboard;
+
+        dialogRef.afterClosed().subscribe(result => {
+            this.reloadDashboardsEmitter.emit(true);
+        });
+    }
+
+    openEditDashboardDialog(dashboard: Dashboard) {
+        this.openDashboardModificationDialog(false, dashboard);
+    }
+
+    openDeleteDashboardDialog(dashboard: Dashboard) {
+        // TODO add confirm dialog
+        this.dashboardService.deleteDashboard(dashboard).subscribe(result => {
+            this.reloadDashboardsEmitter.emit(true);
+        });
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.css b/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.css
index e69de29..b0ebff0 100644
--- a/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.css
+++ b/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.css
@@ -0,0 +1,3 @@
+.m-20 {
+    margin: 20px;
+}
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.html b/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.html
index a3bf4b1..6cc0ef4 100644
--- a/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.html
+++ b/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.html
@@ -1,13 +1,13 @@
-<button mat-button mat-raised-button color="primary" (click)="addWidget()">Add visualization</button>
-
-<gridster [options]="options">
-
-    <ng-container *ngFor="let item of items">
-
-        <gridster-item [item]="item">
-            <dashboard-widget [widget]="item"></dashboard-widget>
-        </gridster-item>
-
-    </ng-container>
-
-</gridster>
\ No newline at end of file
+<div fxFlex="100" fxLayout="column" class="m-20">
+    <div fxLayout="row wrap" style="margin-bottom:20px;">
+        <button mat-button mat-raised-button color="primary" (click)="addWidget()">Add visualization</button>
+    </div>
+
+    <gridster [options]="options">
+        <ng-container *ngFor="let item of items">
+            <gridster-item [item]="item">
+                <dashboard-widget [widget]="item"></dashboard-widget>
+            </gridster-item>
+        </ng-container>
+    </gridster>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.ts b/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.ts
index 1a7e06e..2b4f76d 100644
--- a/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.ts
+++ b/ui/src/app/dashboard-v2/components/panel/dashboard-panel.component.ts
@@ -4,7 +4,7 @@ import {Subscription} from "rxjs";
 import {MockDashboardService} from "../../services/MockDashboard.service";
 import {GridType} from "angular-gridster2";
 import {MatDialog} from "@angular/material/dialog";
-import {AddVisualizationDialogComponent} from "../../dialogs/add-visualization-dialog.component";
+import {AddVisualizationDialogComponent} from "../../dialogs/add-widget/add-visualization-dialog.component";
 
 @Component({
     selector: 'dashboard-panel',
@@ -45,6 +45,7 @@ export class DashboardPanelComponent implements OnInit {
 
         dialogRef.afterClosed().subscribe(result => {
             if (result) {
+                console.log(result);
                 // this.addNewVisulizationItem(result);
                 // this.measurementPresent = true;
                 // this.mainLayer.draw();
diff --git a/ui/src/app/dashboard-v2/dashboard.component.html b/ui/src/app/dashboard-v2/dashboard.component.html
index 56f8e2d..9184530 100644
--- a/ui/src/app/dashboard-v2/dashboard.component.html
+++ b/ui/src/app/dashboard-v2/dashboard.component.html
@@ -9,7 +9,13 @@
     </div>
 
     <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" *ngIf="dashboardsLoaded">
+    <dashboard-overview (reloadDashboardsEmitter)="getDashboards($event)" [dashboards]="dashboards"
+                        *ngIf="!dashboardTabSelected">
+
+    </dashboard-overview>
     <dashboard-panel fxLayout="column" [dashboard]="selectedDashboard"
-                     style="height:100%;"></dashboard-panel>
+                     style="height:100%;" *ngIf="dashboardTabSelected">
+
+    </dashboard-panel>
     </div>
 </div>
diff --git a/ui/src/app/dashboard-v2/dashboard.component.ts b/ui/src/app/dashboard-v2/dashboard.component.ts
index d5e40b2..ad69a51 100644
--- a/ui/src/app/dashboard-v2/dashboard.component.ts
+++ b/ui/src/app/dashboard-v2/dashboard.component.ts
@@ -1,8 +1,7 @@
-import {Component, Input, OnInit} from "@angular/core";
-import {Subscription} from "rxjs";
-import {GridType} from "angular-gridster2";
-import {Dashboard, DashboardConfig} from "./models/dashboard.model";
+import {Component, OnInit} from "@angular/core";
+import {Dashboard} from "./models/dashboard.model";
 import {MockDashboardService} from "./services/MockDashboard.service";
+import {DashboardService} from "./services/dashboard.service";
 
 @Component({
     selector: 'dashboard',
@@ -13,11 +12,12 @@ export class DashboardComponent implements OnInit {
 
     selectedDashboard: Dashboard;
     selectedIndex: number = 0;
-    dashboardsLoaded = false;
+    dashboardsLoaded: boolean = false;
+    dashboardTabSelected: boolean = false;
 
     dashboards: Array<Dashboard>;
 
-    constructor(private dashboardService: MockDashboardService) {}
+    constructor(private dashboardService: DashboardService) {}
 
     public ngOnInit() {
         this.getDashboards();
@@ -26,14 +26,19 @@ export class DashboardComponent implements OnInit {
 
 
     selectDashboard(index: number) {
-        this.selectedDashboard = this.dashboards[index];
+        if (index == 0) {
+            this.dashboardTabSelected = false;
+        } else {
+            this.dashboardTabSelected = true;
+            this.selectedDashboard = this.dashboards[index - 1];
+        }
     }
 
-    protected getDashboards() {
+    protected getDashboards(reload?: boolean) {
+        this.dashboardsLoaded = false;
         this.dashboardService.getDashboards().subscribe(data => {
             this.dashboards = data;
             this.selectedIndex = 0;
-            this.selectDashboard(0);
             this.dashboardsLoaded = true;
         });
     }
diff --git a/ui/src/app/dashboard-v2/dashboard.module.ts b/ui/src/app/dashboard-v2/dashboard.module.ts
index 2cd4cbb..e166d23 100644
--- a/ui/src/app/dashboard-v2/dashboard.module.ts
+++ b/ui/src/app/dashboard-v2/dashboard.module.ts
@@ -11,20 +11,16 @@ import {DashboardWidgetComponent} from "./components/widget/dashboard-widget.com
 import {CustomMaterialModule} from "../CustomMaterial/custom-material.module";
 import {FormsModule} from "@angular/forms";
 import {ColorPickerModule} from "ngx-color-picker";
-import {AddVisualizationDialogComponent} from "./dialogs/add-visualization-dialog.component";
+import {AddVisualizationDialogComponent} from "./dialogs/add-widget/add-visualization-dialog.component";
 import {MatGridListModule} from "@angular/material/grid-list";
-import {ShapeService} from "../app-asset-monitoring/services/shape.service";
 import {ElementIconText} from "../services/get-element-icon-text.service";
 import {DashboardService} from "./services/dashboard.service";
 import {ConnectModule} from "../connect/connect.module";
-import {PropertySelectorService} from "../services/property-selector.service";
 import {NumberVizComponent} from "./components/widgets/number/number-viz.component";
 import {streamPipesStompConfig} from "./services/websocket.config";
 import {InjectableRxStompConfig, RxStompService, rxStompServiceFactory} from "@stomp/ng2-stompjs";
-//import { DashboardWidgetsModule } from 'dashboard-widgets';
-//import { FunnelChartComponent, ParliamentChartComponent, PieChartComponent, TimelineComponent } from
-// 'dashboard-widgets';
-
+import {DashboardOverviewComponent} from "./components/overview/dashboard-overview.component";
+import {EditDashboardDialogComponent} from "./dialogs/edit-dashboard/edit-dashboard-dialog.component";
 
 const dashboardWidgets = [
 
@@ -49,9 +45,11 @@ const dashboardWidgets = [
     ],
     declarations: [
         DashboardComponent,
+        DashboardOverviewComponent,
         DashboardPanelComponent,
         DashboardWidgetComponent,
         AddVisualizationDialogComponent,
+        EditDashboardDialogComponent,
         NumberVizComponent
     ],
     providers: [
@@ -77,7 +75,8 @@ const dashboardWidgets = [
     ],
     entryComponents: [
         DashboardComponent,
-        AddVisualizationDialogComponent
+        AddVisualizationDialogComponent,
+        EditDashboardDialogComponent
     ]
 })
 export class DashboardModule {
diff --git a/ui/src/app/dashboard-v2/dialogs/add-visualization-dialog.component.css b/ui/src/app/dashboard-v2/dialogs/add-widget/add-visualization-dialog.component.css
similarity index 100%
copy from ui/src/app/dashboard-v2/dialogs/add-visualization-dialog.component.css
copy to ui/src/app/dashboard-v2/dialogs/add-widget/add-visualization-dialog.component.css
diff --git a/ui/src/app/dashboard-v2/dialogs/add-visualization-dialog.component.html b/ui/src/app/dashboard-v2/dialogs/add-widget/add-visualization-dialog.component.html
similarity index 100%
rename from ui/src/app/dashboard-v2/dialogs/add-visualization-dialog.component.html
rename to ui/src/app/dashboard-v2/dialogs/add-widget/add-visualization-dialog.component.html
diff --git a/ui/src/app/dashboard-v2/dialogs/add-visualization-dialog.component.ts b/ui/src/app/dashboard-v2/dialogs/add-widget/add-visualization-dialog.component.ts
similarity index 69%
rename from ui/src/app/dashboard-v2/dialogs/add-visualization-dialog.component.ts
rename to ui/src/app/dashboard-v2/dialogs/add-widget/add-visualization-dialog.component.ts
index 737d1fc..1ecd4e2 100644
--- a/ui/src/app/dashboard-v2/dialogs/add-visualization-dialog.component.ts
+++ b/ui/src/app/dashboard-v2/dialogs/add-widget/add-visualization-dialog.component.ts
@@ -16,18 +16,19 @@
  *
  */
 
-import {Component, Inject} from "@angular/core";
-import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material";
-import {DashboardService} from "../services/dashboard.service";
-import {ElementIconText} from "../../services/get-element-icon-text.service";
-import {WidgetRegistry} from "../registry/widget-registry";
-import {MappingPropertyUnary} from "../../connect/model/MappingPropertyUnary";
-import {MappingPropertyGenerator} from "../sdk/matching/mapping-property-generator";
-import {EventProperty} from "../../connect/schema-editor/model/EventProperty";
-import {EventSchema} from "../../connect/schema-editor/model/EventSchema";
-import {DashboardWidget} from "../../core-model/dashboard/DashboardWidget";
-import {DashboardWidgetSettings} from "../../core-model/dashboard/DashboardWidgetSettings";
-import {VisualizablePipeline} from "../../core-model/dashboard/VisualizablePipeline";
+import {Component} from "@angular/core";
+import {MatDialogRef} from "@angular/material";
+import {DashboardService} from "../../services/dashboard.service";
+import {ElementIconText} from "../../../services/get-element-icon-text.service";
+import {WidgetRegistry} from "../../registry/widget-registry";
+import {MappingPropertyUnary} from "../../../connect/model/MappingPropertyUnary";
+import {MappingPropertyGenerator} from "../../sdk/matching/mapping-property-generator";
+import {EventProperty} from "../../../connect/schema-editor/model/EventProperty";
+import {EventSchema} from "../../../connect/schema-editor/model/EventSchema";
+import {DashboardWidget} from "../../../core-model/dashboard/DashboardWidget";
+import {DashboardWidgetSettings} from "../../../core-model/dashboard/DashboardWidgetSettings";
+import {VisualizablePipeline} from "../../../core-model/dashboard/VisualizablePipeline";
+import {Dashboard} from "../../models/dashboard.model";
 
 @Component({
     selector: 'add-visualization-dialog-component',
@@ -51,11 +52,13 @@ export class AddVisualizationDialogComponent {
     }];
 
     visualizablePipelines: Array<VisualizablePipeline> = [];
-    availableWidgets:  Array<DashboardWidgetSettings>;
+    availableWidgets: Array<DashboardWidgetSettings>;
 
     selectedPipeline: VisualizablePipeline;
     selectedWidget: DashboardWidgetSettings;
 
+    dashboard: Dashboard;
+
     selectedType: any;
     page: any = "select-pipeline";
 
@@ -69,14 +72,7 @@ export class AddVisualizationDialogComponent {
 
     ngOnInit() {
         this.dashboardService.getVisualizablePipelines().subscribe(visualizations => {
-            visualizations.forEach(vis => {
-                this.visualizablePipelines.push(vis);
-                // this.dashboardService.getPipeline(vis.doc.pipelineId)
-                //     .subscribe(pipeline => {
-                //         vis.doc.name = pipeline.name;
-                //         this.visualizablePipelines.push(vis);
-                //     });
-            });
+            this.visualizablePipelines = visualizations;
         });
         this.availableWidgets = WidgetRegistry.getAvailableWidgets();
     }
@@ -114,10 +110,10 @@ export class AddVisualizationDialogComponent {
     selectWidget(widget) {
         this.selectedWidget = widget;
         this.selectedWidget.config.forEach(sp => {
-           if (sp instanceof MappingPropertyUnary) {
-               let requirement: EventProperty = this.findRequirement(this.selectedWidget.requiredSchema, sp.internalName);
-               sp.mapsFromOptions = new MappingPropertyGenerator(requirement, this.selectedPipeline.schema.eventProperties).computeMatchingProperties();
-           }
+            if (sp instanceof MappingPropertyUnary) {
+                let requirement: EventProperty = this.findRequirement(this.selectedWidget.requiredSchema, sp.internalName);
+                sp.mapsFromOptions = new MappingPropertyGenerator(requirement, this.selectedPipeline.schema.eventProperties).computeMatchingProperties();
+            }
         });
         this.next();
     }
@@ -133,11 +129,11 @@ export class AddVisualizationDialogComponent {
             this.page = 'configure-widget';
         } else {
             let configuredWidget: DashboardWidget = new DashboardWidget();
-            configuredWidget.widgetId = "a";
+            configuredWidget._id = "asd";
             configuredWidget.dashboardWidgetSettings = this.selectedWidget;
             configuredWidget.dashboardWidgetDataConfig = this.selectedPipeline;
             this.dashboardService.saveWidget(configuredWidget).subscribe(response => {
-                this.dialogRef.close();
+                this.dialogRef.close(response);
             });
         }
     }
diff --git a/ui/src/app/dashboard-v2/dialogs/add-visualization-dialog.component.css b/ui/src/app/dashboard-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.css
similarity index 100%
rename from ui/src/app/dashboard-v2/dialogs/add-visualization-dialog.component.css
rename to ui/src/app/dashboard-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.css
diff --git a/ui/src/app/dashboard-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.html b/ui/src/app/dashboard-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.html
new file mode 100644
index 0000000..a1d273e
--- /dev/null
+++ b/ui/src/app/dashboard-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.html
@@ -0,0 +1,54 @@
+<!--
+~ 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.
+~
+-->
+
+<mat-toolbar>
+    <div class="md-toolbar-tools">
+        <h2>{{createMode ? 'New dashboard' : 'Edit dashboard'}}</h2>
+        <span fxFlex></span>
+        <button mat-icon-button (click)="onCancel()">
+            <i class="material-icons">close</i>
+        </button>
+    </div>
+</mat-toolbar>
+<mat-divider></mat-divider>
+<div mat-dialog-content class="md-dialog-content">
+    <div fxFlex="100">
+        <div fxFlex="100" fxLayout="column" style="margin:5px;width:100%">
+            <mat-form-field class="full-width">
+                <mat-label>Dashboard Name</mat-label>
+                <input matInput [(ngModel)]="dashboard.name">
+            </mat-form-field>
+            <mat-form-field class="full-width">
+                <mat-label>Description</mat-label>
+                <input matInput [(ngModel)]="dashboard.description">
+            </mat-form-field>
+
+        </div>
+    </div>
+</div>
+<mat-divider></mat-divider>
+<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
+    <button mat-button mat-raised-button class="mat-basic" (click)="onCancel()">
+        Cancel
+    </button>
+    <button mat-button mat-raised-button color="primary" (click)="onSave()">
+        {{createMode ? 'Create' : 'Save'}}
+    </button>
+</div>
+
+
diff --git a/ui/src/app/dashboard-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts b/ui/src/app/dashboard-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
new file mode 100644
index 0000000..5319491
--- /dev/null
+++ b/ui/src/app/dashboard-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
@@ -0,0 +1,60 @@
+/*
+ * 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} from "@angular/core";
+import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material";
+import {DashboardService} from "../../services/dashboard.service";
+import {DashboardWidgetSettings} from "../../../core-model/dashboard/DashboardWidgetSettings";
+import {VisualizablePipeline} from "../../../core-model/dashboard/VisualizablePipeline";
+import {Dashboard} from "../../models/dashboard.model";
+
+@Component({
+    selector: 'edit-dashboard-dialog-component',
+    templateUrl: './edit-dashboard-dialog.component.html',
+    styleUrls: ['./edit-dashboard-dialog.component.css']
+})
+export class EditDashboardDialogComponent {
+
+    createMode: boolean;
+    dashboard: Dashboard;
+
+    constructor(
+        public dialogRef: MatDialogRef<EditDashboardDialogComponent>,
+        private dashboardService: DashboardService) {
+    }
+
+    ngOnInit() {
+
+    }
+
+    onCancel(): void {
+        this.dialogRef.close();
+    }
+
+    onSave(): void {
+        if (this.createMode) {
+            this.dashboardService.saveDashboard(this.dashboard).subscribe();
+        } else {
+            this.dashboardService.updateDashboard(this.dashboard).subscribe();
+        }
+        this.dialogRef.close();
+    }
+
+
+
+}
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/models/dashboard.model.ts b/ui/src/app/dashboard-v2/models/dashboard.model.ts
index 587ff4e..37ba299 100644
--- a/ui/src/app/dashboard-v2/models/dashboard.model.ts
+++ b/ui/src/app/dashboard-v2/models/dashboard.model.ts
@@ -1,7 +1,4 @@
 import {GridsterConfig, GridsterItem} from "angular-gridster2";
-import {StaticProperty} from "../../connect/model/StaticProperty";
-import {WidgetData} from "./widget-data.model";
-import {VisualizablePipeline} from "../../core-model/dashboard/VisualizablePipeline";
 
 export interface DashboardConfig extends GridsterConfig {}
 
@@ -12,5 +9,8 @@ export interface DashboardItem extends GridsterItem {
 export interface Dashboard {
     id?: string;
     name?: string;
+    description?: string;
     widgets?: Array<DashboardItem>;
+    _id?: string;
+    _rev?: string;
 }
\ No newline at end of file
diff --git a/ui/src/app/dashboard-v2/services/dashboard.service.ts b/ui/src/app/dashboard-v2/services/dashboard.service.ts
index 1f1b78d..da0849e 100644
--- a/ui/src/app/dashboard-v2/services/dashboard.service.ts
+++ b/ui/src/app/dashboard-v2/services/dashboard.service.ts
@@ -48,27 +48,22 @@ export class DashboardService {
             });
     }
 
-    deserializeSchema(schema: any): EventSchema {
-        let eventSchema: EventSchema = new EventSchema();
-        let eventProperties = new Array<EventProperty>();
-
-        schema.eventProperties.forEach(ep => {
-           eventProperties.push(this.makeProperty(ep));
+    getDashboards(): Observable<Array<Dashboard>> {
+        return this.http.get(this.dashboardUrl).map(data => {
+           return data as Dashboard[];
         });
+    }
 
-        eventSchema.eventProperties = eventProperties;
-        return eventSchema;
+    updateDashboard(dashboard: Dashboard): Observable<any> {
+        return this.http.put(this.dashboardUrl + "/" +dashboard._id, dashboard);
     }
 
-    makeProperty(ep: any): EventProperty {
-        // TODO find a better way to deserialize the schema
-        if (ep.type === "org.apache.streampipes.model.schema.EventPropertyPrimitive") {
-            return Object.assign(new EventPropertyPrimitive(), ep.properties);
-        }
+    deleteDashboard(dashboard: Dashboard): Observable<any> {
+        return this.http.delete(this.dashboardUrl + "/" +dashboard._id);
     }
 
-    getPipeline(pipelineId): Observable<any> {
-        return this.http.get('/pipeline/' + pipelineId);
+    saveDashboard(dashboard: Dashboard): Observable<any> {
+        return this.http.post(this.dashboardUrl, dashboard);
     }
 
     private get baseUrl() {
@@ -97,16 +92,12 @@ export class DashboardService {
         return from(promise);
     }
 
-    saveWidget(widget: DashboardWidget): Observable<StatusMessage> {
+    saveWidget(widget: DashboardWidget): Observable<DashboardWidget> {
         return this.serializeAndPost(this.dashboardWidgetUrl, widget);
     }
 
-    saveDashboard(dashboard: Dashboard) {
-        this.http.post('/dashboard', dashboard);
-    }
-
-    serializeAndPost(url: string, object: any): Observable<StatusMessage> {
-        let promise = new Promise<StatusMessage>((resolve, reject) => {
+    serializeAndPost(url: string, object: any): Observable<DashboardWidget> {
+        let promise = new Promise<DashboardWidget>((resolve, reject) => {
             this.tsonLdSerializerService.toJsonLd(object).subscribe(serialized => {
                 const httpOptions = {
                     headers: new HttpHeaders({
@@ -114,7 +105,7 @@ export class DashboardService {
                     }),
                 };
                 this.http.post(url, serialized, httpOptions).pipe(map(response => {
-                    resolve(response as StatusMessage);
+                    resolve(this.tsonLdSerializerService.fromJsonLd(response, "sp:DashboardWidgetModel"));
                 })).subscribe();
             });
         });
diff --git a/ui/src/assets/dashboards.json b/ui/src/assets/dashboards.json
index 5ee2728..dc722b5 100644
--- a/ui/src/assets/dashboards.json
+++ b/ui/src/assets/dashboards.json
@@ -22,7 +22,7 @@
     "name": "Sample Dashboard 5",
     "widgets": [
       {
-        "id": "1",
+        "id": "9efc42508b0348a78304a84bbfda3363",
         "name": "Timeline",
         "component": "timeline",
         "widgetType": "number",