Skip to content

Commit

Permalink
Time Series Metric Visualizations (#9725)
Browse files Browse the repository at this point in the history
* Initial import

* updating the editor width to match the new specs

* Adding tribe node support

* Adding tests for server libs

* removing bluebird

* removing extra cruft

* Fixing the font sizes

* Fixed the updating code

* Adding brushing

* Fixing linting issues

* Adding global filters

* Adding missing packages

* Default gauge style to half circle

* Fixing the markdown css bug

* Adding tests for the get_vis_data api

* Adding time offset

* Adding time offset to each type

* fixing bugs from time offset

* adding index pattern option to series

* Adding index pattern overrides

* Adding index pattern overrides

* Fixing tests

* Fixing brushing in the vis editor

* Changing the label

* Change the behavior of selecting a pipeline agg when only one exists.

* Refactoring series a bit

* Changing series options to just options

* Making sure we honor the toaster container height

* Adding first tests

* renaming vis_config to panel_config

* renaming vis_config to panel_config

* Adding more tests

* adding more tests

* removing api subdirectory

* refactoring get_vis_data (breaking it up and removing unused imports)

* reorganizing the visualization directory

* Re-organizing directory layouts and moving things to more logical places

* Refactoring React compontents to use ES6 syntax and adding propTypes for each. Also refactored out splats as much as possible.

* Adding serial differencing

* Refactored gauge to use 2 components instead of 4

* Finishing react refactor on visualizations. Consolidated legned funtionality

* Refactoring series config and removing a bunch of duplicate code

* fixing series config name

* Fixing numbers and strings (doesnt matter which it is); Fixing classname

* Changing the way the dark theme works

* Adding new vis into list for test

* Adding empty bucket check

* Fixing the index patterns in the aggs

* Fixing typo

* Refactoring vis_data

* Fixing std_metric

* Fixing refresh-hack

* Adding tests for get_splits, get_last_metric, map_bucket

* Fixing the error handing

* removing restrictions

* Sometimes values are strings or numbers... it doesn't matter

* Adding new color options for splits

* Fixing colors

* fixing size

* Adding support for fitlers agg

* Fixing tests

* Fixing splits for filters

* Fixing Top N to work better with fitlers

* Adding annotation editor

* initial work for annotations

* Finalizing annotations

* Fixing label

* making it expandable

* Fixing hacks fixed by #10175

* Fixing bars to use the same stacking options as lines

* Getting rid of align by colons

* removing unused depends

* removing unused depends

* Changing to readable lodash function

* Adding missing parens

* refactoring custom color picker

* Removing string refs and converting uncontrolled components

* Fixing the controlled components where value maybe null; converting error to css

* refactoring styles from components

* fixing the refresh behavoir borked by fullEditor

* Adding the executor service

* Fixing the test directories

* fixing save

* Adding filter ratios

* Fixing controlled components

* Trying to fix the weird typing

* Fixing offset bug with days

* Adding percentile rank

* Fixing yaxis updates; fixing percentile rank layout; adding steps to line chart

* removing unused depends

* Fixed a bug with the index patterns updating; fixed bug with charts rendering too much

* Fixing tests

* Commenting out React tests because the ENV must have change and they are no longer working

* Moving bucket transform

* moving calculate auto

* Moving calculate_indices

* moving extended_stats_types && get_agg_value

* moving get_buckets_path

* moving get_sibling_agg_value

* moving parse_settings

* moving series_agg

* Moving unit_to_seconds

* Fixing tests

* Fixing per PR

* Renaming vars to make it more clear what's happening

* Changing the way testible functions are exported

* fixing tests

* removing unused imports; fixing typos; fixing package name

* Name has to match the plugin path

* Fixing typos; removing unused imports

* fixing tests

* rearanging and removing unused imports

* Fixing a bug with unque names for radio buttons on the same form

* Fixing filter ratio to use a metric instead of just count

* fixing a bug with the new filter ratios

* Fixing the file path from the #8

* Fixing renderComplete trigger; Fixing embedded mode; Changing names for Timelion and Time Series Visual Builder

* Fixing name

* Fixing docs

* Fixing a typo for the field select for terms splits

* Fixing tests
  • Loading branch information
simianhacker authored Mar 2, 2017
1 parent 7cbc22b commit 4f3e625
Show file tree
Hide file tree
Showing 247 changed files with 16,793 additions and 5 deletions.
4 changes: 2 additions & 2 deletions docs/timelion.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Timelion is a time series data visualizer that enables you to combine totally
independent data sources within a single visualization. It's driven by a simple
expression language you use to retrieve time series data, perform calculations
to tease out the answers to complex questions, and visualize the results.
to tease out the answers to complex questions, and visualize the results.

For example, Timelion enables you to easily get the answers to questions like:

Expand All @@ -32,7 +32,7 @@ Timelion expression as a Kibana dashboard panel. You can then add it to
a dashboard like any other visualization.

TIP: You can also create time series visualizations right from the Visualize
app--just select the Timeseries visualization type and enter a Timelion
app--just select the Timelion visualization type and enter a Timelion
expression in the expression field.


Expand Down
2 changes: 1 addition & 1 deletion docs/visualize.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ instructions.
<<tagcloud-chart,Tag cloud>>:: Display words as a cloud in which the size of the word correspond to its importance
<<tilemap,Tile map>>:: Associate the results of an aggregation with geographic
locations.
Timeseries:: Compute and combine data from multiple time series
Timelion:: Compute and combine data from multiple time series
data sets.

. Specify a search query to retrieve the data for your visualization:
Expand Down
14 changes: 14 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"brace": "0.5.1",
"bunyan": "1.7.1",
"check-hash": "1.0.1",
"color": "1.0.3",
"commander": "2.8.1",
"css-loader": "0.17.0",
"d3": "3.5.6",
Expand Down Expand Up @@ -187,12 +188,14 @@
"classnames": "2.2.5",
"del": "1.2.1",
"elasticdump": "2.1.1",
"enzyme": "2.7.0",
"eslint": "3.11.1",
"eslint-plugin-babel": "4.0.0",
"eslint-plugin-mocha": "4.7.0",
"event-stream": "3.3.2",
"expect.js": "0.3.1",
"faker": "1.1.0",
"flot-charts": "^0.8.3",
"grunt": "1.0.1",
"grunt-aws-s3": "0.14.5",
"grunt-babel": "6.0.0",
Expand All @@ -212,6 +215,7 @@
"image-diff": "1.6.0",
"intern": "3.2.3",
"istanbul-instrumenter-loader": "0.1.3",
"jsdom": "9.9.1",
"karma": "1.2.0",
"karma-chrome-launcher": "0.2.0",
"karma-coverage": "0.5.1",
Expand All @@ -232,15 +236,25 @@
"npm": "3.10.10",
"portscanner": "1.0.0",
"proxyquire": "1.7.10",
"pui-react-overlay-trigger": "^7.0.0",
"pui-react-tooltip": "^7.0.0",
"react": "15.2.0",
"react-ace": "3.7.0",
"react-addons-test-utils": "15.2.0",
"react-anything-sortable": "^1.6.1",
"react-color": "^2.2.7",
"react-dom": "15.2.0",
"react-markdown": "^2.4.2",
"react-redux": "4.4.5",
"react-router": "2.0.0",
"react-router-redux": "4.0.4",
"react-select": "^1.0.0-rc.1",
"react-sortable": "^1.1.0",
"reactcss": "^1.0.7",
"redux": "3.0.0",
"redux-thunk": "0.1.0",
"sass-loader": "4.0.0",
"simianhacker-react-resize-aware": "^1.0.11",
"simple-git": "1.37.0",
"sinon": "1.17.2",
"source-map": "0.5.6",
Expand Down
31 changes: 31 additions & 0 deletions src/core_plugins/metrics/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import fieldsRoutes from './server/routes/fields';
import visDataRoutes from './server/routes/vis';

export default function (kibana) {
return new kibana.Plugin({
require: ['kibana','elasticsearch'],

uiExports: {
visTypes: [
'plugins/metrics/kbn_vis_types'
]
},

config(Joi) {
return Joi.object({
enabled: Joi.boolean().default(true),
chartResolution: Joi.number().default(150),
minimumBucketSize: Joi.number().default(10)
}).default();
},


init(server, options) {
const { status } = server.plugins.elasticsearch;
fieldsRoutes(server);
visDataRoutes(server);
}


});
}
6 changes: 6 additions & 0 deletions src/core_plugins/metrics/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"author": "Chris Cowan<[email protected]>",
"name": "metrics",
"version": "kibana"
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// import React from 'react';
// import { expect } from 'chai';
// import { shallow } from 'enzyme';
// import sinon from 'sinon';
// import AddDeleteButtons from '../add_delete_buttons';
// import Tooltip from '../tooltip';

// describe('<AddDeleteButtons />', () => {

// it('calls onAdd={handleAdd}', () => {
// const handleAdd = sinon.spy();
// const wrapper = shallow(
// <AddDeleteButtons onAdd={handleAdd} />
// );
// wrapper.find('a').at(0).simulate('click');
// expect(handleAdd.calledOnce).to.equal(true);
// });

// it('calls onDelete={handleDelete}', () => {
// const handleDelete = sinon.spy();
// const wrapper = shallow(
// <AddDeleteButtons onDelete={handleDelete} />
// );
// wrapper.find('a').at(1).simulate('click');
// expect(handleDelete.calledOnce).to.equal(true);
// });

// it('calls onClone={handleClone}', () => {
// const handleClone = sinon.spy();
// const wrapper = shallow(
// <AddDeleteButtons onClone={handleClone} />
// );
// wrapper.find('a').at(0).simulate('click');
// expect(handleClone.calledOnce).to.equal(true);
// });

// it('disableDelete={true}', () => {
// const wrapper = shallow(
// <AddDeleteButtons disableDelete={true} />
// );
// expect(wrapper.find({ text: 'Delete' })).to.have.length(0);
// });

// it('disableAdd={true}', () => {
// const wrapper = shallow(
// <AddDeleteButtons disableAdd={true} />
// );
// expect(wrapper.find({ text: 'Add' })).to.have.length(0);
// });

// it('should not display clone by default', () => {
// const wrapper = shallow(
// <AddDeleteButtons />
// );
// expect(wrapper.find({ text: 'Clone' })).to.have.length(0);
// });

// it('should not display clone when disableAdd={true}', () => {
// const fn = sinon.spy();
// const wrapper = shallow(
// <AddDeleteButtons onClone={fn} disableAdd={true} />
// );
// expect(wrapper.find({ text: 'Clone' })).to.have.length(0);
// });

// });

33 changes: 33 additions & 0 deletions src/core_plugins/metrics/public/components/__tests__/yes_no.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// import React from 'react';
// import { expect } from 'chai';
// import { shallow } from 'enzyme';
// import sinon from 'sinon';
// import YesNo from '../yes_no';

// describe('<YesNo />', () => {

// it('call onChange={handleChange} on yes', () => {
// const handleChange = sinon.spy();
// const wrapper = shallow(
// <YesNo name="test" onChange={handleChange} />
// );
// wrapper.find('input').first().simulate('change');
// expect(handleChange.calledOnce).to.equal(true);
// expect(handleChange.firstCall.args[0]).to.eql({
// test: 1
// });
// });

// it('call onChange={handleChange} on no', () => {
// const handleChange = sinon.spy();
// const wrapper = shallow(
// <YesNo name="test" onChange={handleChange} />
// );
// wrapper.find('input').last().simulate('change');
// expect(handleChange.calledOnce).to.equal(true);
// expect(handleChange.firstCall.args[0]).to.eql({
// test: 0
// });
// });

// });
58 changes: 58 additions & 0 deletions src/core_plugins/metrics/public/components/add_delete_buttons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { Component, PropTypes } from 'react';
import Tooltip from './tooltip';

function AddDeleteButtons(props) {
const createDelete = () => {
if (props.disableDelete) {
return null;
}
return (
<Tooltip text="Delete">
<a className="thor__button-outlined-danger sm" onClick={ props.onDelete }>
<i className="fa fa-trash-o"></i>
</a>
</Tooltip>
);
};
const createAdd = () => {
if (props.disableAdd) {
return null;
}
return (
<Tooltip text="Add">
<a className="thor__button-outlined-default sm" onClick={ props.onAdd }>
<i className="fa fa-plus"></i>
</a>
</Tooltip>
);
};
const deleteBtn = createDelete();
const addBtn = createAdd();
let clone;
if (props.onClone && !props.disableAdd) {
clone = (
<Tooltip text="Clone">
<a className="thor__button-outlined-default sm" onClick={ props.onClone }>
<i className="fa fa-files-o"></i>
</a>
</Tooltip>
);
}
return (
<div className="add_delete__buttons">
{ clone }
{ addBtn }
{ deleteBtn }
</div>
);
}

AddDeleteButtons.propTypes = {
disableAdd: PropTypes.bool,
disableDelete: PropTypes.bool,
onClone: PropTypes.func,
onAdd: PropTypes.func,
onDelete: PropTypes.func
};

export default AddDeleteButtons;
51 changes: 51 additions & 0 deletions src/core_plugins/metrics/public/components/aggs/agg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { PropTypes } from 'react';
import StdAgg from './std_agg';
import aggToComponent from '../lib/agg_to_component';
import { sortable } from 'react-anything-sortable';

function Agg(props) {
const { model } = props;
let Component = aggToComponent[model.type];
if (!Component) {
Component = StdAgg;
}
const style = Object.assign({ cursor: 'default' }, props.style);
return (
<div
className={props.className}
style={style}
onMouseDown={props.onMouseDown}
onTouchStart={props.onTouchStart}>
<Component
fields={props.fields}
disableDelete={props.disableDelete}
model={props.model}
onAdd={props.onAdd}
onChange={props.onChange}
onDelete={props.onDelete}
panel={props.panel}
series={props.series}
siblings={props.siblings}/>
</div>
);

}

Agg.propTypes = {
disableDelete: PropTypes.bool,
fields: PropTypes.object,
model: PropTypes.object,
onAdd: PropTypes.func,
onChange: PropTypes.func,
onDelete: PropTypes.func,
onMouseDown: PropTypes.func,
onSortableItemMount: PropTypes.func,
onSortableItemReadyToMove: PropTypes.func,
onTouchStart: PropTypes.func,
panel: PropTypes.object,
series: PropTypes.object,
siblings: PropTypes.array,
sortData: PropTypes.string,
};

export default sortable(Agg);
53 changes: 53 additions & 0 deletions src/core_plugins/metrics/public/components/aggs/agg_row.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { PropTypes } from 'react';
import _ from 'lodash';
import AddDeleteButtons from '../add_delete_buttons';
import Tooltip from '../tooltip';

function AggRow(props) {
let iconClassName = 'fa fa-eye-slash';
let iconRowClassName = 'vis_editor__agg_row-icon';
const last = _.last(props.siblings);
if (last.id === props.model.id) {
iconClassName = 'fa fa-eye';
iconRowClassName += ' last';
}

let dragHandle;
if (!props.disableDelete) {
dragHandle = (
<div>
<Tooltip text="Sort">
<div className="vis_editor__agg_sort thor__button-outlined-default sm">
<i className="fa fa-sort"></i>
</div>
</Tooltip>
</div>
);
}

return (
<div className="vis_editor__agg_row">
<div className="vis_editor__agg_row-item">
<div className={iconRowClassName}>
<i className={iconClassName}></i>
</div>
{props.children}
{ dragHandle }
<AddDeleteButtons
onAdd={props.onAdd}
onDelete={props.onDelete}
disableDelete={props.disableDelete}/>
</div>
</div>
);
}

AggRow.propTypes = {
disableDelete: PropTypes.bool,
model: PropTypes.object,
onAdd: PropTypes.func,
onDelete: PropTypes.func,
siblings: PropTypes.array,
};

export default AggRow;
Loading

0 comments on commit 4f3e625

Please sign in to comment.