[Uptime] Add crosshair sync for monitor page charts (#28631)

* Add crosshair sync for monitor page charts.

* Fix errant prop in chart component.

* Fix checks domain.
This commit is contained in:
Justin Kambic 2019-01-23 14:00:38 -05:00 committed by GitHub
parent a11e471420
commit 476a88e309
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -32,130 +32,217 @@ interface MonitorChartsProps {
monitorId: string;
}
interface MonitorChartsState {
crosshairLocation: number;
}
type Props = MonitorChartsProps & UptimeCommonProps;
export const MonitorCharts = ({
dateRangeStart,
dateRangeEnd,
monitorId,
autorefreshIsPaused,
autorefreshInterval,
}: Props) => (
<Query
pollInterval={autorefreshIsPaused ? undefined : autorefreshInterval}
query={createGetMonitorChartsQuery}
variables={{ dateRangeStart, dateRangeEnd, monitorId }}
>
{({ loading, error, data }) => {
if (loading) {
return i18n.translate('xpack.uptime.monitorCharts.loadingMessage', {
defaultMessage: 'Loading…',
});
}
if (error) {
return i18n.translate('xpack.uptime.monitorCharts.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
export class MonitorCharts extends React.Component<Props, MonitorChartsState> {
constructor(props: Props) {
super(props);
this.state = { crosshairLocation: 0 };
}
// TODO: this should not exist in the UI, update the GQL resolver/schema to return
// an object that contains these series already shaped in the way required by the visualizations.
const { monitorChartsData } = data;
const rttWriteRequestSeries: any[] = [];
const rttValidateSeries: any[] = [];
const rttContentSeries: any[] = [];
const rttResponseSeries: any[] = [];
const rttTcpSeries: any[] = [];
const avgDurationSeries: any[] = [];
const areaRttSeries: any[] = [];
const downSeries: any[] = [];
const upSeries: any[] = [];
const checksSeries: any[] = [];
const maxRtt: any[] = [];
monitorChartsData.forEach(
({
maxWriteRequest,
maxValidate,
maxContent,
maxResponse,
maxTcpRtt,
avgDuration,
maxDuration,
minDuration,
status,
}: any) => {
// We're summing these values because we need to know what the max value of the RTT
// fields are in order to provide an accurate domain size for the RTT combination series.
maxRtt.push({
x: maxWriteRequest.x,
y: maxWriteRequest.y + maxValidate.y + maxContent.y + maxResponse.y + maxTcpRtt.y,
});
// TODO: these types of computations should take place on the server and be reflected in the GQL schema
rttWriteRequestSeries.push(maxWriteRequest);
rttValidateSeries.push(maxValidate);
rttContentSeries.push(maxContent);
rttResponseSeries.push(maxResponse);
rttTcpSeries.push(maxTcpRtt);
avgDurationSeries.push(avgDuration);
areaRttSeries.push({ x: minDuration.x, y0: minDuration.y, y: maxDuration.y });
downSeries.push({ x: status.x, y: status.down });
upSeries.push({ x: status.x, y: status.up });
checksSeries.push({ x: status.x, y: status.total });
}
);
public render() {
const {
dateRangeStart,
dateRangeEnd,
monitorId,
autorefreshIsPaused,
autorefreshInterval,
} = this.props;
return (
<Query
pollInterval={autorefreshIsPaused ? undefined : autorefreshInterval}
query={createGetMonitorChartsQuery}
variables={{ dateRangeStart, dateRangeEnd, monitorId }}
>
{({ loading, error, data }) => {
if (loading) {
return i18n.translate('xpack.uptime.monitorCharts.loadingMessage', {
defaultMessage: 'Loading…',
});
}
if (error) {
return i18n.translate('xpack.uptime.monitorCharts.errorMessage', {
values: { message: error.message },
defaultMessage: 'Error {message}',
});
}
// As above, we are building a domain size for the chart to use.
// Without this code the chart could render data outside of the field.
const checksDomain = upSeries.concat(downSeries).map(({ y }) => y);
const domainLimits = [Math.min(...checksDomain), Math.max(...checksDomain)];
const durationDomain = avgDurationSeries.concat(areaRttSeries);
const durationLimits = [0, Math.max(...durationDomain.map(({ y }) => y))];
// TODO: this should not exist in the UI, update the GQL resolver/schema to return
// an object that contains these series already shaped in the way required by the visualizations.
const { monitorChartsData } = data;
const rttWriteRequestSeries: any[] = [];
const rttValidateSeries: any[] = [];
const rttContentSeries: any[] = [];
const rttResponseSeries: any[] = [];
const rttTcpSeries: any[] = [];
const avgDurationSeries: any[] = [];
const areaRttSeries: any[] = [];
const downSeries: any[] = [];
const upSeries: any[] = [];
const checksSeries: any[] = [];
const maxRtt: any[] = [];
monitorChartsData.forEach(
({
maxWriteRequest,
maxValidate,
maxContent,
maxResponse,
maxTcpRtt,
avgDuration,
maxDuration,
minDuration,
status,
}: any) => {
// We're summing these values because we need to know what the max value of the RTT
// fields are in order to provide an accurate domain size for the RTT combination series.
maxRtt.push({
x: maxWriteRequest.x,
y: maxWriteRequest.y + maxValidate.y + maxContent.y + maxResponse.y + maxTcpRtt.y,
});
// TODO: these types of computations should take place on the server and be reflected in the GQL schema
rttWriteRequestSeries.push(maxWriteRequest);
rttValidateSeries.push(maxValidate);
rttContentSeries.push(maxContent);
rttResponseSeries.push(maxResponse);
rttTcpSeries.push(maxTcpRtt);
avgDurationSeries.push(avgDuration);
areaRttSeries.push({ x: minDuration.x, y0: minDuration.y, y: maxDuration.y });
downSeries.push({ x: status.x, y: status.down });
upSeries.push({ x: status.x, y: status.up });
checksSeries.push({ x: status.x, y: status.total });
}
);
return (
<Fragment>
<EuiFlexGroup>
<EuiFlexItem>
<EuiTitle size="xs">
<h4>
<FormattedMessage
id="xpack.uptime.monitorCharts.monitorDuration.titleLabel"
defaultMessage="Monitor Duration ms"
description="The 'ms' is an abbreviation for milliseconds."
/>
</h4>
</EuiTitle>
<EuiPanel style={{ maxWidth: 520, maxHeight: 220 }}>
<EuiSeriesChart
margins={{ left: 60, right: 40, top: 10, bottom: 40 }}
width={500}
height={200}
xType={EuiSeriesChartUtils.SCALE.TIME}
yDomain={durationLimits}
>
<EuiAreaSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel',
{
defaultMessage: 'Duration range',
}
)}
data={areaRttSeries}
curve="curveBasis"
/>
<EuiLineSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel',
{
defaultMessage: 'Mean duration',
}
)}
data={avgDurationSeries}
/>
</EuiSeriesChart>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
// As above, we are building a domain size for the chart to use.
// Without this code the chart could render data outside of the field.
const checksDomain = upSeries.concat(downSeries).map(({ y }) => y);
const domainLimits = [0, Math.max(...checksDomain)];
const durationDomain = avgDurationSeries.concat(areaRttSeries);
const durationLimits = [0, Math.max(...durationDomain.map(({ y }) => y))];
// find the greatest y-value for rtt chart
const rttLimits = [0, Math.max(...maxRtt.map(({ y }) => y))];
return (
<Fragment>
<EuiFlexGroup>
<EuiFlexItem>
<EuiTitle size="xs">
<h4>
<FormattedMessage
id="xpack.uptime.monitorCharts.rttBreakdownTitle"
defaultMessage="RTT Breakdown ms"
description="The 'ms' is an abbreviation for milliseconds."
/>
</h4>
</EuiTitle>
<EuiPanel>
<EuiSeriesChart
stackBy="y"
margins={{ left: 60, right: 40, top: 10, bottom: 40 }}
xType={EuiSeriesChartUtils.SCALE.TIME}
width={500}
height={200}
crosshairValue={this.state.crosshairLocation}
onCrosshairUpdate={this.updateCrosshairLocation}
yDomain={rttLimits}
>
<EuiAreaSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.rtt.series.writeRequestLabel',
{
defaultMessage: 'Write request',
}
)}
data={rttWriteRequestSeries}
curve="curveBasis"
/>
<EuiAreaSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.rtt.series.validateLabel',
{
defaultMessage: 'Validate',
}
)}
data={rttValidateSeries}
curve="curveBasis"
/>
<EuiAreaSeries
name={i18n.translate('xpack.uptime.monitorCharts.rtt.series.contentLabel', {
defaultMessage: 'Content',
})}
data={rttContentSeries}
curve="curveBasis"
/>
<EuiAreaSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.rtt.series.responseLabel',
{
defaultMessage: 'Response',
}
)}
data={rttResponseSeries}
curve="curveBasis"
/>
<EuiAreaSeries
name={i18n.translate('xpack.uptime.monitorCharts.rtt.series.tcpLabel', {
defaultMessage: 'Tcp',
})}
data={rttTcpSeries}
curve="curveBasis"
/>
</EuiSeriesChart>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiTitle size="xs">
<h4>
<FormattedMessage
id="xpack.uptime.monitorCharts.monitorDuration.titleLabel"
defaultMessage="Monitor Duration ms"
description="The 'ms' is an abbreviation for milliseconds."
/>
</h4>
</EuiTitle>
<EuiPanel style={{ maxWidth: 520, maxHeight: 220 }}>
<EuiSeriesChart
margins={{ left: 60, right: 40, top: 10, bottom: 40 }}
width={500}
height={200}
xType={EuiSeriesChartUtils.SCALE.TIME}
yDomain={durationLimits}
crosshairValue={this.state.crosshairLocation}
onCrosshairUpdate={this.updateCrosshairLocation}
>
<EuiAreaSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel',
{
defaultMessage: 'Duration range',
}
)}
data={areaRttSeries}
curve="curveBasis"
/>
<EuiLineSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel',
{
defaultMessage: 'Mean duration',
}
)}
data={avgDurationSeries}
/>
</EuiSeriesChart>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
<EuiTitle size="xs">
<h4>
<FormattedMessage
@ -171,6 +258,8 @@ export const MonitorCharts = ({
height={200}
xType={EuiSeriesChartUtils.SCALE.TIME}
stackBy="y"
crosshairValue={this.state.crosshairLocation}
onCrosshairUpdate={this.updateCrosshairLocation}
yDomain={domainLimits}
>
<EuiAreaSeries
@ -195,10 +284,12 @@ export const MonitorCharts = ({
/>
</EuiSeriesChart>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</Fragment>
);
}}
</Query>
);
</Fragment>
);
}}
</Query>
);
}
private updateCrosshairLocation = (crosshairLocation: number) =>
this.setState({ crosshairLocation });
}