Skip to content

Commit

Permalink
Add ability to select column from detail row in doc table. Store sort…
Browse files Browse the repository at this point in the history
…/columns on dashboard

Add a remove column icon to the header
  • Loading branch information
Rashid Khan committed Apr 7, 2015
1 parent dd9ff18 commit 425053b
Show file tree
Hide file tree
Showing 30 changed files with 206 additions and 189 deletions.
5 changes: 4 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
insert_final_newline = true

[*.md]
insert_final_newline = false
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ module.exports = function (grunt) {
'Gruntfile.js',
'<%= root %>/tasks/**/*.js',
'<%= src %>/kibana/*.js',
'<%= src %>/server/*.js',
'<%= src %>/server/**/*.js',
'<%= src %>/kibana/{components,directives,factories,filters,plugins,registry,services,utils}/**/*.js',
'<%= unitTestDir %>/**/*.js',
'!<%= unitTestDir %>/specs/vislib/fixture/**/*'
Expand Down
9 changes: 5 additions & 4 deletions src/kibana/components/doc_table/components/table_header.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
<span ng-click="sort(indexPattern.timeFieldName)" tooltip="Sort by time">Time <i ng-class="headerClass(indexPattern.timeFieldName)"></i></span>
</th>
<th ng-repeat="name in columns">
<span ng-click="sort(name)" class="table-header-name" tooltip="{{tooltip(name)}}">
{{name | shortDots}} <i ng-class="headerClass(name)"></i>
<span class="table-header-name">
{{name | shortDots}} <i ng-class="headerClass(name)" ng-click="sort(name)" tooltip="{{tooltip(name)}}" tooltip-append-to-body="1"></i>
</span>
<span class="table-header-move">
<i ng-click="moveLeft(name)" class="fa fa-angle-double-left" ng-show="!$first" tooltip="Move column to the left"></i>
<i ng-click="moveRight(name)" class="fa fa-angle-double-right" ng-show="!$last" tooltip="Move column to the right"></i>
<i ng-click="toggleColumn(name)" ng-show="canRemove(name)" class="fa fa-remove" tooltip="Remove column" tooltip-append-to-body="1"></i>
<i ng-click="moveLeft(name)" class="fa fa-angle-double-left" ng-show="!$first" tooltip="Move column to the left" tooltip-append-to-body="1"></i>
<i ng-click="moveRight(name)" class="fa fa-angle-double-right" ng-show="!$last" tooltip="Move column to the right" tooltip-append-to-body="1"></i>
</span>
</th>
11 changes: 10 additions & 1 deletion src/kibana/components/doc_table/components/table_header.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ define(function (require) {

var sortableField = function (field) {
if (!$scope.indexPattern) return;
return $scope.indexPattern.fields.byName[field].sortable;
var sortable = _.deepGet($scope.indexPattern.fields.byName[field], 'sortable');
return sortable;
};

$scope.tooltip = function (column) {
if (!sortableField(column)) return ''; else return 'Sort by ' + shortDotsFilter(column);
};

$scope.canRemove = function (name) {
return (name !== '_source' || $scope.columns.length !== 1);
};

$scope.headerClass = function (column) {
if (!sortableField(column)) return;

Expand All @@ -49,6 +54,10 @@ define(function (require) {
_.move($scope.columns, index, ++index);
};

$scope.toggleColumn = function (fieldName) {
_.toggleInOut($scope.columns, fieldName);
};

$scope.sort = function (column) {
if (!column || !sortableField(column)) return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
<a class="pull-right" ng-href="#/doc/{{indexPattern.id}}/{{row._index}}/{{row._type}}/?id={{row._id | uriescape}}">
<small>Link to /{{row._index}}/{{row._type}}/{{row._id | uriescape}}</small></i>
</a>
<doc-viewer hit="row" filter="filter" index-pattern="indexPattern"></doc-viewer>
<doc-viewer hit="row" filter="filter" columns="columns" index-pattern="indexPattern"></doc-viewer>
</td>
9 changes: 9 additions & 0 deletions src/kibana/components/doc_table/doc_table.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ define(function (require) {
$scope.limit += 50;
};

$scope.$watchCollection('columns', function (columns, oldColumns) {
if (oldColumns.length === 1 && oldColumns[0] === '_source' && $scope.columns.length > 1) {
_.pull($scope.columns, '_source');
}

if ($scope.columns.length === 0) $scope.columns.push('_source');
});


$scope.$watch('searchSource', prereq(function (searchSource) {
if (!$scope.searchSource) return;

Expand Down
18 changes: 15 additions & 3 deletions src/kibana/components/doc_viewer/doc_viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,25 @@
</td>
<td width="1%" class="doc-viewer-buttons" ng-if="filter">
<span bo-if="mapping[field].filterable">
<i ng-click="filter(mapping[field], flattened[field], '+')" class="fa fa-search-plus"></i>
<i ng-click="filter(mapping[field], flattened[field],'-')" class="fa fa-search-minus"></i>
<i ng-click="filter(mapping[field], flattened[field], '+')"
tooltip="Filter for value"
tooltip-append-to-body="1"
class="fa fa-search-plus"></i>
<i ng-click="filter(mapping[field], flattened[field],'-')"
tooltip="Filter out value"
tooltip-append-to-body="1"
class="fa fa-search-minus"></i>
</span>
<span bo-if="!mapping[field].filterable" tooltip="Unindexed fields can not be searched">
<i class="fa fa-search-plus text-muted"></i>
<i class="fa fa-search-minus text-muted"></i>
</span>
<span bo-if="columns">
<i ng-click="toggleColumn(field)"
tooltip="Toggle column in table"
tooltip-append-to-body="1"
class="fa fa-columns"></i>
</span>
</td>

<td>
Expand All @@ -45,6 +57,6 @@
</tbody>
</table>

<pre ng-show="mode == 'json'">{{hit | json}}</pre>
<div id="json-ace" ng-show="mode == 'json'" readonly ui-ace="{ useWrapMode: true, advanced: { highlightActiveLine: false }, rendererOptions: { showPrintMargin: false, maxLines: 4294967296 }, mode: 'json' }" ng-model="hit_json"></div>
</div>
</div>
8 changes: 8 additions & 0 deletions src/kibana/components/doc_viewer/doc_viewer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
define(function (require) {
var _ = require('lodash');
var angular = require('angular');
require('angular-ui-ace');

var html = require('text!components/doc_viewer/doc_viewer.html');
require('css!components/doc_viewer/doc_viewer.css');
Expand All @@ -15,6 +17,7 @@ define(function (require) {
hit: '=',
indexPattern: '=',
filter: '=?',
columns: '=?'
},
link: function ($scope, $el, attr) {
// If a field isn't in the mapping, use this
Expand All @@ -24,6 +27,7 @@ define(function (require) {
$scope.mapping = $scope.indexPattern.fields.byName;

$scope.flattened = $scope.indexPattern.flattenHit($scope.hit);
$scope.hit_json = angular.toJson($scope.hit, true);
$scope.formatted = _.mapValues($scope.flattened, function (value, name) {
var mapping = $scope.mapping[name];
var formatter = (mapping && mapping.format) ? mapping.format : defaultFormat;
Expand All @@ -34,6 +38,10 @@ define(function (require) {
});
$scope.fields = _.keys($scope.flattened).sort();

$scope.toggleColumn = function (fieldName) {
_.toggleInOut($scope.columns, fieldName);
};

$scope.showArrayInObjectsWarning = function (row, field) {
var value = $scope.flattened[field];
return _.isArray(value) && typeof value[0] === 'object';
Expand Down
4 changes: 2 additions & 2 deletions src/kibana/components/index_patterns/_index_pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ define(function (require) {
}
},
filterable: {
value: field.name === '_id' || ((field.indexed && type.filterable) || field.scripted)
value: field.name === '_id' || ((field.indexed && type && type.filterable) || field.scripted)
},
format: {
get: function () {
Expand All @@ -113,7 +113,7 @@ define(function (require) {
}
},
sortable: {
value: field.indexed && type.sortable
value: field.indexed && type && type.sortable
},
scripted: {
// enumerable properties end up in the JSON
Expand Down
4 changes: 2 additions & 2 deletions src/kibana/directives/field_name.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ define(function (require) {
'field',
'fieldName',
'fieldType',
'field.rowCount'
'field.inData'
], function () {

var type = $scope.field ? $scope.field.type : $scope.fieldType;
var name = $scope.field ? $scope.field.name : $scope.fieldName;
var results = $scope.field ? !$scope.field.rowCount && !$scope.field.scripted : false;
var results = $scope.field ? !$scope.field.inData && !$scope.field.scripted : false;
var scripted = $scope.field ? $scope.field.scripted : false;

var displayName = $filter('shortDots')(name);
Expand Down
11 changes: 11 additions & 0 deletions src/kibana/plugins/dashboard/components/panel/lib/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ define(function (require) {
return function (panel, $scope) { // Function parameters here
return savedSearches.get(panel.id)
.then(function (savedSearch) {
panel.columns = panel.columns || savedSearch.columns;
panel.sort = panel.sort || savedSearch.sort;

$scope.$watchCollection('panel.columns', function () {
$scope.state.save();
});

$scope.$watchCollection('panel.sort', function () {
$scope.state.save();
});

return {
savedObj: savedSearch,
panel: panel,
Expand Down
4 changes: 2 additions & 2 deletions src/kibana/plugins/dashboard/components/panel/panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@

<doc-table ng-switch-when="search"
search-source="savedObj.searchSource"
sorting="savedObj.sort"
columns="savedObj.columns"
sorting="panel.sort"
columns="panel.columns"
class="panel-content"
filter="filter">
</doc-table>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ <h5>Selected Fields</h5>
</div>
<ul
bindonce class="list-unstyled discover-selected-fields" >
<discover-field ng-repeat="field in fields|filter:{display:true}">
<discover-field ng-repeat="field in fields.raw|filter:{display:true}">
</discover-field>
</ul>

<div class="sidebar-list-header sidebar-item">
<h5>Fields
<h5>Available Fields
<i
ng-class="{ 'fa-chevron-right': !showFields, 'fa-chevron-down': showFields }"
ng-click="showFields = !showFields"
Expand Down Expand Up @@ -105,9 +105,9 @@ <h5>Fields
</div>

<ul bindonce
ng-show="(fields | filter:filter.popularity).length > 0"
ng-show="(popularFields | filter:filter.isFieldFiltered).length > 0"
class="list-unstyled sidebar-well discover-popular-fields" ng-class="{ 'hidden-sm': !showFields, 'hidden-xs': !showFields }">
<li class="sidebar-item sidebar-list-header"><h6>Popular fields</h6></li>
<li class="sidebar-item sidebar-list-header"><h6>Popular</h6></li>
<discover-field ng-repeat="field in popularFields | filter:filter.isFieldFiltered">
</discover-field>
</ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ define(function (require) {
var rison = require('utils/rison');
var qs = require('utils/query_string');
var fieldCalculator = require('plugins/discover/components/field_chooser/lib/field_calculator');
var IndexedArray = require('utils/indexed_array/index');


require('directives/css_truncate');
Expand All @@ -16,8 +17,7 @@ define(function (require) {
return {
restrict: 'E',
scope: {
fields: '=',
toggle: '=',
columns: '=',
data: '=',
state: '=',
indexPattern: '=',
Expand Down Expand Up @@ -55,11 +55,14 @@ define(function (require) {
reset: function () {
filter.vals = _.clone(filter.defaults);
},
isFieldSelected: function (field) {
return field.display;
},
isFieldFiltered: function (field) {
var matchFilter = (filter.vals.type == null || field.type === filter.vals.type);
var isAnalyzed = (filter.vals.analyzed == null || field.analyzed === filter.vals.analyzed);
var isIndexed = (filter.vals.indexed == null || field.indexed === filter.vals.indexed);
var rowsScritpedOrMissing = (!filter.vals.missing || field.scripted || field.rowCount > 0);
var rowsScritpedOrMissing = (!filter.vals.missing || field.scripted || field.inData);
var matchName = (!filter.vals.name || field.name.indexOf(filter.vals.name) !== -1);

return !field.display
Expand Down Expand Up @@ -87,6 +90,11 @@ define(function (require) {
filter.active = filter.getActive();
});

$scope.toggle = function (fieldName) {
$scope.increaseFieldCounter(fieldName);
_.toggleInOut($scope.columns, fieldName);
};

var calculateFields = function (newFields) {
// Find the top N most popular fields
$scope.popularFields = _(newFields)
Expand All @@ -110,16 +118,47 @@ define(function (require) {
};

$scope.$watch('fields', calculateFields);

$scope.$watch('indexPattern', function (indexPattern) {
$scope.fields = new IndexedArray ({
index: ['name'],
initialSet: _($scope.indexPattern.fields)
.sortBy('name')
.transform(function (fields, field) {
// clone the field with Object.create so that its getters
// and non-enumerable props are preserved
var clone = Object.create(field);
clone.display = _.contains($scope.columns, field.name);
fields.push(clone);
}, [])
.value()
});

});

$scope.$watchCollection('columns', function (columns, oldColumns) {
_.each($scope.fields, function (field) {
field.display = _.contains(columns, field.name) ? true : false;
});
});

$scope.$watch('data', function () {

// Get all fields current in data set
var currentFields = _.chain($scope.data).map(function (d) {
return _.keys($scope.indexPattern.flattenHit(d));
}).flatten().unique().sort().value();

_.each($scope.fields, function (field) {
field.inData = _.contains(currentFields, field.name) ? true : false;
if (field.details) {
$scope.details(field, true);
}
});
});

$scope.increaseFieldCounter = function (field) {
$scope.indexPattern.popularizeField(field.name, 1);
$scope.increaseFieldCounter = function (fieldName) {
$scope.indexPattern.popularizeField(fieldName, 1);
};

$scope.runAgg = function (field) {
Expand Down
Loading

0 comments on commit 425053b

Please sign in to comment.