You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ze...@apache.org on 2020/02/20 11:33:18 UTC

[incubator-streampipes] 02/02: Copied dashboard as template for new data explorer

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

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

commit 4862b73650982481c0fb47e5145f288344566c12
Author: Philipp Zehnder <ze...@fzi.de>
AuthorDate: Thu Feb 20 12:32:31 2020 +0100

    Copied dashboard as template for new data explorer
---
 ui/deployment/dev/config.yml                       |   3 +-
 ui/deployment/modules.yml                          |  15 ++
 .../components/grid/dashboard-grid.component.css   |  25 +++
 .../components/grid/dashboard-grid.component.html  |  32 ++++
 .../components/grid/dashboard-grid.component.ts    |  98 ++++++++++++
 .../overview/dashboard-overview.component.css      |  25 +++
 .../overview/dashboard-overview.component.html     |  98 ++++++++++++
 .../overview/dashboard-overview.component.ts       |  89 +++++++++++
 .../components/panel/dashboard-panel.component.css |  25 +++
 .../panel/dashboard-panel.component.html           |  35 +++++
 .../components/panel/dashboard-panel.component.ts  | 128 ++++++++++++++++
 .../widget/dashboard-widget.component.css          |  53 +++++++
 .../widget/dashboard-widget.component.html         |  65 ++++++++
 .../widget/dashboard-widget.component.ts           |  81 ++++++++++
 .../components/widgets/area/area-config.ts         |  32 ++++
 .../widgets/area/area-widget.component.css         |  24 +++
 .../widgets/area/area-widget.component.html        |  41 +++++
 .../widgets/area/area-widget.component.ts          |  43 ++++++
 .../components/widgets/base/base-config.ts         |  24 +++
 .../widgets/base/base-ngx-charts-widget.ts         |  74 +++++++++
 .../widgets/base/base-ngx-line-charts-widget.ts    |  74 +++++++++
 .../widgets/base/base-ngx-line-config.ts           |  47 ++++++
 .../components/widgets/base/base-widget.ts         |  96 ++++++++++++
 .../components/widgets/gauge/gauge-config.ts       |  48 ++++++
 .../widgets/gauge/gauge-widget.component.css       |  32 ++++
 .../widgets/gauge/gauge-widget.component.html      |  36 +++++
 .../widgets/gauge/gauge-widget.component.ts        |  67 ++++++++
 .../components/widgets/image/image-config.ts       |  44 ++++++
 .../widgets/image/image-widget.component.css       |  31 ++++
 .../widgets/image/image-widget.component.html      |  26 ++++
 .../widgets/image/image-widget.component.ts        |  62 ++++++++
 .../components/widgets/line/line-config.ts         |  30 ++++
 .../widgets/line/line-widget.component.css         |  32 ++++
 .../widgets/line/line-widget.component.html        |  41 +++++
 .../widgets/line/line-widget.component.ts          |  46 ++++++
 .../components/widgets/number/number-config.ts     |  42 +++++
 .../widgets/number/number-widget.component.css     |  36 +++++
 .../widgets/number/number-widget.component.html    |  27 ++++
 .../widgets/number/number-widget.component.ts      |  60 ++++++++
 .../components/widgets/table/table-config.ts       |  44 ++++++
 .../widgets/table/table-widget.component.css       |  26 ++++
 .../widgets/table/table-widget.component.html      |  36 +++++
 .../widgets/table/table-widget.component.ts        |  77 ++++++++++
 .../data-explorer-v2.component.css                 |  21 +++
 .../data-explorer-v2.component.html                |  51 +++++++
 .../data-explorer-v2/data-explorer-v2.component.ts |  83 ++++++++++
 .../data-explorer-v2/data-explorer-v2.module.ts    | 126 +++++++++++++++
 .../add-visualization-dialog.component.css         |  55 +++++++
 .../add-visualization-dialog.component.html        |  95 ++++++++++++
 .../add-visualization-dialog.component.ts          | 169 +++++++++++++++++++++
 .../edit-dashboard-dialog.component.css            |  55 +++++++
 .../edit-dashboard-dialog.component.html           |  55 +++++++
 .../edit-dashboard-dialog.component.ts             |  60 ++++++++
 .../app/data-explorer-v2/models/dashboard.model.ts |  36 +++++
 .../data-explorer-v2/models/gridster-info.model.ts |  24 +++
 .../data-explorer-v2/models/multi-series.model.ts  |  29 ++++
 .../registry/widget-config-builder.ts              | 121 +++++++++++++++
 .../data-explorer-v2/registry/widget-registry.ts   |  44 ++++++
 .../sdk/collected-schema-requirements.ts           |  38 +++++
 ui/src/app/data-explorer-v2/sdk/ep-requirements.ts |  68 +++++++++
 .../sdk/extractor/static-property-extractor.ts     |  78 ++++++++++
 .../sdk/matching/datatype-match.ts                 |  44 ++++++
 .../sdk/matching/domain-property-match.ts          |  28 ++++
 .../sdk/matching/mapping-property-generator.ts     |  46 ++++++
 .../sdk/matching/primitive-property-match.ts       |  33 ++++
 .../sdk/matching/property-match.ts                 |  32 ++++
 ui/src/app/data-explorer-v2/sdk/model/datatypes.ts |  40 +++++
 .../app/data-explorer-v2/sdk/model/vocabulary.ts   |  23 +++
 .../sdk/schema-requirements-builder.ts             |  69 +++++++++
 .../data-explorer-v2/services/dashboard.service.ts | 137 +++++++++++++++++
 .../services/refresh-dashboard.service.ts          |  30 ++++
 .../data-explorer-v2/services/resize.service.ts    |  31 ++++
 .../data-explorer-v2/services/websocket.config.ts  |  36 +++++
 .../services/websocket.settings.ts                 |  32 ++++
 74 files changed, 3858 insertions(+), 1 deletion(-)

diff --git a/ui/deployment/dev/config.yml b/ui/deployment/dev/config.yml
index 0424e05..789ce73 100644
--- a/ui/deployment/dev/config.yml
+++ b/ui/deployment/dev/config.yml
@@ -27,4 +27,5 @@ modules:
   - spMyElements
   - spDataExplorer
   - spConfiguration
-  - spDashboard2
\ No newline at end of file
+  - spDashboard2
+  - spDataExplorer2
diff --git a/ui/deployment/modules.yml b/ui/deployment/modules.yml
index 62432db..1285959 100644
--- a/ui/deployment/modules.yml
+++ b/ui/deployment/modules.yml
@@ -169,4 +169,19 @@ spDashboard2:
   description: 'dashboard-v2'
   icon: 'navigation:ic_apps_24px'
   homeImage: '/assets/img/home/configuration.png'
+  admin: false
+spDataExplorer2:
+  ng5: True
+  ng1_templateUrl: ''
+  ng1_controller: ''
+  ng5_moduleName: 'DataExplorerV2Module'
+  ng5_component: 'DataExplorerV2Component'
+  ng5_componentPath: '../data-explorer-v2/data-explorer-v2.component'
+  path: './data-explorer-v2/data-explorer-v2.module'
+  link: 'streampipes.dataexplorerv2'
+  url: '/dataexplorerv2'
+  title: 'Data Explorer'
+  description: 'data-explorer-v2'
+  icon: 'navigation:ic_apps_24px'
+  homeImage: '/assets/img/home/configuration.png'
   admin: false
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/grid/dashboard-grid.component.css b/ui/src/app/data-explorer-v2/components/grid/dashboard-grid.component.css
new file mode 100644
index 0000000..6368cea
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/grid/dashboard-grid.component.css
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ *
+ */
+
+gridster ::ng-deep {
+    background: white;
+}
+
+gridster.edit ::ng-deep {
+    background: #d3d3d3;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/grid/dashboard-grid.component.html b/ui/src/app/data-explorer-v2/components/grid/dashboard-grid.component.html
new file mode 100644
index 0000000..62c4cc5
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/grid/dashboard-grid.component.html
@@ -0,0 +1,32 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div *ngIf="dashboard.displayHeader" class="text-center">
+    <h2>{{dashboard.name}}</h2>
+    <h3>{{dashboard.description}}</h3>
+</div>
+<gridster [options]="options" [ngClass]="editMode ? 'edit' : ''">
+    <ng-container *ngFor="let item of dashboard.widgets;let i=index">
+        <gridster-item [item]="item" #gridsterItemComponent>
+            <dashboard-widget (updateCallback)="propagateItemUpdate($event)"
+                              (deleteCallback)="propagateItemRemoval($event)"
+                              [item]="item" [widget]="item"
+            [editMode]="editMode" [gridsterItemComponent]="gridsterItemComponent"></dashboard-widget>
+        </gridster-item>
+    </ng-container>
+</gridster>
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/grid/dashboard-grid.component.ts b/ui/src/app/data-explorer-v2/components/grid/dashboard-grid.component.ts
new file mode 100644
index 0000000..fc17584
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/grid/dashboard-grid.component.ts
@@ -0,0 +1,98 @@
+/*
+ * 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 {
+    AfterViewInit,
+    Component, EventEmitter,
+    Input,
+    OnChanges,
+    OnInit, Output,
+    QueryList,
+    SimpleChanges,
+    ViewChildren
+} from "@angular/core";
+import {Dashboard, DashboardConfig, DashboardItem} from "../../models/dashboard.model";
+import {GridsterInfo} from "../../models/gridster-info.model";
+import {ResizeService} from "../../services/resize.service";
+import {GridsterItemComponent, GridType} from "angular-gridster2";
+import {DashboardService} from "../../services/dashboard.service";
+import {RefreshDashboardService} from "../../services/refresh-dashboard.service";
+import {DashboardWidget} from "../../../core-model/dashboard/DashboardWidget";
+
+@Component({
+    selector: 'dashboard-grid',
+    templateUrl: './dashboard-grid.component.html',
+    styleUrls: ['./dashboard-grid.component.css']
+})
+export class DashboardGridComponent implements OnInit, OnChanges {
+
+    @Input() editMode: boolean;
+    @Input() dashboard: Dashboard;
+
+    @Output() deleteCallback: EventEmitter<DashboardItem> = new EventEmitter<DashboardItem>();
+    @Output() updateCallback: EventEmitter<DashboardWidget> = new EventEmitter<DashboardWidget>();
+
+    options: DashboardConfig;
+    loaded: boolean = false;
+
+    @ViewChildren(GridsterItemComponent) gridsterItemComponents: QueryList<GridsterItemComponent>;
+
+    constructor(private resizeService: ResizeService,
+                private dashboardService: DashboardService,
+                private refreshDashboardService: RefreshDashboardService) {
+
+    }
+
+    ngOnInit(): void {
+        this.options = {
+            disablePushOnDrag: true,
+            draggable: { enabled: this.editMode },
+            gridType: GridType.VerticalFixed,
+            minCols: 8,
+            maxCols: 8,
+            minRows: 4,
+            fixedRowHeight: 100,
+            fixedColWidth: 100,
+            resizable: { enabled: this.editMode },
+            itemResizeCallback: ((item, itemComponent) => {
+                this.resizeService.notify({gridsterItem: item, gridsterItemComponent: itemComponent} as GridsterInfo);
+            }),
+            itemInitCallback: ((item, itemComponent) => {
+                this.resizeService.notify({gridsterItem: item, gridsterItemComponent: itemComponent} as GridsterInfo);
+            })
+        };
+    }
+
+    ngOnChanges(changes: SimpleChanges): void {
+        if (changes["editMode"] && this.options) {
+            this.options.draggable.enabled = this.editMode;
+            this.options.resizable.enabled = this.editMode;
+            this.options.displayGrid = this.editMode ? 'always' : 'none';
+            this.options.api.optionsChanged();
+        }
+    }
+
+    propagateItemRemoval(widget: DashboardItem) {
+        this.deleteCallback.emit(widget);
+    }
+
+    propagateItemUpdate(dashboardWidget: DashboardWidget) {
+        this.updateCallback.emit(dashboardWidget);
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/overview/dashboard-overview.component.css b/ui/src/app/data-explorer-v2/components/overview/dashboard-overview.component.css
new file mode 100644
index 0000000..dc9cc49
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/overview/dashboard-overview.component.css
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ *
+ */
+
+table {
+    width:100%;
+}
+
+.m-20 {
+    margin: 20px;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/overview/dashboard-overview.component.html b/ui/src/app/data-explorer-v2/components/overview/dashboard-overview.component.html
new file mode 100644
index 0000000..86a80f4
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/overview/dashboard-overview.component.html
@@ -0,0 +1,98 @@
+<!--
+  ~ 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="60" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Dashboard</th>
+                    <td fxFlex="60" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
+                        {{element.name}}<br/>
+                        {{element.description}}
+                    </td>
+                </ng-container>
+
+                <ng-container matColumnDef="open">
+                    <th fxFlex="10" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Show</th>
+                    <td fxFlex="10" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
+                        <div fxLayout="row">
+                            <button mat-button mat-icon-button color="primary"
+                                    (click)="showDashboard(element)">
+                                <i class="material-icons">visibility</i>
+                            </button>
+                        </div>
+                    </td>
+                </ng-container>
+
+                <ng-container matColumnDef="openWindow">
+                    <th fxFlex="10" fxLayoutAlign="start center" mat-header-cell *matHeaderCellDef> Window</th>
+                    <td fxFlex="10" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
+                        <div fxLayout="row">
+                            <button mat-button mat-icon-button color="primary"
+                                    (click)="openExternalDashboard(element)">
+                                <i class="material-icons">open_in_new</i>
+                            </button>
+                        </div>
+                    </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/data-explorer-v2/components/overview/dashboard-overview.component.ts b/ui/src/app/data-explorer-v2/components/overview/dashboard-overview.component.ts
new file mode 100644
index 0000000..e18af21
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/overview/dashboard-overview.component.ts
@@ -0,0 +1,89 @@
+/*
+ * 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, 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<void>();
+    @Output() selectDashboardEmitter = new EventEmitter<Dashboard>();
+
+    dataSource = new MatTableDataSource<Dashboard>();
+    displayedColumns: string[] = ['name', 'open', 'openWindow', '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();
+        });
+    }
+
+    openEditDashboardDialog(dashboard: Dashboard) {
+        this.openDashboardModificationDialog(false, dashboard);
+    }
+
+    openDeleteDashboardDialog(dashboard: Dashboard) {
+        // TODO add confirm dialog
+        this.dashboardService.deleteDashboard(dashboard).subscribe(result => {
+            this.reloadDashboardsEmitter.emit();
+        });
+    }
+
+    showDashboard(dashboard: Dashboard) {
+        this.selectDashboardEmitter.emit(dashboard);
+    }
+
+    openExternalDashboard(dashboard: Dashboard) {
+
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/panel/dashboard-panel.component.css b/ui/src/app/data-explorer-v2/components/panel/dashboard-panel.component.css
new file mode 100644
index 0000000..1faa4d1
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/panel/dashboard-panel.component.css
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ *
+ */
+
+.m-20 {
+    margin: 20px;
+}
+
+.h-100 {
+    height:100%;
+}
diff --git a/ui/src/app/data-explorer-v2/components/panel/dashboard-panel.component.html b/ui/src/app/data-explorer-v2/components/panel/dashboard-panel.component.html
new file mode 100644
index 0000000..682418b
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/panel/dashboard-panel.component.html
@@ -0,0 +1,35 @@
+<!--
+  ~ 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" style="margin-bottom:20px;" *ngIf="editMode">
+        <button mat-button mat-raised-button color="primary" (click)="updateDashboardAndCloseEditMode()"
+                style="margin-right:10px;">Save
+        </button>
+        <button mat-button mat-raised-button class="mat-basic" (click)="discardChanges()"
+                style="margin-right:10px;">Discard
+        </button>
+        <button mat-button mat-raised-button color="primary" (click)="addWidget()" [disabled]="!editMode">Add
+            visualization</button>
+    </div>
+
+    <dashboard-grid [editMode]="editMode" [dashboard]="dashboard"
+                    (updateCallback)="updateAndQueueItemForDeletion($event)"
+                    (deleteCallback)="removeAndQueueItemForDeletion($event)"
+                    class="h-100"></dashboard-grid>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/panel/dashboard-panel.component.ts b/ui/src/app/data-explorer-v2/components/panel/dashboard-panel.component.ts
new file mode 100644
index 0000000..8b4895f
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/panel/dashboard-panel.component.ts
@@ -0,0 +1,128 @@
+/*
+ * 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, EventEmitter, Input, OnInit, Output} from "@angular/core";
+import {Dashboard, DashboardItem} from "../../models/dashboard.model";
+import {forkJoin, Observable, Subscription} from "rxjs";
+import {MatDialog} from "@angular/material/dialog";
+import {AddVisualizationDialogComponent} from "../../dialogs/add-widget/add-visualization-dialog.component";
+import {DashboardWidget} from "../../../core-model/dashboard/DashboardWidget";
+import {DashboardService} from "../../services/dashboard.service";
+import {RefreshDashboardService} from "../../services/refresh-dashboard.service";
+
+@Component({
+    selector: 'dashboard-panel',
+    templateUrl: './dashboard-panel.component.html',
+    styleUrls: ['./dashboard-panel.component.css']
+})
+export class DashboardPanelComponent implements OnInit {
+
+    @Input() dashboard: Dashboard;
+    @Input("editMode") editMode: boolean;
+    @Output("editModeChange") editModeChange: EventEmitter<boolean> = new EventEmitter();
+
+    public items: DashboardItem[];
+
+    protected subscription: Subscription;
+
+    widgetIdsToRemove: Array<string> = [];
+    widgetsToUpdate: Map<string, DashboardWidget> = new Map<string, DashboardWidget>();
+
+    constructor(private dashboardService: DashboardService,
+                public dialog: MatDialog,
+                private refreshDashboardService: RefreshDashboardService) {
+    }
+
+    public ngOnInit() {
+
+    }
+
+    addWidget(): void {
+        const dialogRef = this.dialog.open(AddVisualizationDialogComponent, {
+            width: '70%',
+            height: '500px',
+            panelClass: 'custom-dialog-container'
+        });
+
+        dialogRef.afterClosed().subscribe(widget => {
+            if (widget) {
+                this.addWidgetToDashboard(widget);
+            }
+        });
+    }
+
+    addWidgetToDashboard(widget: DashboardWidget) {
+        let dashboardItem = {} as DashboardItem;
+        dashboardItem.widgetId = widget._id;
+        dashboardItem.id = widget._id;
+        // TODO there should be a widget type DashboardWidget
+        dashboardItem.widgetType = widget.dashboardWidgetSettings.widgetName;
+        dashboardItem.cols = 2;
+        dashboardItem.rows = 2;
+        dashboardItem.x = 0;
+        dashboardItem.y = 0;
+        this.dashboard.widgets.push(dashboardItem);
+    }
+
+    updateDashboardAndCloseEditMode() {
+        this.dashboardService.updateDashboard(this.dashboard).subscribe(result => {
+            if (this.widgetsToUpdate.size > 0) {
+                forkJoin(this.prepareWidgetUpdates()).subscribe(result => {
+                    this.closeEditModeAndReloadDashboard();
+                });
+            } else {
+                this.deleteWidgets();
+                this.closeEditModeAndReloadDashboard()
+            }
+        })
+    }
+
+    closeEditModeAndReloadDashboard() {
+        this.editModeChange.emit(!(this.editMode));
+        this.refreshDashboardService.notify(this.dashboard._id);
+    }
+
+    prepareWidgetUpdates(): Array<Observable<any>> {
+        let promises: Array<Observable<any>> = [];
+        this.widgetsToUpdate.forEach((widget, key) => {
+            promises.push(this.dashboardService.updateWidget(widget));
+        })
+
+        return promises;
+    }
+
+    discardChanges() {
+        this.editModeChange.emit(!(this.editMode));
+        this.refreshDashboardService.notify(this.dashboard._id);
+    }
+
+    removeAndQueueItemForDeletion(widget: DashboardItem) {
+        this.dashboard.widgets.splice(this.dashboard.widgets.indexOf(widget), 1);
+        this.widgetIdsToRemove.push(widget.id);
+    }
+
+    updateAndQueueItemForDeletion(dashboardWidget: DashboardWidget) {
+        this.widgetsToUpdate.set(dashboardWidget._id, dashboardWidget);
+    }
+
+    deleteWidgets() {
+        this.widgetIdsToRemove.forEach(widgetId => {
+            this.dashboardService.deleteWidget(widgetId).subscribe();
+        });
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widget/dashboard-widget.component.css b/ui/src/app/data-explorer-v2/components/widget/dashboard-widget.component.css
new file mode 100644
index 0000000..dea206d
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widget/dashboard-widget.component.css
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ */
+
+.h-100 {
+    height:100%;
+}
+
+.h-40 {
+    height:40px;
+}
+
+.p-0 {
+    padding:0;
+}
+
+.p-20 {
+    padding: 20px;
+}
+
+.m-0 {
+    margin:0;
+}
+
+.box {
+    display: flex;
+    flex-flow: column;
+    height: 100%;
+    border:0px solid black;
+}
+
+.box .row.content {
+    flex: 1 1 auto;
+}
+
+.box .row.header {
+    flex: 0 1 auto;
+}
+
diff --git a/ui/src/app/data-explorer-v2/components/widget/dashboard-widget.component.html b/ui/src/app/data-explorer-v2/components/widget/dashboard-widget.component.html
new file mode 100644
index 0000000..98851a7
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widget/dashboard-widget.component.html
@@ -0,0 +1,65 @@
+<!--
+  ~ 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 style="height:100%;">
+    <div class="box">
+        <div class="assemblyOptions sp-blue-bg m-0 row header h-40" *ngIf="editMode">
+            <div fxFlex="100" layout="row" fxLayoutAlign="end center">
+                <button mat-button mat-icon-button color="white" (click)="editWidget()">
+                    <i class="material-icons">settings</i>
+                </button>
+                <button mat-button mat-icon-button color="white" (click)="removeWidget()">
+                    <i class="material-icons">clear</i>
+                </button>
+            </div>
+        </div>
+        <div class="h-100 p-0 row content">
+            <!--        <div *ngIf="widget."></div>-->
+            <div *ngIf="widgetLoaded" class="h-100">
+                <div *ngIf="widget.widgetType === 'number'" class="h-100 p-0">
+                    <number-widget [gridsterItemComponent]="gridsterItemComponent" [gridsterItem]="item"
+                                   [widget]="widget" [editMode]="editMode"
+                                   [widgetConfig]="configuredWidget" class="h-100"></number-widget>
+                </div>
+                <div *ngIf="widget.widgetType === 'line'" class="h-100 p-0">
+                    <line-widget [gridsterItemComponent]="gridsterItemComponent" [editMode]="editMode"
+                                 [gridsterItem]="item" [widget]="widget" [widgetConfig]="configuredWidget" class="h-100"></line-widget>
+                </div>
+                <div *ngIf="widget.widgetType === 'area'" class="h-100 p-0">
+                    <area-widget [gridsterItemComponent]="gridsterItemComponent" [editMode]="editMode"
+                                 [gridsterItem]="item" [widget]="widget" [widgetConfig]="configuredWidget" class="h-100"></area-widget>
+                </div>
+                <div *ngIf="widget.widgetType === 'table'" class="h-100 p-0">
+                    <table-widget [gridsterItemComponent]="gridsterItemComponent"
+                                  [gridsterItem]="item" [widget]="widget" [editMode]="editMode"
+                                  [widgetConfig]="configuredWidget" class="h-100"></table-widget>
+                </div>
+                <div *ngIf="widget.widgetType === 'gauge'" class="h-100 p-0">
+                    <gauge-widget [gridsterItemComponent]="gridsterItemComponent"
+                                  [gridsterItem]="item" [widget]="widget" [editMode]="editMode"
+                                  [widgetConfig]="configuredWidget" class="h-100"></gauge-widget>
+                </div>
+                <div *ngIf="widget.widgetType === 'image'" class="h-100 p-0">
+                    <image-widget [gridsterItemComponent]="gridsterItemComponent"
+                                  [gridsterItem]="item" [widget]="widget" [editMode]="editMode"
+                                  [widgetConfig]="configuredWidget" class="h-100"></image-widget>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widget/dashboard-widget.component.ts b/ui/src/app/data-explorer-v2/components/widget/dashboard-widget.component.ts
new file mode 100644
index 0000000..60a480a
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widget/dashboard-widget.component.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 {AfterViewInit, Component, ElementRef, EventEmitter, Input, OnInit, Output} from "@angular/core";
+import {Dashboard, DashboardItem} from "../../models/dashboard.model";
+import {DashboardService} from "../../services/dashboard.service";
+import {DashboardImageComponent} from "../../../app-transport-monitoring/components/dashboard-image/dashboard-image.component";
+import {DashboardWidget} from "../../../core-model/dashboard/DashboardWidget";
+import {Subject} from "rxjs";
+import {GridsterItem, GridsterItemComponent} from "angular-gridster2";
+import {GridsterInfo} from "../../models/gridster-info.model";
+import {ResizeService} from "../../services/resize.service";
+import {AddVisualizationDialogComponent} from "../../dialogs/add-widget/add-visualization-dialog.component";
+import {MatDialog} from "@angular/material/dialog";
+
+@Component({
+    selector: 'dashboard-widget',
+    templateUrl: './dashboard-widget.component.html',
+    styleUrls: ['./dashboard-widget.component.css']
+})
+export class DashboardWidgetComponent implements OnInit {
+
+    @Input() widget: DashboardItem;
+    @Input() editMode: boolean;
+    @Input() item: GridsterItem;
+    @Input() gridsterItemComponent: GridsterItemComponent;
+
+    @Output() deleteCallback: EventEmitter<DashboardItem> = new EventEmitter<DashboardItem>();
+    @Output() updateCallback: EventEmitter<DashboardWidget> = new EventEmitter<DashboardWidget>();
+
+    widgetLoaded: boolean = false;
+    configuredWidget: DashboardWidget;
+
+    constructor(private dashboardService: DashboardService,
+                private dialog: MatDialog) {
+    }
+
+    ngOnInit(): void {
+        this.dashboardService.getWidget(this.widget.id).subscribe(response => {
+            this.configuredWidget = response;
+            this.widgetLoaded = true;
+        });
+    }
+
+    removeWidget() {
+        this.deleteCallback.emit(this.widget);
+    }
+
+    editWidget(): void {
+        const dialogRef = this.dialog.open(AddVisualizationDialogComponent, {
+            width: '70%',
+            height: '500px',
+            panelClass: 'custom-dialog-container',
+            data: {
+                "widget": this.configuredWidget
+            }
+        });
+
+        dialogRef.afterClosed().subscribe(widget => {
+            if (widget) {
+                this.configuredWidget = widget;
+                this.updateCallback.emit(this.configuredWidget);
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/area/area-config.ts b/ui/src/app/data-explorer-v2/components/widgets/area/area-config.ts
new file mode 100644
index 0000000..23d01a7
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/area/area-config.ts
@@ -0,0 +1,32 @@
+/*
+ * 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 {BaseNgxLineConfig} from "../base/base-ngx-line-config";
+
+export class AreaConfig extends BaseNgxLineConfig {
+
+    getWidgetLabel(): string {
+        return "area";
+    }
+
+    getWidgetName(): string {
+        return "area";
+    }
+
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/area/area-widget.component.css b/ui/src/app/data-explorer-v2/components/widgets/area/area-widget.component.css
new file mode 100644
index 0000000..4215dfd
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/area/area-widget.component.css
@@ -0,0 +1,24 @@
+/*
+ *   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.
+ */
+
+.title-panel {
+    font-size:20px;
+}
+
+.mt-20 {
+    margin-top:20px;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/area/area-widget.component.html b/ui/src/app/data-explorer-v2/components/widgets/area/area-widget.component.html
new file mode 100644
index 0000000..9f9bbeb
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/area/area-widget.component.html
@@ -0,0 +1,41 @@
+<!--
+  ~ 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" fxLayoutAlign="center center" fxLayout="column" class="main-panel" [ngStyle]="{'background-color': selectedBackgroundColor, 'color': selectedPrimaryTextColor}">
+    <div class="title-panel mt-20" *ngIf="hasTitlePanelSettings">
+        {{selectedTitle}}
+    </div>
+    <ngx-charts-area-chart *ngIf="displayChart"
+                           [showXAxisLabel]="false"
+                           [showYAxisLabel]="false"
+                           [scheme]="colorScheme"
+                           [timeline]="false"
+                           [view]="view"
+                           [autoScale]="false"
+                           [xAxis]="true"
+                           [yAxis]="true"
+                           [yScaleMin]="minYAxisRange"
+                           [yScaleMax]="maxYAxisRange"
+                           [tooltipDisabled]="true"
+                           [animations]="false"
+                           [xAxisTickFormatting]="timestampTickFormatting"
+                           [results]="multi" style="margin-top:10px;margin-bottom:10px;"
+                           [ngStyle]="{'fill': selectedPrimaryTextColor}">
+    </ngx-charts-area-chart>
+</div>
+
diff --git a/ui/src/app/data-explorer-v2/components/widgets/area/area-widget.component.ts b/ui/src/app/data-explorer-v2/components/widgets/area/area-widget.component.ts
new file mode 100644
index 0000000..aaa6db0
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/area/area-widget.component.ts
@@ -0,0 +1,43 @@
+/*
+ * 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, OnDestroy, OnInit} from "@angular/core";
+import {BaseNgxLineChartsStreamPipesWidget} from "../base/base-ngx-line-charts-widget";
+import {RxStompService} from "@stomp/ng2-stompjs";
+import {ResizeService} from "../../../services/resize.service";
+
+@Component({
+    selector: 'area-widget',
+    templateUrl: './area-widget.component.html',
+    styleUrls: ['./area-widget.component.css']
+})
+export class AreaWidgetComponent extends BaseNgxLineChartsStreamPipesWidget implements OnInit, OnDestroy {
+
+    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
+        super(rxStompService, resizeService);
+    }
+
+    ngOnInit(): void {
+        super.ngOnInit();
+    }
+
+    ngOnDestroy(): void {
+        super.ngOnDestroy();
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/base/base-config.ts b/ui/src/app/data-explorer-v2/components/widgets/base/base-config.ts
new file mode 100644
index 0000000..fc221cb
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/base/base-config.ts
@@ -0,0 +1,24 @@
+/*
+ * 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 {DashboardWidgetSettings} from "../../../../core-model/dashboard/DashboardWidgetSettings";
+
+export abstract class WidgetConfig {
+
+    abstract getConfig(): DashboardWidgetSettings;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/base/base-ngx-charts-widget.ts b/ui/src/app/data-explorer-v2/components/widgets/base/base-ngx-charts-widget.ts
new file mode 100644
index 0000000..619bd3d
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/base/base-ngx-charts-widget.ts
@@ -0,0 +1,74 @@
+/*
+ * 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 {BaseStreamPipesWidget} from "./base-widget";
+import {RxStompService} from "@stomp/ng2-stompjs";
+import {ResizeService} from "../../../services/resize.service";
+import {GridsterInfo} from "../../../models/gridster-info.model";
+import {GridsterItemComponent} from "angular-gridster2";
+
+export abstract class BaseNgxChartsStreamPipesWidget extends BaseStreamPipesWidget {
+
+    view: any[] = [];
+    displayChart: boolean = false;
+
+    colorScheme: any;
+
+    constructor(rxStompService: RxStompService, protected resizeService: ResizeService) {
+        super(rxStompService);
+    }
+
+    ngOnInit() {
+        super.ngOnInit();
+        this.colorScheme = {domain: [this.selectedSecondaryTextColor, this.selectedPrimaryTextColor]};
+        this.view = [this.computeCurrentWidth(this.gridsterItemComponent),
+            this.computeCurrentHeight(this.gridsterItemComponent)];
+        this.displayChart = true;
+        this.resizeService.resizeSubject.subscribe(info => {
+            this.onResize(info);
+        });
+    }
+
+    onResize(info: GridsterInfo) {
+        if (info.gridsterItem.id === this.gridsterItem.id) {
+            setTimeout(() => {
+                this.displayChart = false;
+                this.view = [this.computeCurrentWidth(info.gridsterItemComponent),
+                    this.computeCurrentHeight(info.gridsterItemComponent)];
+                this.displayChart = true;
+            }, 100);
+        }
+    }
+
+    computeCurrentWidth(gridsterItemComponent: GridsterItemComponent): number {
+        return (gridsterItemComponent.width - (BaseNgxChartsStreamPipesWidget.PADDING * 2));
+    }
+
+    computeCurrentHeight(gridsterItemComponent: GridsterItemComponent): number {
+        return (gridsterItemComponent.height - (BaseNgxChartsStreamPipesWidget.PADDING * 2) - this.editModeOffset() - this.titlePanelOffset());
+    }
+
+    editModeOffset(): number {
+        return this.editMode ? BaseNgxChartsStreamPipesWidget.EDIT_HEADER_HEIGHT : 0;
+    }
+
+    titlePanelOffset(): number {
+        return this.hasTitlePanelSettings ? 20 : 0;
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/base/base-ngx-line-charts-widget.ts b/ui/src/app/data-explorer-v2/components/widgets/base/base-ngx-line-charts-widget.ts
new file mode 100644
index 0000000..03d0172
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/base/base-ngx-line-charts-widget.ts
@@ -0,0 +1,74 @@
+/*
+ * 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 {RxStompService} from "@stomp/ng2-stompjs";
+import {ResizeService} from "../../../services/resize.service";
+import {BaseNgxChartsStreamPipesWidget} from "./base-ngx-charts-widget";
+import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
+import {LineConfig} from "../line/line-config";
+
+export abstract class BaseNgxLineChartsStreamPipesWidget extends BaseNgxChartsStreamPipesWidget {
+
+    multi:any = [];
+
+    selectedNumberProperty: string;
+    selectedTimestampProperty: string;
+    minYAxisRange: number;
+    maxYAxisRange: number;
+
+    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
+        super(rxStompService, resizeService);
+    }
+
+    ngOnInit(): void {
+        super.ngOnInit();
+        this.multi = [
+            {
+                "name": this.selectedNumberProperty,
+                "series": [
+                ]
+            }];
+    }
+
+    protected extractConfig(extractor: StaticPropertyExtractor) {
+        this.selectedNumberProperty = extractor.mappingPropertyValue(LineConfig.NUMBER_MAPPING_KEY);
+        this.selectedTimestampProperty = extractor.mappingPropertyValue(LineConfig.TIMESTAMP_MAPPING_KEY);
+        this.minYAxisRange = extractor.integerParameter(LineConfig.MIN_Y_AXIS_KEY);
+        this.maxYAxisRange = extractor.integerParameter(LineConfig.MAX_Y_AXIS_KEY);
+    }
+
+    protected onEvent(event: any) {
+        let time = event[this.selectedTimestampProperty];
+        let value = event[this.selectedNumberProperty];
+        this.makeEvent(time, value);
+    }
+
+    makeEvent(time: any, value: any): void {
+        this.multi[0].series.push({"name": time, "value": value});
+        if (this.multi[0].series.length > 10) {
+            this.multi[0].series.shift();
+        }
+        this.multi = [...this.multi];
+    }
+
+    timestampTickFormatting(timestamp: any): string {
+        var date = new Date(timestamp);
+        let timeString = date.getHours() + ':' + date.getMinutes().toString().substr(-2) + ':' + date.getSeconds().toString().substr(-2);
+        return timeString;
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/base/base-ngx-line-config.ts b/ui/src/app/data-explorer-v2/components/widgets/base/base-ngx-line-config.ts
new file mode 100644
index 0000000..143d4c1
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/base/base-ngx-line-config.ts
@@ -0,0 +1,47 @@
+/*
+ * 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 {WidgetConfig} from "./base-config";
+import {DashboardWidgetSettings} from "../../../../core-model/dashboard/DashboardWidgetSettings";
+import {WidgetConfigBuilder} from "../../../registry/widget-config-builder";
+import {SchemaRequirementsBuilder} from "../../../sdk/schema-requirements-builder";
+import {EpRequirements} from "../../../sdk/ep-requirements";
+
+export abstract class BaseNgxLineConfig extends WidgetConfig {
+
+    static readonly NUMBER_MAPPING_KEY: string = "number-mapping";
+    static readonly TIMESTAMP_MAPPING_KEY: string = "timestamp-mapping";
+    static readonly MIN_Y_AXIS_KEY: string = "min-y-axis-key";
+    static readonly MAX_Y_AXIS_KEY: string = "max-y-axis-key";
+
+    getConfig(): DashboardWidgetSettings {
+        return WidgetConfigBuilder.createWithSelectableColorsAndTitlePanel(this.getWidgetName(), this.getWidgetLabel())
+            .requiredSchema(SchemaRequirementsBuilder
+                .create()
+                .requiredPropertyWithUnaryMapping(BaseNgxLineConfig.TIMESTAMP_MAPPING_KEY, "Timestamp field", "", EpRequirements.timestampReq())
+                .requiredPropertyWithUnaryMapping(BaseNgxLineConfig.NUMBER_MAPPING_KEY, "Number field", "", EpRequirements.numberReq())
+                .build())
+            .requiredIntegerParameter(BaseNgxLineConfig.MIN_Y_AXIS_KEY, "Y-axis range (min)", "")
+            .requiredIntegerParameter(BaseNgxLineConfig.MAX_Y_AXIS_KEY, "Y-axis range (min)", "")
+            .build();
+    }
+
+    abstract getWidgetName(): string;
+
+    abstract getWidgetLabel(): string;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/base/base-widget.ts b/ui/src/app/data-explorer-v2/components/widgets/base/base-widget.ts
new file mode 100644
index 0000000..79bd7da
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/base/base-widget.ts
@@ -0,0 +1,96 @@
+/*
+ * 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 {Input, OnChanges, OnInit, SimpleChanges} from "@angular/core";
+import {DashboardItem} from "../../../models/dashboard.model";
+import {DashboardWidget} from "../../../../core-model/dashboard/DashboardWidget";
+import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
+import {RxStompService} from "@stomp/ng2-stompjs";
+import {Message} from "@stomp/stompjs";
+import {Subscription} from "rxjs";
+import {GridsterItem, GridsterItemComponent} from "angular-gridster2";
+import {WidgetConfigBuilder} from "../../../registry/widget-config-builder";
+
+export abstract class BaseStreamPipesWidget implements OnChanges {
+
+    @Input() widget: DashboardItem;
+    @Input() widgetConfig: DashboardWidget;
+    @Input() gridsterItem: GridsterItem;
+    @Input() gridsterItemComponent: GridsterItemComponent;
+    @Input() editMode: boolean;
+
+    static readonly PADDING: number = 20;
+    static readonly EDIT_HEADER_HEIGHT: number = 40;
+
+    subscription: Subscription;
+
+    hasSelectableColorSettings: boolean;
+    hasTitlePanelSettings: boolean;
+
+    selectedBackgroundColor: string;
+    selectedPrimaryTextColor: string;
+    selectedSecondaryTextColor: string;
+    selectedTitle: string;
+
+    defaultBackgroundColor: string = "#1B1464";
+    defaultPrimaryTextColor: string = "#FFFFFF";
+    defaultSecondaryTextColor: string = "#39B54A";
+
+    protected constructor(private rxStompService: RxStompService) {
+    }
+
+    ngOnInit(): void {
+        this.prepareConfigExtraction();
+        this.subscription = this.rxStompService.watch("/topic/" +this.widgetConfig.dashboardWidgetDataConfig.topic).subscribe((message: Message) => {
+            this.onEvent(JSON.parse(message.body));
+        });
+    }
+
+    prepareConfigExtraction() {
+        let extractor: StaticPropertyExtractor = new StaticPropertyExtractor(this.widgetConfig.dashboardWidgetDataConfig.schema, this.widgetConfig.dashboardWidgetSettings.config);
+        if (extractor.hasStaticProperty(WidgetConfigBuilder.BACKGROUND_COLOR_KEY)) {
+            this.hasSelectableColorSettings = true;
+            this.selectedBackgroundColor = extractor.selectedColor(WidgetConfigBuilder.BACKGROUND_COLOR_KEY);
+            this.selectedPrimaryTextColor = extractor.selectedColor(WidgetConfigBuilder.PRIMARY_TEXT_COLOR_KEY);
+            this.selectedSecondaryTextColor = extractor.selectedColor(WidgetConfigBuilder.SECONDARY_TEXT_COLOR_KEY);
+        } else {
+            this.selectedBackgroundColor = this.defaultBackgroundColor;
+            this.selectedPrimaryTextColor = this.defaultPrimaryTextColor;
+            this.selectedSecondaryTextColor = this.defaultSecondaryTextColor;
+        }
+        if (extractor.hasStaticProperty(WidgetConfigBuilder.TITLE_KEY)) {
+            this.hasTitlePanelSettings = true;
+            this.selectedTitle = extractor.stringParameter(WidgetConfigBuilder.TITLE_KEY);
+        }
+        this.extractConfig(extractor);
+    }
+
+    ngOnDestroy(): void {
+        this.subscription.unsubscribe();
+    }
+
+    protected abstract extractConfig(extractor: StaticPropertyExtractor);
+
+    protected abstract onEvent(event: any);
+
+    ngOnChanges(changes: SimpleChanges): void {
+        if (changes["widgetConfig"]) {
+            this.prepareConfigExtraction();
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-config.ts b/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-config.ts
new file mode 100644
index 0000000..76eb3a8
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-config.ts
@@ -0,0 +1,48 @@
+/*
+ * 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 {WidgetConfig} from "../base/base-config";
+import {DashboardWidgetSettings} from "../../../../core-model/dashboard/DashboardWidgetSettings";
+import {WidgetConfigBuilder} from "../../../registry/widget-config-builder";
+import {SchemaRequirementsBuilder} from "../../../sdk/schema-requirements-builder";
+import {EpRequirements} from "../../../sdk/ep-requirements";
+
+export class GaugeConfig extends WidgetConfig {
+
+    static readonly TITLE_KEY: string = "title-key";
+    static readonly NUMBER_MAPPING_KEY: string = "number-mapping";
+    static readonly COLOR_KEY: string = "color-key";
+    static readonly MIN_KEY: string = "min-key";
+    static readonly MAX_KEY: string = "max-key";
+
+    constructor() {
+        super();
+    }
+
+    getConfig(): DashboardWidgetSettings {
+        return WidgetConfigBuilder.createWithSelectableColorsAndTitlePanel("gauge", "gauge")
+            .requiredSchema(SchemaRequirementsBuilder
+                .create()
+                .requiredPropertyWithUnaryMapping(GaugeConfig.NUMBER_MAPPING_KEY, "Select property", "", EpRequirements.numberReq())
+                .build())
+            .requiredIntegerParameter(GaugeConfig.MIN_KEY, "Min Y axis value", "")
+            .requiredIntegerParameter(GaugeConfig.MAX_KEY, "Max Y axis value", "")
+            .build();
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-widget.component.css b/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-widget.component.css
new file mode 100644
index 0000000..0dd319a
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-widget.component.css
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ *
+ */
+
+.main-panel {
+    width:100%;
+    height: 100%;
+    display:inline-grid;
+    align-content: center;
+}
+
+.mt-20 {
+    margin-top:20px;
+}
+
+.title-panel {
+    font-size:20px;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-widget.component.html b/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-widget.component.html
new file mode 100644
index 0000000..9b6c9ee
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-widget.component.html
@@ -0,0 +1,36 @@
+<!--
+  ~ 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" fxLayoutAlign="center center" fxLayout="column" class="main-panel"
+     [ngStyle]="{'background-color': selectedBackgroundColor, 'color': selectedPrimaryTextColor}">
+    <div class="title-panel mt-20" *ngIf="hasTitlePanelSettings">
+        {{selectedTitle}}
+    </div>
+    <ngx-charts-gauge
+            [view]="view"
+            [scheme]="colorScheme"
+            [results]="data"
+            [min]="min"
+            [max]="max"
+            [angleSpan]="240"
+            [startAngle]="-120"
+            [bigSegments]="10"
+            [smallSegments]="5"
+            [ngStyle]="{'fill': selectedPrimaryTextColor}" *ngIf="displayChart">
+    </ngx-charts-gauge>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-widget.component.ts b/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-widget.component.ts
new file mode 100644
index 0000000..479da83
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/gauge/gauge-widget.component.ts
@@ -0,0 +1,67 @@
+/*
+ * 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 {AfterViewInit, Component, ElementRef, OnDestroy, OnInit} from "@angular/core";
+import {BaseNgxChartsStreamPipesWidget} from "../base/base-ngx-charts-widget";
+import {RxStompService} from "@stomp/ng2-stompjs";
+import {ResizeService} from "../../../services/resize.service";
+import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
+import {GaugeConfig} from "./gauge-config";
+
+
+@Component({
+    selector: 'gauge-widget',
+    templateUrl: './gauge-widget.component.html',
+    styleUrls: ['./gauge-widget.component.css']
+})
+export class GaugeWidgetComponent extends BaseNgxChartsStreamPipesWidget implements OnInit, OnDestroy {
+
+    data: any = [];
+    min: number;
+    max: number;
+
+    selectedProperty: string;
+
+    constructor(rxStompService: RxStompService, resizeService: ResizeService, private el: ElementRef) {
+        super(rxStompService, resizeService);
+    }
+
+    ngOnInit(): void {
+        super.ngOnInit();
+    }
+
+    ngOnDestroy(): void {
+        super.ngOnDestroy();
+    }
+
+    extractConfig(extractor: StaticPropertyExtractor) {
+        this.min = extractor.integerParameter(GaugeConfig.MIN_KEY);
+        this.max = extractor.integerParameter(GaugeConfig.MAX_KEY);
+        this.selectedProperty = extractor.mappingPropertyValue(GaugeConfig.NUMBER_MAPPING_KEY);
+    }
+
+    isNumber(item: any): boolean {
+        return false;
+    }
+
+    protected onEvent(event: any) {
+        this.data[0] = ({"name": "value", "value": event[this.selectedProperty]});
+        this.data = [...this.data];
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/image/image-config.ts b/ui/src/app/data-explorer-v2/components/widgets/image/image-config.ts
new file mode 100644
index 0000000..20e3086
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/image/image-config.ts
@@ -0,0 +1,44 @@
+/*
+ * 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 {WidgetConfig} from "../base/base-config";
+import {DashboardWidgetSettings} from "../../../../core-model/dashboard/DashboardWidgetSettings";
+import {WidgetConfigBuilder} from "../../../registry/widget-config-builder";
+import {SchemaRequirementsBuilder} from "../../../sdk/schema-requirements-builder";
+import {EpRequirements} from "../../../sdk/ep-requirements";
+
+export class ImageConfig extends WidgetConfig {
+
+    static readonly TITLE_KEY: string = "title-key";
+    static readonly NUMBER_MAPPING_KEY: string = "number-mapping";
+
+    constructor() {
+        super();
+    }
+
+    getConfig(): DashboardWidgetSettings {
+        return WidgetConfigBuilder.create("image", "image")
+            .requiredSchema(SchemaRequirementsBuilder
+                .create()
+                .requiredPropertyWithUnaryMapping(ImageConfig.NUMBER_MAPPING_KEY, "Select property", "", EpRequirements.imageReq())
+                .build())
+            .requiredTextParameter(ImageConfig.TITLE_KEY, "Title", "The title")
+            .build();
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/image/image-widget.component.css b/ui/src/app/data-explorer-v2/components/widgets/image/image-widget.component.css
new file mode 100644
index 0000000..340d4a7
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/image/image-widget.component.css
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ *
+ */
+
+.image-box {
+    width:100%;
+    height: 100%;
+    color: #fff;
+    text-align: center;
+    left: 50%;
+    display:inline-grid;
+    align-content: center;
+}
+
+.image-title {
+    font-size:14px;
+}
diff --git a/ui/src/app/data-explorer-v2/components/widgets/image/image-widget.component.html b/ui/src/app/data-explorer-v2/components/widgets/image/image-widget.component.html
new file mode 100644
index 0000000..ea6be46
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/image/image-widget.component.html
@@ -0,0 +1,26 @@
+<!--
+  ~ 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 class="image-box" [ngStyle]="{'background-color': 'white'}">
+    <div class="imageTitle">
+        {{title}}
+    </div>
+    <div class="imageContent">
+        <img style="width: 100%;" src="data:image/jpg;base64,{{item}}" *ngIf="item" />
+    </div>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/image/image-widget.component.ts b/ui/src/app/data-explorer-v2/components/widgets/image/image-widget.component.ts
new file mode 100644
index 0000000..6725eea
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/image/image-widget.component.ts
@@ -0,0 +1,62 @@
+/*
+ * 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, OnDestroy, OnInit} from "@angular/core";
+import {BaseNgxChartsStreamPipesWidget} from "../base/base-ngx-charts-widget";
+import {RxStompService} from "@stomp/ng2-stompjs";
+import {ResizeService} from "../../../services/resize.service";
+import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
+import {GaugeConfig} from "../gauge/gauge-config";
+
+@Component({
+    selector: 'image-widget',
+    templateUrl: './image-widget.component.html',
+    styleUrls: ['./image-widget.component.css']
+})
+export class ImageWidgetComponent extends BaseNgxChartsStreamPipesWidget implements OnInit, OnDestroy {
+
+    item: any;
+    title: string;
+    selectedProperty: string;
+
+    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
+        super(rxStompService, resizeService);
+    }
+
+    ngOnInit(): void {
+        super.ngOnInit();
+    }
+
+    ngOnDestroy(): void {
+        super.ngOnDestroy();
+    }
+
+    extractConfig(extractor: StaticPropertyExtractor) {
+        this.title = extractor.singleValueParameter(GaugeConfig.TITLE_KEY);
+        this.selectedProperty = extractor.mappingPropertyValue(GaugeConfig.NUMBER_MAPPING_KEY);
+    }
+
+    isNumber(item: any): boolean {
+        return false;
+    }
+
+    protected onEvent(event: any) {
+        this.item = event[this.selectedProperty];
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/line/line-config.ts b/ui/src/app/data-explorer-v2/components/widgets/line/line-config.ts
new file mode 100644
index 0000000..da45420
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/line/line-config.ts
@@ -0,0 +1,30 @@
+/*
+ * 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 {BaseNgxLineConfig} from "../base/base-ngx-line-config";
+
+export class LineConfig extends BaseNgxLineConfig {
+
+    getWidgetLabel(): string {
+        return "line";
+    }
+
+    getWidgetName(): string {
+        return "line";
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/line/line-widget.component.css b/ui/src/app/data-explorer-v2/components/widgets/line/line-widget.component.css
new file mode 100644
index 0000000..0dd319a
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/line/line-widget.component.css
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ *
+ */
+
+.main-panel {
+    width:100%;
+    height: 100%;
+    display:inline-grid;
+    align-content: center;
+}
+
+.mt-20 {
+    margin-top:20px;
+}
+
+.title-panel {
+    font-size:20px;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/line/line-widget.component.html b/ui/src/app/data-explorer-v2/components/widgets/line/line-widget.component.html
new file mode 100644
index 0000000..e3eea5f
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/line/line-widget.component.html
@@ -0,0 +1,41 @@
+<!--
+  ~ 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" fxLayoutAlign="center center" fxLayout="column" class="main-panel" [ngStyle]="{'background-color': selectedBackgroundColor, 'color': selectedPrimaryTextColor}">
+    <div class="title-panel mt-20" *ngIf="hasTitlePanelSettings">
+        {{selectedTitle}}
+    </div>
+    <ngx-charts-line-chart *ngIf="displayChart"
+                           [showXAxisLabel]="false"
+                           [showYAxisLabel]="false"
+                           [scheme]="colorScheme"
+                           [timeline]="false"
+                           [view]="view"
+                           [autoScale]="false"
+                           [xAxis]="true"
+                           [yAxis]="true"
+                           [yScaleMin]="minYAxisRange"
+                           [yScaleMax]="maxYAxisRange"
+                           [tooltipDisabled]="true"
+                           [animations]="false"
+                           [xAxisTickFormatting]="timestampTickFormatting"
+                           [results]="multi" style="margin-top:10px;margin-bottom:10px;"
+                           [ngStyle]="{'fill': selectedPrimaryTextColor}">
+    </ngx-charts-line-chart>
+</div>
+
diff --git a/ui/src/app/data-explorer-v2/components/widgets/line/line-widget.component.ts b/ui/src/app/data-explorer-v2/components/widgets/line/line-widget.component.ts
new file mode 100644
index 0000000..31d4ff2
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/line/line-widget.component.ts
@@ -0,0 +1,46 @@
+/*
+ * 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 {AfterViewInit, Component, ElementRef, OnDestroy, OnInit} from "@angular/core";
+import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
+import {RxStompService} from "@stomp/ng2-stompjs";
+import {LineConfig} from "./line-config";
+import {ResizeService} from "../../../services/resize.service";
+import {BaseNgxChartsStreamPipesWidget} from "../base/base-ngx-charts-widget";
+import {BaseNgxLineChartsStreamPipesWidget} from "../base/base-ngx-line-charts-widget";
+
+@Component({
+    selector: 'line-widget',
+    templateUrl: './line-widget.component.html',
+    styleUrls: ['./line-widget.component.css']
+})
+export class LineWidgetComponent extends BaseNgxLineChartsStreamPipesWidget implements OnInit, OnDestroy {
+
+    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
+        super(rxStompService, resizeService);
+    }
+
+    ngOnInit(): void {
+        super.ngOnInit();
+    }
+
+    ngOnDestroy(): void {
+        super.ngOnDestroy();
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/number/number-config.ts b/ui/src/app/data-explorer-v2/components/widgets/number/number-config.ts
new file mode 100644
index 0000000..f4f0b81
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/number/number-config.ts
@@ -0,0 +1,42 @@
+/*
+ * 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 {WidgetConfigBuilder} from "../../../registry/widget-config-builder";
+import {SchemaRequirementsBuilder} from "../../../sdk/schema-requirements-builder";
+import {EpRequirements} from "../../../sdk/ep-requirements";
+import {DashboardWidgetSettings} from "../../../../core-model/dashboard/DashboardWidgetSettings";
+import {WidgetConfig} from "../base/base-config";
+
+export class NumberConfig extends WidgetConfig {
+
+    static readonly NUMBER_MAPPING_KEY: string = "number-mapping";
+
+    constructor() {
+        super();
+    }
+
+    getConfig(): DashboardWidgetSettings {
+        return WidgetConfigBuilder.createWithSelectableColorsAndTitlePanel("number", "number")
+            .requiredSchema(SchemaRequirementsBuilder
+                .create()
+                .requiredPropertyWithUnaryMapping(NumberConfig.NUMBER_MAPPING_KEY, "Select property", "", EpRequirements.numberReq())
+                .build())
+            .build();
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/number/number-widget.component.css b/ui/src/app/data-explorer-v2/components/widgets/number/number-widget.component.css
new file mode 100644
index 0000000..eaf8444
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/number/number-widget.component.css
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ */
+
+.circleNumber {
+    width:100%;
+    height: 100%;
+    text-align: center;
+    left: 50%;
+    display:inline-grid;
+    align-content: center;
+}
+
+
+.numberItem {
+    font-size:60px;
+    font-weight:bold;
+}
+
+.title-panel {
+    font-size:20px;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/number/number-widget.component.html b/ui/src/app/data-explorer-v2/components/widgets/number/number-widget.component.html
new file mode 100644
index 0000000..0550f87
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/number/number-widget.component.html
@@ -0,0 +1,27 @@
+<!--
+  ~ 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 class="circleNumber" [ngStyle]="{'background-color': selectedBackgroundColor, 'color': selectedPrimaryTextColor}">
+    <div class="title-panel" *ngIf="hasTitlePanelSettings">
+        {{selectedTitle}}
+    </div>
+    <div class="numberItem">
+        <div *ngIf="isNumber(item)">{{item}}</div>
+        <div *ngIf="!isNumber(item)">{{item}}</div>
+    </div>
+</div>
diff --git a/ui/src/app/data-explorer-v2/components/widgets/number/number-widget.component.ts b/ui/src/app/data-explorer-v2/components/widgets/number/number-widget.component.ts
new file mode 100644
index 0000000..7157be8
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/number/number-widget.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, Input, OnDestroy, OnInit} from "@angular/core";
+import {RxStompService} from "@stomp/ng2-stompjs";
+import {BaseStreamPipesWidget} from "../base/base-widget";
+import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
+import {NumberConfig} from "./number-config";
+
+@Component({
+    selector: 'number-widget',
+    templateUrl: './number-widget.component.html',
+    styleUrls: ['./number-widget.component.css']
+})
+export class NumberWidgetComponent extends BaseStreamPipesWidget implements OnInit, OnDestroy {
+
+    item: any;
+
+    selectedProperty: string;
+
+    constructor(rxStompService: RxStompService) {
+        super(rxStompService);
+    }
+
+    ngOnInit(): void {
+        super.ngOnInit();
+    }
+
+    ngOnDestroy(): void {
+        super.ngOnDestroy();
+    }
+
+    extractConfig(extractor: StaticPropertyExtractor) {
+        this.selectedProperty = extractor.mappingPropertyValue(NumberConfig.NUMBER_MAPPING_KEY);
+    }
+
+    isNumber(item: any): boolean {
+        return false;
+    }
+
+    protected onEvent(event: any) {
+        this.item = event[this.selectedProperty];
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/table/table-config.ts b/ui/src/app/data-explorer-v2/components/widgets/table/table-config.ts
new file mode 100644
index 0000000..47b71f5
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/table/table-config.ts
@@ -0,0 +1,44 @@
+/*
+ * 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 {WidgetConfig} from "../base/base-config";
+import {DashboardWidgetSettings} from "../../../../core-model/dashboard/DashboardWidgetSettings";
+import {WidgetConfigBuilder} from "../../../registry/widget-config-builder";
+import {SchemaRequirementsBuilder} from "../../../sdk/schema-requirements-builder";
+import {EpRequirements} from "../../../sdk/ep-requirements";
+
+export class TableConfig extends WidgetConfig {
+
+    static readonly TITLE_KEY: string = "title-key";
+    static readonly SELECTED_PROPERTIES_KEYS: string = "selected-fields-key";
+
+    constructor() {
+        super();
+    }
+
+    getConfig(): DashboardWidgetSettings {
+        return WidgetConfigBuilder.createWithSelectableColorsAndTitlePanel("table", "table")
+            .requiredSchema(SchemaRequirementsBuilder
+                .create()
+                .requiredPropertyWithNaryMapping(TableConfig.SELECTED_PROPERTIES_KEYS, "Select properties", "", EpRequirements.anyProperty())
+                .build())
+            .requiredTextParameter(TableConfig.TITLE_KEY, "Title", "The title")
+            .build();
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/table/table-widget.component.css b/ui/src/app/data-explorer-v2/components/widgets/table/table-widget.component.css
new file mode 100644
index 0000000..59023f4
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/table/table-widget.component.css
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ *
+ */
+
+.title-panel {
+    font-size:20px;
+    text-align:center;
+}
+
+.mt-20 {
+    margin-top:20px;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/table/table-widget.component.html b/ui/src/app/data-explorer-v2/components/widgets/table/table-widget.component.html
new file mode 100644
index 0000000..dc55f14
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/table/table-widget.component.html
@@ -0,0 +1,36 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div fxLayout="column" fxFlex="100" [ngStyle]="{'background-color': selectedBackgroundColor, 'color':
+selectedPrimaryTextColor}">
+    <div class="title-panel mt-20" *ngIf="hasTitlePanelSettings">
+        {{selectedTitle}}
+    </div>
+    <table fxFlex="100" mat-table [dataSource]="dataSource" [ngStyle]="{'background': selectedBackgroundColor}">
+
+        <ng-container *ngFor="let element of selectedProperties" [cdkColumnDef]="element">
+            <th mat-header-cell [ngStyle]="{'color': selectedPrimaryTextColor}"
+                *matHeaderCellDef><label>{{element}}</label></th>
+            <td mat-cell *matCellDef="let row" [ngStyle]="{'color': selectedPrimaryTextColor}">{{row[element]}}</td>
+        </ng-container>
+
+        <tr mat-header-row *matHeaderRowDef="selectedProperties; sticky: true"></tr>
+        <tr mat-row *matRowDef="let row; columns: selectedProperties;"></tr>
+
+    </table>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/components/widgets/table/table-widget.component.ts b/ui/src/app/data-explorer-v2/components/widgets/table/table-widget.component.ts
new file mode 100644
index 0000000..56c970b
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/widgets/table/table-widget.component.ts
@@ -0,0 +1,77 @@
+/*
+ * 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, OnDestroy, OnInit} from "@angular/core";
+import {BaseStreamPipesWidget} from "../base/base-widget";
+import {RxStompService} from "@stomp/ng2-stompjs";
+import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
+import {MatTableDataSource} from "@angular/material/table";
+import {TableConfig} from "./table-config";
+import {SemanticTypeUtilsService} from "../../../../core-services/semantic-type/semantic-type-utils.service";
+
+@Component({
+    selector: 'table-widget',
+    templateUrl: './table-widget.component.html',
+    styleUrls: ['./table-widget.component.css']
+})
+export class TableWidgetComponent extends BaseStreamPipesWidget implements OnInit, OnDestroy {
+
+    selectedProperties: Array<string>;
+
+    displayedColumns: String[] = [];
+    dataSource = new MatTableDataSource();
+    semanticTypes: { [key: string]: string; } = {};
+
+    constructor(rxStompService: RxStompService, private semanticTypeUtils: SemanticTypeUtilsService) {
+        super(rxStompService);
+    }
+
+    ngOnInit(): void {
+        super.ngOnInit();
+
+        this.widgetConfig.dashboardWidgetDataConfig.schema.eventProperties.forEach((key, index) => {
+            this.semanticTypes[key.runtimeName] = key.domainProperty
+        });
+    }
+
+    ngOnDestroy(): void {
+        super.ngOnDestroy();
+    }
+
+    extractConfig(extractor: StaticPropertyExtractor) {
+        this.selectedProperties = extractor.mappingPropertyValues(TableConfig.SELECTED_PROPERTIES_KEYS);
+    }
+
+    protected onEvent(event: any) {
+        this.dataSource.data.unshift(this.createTableObject(event));
+        if (this.dataSource.data.length > 10) {
+            this.dataSource.data.pop();
+        }
+        this.dataSource.data = [...this.dataSource.data];
+    }
+
+    createTableObject(event: any) {
+        let object = {};
+        this.selectedProperties.forEach((key, index) => {
+            event[key] = this.semanticTypeUtils.getValue(event[key], this.semanticTypes[key]);
+            object[key] = event[key];
+        });
+        return object;
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/data-explorer-v2.component.css b/ui/src/app/data-explorer-v2/data-explorer-v2.component.css
new file mode 100644
index 0000000..7eaab26
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/data-explorer-v2.component.css
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ *
+ */
+
+.mr-20 {
+    margin-right:20px;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/data-explorer-v2.component.html b/ui/src/app/data-explorer-v2/data-explorer-v2.component.html
new file mode 100644
index 0000000..6bb288d
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/data-explorer-v2.component.html
@@ -0,0 +1,51 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div fxLayout="column" class="page-container">
+    <div fxLayout="row" style="padding:0px;background-color:#f6f6f6;">
+        <div fxFlex="100" style="line-height:24px;border-bottom:1px solid #ccc">
+            <div fxFlex="100" fxLayout="row">
+                <div fxFlex fxLayoutAlign="start center">
+                    <mat-tab-group [selectedIndex]="selectedIndex" (selectedIndexChange)="selectDashboard($event)">
+                        <mat-tab label="Start"></mat-tab>
+                        <mat-tab *ngFor="let dashboard of dashboards" label="{{dashboard.name}}"></mat-tab>
+                    </mat-tab-group>
+                </div>
+                <div fxFlex fxLayoutAlign="end center" class="mr-20">
+                <button mat-button mat-icon-button color="primary"
+                        *ngIf="selectedIndex > 0" (click)="toggleEditMode()" [disabled]="editMode">
+                    <i class="material-icons">edit</i>
+                </button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100" *ngIf="dashboardsLoaded">
+    <dashboard-overview (selectDashboardEmitter)="openDashboard($event)"
+                        (reloadDashboardsEmitter)="getDashboards()"
+                        [dashboards]="dashboards"
+                        *ngIf="!dashboardTabSelected">
+
+    </dashboard-overview>
+    <dashboard-panel fxLayout="column" [(editMode)]="editMode" [dashboard]="selectedDashboard"
+                     style="height:100%;" *ngIf="dashboardTabSelected">
+
+    </dashboard-panel>
+    </div>
+</div>
diff --git a/ui/src/app/data-explorer-v2/data-explorer-v2.component.ts b/ui/src/app/data-explorer-v2/data-explorer-v2.component.ts
new file mode 100644
index 0000000..eab8564
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/data-explorer-v2.component.ts
@@ -0,0 +1,83 @@
+/*
+ * 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, OnInit } from '@angular/core';
+import { Dashboard } from './models/dashboard.model';
+import { DashboardService } from './services/dashboard.service';
+import { RefreshDashboardService } from './services/refresh-dashboard.service';
+
+@Component({
+    selector: 'data-explorer-v2',
+    templateUrl: './data-explorer-v2.component.html',
+    styleUrls: ['./data-explorer-v2.component.css']
+})
+export class DataExplorerV2Component implements OnInit {
+
+    selectedDashboard: Dashboard;
+    selectedIndex = 0;
+    dashboardsLoaded = false;
+    dashboardTabSelected = false;
+
+    editMode = false;
+
+    dashboards: Dashboard[];
+
+    constructor(private dashboardService: DashboardService,
+                private refreshDashboardService: RefreshDashboardService) {}
+
+    public ngOnInit() {
+        this.getDashboards();
+        this.refreshDashboardService.refreshSubject.subscribe(currentDashboardId => {
+            this.getDashboards(currentDashboardId);
+        });
+
+    }
+
+    openDashboard(dashboard: Dashboard) {
+        const index = this.dashboards.indexOf(dashboard);
+        this.selectDashboard((index + 1));
+    }
+
+    selectDashboard(index: number) {
+        this.selectedIndex = index;
+        if (index == 0) {
+            this.dashboardTabSelected = false;
+        } else {
+            this.dashboardTabSelected = true;
+            this.selectedDashboard = this.dashboards[(index - 1)];
+        }
+    }
+
+    protected getDashboards(currentDashboardId?: string) {
+        this.dashboardsLoaded = false;
+        this.dashboardService.getDashboards().subscribe(data => {
+            this.dashboards = data;
+            if (currentDashboardId) {
+                const currentDashboard = this.dashboards.find(d => d._id === currentDashboardId);
+                this.selectDashboard(this.dashboards.indexOf(currentDashboard) + 1);
+            } else {
+                this.selectedIndex = 0;
+            }
+            this.dashboardsLoaded = true;
+        });
+    }
+
+    toggleEditMode() {
+        this.editMode = ! (this.editMode);
+    }
+}
diff --git a/ui/src/app/data-explorer-v2/data-explorer-v2.module.ts b/ui/src/app/data-explorer-v2/data-explorer-v2.module.ts
new file mode 100644
index 0000000..1e4d678
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/data-explorer-v2.module.ts
@@ -0,0 +1,126 @@
+/*
+ * 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 { CdkTableModule } from '@angular/cdk/table';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { FormsModule } from '@angular/forms';
+import { MatGridListModule } from '@angular/material/grid-list';
+import { MatTabsModule } from '@angular/material/tabs';
+import { InjectableRxStompConfig, RxStompService, rxStompServiceFactory } from '@stomp/ng2-stompjs';
+import { NgxChartsModule } from '@swimlane/ngx-charts';
+import { GridsterModule } from 'angular-gridster2';
+import { DynamicModule } from 'ng-dynamic-component';
+import { ColorPickerModule } from 'ngx-color-picker';
+import { ConnectModule } from '../connect/connect.module';
+import { SemanticTypeUtilsService } from '../core-services/semantic-type/semantic-type-utils.service';
+import { CustomMaterialModule } from '../CustomMaterial/custom-material.module';
+import { ElementIconText } from '../services/get-element-icon-text.service';
+import { DashboardGridComponent } from './components/grid/dashboard-grid.component';
+import { DashboardOverviewComponent } from './components/overview/dashboard-overview.component';
+import { DashboardPanelComponent } from './components/panel/dashboard-panel.component';
+import { DashboardWidgetComponent } from './components/widget/dashboard-widget.component';
+import { AreaWidgetComponent } from './components/widgets/area/area-widget.component';
+import { GaugeWidgetComponent } from './components/widgets/gauge/gauge-widget.component';
+import { ImageWidgetComponent } from './components/widgets/image/image-widget.component';
+import { LineWidgetComponent } from './components/widgets/line/line-widget.component';
+import { NumberWidgetComponent } from './components/widgets/number/number-widget.component';
+import { TableWidgetComponent } from './components/widgets/table/table-widget.component';
+import { DataExplorerV2Component } from './data-explorer-v2.component';
+import { AddVisualizationDialogComponent } from './dialogs/add-widget/add-visualization-dialog.component';
+import { EditDashboardDialogComponent } from './dialogs/edit-dashboard/edit-dashboard-dialog.component';
+import { DashboardService } from './services/dashboard.service';
+import { RefreshDashboardService } from './services/refresh-dashboard.service';
+import { ResizeService } from './services/resize.service';
+import { streamPipesStompConfig } from './services/websocket.config';
+
+const dashboardWidgets = [
+
+];
+
+@NgModule({
+    imports: [
+        CommonModule,
+        MatTabsModule,
+        DynamicModule.withComponents(
+            dashboardWidgets
+        ),
+        FlexLayoutModule,
+        GridsterModule,
+        CommonModule,
+        FlexLayoutModule,
+        CustomMaterialModule,
+        FormsModule,
+        ColorPickerModule,
+        MatGridListModule,
+        ConnectModule,
+        NgxChartsModule,
+        CdkTableModule,
+    ],
+    declarations: [
+        DataExplorerV2Component,
+        DashboardGridComponent,
+        DashboardOverviewComponent,
+        DashboardPanelComponent,
+        DashboardWidgetComponent,
+        AddVisualizationDialogComponent,
+        EditDashboardDialogComponent,
+        AreaWidgetComponent,
+        LineWidgetComponent,
+        NumberWidgetComponent,
+        TableWidgetComponent,
+        GaugeWidgetComponent,
+        ImageWidgetComponent
+    ],
+    providers: [
+        DashboardService,
+        ResizeService,
+        RefreshDashboardService,
+        SemanticTypeUtilsService,
+        {
+            provide: 'RestApi',
+            useFactory: ($injector: any) => $injector.get('RestApi'),
+            deps: ['$injector'],
+        },
+        ElementIconText,
+        {
+            provide: InjectableRxStompConfig,
+            useValue: streamPipesStompConfig
+        },
+        {
+            provide: RxStompService,
+            useFactory: rxStompServiceFactory,
+            deps: [InjectableRxStompConfig]
+        }
+    ],
+    exports: [
+        DataExplorerV2Component
+    ],
+    entryComponents: [
+        DataExplorerV2Component,
+        AddVisualizationDialogComponent,
+        EditDashboardDialogComponent
+    ]
+})
+export class DataExplorerV2Module {
+
+    constructor() {
+    }
+
+}
diff --git a/ui/src/app/data-explorer-v2/dialogs/add-widget/add-visualization-dialog.component.css b/ui/src/app/data-explorer-v2/dialogs/add-widget/add-visualization-dialog.component.css
new file mode 100644
index 0000000..e00a7b4
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/dialogs/add-widget/add-visualization-dialog.component.css
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ *
+ */
+
+.element-margin {
+    margin-top:10px;
+    margin-bottom:10px;
+}
+
+mat-toolbar {
+    background: #39b54a;
+    color:white;
+}
+
+mat-dialog-content {
+    padding: 24px;
+    -webkit-box-ordinal-group: 2;
+    -webkit-order: 1;
+    order: 1;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+    flex-direction: column;
+    overflow: auto;
+    -webkit-overflow-scrolling: touch;
+}
+
+.mat-dialog-content {
+    width:100%;
+    height:74%;
+    margin: 0px;
+}
+
+.mat-dialog-actions {
+    margin-bottom:0px;
+    padding-right:10px;
+}
+
+.mat-radio-button {
+    padding: 10px;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/dialogs/add-widget/add-visualization-dialog.component.html b/ui/src/app/data-explorer-v2/dialogs/add-widget/add-visualization-dialog.component.html
new file mode 100644
index 0000000..c746d86
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/dialogs/add-widget/add-visualization-dialog.component.html
@@ -0,0 +1,95 @@
+<!--
+~ 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>{{dialogTitle}}</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" style="margin:5px;width:100%">
+                <div *ngIf="page == 'select-pipeline'">
+                    <h4>{{pages[0].description}}</h4>
+                    <mat-grid-list
+                            [cols]="3" [rowHeight]="200"
+                            [gutterSize]="100">
+
+                        <mat-grid-tile class="gray" *ngFor="let pipeline of visualizablePipelines">
+                            <div [ngClass]="getSelectedPipelineCss(pipeline)"
+                                 (click)="selectPipeline(pipeline)">
+                                {{iconText(pipeline.visualizationName)}}
+                                <h5>{{pipeline.visualizationName}}</h5>
+                            </div>
+                        </mat-grid-tile>
+                    </mat-grid-list>
+                </div>
+
+                <!-- Select Type -->
+                <div *ngIf="page == 'select-widget'" fxLayout="column">
+                    <h4>{{pages[1].description}}</h4>
+                    <mat-grid-list
+                            [cols]="3" [rowHeight]="200"
+                            [gutterSize]="100">
+
+                        <mat-grid-tile class="gray" *ngFor="let widget of availableWidgets">
+                            <div [ngClass]="getSelectedPipelineCss(widget.widgetLabel)"
+                                 (click)="selectWidget(widget)">
+                                {{iconText(widget.widgetLabel)}}
+                                <h5>{{widget.widgetLabel}}</h5>
+                            </div>
+                        </mat-grid-tile>
+                    </mat-grid-list>
+                </div>
+
+                <!-- Select Scheme -->
+                <div *ngIf="page == 'configure-widget'" fxLayout="column">
+                    <b><h4>{{pages[2].description}}</h4></b>
+                    <div fxFlex="100" fxLayout="column">
+                        <app-static-property *ngFor="let config of selectedWidget.config" [staticProperty]="config"
+                                             [staticProperties]="selectedWidget.config"
+                                             [eventSchema]="selectedPipeline.schema"></app-static-property>
+                    </div>
+
+                </div>
+
+            </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 class="mat-basic" (click)="back()" *ngIf="(!('select-pipeline'===page))
+        && !(data)">
+            Back
+        </button>
+        <button mat-button mat-raised-button color="primary" (click)="next()">
+            <span *ngIf="!data && 'configure-widget' === page">Create</span>
+            <span *ngIf="data && 'configure-widget' === page">Save</span>
+            <span *ngIf="data == null && !('configure-widget' === page)">Next</span>
+        </button>
+    </div>
+
+
diff --git a/ui/src/app/data-explorer-v2/dialogs/add-widget/add-visualization-dialog.component.ts b/ui/src/app/data-explorer-v2/dialogs/add-widget/add-visualization-dialog.component.ts
new file mode 100644
index 0000000..24df862
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/dialogs/add-widget/add-visualization-dialog.component.ts
@@ -0,0 +1,169 @@
+/*
+ * 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/dialog";
+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";
+import {MappingPropertyNary} from "../../../connect/model/MappingPropertyNary";
+
+@Component({
+    selector: 'add-visualization-dialog-component',
+    templateUrl: './add-visualization-dialog.component.html',
+    styleUrls: ['./add-visualization-dialog.component.css']
+})
+export class AddVisualizationDialogComponent {
+
+    pages = [{
+        type: "select-pipeline",
+        title: "Select Pipeline",
+        description: "Select a pipeline you'd like to visualize"
+    }, {
+        type: "select-widget",
+        title: "Select Widget",
+        description: "Select widget"
+    }, {
+        type: "configure-widget",
+        title: "Configure Widget",
+        description: "Configure widget"
+    }];
+
+    visualizablePipelines: Array<VisualizablePipeline> = [];
+    availableWidgets: Array<DashboardWidgetSettings>;
+
+    selectedPipeline: VisualizablePipeline;
+    selectedWidget: DashboardWidgetSettings;
+
+    dashboard: Dashboard;
+
+    selectedType: any;
+    page: any = "select-pipeline";
+    dialogTitle: string;
+
+
+    constructor(
+        public dialogRef: MatDialogRef<AddVisualizationDialogComponent>,
+        @Inject(MAT_DIALOG_DATA) public data: any,
+        private dashboardService: DashboardService,
+        public elementIconText: ElementIconText) {
+    }
+
+    ngOnInit() {
+        if (!this.data) {
+            this.dialogTitle = "Add widget";
+            this.dashboardService.getVisualizablePipelines().subscribe(visualizations => {
+                this.visualizablePipelines = visualizations;
+            });
+            this.availableWidgets = WidgetRegistry.getAvailableWidgetTemplates();
+        } else {
+            this.dialogTitle = "Edit widget";
+            this.selectedPipeline = this.data.widget.dashboardWidgetDataConfig;
+            this.selectedWidget = this.data.widget.dashboardWidgetSettings;
+            this.page = 'configure-widget';
+        }
+    }
+
+    onCancel(): void {
+        this.dialogRef.close();
+    }
+
+    getSelectedPipelineCss(vis) {
+        return this.getSelectedCss(this.selectedPipeline, vis);
+    }
+
+    getSelectedVisTypeCss(type) {
+        return this.getSelectedCss(this.selectedType, type);
+    }
+
+    getSelectedCss(selected, current) {
+        if (selected == current) {
+            return "wizard-preview wizard-preview-selected";
+        } else {
+            return "wizard-preview";
+        }
+    }
+
+    getTabCss(page) {
+        if (page == this.page) return "md-fab md-accent";
+        else return "md-fab md-accent wizard-inactive";
+    }
+
+    selectPipeline(vis) {
+        this.selectedPipeline = vis;
+        this.next();
+    }
+
+    selectWidget(widget) {
+        this.selectedWidget = widget;
+        this.selectedWidget.config.forEach(sp => {
+            if (sp instanceof MappingPropertyUnary || sp instanceof MappingPropertyNary) {
+                let requirement: EventProperty = this.findRequirement(this.selectedWidget.requiredSchema, sp.internalName);
+                sp.mapsFromOptions = new MappingPropertyGenerator(requirement, this.selectedPipeline.schema.eventProperties).computeMatchingProperties();
+            }
+        });
+        this.next();
+    }
+
+    findRequirement(requiredSchema: EventSchema, internalName: string) {
+        return requiredSchema.eventProperties.find(ep => ep.runtimeName === internalName);
+    }
+
+    next() {
+        if (this.page == 'select-pipeline') {
+            this.page = 'select-widget';
+        } else if (this.page == 'select-widget') {
+            this.page = 'configure-widget';
+        } else {
+            let configuredWidget: DashboardWidget = new DashboardWidget();
+            configuredWidget.dashboardWidgetSettings = this.selectedWidget;
+            configuredWidget.dashboardWidgetDataConfig = this.selectedPipeline;
+            if (!this.data) {
+                this.dashboardService.saveWidget(configuredWidget).subscribe(response => {
+                    this.dialogRef.close(response);
+                });
+            } else {
+                configuredWidget._id = this.data.widget._id;
+                configuredWidget._ref = this.data.widget._ref;
+                configuredWidget.widgetId = this.data.widget.widgetId;
+                this.dialogRef.close(configuredWidget);
+            }
+        }
+    }
+
+    back() {
+        if (this.page == 'select-widget') {
+            this.page = 'select-pipeline';
+        } else if (this.page == 'configure-widget') {
+            this.page = 'select-widget';
+        }
+    }
+
+    iconText(s) {
+        return this.elementIconText.getElementIconText(s);
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.css b/ui/src/app/data-explorer-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.css
new file mode 100644
index 0000000..e00a7b4
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.css
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ *
+ */
+
+.element-margin {
+    margin-top:10px;
+    margin-bottom:10px;
+}
+
+mat-toolbar {
+    background: #39b54a;
+    color:white;
+}
+
+mat-dialog-content {
+    padding: 24px;
+    -webkit-box-ordinal-group: 2;
+    -webkit-order: 1;
+    order: 1;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+    -webkit-flex-direction: column;
+    flex-direction: column;
+    overflow: auto;
+    -webkit-overflow-scrolling: touch;
+}
+
+.mat-dialog-content {
+    width:100%;
+    height:74%;
+    margin: 0px;
+}
+
+.mat-dialog-actions {
+    margin-bottom:0px;
+    padding-right:10px;
+}
+
+.mat-radio-button {
+    padding: 10px;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.html b/ui/src/app/data-explorer-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.html
new file mode 100644
index 0000000..980b679
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.html
@@ -0,0 +1,55 @@
+<!--
+~ 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>
+            <mat-checkbox [(ngModel)]="dashboard.displayHeader">Show name and description in dashboard</mat-checkbox>
+
+        </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/data-explorer-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts b/ui/src/app/data-explorer-v2/dialogs/edit-dashboard/edit-dashboard-dialog.component.ts
new file mode 100644
index 0000000..72d9433
--- /dev/null
+++ b/ui/src/app/data-explorer-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/dialog";
+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/data-explorer-v2/models/dashboard.model.ts b/ui/src/app/data-explorer-v2/models/dashboard.model.ts
new file mode 100644
index 0000000..1193e71
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/models/dashboard.model.ts
@@ -0,0 +1,36 @@
+/*
+ * 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 {GridsterConfig, GridsterItem} from "angular-gridster2";
+
+export interface DashboardConfig extends GridsterConfig {}
+
+export interface DashboardItem extends GridsterItem {
+    widgetId: string;
+    id: string;
+}
+
+export interface Dashboard {
+    id?: string;
+    name?: string;
+    description?: string;
+    displayHeader?: boolean;
+    widgets?: Array<DashboardItem>;
+    _id?: string;
+    _rev?: string;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/models/gridster-info.model.ts b/ui/src/app/data-explorer-v2/models/gridster-info.model.ts
new file mode 100644
index 0000000..43c41de
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/models/gridster-info.model.ts
@@ -0,0 +1,24 @@
+/*
+ * 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 {GridsterItem, GridsterItemComponent} from "angular-gridster2";
+
+export interface GridsterInfo {
+    gridsterItem: GridsterItem;
+    gridsterItemComponent: GridsterItemComponent
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/models/multi-series.model.ts b/ui/src/app/data-explorer-v2/models/multi-series.model.ts
new file mode 100644
index 0000000..e95f777
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/models/multi-series.model.ts
@@ -0,0 +1,29 @@
+/*
+ * 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 {DashboardItem} from "./dashboard.model";
+
+export interface MultiSeries {
+    name?: string;
+    series?: Array<MultiSeriesEntry>;
+}
+
+export interface MultiSeriesEntry {
+    name: string;
+    value: any;
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/registry/widget-config-builder.ts b/ui/src/app/data-explorer-v2/registry/widget-config-builder.ts
new file mode 100644
index 0000000..ed9a5f8
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/registry/widget-config-builder.ts
@@ -0,0 +1,121 @@
+/*
+ * 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 {FreeTextStaticProperty} from "../../connect/model/FreeTextStaticProperty";
+import {CollectedSchemaRequirements} from "../sdk/collected-schema-requirements";
+import {DashboardWidgetSettings} from "../../core-model/dashboard/DashboardWidgetSettings";
+import {Datatypes} from "../sdk/model/datatypes";
+import {ColorPickerStaticProperty} from "../../connect/model/ColorPickerStaticProperty";
+
+export class WidgetConfigBuilder {
+
+    static readonly BACKGROUND_COLOR_KEY: string = "spi-background-color-key";
+    static readonly PRIMARY_TEXT_COLOR_KEY: string = "spi-primary-text-color-key";
+    static readonly SECONDARY_TEXT_COLOR_KEY: string = "spi-secondary-text-color-key";
+
+    static readonly TITLE_KEY: string = "spi-title-key";
+
+    private widget: DashboardWidgetSettings;
+
+    private constructor(widgetName: string, widgetLabel: string, withColors?: boolean, withTitlePanel?: boolean) {
+        this.widget = new DashboardWidgetSettings();
+        this.widget.widgetLabel = widgetLabel;
+        this.widget.widgetName = widgetName;
+        this.widget.config = [];
+        if (withColors) {
+        this.requiredColorParameter(WidgetConfigBuilder.BACKGROUND_COLOR_KEY, "Background color", "The background" +
+            " color", "#1B1464");
+        this.requiredColorParameter(WidgetConfigBuilder.PRIMARY_TEXT_COLOR_KEY, "Primary text color", "The" +
+                " primary text color", "#FFFFFF");
+        this.requiredColorParameter(WidgetConfigBuilder.SECONDARY_TEXT_COLOR_KEY, "Secondary text color", "The" +
+            " secondary text" +
+            " color", "#bebebe")
+        }
+        if (withTitlePanel) {
+        this.requiredTextParameter(WidgetConfigBuilder.TITLE_KEY, "Title", "The title")
+        }
+    }
+
+    static create(widgetName: string, widgetLabel: string): WidgetConfigBuilder {
+        return new WidgetConfigBuilder(widgetName, widgetLabel);
+    }
+
+    static createWithSelectableColors(widgetName: string, widgetLabel: string): WidgetConfigBuilder {
+        return new WidgetConfigBuilder(widgetName, widgetLabel, true);
+    }
+
+    static createWithSelectableColorsAndTitlePanel(widgetName: string, widgetLabel: string): WidgetConfigBuilder {
+        return new WidgetConfigBuilder(widgetName, widgetLabel, true, true);
+    }
+
+    requiredTextParameter(id: string, label: string, description: string): WidgetConfigBuilder {
+        let fst: FreeTextStaticProperty = this.prepareStaticProperty(id, label, description, Datatypes.String.toUri())
+        this.widget.config.push(fst);
+        return this;
+    }
+
+    requiredColorParameter(id: string, label: string, description: string, defaultColor?: string): WidgetConfigBuilder {
+        let csp = new ColorPickerStaticProperty();
+        csp.internalName = id;
+        csp.label = label;
+        csp.description = description;
+        if (defaultColor) {
+            csp.selectedColor = defaultColor;
+        }
+        this.widget.config.push(csp);
+        return this;
+    }
+
+
+    requiredIntegerParameter(id: string, label: string, description: string): WidgetConfigBuilder {
+        let fst: FreeTextStaticProperty = this.prepareStaticProperty(id, label, description, Datatypes.Integer.toUri())
+        this.widget.config.push(fst);
+        return this;
+    }
+
+    requiredFloatParameter(id: string, label: string, description: string): WidgetConfigBuilder {
+        let fst: FreeTextStaticProperty = this.prepareStaticProperty(id, label, description, Datatypes.Float.toUri())
+        this.widget.config.push(fst);
+        return this;
+    }
+
+    requiredSchema(collectedSchemaRequirements: CollectedSchemaRequirements): WidgetConfigBuilder {
+        this.widget.requiredSchema = collectedSchemaRequirements.getEventSchema();
+        this.widget.config = this.widget.config.concat(collectedSchemaRequirements.getRequiredMappingProperties());
+
+        return this;
+    }
+
+    prepareStaticProperty(id: string, label: string, description: string, datatype: string) {
+        let fst: FreeTextStaticProperty = new FreeTextStaticProperty();
+        fst.internalName = id;
+        fst.label = label;
+        fst.description = description;
+        fst.requiredDatatype = datatype;
+
+        return fst;
+    }
+
+    build(): DashboardWidgetSettings {
+        for(let i = 0; i < this.widget.config.length; i++) {
+            this.widget.config[i].index = i;
+        }
+        return this.widget;
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/registry/widget-registry.ts b/ui/src/app/data-explorer-v2/registry/widget-registry.ts
new file mode 100644
index 0000000..3c62fe6
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/registry/widget-registry.ts
@@ -0,0 +1,44 @@
+/*
+ * 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 {NumberConfig} from "../components/widgets/number/number-config";
+import {DashboardWidgetSettings} from "../../core-model/dashboard/DashboardWidgetSettings";
+import {WidgetConfig} from "../components/widgets/base/base-config";
+import {LineConfig} from "../components/widgets/line/line-config";
+import {TableConfig} from "../components/widgets/table/table-config";
+import {GaugeConfig} from "../components/widgets/gauge/gauge-config";
+import {ImageConfig} from "../components/widgets/image/image-config";
+import {AreaConfig} from "../components/widgets/area/area-config";
+
+export class WidgetRegistry {
+
+    private static availableWidgets: Array<WidgetConfig> = [
+        new NumberConfig(),
+        new LineConfig(),
+        new TableConfig(),
+        new GaugeConfig(),
+        new ImageConfig(),
+        new AreaConfig()
+    ];
+
+    static getAvailableWidgetTemplates(): Array<DashboardWidgetSettings> {
+        let widgetTemplates = new Array<DashboardWidgetSettings>();
+        this.availableWidgets.forEach(widget => widgetTemplates.push(widget.getConfig()));
+        return widgetTemplates;
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/collected-schema-requirements.ts b/ui/src/app/data-explorer-v2/sdk/collected-schema-requirements.ts
new file mode 100644
index 0000000..da96d05
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/collected-schema-requirements.ts
@@ -0,0 +1,38 @@
+/*
+ * 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 {StaticProperty} from "../../connect/model/StaticProperty";
+import {EventProperty} from "../../connect/schema-editor/model/EventProperty";
+import {EventSchema} from "../../connect/schema-editor/model/EventSchema";
+
+export class CollectedSchemaRequirements {
+
+    constructor(private requiredEventProperties: Array<EventProperty>, private requiredMappingProperties: Array<StaticProperty>) {
+
+    }
+
+    getEventSchema(): EventSchema {
+        let eventSchema = new EventSchema();
+        eventSchema.eventProperties = this.requiredEventProperties;
+        return eventSchema;
+    }
+
+    getRequiredMappingProperties(): Array<StaticProperty> {
+        return this.requiredMappingProperties;
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/ep-requirements.ts b/ui/src/app/data-explorer-v2/sdk/ep-requirements.ts
new file mode 100644
index 0000000..b298a7a
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/ep-requirements.ts
@@ -0,0 +1,68 @@
+/*
+ * 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 {EventProperty} from "../../connect/schema-editor/model/EventProperty";
+import {EventPropertyPrimitive} from "../../connect/schema-editor/model/EventPropertyPrimitive";
+import {Datatypes} from "./model/datatypes";
+
+export class EpRequirements {
+
+    private static ep(): EventPropertyPrimitive {
+        let ep = new EventPropertyPrimitive(undefined, undefined);
+        return ep;
+    }
+
+    static anyProperty(): EventProperty {
+        return EpRequirements.ep();
+    }
+
+    static imageReq(): EventProperty {
+        return EpRequirements.domainPropertyReq("https://image.com");
+    }
+
+    static timestampReq(): EventProperty {
+        return EpRequirements.domainPropertyReq("http://schema.org/DateTime");
+    }
+
+    static numberReq(): EventProperty {
+        return EpRequirements.datatypeReq(Datatypes.Number);
+    }
+
+    static stringReq(): EventProperty {
+        return EpRequirements.datatypeReq(Datatypes.String);
+    }
+
+    static integerReq(): EventProperty {
+        return EpRequirements.datatypeReq(Datatypes.Integer);
+    }
+
+    static domainPropertyReq(domainProperty: string): EventPropertyPrimitive {
+        let eventProperty = EpRequirements.ep();
+        eventProperty.setDomainProperty(domainProperty);
+        return eventProperty;
+
+    }
+
+    static datatypeReq(datatype: Datatypes): EventPropertyPrimitive {
+        let eventProperty = EpRequirements.ep();
+        eventProperty.setRuntimeType(datatype.toUri());
+        return eventProperty;
+}
+
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/extractor/static-property-extractor.ts b/ui/src/app/data-explorer-v2/sdk/extractor/static-property-extractor.ts
new file mode 100644
index 0000000..93d0adb
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/extractor/static-property-extractor.ts
@@ -0,0 +1,78 @@
+/*
+ * 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 {EventSchema} from "../../../connect/schema-editor/model/EventSchema";
+import {StaticProperty} from "../../../connect/model/StaticProperty";
+import {MappingPropertyUnary} from "../../../connect/model/MappingPropertyUnary";
+import {FreeTextStaticProperty} from "../../../connect/model/FreeTextStaticProperty";
+import {ColorPickerStaticProperty} from "../../../connect/model/ColorPickerStaticProperty";
+import {MappingPropertyNary} from "../../../connect/model/MappingPropertyNary";
+
+export class StaticPropertyExtractor {
+
+    constructor(private inputSchema: EventSchema,
+                private staticProperties: Array<StaticProperty>) {
+
+    }
+
+    hasStaticProperty(internalId: string): boolean {
+        return this.getStaticPropertyByName(internalId) !== undefined;
+    }
+
+    mappingPropertyValue(internalId: string): string {
+        let sp: MappingPropertyUnary = this.getStaticPropertyByName(internalId) as MappingPropertyUnary;
+        return this.removePrefix(sp.selectedProperty);
+    }
+
+    mappingPropertyValues(internalId: string): Array<string> {
+        let sp: MappingPropertyNary = this.getStaticPropertyByName(internalId) as MappingPropertyNary;
+        let properties: Array<string> = [];
+        sp.selectedProperties.forEach(ep => {
+           properties.push(this.removePrefix(ep));
+        });
+        return properties;
+    }
+
+    singleValueParameter(internalId: string): any {
+        let sp: FreeTextStaticProperty = this.getStaticPropertyByName(internalId) as FreeTextStaticProperty;
+        return sp.value;
+    }
+
+    selectedColor(internalId: string): any {
+        let sp: ColorPickerStaticProperty = this.getStaticPropertyByName(internalId) as ColorPickerStaticProperty;
+        return sp.selectedColor;
+    }
+
+    stringParameter(internalId: string): string {
+        return this.singleValueParameter(internalId) as string;
+    }
+
+    integerParameter(internalId: string): number {
+        return this.singleValueParameter(internalId) as number;
+    }
+
+    getStaticPropertyByName(internalId: string): StaticProperty {
+        return this.staticProperties.find(sp => (sp.internalName == internalId));
+    }
+
+
+    removePrefix(propertyValue: string) {
+        return propertyValue.split("::").length > 1 ? propertyValue.split("::")[1] : propertyValue;
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/matching/datatype-match.ts b/ui/src/app/data-explorer-v2/sdk/matching/datatype-match.ts
new file mode 100644
index 0000000..5b71398
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/matching/datatype-match.ts
@@ -0,0 +1,44 @@
+/*
+ * 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 {Datatypes} from "../model/datatypes";
+
+export class DatatypeMatch {
+
+    match(datatypeRequirement: string, datatypeOffer: string) {
+        if (datatypeRequirement == undefined) {
+            return true;
+        } else {
+            return (datatypeRequirement == datatypeOffer) || this.subClassOf(datatypeOffer, datatypeRequirement);
+        }
+    }
+
+    subClassOf(offer: string, requirement: string): boolean {
+        if (!(requirement === (Datatypes.Number.toUri()))){
+          return false;
+        }
+        else {
+            if (offer === Datatypes.Integer.toUri()
+                || offer === Datatypes.Long.toUri()
+                || offer === Datatypes.Double.toUri()
+                || offer === Datatypes.Float.toUri())
+                return true;
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/matching/domain-property-match.ts b/ui/src/app/data-explorer-v2/sdk/matching/domain-property-match.ts
new file mode 100644
index 0000000..836df01
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/matching/domain-property-match.ts
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ *
+ */
+
+export class DomainPropertyMatch {
+
+    match(domainPropertyRequirement: string, domainPropertyOffer: string) {
+        if (domainPropertyRequirement == undefined) {
+            return true;
+        } else {
+            return domainPropertyRequirement == domainPropertyOffer;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/matching/mapping-property-generator.ts b/ui/src/app/data-explorer-v2/sdk/matching/mapping-property-generator.ts
new file mode 100644
index 0000000..3f47e1c
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/matching/mapping-property-generator.ts
@@ -0,0 +1,46 @@
+/*
+ * 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 {EventProperty} from "../../../connect/schema-editor/model/EventProperty";
+import {PropertyMatch} from "./property-match";
+
+export class MappingPropertyGenerator {
+
+    private selector: string = "s0";
+    private separator: string = "::";
+
+    constructor(private requiredEventProperty: EventProperty, private providedEventProperties: Array<EventProperty>) {
+
+    }
+
+    computeMatchingProperties(): Array<string> {
+        let mapsFromOptions: Array<string> = [];
+
+        this.providedEventProperties.forEach(ep => {
+           if (new PropertyMatch().match(this.requiredEventProperty, ep)) {
+               mapsFromOptions.push(this.makeSelector(ep.runtimeName));
+           }
+        });
+
+        return mapsFromOptions;
+    }
+
+    makeSelector(runtimeName: string): string {
+        return this.selector + this.separator + runtimeName;
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/matching/primitive-property-match.ts b/ui/src/app/data-explorer-v2/sdk/matching/primitive-property-match.ts
new file mode 100644
index 0000000..6fadf06
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/matching/primitive-property-match.ts
@@ -0,0 +1,33 @@
+/*
+ * 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 {EventPropertyPrimitive} from "../../../connect/schema-editor/model/EventPropertyPrimitive";
+import {DatatypeMatch} from "./datatype-match";
+import {DomainPropertyMatch} from "./domain-property-match";
+
+export class PrimitivePropertyMatch {
+
+    match(requirement: EventPropertyPrimitive, offer: EventPropertyPrimitive) {
+        if (requirement != undefined) {
+            return new DatatypeMatch().match(requirement.runtimeType, offer.runtimeType) &&
+                new DomainPropertyMatch().match(requirement.domainProperty, offer.domainProperty);
+        } else {
+            return true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/matching/property-match.ts b/ui/src/app/data-explorer-v2/sdk/matching/property-match.ts
new file mode 100644
index 0000000..29e145c
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/matching/property-match.ts
@@ -0,0 +1,32 @@
+/*
+ * 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 {EventProperty} from "../../../connect/schema-editor/model/EventProperty";
+import {EventPropertyPrimitive} from "../../../connect/schema-editor/model/EventPropertyPrimitive";
+import {PrimitivePropertyMatch} from "./primitive-property-match";
+
+export class PropertyMatch {
+
+    match(requirement: EventProperty, offer: EventProperty): boolean {
+        if (requirement instanceof EventPropertyPrimitive && offer instanceof EventPropertyPrimitive) {
+            return new PrimitivePropertyMatch().match(requirement, offer);
+        } else {
+            return false;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/model/datatypes.ts b/ui/src/app/data-explorer-v2/sdk/model/datatypes.ts
new file mode 100644
index 0000000..a990e63
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/model/datatypes.ts
@@ -0,0 +1,40 @@
+/*
+ * 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 {Vocabulary} from "./vocabulary";
+
+export class Datatypes {
+
+    static readonly Integer = new Datatypes(Vocabulary.XSD, "integer");
+    static readonly Long = new Datatypes(Vocabulary.XSD, "long");
+    static readonly Float = new Datatypes(Vocabulary.XSD, "float");
+    static readonly Boolean = new Datatypes(Vocabulary.XSD, "boolean");
+    static readonly String = new Datatypes(Vocabulary.XSD, "string");
+    static readonly Double = new Datatypes(Vocabulary.XSD, "double");
+    static readonly Number = new Datatypes(Vocabulary.SO, "Number");
+
+    private constructor(private readonly vocabulary: string, private readonly entity: string ) {
+
+    }
+
+    toUri() {
+        return this.vocabulary + this.entity;
+    }
+
+
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/model/vocabulary.ts b/ui/src/app/data-explorer-v2/sdk/model/vocabulary.ts
new file mode 100644
index 0000000..175377b
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/model/vocabulary.ts
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ *
+ */
+
+export class Vocabulary {
+
+    static readonly XSD: string = "http://www.w3.org/2001/XMLSchema#";
+    static readonly SO: string = "http://schema.org/";
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/sdk/schema-requirements-builder.ts b/ui/src/app/data-explorer-v2/sdk/schema-requirements-builder.ts
new file mode 100644
index 0000000..ad0c14e
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/sdk/schema-requirements-builder.ts
@@ -0,0 +1,69 @@
+/*
+ * 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 {EventProperty} from "../../connect/schema-editor/model/EventProperty";
+import {StaticProperty} from "../../connect/model/StaticProperty";
+import {CollectedSchemaRequirements} from "./collected-schema-requirements";
+import {MappingPropertyUnary} from "../../connect/model/MappingPropertyUnary";
+import {MappingPropertyNary} from "../../connect/model/MappingPropertyNary";
+
+export class SchemaRequirementsBuilder {
+
+    private requiredEventProperties: Array<EventProperty>;
+    private staticProperties: Array<StaticProperty>;
+
+    private constructor() {
+        this.requiredEventProperties = [];
+        this.staticProperties = [];
+    }
+
+    static create(): SchemaRequirementsBuilder {
+        return new SchemaRequirementsBuilder();
+    }
+
+    requiredPropertyWithUnaryMapping(internalId: string, label: string, description: string, eventProperty: EventProperty): SchemaRequirementsBuilder {
+        eventProperty.setRuntimeName(internalId);
+        let mp = this.makeMappingProperty(internalId, label, description, new MappingPropertyUnary());
+
+        this.staticProperties.push(mp);
+        this.requiredEventProperties.push(eventProperty);
+
+        return this;
+    }
+
+    requiredPropertyWithNaryMapping(internalId: string, label: string, description: string, eventProperty: EventProperty): SchemaRequirementsBuilder {
+        eventProperty.setRuntimeName(internalId);
+        let mp = this.makeMappingProperty(internalId, label, description, new MappingPropertyNary());
+
+        this.staticProperties.push(mp);
+        this.requiredEventProperties.push(eventProperty);
+
+        return this;
+    }
+
+    makeMappingProperty(internalId: string, label: string, description: string, sp: StaticProperty): StaticProperty {
+        sp.internalName = internalId;
+        sp.label = label;
+        sp.description = description;
+        return sp;
+    }
+
+    build() {
+        return new CollectedSchemaRequirements(this.requiredEventProperties, this.staticProperties);
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/services/dashboard.service.ts b/ui/src/app/data-explorer-v2/services/dashboard.service.ts
new file mode 100644
index 0000000..2f97107
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/services/dashboard.service.ts
@@ -0,0 +1,137 @@
+/*
+ * 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 {HttpClient, HttpHeaders} from "@angular/common/http";
+import {Injectable} from "@angular/core";
+import {map} from "rxjs/operators";
+import {from, Observable} from "rxjs";
+import {AuthStatusService} from "../../services/auth-status.service";
+import {Dashboard} from "../models/dashboard.model";
+import {EventSchema} from "../../connect/schema-editor/model/EventSchema";
+import {EventProperty} from "../../connect/schema-editor/model/EventProperty";
+import {EventPropertyPrimitive} from "../../connect/schema-editor/model/EventPropertyPrimitive";
+import {TsonLdSerializerService} from "../../platform-services/tsonld-serializer.service";
+import {StatusMessage} from "../../connect/model/message/StatusMessage";
+import {RuntimeOptionsResponse} from "../../connect/model/connect/runtime/RuntimeOptionsResponse";
+import {DashboardWidget} from "../../core-model/dashboard/DashboardWidget";
+import {VisualizablePipeline} from "../../core-model/dashboard/VisualizablePipeline";
+
+@Injectable()
+export class DashboardService {
+
+
+    constructor(private http: HttpClient, 
+                private authStatusService: AuthStatusService,
+                private tsonLdSerializerService: TsonLdSerializerService,) {
+    }
+
+    getVisualizablePipelines(): Observable<Array<VisualizablePipeline>> {
+        return this.http
+            .get(this.visualizablePipelineUrl)
+            .map(data => {
+                return this.tsonLdSerializerService.fromJsonLdContainer(data, 'sp:VisualizablePipeline')
+            });
+    }
+
+    getDashboards(): Observable<Array<Dashboard>> {
+        return this.http.get(this.dashboardUrl).map(data => {
+           return data as Dashboard[];
+        });
+    }
+
+    updateDashboard(dashboard: Dashboard): Observable<Dashboard> {
+        return this.http.put(this.dashboardUrl + "/" +dashboard._id, dashboard).map(data => {
+            return data as Dashboard;
+        });
+    }
+
+    deleteDashboard(dashboard: Dashboard): Observable<any> {
+        return this.http.delete(this.dashboardUrl + "/" +dashboard._id);
+    }
+
+    saveDashboard(dashboard: Dashboard): Observable<any> {
+        return this.http.post(this.dashboardUrl, dashboard);
+    }
+
+    private get baseUrl() {
+        return '/streampipes-backend';
+    }
+
+    private get dashboardUrl() {
+        return this.baseUrl + '/api/v2/users/' + this.authStatusService.email + '/ld/dashboards'
+    }
+
+    private get dashboardWidgetUrl() {
+        return this.baseUrl + '/api/v2/users/' + this.authStatusService.email + '/ld/widgets'
+    }
+
+    private get visualizablePipelineUrl() {
+        return this.baseUrl + '/api/v2/users/' + this.authStatusService.email + '/ld/pipelines'
+    }
+
+    getWidget(widgetId: string): Observable<DashboardWidget> {
+        let promise = new Promise<DashboardWidget>((resolve, reject) => {
+            this.http.get(this.dashboardWidgetUrl + "/" +widgetId).subscribe(response => {
+                let dashboardWidget: DashboardWidget = this.tsonLdSerializerService.fromJsonLd(response, "sp:DashboardWidgetModel");
+                dashboardWidget.dashboardWidgetSettings.config.sort((a, b) => {
+                    return a.index - b.index;
+                });
+                resolve(dashboardWidget);
+            });
+        });
+        return from(promise);
+    }
+
+    saveWidget(widget: DashboardWidget): Observable<DashboardWidget> {
+        return this.serializeAndPost(this.dashboardWidgetUrl, widget);
+    }
+
+    deleteWidget(widgetId: string): Observable<any> {
+        return this.http.delete(this.dashboardWidgetUrl + "/" +widgetId);
+    }
+
+    updateWidget(widget: DashboardWidget): Observable<any> {
+        let promise = new Promise<DashboardWidget>((resolve, reject) => {
+            this.tsonLdSerializerService.toJsonLd(widget).subscribe(serialized => {
+                this.http.put(this.dashboardWidgetUrl + "/" +widget._id, serialized, this.jsonLdHeaders()).subscribe(result => {
+                    resolve();
+                })
+            });
+        });
+        return from(promise);
+    }
+
+    serializeAndPost(url: string, object: any): Observable<DashboardWidget> {
+        let promise = new Promise<DashboardWidget>((resolve, reject) => {
+            this.tsonLdSerializerService.toJsonLd(object).subscribe(serialized => {
+                this.http.post(url, serialized, this.jsonLdHeaders()).pipe(map(response => {
+                    resolve(this.tsonLdSerializerService.fromJsonLd(response, "sp:DashboardWidgetModel"));
+                })).subscribe();
+            });
+        });
+        return from(promise);
+    }
+
+    jsonLdHeaders(): any {
+        return {
+            headers: new HttpHeaders({
+                'Content-Type': 'application/ld+json',
+            }),
+        };
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/services/refresh-dashboard.service.ts b/ui/src/app/data-explorer-v2/services/refresh-dashboard.service.ts
new file mode 100644
index 0000000..4f9c0e3
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/services/refresh-dashboard.service.ts
@@ -0,0 +1,30 @@
+/*
+ * 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 {Injectable} from "@angular/core";
+import {ReplaySubject} from "rxjs";
+
+@Injectable()
+export class RefreshDashboardService {
+
+    public refreshSubject: ReplaySubject<string> = new ReplaySubject<string>();
+
+    public notify(currentDashboard: string): void {
+        this.refreshSubject.next(currentDashboard);
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/services/resize.service.ts b/ui/src/app/data-explorer-v2/services/resize.service.ts
new file mode 100644
index 0000000..9c53041
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/services/resize.service.ts
@@ -0,0 +1,31 @@
+/*
+ * 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 {ReplaySubject} from "rxjs";
+import {Injectable} from "@angular/core";
+import {GridsterInfo} from "../models/gridster-info.model";
+
+@Injectable()
+export class ResizeService {
+
+    public resizeSubject: ReplaySubject<GridsterInfo> = new ReplaySubject<GridsterInfo>();
+
+    public notify(info: GridsterInfo): void {
+        this.resizeSubject.next(info);
+    }
+}
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/services/websocket.config.ts b/ui/src/app/data-explorer-v2/services/websocket.config.ts
new file mode 100644
index 0000000..d58c891
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/services/websocket.config.ts
@@ -0,0 +1,36 @@
+/*
+ * 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 {InjectableRxStompConfig} from "@stomp/ng2-stompjs";
+import {WebsocketSettings} from "./websocket.settings";
+
+export const streamPipesStompConfig: InjectableRxStompConfig = {
+
+    brokerURL: new WebsocketSettings().getBrokerUrl(),
+
+    connectHeaders: {
+        login: 'admin',
+        passcode: 'admin'
+    },
+
+    heartbeatIncoming: 0,
+    heartbeatOutgoing: 20000,
+
+    reconnectDelay: 200,
+
+};
\ No newline at end of file
diff --git a/ui/src/app/data-explorer-v2/services/websocket.settings.ts b/ui/src/app/data-explorer-v2/services/websocket.settings.ts
new file mode 100644
index 0000000..9503872
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/services/websocket.settings.ts
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ *
+ */
+
+export class WebsocketSettings {
+
+    getBrokerUrl(): string {
+        return this.getWebsocketScheme() + "//" + location.host + "/streampipes/ws";
+    }
+
+    getWebsocketScheme(): string {
+        if (location.protocol === 'https:') {
+            return "wss:";
+        } else {
+            return "ws:";
+        }
+    }
+}
\ No newline at end of file