Skip to content

Commit 5193a14

Browse files
authored
Merge pull request #4 from billmurrin/add-search-menus
Add search menus
2 parents fff6c1c + df940c2 commit 5193a14

File tree

8 files changed

+99
-33
lines changed

8 files changed

+99
-33
lines changed

README.md

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The QuickValuesPlus Widget is an enhanced fork of the GrayLog2 Quick Values Widg
77

88
When the QuickValuesPlus Widget is added to a stream as a field analyzer it adds a "Remove from search" button. The button will negate the field in the search bar (E.g. !field_name:foo).
99

10-
![alt text](http://i.imgur.com/0tfXFTu.png "Remove From Search Button")
10+
![alt text](http://i.imgur.com/uthGeG1.png "Remove From Search Button")
1111

1212
In addition, the QuickValuesPlus Widget has extra features when added to dashboards, such as:
1313
* Support for **ascending** OR **descending** sort order in the datatable. Can now obtain true bottom values.
@@ -16,15 +16,25 @@ In addition, the QuickValuesPlus Widget has extra features when added to dashboa
1616

1717
![alt text](http://i.imgur.com/7PLDXCW.png "Example of Configuration Options")
1818

19-
**Required Graylog versions:**
20-
* Version 1.0.0 was tested and is compatible with Graylog version 2.1.3
21-
* Version 2.0.0 was tested and is compatible with Graylog versions 2.2.1, 2.2.2, and 2.2.3
22-
23-
Please file a bug report providing as much detail as possible if you find that the plugin is not working.
19+
In version 2.1.0, a Customization menu was introduced to help control the sort order, number of top values and the table size of the plugin when used in Search.
20+
21+
![alt text](http://i.imgur.com/TsZQxil.png "Example of Options Menu")
2422

25-
Way Ahead (Next Version)
23+
Options Menu Caveat
2624
-----------
27-
* Add customize menu to widget when attached to a stream which allows ability to toggle sort order, top values and table size.
25+
26+
Right now, Graylog's REST API does not support a sort option for the RelativeSearch lookup on /terms. I plan on doing a Pull Request for this in the future.
27+
28+
With that means is that at this time we cannot obtain a "TRUE" ascending order query. The ascending order observed is actually based on a descending ordered query.
29+
30+
If you want a true ascending query, simply add the visualization as a dashboard. The widget code does obtain the *TRUE* ascending order query.
31+
32+
Required Graylog Versions
33+
-----------
34+
* Version 1.0.0 was tested and is compatible with Graylog version 2.1.3.
35+
* Version 2.1.0 was tested and is compatible with Graylog versions 2.2.1, 2.2.2, and 2.2.3
36+
37+
Please file a bug report providing as much detail as possible if you find that the plugin is not working.
2838

2939
Installation
3040
------------
@@ -35,6 +45,12 @@ and can be configured in your `graylog.conf` file.
3545

3646
Restart `graylog-server` and you are done.
3747

48+
Way Ahead - Next Version(s)
49+
-----------
50+
* Add support to modify the field of the widget.
51+
* Add code to make the Dropdown menu go away after a selection.
52+
* Add a System Configuration menu to allow users to change the global defaults for sort order, top values, and table size.
53+
3854
Development
3955
-----------
4056
You can improve your development experience for the web interface part of your plugin
@@ -95,17 +111,4 @@ This project is using Maven 3 and requires Java 8 or higher.
95111
* Run `mvn package` to build a JAR file.
96112
* Optional: Run `mvn jdeb:jdeb` and `mvn rpm:rpm` to create a DEB and RPM package respectively.
97113
* Copy generated JAR file in target directory to your Graylog plugin directory.
98-
* Restart the Graylog.
99-
100-
Plugin Release
101-
--------------
102-
103-
We are using the maven release plugin:
104-
105-
```
106-
$ mvn release:prepare
107-
[...]
108-
$ mvn release:perform
109-
```
110-
111-
This sets the version numbers, creates a tag and pushes to GitHub. Travis CI will build the release artifacts and upload to GitHub automatically.
114+
* Restart the Graylog.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "QuickValuesPlusWidget",
3-
"version": "2.0.0",
3+
"version": "2.1.0",
44
"description": "GrayLog2 QuickValuesPlus Widget Plusin",
55
"repository": {
66
"type": "git",
@@ -40,7 +40,7 @@
4040
"react-dom": "^0.14.6",
4141
"react-hot-loader": "^3.0.0-beta.3",
4242
"react-proxy-loader": "^0.3.4",
43+
"style-loader": "^0.16.1",
4344
"webpack": "^1.12.2"
4445
}
4546
}
46-

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
<groupId>org.graylog.plugins</groupId>
1010
<artifactId>graylog-plugin-quickvaluesplus-widget</artifactId>
11-
<version>2.0.0</version>
11+
<version>2.1.0</version>
1212
<packaging>jar</packaging>
1313

1414
<name>${project.artifactId}</name>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.dropdown-menu a.selected {
2+
font-weight: bold;
3+
}

src/web/components/FieldQuickValuesPlus.jsx

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import React, {PropTypes} from 'react';
22
import ReactDOM from 'react-dom';
3-
import {Button} from 'react-bootstrap';
3+
import {Button, DropdownButton, MenuItem} from 'react-bootstrap';
44
import Reflux from 'reflux';
55

66
import QuickValuesPlusVisualization from 'components/QuickValuesPlusVisualization';
77
import AddToDashboardMenu from 'components/dashboard/AddToDashboardMenu';
88
import Spinner from 'components/common/Spinner';
9+
import StringUtils from 'util/StringUtils';
910
import UIUtils from 'util/UIUtils';
1011

1112
import StoreProvider from 'injection/StoreProvider';
1213
import { QuickValuesPlusActions, QuickValuesPlusStore } from 'stores/QuickValuesPlusStore';
14+
1315
const RefreshStore = StoreProvider.getStore('Refresh');
1416

1517
const FieldQuickValuesPlus = React.createClass({
@@ -26,8 +28,13 @@ const FieldQuickValuesPlus = React.createClass({
2628
data: [],
2729
};
2830
},
31+
style: require('!style/useable!css!./FieldQuickValuesPlus.css'),
2932

33+
componentWillMount() {
34+
this.setState({quickValuesOptions: {top_values: 5, sort_order: "descending", table_size: 50, show_pie_chart: true, show_data_table: true}});
35+
},
3036
componentDidMount() {
37+
this.style.use();
3138
this._loadQuickValuesData();
3239
},
3340
componentDidUpdate(oldProps, oldState) {
@@ -49,6 +56,7 @@ const FieldQuickValuesPlus = React.createClass({
4956
},
5057

5158
componentWillUnmount() {
59+
this.style.unuse();
5260
this._stopTimer();
5361
},
5462

@@ -71,23 +79,66 @@ const FieldQuickValuesPlus = React.createClass({
7179
_loadQuickValuesData() {
7280
if (this.state.field !== undefined) {
7381
this.setState({loadPending: true});
74-
const promise = QuickValuesPlusActions.getQuickValues(this.state.field);
82+
const promise = QuickValuesPlusActions.getQuickValues(this.state.field, 50);
7583
promise.then((data) => this.setState({data: data, loadPending: false}));
7684
}
7785
},
7886
_resetStatus() {
7987
this.setState(this.getInitialState());
8088
},
89+
sortordermenu: ['ascending', 'descending'],
90+
topvaluesmenu: [5,10,15,20,25],
91+
tablesizemenu: [10,15,20,25,50,75,100],
92+
93+
_submenuItemClassName(configKey, value) {
94+
return this.state.quickValuesOptions[configKey] === value ? 'selected' : '';
95+
},
96+
_updateOptionState(configKey, value) {
97+
let newOptions = Object.assign({}, this.state.quickValuesOptions, {[configKey]: value});
98+
this.refs.thedash.refs.widgetModal.setState({config: newOptions});
99+
this.setState({quickValuesOptions: newOptions});
100+
const promise = QuickValuesPlusActions.getQuickValues(this.state.field, newOptions['table_size']);
101+
promise.then((data) => this.setState({data: data, loadPending: false}));
102+
},
103+
_getSubmenu(configKey, values) {
104+
const submenuItems = values.map((value) => {
105+
const readableName = value;
106+
return (
107+
<li key={`menu-item-${value}`}>
108+
<a href="#" onClick={() => this._updateOptionState(configKey, value)} className={this._submenuItemClassName(configKey, value)} data-type={value}>
109+
{StringUtils.capitalizeFirstLetter(readableName.toString())}
110+
</a>
111+
</li>
112+
);
113+
});
114+
115+
return <ul className={`dropdown-menu ${configKey}-selector`}>{submenuItems}</ul>;
116+
},
81117
render() {
82118
let content;
83-
84119
let inner;
120+
121+
const submenus = [
122+
<li key="sort_order-submenu" className="dropdown-submenu left-submenu">
123+
<a href="#">Sort Order</a>
124+
{this._getSubmenu('sort_order', this.sortordermenu)}
125+
</li>,
126+
<li key="top_values-submenu" className="dropdown-submenu left-submenu">
127+
<a href="#">Top Values</a>
128+
{this._getSubmenu('top_values', this.topvaluesmenu)}
129+
</li>,
130+
<li key="table_size-submenu" className="dropdown-submenu left-submenu">
131+
<a href="#">Table Size</a>
132+
{this._getSubmenu('table_size', this.tablesizemenu)}
133+
</li>,
134+
];
135+
85136
if (this.state.data.length === 0) {
86137
inner = <Spinner />;
87138
} else {
88139
inner = (
89140
<QuickValuesPlusVisualization id={this.state.field}
90-
config={{top_values: 5, sort_order: "descending", table_size: 50, show_pie_chart: true, show_data_table: true}}
141+
config={this.state.quickValuesOptions}
91142
data={this.state.data}
92143
horizontal
93144
displayAddToSearchButton
@@ -101,12 +152,16 @@ const FieldQuickValuesPlus = React.createClass({
101152
<div className="content-col">
102153
<div className="pull-right">
103154
<AddToDashboardMenu title="Add to dashboard"
155+
ref="thedash"
104156
widgetType={this.WIDGET_TYPE}
105-
configuration={{field: this.state.field}}
157+
configuration={{field: this.state.field, table_size: this.state.quickValuesOptions['table_size'], sort_order: this.state.quickValuesOptions['sort_order'], top_values: this.state.quickValuesOptions['top_values']}}
106158
bsStyle="default"
107159
pullRight
108160
permissions={this.props.permissions}>
109161
<Button bsSize="small" onClick={() => this._resetStatus()}>Dismiss</Button>
162+
<DropdownButton bsSize="small" className="quickvalues-settings" title="Customize" id="customize-quick-values-plus-dropdown">
163+
{submenus}
164+
</DropdownButton>
110165
</AddToDashboardMenu>
111166
</div>
112167
<h1>Quick Values for {this.state.field} {this.state.loadPending && <i

src/web/components/QuickValuesPlusWidgetCreateConfiguration.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, {PropTypes} from 'react';
22
import { Input } from 'react-bootstrap';
3+
import QuickValuesPlusVisualization from 'components/QuickValuesPlusVisualization';
34

45
const QuickValuesPlusWidgetCreateConfiguration = React.createClass({
56
propTypes: {
@@ -8,6 +9,7 @@ const QuickValuesPlusWidgetCreateConfiguration = React.createClass({
89
},
910

1011
getInitialConfiguration() {
12+
1113
return {
1214
top_values: 5,
1315
table_size: 50,

src/web/stores/QuickValuesPlusStore.jsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const QuickValuesPlusStore = Reflux.createStore({
1616
listenables: [QuickValuesPlusActions],
1717
getInitialState() {
1818
},
19-
getQuickValues(field) {
19+
getQuickValues(field, tableSize) {
2020
const originalSearchURLParams = SearchStore.getOriginalSearchURLParams();
2121
const streamId = SearchStore.searchInStream ? SearchStore.searchInStream.id : null;
2222
const rangeType = originalSearchURLParams.get('rangetype');
@@ -34,9 +34,11 @@ export const QuickValuesPlusStore = Reflux.createStore({
3434
break;
3535
}
3636
let url = ApiRoutes.UniversalSearchApiController.fieldTerms(rangeType, originalSearchURLParams.get('q') || '*', field, timerange, streamId).url;
37-
//alert("url is " + url);
3837
url = URLUtils.qualifyUrl(url);
39-
//alert("URL2 is " + url);
38+
39+
//If it was set, append the optional Size parameter to the query.
40+
if (tableSize !== undefined) url = url + "&size=" + tableSize;
41+
4042
const promise = fetch('GET', url);
4143
promise.catch(function (error) {
4244
UserNotification.error('Loading quick values failed with status: ' + error, 'Could not load quick values');

webpack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ const path = require('path');
44

55
// Remember to use the same name here and in `getUniqueId()` in the java MetaData class
66
module.exports = new PluginWebpackConfig('org.graylog.plugins.quickvaluesplus.QuickValuesPlusWidgetPlugin', loadBuildConfig(path.resolve(__dirname, './build.config')), {
7+
test: /\.css$/, loader: "style-loader!css-loader"
78
});

0 commit comments

Comments
 (0)