From db42b4cd2d16494825120d8ea9964fc5f8655f35 Mon Sep 17 00:00:00 2001 From: Tong Wang Date: Wed, 4 Jan 2017 14:15:50 -0500 Subject: [PATCH] export documents in discover tab in CSV format --- src/ui/public/doc_table/doc_table.html | 16 +++++- src/ui/public/doc_table/doc_table.js | 77 +++++++++++++++++++++++++- src/ui/public/doc_table/doc_table.less | 4 ++ 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/src/ui/public/doc_table/doc_table.html b/src/ui/public/doc_table/doc_table.html index bab9514e1d2ac..283f010c2fd73 100644 --- a/src/ui/public/doc_table/doc_table.html +++ b/src/ui/public/doc_table/doc_table.html @@ -1,8 +1,18 @@
+ ng-class="{ loading: searchSource.activeFetchCount > 0 }"> + +
+ Export:   + + Raw +     + + Formatted + +
+
@@ -109,4 +119,4 @@

No results found

-
+
\ No newline at end of file diff --git a/src/ui/public/doc_table/doc_table.js b/src/ui/public/doc_table/doc_table.js index be11e2a729b06..ff4c4e80ebab3 100644 --- a/src/ui/public/doc_table/doc_table.js +++ b/src/ui/public/doc_table/doc_table.js @@ -1,17 +1,21 @@ import _ from 'lodash'; import html from 'ui/doc_table/doc_table.html'; import { getSort } from 'ui/doc_table/lib/get_sort'; +import { saveAs } from '@elastic/filesaver'; import 'ui/doc_table/doc_table.less'; import 'ui/directives/truncated'; import 'ui/directives/infinite_scroll'; import 'ui/doc_table/components/table_header'; import 'ui/doc_table/components/table_row'; import { uiModules } from 'ui/modules'; +import { RegistryFieldFormatsProvider } from 'ui/registry/field_formats'; + import { getLimitedSearchResultsMessage } from './doc_table_strings'; uiModules.get('kibana') -.directive('docTable', function (config, Notifier, getAppState, pagerFactory, $filter) { +.directive('docTable', function (config, Notifier, getAppState, pagerFactory, $filter, Private) { + const fieldFormats = Private(RegistryFieldFormatsProvider); return { restrict: 'E', template: html, @@ -140,6 +144,77 @@ uiModules.get('kibana') $scope.shouldShowLimitedResultsWarning = () => ( !$scope.pager.hasNextPage && $scope.pager.totalItems < $scope.totalHitCount ); + + $scope.exportAsCsv = function (formatted) { + var csv = { + separator: config.get('csv:separator'), + quoteValues: config.get('csv:quoteValues') + }; + + var rows = $scope.hits; + var columns = $scope.columns; + if ($scope.indexPattern.timeFieldName) { + columns = [$scope.indexPattern.timeFieldName].concat(columns); + } + var nonAlphaNumRE = /[^a-zA-Z0-9]/; + var allDoubleQuoteRE = /"/g; + + function escape(val) { + if (_.isObject(val)) val = val.valueOf(); + val = String(val); + if (csv.quoteValues && nonAlphaNumRE.test(val)) { + val = '"' + val.replace(allDoubleQuoteRE, '""') + '"'; + } + return val; + } + + function formatField(value, name) { + var field = $scope.indexPattern.fields.byName[name]; + if (!field) return value; + var defaultFormat = fieldFormats.getDefaultType(field.type); + var formatter = (field && field.format) ? field.format : defaultFormat; + + return formatter.convert(value); + } + + function formatRow(row) { + $scope.indexPattern.flattenHit(row); + row.$$_formatted = row.$$_formatted || _.mapValues(row.$$_flattened, formatField); + return row.$$_formatted; + } + + // get column values for each row + var csvRows = rows.map(function (row, i) { + return columns.map(function (column, j) { + var val; + + if (formatted) { + val = (row.$$_formatted || formatRow(row))[column]; + } else { + val = (row.$$_flattened || formatRow(row))[column]; + } + + val = (val == null) ? '' : val; + + return val; + }); + }); + + // escape each cell in each row + csvRows = csvRows.map(function (row, i) { + return row.map(escape); + }); + + // add the columns to the rows + csvRows.unshift(columns.map(escape)); + + var data = csvRows.map(function (row) { + return row.join(csv.separator) + '\r\n'; + }).join(''); + + saveAs(new Blob([data], { type: 'text/plain' }), 'export.csv'); + }; + } }; }); diff --git a/src/ui/public/doc_table/doc_table.less b/src/ui/public/doc_table/doc_table.less index 7777ff9900c52..9ed48f08c2b2d 100644 --- a/src/ui/public/doc_table/doc_table.less +++ b/src/ui/public/doc_table/doc_table.less @@ -63,6 +63,10 @@ doc-table { z-index: 20; opacity: @loading-opacity; } + + .export { + margin: 10px; + } } /**