[Uptime] Implemented drag and select on charts (#57089) (#57665)

* Implemented drag and select on charts

* fix test

* unused

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Shahzad 2020-02-14 14:54:17 +01:00 committed by GitHub
parent ba8b610424
commit 552e8f83af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 316 additions and 46 deletions

View file

@ -1,48 +1,248 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PingHistogram component renders the component without errors 1`] = `
<Fragment>
<EuiTitle
size="xs"
Array [
<h2
class="euiTitle euiTitle--xsmall"
>
<h5>
<FormattedMessage
defaultMessage="Pings over time"
id="xpack.uptime.snapshot.pingsOverTimeTitle"
values={Object {}}
Pings over time
</h2>,
<div
aria-label="Bar Chart showing uptime status over time from a year ago to a year ago."
style="height:100%;opacity:1;transition:opacity 0.2s"
>
<div
class="echChart"
>
<div
class="echChartStatus"
data-ech-render-complete="false"
data-ech-render-count="0"
/>
</h5>
</EuiTitle>
<EuiPanel
paddingSize="s"
style={
<div
class="echChartResizer"
/>
<div
class="echContainer"
>
<div
class="echReactiveChart_unavailable"
>
<p>
No data to display
</p>
</div>
</div>
</div>
</div>,
]
`;
exports[`PingHistogram component shallow renders the component without errors 1`] = `
<ContextProvider
value={
Object {
"history": Object {
"action": "POP",
"block": [Function],
"canGo": [Function],
"createHref": [Function],
"entries": Array [
Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
],
"go": [Function],
"goBack": [Function],
"goForward": [Function],
"index": 0,
"length": 1,
"listen": [Function],
"location": Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
"push": [Function],
"replace": [Function],
},
"location": Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
"match": Object {
"isExact": true,
"params": Object {},
"path": "/",
"url": "/",
},
"staticContext": undefined,
}
}
>
<PingHistogramComponent
absoluteEndDate={1548700920000}
absoluteStartDate={1548697920000}
data={
Object {
"height": 170,
"histogram": Array [
Object {
"downCount": 6,
"upCount": 33,
"x": 1581068329000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 30,
"x": 1581068359000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 33,
"x": 1581068389000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 30,
"x": 1581068419000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 33,
"x": 1581068449000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 30,
"x": 1581068479000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 33,
"x": 1581068509000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 30,
"x": 1581068539000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 33,
"x": 1581068569000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 30,
"x": 1581068599000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 33,
"x": 1581068629000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 30,
"x": 1581068659000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 33,
"x": 1581068689000,
"y": 1,
},
Object {
"downCount": 6,
"upCount": 30,
"x": 1581068719000,
"y": 1,
},
Object {
"downCount": 5,
"upCount": 34,
"x": 1581068749000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 33,
"x": 1581068779000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 36,
"x": 1581068809000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 33,
"x": 1581068839000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 36,
"x": 1581068869000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 33,
"x": 1581068899000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 36,
"x": 1581068929000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 33,
"x": 1581068959000,
"y": 1,
},
Object {
"downCount": 3,
"upCount": 36,
"x": 1581068989000,
"y": 1,
},
Object {
"downCount": 1,
"upCount": 11,
"x": 1581069019000,
"y": 1,
},
],
"interval": "1s",
}
}
>
<EuiEmptyPrompt
body={
<p>
<FormattedMessage
defaultMessage="Sorry, there is no data available for the histogram"
id="xpack.uptime.snapshot.noDataDescription"
values={Object {}}
/>
</p>
}
title={
<EuiTitle>
<h5>
<FormattedMessage
defaultMessage="No histogram data available"
id="xpack.uptime.snapshot.noDataTitle"
values={Object {}}
/>
</h5>
</EuiTitle>
}
/>
</EuiPanel>
</Fragment>
/>
</ContextProvider>
`;

View file

@ -5,17 +5,51 @@
*/
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { PingHistogramComponent, PingHistogramComponentProps } from '../ping_histogram';
import { renderWithRouter, shallowWithRouter } from '../../../../lib';
describe('PingHistogram component', () => {
const props: PingHistogramComponentProps = {
absoluteStartDate: 1548697920000,
absoluteEndDate: 1548700920000,
data: {
histogram: [
{ x: 1581068329000, downCount: 6, upCount: 33, y: 1 },
{ x: 1581068359000, downCount: 6, upCount: 30, y: 1 },
{ x: 1581068389000, downCount: 6, upCount: 33, y: 1 },
{ x: 1581068419000, downCount: 6, upCount: 30, y: 1 },
{ x: 1581068449000, downCount: 6, upCount: 33, y: 1 },
{ x: 1581068479000, downCount: 6, upCount: 30, y: 1 },
{ x: 1581068509000, downCount: 6, upCount: 33, y: 1 },
{ x: 1581068539000, downCount: 6, upCount: 30, y: 1 },
{ x: 1581068569000, downCount: 6, upCount: 33, y: 1 },
{ x: 1581068599000, downCount: 6, upCount: 30, y: 1 },
{ x: 1581068629000, downCount: 6, upCount: 33, y: 1 },
{ x: 1581068659000, downCount: 6, upCount: 30, y: 1 },
{ x: 1581068689000, downCount: 6, upCount: 33, y: 1 },
{ x: 1581068719000, downCount: 6, upCount: 30, y: 1 },
{ x: 1581068749000, downCount: 5, upCount: 34, y: 1 },
{ x: 1581068779000, downCount: 3, upCount: 33, y: 1 },
{ x: 1581068809000, downCount: 3, upCount: 36, y: 1 },
{ x: 1581068839000, downCount: 3, upCount: 33, y: 1 },
{ x: 1581068869000, downCount: 3, upCount: 36, y: 1 },
{ x: 1581068899000, downCount: 3, upCount: 33, y: 1 },
{ x: 1581068929000, downCount: 3, upCount: 36, y: 1 },
{ x: 1581068959000, downCount: 3, upCount: 33, y: 1 },
{ x: 1581068989000, downCount: 3, upCount: 36, y: 1 },
{ x: 1581069019000, downCount: 1, upCount: 11, y: 1 },
],
interval: '1s',
},
};
it('shallow renders the component without errors', () => {
const component = shallowWithRouter(<PingHistogramComponent {...props} />);
expect(component).toMatchSnapshot();
});
it('renders the component without errors', () => {
const component = shallowWithIntl(<PingHistogramComponent {...props} />);
const component = renderWithRouter(<PingHistogramComponent {...props} />);
expect(component).toMatchSnapshot();
});
});

View file

@ -8,6 +8,7 @@ import { Axis, Chart, Position, timeFormatter, Settings } from '@elastic/charts'
import { EuiPanel, EuiTitle } from '@elastic/eui';
import React from 'react';
import { i18n } from '@kbn/i18n';
import moment from 'moment';
import { FormattedMessage } from '@kbn/i18n/react';
import { getChartDateLabel } from '../../../lib/helper';
import { LocationDurationLine } from '../../../../common/graphql/types';
@ -50,9 +51,15 @@ export const DurationChart = ({
loading,
}: DurationChartProps) => {
const hasLines = locationDurationLines.length > 0;
const [getUrlParams] = useUrlParams();
const [getUrlParams, updateUrlParams] = useUrlParams();
const { absoluteDateRangeStart: min, absoluteDateRangeEnd: max } = getUrlParams();
const onBrushEnd = (minX: number, maxX: number) => {
updateUrlParams({
dateRangeStart: moment(minX).toISOString(),
dateRangeEnd: moment(maxX).toISOString(),
});
};
return (
<>
<EuiPanel paddingSize="m">
@ -68,7 +75,12 @@ export const DurationChart = ({
<ChartWrapper height="400px" loading={loading}>
{hasLines ? (
<Chart>
<Settings xDomain={{ min, max }} showLegend={true} legendPosition={Position.Bottom} />
<Settings
xDomain={{ min, max }}
showLegend={true}
legendPosition={Position.Bottom}
onBrushEnd={onBrushEnd}
/>
<Axis
id="bottom"
position={Position.Bottom}

View file

@ -15,6 +15,7 @@ import {
} from '@elastic/charts';
import { i18n } from '@kbn/i18n';
import React from 'react';
import moment from 'moment';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiText, EuiToolTip } from '@elastic/eui';
import { SummaryHistogramPoint } from '../../../../common/graphql/types';
@ -38,15 +39,25 @@ export interface MonitorBarSeriesProps {
* @param props - the values for the monitor this chart visualizes
*/
export const MonitorBarSeries = ({ dangerColor, histogramSeries }: MonitorBarSeriesProps) => {
const [getUrlParams] = useUrlParams();
const [getUrlParams, updateUrlParams] = useUrlParams();
const { absoluteDateRangeStart, absoluteDateRangeEnd } = getUrlParams();
const onBrushEnd = (min: number, max: number) => {
updateUrlParams({
dateRangeStart: moment(min).toISOString(),
dateRangeEnd: moment(max).toISOString(),
});
};
const id = 'downSeries';
return seriesHasDownValues(histogramSeries) ? (
<div style={{ height: 50, width: '100%', maxWidth: '1200px', marginRight: 15 }}>
<Chart>
<Settings xDomain={{ min: absoluteDateRangeStart, max: absoluteDateRangeEnd }} />
<Settings
xDomain={{ min: absoluteDateRangeStart, max: absoluteDateRangeEnd }}
onBrushEnd={onBrushEnd}
/>
<Axis
hide
id="bottom"

View file

@ -14,6 +14,7 @@ import { getChartDateLabel } from '../../../lib/helper';
import { ChartWrapper } from './chart_wrapper';
import { UptimeThemeContext } from '../../../contexts';
import { HistogramResult } from '../../../../common/types';
import { useUrlParams } from '../../../hooks';
export interface PingHistogramComponentProps {
/**
@ -45,6 +46,9 @@ export const PingHistogramComponent: React.FC<PingHistogramComponentProps> = ({
const {
colors: { danger, gray },
} = useContext(UptimeThemeContext);
const [, updateUrlParams] = useUrlParams();
if (!data || !data.histogram)
/**
* TODO: the Fragment, EuiTitle, and EuiPanel should be extracted to a dumb component
@ -93,6 +97,13 @@ export const PingHistogramComponent: React.FC<PingHistogramComponentProps> = ({
const upMonitorsId = i18n.translate('xpack.uptime.snapshotHistogram.series.upLabel', {
defaultMessage: 'Up',
});
const onBrushEnd = (min: number, max: number) => {
updateUrlParams({
dateRangeStart: moment(min).toISOString(),
dateRangeEnd: moment(max).toISOString(),
});
};
return (
<>
<EuiTitle size="xs">
@ -122,6 +133,7 @@ export const PingHistogramComponent: React.FC<PingHistogramComponentProps> = ({
max: absoluteEndDate,
}}
showLegend={false}
onBrushEnd={onBrushEnd}
/>
<Axis
id={i18n.translate('xpack.uptime.snapshotHistogram.xAxisId', {
@ -142,6 +154,7 @@ export const PingHistogramComponent: React.FC<PingHistogramComponentProps> = ({
'The label on the y-axis of a chart that displays the number of times Heartbeat has pinged a set of services/websites.',
})}
/>
<BarSeries
customSeriesColors={[danger]}
data={histogram.map(({ x, downCount }) => [x, downCount || 0])}

View file

@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { renderWithRouter, shallowWithRouter, mountWithRouter } from './helper/render_with_router';
export { renderWithRouter, shallowWithRouter, mountWithRouter } from './helper/helper_with_router';