Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doc viewer app #2121

Merged
merged 13 commits into from
Dec 5, 2014
14 changes: 5 additions & 9 deletions src/kibana/components/courier/data_source/_abstract.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,16 +264,12 @@ define(function (require) {
'match_all': {}
};
}
flatState.body.fields = ['*', '_source'];

_.each(flatState.index.fields.byType['date'], function (field) {
if (field.indexed) {
flatState.body.script_fields = flatState.body.script_fields || {};
flatState.body.script_fields[field.name] = {
script: 'doc["' + field.name + '"].value'
};
}
});
var computedFields = flatState.index.getComputedFields();
flatState.body.fields = computedFields.fields;
flatState.body.script_fields = flatState.body.script_fields || {};
_.extend(flatState.body.script_fields, computedFields.scriptFields);


/**
* Create a filter that can be reversed for filters with negate set
Expand Down
68 changes: 35 additions & 33 deletions src/kibana/components/doc_viewer/doc_viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,41 @@
<li ng-class="{active: mode == 'json'}"><a ng-click="mode='json'">JSON</a></li>
</ul>

<table class="table table-condensed" ng-show="mode == 'table'" bindonce>
<tbody>
<tr ng-repeat="field in fields" bindonce>
<td field-name="field"
field-type="mapping[field].type"
width="1%"
class="doc-viewer-field">
</td>
<td width="1%" class="doc-viewer-buttons" ng-if="filter">
<span bo-if="showFilters(mapping[field])">
<i ng-click="filter(field, flattened[field], '+')" class="fa fa-search-plus"></i>
<i ng-click="filter(field, flattened[field],'-')" class="fa fa-search-minus"></i>
</span>
<span bo-if="!showFilters(mapping[field])" 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>
</td>
<div class="content">
<table class="table table-condensed" ng-show="mode == 'table'" bindonce>
<tbody>
<tr ng-repeat="field in fields" bindonce>
<td field-name="field"
field-type="mapping[field].type"
width="1%"
class="doc-viewer-field">
</td>
<td width="1%" class="doc-viewer-buttons" ng-if="filter">
<span bo-if="showFilters(mapping[field])">
<i ng-click="filter(field, flattened[field], '+')" class="fa fa-search-plus"></i>
<i ng-click="filter(field, flattened[field],'-')" class="fa fa-search-minus"></i>
</span>
<span bo-if="!showFilters(mapping[field])" 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>
</td>

<td>
<i bo-if="!mapping[field] && !showArrayInObjectsWarning(doc, field)"
tooltip-placement="top"
tooltip="No cached mapping for this field. Refresh your mapping from the Settings > Indices page"
class="fa fa-warning text-color-warning ng-scope doc-viewer-no-mapping"></i>
<i bo-if="showArrayInObjectsWarning(doc, field)"
tooltip-placement="top"
tooltip="Objects in arrays are not well supported."
class="fa fa-warning text-color-warning ng-scope doc-viewer-object-array"></i>
<span class="doc-viewer-value" ng-bind-html="(formatted[field] || hit[field]) | highlight : hit.highlight[field] | trustAsHtml"></span>
</td>
</tr>
</tbody>
</table>
<td>
<i bo-if="!mapping[field] && !showArrayInObjectsWarning(doc, field)"
tooltip-placement="top"
tooltip="No cached mapping for this field. Refresh your mapping from the Settings > Indices page"
class="fa fa-warning text-color-warning ng-scope doc-viewer-no-mapping"></i>
<i bo-if="showArrayInObjectsWarning(doc, field)"
tooltip-placement="top"
tooltip="Objects in arrays are not well supported."
class="fa fa-warning text-color-warning ng-scope doc-viewer-object-array"></i>
<span class="doc-viewer-value" ng-bind-html="(formatted[field] || hit[field]) | highlight : hit.highlight[field] | trustAsHtml"></span>
</td>
</tr>
</tbody>
</table>

<pre ng-show="mode == 'json'">{{hit | json}}</pre>
<pre ng-show="mode == 'json'">{{hit | json}}</pre>
</div>
</div>
7 changes: 7 additions & 0 deletions src/kibana/components/doc_viewer/doc_viewer.less
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,11 @@ doc-viewer .doc-viewer {
white-space: pre-wrap;
}

td, pre {
font-family: "Lucida Console", Monaco, monospace;
}

.content {
margin-top: @padding-base-vertical;
}
}
23 changes: 23 additions & 0 deletions src/kibana/components/index_patterns/_get_computed_fields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Takes a hit, merges it with any stored/scripted fields, and with the metaFields
// returns a flattened version
define(function (require) {
var _ = require('lodash');
return function () {
var self = this;
var scriptFields = {};

_.each(self.fields.byType['date'], function (field) {
if (field.indexed) {
scriptFields[field.name] = {
script: 'doc["' + field.name + '"].value'
};
}
});

return {
fields: ['*', '_source'],
scriptFields: scriptFields
};

};
});
4 changes: 4 additions & 0 deletions src/kibana/components/index_patterns/_index_pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ define(function (require) {
var DocSource = Private(require('components/courier/data_source/doc_source'));
var flattenSearchResponse = require('components/index_patterns/_flatten_search_response');
var flattenHit = require('components/index_patterns/_flatten_hit');
var getComputedFields = require('components/index_patterns/_get_computed_fields');


var IndexedArray = require('utils/indexed_array/index');

Expand Down Expand Up @@ -224,6 +226,8 @@ define(function (require) {
self.metaFields = config.get('metaFields');
self.flattenSearchResponse = flattenSearchResponse.bind(self);
self.flattenHit = flattenHit.bind(self);
self.getComputedFields = getComputedFields.bind(self);


}
return IndexPattern;
Expand Down
3 changes: 3 additions & 0 deletions src/kibana/plugins/discover/partials/table_row/details.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<td colspan="{{ columns.length + 2 }}">
<a class="pull-right" ng-href="#/doc/{{indexPattern.id}}/{{row._index}}/{{row._type}}/{{row._id}}">
<small>Link to /{{row._index}}/{{row._type}}/{{row._id}}</small></i>
</a>
<doc-viewer hit="row" filter="filter" index-pattern="indexPattern"></doc-viewer>
</td>
66 changes: 66 additions & 0 deletions src/kibana/plugins/doc/controllers/doc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
define(function (require) {
var _ = require('lodash');
var angular = require('angular');

require('components/notify/notify');
require('components/courier/courier');
require('components/doc_viewer/doc_viewer');
require('components/index_patterns/index_patterns');

var app = require('modules').get('apps/doc', [
'kibana/notify',
'kibana/courier',
'kibana/index_patterns'
]);

require('routes')
.when('/doc/:indexPattern/:index/:type/:id', {
template: require('text!plugins/doc/index.html'),
resolve: {
indexPattern: function (courier, savedSearches, $route) {
return courier.indexPatterns.get($route.current.params.indexPattern);
}
}
});

app.controller('doc', function ($scope, $route, es, timefilter) {

timefilter.enabled = false;

// Pretty much only need this for formatting, not actually using it for fetching anything.
$scope.indexPattern = $route.current.locals.indexPattern;

var computedFields = $scope.indexPattern.getComputedFields();

es.search({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Why a search here?
A: Elasticsearch GET API doesn't support stored or scripted fields, have to go through the search API

Q: Well then why didn't you use a searchSource?
A: It seemed wasteful to start up a temporary indexPattern and searchSource for one request. I would need to new up an indexPattern as the existing one could match some range of indices, and I need exactly one index. The indexPattern that does get loaded here is only used for formatters and scripted fields retrieval.

index: $route.current.params.index,
type: $route.current.params.type,
body: {
query: {
ids: {
values: [$route.current.params.id]
}
},
fields: computedFields.fields,
script_fields: computedFields.scriptFields
}
}).then(function (resp) {
if (resp.hits) {
if (resp.hits.total < 1) {
$scope.status = 'notFound';
} else {
$scope.status = 'found';
$scope.hit = resp.hits.hits[0];
}
}
}).catch(function (err) {
if (err.status === 404) {
$scope.status = 'notFound';
} else {
$scope.status = 'error';
$scope.resp = err;
}
});

});
});
47 changes: 47 additions & 0 deletions src/kibana/plugins/doc/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<div ng-controller="doc" class="app-container">

<div class="container-fluid">
<div class="row">

<!-- no results -->
<div class="col-md-12" ng-if="status === 'notFound'">
<div class="col-md-12">
<h1>Failed to locate document. <i class="fa fa-meh-o"></i></h1>

<p>
Unfortunately I could not find any documents matching that id, of that type, in that index. I tried really hard. I wanted it to be there. Sometimes I swear documents grow legs and just walk out of the index. Sneaky. I wish I could offer some advice here, something to make you feel better
</p>

</div>
</div>

<!-- no results -->
<div class="col-md-12" ng-if="status === 'error'">
<div class="col-md-12">
<h1>This is bad. <i class="fa fa-meh-o"></i></h1>

<p>
Oh no. Something went very wrong. Its not just that I couldn't find your document, I couldn't even try. The index was missing, or the type. Go check out Elasticsearch, something isn't quite right here.
</p>

</div>
</div>

<!-- loading -->
<div class="col-md-12" ng-if="status === undefined">
<div class="discover-overlay">
<h2>Searching</h2>
<div class="spinner large"></div>
<div ng-show="fetchStatus">{{fetchStatus.complete}}/{{fetchStatus.total}}</div>
</div>
</div>

<!-- result -->
<div class="col-md-12" ng-if="status === 'found'">
<h2><b>Doc:</b> {{hit._index}}/{{hit._type}}/{{hit._id}}</h2>

<doc-viewer hit="hit" index-pattern="indexPattern"></doc-viewer>
</div>
</div>
</div>
</div>
12 changes: 12 additions & 0 deletions src/kibana/plugins/doc/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
define(function (require, module, exports) {
require('plugins/doc/controllers/doc');

var apps = require('registry/apps');
apps.register(function DocAppModule() {
return {
id: 'doc',
name: 'Doc Viewer',
order: -1
};
});
});
6 changes: 6 additions & 0 deletions src/kibana/plugins/kibana/_apps.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ define(function (require) {
return app.lastPath;
}

function getShow(app) {
app.show = app.order >= 0 ? true : false;
}

function setLastPath(app, path) {
app.lastPath = path;
return sessionStorage.set(appKey(app), path);
Expand All @@ -19,6 +23,8 @@ define(function (require) {
$scope.apps = Private(require('registry/apps'));
// initialize each apps lastPath (fetch it from storage)
$scope.apps.forEach(getLastPath);
$scope.apps.forEach(getShow);


function onRouteChange() {
var route = $location.path().split(/\//);
Expand Down
2 changes: 1 addition & 1 deletion src/kibana/plugins/kibana/kibana.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<!-- Full navbar -->
<div collapse="!showCollapsed" class="navbar-collapse" id="kibana-primary-navbar">
<ul class="nav navbar-nav">
<li ng-repeat="app in apps.inOrder" ng-class="{active: activeApp === app}">
<li ng-repeat="app in apps.inOrder | filter:{show: true}" ng-class="{active: activeApp === app}">
<a ng-href="#{{app.lastPath}}" bo-text="app.name"></a>
</li>
</ul>
Expand Down
2 changes: 2 additions & 0 deletions test/unit/fixtures/stubbed_logstash_index_pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ define(function (require) {
var StubIndexPattern = Private(require('test_utils/stub_index_pattern'));
var flattenSearchResponse = require('components/index_patterns/_flatten_search_response');
var flattenHit = require('components/index_patterns/_flatten_hit');
var getComputedFields = require('components/index_patterns/_get_computed_fields');

var _ = require('lodash');

Expand All @@ -23,6 +24,7 @@ define(function (require) {
{ name: 'custom_user_field', displayName: 'custom_user_field', type: 'conflict', indexed: false, analyzed: false, count: 0 }
]);

indexPattern.getComputedFields = _.bind(getComputedFields, indexPattern);
indexPattern.flattenSearchResponse = _.bind(flattenSearchResponse, indexPattern);
indexPattern.flattenHit = _.bind(flattenHit, indexPattern);
indexPattern.metaFields = ['_id', '_type', '_source'];
Expand Down
Loading