Skip to content

Commit 57ae018

Browse files
tongwangfbaligand
authored andcommitted
export documents in discover tab in CSV format
1 parent b67ac57 commit 57ae018

File tree

3 files changed

+93
-4
lines changed

3 files changed

+93
-4
lines changed

src/ui/public/doc_table/doc_table.html

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
<div
22
class="doc-table-container"
33
ng-if="hits.length"
4-
ng-class="{ loading: searchSource.activeFetchCount > 0 }"
5-
>
4+
ng-class="{ loading: searchSource.activeFetchCount > 0 }">
5+
6+
<div class="export">
7+
<small>Export:</small>&nbsp;&nbsp;
8+
<a class="small" ng-click="exportAsCsv(false)">
9+
Raw <i aria-hidden="true" class="fa fa-download"></i>
10+
</a>&nbsp;&nbsp;&nbsp;
11+
<a class="small" ng-click="exportAsCsv(true)">
12+
Formatted <i aria-hidden="true" class="fa fa-download"></i>
13+
</a>
14+
</div>
15+
616
<div ng-if="!infiniteScroll">
717
<div class="kuiBar docTableBar">
818
<div class="kuiBarSection">
@@ -109,4 +119,4 @@
109119
<div ng-if="hits != null && !hits.length" class="table-vis-error">
110120
<h2><i class="fa fa-meh-o"></i></h2>
111121
<h4>No results found</h4>
112-
</div>
122+
</div>

src/ui/public/doc_table/doc_table.js

+76-1
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import _ from 'lodash';
22
import html from 'ui/doc_table/doc_table.html';
33
import { getSort } from 'ui/doc_table/lib/get_sort';
4+
import { saveAs } from '@elastic/filesaver';
45
import 'ui/doc_table/doc_table.less';
56
import 'ui/directives/truncated';
67
import 'ui/directives/infinite_scroll';
78
import 'ui/doc_table/components/table_header';
89
import 'ui/doc_table/components/table_row';
910
import { uiModules } from 'ui/modules';
11+
import { RegistryFieldFormatsProvider } from 'ui/registry/field_formats';
12+
1013

1114
import { getLimitedSearchResultsMessage } from './doc_table_strings';
1215

1316
uiModules.get('kibana')
14-
.directive('docTable', function (config, Notifier, getAppState, pagerFactory, $filter) {
17+
.directive('docTable', function (config, Notifier, getAppState, pagerFactory, $filter, Private) {
18+
const fieldFormats = Private(RegistryFieldFormatsProvider);
1519
return {
1620
restrict: 'E',
1721
template: html,
@@ -140,6 +144,77 @@ uiModules.get('kibana')
140144
$scope.shouldShowLimitedResultsWarning = () => (
141145
!$scope.pager.hasNextPage && $scope.pager.totalItems < $scope.totalHitCount
142146
);
147+
148+
$scope.exportAsCsv = function (formatted) {
149+
var csv = {
150+
separator: config.get('csv:separator'),
151+
quoteValues: config.get('csv:quoteValues')
152+
};
153+
154+
var rows = $scope.hits;
155+
var columns = $scope.columns;
156+
if ($scope.indexPattern.timeFieldName) {
157+
columns = [$scope.indexPattern.timeFieldName].concat(columns);
158+
}
159+
var nonAlphaNumRE = /[^a-zA-Z0-9]/;
160+
var allDoubleQuoteRE = /"/g;
161+
162+
function escape(val) {
163+
if (_.isObject(val)) val = val.valueOf();
164+
val = String(val);
165+
if (csv.quoteValues && nonAlphaNumRE.test(val)) {
166+
val = '"' + val.replace(allDoubleQuoteRE, '""') + '"';
167+
}
168+
return val;
169+
}
170+
171+
function formatField(value, name) {
172+
var field = $scope.indexPattern.fields.byName[name];
173+
if (!field) return value;
174+
var defaultFormat = fieldFormats.getDefaultType(field.type);
175+
var formatter = (field && field.format) ? field.format : defaultFormat;
176+
177+
return formatter.convert(value);
178+
}
179+
180+
function formatRow(row) {
181+
$scope.indexPattern.flattenHit(row);
182+
row.$$_formatted = row.$$_formatted || _.mapValues(row.$$_flattened, formatField);
183+
return row.$$_formatted;
184+
}
185+
186+
// get column values for each row
187+
var csvRows = rows.map(function (row, i) {
188+
return columns.map(function (column, j) {
189+
var val;
190+
191+
if (formatted) {
192+
val = (row.$$_formatted || formatRow(row))[column];
193+
} else {
194+
val = (row.$$_flattened || formatRow(row))[column];
195+
}
196+
197+
val = (val == null) ? '' : val;
198+
199+
return val;
200+
});
201+
});
202+
203+
// escape each cell in each row
204+
csvRows = csvRows.map(function (row, i) {
205+
return row.map(escape);
206+
});
207+
208+
// add the columns to the rows
209+
csvRows.unshift(columns.map(escape));
210+
211+
var data = csvRows.map(function (row) {
212+
return row.join(csv.separator) + '\r\n';
213+
}).join('');
214+
215+
saveAs(new Blob([data], { type: 'text/plain' }), 'export.csv');
216+
};
217+
143218
}
144219
};
145220
});

src/ui/public/doc_table/doc_table.less

+4
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ doc-table {
6363
z-index: 20;
6464
opacity: @loading-opacity;
6565
}
66+
67+
.export {
68+
margin: 10px;
69+
}
6670
}
6771

6872
/**

0 commit comments

Comments
 (0)