Commit b2758b2a by David Committed by GitHub

Merge pull request #13408 from grafana/limit-number-of-series-in-explore

Limit number of time series in explore
parents fda8a08e e50a87ae
...@@ -604,7 +604,9 @@ export class Explore extends React.Component<any, ExploreState> { ...@@ -604,7 +604,9 @@ export class Explore extends React.Component<any, ExploreState> {
</div> </div>
<main className="m-t-2"> <main className="m-t-2">
{supportsGraph && showingGraph ? ( {supportsGraph &&
showingGraph &&
graphResult && (
<Graph <Graph
data={graphResult} data={graphResult}
height={graphHeight} height={graphHeight}
...@@ -613,7 +615,7 @@ export class Explore extends React.Component<any, ExploreState> { ...@@ -613,7 +615,7 @@ export class Explore extends React.Component<any, ExploreState> {
options={requestOptions} options={requestOptions}
split={split} split={split}
/> />
) : null} )}
{supportsTable && showingTable ? ( {supportsTable && showingTable ? (
<Table className="m-t-3" data={tableResult} loading={loading} onClickCell={this.onClickTableCell} /> <Table className="m-t-3" data={tableResult} loading={loading} onClickCell={this.onClickTableCell} />
) : null} ) : null}
......
import React from 'react';
import { shallow } from 'enzyme';
import Graph from './Graph';
import { mockData } from './__mocks__/mockData';
const setup = (propOverrides?: object) => {
const props = Object.assign(
{
data: mockData().slice(0, 19),
options: {
interval: '20s',
range: { from: 'now-6h', to: 'now' },
targets: [
{
format: 'time_series',
instant: false,
hinting: true,
expr: 'prometheus_http_request_duration_seconds_bucket',
},
],
},
},
propOverrides
);
// Enzyme.shallow did not work well with jquery.flop. Mocking the draw function.
Graph.prototype.draw = jest.fn();
const wrapper = shallow(<Graph {...props} />);
const instance = wrapper.instance() as Graph;
return {
wrapper,
instance,
};
};
describe('Render', () => {
it('should render component', () => {
const { wrapper } = setup();
expect(wrapper).toMatchSnapshot();
});
it('should render component with disclaimer', () => {
const { wrapper } = setup({
data: mockData(),
});
expect(wrapper).toMatchSnapshot();
});
it('should show query return no time series', () => {
const { wrapper } = setup({
data: [],
});
expect(wrapper).toMatchSnapshot();
});
});
...@@ -9,6 +9,8 @@ import TimeSeries from 'app/core/time_series2'; ...@@ -9,6 +9,8 @@ import TimeSeries from 'app/core/time_series2';
import Legend from './Legend'; import Legend from './Legend';
const MAX_NUMBER_OF_TIME_SERIES = 20;
// Copied from graph.ts // Copied from graph.ts
function time_format(ticks, min, max) { function time_format(ticks, min, max) {
if (min && max && ticks) { if (min && max && ticks) {
...@@ -67,6 +69,16 @@ const FLOT_OPTIONS = { ...@@ -67,6 +69,16 @@ const FLOT_OPTIONS = {
}; };
class Graph extends Component<any, any> { class Graph extends Component<any, any> {
state = {
showAllTimeSeries: false,
};
getGraphData() {
const { data } = this.props;
return this.state.showAllTimeSeries ? data : data.slice(0, MAX_NUMBER_OF_TIME_SERIES);
}
componentDidMount() { componentDidMount() {
this.draw(); this.draw();
} }
...@@ -82,8 +94,19 @@ class Graph extends Component<any, any> { ...@@ -82,8 +94,19 @@ class Graph extends Component<any, any> {
} }
} }
onShowAllTimeSeries = () => {
this.setState(
{
showAllTimeSeries: true,
},
this.draw
);
};
draw() { draw() {
const { data, options: userOptions } = this.props; const { options: userOptions } = this.props;
const data = this.getGraphData();
const $el = $(`#${this.props.id}`); const $el = $(`#${this.props.id}`);
if (!data) { if (!data) {
$el.empty(); $el.empty();
...@@ -124,8 +147,10 @@ class Graph extends Component<any, any> { ...@@ -124,8 +147,10 @@ class Graph extends Component<any, any> {
} }
render() { render() {
const { data, height, loading } = this.props; const { height, loading } = this.props;
if (!loading && data && data.length === 0) { const data = this.getGraphData();
if (!loading && data.length === 0) {
return ( return (
<div className="panel-container"> <div className="panel-container">
<div className="muted m-a-1">The queries returned no time series to graph.</div> <div className="muted m-a-1">The queries returned no time series to graph.</div>
...@@ -133,10 +158,22 @@ class Graph extends Component<any, any> { ...@@ -133,10 +158,22 @@ class Graph extends Component<any, any> {
); );
} }
return ( return (
<div>
{this.props.data.length > MAX_NUMBER_OF_TIME_SERIES &&
!this.state.showAllTimeSeries && (
<div className="time-series-disclaimer">
<i className="fa fa-fw fa-warning disclaimer-icon" />
{`Showing only ${MAX_NUMBER_OF_TIME_SERIES} time series. `}
<span className="show-all-time-series" onClick={this.onShowAllTimeSeries}>{`Show all ${
this.props.data.length
}`}</span>
</div>
)}
<div className="panel-container"> <div className="panel-container">
<div id={this.props.id} className="explore-graph" style={{ height }} /> <div id={this.props.id} className="explore-graph" style={{ height }} />
<Legend data={data} /> <Legend data={data} />
</div> </div>
</div>
); );
} }
} }
......
export const mockData = () => {
return [
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/label/:name/values',
instance: 'localhost:9090',
job: 'prometheus',
le: '+Inf',
},
values: [[1537858100, '16'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/label/:name/values',
instance: 'localhost:9090',
job: 'prometheus',
le: '0.1',
},
values: [[1537858100, '16'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/label/:name/values',
instance: 'localhost:9090',
job: 'prometheus',
le: '0.2',
},
values: [[1537858100, '16'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/label/:name/values',
instance: 'localhost:9090',
job: 'prometheus',
le: '0.4',
},
values: [[1537858100, '16'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/label/:name/values',
instance: 'localhost:9090',
job: 'prometheus',
le: '1',
},
values: [[1537858100, '16'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/label/:name/values',
instance: 'localhost:9090',
job: 'prometheus',
le: '120',
},
values: [[1537858100, '16'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/label/:name/values',
instance: 'localhost:9090',
job: 'prometheus',
le: '20',
},
values: [[1537858100, '16'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/label/:name/values',
instance: 'localhost:9090',
job: 'prometheus',
le: '3',
},
values: [[1537858100, '16'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/label/:name/values',
instance: 'localhost:9090',
job: 'prometheus',
le: '60',
},
values: [[1537858100, '16'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/label/:name/values',
instance: 'localhost:9090',
job: 'prometheus',
le: '8',
},
values: [[1537858100, '16'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/metrics',
instance: 'localhost:9090',
job: 'prometheus',
le: '+Inf',
},
values: [[1537858060, '1195'], [1537858080, '1195'], [1537858100, '1195']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/metrics',
instance: 'localhost:9090',
job: 'prometheus',
le: '0.1',
},
values: [[1537858060, '1195'], [1537858080, '1195'], [1537858100, '1195']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/metrics',
instance: 'localhost:9090',
job: 'prometheus',
le: '0.4',
},
values: [[1537858060, '1195'], [1537858080, '1195'], [1537858100, '1195']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/metrics',
instance: 'localhost:9090',
job: 'prometheus',
le: '1',
},
values: [[1537847900, '953'], [1537858080, '1195'], [1537858100, '1195']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/metrics',
instance: 'localhost:9090',
job: 'prometheus',
le: '120',
},
values: [[1537858060, '1195'], [1537858080, '1195'], [1537858100, '1195']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/metrics',
instance: 'localhost:9090',
job: 'prometheus',
le: '20',
},
values: [[1537858060, '1195'], [1537858080, '1195'], [1537858100, '1195']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/metrics',
instance: 'localhost:9090',
job: 'prometheus',
le: '3',
},
values: [[1537858060, '1195'], [1537858080, '1195'], [1537858100, '1195']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/metrics',
instance: 'localhost:9090',
job: 'prometheus',
le: '60',
},
values: [[1537858060, '1195'], [1537858080, '1195'], [1537858100, '1195']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/metrics',
instance: 'localhost:9090',
job: 'prometheus',
le: '8',
},
values: [[1537858060, '1195'], [1537858080, '1195'], [1537858100, '1195']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/query',
instance: 'localhost:9090',
job: 'prometheus',
le: '+Inf',
},
values: [[1537858100, '55'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/query',
instance: 'localhost:9090',
job: 'prometheus',
le: '0.1',
},
values: [[1537858100, '55'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/query',
instance: 'localhost:9090',
job: 'prometheus',
le: '0.2',
},
values: [[1537858100, '55'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/query',
instance: 'localhost:9090',
job: 'prometheus',
le: '0.4',
},
values: [[1537858100, '55'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/query',
instance: 'localhost:9090',
job: 'prometheus',
le: '1',
},
values: [[1537858100, '55'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/query',
instance: 'localhost:9090',
job: 'prometheus',
le: '120',
},
values: [[1537858100, '55'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/query',
instance: 'localhost:9090',
job: 'prometheus',
le: '20',
},
values: [[1537858100, '55'], [1537861960, '1'], [1537861980, '1']],
},
{
metric: {
__name__: 'prometheus_http_request_duration_seconds_bucket',
handler: '/query',
instance: 'localhost:9090',
job: 'prometheus',
le: '3',
},
values: [[1537857260, '55'], [1537861960, '1'], [1537861980, '1']],
},
];
};
...@@ -55,6 +55,25 @@ ...@@ -55,6 +55,25 @@
margin-top: 2 * $panel-margin; margin-top: 2 * $panel-margin;
} }
.time-series-disclaimer {
width: 300px;
margin: $panel-margin auto;
padding: 10px 0;
border-radius: $border-radius;
text-align: center;
background-color: $panel-bg;
.disclaimer-icon {
color: $yellow;
margin-right: $panel-margin/2;
}
.show-all-time-series {
cursor: pointer;
color: $external-link-color;
}
}
.elapsed-time { .elapsed-time {
position: absolute; position: absolute;
left: 0; left: 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment