Skip to content

Commit

Permalink
Add app to display discover entry context
Browse files Browse the repository at this point in the history
  • Loading branch information
weltenwort committed Nov 23, 2016
1 parent 4556ac3 commit f80a169
Show file tree
Hide file tree
Showing 12 changed files with 300 additions and 2 deletions.
26 changes: 26 additions & 0 deletions src/core_plugins/kibana/public/context/api/anchor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import _ from 'lodash';

import {addComputedFields} from './utils/fields';
import {createAnchorQuery} from './utils/queries';


async function fetchAnchor(es, indexPattern, uid, sort) {
const indices = await indexPattern.toIndexList();
const response = await es.search({
index: indices,
body: addComputedFields(indexPattern, createAnchorQuery(uid, sort)),
});

if (_.get(response, ['hits', 'total'], 0) < 1) {
throw new Error('Failed to load anchor row.');
}

return _.assign({}, response.hits.hits[0], {
$$_isAnchor: true,
});
}


export {
fetchAnchor,
};
41 changes: 41 additions & 0 deletions src/core_plugins/kibana/public/context/api/context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import _ from 'lodash';

import {addComputedFields} from './utils/fields';
import {getDocumentUid} from './utils/ids';
import {createSuccessorsQuery} from './utils/queries.js';
import {reverseQuerySort} from './utils/sorting';


async function fetchContext(es, indexPattern, anchorDocument, sort, size) {
const indices = await indexPattern.toIndexList();
const anchorUid = getDocumentUid(anchorDocument._type, anchorDocument._id);
const successorsQuery = addComputedFields(
indexPattern,
createSuccessorsQuery(anchorUid, anchorDocument.sort, sort, size)
);
const predecessorsQuery = reverseQuerySort(successorsQuery);

const response = await es.msearch({
body: [
{index: indices},
predecessorsQuery,
{index: indices},
successorsQuery,
],
});

const predecessors = _.get(response, ['responses', 0, 'hits', 'hits'], []);
const successors = _.get(response, ['responses', 1, 'hits', 'hits'], []);

predecessors.reverse();

return {
predecessors,
successors,
};
}


export {
fetchContext,
};
17 changes: 17 additions & 0 deletions src/core_plugins/kibana/public/context/api/utils/fields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import _ from 'lodash';


function addComputedFields(indexPattern, query) {
const computedFields = indexPattern.getComputedFields();

return _.assign({}, query, {
script_fields: computedFields.scriptFields,
docvalue_fields: computedFields.docvalueFields,
stored_fields: computedFields.storedFields,
});
};


export {
addComputedFields,
};
8 changes: 8 additions & 0 deletions src/core_plugins/kibana/public/context/api/utils/ids.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function getDocumentUid(type, id) {
return `${type}#${id}`;
}


export {
getDocumentUid,
};
29 changes: 29 additions & 0 deletions src/core_plugins/kibana/public/context/api/utils/queries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
function createAnchorQuery(uid, contextSort) {
return {
_source: true,
query: {
terms: {
_uid: [uid],
},
},
sort: [contextSort],
};
};

function createSuccessorsQuery(anchorUid, anchorSortValues, contextSort, size) {
return {
_source: true,
query: {
match_all: {},
},
size,
sort: [ contextSort, { _uid: 'asc' } ],
search_after: anchorSortValues.concat([ anchorUid ]),
};
};


export {
createAnchorQuery,
createSuccessorsQuery,
};
35 changes: 35 additions & 0 deletions src/core_plugins/kibana/public/context/api/utils/sorting.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import _ from 'lodash';


function reverseQuerySort(query) {
return _.assign({}, query, {
sort: _.get(query, 'sort', []).map(reverseSortDirective),
});
}

function reverseSortDirective(sortDirective) {
if (_.isString(sortDirective)) {
return {
[sortDirective]: (sortDirective === '_score' ? 'asc' : 'desc'),
};
} else if (_.isObject(sortDirective)) {
return _.mapValues(sortDirective, reverseSortDirection);
} else {
return sortDirective;
}
}

function reverseSortDirection(sortDirection) {
if (_.isObject(sortDirection)) {
return sortDirection.order = reverseSortDirection(sortDirection.order);
} else {
return (sortDirection === 'asc' ? 'desc' : 'asc');
}
}


export {
reverseQuerySort,
reverseSortDirection,
reverseSortDirective,
};
32 changes: 32 additions & 0 deletions src/core_plugins/kibana/public/context/app.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<div class="app-container">
<kbn-top-nav name="context" config="topNavMenu">
<!-- Transcluded elements. -->
<div data-transclude-slots>
<!-- Breadcrumbs. -->
<div data-transclude-slot="topLeftCorner" class="localBreadcrumbs">
<div class="localBreadcrumb">
<span class="localBreadcrumb">Context</span>
<span ng-bind="contextApp.indexPattern.id" class="localBreadcrumb"></span>
<span ng-bind="contextApp.anchorUid" class="localBreadcrumb"></span>
</div>
</div>
</div>
</kbn-top-nav>

<div class="container-fluid" role="main">
<div class="row">
<div class="col-md-12">
<div class="discover-table" fixed-scroll>
<doc-table
hits="contextApp.rows"
index-pattern="contextApp.indexPattern"
sorting="contextApp.sort"
columns="contextApp.columns"
infinite-scroll="true"
>
</doc-table>
</div>
</div>
</div>
</div>
</div>
74 changes: 74 additions & 0 deletions src/core_plugins/kibana/public/context/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import _ from 'lodash';

import uiModules from 'ui/modules';
import contextAppTemplate from './app.html';
import {fetchAnchor} from './api/anchor';
import {fetchContext} from './api/context';


const module = uiModules.get('apps/context', [
'kibana',
'ngRoute',
]);

module.directive('contextApp', function ContextApp() {
return {
bindToController: true,
controller: ContextAppController,
controllerAs: 'contextApp',
restrict: 'E',
scope: {
anchorUid: '=',
columns: '=',
indexPattern: '=',
size: '=',
sort: '=',
},
template: contextAppTemplate,
};
});

function ContextAppController($q, es) {
this.anchorRow = null;
this.rows = [];

this.initialize = () => {
this.actions.reload();
};

this.actions = {
fetchAnchorRow: () => (
$q.resolve()
.then(() => (
fetchAnchor(es, this.indexPattern, this.anchorUid, _.zipObject([this.sort]))
))
.then(anchorRow => (
this.anchorRow = anchorRow
))
),
fetchContextRows: () => (
$q.resolve(this.anchorRowPromise)
.then(anchorRow => (
fetchContext(es, this.indexPattern, anchorRow, _.zipObject([this.sort]), this.size)
))
.then(({predecessors, successors}) => {
this.predecessorRows = predecessors;
this.successorRows = successors;
})
.then(() => (
this.rows = [].concat(this.predecessorRows, [this.anchorRow], this.successorRows)
))
),
reload: () => {
this.anchorRowPromise = this.actions.fetchAnchorRow();
this.contextRowsPromise = this.actions.fetchContextRows();

$q.all([
this.anchorRowPromise,
this.contextRowsPromise,
]);
},
};

this.initialize();
}
30 changes: 30 additions & 0 deletions src/core_plugins/kibana/public/context/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import uiRoutes from 'ui/routes';
import './app';
import {getDocumentUid} from './api/utils/ids';


uiRoutes
.when('/context/:indexPattern/:type/:id', {
controller: ContextAppRouteController,
controllerAs: 'contextAppRoute',
resolve: {
indexPattern: function ($route, courier, savedSearches) {
return courier.indexPatterns.get($route.current.params.indexPattern);
},
},
template: (
`<context-app
anchor-uid="contextAppRoute.anchorUid"
columns="['_source']"
index-pattern="contextAppRoute.indexPattern"
size="5"
sort="['@timestamp', 'desc']"
>`
),
});


function ContextAppRouteController($routeParams, indexPattern) {
this.anchorUid = getDocumentUid($routeParams.type, $routeParams.id);
this.indexPattern = indexPattern;
}
4 changes: 4 additions & 0 deletions src/core_plugins/kibana/public/discover/styles/main.less
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@
font-size: 9px;
}

.discover-table-row--highlight {
font-weight: bold;
}

.shard-failures {
color: @discover-shard-failures-color;
background-color: @discover-shard-failures-bg !important;
Expand Down
1 change: 1 addition & 0 deletions src/core_plugins/kibana/public/kibana.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'plugins/kibana/dashboard/index';
import 'plugins/kibana/management/index';
import 'plugins/kibana/doc';
import 'plugins/kibana/dev_tools';
import 'plugins/kibana/context';
import 'ui/vislib';
import 'ui/agg_response';
import 'ui/agg_types';
Expand Down
5 changes: 3 additions & 2 deletions src/ui/public/doc_table/doc_table.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@
sorting="sorting"
index-pattern="indexPattern"
filter="filter"
class="discover-table-row"></tr>
class="discover-table-row"
ng-class="{'discover-table-row--highlight': row['$$_isAnchor']}"></tr>
</tbody>
</table>
<kbn-infinite-scroll ng-if="infiniteScroll" more="addRows"></kbn-infinite-scroll>
</div>
<div ng-if="hits != null && !hits.length" class="table-vis-error">
<h2><i class="fa fa-meh-o"></i></h2>
<h4>No results found</h4>
</div>
</div>

0 comments on commit f80a169

Please sign in to comment.