浏览代码

CSV Export: Timezone based on dashboard setting (#18002)

* Timezone export CSV based on dashboard setting

* Add options object and interface
Tobias Skarhed 6 年之前
父节点
当前提交
9e87dbb153

+ 3 - 3
public/app/core/specs/file_export.test.ts

@@ -28,7 +28,7 @@ describe('file_export', () => {
 
   describe('when exporting series as rows', () => {
     it('should export points in proper order', () => {
-      const text = fileExport.convertSeriesListToCsv(ctx.seriesList, ctx.timeFormat);
+      const text = fileExport.convertSeriesListToCsv(ctx.seriesList, { dateTimeFormat: ctx.timeFormat });
       const expectedText =
         '"Series";"Time";"Value"\r\n' +
         '"series_1";"1500026100";1\r\n' +
@@ -48,7 +48,7 @@ describe('file_export', () => {
 
   describe('when exporting series as columns', () => {
     it('should export points in proper order', () => {
-      const text = fileExport.convertSeriesListToCsvColumns(ctx.seriesList, ctx.timeFormat);
+      const text = fileExport.convertSeriesListToCsvColumns(ctx.seriesList, { dateTimeFormat: ctx.timeFormat });
       const expectedText =
         '"Time";"series_1";"series_2"\r\n' +
         '"1500026100";1;11\r\n' +
@@ -65,7 +65,7 @@ describe('file_export', () => {
       const expectedSeries1DataPoints = ctx.seriesList[0].datapoints.slice();
       const expectedSeries2DataPoints = ctx.seriesList[1].datapoints.slice();
 
-      fileExport.convertSeriesListToCsvColumns(ctx.seriesList, ctx.timeFormat);
+      fileExport.convertSeriesListToCsvColumns(ctx.seriesList, { dateTimeFormat: ctx.timeFormat });
 
       expect(expectedSeries1DataPoints).toEqual(ctx.seriesList[0].datapoints);
       expect(expectedSeries2DataPoints).toEqual(ctx.seriesList[1].datapoints);

+ 36 - 12
public/app/core/utils/file_export.ts

@@ -1,7 +1,7 @@
 import { isBoolean, isNumber, sortedUniq, sortedIndexOf, unescape as htmlUnescaped } from 'lodash';
 import { saveAs } from 'file-saver';
 import { isNullOrUndefined } from 'util';
-import { dateTime } from '@grafana/data';
+import { dateTime, TimeZone } from '@grafana/data';
 
 const DEFAULT_DATETIME_FORMAT = 'YYYY-MM-DDTHH:mm:ssZ';
 const POINT_TIME_INDEX = 1;
@@ -12,7 +12,19 @@ const END_ROW = '\r\n';
 const QUOTE = '"';
 const EXPORT_FILENAME = 'grafana_data_export.csv';
 
-function csvEscaped(text) {
+interface SeriesListToCsvColumnsOptions {
+  dateTimeFormat: string;
+  excel: boolean;
+  timezone: TimeZone;
+}
+
+const defaultOptions: SeriesListToCsvColumnsOptions = {
+  dateTimeFormat: DEFAULT_DATETIME_FORMAT,
+  excel: false,
+  timezone: '',
+};
+
+function csvEscaped(text: string) {
   if (!text) {
     return text;
   }
@@ -25,13 +37,13 @@ function csvEscaped(text) {
 }
 
 const domParser = new DOMParser();
-function htmlDecoded(text) {
+function htmlDecoded(text: string) {
   if (!text) {
     return text;
   }
 
   const regexp = /&[^;]+;/g;
-  function htmlDecoded(value) {
+  function htmlDecoded(value: string) {
     const parsedDom = domParser.parseFromString(value, 'text/html');
     return parsedDom.body.textContent;
   }
@@ -58,14 +70,19 @@ function formatRow(row, addEndRowDelimiter = true) {
   return addEndRowDelimiter ? text + END_ROW : text;
 }
 
-export function convertSeriesListToCsv(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) {
+export function convertSeriesListToCsv(seriesList, options: Partial<SeriesListToCsvColumnsOptions>) {
+  const { dateTimeFormat, excel, timezone } = { ...defaultOptions, ...options };
   let text = formatSpecialHeader(excel) + formatRow(['Series', 'Time', 'Value']);
   for (let seriesIndex = 0; seriesIndex < seriesList.length; seriesIndex += 1) {
     for (let i = 0; i < seriesList[seriesIndex].datapoints.length; i += 1) {
       text += formatRow(
         [
           seriesList[seriesIndex].alias,
-          dateTime(seriesList[seriesIndex].datapoints[i][POINT_TIME_INDEX]).format(dateTimeFormat),
+          timezone === 'utc'
+            ? dateTime(seriesList[seriesIndex].datapoints[i][POINT_TIME_INDEX])
+                .utc()
+                .format(dateTimeFormat)
+            : dateTime(seriesList[seriesIndex].datapoints[i][POINT_TIME_INDEX]).format(dateTimeFormat),
           seriesList[seriesIndex].datapoints[i][POINT_VALUE_INDEX],
         ],
         i < seriesList[seriesIndex].datapoints.length - 1 || seriesIndex < seriesList.length - 1
@@ -75,12 +92,13 @@ export function convertSeriesListToCsv(seriesList, dateTimeFormat = DEFAULT_DATE
   return text;
 }
 
-export function exportSeriesListToCsv(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) {
-  const text = convertSeriesListToCsv(seriesList, dateTimeFormat, excel);
+export function exportSeriesListToCsv(seriesList, options: Partial<SeriesListToCsvColumnsOptions>) {
+  const text = convertSeriesListToCsv(seriesList, options);
   saveSaveBlob(text, EXPORT_FILENAME);
 }
 
-export function convertSeriesListToCsvColumns(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) {
+export function convertSeriesListToCsvColumns(seriesList, options: Partial<SeriesListToCsvColumnsOptions>) {
+  const { dateTimeFormat, excel, timezone } = { ...defaultOptions, ...options };
   // add header
   let text =
     formatSpecialHeader(excel) +
@@ -96,7 +114,13 @@ export function convertSeriesListToCsvColumns(seriesList, dateTimeFormat = DEFAU
 
   // make text
   for (let i = 0; i < extendedDatapointsList[0].length; i += 1) {
-    const timestamp = dateTime(extendedDatapointsList[0][i][POINT_TIME_INDEX]).format(dateTimeFormat);
+    const timestamp =
+      timezone === 'utc'
+        ? dateTime(extendedDatapointsList[0][i][POINT_TIME_INDEX])
+            .utc()
+            .format(dateTimeFormat)
+        : dateTime(extendedDatapointsList[0][i][POINT_TIME_INDEX]).format(dateTimeFormat);
+
     text += formatRow(
       [timestamp].concat(
         extendedDatapointsList.map(datapoints => {
@@ -143,8 +167,8 @@ function mergeSeriesByTime(seriesList) {
   return result;
 }
 
-export function exportSeriesListToCsvColumns(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) {
-  const text = convertSeriesListToCsvColumns(seriesList, dateTimeFormat, excel);
+export function exportSeriesListToCsvColumns(seriesList, options: Partial<SeriesListToCsvColumnsOptions>) {
+  const text = convertSeriesListToCsvColumns(seriesList, options);
   saveSaveBlob(text, EXPORT_FILENAME);
 }
 

+ 12 - 2
public/app/features/dashboard/components/ExportDataModal/ExportDataModalCtrl.ts

@@ -1,6 +1,7 @@
 import angular from 'angular';
 import * as fileExport from 'app/core/utils/file_export';
 import appEvents from 'app/core/app_events';
+import { DashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
 
 export class ExportDataModalCtrl {
   private data: any[];
@@ -9,14 +10,23 @@ export class ExportDataModalCtrl {
   dateTimeFormat = 'YYYY-MM-DDTHH:mm:ssZ';
   excel = false;
 
+  /** @ngInject */
+  constructor(private dashboardSrv: DashboardSrv) {}
+
   export() {
+    const timezone = this.dashboardSrv.getCurrent().timezone;
+    const options = {
+      excel: this.excel,
+      dateTimeFormat: this.dateTimeFormat,
+      timezone,
+    };
     if (this.panel === 'table') {
       fileExport.exportTableDataToCsv(this.data, this.excel);
     } else {
       if (this.asRows) {
-        fileExport.exportSeriesListToCsv(this.data, this.dateTimeFormat, this.excel);
+        fileExport.exportSeriesListToCsv(this.data, options);
       } else {
-        fileExport.exportSeriesListToCsvColumns(this.data, this.dateTimeFormat, this.excel);
+        fileExport.exportSeriesListToCsvColumns(this.data, options);
       }
     }