Skip to content

Commit

Permalink
re-enable "show field terms"
Browse files Browse the repository at this point in the history
 - this version can show the terms for every field now, instead of only the field 'message'
 - terms are shown inline below the actual field value to make it easier to compare
  • Loading branch information
kroepke committed Apr 27, 2015
1 parent a556ad5 commit 58c589e
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 24 deletions.
19 changes: 5 additions & 14 deletions app/assets/stylesheets/graylog2.less
Expand Up @@ -416,20 +416,11 @@ a.fields-set-chooser {
color: #26ADE4;
}

.terms-msg-modal .modal-header {
font-size: 11px;
}

.terms-msg-modal .modal-body li {
float: left;
.message-terms {
margin-right: 8px;
font-family: monospace;
}

.terms-msg-modal .modal-body .as-list li {
float: none !important;
}

.support-sources ul {
margin-top: 5px;
}
Expand Down Expand Up @@ -2945,10 +2936,10 @@ table.messages tr.message-detail-row dl.message-details-fields dd {
border-bottom: 1px solid #ececec;
}

table.messages tr.message-detail-row dl.message-details dd ul {
list-style-type: disc;
padding-left: 25px;
}
//table.messages tr.message-detail-row dl.message-details dd ul {
// list-style-type: disc;
// padding-left: 25px;
//}

table.messages tr.message-detail-row dl.message-details dd ul li {
margin-top: 3px;
Expand Down
8 changes: 4 additions & 4 deletions app/controllers/MessagesController.java
Expand Up @@ -150,12 +150,12 @@ public Result analyze(String index, String id, String field) {
try {
MessageResult message = messagesService.getMessage(index, id);

String analyzeField = (String) message.getFilteredFields().get(field);
if (analyzeField == null || analyzeField.isEmpty()) {
Object analyzeField = message.getFilteredFields().get(field);
if (analyzeField == null || (analyzeField instanceof String) && ((String)analyzeField).isEmpty()) {
return status(404, "Message does not have requested field " + field);
}

MessageAnalyzeResult result = messagesService.analyze(index, analyzeField);
final String stringifiedValue = String.valueOf(analyzeField);
MessageAnalyzeResult result = messagesService.analyze(index, stringifiedValue);
return ok(Json.toJson(result.getTokens()));
} catch (IOException e) {
return status(500, views.html.errors.error.render(ApiClient.ERROR_MSG_IO, e, request()));
Expand Down
1 change: 1 addition & 0 deletions app/views/partials/navbar.scala.html
Expand Up @@ -26,6 +26,7 @@
routes.javascript.SystemController.index,
routes.javascript.NodesController.nodes,
routes.javascript.NodesController.node,
routes.javascript.MessagesController.analyze,
routes.javascript.MessagesController.show,
routes.javascript.InputsController.index,
routes.javascript.OutputsController.index,
Expand Down
37 changes: 31 additions & 6 deletions javascript/src/components/search/MessageDetail.jsx
Expand Up @@ -9,14 +9,19 @@ var Row = require('react-bootstrap').Row;
var Col = require('react-bootstrap').Col;
var OverlayTrigger = require('react-bootstrap').OverlayTrigger;
var Tooltip = require('react-bootstrap').Tooltip;
var SplitButton = require('react-bootstrap').SplitButton;
var MenuItem = require('react-bootstrap').MenuItem;
var Alert = require('react-bootstrap').Alert;
var ReactZeroClipboard = require('react-zeroclipboard');

var Immutable = require('immutable');
var MessagesStore = require('../../stores/messages/MessagesStore');

var MessageDetail = React.createClass({
getInitialState() {
return {
scrollWarn: false
scrollWarn: false,
messageTerms: Immutable.Map()
};
},
componentDidMount() {
Expand All @@ -40,20 +45,42 @@ var MessageDetail = React.createClass({
:
<span style={{wordBreak: 'break-word'}}>stopped node</span>;
},
_loadTerms(field) {
return () => {
var promise = MessagesStore.fieldTerms(this.props.message.index, this.props.message.id, field);
promise.done((terms) => this._onTermsLoaded(field, terms))
}
},
_onTermsLoaded(field, terms) {
var map = Immutable.Map().set(field, terms);
this.setState({messageTerms: map});
},
render() {
var messageUrl = jsRoutes.controllers.MessagesController.show(this.props.message.index, this.props.message.id).url;

var fields = [];
var formattedFields = Immutable.Map(this.props.message['formatted_fields']);
var idx = 0;
formattedFields.forEach((value, key) => {
idx++;
// this is to work around the fact that the container has an overflow-y: auto. well :grumpy:
var shouldDropup = !!(formattedFields.size > 4 && idx >= formattedFields.size - 1);
var showTerms = this.state.messageTerms.has(key);
var terms = showTerms ? Immutable.fromJS(this.state.messageTerms.get(key)) : Immutable.List();
var termsMarkup = [];
terms.forEach((term, idx) => termsMarkup.push(<span key={idx} className="message-terms">{term}</span>));
fields.push(<dt key={key + "dt"}>{key}</dt>);
fields.push(
<dd key={key + "dd"}>
<div className="message-field-actions pull-right">
<a href="#" className="btn btn-xs btn-default search-link" data-field="@f.getName" data-value="@Tools.removeTrailingNewline(r.getFormattedFields.get(f.getName))" title="Append to search query"><i className="fa fa-search-plus"></i></a>
<a href="#" className="btn btn-xs btn-default" title="Split into fields / Create extractor"><i className="fa fa-magic"></i></a>
<SplitButton dropup={shouldDropup} pullRight={true} bsSize="xsmall" title={<i className="fa fa-search-plus"></i>} key={1}>
<MenuItem>Create extractor for field {key}</MenuItem>
<MenuItem onClick={this._loadTerms(key)}>Show terms of {key}</MenuItem>
</SplitButton>
</div>
{value}
{showTerms && <br />}
{showTerms && <Alert bsStyle='info' onDismiss={() => this.setState({messageTerms: Immutable.Map()})}>Field terms: {termsMarkup}</Alert>}
</dd>
);
});
Expand Down Expand Up @@ -87,8 +114,6 @@ var MessageDetail = React.createClass({
</ReactZeroClipboard>
</OverlayTrigger>

<Button href="#">Show terms</Button>

<Button href="#">Test against stream</Button>
</ButtonGroup>
<h3><i className="fa fa-envelope"></i> <a href={messageUrl} style={{color: '#000'}}>{this.props.message.id}</a></h3>
Expand Down Expand Up @@ -118,7 +143,7 @@ var MessageDetail = React.createClass({
</dl>
</Col>
<Col md={9}>
<div ref="messageList" style={{maxHeight: 1000, overflowY: 'auto'}}>
<div ref="messageList" style={{minHeight: 200, maxHeight: 1000, overflowY: 'auto'}}>
{this.state.scrollWarn ? <span><i className="fa fa-exclamation-triangle"></i> Scroll field list for more details...</span> : null}
<dl className="message-details message-details-fields">
{fields}
Expand Down
11 changes: 11 additions & 0 deletions javascript/src/stores/messages/MessagesStore.ts
Expand Up @@ -3,6 +3,7 @@
'use strict';

declare var $: any;
declare var jsRoutes: any;

import UserNotification = require("../../util/UserNotification");
import URLUtils = require("../../util/URLUtils");
Expand Down Expand Up @@ -30,6 +31,16 @@ var MessagesStore = {
"Could not load message information");
});
return promise;
},

fieldTerms(index: string, messageId: string, field: string): JQueryPromise<Array<string>> {
var url = jsRoutes.controllers.MessagesController.analyze(index, messageId, field).url;
var promise = $.getJSON(url);
promise.fail((jqXHR, textStatus, errorThrown) => {
UserNotification.error("Loading field terms failed with status: " + errorThrown,
"Could not load field terms.");
});
return promise;
}
};

Expand Down

0 comments on commit 58c589e

Please sign in to comment.