|
|
@@ -1,59 +1,108 @@
|
|
|
-import _ from 'lodash';
|
|
|
+import { isBoolean, isNumber, sortedUniq, sortedIndexOf, unescape as htmlUnescaped } from 'lodash';
|
|
|
import moment from 'moment';
|
|
|
import { saveAs } from 'file-saver';
|
|
|
+import { isNullOrUndefined } from 'util';
|
|
|
|
|
|
const DEFAULT_DATETIME_FORMAT = 'YYYY-MM-DDTHH:mm:ssZ';
|
|
|
const POINT_TIME_INDEX = 1;
|
|
|
const POINT_VALUE_INDEX = 0;
|
|
|
|
|
|
+const END_COLUMN = ';';
|
|
|
+const END_ROW = '\r\n';
|
|
|
+const QUOTE = '"';
|
|
|
+const EXPORT_FILENAME = 'grafana_data_export.csv';
|
|
|
+
|
|
|
+function csvEscaped(text) {
|
|
|
+ if (!text) {
|
|
|
+ return text;
|
|
|
+ }
|
|
|
+
|
|
|
+ return text.split(QUOTE).join(QUOTE + QUOTE);
|
|
|
+}
|
|
|
+
|
|
|
+const domParser = new DOMParser();
|
|
|
+function htmlDecoded(text) {
|
|
|
+ if (!text) {
|
|
|
+ return text;
|
|
|
+ }
|
|
|
+
|
|
|
+ const regexp = /&[^;]+;/g;
|
|
|
+ function htmlDecoded(value) {
|
|
|
+ const parsedDom = domParser.parseFromString(value, 'text/html');
|
|
|
+ return parsedDom.body.textContent;
|
|
|
+ }
|
|
|
+ return text.replace(regexp, htmlDecoded).replace(regexp, htmlDecoded);
|
|
|
+}
|
|
|
+
|
|
|
+function formatSpecialHeader(useExcelHeader) {
|
|
|
+ return useExcelHeader ? `sep=${END_COLUMN}${END_ROW}` : '';
|
|
|
+}
|
|
|
+
|
|
|
+function formatRow(row, addEndRowDelimiter = true) {
|
|
|
+ let text = '';
|
|
|
+ for (let i = 0; i < row.length; i += 1) {
|
|
|
+ if (isBoolean(row[i]) || isNullOrUndefined(row[i])) {
|
|
|
+ text += row[i];
|
|
|
+ } else if (isNumber(row[i])) {
|
|
|
+ text += row[i].toLocaleString();
|
|
|
+ } else {
|
|
|
+ text += `${QUOTE}${csvEscaped(htmlUnescaped(htmlDecoded(row[i])))}${QUOTE}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i < row.length - 1) {
|
|
|
+ text += END_COLUMN;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return addEndRowDelimiter ? text + END_ROW : text;
|
|
|
+}
|
|
|
+
|
|
|
export function convertSeriesListToCsv(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) {
|
|
|
- var text = (excel ? 'sep=;\n' : '') + 'Series;Time;Value\n';
|
|
|
- _.each(seriesList, function(series) {
|
|
|
- _.each(series.datapoints, function(dp) {
|
|
|
- text +=
|
|
|
- series.alias + ';' + moment(dp[POINT_TIME_INDEX]).format(dateTimeFormat) + ';' + dp[POINT_VALUE_INDEX] + '\n';
|
|
|
- });
|
|
|
- });
|
|
|
+ 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,
|
|
|
+ moment(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
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
return text;
|
|
|
}
|
|
|
|
|
|
export function exportSeriesListToCsv(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) {
|
|
|
- var text = convertSeriesListToCsv(seriesList, dateTimeFormat, excel);
|
|
|
- saveSaveBlob(text, 'grafana_data_export.csv');
|
|
|
+ let text = convertSeriesListToCsv(seriesList, dateTimeFormat, excel);
|
|
|
+ saveSaveBlob(text, EXPORT_FILENAME);
|
|
|
}
|
|
|
|
|
|
export function convertSeriesListToCsvColumns(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) {
|
|
|
- let text = (excel ? 'sep=;\n' : '') + 'Time;';
|
|
|
// add header
|
|
|
- _.each(seriesList, function(series) {
|
|
|
- text += series.alias + ';';
|
|
|
- });
|
|
|
- text = text.substring(0, text.length - 1);
|
|
|
- text += '\n';
|
|
|
-
|
|
|
+ let text =
|
|
|
+ formatSpecialHeader(excel) +
|
|
|
+ formatRow(
|
|
|
+ ['Time'].concat(
|
|
|
+ seriesList.map(function(val) {
|
|
|
+ return val.alias;
|
|
|
+ })
|
|
|
+ )
|
|
|
+ );
|
|
|
// process data
|
|
|
seriesList = mergeSeriesByTime(seriesList);
|
|
|
- var dataArr = [[]];
|
|
|
- var sIndex = 1;
|
|
|
- _.each(seriesList, function(series) {
|
|
|
- var cIndex = 0;
|
|
|
- dataArr.push([]);
|
|
|
- _.each(series.datapoints, function(dp) {
|
|
|
- dataArr[0][cIndex] = moment(dp[POINT_TIME_INDEX]).format(dateTimeFormat);
|
|
|
- dataArr[sIndex][cIndex] = dp[POINT_VALUE_INDEX];
|
|
|
- cIndex++;
|
|
|
- });
|
|
|
- sIndex++;
|
|
|
- });
|
|
|
|
|
|
// make text
|
|
|
- for (var i = 0; i < dataArr[0].length; i++) {
|
|
|
- text += dataArr[0][i] + ';';
|
|
|
- for (var j = 1; j < dataArr.length; j++) {
|
|
|
- text += dataArr[j][i] + ';';
|
|
|
- }
|
|
|
- text = text.substring(0, text.length - 1);
|
|
|
- text += '\n';
|
|
|
+ for (let i = 0; i < seriesList[0].datapoints.length; i += 1) {
|
|
|
+ const timestamp = moment(seriesList[0].datapoints[i][POINT_TIME_INDEX]).format(dateTimeFormat);
|
|
|
+ text += formatRow(
|
|
|
+ [timestamp].concat(
|
|
|
+ seriesList.map(function(series) {
|
|
|
+ return series.datapoints[i][POINT_VALUE_INDEX];
|
|
|
+ })
|
|
|
+ ),
|
|
|
+ i < seriesList[0].datapoints.length - 1
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
return text;
|
|
|
@@ -71,15 +120,15 @@ function mergeSeriesByTime(seriesList) {
|
|
|
timestamps.push(seriesPoints[j][POINT_TIME_INDEX]);
|
|
|
}
|
|
|
}
|
|
|
- timestamps = _.sortedUniq(timestamps.sort());
|
|
|
+ timestamps = sortedUniq(timestamps.sort());
|
|
|
|
|
|
for (let i = 0; i < seriesList.length; i++) {
|
|
|
let seriesPoints = seriesList[i].datapoints;
|
|
|
- let seriesTimestamps = _.map(seriesPoints, p => p[POINT_TIME_INDEX]);
|
|
|
+ let seriesTimestamps = seriesPoints.map(p => p[POINT_TIME_INDEX]);
|
|
|
let extendedSeries = [];
|
|
|
let pointIndex;
|
|
|
for (let j = 0; j < timestamps.length; j++) {
|
|
|
- pointIndex = _.sortedIndexOf(seriesTimestamps, timestamps[j]);
|
|
|
+ pointIndex = sortedIndexOf(seriesTimestamps, timestamps[j]);
|
|
|
if (pointIndex !== -1) {
|
|
|
extendedSeries.push(seriesPoints[pointIndex]);
|
|
|
} else {
|
|
|
@@ -93,27 +142,26 @@ function mergeSeriesByTime(seriesList) {
|
|
|
|
|
|
export function exportSeriesListToCsvColumns(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) {
|
|
|
let text = convertSeriesListToCsvColumns(seriesList, dateTimeFormat, excel);
|
|
|
- saveSaveBlob(text, 'grafana_data_export.csv');
|
|
|
+ saveSaveBlob(text, EXPORT_FILENAME);
|
|
|
}
|
|
|
|
|
|
-export function exportTableDataToCsv(table, excel = false) {
|
|
|
- var text = excel ? 'sep=;\n' : '';
|
|
|
- // add header
|
|
|
- _.each(table.columns, function(column) {
|
|
|
- text += (column.title || column.text) + ';';
|
|
|
- });
|
|
|
- text += '\n';
|
|
|
+export function convertTableDataToCsv(table, excel = false) {
|
|
|
+ let text = formatSpecialHeader(excel);
|
|
|
+ // add headline
|
|
|
+ text += formatRow(table.columns.map(val => val.title || val.text));
|
|
|
// process data
|
|
|
- _.each(table.rows, function(row) {
|
|
|
- _.each(row, function(value) {
|
|
|
- text += value + ';';
|
|
|
- });
|
|
|
- text += '\n';
|
|
|
- });
|
|
|
- saveSaveBlob(text, 'grafana_data_export.csv');
|
|
|
+ for (let i = 0; i < table.rows.length; i += 1) {
|
|
|
+ text += formatRow(table.rows[i], i < table.rows.length - 1);
|
|
|
+ }
|
|
|
+ return text;
|
|
|
+}
|
|
|
+
|
|
|
+export function exportTableDataToCsv(table, excel = false) {
|
|
|
+ let text = convertTableDataToCsv(table, excel);
|
|
|
+ saveSaveBlob(text, EXPORT_FILENAME);
|
|
|
}
|
|
|
|
|
|
export function saveSaveBlob(payload, fname) {
|
|
|
- var blob = new Blob([payload], { type: 'text/csv;charset=utf-8' });
|
|
|
+ let blob = new Blob([payload], { type: 'text/csv;charset=utf-8;header=present;' });
|
|
|
saveAs(blob, fname);
|
|
|
}
|