mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
* Refactor chart querying. * Fix monitor chart query. * Refactor several inline computations to helper functions. Improve schema naming. * Move unit conversion to client, remove bare conversion values. * Add API tests for monitor charts. * Add test for conversion function. * Add type annotations to latest schema additions. * Fix typo. * Refactor based on PR feedback, add comments asked for in PR feedback. * Rename fields in schema, update tests. Extract monitor charts to functional component and add unit test.
This commit is contained in:
parent
d7f95fee0d
commit
507e7139e3
30 changed files with 1135 additions and 389 deletions
|
@ -183,11 +183,7 @@
|
|||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": { "kind": "OBJECT", "name": "MonitorChartEntry", "ofType": null }
|
||||
},
|
||||
"type": { "kind": "OBJECT", "name": "MonitorChart", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
|
@ -1575,11 +1571,11 @@
|
|||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "LatestMonitor",
|
||||
"description": "",
|
||||
"description": "Represents the latest recorded information about a monitor.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"description": "",
|
||||
"description": "The ID of the monitor represented by this data.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
|
@ -1591,7 +1587,7 @@
|
|||
},
|
||||
{
|
||||
"name": "ping",
|
||||
"description": "",
|
||||
"description": "Information from the latest document.",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "Ping", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
|
@ -1599,7 +1595,7 @@
|
|||
},
|
||||
{
|
||||
"name": "upSeries",
|
||||
"description": "",
|
||||
"description": "Buckets of recent up count status data.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
|
@ -1611,7 +1607,7 @@
|
|||
},
|
||||
{
|
||||
"name": "downSeries",
|
||||
"description": "",
|
||||
"description": "Buckets of recent down count status data.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
|
@ -1793,86 +1789,94 @@
|
|||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "MonitorChartEntry",
|
||||
"description": "",
|
||||
"name": "MonitorChart",
|
||||
"description": "The data used to populate the monitor charts.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "maxContent",
|
||||
"description": "",
|
||||
"name": "durationArea",
|
||||
"description": "The max and min values for the monitor duration.",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null },
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "OBJECT", "name": "MonitorDurationAreaPoint", "ofType": null }
|
||||
}
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "maxResponse",
|
||||
"description": "",
|
||||
"name": "durationLine",
|
||||
"description": "The average values for the monitor duration.",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "maxValidate",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "maxTotal",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "maxWriteRequest",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "maxTcpRtt",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "maxDuration",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "minDuration",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "avgDuration",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "DataPoint", "ofType": null },
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "MonitorDurationAveragePoint",
|
||||
"ofType": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"description": "",
|
||||
"description": "The counts of up/down checks for the monitor.",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "StatusData", "ofType": null },
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "OBJECT", "name": "StatusData", "ofType": null }
|
||||
}
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "statusMaxCount",
|
||||
"description": "The maximum status doc count in this chart.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "Int", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "durationMaxValue",
|
||||
"description": "The maximum duration value in this chart.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "Int", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
|
@ -1884,20 +1888,32 @@
|
|||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "DataPoint",
|
||||
"description": "",
|
||||
"name": "MonitorDurationAreaPoint",
|
||||
"description": "Represents a monitor's duration performance in microseconds at a point in time.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "x",
|
||||
"description": "",
|
||||
"description": "The timeseries value for this point in time.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null },
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "y",
|
||||
"description": "",
|
||||
"name": "yMin",
|
||||
"description": "The min duration value in microseconds at this time.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "yMax",
|
||||
"description": "The max duration value in microseconds at this point.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
|
@ -1921,20 +1937,55 @@
|
|||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "StatusData",
|
||||
"description": "",
|
||||
"name": "MonitorDurationAveragePoint",
|
||||
"description": "Represents the average monitor duration ms at a point in time.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "x",
|
||||
"description": "",
|
||||
"description": "The timeseries value for this point.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null },
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "y",
|
||||
"description": "The average duration ms for the monitor.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "StatusData",
|
||||
"description": "Represents a bucket of monitor status information.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "x",
|
||||
"description": "The timeseries point for this status data.",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "up",
|
||||
"description": "",
|
||||
"description": "The value of up counts for this point.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "Int", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
|
@ -1942,7 +1993,7 @@
|
|||
},
|
||||
{
|
||||
"name": "down",
|
||||
"description": "",
|
||||
"description": "The value for down counts for this point.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "Int", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
|
@ -1950,7 +2001,7 @@
|
|||
},
|
||||
{
|
||||
"name": "total",
|
||||
"description": "",
|
||||
"description": "The total down counts for this point.",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "Int", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
|
@ -2854,6 +2905,33 @@
|
|||
}
|
||||
],
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "DataPoint",
|
||||
"description": "",
|
||||
"fields": [
|
||||
{
|
||||
"name": "x",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "y",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
|
|
|
@ -24,7 +24,7 @@ export interface Query {
|
|||
|
||||
getSnapshot?: Snapshot | null;
|
||||
|
||||
getMonitorChartsData?: (MonitorChartEntry | null)[] | null;
|
||||
getMonitorChartsData?: MonitorChart | null;
|
||||
|
||||
getLatestMonitors: Ping[];
|
||||
|
||||
|
@ -307,14 +307,15 @@ export interface DocCount {
|
|||
export interface LatestMonitorsResult {
|
||||
monitors?: LatestMonitor[] | null;
|
||||
}
|
||||
|
||||
/** Represents the latest recorded information about a monitor. */
|
||||
export interface LatestMonitor {
|
||||
/** The ID of the monitor represented by this data. */
|
||||
id: MonitorKey;
|
||||
|
||||
/** Information from the latest document. */
|
||||
ping?: Ping | null;
|
||||
|
||||
/** Buckets of recent up count status data. */
|
||||
upSeries?: (MonitorSeriesPoint | null)[] | null;
|
||||
|
||||
/** Buckets of recent down count status data. */
|
||||
downSeries?: (MonitorSeriesPoint | null)[] | null;
|
||||
}
|
||||
|
||||
|
@ -351,42 +352,44 @@ export interface HistogramDataPoint {
|
|||
|
||||
y?: UnsignedInteger | null;
|
||||
}
|
||||
|
||||
export interface MonitorChartEntry {
|
||||
maxContent?: DataPoint | null;
|
||||
|
||||
maxResponse?: DataPoint | null;
|
||||
|
||||
maxValidate?: DataPoint | null;
|
||||
|
||||
maxTotal?: DataPoint | null;
|
||||
|
||||
maxWriteRequest?: DataPoint | null;
|
||||
|
||||
maxTcpRtt?: DataPoint | null;
|
||||
|
||||
maxDuration?: DataPoint | null;
|
||||
|
||||
minDuration?: DataPoint | null;
|
||||
|
||||
avgDuration?: DataPoint | null;
|
||||
|
||||
status?: StatusData | null;
|
||||
/** The data used to populate the monitor charts. */
|
||||
export interface MonitorChart {
|
||||
/** The max and min values for the monitor duration. */
|
||||
durationArea: MonitorDurationAreaPoint[];
|
||||
/** The average values for the monitor duration. */
|
||||
durationLine: MonitorDurationAveragePoint[];
|
||||
/** The counts of up/down checks for the monitor. */
|
||||
status: StatusData[];
|
||||
/** The maximum status doc count in this chart. */
|
||||
statusMaxCount: number;
|
||||
/** The maximum duration value in this chart. */
|
||||
durationMaxValue: number;
|
||||
}
|
||||
|
||||
export interface DataPoint {
|
||||
x?: UnsignedInteger | null;
|
||||
|
||||
/** Represents a monitor's duration performance in microseconds at a point in time. */
|
||||
export interface MonitorDurationAreaPoint {
|
||||
/** The timeseries value for this point in time. */
|
||||
x: UnsignedInteger;
|
||||
/** The min duration value in microseconds at this time. */
|
||||
yMin?: number | null;
|
||||
/** The max duration value in microseconds at this point. */
|
||||
yMax?: number | null;
|
||||
}
|
||||
/** Represents the average monitor duration ms at a point in time. */
|
||||
export interface MonitorDurationAveragePoint {
|
||||
/** The timeseries value for this point. */
|
||||
x: UnsignedInteger;
|
||||
/** The average duration ms for the monitor. */
|
||||
y?: number | null;
|
||||
}
|
||||
|
||||
/** Represents a bucket of monitor status information. */
|
||||
export interface StatusData {
|
||||
x?: UnsignedInteger | null;
|
||||
|
||||
/** The timeseries point for this status data. */
|
||||
x: UnsignedInteger;
|
||||
/** The value of up counts for this point. */
|
||||
up?: number | null;
|
||||
|
||||
/** The value for down counts for this point. */
|
||||
down?: number | null;
|
||||
|
||||
/** The total down counts for this point. */
|
||||
total?: number | null;
|
||||
}
|
||||
|
||||
|
@ -424,6 +427,12 @@ export interface MonitorPageTitle {
|
|||
name?: string | null;
|
||||
}
|
||||
|
||||
export interface DataPoint {
|
||||
x?: UnsignedInteger | null;
|
||||
|
||||
y?: number | null;
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// Arguments
|
||||
// ====================================================
|
||||
|
|
|
@ -0,0 +1,355 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`MonitorCharts component renders the component without errors 1`] = `
|
||||
<Fragment>
|
||||
<EuiFlexGroup
|
||||
alignItems="stretch"
|
||||
component="div"
|
||||
direction="row"
|
||||
gutterSize="l"
|
||||
justifyContent="flexStart"
|
||||
responsive={true}
|
||||
wrap={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={true}
|
||||
>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
textTransform="none"
|
||||
>
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
defaultMessage="Monitor Duration ms"
|
||||
description="The 'ms' is an abbreviation for milliseconds."
|
||||
id="xpack.uptime.monitorCharts.monitorDuration.titleLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
paddingSize="m"
|
||||
style={
|
||||
Object {
|
||||
"maxHeight": 220,
|
||||
"maxWidth": 520,
|
||||
}
|
||||
}
|
||||
>
|
||||
<FlexibleEuiSeriesChart
|
||||
crosshairValue={150}
|
||||
height={200}
|
||||
margins={
|
||||
Object {
|
||||
"bottom": 40,
|
||||
"left": 60,
|
||||
"right": 40,
|
||||
"top": 10,
|
||||
}
|
||||
}
|
||||
onCrosshairUpdate={[MockFunction]}
|
||||
width={500}
|
||||
xCrosshairFormat="YYYY-MM-DD hh:mmZ"
|
||||
xType="time"
|
||||
yDomain={
|
||||
Array [
|
||||
0,
|
||||
75,
|
||||
]
|
||||
}
|
||||
>
|
||||
<EuiAreaSeries
|
||||
color="secondaryColor"
|
||||
curve="curveBasis"
|
||||
data={
|
||||
Array [
|
||||
Object {
|
||||
"x": 1548697620000,
|
||||
"y": 3120,
|
||||
"y0": 106,
|
||||
},
|
||||
Object {
|
||||
"x": 1548697920000,
|
||||
"y": 3955,
|
||||
"y0": 122,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698220000,
|
||||
"y": 3705,
|
||||
"y0": 118,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698520000,
|
||||
"y": 6669,
|
||||
"y0": 123,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698820000,
|
||||
"y": 3956,
|
||||
"y0": 117,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699120000,
|
||||
"y": 4045,
|
||||
"y0": 122,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699420000,
|
||||
"y": 3683,
|
||||
"y0": 120,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699720000,
|
||||
"y": 3701,
|
||||
"y0": 115,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700020000,
|
||||
"y": 3632,
|
||||
"y0": 112,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700320000,
|
||||
"y": 3801,
|
||||
"y0": 105,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700620000,
|
||||
"y": 3925,
|
||||
"y0": 124,
|
||||
},
|
||||
]
|
||||
}
|
||||
fillOpacity={1}
|
||||
lineSize={1}
|
||||
name="Duration range"
|
||||
/>
|
||||
<EuiLineSeries
|
||||
borderOpacity={1}
|
||||
color="primaryColor"
|
||||
curve="linear"
|
||||
data={
|
||||
Array [
|
||||
Object {
|
||||
"x": 1548697620000,
|
||||
"y": 744,
|
||||
},
|
||||
Object {
|
||||
"x": 1548697920000,
|
||||
"y": 767,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698220000,
|
||||
"y": 787,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698520000,
|
||||
"y": 781,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698820000,
|
||||
"y": 742,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699120000,
|
||||
"y": 759,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699420000,
|
||||
"y": 738,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699720000,
|
||||
"y": 729,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700020000,
|
||||
"y": 720,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700320000,
|
||||
"y": 769,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700620000,
|
||||
"y": 741,
|
||||
},
|
||||
]
|
||||
}
|
||||
lineMarkSize={0}
|
||||
lineSize={1}
|
||||
name="Mean duration"
|
||||
showLineMarks={false}
|
||||
/>
|
||||
</FlexibleEuiSeriesChart>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={true}
|
||||
>
|
||||
<EuiTitle
|
||||
size="xs"
|
||||
textTransform="none"
|
||||
>
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
defaultMessage="Check status"
|
||||
id="xpack.uptime.monitorCharts.checkStatus.title"
|
||||
values={Object {}}
|
||||
/>
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
paddingSize="m"
|
||||
style={
|
||||
Object {
|
||||
"maxHeight": 220,
|
||||
"maxWidth": 520,
|
||||
}
|
||||
}
|
||||
>
|
||||
<FlexibleEuiSeriesChart
|
||||
crosshairValue={150}
|
||||
height={200}
|
||||
margins={
|
||||
Object {
|
||||
"bottom": 40,
|
||||
"left": 60,
|
||||
"right": 40,
|
||||
"top": 10,
|
||||
}
|
||||
}
|
||||
onCrosshairUpdate={[MockFunction]}
|
||||
stackBy="y"
|
||||
width={500}
|
||||
xCrosshairFormat="YYYY-MM-DD hh:mmZ"
|
||||
xType="time"
|
||||
yDomain={
|
||||
Array [
|
||||
0,
|
||||
75,
|
||||
]
|
||||
}
|
||||
>
|
||||
<EuiAreaSeries
|
||||
color="primaryColor"
|
||||
curve="curveBasis"
|
||||
data={
|
||||
Array [
|
||||
Object {
|
||||
"x": 1548697620000,
|
||||
"y": 74,
|
||||
},
|
||||
Object {
|
||||
"x": 1548697920000,
|
||||
"y": 75,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698220000,
|
||||
"y": 75,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698520000,
|
||||
"y": 73,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698820000,
|
||||
"y": 75,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699120000,
|
||||
"y": 74,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699420000,
|
||||
"y": 75,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699720000,
|
||||
"y": 75,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700020000,
|
||||
"y": 75,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700320000,
|
||||
"y": 75,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700620000,
|
||||
"y": 75,
|
||||
},
|
||||
]
|
||||
}
|
||||
fillOpacity={1}
|
||||
lineSize={1}
|
||||
name="Up count"
|
||||
/>
|
||||
<EuiAreaSeries
|
||||
color="dangerColor"
|
||||
curve="linear"
|
||||
data={
|
||||
Array [
|
||||
Object {
|
||||
"x": 1548697620000,
|
||||
"y": null,
|
||||
},
|
||||
Object {
|
||||
"x": 1548697920000,
|
||||
"y": null,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698220000,
|
||||
"y": null,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698520000,
|
||||
"y": null,
|
||||
},
|
||||
Object {
|
||||
"x": 1548698820000,
|
||||
"y": null,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699120000,
|
||||
"y": null,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699420000,
|
||||
"y": null,
|
||||
},
|
||||
Object {
|
||||
"x": 1548699720000,
|
||||
"y": null,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700020000,
|
||||
"y": null,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700320000,
|
||||
"y": null,
|
||||
},
|
||||
Object {
|
||||
"x": 1548700620000,
|
||||
"y": null,
|
||||
},
|
||||
]
|
||||
}
|
||||
fillOpacity={1}
|
||||
lineSize={1}
|
||||
name="Down count"
|
||||
/>
|
||||
</FlexibleEuiSeriesChart>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</Fragment>
|
||||
`;
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { MonitorCharts } from '../monitor_charts';
|
||||
|
||||
describe('MonitorCharts component', () => {
|
||||
const chartResponse = {
|
||||
monitorChartsData: {
|
||||
durationArea: [
|
||||
{ x: 1548697620000, yMin: 106421, yMax: 3120392 },
|
||||
{ x: 1548697920000, yMin: 121653, yMax: 3955186 },
|
||||
{ x: 1548698220000, yMin: 118224, yMax: 3705359 },
|
||||
{ x: 1548698520000, yMin: 123345, yMax: 6669234 },
|
||||
{ x: 1548698820000, yMin: 117268, yMax: 3955729 },
|
||||
{ x: 1548699120000, yMin: 122110, yMax: 4045216 },
|
||||
{ x: 1548699420000, yMin: 120015, yMax: 3682859 },
|
||||
{ x: 1548699720000, yMin: 114751, yMax: 3701297 },
|
||||
{ x: 1548700020000, yMin: 111949, yMax: 3632224 },
|
||||
{ x: 1548700320000, yMin: 105126, yMax: 3801401 },
|
||||
{ x: 1548700620000, yMin: 123639, yMax: 3925269 },
|
||||
],
|
||||
durationLine: [
|
||||
{ x: 1548697620000, y: 743928.2027027027 },
|
||||
{ x: 1548697920000, y: 766840.0133333333 },
|
||||
{ x: 1548698220000, y: 786970.8266666667 },
|
||||
{ x: 1548698520000, y: 781064.7808219178 },
|
||||
{ x: 1548698820000, y: 741563.04 },
|
||||
{ x: 1548699120000, y: 759354.6756756756 },
|
||||
{ x: 1548699420000, y: 737533.3866666667 },
|
||||
{ x: 1548699720000, y: 728669.0266666666 },
|
||||
{ x: 1548700020000, y: 719951.64 },
|
||||
{ x: 1548700320000, y: 769181.7866666666 },
|
||||
{ x: 1548700620000, y: 740805.2666666667 },
|
||||
],
|
||||
status: [
|
||||
{ x: 1548697620000, up: 74, down: null, total: 74 },
|
||||
{ x: 1548697920000, up: 75, down: null, total: 75 },
|
||||
{ x: 1548698220000, up: 75, down: null, total: 75 },
|
||||
{ x: 1548698520000, up: 73, down: null, total: 73 },
|
||||
{ x: 1548698820000, up: 75, down: null, total: 75 },
|
||||
{ x: 1548699120000, up: 74, down: null, total: 74 },
|
||||
{ x: 1548699420000, up: 75, down: null, total: 75 },
|
||||
{ x: 1548699720000, up: 75, down: null, total: 75 },
|
||||
{ x: 1548700020000, up: 75, down: null, total: 75 },
|
||||
{ x: 1548700320000, up: 75, down: null, total: 75 },
|
||||
{ x: 1548700620000, up: 75, down: null, total: 75 },
|
||||
],
|
||||
statusMaxCount: 75,
|
||||
durationMaxValue: 6669234,
|
||||
},
|
||||
};
|
||||
|
||||
it('renders the component without errors', () => {
|
||||
const component = shallowWithIntl(
|
||||
<MonitorCharts
|
||||
checkDomainLimits={[0, 75]}
|
||||
crosshairLocation={150}
|
||||
danger="dangerColor"
|
||||
durationDomainLimits={[0, 75]}
|
||||
monitorChartData={chartResponse.monitorChartsData}
|
||||
primary="primaryColor"
|
||||
secondary="secondaryColor"
|
||||
updateCrosshairLocation={jest.fn()}
|
||||
/>
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -9,6 +9,7 @@ export { EmptyStatusBar } from './empty_status_bar';
|
|||
export { ErrorList } from './error_list';
|
||||
export { FilterBar } from './filter_bar';
|
||||
export { FilterBarLoading } from './filter_bar_loading';
|
||||
export { MonitorCharts } from './monitor_charts';
|
||||
export { MonitorList } from './monitor_list';
|
||||
export { MonitorPageTitle } from './monitor_page_title';
|
||||
export { MonitorStatusBar } from './monitor_status_bar';
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import {
|
||||
// @ts-ignore missing typings
|
||||
EuiAreaSeries,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
// @ts-ignore missing typings
|
||||
EuiLineSeries,
|
||||
EuiPanel,
|
||||
// @ts-ignore missing typings
|
||||
EuiSeriesChart,
|
||||
// @ts-ignore missing typings
|
||||
EuiSeriesChartUtils,
|
||||
// @ts-ignore missing typings
|
||||
EuiSpacer,
|
||||
// @ts-ignore missing typings
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React, { Fragment } from 'react';
|
||||
import { MonitorChart } from '../../../common/graphql/types';
|
||||
import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../lib/helper';
|
||||
|
||||
interface MonitorChartsProps {
|
||||
checkDomainLimits: number[];
|
||||
crosshairLocation: number;
|
||||
danger: string;
|
||||
durationDomainLimits: number[];
|
||||
monitorChartData: MonitorChart;
|
||||
primary: string;
|
||||
secondary: string;
|
||||
updateCrosshairLocation: (crosshairLocation: number) => void;
|
||||
}
|
||||
|
||||
export const MonitorCharts = ({
|
||||
checkDomainLimits,
|
||||
crosshairLocation,
|
||||
danger,
|
||||
durationDomainLimits,
|
||||
monitorChartData: { durationArea, durationLine, status },
|
||||
primary,
|
||||
secondary,
|
||||
updateCrosshairLocation,
|
||||
}: MonitorChartsProps) => (
|
||||
<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}
|
||||
xCrosshairFormat="YYYY-MM-DD hh:mmZ"
|
||||
yDomain={durationDomainLimits}
|
||||
crosshairValue={crosshairLocation}
|
||||
onCrosshairUpdate={updateCrosshairLocation}
|
||||
>
|
||||
<EuiAreaSeries
|
||||
color={secondary}
|
||||
name={i18n.translate(
|
||||
'xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel',
|
||||
{
|
||||
defaultMessage: 'Duration range',
|
||||
}
|
||||
)}
|
||||
data={durationArea.map(({ x, yMin, yMax }) => ({
|
||||
x,
|
||||
y0: microsToMillis(yMin),
|
||||
y: microsToMillis(yMax),
|
||||
}))}
|
||||
curve="curveBasis"
|
||||
/>
|
||||
<EuiLineSeries
|
||||
color={primary}
|
||||
name={i18n.translate(
|
||||
'xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel',
|
||||
{
|
||||
defaultMessage: 'Mean duration',
|
||||
}
|
||||
)}
|
||||
data={durationLine.map(({ x, y }) => ({
|
||||
x,
|
||||
y: microsToMillis(y),
|
||||
}))}
|
||||
/>
|
||||
</EuiSeriesChart>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.monitorCharts.checkStatus.title"
|
||||
defaultMessage="Check status"
|
||||
/>
|
||||
</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}
|
||||
xCrosshairFormat="YYYY-MM-DD hh:mmZ"
|
||||
stackBy="y"
|
||||
crosshairValue={crosshairLocation}
|
||||
onCrosshairUpdate={updateCrosshairLocation}
|
||||
yDomain={checkDomainLimits}
|
||||
>
|
||||
<EuiAreaSeries
|
||||
name={i18n.translate('xpack.uptime.monitorCharts.checkStatus.series.upCountLabel', {
|
||||
defaultMessage: 'Up count',
|
||||
})}
|
||||
data={status.map(({ x, up }) => ({ x, y: up }))}
|
||||
curve="curveBasis"
|
||||
color={primary}
|
||||
/>
|
||||
<EuiAreaSeries
|
||||
name={i18n.translate('xpack.uptime.monitorCharts.checkStatus.series.downCountLabel', {
|
||||
defaultMessage: 'Down count',
|
||||
})}
|
||||
data={status.map(({ x, down }) => ({ x, y: down }))}
|
||||
color={danger}
|
||||
/>
|
||||
</EuiSeriesChart>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</Fragment>
|
||||
);
|
|
@ -11,7 +11,7 @@ import moment from 'moment';
|
|||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
duration?: number;
|
||||
duration?: number | null;
|
||||
url?: string;
|
||||
status?: string;
|
||||
timestamp?: string;
|
||||
|
@ -50,19 +50,21 @@ export const MonitorStatusBar = ({ timestamp, url, duration, status }: Props) =>
|
|||
</EuiLink>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
aria-label={i18n.translate('xpack.uptime.monitorStatusBar.durationTextAriaLabel', {
|
||||
defaultMessage: 'Monitor duration in milliseconds',
|
||||
})}
|
||||
grow={false}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.monitorStatusBar.healthStatus.durationInMillisecondsMessage"
|
||||
values={{ duration: duration ? duration : 0 }}
|
||||
defaultMessage="{duration}ms"
|
||||
description="The 'ms' is an abbreviation for 'milliseconds'."
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
{!!duration && (
|
||||
<EuiFlexItem
|
||||
aria-label={i18n.translate('xpack.uptime.monitorStatusBar.durationTextAriaLabel', {
|
||||
defaultMessage: 'Monitor duration in milliseconds',
|
||||
})}
|
||||
grow={false}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.monitorStatusBar.healthStatus.durationInMillisecondsMessage"
|
||||
values={{ duration }}
|
||||
defaultMessage="{duration}ms"
|
||||
description="The 'ms' is an abbreviation for 'milliseconds'."
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
<EuiFlexItem
|
||||
aria-label={i18n.translate('xpack.uptime.monitorStatusBar.timestampFromNowTextAriaLabel', {
|
||||
defaultMessage: 'Time since last check',
|
||||
|
|
|
@ -23,6 +23,7 @@ import { get } from 'lodash';
|
|||
import moment from 'moment';
|
||||
import React, { Fragment } from 'react';
|
||||
import { Ping, PingResults } from '../../../common/graphql/types';
|
||||
import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../lib/helper';
|
||||
|
||||
interface PingListProps {
|
||||
loading: boolean;
|
||||
|
@ -88,7 +89,7 @@ export const PingList = ({
|
|||
defaultMessage: 'Duration ms',
|
||||
description: 'The "ms" in the default message is an abbreviation for milliseconds',
|
||||
}),
|
||||
render: (duration: number) => duration / 1000,
|
||||
render: (duration: number) => microsToMillis(duration),
|
||||
},
|
||||
{
|
||||
field: 'error.type',
|
||||
|
|
|
@ -6,22 +6,19 @@
|
|||
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const createGetMonitorChartsQueryString = `
|
||||
export const getMonitorChartsQueryString = `
|
||||
query MonitorCharts($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId: String!) {
|
||||
monitorChartsData: getMonitorChartsData(
|
||||
monitorId: $monitorId
|
||||
dateRangeStart: $dateRangeStart
|
||||
dateRangeEnd: $dateRangeEnd
|
||||
) {
|
||||
minDuration {
|
||||
durationArea {
|
||||
x
|
||||
y
|
||||
yMin
|
||||
yMax
|
||||
}
|
||||
maxDuration {
|
||||
x
|
||||
y
|
||||
}
|
||||
avgDuration {
|
||||
durationLine {
|
||||
x
|
||||
y
|
||||
}
|
||||
|
@ -31,10 +28,12 @@ query MonitorCharts($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId
|
|||
down
|
||||
total
|
||||
}
|
||||
statusMaxCount
|
||||
durationMaxValue
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const createGetMonitorChartsQuery = gql`
|
||||
${createGetMonitorChartsQueryString}
|
||||
${getMonitorChartsQueryString}
|
||||
`;
|
||||
|
|
|
@ -4,28 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import {
|
||||
// @ts-ignore missing typings
|
||||
EuiAreaSeries,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
// @ts-ignore missing typings
|
||||
EuiLineSeries,
|
||||
EuiPanel,
|
||||
// @ts-ignore missing typings
|
||||
EuiSeriesChart,
|
||||
// @ts-ignore missing typings
|
||||
EuiSeriesChartUtils,
|
||||
// @ts-ignore missing typings
|
||||
EuiSpacer,
|
||||
// @ts-ignore missing typings
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
import { Query } from 'react-apollo';
|
||||
import { MonitorChart } from '../../../../common/graphql/types';
|
||||
import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../../lib/helper';
|
||||
import { UptimeCommonProps } from '../../../uptime_app';
|
||||
import { MonitorCharts } from '../../functional';
|
||||
import { createGetMonitorChartsQuery } from './get_monitor_charts';
|
||||
|
||||
interface MonitorChartsProps {
|
||||
|
@ -72,125 +57,27 @@ export class MonitorChartsQuery extends React.Component<Props, MonitorChartsStat
|
|||
});
|
||||
}
|
||||
|
||||
// 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 avgDurationSeries: any[] = [];
|
||||
const areaDurationSeries: any[] = [];
|
||||
const downSeries: any[] = [];
|
||||
const upSeries: any[] = [];
|
||||
const checksSeries: any[] = [];
|
||||
monitorChartsData.forEach(({ avgDuration, maxDuration, minDuration, status }: any) => {
|
||||
avgDurationSeries.push(avgDuration);
|
||||
areaDurationSeries.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 });
|
||||
});
|
||||
const {
|
||||
monitorChartsData,
|
||||
monitorChartsData: { durationMaxValue, statusMaxCount },
|
||||
}: { monitorChartsData: MonitorChart } = data;
|
||||
|
||||
// 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 checkDomainLimits = [0, Math.max(...checksDomain)];
|
||||
const durationDomain = avgDurationSeries.concat(areaDurationSeries);
|
||||
const durationDomainLimits = [0, Math.max(...durationDomain.map(({ y }) => y))];
|
||||
const durationMax = microsToMillis(durationMaxValue);
|
||||
// These limits provide domain sizes for the charts
|
||||
const checkDomainLimits = [0, statusMaxCount];
|
||||
const durationDomainLimits = [0, durationMax ? durationMax : 0];
|
||||
|
||||
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}
|
||||
xCrosshairFormat="YYYY-MM-DD hh:mmZ"
|
||||
yDomain={durationDomainLimits}
|
||||
crosshairValue={this.state.crosshairLocation}
|
||||
onCrosshairUpdate={this.updateCrosshairLocation}
|
||||
>
|
||||
<EuiAreaSeries
|
||||
color={secondary}
|
||||
name={i18n.translate(
|
||||
'xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel',
|
||||
{
|
||||
defaultMessage: 'Duration range',
|
||||
}
|
||||
)}
|
||||
data={areaDurationSeries}
|
||||
curve="curveBasis"
|
||||
/>
|
||||
<EuiLineSeries
|
||||
color={primary}
|
||||
name={i18n.translate(
|
||||
'xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel',
|
||||
{
|
||||
defaultMessage: 'Mean duration',
|
||||
}
|
||||
)}
|
||||
data={avgDurationSeries}
|
||||
/>
|
||||
</EuiSeriesChart>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.monitorCharts.checkStatus.title"
|
||||
defaultMessage="Check status"
|
||||
/>
|
||||
</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}
|
||||
xCrosshairFormat="YYYY-MM-DD hh:mmZ"
|
||||
stackBy="y"
|
||||
crosshairValue={this.state.crosshairLocation}
|
||||
onCrosshairUpdate={this.updateCrosshairLocation}
|
||||
yDomain={checkDomainLimits}
|
||||
>
|
||||
<EuiAreaSeries
|
||||
name={i18n.translate(
|
||||
'xpack.uptime.monitorCharts.checkStatus.series.upCountLabel',
|
||||
{
|
||||
defaultMessage: 'Up count',
|
||||
}
|
||||
)}
|
||||
data={upSeries}
|
||||
curve="curveBasis"
|
||||
color={primary}
|
||||
/>
|
||||
<EuiAreaSeries
|
||||
name={i18n.translate(
|
||||
'xpack.uptime.monitorCharts.checkStatus.series.downCountLabel',
|
||||
{
|
||||
defaultMessage: 'Down count',
|
||||
}
|
||||
)}
|
||||
data={downSeries}
|
||||
color={danger}
|
||||
/>
|
||||
</EuiSeriesChart>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</Fragment>
|
||||
<MonitorCharts
|
||||
checkDomainLimits={checkDomainLimits}
|
||||
crosshairLocation={this.state.crosshairLocation}
|
||||
danger={danger}
|
||||
durationDomainLimits={durationDomainLimits}
|
||||
monitorChartData={monitorChartsData}
|
||||
primary={primary}
|
||||
secondary={secondary}
|
||||
updateCrosshairLocation={this.updateCrosshairLocation}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</Query>
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { formatDuration } from '../format_duration';
|
||||
|
||||
describe('formatDuration', () => {
|
||||
it('returns 0 for undefined', () => {
|
||||
const result = formatDuration(undefined);
|
||||
expect(result).toEqual(0);
|
||||
});
|
||||
|
||||
it('returns 0 for NaN', () => {
|
||||
const result = formatDuration(NaN);
|
||||
expect(result).toEqual(0);
|
||||
});
|
||||
|
||||
it('returns duration value in ms', () => {
|
||||
const duration = 320000; // microseconds
|
||||
expect(formatDuration(duration)).toEqual(320);
|
||||
});
|
||||
});
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const formatDuration = (duration: number | undefined): number => {
|
||||
if (duration === undefined) {
|
||||
return 0;
|
||||
}
|
||||
// TODO: formatting should not be performed this way, remove bare number
|
||||
return isNaN(duration) ? 0 : duration / 1000;
|
||||
};
|
|
@ -10,9 +10,9 @@ import { get } from 'lodash';
|
|||
import React from 'react';
|
||||
import { Query } from 'react-apollo';
|
||||
import { Ping } from 'x-pack/plugins/uptime/common/graphql/types';
|
||||
import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../../lib/helper';
|
||||
import { UptimeCommonProps } from '../../../uptime_app';
|
||||
import { EmptyStatusBar, MonitorStatusBar } from '../../functional';
|
||||
import { formatDuration } from './format_duration';
|
||||
import { getMonitorStatusBarQuery } from './get_monitor_status_bar';
|
||||
|
||||
interface MonitorStatusBarProps {
|
||||
|
@ -63,16 +63,11 @@ export const MonitorStatusBarQuery = ({
|
|||
}
|
||||
const { monitor, timestamp, url } = monitorStatus[0];
|
||||
const status = get(monitor, 'status', undefined);
|
||||
const duration = parseInt(get(monitor, 'duration.us'), 10);
|
||||
const duration = microsToMillis(get(monitor, 'duration.us', null));
|
||||
const full = get(url, 'full', undefined);
|
||||
|
||||
return (
|
||||
<MonitorStatusBar
|
||||
duration={formatDuration(duration)}
|
||||
status={status}
|
||||
timestamp={timestamp}
|
||||
url={full}
|
||||
/>
|
||||
<MonitorStatusBar duration={duration} status={status} timestamp={timestamp} url={full} />
|
||||
);
|
||||
}}
|
||||
</Query>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { convertMicrosecondsToMilliseconds } from '../convert_measurements';
|
||||
|
||||
describe('convertMicrosecondsToMilliseconds', () => {
|
||||
it('converts microseconds to millis', () => {
|
||||
const microValue = 3425342;
|
||||
const result = convertMicrosecondsToMilliseconds(microValue);
|
||||
expect(result).toEqual(3425);
|
||||
});
|
||||
it('returns null for null parameter', () => {
|
||||
expect(convertMicrosecondsToMilliseconds(null)).toBeNull();
|
||||
});
|
||||
it('returns undefined for undefined parameter', () => {
|
||||
expect(convertMicrosecondsToMilliseconds(undefined)).toBeUndefined();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
const NUM_MICROSECONDS_IN_MILLISECOND = 1000;
|
||||
|
||||
/**
|
||||
* This simply converts microseconds to milliseconds. People tend to prefer ms to us
|
||||
* when visualizaing request duration times.
|
||||
*/
|
||||
export const convertMicrosecondsToMilliseconds = (microseconds: number | null | undefined) =>
|
||||
microseconds ? Math.round(microseconds / NUM_MICROSECONDS_IN_MILLISECOND) : microseconds;
|
7
x-pack/plugins/uptime/public/lib/helper/index.ts
Normal file
7
x-pack/plugins/uptime/public/lib/helper/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { convertMicrosecondsToMilliseconds } from './convert_measurements';
|
|
@ -15,6 +15,7 @@ import {
|
|||
GetMonitorPageTitleQueryArgs,
|
||||
GetMonitorsQueryArgs,
|
||||
GetSnapshotQueryArgs,
|
||||
MonitorChart,
|
||||
MonitorPageTitle,
|
||||
Ping,
|
||||
Snapshot,
|
||||
|
@ -113,8 +114,8 @@ export const createMonitorsResolvers: CreateUMGraphQLResolvers = (
|
|||
resolver,
|
||||
{ monitorId, dateRangeStart, dateRangeEnd },
|
||||
{ req }
|
||||
): Promise<any> {
|
||||
return libs.monitors.getMonitorChartsData(req, monitorId, dateRangeStart, dateRangeEnd);
|
||||
): Promise<MonitorChart> {
|
||||
return await libs.monitors.getMonitorChartsData(req, monitorId, dateRangeStart, dateRangeEnd);
|
||||
},
|
||||
async getLatestMonitors(
|
||||
resolver,
|
||||
|
|
|
@ -35,24 +35,30 @@ export const monitorsSchema = gql`
|
|||
y: Float
|
||||
}
|
||||
|
||||
"Represents a bucket of monitor status information."
|
||||
type StatusData {
|
||||
x: UnsignedInteger
|
||||
"The timeseries point for this status data."
|
||||
x: UnsignedInteger!
|
||||
"The value of up counts for this point."
|
||||
up: Int
|
||||
"The value for down counts for this point."
|
||||
down: Int
|
||||
"The total down counts for this point."
|
||||
total: Int
|
||||
}
|
||||
|
||||
type MonitorChartEntry {
|
||||
maxContent: DataPoint
|
||||
maxResponse: DataPoint
|
||||
maxValidate: DataPoint
|
||||
maxTotal: DataPoint
|
||||
maxWriteRequest: DataPoint
|
||||
maxTcpRtt: DataPoint
|
||||
maxDuration: DataPoint
|
||||
minDuration: DataPoint
|
||||
avgDuration: DataPoint
|
||||
status: StatusData
|
||||
"The data used to populate the monitor charts."
|
||||
type MonitorChart {
|
||||
"The max and min values for the monitor duration."
|
||||
durationArea: [MonitorDurationAreaPoint!]!
|
||||
"The average values for the monitor duration."
|
||||
durationLine: [MonitorDurationAveragePoint!]!
|
||||
"The counts of up/down checks for the monitor."
|
||||
status: [StatusData!]!
|
||||
"The maximum status doc count in this chart."
|
||||
statusMaxCount: Int!
|
||||
"The maximum duration value in this chart."
|
||||
durationMaxValue: Int!
|
||||
}
|
||||
|
||||
type MonitorKey {
|
||||
|
@ -65,10 +71,33 @@ export const monitorsSchema = gql`
|
|||
y: Int
|
||||
}
|
||||
|
||||
"Represents a monitor's duration performance in microseconds at a point in time."
|
||||
type MonitorDurationAreaPoint {
|
||||
"The timeseries value for this point in time."
|
||||
x: UnsignedInteger!
|
||||
"The min duration value in microseconds at this time."
|
||||
yMin: Float
|
||||
"The max duration value in microseconds at this point."
|
||||
yMax: Float
|
||||
}
|
||||
|
||||
"Represents the average monitor duration ms at a point in time."
|
||||
type MonitorDurationAveragePoint {
|
||||
"The timeseries value for this point."
|
||||
x: UnsignedInteger!
|
||||
"The average duration ms for the monitor."
|
||||
y: Float
|
||||
}
|
||||
|
||||
"Represents the latest recorded information about a monitor."
|
||||
type LatestMonitor {
|
||||
"The ID of the monitor represented by this data."
|
||||
id: MonitorKey!
|
||||
"Information from the latest document."
|
||||
ping: Ping
|
||||
"Buckets of recent up count status data."
|
||||
upSeries: [MonitorSeriesPoint]
|
||||
"Buckets of recent down count status data."
|
||||
downSeries: [MonitorSeriesPoint]
|
||||
}
|
||||
|
||||
|
@ -104,7 +133,7 @@ export const monitorsSchema = gql`
|
|||
monitorId: String!
|
||||
dateRangeStart: String!
|
||||
dateRangeEnd: String!
|
||||
): [MonitorChartEntry]
|
||||
): MonitorChart
|
||||
|
||||
getLatestMonitors(dateRangeStart: String!, dateRangeEnd: String!, monitorId: String): [Ping!]!
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { MonitorPageTitle } from 'x-pack/plugins/uptime/common/graphql/types';
|
||||
import { MonitorChart, MonitorPageTitle } from '../../../../common/graphql/types';
|
||||
|
||||
export interface UMMonitorsAdapter {
|
||||
getMonitorChartsData(
|
||||
|
@ -12,7 +12,7 @@ export interface UMMonitorsAdapter {
|
|||
monitorId: string,
|
||||
dateRangeStart: string,
|
||||
dateRangeEnd: string
|
||||
): Promise<any>;
|
||||
): Promise<MonitorChart>;
|
||||
getMonitors(
|
||||
request: any,
|
||||
dateRangeStart: string,
|
||||
|
|
|
@ -10,21 +10,16 @@ import {
|
|||
ErrorListItem,
|
||||
FilterBar,
|
||||
LatestMonitor,
|
||||
MonitorChart,
|
||||
MonitorKey,
|
||||
MonitorPageTitle,
|
||||
MonitorSeriesPoint,
|
||||
Ping,
|
||||
} from '../../../../common/graphql/types';
|
||||
import { getFilteredQuery, getFilteredQueryAndStatusFilter } from '../../helper';
|
||||
import { dropLatestBucket, getFilteredQuery, getFilteredQueryAndStatusFilter } from '../../helper';
|
||||
import { DatabaseAdapter } from '../database';
|
||||
import { UMMonitorsAdapter } from './adapter_types';
|
||||
|
||||
// the values for these charts are stored as μs, but should be displayed as ms
|
||||
const formatChartValue = (time: any, chartPoint: any) => ({
|
||||
x: time,
|
||||
y: chartPoint.value === null ? null : chartPoint.value / 1000,
|
||||
});
|
||||
|
||||
const formatStatusBuckets = (time: any, buckets: any, docCount: any) => {
|
||||
let up = null;
|
||||
let down = null;
|
||||
|
@ -62,7 +57,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
monitorId: string,
|
||||
dateRangeStart: string,
|
||||
dateRangeEnd: string
|
||||
): Promise<any> {
|
||||
): Promise<MonitorChart> {
|
||||
const params = {
|
||||
index: INDEX_NAMES.HEARTBEAT,
|
||||
body: {
|
||||
|
@ -79,15 +74,9 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
timeseries: {
|
||||
auto_date_histogram: {
|
||||
field: '@timestamp',
|
||||
buckets: 50,
|
||||
buckets: 25,
|
||||
},
|
||||
aggs: {
|
||||
max_content: { max: { field: 'http.rtt.content.us' } },
|
||||
max_response: { max: { field: 'http.rtt.response_header.us' } },
|
||||
max_validate: { max: { field: 'http.rtt.validate.us' } },
|
||||
max_total: { max: { field: 'http.rtt.total.us' } },
|
||||
max_write_request: { max: { field: 'http.rtt.write_request.us' } },
|
||||
max_tcp_rtt: { max: { field: 'tcp.rtt.connect.us' } },
|
||||
status: { terms: { field: 'monitor.status', size: 2, shard_size: 2 } },
|
||||
duration: { stats: { field: 'monitor.duration.us' } },
|
||||
},
|
||||
|
@ -97,33 +86,49 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter {
|
|||
};
|
||||
|
||||
const result = await this.database.search(request, params);
|
||||
const buckets = get(result, 'aggregations.timeseries.buckets', []);
|
||||
const buckets = dropLatestBucket(get(result, 'aggregations.timeseries.buckets', []));
|
||||
|
||||
return buckets.map(
|
||||
({
|
||||
key,
|
||||
max_content,
|
||||
duration: { avg, max, min },
|
||||
max_write_request,
|
||||
max_validate,
|
||||
max_tcp_rtt,
|
||||
max_response,
|
||||
max_total,
|
||||
status,
|
||||
doc_count,
|
||||
}: any) => ({
|
||||
maxContent: formatChartValue(key, max_content),
|
||||
maxWriteRequest: formatChartValue(key, max_write_request),
|
||||
maxValidate: formatChartValue(key, max_validate),
|
||||
maxTcpRtt: formatChartValue(key, max_tcp_rtt),
|
||||
maxResponse: formatChartValue(key, max_response),
|
||||
maxTotal: formatChartValue(key, max_total),
|
||||
avgDuration: formatChartValue(key, { value: avg }),
|
||||
maxDuration: formatChartValue(key, { value: max }),
|
||||
minDuration: formatChartValue(key, { value: min }),
|
||||
status: formatStatusBuckets(key, status.buckets, doc_count),
|
||||
})
|
||||
);
|
||||
/**
|
||||
* The code below is responsible for formatting the aggregation data we fetched above in a way
|
||||
* that the chart components used by the client understands.
|
||||
* There are five required values. Two are lists of points that conform to a simple (x,y) structure.
|
||||
*
|
||||
* The third list is for an area chart expressing a range, and it requires an (x,y,y0) structure,
|
||||
* where y0 is the min value for the point and y is the max.
|
||||
*
|
||||
* Additionally, we supply the maximum value for duration and status, so the corresponding charts know
|
||||
* what the domain size should be.
|
||||
*/
|
||||
const monitorChartsData: MonitorChart = {
|
||||
durationArea: [],
|
||||
durationLine: [],
|
||||
status: [],
|
||||
durationMaxValue: 0,
|
||||
statusMaxCount: 0,
|
||||
};
|
||||
|
||||
buckets.forEach(bucket => {
|
||||
const x = get(bucket, 'key');
|
||||
const docCount = get(bucket, 'doc_count', 0);
|
||||
// update the maximum value for each point
|
||||
monitorChartsData.statusMaxCount = Math.max(docCount, monitorChartsData.statusMaxCount);
|
||||
monitorChartsData.durationMaxValue = Math.max(
|
||||
monitorChartsData.durationMaxValue,
|
||||
get(bucket, 'duration.max', 0)
|
||||
);
|
||||
|
||||
// these points express a range that will be displayed as an area chart
|
||||
monitorChartsData.durationArea.push({
|
||||
x,
|
||||
yMin: get(bucket, 'duration.min', null),
|
||||
yMax: get(bucket, 'duration.max', null),
|
||||
});
|
||||
monitorChartsData.durationLine.push({ x, y: get(bucket, 'duration.avg', null) });
|
||||
monitorChartsData.status.push(
|
||||
formatStatusBuckets(x, get(bucket, 'status.buckets', []), docCount)
|
||||
);
|
||||
});
|
||||
return monitorChartsData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { MonitorPageTitle } from '../../../common/graphql/types';
|
||||
import { MonitorChart, MonitorPageTitle } from '../../../common/graphql/types';
|
||||
import { UMMonitorsAdapter } from '../adapters/monitors';
|
||||
|
||||
export class UMMonitorsDomain {
|
||||
|
@ -17,7 +17,7 @@ export class UMMonitorsDomain {
|
|||
monitorId: string,
|
||||
dateRangeStart: string,
|
||||
dateRangeEnd: string
|
||||
): Promise<any> {
|
||||
): Promise<MonitorChart> {
|
||||
return this.adapter.getMonitorChartsData(request, monitorId, dateRangeStart, dateRangeEnd);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`dropLatestBucket drops the last of a list with greater length than 1 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"prop": "val",
|
||||
},
|
||||
]
|
||||
`;
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { dropLatestBucket } from '../drop_latest_bucket';
|
||||
|
||||
describe('dropLatestBucket', () => {
|
||||
it('drops the last of a list with greater length than 1', () => {
|
||||
const testData = [{ prop: 'val' }, { prop: 'val' }];
|
||||
const result = dropLatestBucket(testData);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
it('returns an empty list when length === 1', () => {
|
||||
const testData = [{ prop: 'val' }];
|
||||
const result = dropLatestBucket(testData);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
it('returns an empty list when length === 0', () => {
|
||||
const testData: any[] = [];
|
||||
const result = dropLatestBucket(testData);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* We've had numerous requests to not display semi-full buckets (i.e. it is 13:01 and the
|
||||
* bounds of our bucket are 13:00-13:05). If the first bucket isn't done filling, we'll
|
||||
* start out with nothing returned, otherwise we drop the most recent bucket.
|
||||
* @param buckets The bucket list
|
||||
*/
|
||||
export const dropLatestBucket = (buckets: any[]) =>
|
||||
buckets.length > 1 ? buckets.slice(0, buckets.length - 1) : [];
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { UMESBucket, UMESHistogramBucket } from '../adapters/database';
|
||||
import { dropLatestBucket } from './drop_latest_bucket';
|
||||
|
||||
/**
|
||||
* The charting library we're currently using requires histogram data points have an
|
||||
|
@ -27,7 +28,7 @@ export function formatEsBucketsForHistogram<T extends UMESBucket>(
|
|||
const TERMINAL_INDEX = buckets.length - 1;
|
||||
const { key: terminalBucketTime } = buckets[TERMINAL_INDEX];
|
||||
// drop the most recent bucket to avoid returning incomplete bucket
|
||||
return buckets.slice(0, TERMINAL_INDEX).map((item, index, array) => {
|
||||
return dropLatestBucket(buckets).map((item, index, array) => {
|
||||
const { key } = item;
|
||||
const nextItem = array[index + 1];
|
||||
const bucketSize = nextItem ? Math.abs(nextItem.key - key) : Math.abs(terminalBucketTime - key);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { dropLatestBucket } from './drop_latest_bucket';
|
||||
export { formatEsBucketsForHistogram } from './format_es_buckets_for_histogram';
|
||||
export { getFilteredQuery } from './get_filtered_query';
|
||||
export { getFilteredQueryAndStatusFilter } from './get_filtered_query_and_status';
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"monitorChartsData": {
|
||||
"durationArea": [
|
||||
{ "x": 1548697620000, "yMin": 106421, "yMax": 3120392 },
|
||||
{ "x": 1548697920000, "yMin": 121653, "yMax": 3955186 },
|
||||
{ "x": 1548698220000, "yMin": 118224, "yMax": 3705359 },
|
||||
{ "x": 1548698520000, "yMin": 123345, "yMax": 6669234 },
|
||||
{ "x": 1548698820000, "yMin": 117268, "yMax": 3955729 },
|
||||
{ "x": 1548699120000, "yMin": 122110, "yMax": 4045216 },
|
||||
{ "x": 1548699420000, "yMin": 120015, "yMax": 3682859 },
|
||||
{ "x": 1548699720000, "yMin": 114751, "yMax": 3701297 },
|
||||
{ "x": 1548700020000, "yMin": 111949, "yMax": 3632224 },
|
||||
{ "x": 1548700320000, "yMin": 105126, "yMax": 3801401 },
|
||||
{ "x": 1548700620000, "yMin": 123639, "yMax": 3925269 }
|
||||
],
|
||||
"durationLine": [
|
||||
{ "x": 1548697620000, "y": 743928.2027027027 },
|
||||
{ "x": 1548697920000, "y": 766840.0133333333 },
|
||||
{ "x": 1548698220000, "y": 786970.8266666667 },
|
||||
{ "x": 1548698520000, "y": 781064.7808219178 },
|
||||
{ "x": 1548698820000, "y": 741563.04 },
|
||||
{ "x": 1548699120000, "y": 759354.6756756756 },
|
||||
{ "x": 1548699420000, "y": 737533.3866666667 },
|
||||
{ "x": 1548699720000, "y": 728669.0266666666 },
|
||||
{ "x": 1548700020000, "y": 719951.64 },
|
||||
{ "x": 1548700320000, "y": 769181.7866666666 },
|
||||
{ "x": 1548700620000, "y": 740805.2666666667 }
|
||||
],
|
||||
"status": [
|
||||
{ "x": 1548697620000, "up": 74, "down": null, "total": 74 },
|
||||
{ "x": 1548697920000, "up": 75, "down": null, "total": 75 },
|
||||
{ "x": 1548698220000, "up": 75, "down": null, "total": 75 },
|
||||
{ "x": 1548698520000, "up": 73, "down": null, "total": 73 },
|
||||
{ "x": 1548698820000, "up": 75, "down": null, "total": 75 },
|
||||
{ "x": 1548699120000, "up": 74, "down": null, "total": 74 },
|
||||
{ "x": 1548699420000, "up": 75, "down": null, "total": 75 },
|
||||
{ "x": 1548699720000, "up": 75, "down": null, "total": 75 },
|
||||
{ "x": 1548700020000, "up": 75, "down": null, "total": 75 },
|
||||
{ "x": 1548700320000, "up": 75, "down": null, "total": 75 },
|
||||
{ "x": 1548700620000, "up": 75, "down": null, "total": 75 }
|
||||
],
|
||||
"statusMaxCount": 75,
|
||||
"durationMaxValue": 6669234
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"monitorChartsData": {
|
||||
"durationArea": [],
|
||||
"durationLine": [],
|
||||
"status": [],
|
||||
"statusMaxCount": 0,
|
||||
"durationMaxValue": 0
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ export default function ({ getService, loadTestFile }) {
|
|||
loadTestFile(require.resolve('./doc_count'));
|
||||
loadTestFile(require.resolve('./error_list'));
|
||||
loadTestFile(require.resolve('./filter_bar'));
|
||||
loadTestFile(require.resolve('./monitor_charts'));
|
||||
loadTestFile(require.resolve('./monitor_list'));
|
||||
loadTestFile(require.resolve('./monitor_status_bar'));
|
||||
loadTestFile(require.resolve('./ping_list'));
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from 'expect.js';
|
||||
import { getMonitorChartsQueryString } from '../../../../../plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts';
|
||||
import monitorCharts from './fixtures/monitor_charts';
|
||||
import monitorChartsEmptySet from './fixtures/monitor_charts_empty_set';
|
||||
|
||||
export default function ({ getService }) {
|
||||
describe('monitorCharts query', () => {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
it('will fetch a series of data points for monitor duration and status', async () => {
|
||||
const getMonitorChartsQuery = {
|
||||
operationName: 'MonitorCharts',
|
||||
query: getMonitorChartsQueryString,
|
||||
variables: {
|
||||
dateRangeStart: '2019-01-28T17:40:08.078Z',
|
||||
dateRangeEnd: '2019-01-28T19:00:16.078Z',
|
||||
monitorId: 'auto-http-0X131221E73F825974',
|
||||
},
|
||||
};
|
||||
const {
|
||||
body: { data },
|
||||
} = await supertest
|
||||
.post('/api/uptime/graphql')
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send({ ...getMonitorChartsQuery });
|
||||
expect(data).to.eql(monitorCharts);
|
||||
});
|
||||
|
||||
it('will fetch empty sets for a date range with no data', async () => {
|
||||
const getMonitorChartsQuery = {
|
||||
operationName: 'MonitorCharts',
|
||||
query: getMonitorChartsQueryString,
|
||||
variables: {
|
||||
dateRangeStart: '2002-01-28T17:40:08.078Z',
|
||||
dateRangeEnd: '2002-01-28T19:00:16.078Z',
|
||||
monitorId: 'auto-http-0X131221E73F825974',
|
||||
},
|
||||
};
|
||||
const {
|
||||
body: { data },
|
||||
} = await supertest
|
||||
.post('/api/uptime/graphql')
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send({ ...getMonitorChartsQuery });
|
||||
expect(data).to.eql(monitorChartsEmptySet);
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue