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/05/23 20:55:54 UTC

[incubator-streampipes] branch STREAMPIPES-79 updated: Add download dialog to 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


The following commit(s) were added to refs/heads/STREAMPIPES-79 by this push:
     new 0d18165  Add download dialog to new data explorer
0d18165 is described below

commit 0d181657a1b45987710f33742a49376c5b5c8740
Author: Philipp Zehnder <ze...@fzi.de>
AuthorDate: Sat May 23 22:55:23 2020 +0200

    Add download dialog to new data explorer
---
 .../datadownloadDialog/dataDownload.dialog.css     |  56 ++++++
 .../datadownloadDialog/dataDownload.dialog.html    | 100 +++++++++++
 .../datadownloadDialog/dataDownload.dialog.ts      | 198 +++++++++++++++++++++
 .../widgets/base/base-data-explorer-widget.ts      |  22 ++-
 .../widgets/image/image-widget.component.html      |   3 +
 .../widgets/image/image-widget.component.ts        |   5 +-
 .../line-chart/line-chart-widget.component.html    |   3 +
 .../line-chart/line-chart-widget.component.ts      |   2 +-
 .../widgets/table/table-widget.component.html      |   3 +
 .../widgets/table/table-widget.component.ts        |   5 +-
 .../data-explorer-v2/data-explorer-v2.module.ts    |   7 +-
 11 files changed, 388 insertions(+), 16 deletions(-)

diff --git a/ui/src/app/data-explorer-v2/components/datadownloadDialog/dataDownload.dialog.css b/ui/src/app/data-explorer-v2/components/datadownloadDialog/dataDownload.dialog.css
new file mode 100644
index 0000000..c503893
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/datadownloadDialog/dataDownload.dialog.css
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ *
+ */
+
+example-radio-group {
+    display: flex;
+    flex-direction: column;
+    margin: 15px 0;
+}
+.example-radio-button {
+    margin: 5px;
+    width: 100%;
+}
+
+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;
+}
diff --git a/ui/src/app/data-explorer-v2/components/datadownloadDialog/dataDownload.dialog.html b/ui/src/app/data-explorer-v2/components/datadownloadDialog/dataDownload.dialog.html
new file mode 100644
index 0000000..b9d424e
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/datadownloadDialog/dataDownload.dialog.html
@@ -0,0 +1,100 @@
+<!--
+  ~ 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>Download Data</h2>
+        <span fxFlex></span>
+        <button mat-icon-button (click)="exitDialog()">
+            <i class="material-icons">close</i>
+        </button>
+    </div>
+</mat-toolbar>
+
+<div mat-dialog-content class="md-dialog-content">
+
+
+    <mat-horizontal-stepper  #stepper>
+        <mat-step>
+            <ng-template matStepLabel>Select Data</ng-template>
+            <div>
+                <mat-radio-group class="example-radio-group" [(ngModel)]="selectedData">
+<!--                    <mat-radio-button value="visible" class="example-radio-button">-->
+<!--                        Visible data in charts-->
+<!--                    </mat-radio-button>-->
+                    <mat-radio-button value="all" class="example-radio-button">
+                        All data in database
+                    </mat-radio-button>
+                    <mat-radio-button value="customInterval" class="example-radio-button">
+                        All data in custom time interval
+                    </mat-radio-button>
+                </mat-radio-group>
+                <div fxLayout="row" fxLayoutAlign="start center" style="margin-left: 35px">
+                    <mat-form-field style="top: -10px; width: 270px">
+                        <input matInput [owlDateTime]="dt1" [owlDateTimeTrigger]="dt1"
+                               [(ngModel)]="dateRange" [selectMode]="'range'" [disabled]="selectedData !== 'customInterval'">
+                        <mat-icon matSuffix [owlDateTimeTrigger]="dt1" *ngIf="selectedData === 'customInterval'">event</mat-icon>
+                        <mat-icon matSuffix style="color: #e0e0e0" *ngIf="selectedData !== 'customInterval'">event</mat-icon>
+                        <owl-date-time #dt1></owl-date-time>
+                    </mat-form-field>
+                </div>
+            </div>
+        </mat-step>
+
+
+
+        <mat-step>
+            <ng-template matStepLabel>Select Format</ng-template>
+            <div>
+                <mat-radio-group class="example-radio-group" [(ngModel)]="downloadFormat">
+                    <mat-radio-button value="json" class="example-radio-button">
+                        JSON
+                    </mat-radio-button>
+                    <mat-radio-button value="csv" class="example-radio-button">
+                        CSV
+                    </mat-radio-button>
+                </mat-radio-group>
+            </div>
+        </mat-step>
+
+
+
+
+
+        <mat-step>
+            <ng-template matStepLabel>Download</ng-template>
+            <div div fxLayout="column" fxLayoutAlign="space-around center" *ngIf="!downloadFinish">
+                <mat-spinner></mat-spinner>
+                <label *ngIf="downloadedMBs !== undefined">{{downloadedMBs      | number : '1.0-2' }} Mb</label>
+                <button mat-button warn  color="warn" (click)="cancelDownload()">Cancel</button>
+            </div>
+            <div div fxLayout="column" fxLayoutAlign="space-around center" *ngIf="downloadFinish">
+                <mat-icon style="font-size: 100px;height: 100px; width: 100px; color:#b3b3b3;">check</mat-icon>
+            </div>
+        </mat-step>
+    </mat-horizontal-stepper>
+
+</div>
+
+<mat-divider></mat-divider>
+<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
+    <button mat-button *ngIf="stepper.selectedIndex == 1" color="primary" (click)="previousStep()">Previous</button>
+    <button mat-button mat-raised-button *ngIf="stepper.selectedIndex < 1" color="primary" (click)="nextStep()">Next</button>
+    <button mat-button mat-raised-button *ngIf="stepper.selectedIndex == 1" color="accent" (click)="downloadData()">Download</button>
+    <button mat-button mat-raised-button *ngIf="downloadFinish" color="primary" (click)="exitDialog()">Close</button>
+</div>
diff --git a/ui/src/app/data-explorer-v2/components/datadownloadDialog/dataDownload.dialog.ts b/ui/src/app/data-explorer-v2/components/datadownloadDialog/dataDownload.dialog.ts
new file mode 100644
index 0000000..e434e8b
--- /dev/null
+++ b/ui/src/app/data-explorer-v2/components/datadownloadDialog/dataDownload.dialog.ts
@@ -0,0 +1,198 @@
+/*
+ * 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 { HttpEventType } from '@angular/common/http';
+import { Component, Inject, ViewChild } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { MatStepper } from '@angular/material/stepper';
+import { DatalakeRestService } from '../../../core-services/datalake/datalake-rest.service';
+
+@Component({
+    selector: 'sp-data-download-dialog',
+    templateUrl: 'dataDownload.dialog.html',
+    styleUrls: ['./dataDownload.dialog.css']
+})
+// tslint:disable-next-line:component-class-suffix
+export class DataDownloadDialog {
+
+
+    downloadFormat = 'csv';
+    selectedData = 'visible';
+    downloadFinish = false;
+    downloadedMBs: number = undefined;
+
+    @ViewChild('stepper', { static: true }) stepper: MatStepper;
+
+    downloadHttpRequestSubscribtion;
+
+    dateRange: Date [] = []; // [0] start, [1] end
+
+
+    constructor(public dialogRef: MatDialogRef<DataDownloadDialog>,
+                @Inject(MAT_DIALOG_DATA) public data, private restService: DatalakeRestService, ) {
+        this.dateRange[0] = new Date();
+        this.dateRange[1] = new Date(this.dateRange[0].getTime() + 60000 * 60 * 24);
+    }
+
+    downloadData() {
+        this.nextStep();
+        switch (this.selectedData) {
+            case 'visible':
+
+              // TODO check if I can remove this
+                // if (this.data.yAxesKeys === undefined) {
+                //     this.createFile('', this.downloadFormat, this.data.index, this.getDateString(this.data.date[0]),
+                //       this.getDateString((this.data.date[1])));
+                //
+                // } else if (this.data.data['headers'] !== undefined) {
+                //  // Single Data
+                //     const result = this.convertData(this.data.data, this.downloadFormat, this.data.xAxesKey, this.data.yAxesKeys);
+                //     this.createFile(result, this.data.downloadFormat, this.data.index, this.getDateString(this.data.date[0]),
+                //       this.getDateString(this.data.date[1]));
+                // } else {
+                //     // group data
+                //     Object.keys(this.data.data.dataResults).forEach( groupName => {
+                //         const dataResult = this.data.data.dataResults[groupName];
+                //         const result = this.convertData(dataResult, this.downloadFormat, this.data.xAxesKey, this.data.yAxesKeys);
+                //         const fileName = this.data.index + ' ' + groupName;
+                //         this.createFile(result, this.data.downloadFormat, fileName, this.getDateString(this.data.date[0]),
+                //           this.getDateString(this.data.date[1]));
+                //     });
+                //
+                // }
+                // this.downloadFinish = true;
+                // break;
+            case 'all':
+                this.performRequest(this.restService.downloadRowData(this.data.index, this.downloadFormat), '', '');
+                break;
+            case 'customInterval':
+                this.performRequest(this.restService.downloadRowDataTimeInterval(this.data.index, this.downloadFormat,
+                    this.dateRange[0].getTime(), this.dateRange[1].getTime()), this.getDateString(this.dateRange[0]),
+                  this.getDateString(this.dateRange[1]));
+
+        }
+    }
+
+    performRequest(request, startDate, endDate) {
+        this.downloadHttpRequestSubscribtion = request.subscribe(event => {
+            // progress
+            if (event.type === HttpEventType.DownloadProgress) {
+                this.downloadedMBs = event.loaded / 1024 / 1014;
+            }
+
+            // finished
+            if (event.type === HttpEventType.Response) {
+                this.createFile(event.body, this.downloadFormat, this.data.index, startDate, endDate);
+                this.downloadFinish = true;
+            }
+        });
+    }
+
+    convertData(data, format, xAxesKey, yAxesKeys) {
+        const indexXKey = data.headers.findIndex(headerName => headerName === xAxesKey);
+        const indicesYKeys = [];
+        yAxesKeys.forEach(key => {
+            indicesYKeys.push(data.headers.findIndex(headerName => headerName === key));
+        });
+
+        if (format === 'json') {
+            const resultJson = [];
+
+
+            data.rows.forEach(row => {
+                const tmp = {'time': new Date(row[indexXKey]).getTime()};
+                indicesYKeys.forEach(index => {
+                    if (row[index] !== undefined) {
+                        tmp[data.headers[index]] = row[index];
+                    }
+                });
+                resultJson.push(tmp);
+            });
+
+            return JSON.stringify(resultJson);
+        } else {
+            // CSV
+            let resultCsv = '';
+
+            // header
+            resultCsv += xAxesKey;
+            yAxesKeys.forEach(key => {
+                resultCsv += ';';
+                resultCsv += key;
+            });
+
+
+            // content
+            data.rows.forEach(row => {
+                resultCsv += '\n';
+                resultCsv += new Date(row[indexXKey]).getTime();
+                indicesYKeys.forEach(index => {
+                    resultCsv += ';';
+                    if (row[index] !== undefined) {
+                        resultCsv += row[index];
+                    }
+                });
+            });
+
+            return resultCsv;
+        }
+    }
+
+    createFile(data, format, fileName, startDate, endDate) {
+        const a = document.createElement('a');
+        document.body.appendChild(a);
+        a.style.display = 'display: none';
+
+        // let name = 'sp_' + startDate + '_' + endDate + '_' + fileName + '.' + this.downloadFormat;
+        let name = 'sp_' + startDate + '_' + fileName + '.' + this.downloadFormat;
+        name = name.replace('__', '_');
+
+        const url = window.URL.createObjectURL(new Blob([String(data)], { type: 'data:text/' + format + ';charset=utf-8' }));
+        a.href = url;
+        a.download = name;
+        a.click();
+        window.URL.revokeObjectURL(url);
+    }
+
+    cancelDownload() {
+        try {
+            this.downloadHttpRequestSubscribtion.unsubscribe();
+        } finally {
+            this.exitDialog();
+        }
+    }
+
+
+    exitDialog(): void {
+        this.dialogRef.close();
+    }
+
+    nextStep() {
+        this.stepper.next();
+    }
+
+    previousStep() {
+        this.stepper.previous();
+    }
+
+    getDateString(date: Date) {
+        return date.toLocaleDateString() + 'T' + date.toLocaleTimeString().replace(':', '.')
+                                                                          .replace(':', '.');
+    }
+
+}
diff --git a/ui/src/app/data-explorer-v2/components/widgets/base/base-data-explorer-widget.ts b/ui/src/app/data-explorer-v2/components/widgets/base/base-data-explorer-widget.ts
index 59d0007..bc87317 100644
--- a/ui/src/app/data-explorer-v2/components/widgets/base/base-data-explorer-widget.ts
+++ b/ui/src/app/data-explorer-v2/components/widgets/base/base-data-explorer-widget.ts
@@ -17,6 +17,7 @@
  */
 
 import { EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
 import { GridsterItem, GridsterItemComponent } from 'angular-gridster2';
 import { EventProperty } from '../../../../connect/schema-editor/model/EventProperty';
 import { EventPropertyPrimitive } from '../../../../connect/schema-editor/model/EventPropertyPrimitive';
@@ -25,10 +26,11 @@ import { DataExplorerWidgetModel } from '../../../../core-model/datalake/DataExp
 import { DateRange } from '../../../../core-model/datalake/DateRange';
 import { DatalakeRestService } from '../../../../core-services/datalake/datalake-rest.service';
 import { IDataViewDashboardItem } from '../../../models/dataview-dashboard.model';
+import { DataDownloadDialog } from '../../datadownloadDialog/dataDownload.dialog';
 
 export abstract class BaseDataExplorerWidget implements OnChanges {
 
-  protected constructor(protected dataLakeRestService: DatalakeRestService) {
+  protected constructor(protected dataLakeRestService: DatalakeRestService, protected dialog: MatDialog) {
   }
 
   @Output()
@@ -51,13 +53,14 @@ export abstract class BaseDataExplorerWidget implements OnChanges {
   public showData: boolean;
   public showIsLoadingData: boolean;
 
-
   public removeWidget() {
     this.removeWidgetCallback.emit(true);
   }
 
   public setShownComponents(showNoDataInDateRange: boolean,
-                            showData: boolean, showIsLoadingData: boolean) {
+                            showData: boolean,
+                            showIsLoadingData: boolean,
+                            ) {
 
     this.showNoDataInDateRange = showNoDataInDateRange;
     this.showData = showData;
@@ -119,7 +122,7 @@ export abstract class BaseDataExplorerWidget implements OnChanges {
   }
 
   getRuntimeNames(properties: EventProperty[]): string[] {
-    const result = []
+    const result = [];
     properties.forEach(p => {
         result.push(p.runtimeName);
     });
@@ -127,10 +130,13 @@ export abstract class BaseDataExplorerWidget implements OnChanges {
     return result;
   }
 
+  downloadDataAsFile() {
+    const dialogRef = this.dialog.open(DataDownloadDialog, {
+      width: '600px',
+      data: { index: this.dataExplorerWidget.dataLakeMeasure.measureName, date: this.viewDateRange },
+      panelClass: 'custom-dialog-container'
 
-
-  // updateDataExplorerWidget() {
-  //   this.
-  // }
+    });
+  }
 
 }
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
index 5dcac03..b84b9f1 100644
--- 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
@@ -21,6 +21,9 @@
     <div class="assemblyOptionsDataExplorer sp-blue-bg m-0 row header h-40" style="margin-left: 0px;margin-right: 0px;">
         <div fxFlex="100" layout="row" fxLayoutAlign="end center" style="margin-left: 0px;margin-right: 0px;">
             <sp-select-properties (changeSelectedProperties)="setSelectedColumn($event)" [availableProperties]="availableColumns" [selectedProperties]="selectedColumns"></sp-select-properties>
+            <button mat-icon-button matTooltip="Download data" class="icon" (click)="downloadDataAsFile()" color="white">
+                <i class="material-icons">get_app</i>
+            </button>
             <button mat-button mat-icon-button color="white" (click)="removeWidget()">
                 <i class="material-icons">clear</i>
             </button>
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
index f5dd2f9..8470ebc 100644
--- 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
@@ -23,6 +23,7 @@ import { EventProperty } from '../../../../connect/schema-editor/model/EventProp
 import { DataResult } from '../../../../core-model/datalake/DataResult';
 import { DatalakeRestService } from '../../../../core-services/datalake/datalake-rest.service';
 import { BaseDataExplorerWidget } from '../base/base-data-explorer-widget';
+import { MatDialog } from '@angular/material/dialog';
 
 @Component({
   selector: 'sp-data-explorer-image-widget',
@@ -39,8 +40,8 @@ export class ImageWidgetComponent extends BaseDataExplorerWidget implements OnIn
 
   dataSource = new MatTableDataSource();
 
-  constructor(protected dataLakeRestService: DatalakeRestService) {
-    super(dataLakeRestService);
+  constructor(protected dataLakeRestService: DatalakeRestService, protected dialog: MatDialog, ) {
+    super(dataLakeRestService, dialog);
   }
 
   ngOnInit(): void {
diff --git a/ui/src/app/data-explorer-v2/components/widgets/line-chart/line-chart-widget.component.html b/ui/src/app/data-explorer-v2/components/widgets/line-chart/line-chart-widget.component.html
index b6fdd3c..12574fc 100644
--- a/ui/src/app/data-explorer-v2/components/widgets/line-chart/line-chart-widget.component.html
+++ b/ui/src/app/data-explorer-v2/components/widgets/line-chart/line-chart-widget.component.html
@@ -20,6 +20,9 @@
     <div class="assemblyOptions sp-blue-bg m-0 row header h-40" style="margin-left: 0px;margin-right: 0px;margin-top: 0px;">
         <div fxFlex="100" layout="row" fxLayoutAlign="end center" style="margin-left: 0px;margin-right: 0px;">
             <sp-select-properties (changeSelectedProperties)="setSelectedColumn($event)" [availableProperties]="availableColumns" [selectedProperties]="selectedColumns"></sp-select-properties>
+            <button mat-icon-button matTooltip="Download data" class="icon" (click)="downloadDataAsFile()" color="white">
+                <i class="material-icons">get_app</i>
+            </button>
             <button mat-button mat-icon-button color="white" (click)="removeWidget()">
                 <i class="material-icons">clear</i>
             </button>
diff --git a/ui/src/app/data-explorer-v2/components/widgets/line-chart/line-chart-widget.component.ts b/ui/src/app/data-explorer-v2/components/widgets/line-chart/line-chart-widget.component.ts
index 2a4bd0f..ed6faf3 100644
--- a/ui/src/app/data-explorer-v2/components/widgets/line-chart/line-chart-widget.component.ts
+++ b/ui/src/app/data-explorer-v2/components/widgets/line-chart/line-chart-widget.component.ts
@@ -46,7 +46,7 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
 
   constructor(public dialog: MatDialog, public plotlyService: PlotlyService, public colorService: ColorService,
               public renderer: Renderer2, protected dataLakeRestService: DatalakeRestService) {
-    super(dataLakeRestService);
+    super(dataLakeRestService, dialog);
   }
 
   // indicator variable if labeling mode is activated
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
index dd82bb9..e254464 100644
--- 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
@@ -22,6 +22,9 @@
     <div class="assemblyOptionsDataExplorer sp-blue-bg m-0 row header h-40" style="margin-left: 0px;margin-right: 0px;">
         <div fxFlex="100" layout="row" fxLayoutAlign="end center" style="margin-left: 0px;margin-right: 0px;">
             <sp-select-properties (changeSelectedProperties)="setSelectedColumn($event)" [availableProperties]="availableColumns" [selectedProperties]="selectedColumns"></sp-select-properties>
+            <button mat-icon-button matTooltip="Download data" class="icon" (click)="downloadDataAsFile()" color="white">
+                <i class="material-icons">get_app</i>
+            </button>
             <button mat-button mat-icon-button color="white" (click)="removeWidget()">
                 <i class="material-icons">clear</i>
             </button>
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
index 9c0fb99..8c7e833 100644
--- 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
@@ -17,6 +17,7 @@
  */
 
 import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
 import { MatSort } from '@angular/material/sort';
 import { MatTableDataSource } from '@angular/material/table';
 import { EventProperty } from '../../../../connect/schema-editor/model/EventProperty';
@@ -40,8 +41,8 @@ export class TableWidgetComponent extends BaseDataExplorerWidget implements OnIn
 
   dataSource = new MatTableDataSource();
 
-  constructor(protected dataLakeRestService: DatalakeRestService) {
-    super(dataLakeRestService);
+  constructor(protected dataLakeRestService: DatalakeRestService, protected dialog: MatDialog) {
+    super(dataLakeRestService, dialog);
   }
 
   ngOnInit(): void {
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
index 55ef8b6..f965ce6 100644
--- a/ui/src/app/data-explorer-v2/data-explorer-v2.module.ts
+++ b/ui/src/app/data-explorer-v2/data-explorer-v2.module.ts
@@ -48,9 +48,8 @@ import { DataExplorerDashboardOverviewComponent } from './components/overview/da
 import { DataExplorerDashboardPanelComponent } from './components/panel/data-explorer-dashboard-panel.component';
 import { TimeRangeSelectorComponent } from './components/time-selector/timeRangeSelector.component';
 import { DataExplorerDashboardWidgetComponent } from './components/widget/data-explorer-dashboard-widget.component';
+import { ImageWidgetComponent } from './components/widgets/image/image-widget.component';
 import { LineChartWidgetComponent } from './components/widgets/line-chart/line-chart-widget.component';
-// import { DataDownloadDialog } from './components/widgets/old-explorer-widget/datadownloadDialog/dataDownload.dialog';
-// import { OldExplorerComponent } from './components/widgets/old-explorer-widget/old-explorer.component';
 import { TableWidgetComponent } from './components/widgets/table/table-widget.component';
 import { LoadDataSpinnerComponent } from './components/widgets/utils/load-data-spinner/load-data-spinner.component';
 import { NoDataInDateRangeComponent } from './components/widgets/utils/no-data/no-data-in-date-range.component';
@@ -62,7 +61,7 @@ import { DataLakeService } from './services/data-lake.service';
 import { DataViewDataExplorerService } from './services/data-view-data-explorer.service';
 import { RefreshDashboardService } from './services/refresh-dashboard.service';
 import { ResizeService } from './services/resize.service';
-import {ImageWidgetComponent} from "./components/widgets/image/image-widget.component";
+import { DataDownloadDialog } from './components/datadownloadDialog/dataDownload.dialog';
 
 const dashboardWidgets = [
 
@@ -123,6 +122,7 @@ export const MY_NATIVE_FORMATS = {
     TimeRangeSelectorComponent,
     NoDataInDateRangeComponent,
     LoadDataSpinnerComponent,
+    DataDownloadDialog,
     SelectPropertiesComponent
   ],
   providers: [
@@ -156,6 +156,7 @@ export const MY_NATIVE_FORMATS = {
   entryComponents: [
     DataExplorerV2Component,
     DataExplorerAddVisualizationDialogComponent,
+    DataDownloadDialog,
     DataExplorerEditDataViewDialogComponent
   ]
 })