Skip to content
Snippets Groups Projects
Commit 657fea86 authored by Jose Ivan Vargas Lopez's avatar Jose Ivan Vargas Lopez
Browse files

Add summary statistics prometheus dashboard

parent 9e3cdc02
No related branches found
No related tags found
No related merge requests found
Showing with 421 additions and 299 deletions
Loading
Loading
@@ -3,6 +3,7 @@ import { scaleLinear, scaleTime } from 'd3-scale';
import { axisLeft, axisBottom } from 'd3-axis';
import { max, extent } from 'd3-array';
import { select } from 'd3-selection';
import GraphAxis from './graph/axis.vue';
import GraphLegend from './graph/legend.vue';
import GraphFlag from './graph/flag.vue';
import GraphDeployment from './graph/deployment.vue';
Loading
Loading
@@ -18,10 +19,11 @@ const d3 = { scaleLinear, scaleTime, axisLeft, axisBottom, max, extent, select }
 
export default {
components: {
GraphLegend,
GraphAxis,
GraphFlag,
GraphDeployment,
GraphPath,
GraphLegend,
},
mixins: [MonitoringMixin],
props: {
Loading
Loading
@@ -138,7 +140,7 @@ export default {
this.legendTitle = query.label || 'Average';
this.graphWidth = this.$refs.baseSvg.clientWidth - this.margin.left - this.margin.right;
this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom;
this.baseGraphHeight = this.graphHeight;
this.baseGraphHeight = this.graphHeight - 50;
this.baseGraphWidth = this.graphWidth;
 
// pixel offsets inside the svg and outside are not 1:1
Loading
Loading
@@ -177,14 +179,10 @@ export default {
this.graphHeightOffset,
);
 
if (!this.showLegend) {
this.baseGraphHeight -= 50;
} else if (this.timeSeries.length > 3) {
this.baseGraphHeight = this.baseGraphHeight += (this.timeSeries.length - 3) * 20;
}
const axisXScale = d3.scaleTime().range([0, this.graphWidth - 70]);
const axisYScale = d3.scaleLinear().range([this.graphHeight - this.graphHeightOffset, 0]);
const axisXScale = d3.scaleTime()
.range([0, this.graphWidth - 70]);
const axisYScale = d3.scaleLinear()
.range([this.graphHeight - this.graphHeightOffset, 0]);
 
const allValues = this.timeSeries.reduce((all, { values }) => all.concat(values), []);
axisXScale.domain(d3.extent(allValues, d => d.time));
Loading
Loading
@@ -251,17 +249,12 @@ export default {
class="y-axis"
transform="translate(70, 20)"
/>
<graph-legend
<graph-axis
:graph-width="graphWidth"
:graph-height="graphHeight"
:margin="margin"
:measurements="measurements"
:legend-title="legendTitle"
:y-axis-label="yAxisLabel"
:time-series="timeSeries"
:unit-of-display="unitOfDisplay"
:current-data-index="currentDataIndex"
:show-legend-group="showLegend"
/>
<svg
class="graph-data"
Loading
Loading
@@ -306,5 +299,12 @@ export default {
:deployment-flag-data="deploymentFlagData"
/>
</div>
<graph-legend
v-if="showLegend"
:legend-title="legendTitle"
:time-series="timeSeries"
:current-data-index="currentDataIndex"
:unit-of-display="unitOfDisplay"
/>
</div>
</template>
<script>
export default {
props: {
graphWidth: {
type: Number,
required: true,
},
graphHeight: {
type: Number,
required: true,
},
margin: {
type: Object,
required: true,
},
measurements: {
type: Object,
required: true,
},
yAxisLabel: {
type: String,
required: true,
},
},
data() {
return {
yLabelWidth: 0,
yLabelHeight: 0,
};
},
computed: {
textTransform() {
const yCoordinate =
(this.graphHeight -
this.margin.top +
this.measurements.axisLabelLineOffset) /
2 || 0;
return `translate(15, ${yCoordinate}) rotate(-90)`;
},
rectTransform() {
const yCoordinate =
(this.graphHeight -
this.margin.top +
this.measurements.axisLabelLineOffset) /
2 +
this.yLabelWidth / 2 || 0;
return `translate(0, ${yCoordinate}) rotate(-90)`;
},
xPosition() {
return (
(this.graphWidth + this.measurements.axisLabelLineOffset) / 2 -
this.margin.right || 0
);
},
yPosition() {
return (
this.graphHeight -
this.margin.top +
this.measurements.axisLabelLineOffset || 0
);
},
},
mounted() {
this.$nextTick(() => {
const bbox = this.$refs.ylabel.getBBox();
this.yLabelWidth = bbox.width + 10; // Added some padding
this.yLabelHeight = bbox.height + 5;
});
},
};
</script>
<template>
<g class="axis-label-container">
<line
class="label-x-axis-line"
stroke="#000000"
stroke-width="1"
x1="10"
:y1="yPosition"
:x2="graphWidth + 20"
:y2="yPosition"
/>
<line
class="label-y-axis-line"
stroke="#000000"
stroke-width="1"
x1="10"
y1="0"
:x2="10"
:y2="yPosition"
/>
<rect
class="rect-axis-text"
:transform="rectTransform"
:width="yLabelWidth"
:height="yLabelHeight"
/>
<text
class="label-axis-text y-label-text"
text-anchor="middle"
:transform="textTransform"
ref="ylabel"
>
{{ yAxisLabel }}
</text>
<rect
class="rect-axis-text"
:x="xPosition + 60"
:y="graphHeight - 80"
width="35"
height="50"
/>
<text
class="label-axis-text x-label-text"
:x="xPosition + 60"
:y="yPosition"
dy=".35em"
>
Time
</text>
</g>
</template>
Loading
Loading
@@ -160,7 +160,7 @@ export default {
</div>
</div>
<div class="popover-content">
<table>
<table class="prometheus-table">
<tr
v-for="(series, index) in timeSeries"
:key="index"
Loading
Loading
<script>
import { formatRelevantDigits } from '../../../lib/utils/number_utils';
import { formatRelevantDigits } from '~/lib/utils/number_utils';
 
export default {
props: {
graphWidth: {
type: Number,
required: true,
},
graphHeight: {
type: Number,
required: true,
},
margin: {
type: Object,
required: true,
},
measurements: {
type: Object,
required: true,
},
legendTitle: {
type: String,
required: true,
},
yAxisLabel: {
type: String,
required: true,
},
timeSeries: {
type: Array,
required: true,
},
unitOfDisplay: {
type: String,
required: true,
},
currentDataIndex: {
type: Number,
required: true,
},
showLegendGroup: {
type: Boolean,
required: false,
default: true,
},
},
data() {
return {
yLabelWidth: 0,
yLabelHeight: 0,
seriesXPosition: 0,
metricUsageXPosition: 0,
};
},
computed: {
textTransform() {
const yCoordinate =
(this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 || 0;
return `translate(15, ${yCoordinate}) rotate(-90)`;
},
rectTransform() {
const yCoordinate =
(this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 +
this.yLabelWidth / 2 || 0;
return `translate(0, ${yCoordinate}) rotate(-90)`;
},
xPosition() {
return (this.graphWidth + this.measurements.axisLabelLineOffset) / 2 - this.margin.right || 0;
},
yPosition() {
return this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset || 0;
unitOfDisplay: {
type: String,
required: true,
},
},
mounted() {
this.$nextTick(() => {
const bbox = this.$refs.ylabel.getBBox();
this.metricUsageXPosition = 0;
this.seriesXPosition = 0;
if (this.$refs.legendTitleSvg != null) {
this.seriesXPosition = this.$refs.legendTitleSvg[0].getBBox().width;
}
if (this.$refs.seriesTitleSvg != null) {
this.metricUsageXPosition = this.$refs.seriesTitleSvg[0].getBBox().width;
}
this.yLabelWidth = bbox.width + 10; // Added some padding
this.yLabelHeight = bbox.height + 5;
});
},
methods: {
translateLegendGroup(index) {
return `translate(0, ${12 * index})`;
},
formatMetricUsage(series) {
const value =
series.values[this.currentDataIndex] && series.values[this.currentDataIndex].value;
series.values[this.currentDataIndex] &&
series.values[this.currentDataIndex].value;
if (isNaN(value)) {
return '-';
}
return `${formatRelevantDigits(value)} ${this.unitOfDisplay}`;
},
createSeriesString(index, series) {
if (series.metricTag) {
return `${series.metricTag} ${this.formatMetricUsage(series)}`;
}
return `${this.legendTitle} series ${index + 1} ${this.formatMetricUsage(series)}`;
return `${this.legendTitle} series ${index + 1} ${this.formatMetricUsage(
series,
)}`;
},
summaryMetrics(series) {
return `Avg: ${formatRelevantDigits(series.average)} ${this.unitOfDisplay},
Max: ${formatRelevantDigits(series.max)} ${this.unitOfDisplay}`;
},
strokeDashArray(type) {
if (type === 'dashed') return '6, 3';
if (type === 'dotted') return '3, 3';
Loading
Loading
@@ -116,89 +54,38 @@ export default {
};
</script>
<template>
<g class="axis-label-container">
<line
class="label-x-axis-line"
stroke="#000000"
stroke-width="1"
x1="10"
:y1="yPosition"
:x2="graphWidth + 20"
:y2="yPosition"
/>
<line
class="label-y-axis-line"
stroke="#000000"
stroke-width="1"
x1="10"
y1="0"
:x2="10"
:y2="yPosition"
/>
<rect
class="rect-axis-text"
:transform="rectTransform"
:width="yLabelWidth"
:height="yLabelHeight"
/>
<text
class="label-axis-text y-label-text"
text-anchor="middle"
:transform="textTransform"
ref="ylabel"
>
{{ yAxisLabel }}
</text>
<rect
class="rect-axis-text"
:x="xPosition + 60"
:y="graphHeight - 80"
width="35"
height="50"
/>
<text
class="label-axis-text x-label-text"
:x="xPosition + 60"
:y="yPosition"
dy=".35em"
>
Time
</text>
<template v-if="showLegendGroup">
<g
class="legend-group"
<div class="prometheus-graph-legends prepend-left-10">
<table class="prometheus-table">
<tr
v-for="(series, index) in timeSeries"
:key="index"
:transform="translateLegendGroup(index)"
>
<line
:stroke="series.lineColor"
:stroke-width="measurements.legends.height"
:stroke-dasharray="strokeDashArray(series.lineStyle)"
:x1="measurements.legends.offsetX"
:x2="measurements.legends.offsetX + measurements.legends.width"
:y1="graphHeight - measurements.legends.offsetY"
:y2="graphHeight - measurements.legends.offsetY"
/>
<text
v-if="timeSeries.length > 1"
<td>
<svg
width="15"
height="6"
>
<line
:stroke-dasharray="strokeDashArray(series.lineStyle)"
:stroke="series.lineColor"
stroke-width="4"
:x1="0"
:x2="15"
:y1="2"
:y2="2"
/>
</svg>
</td>
<td
class="legend-metric-title"
ref="legendTitleSvg"
x="38"
:y="graphHeight - 30"
>
{{ createSeriesString(index, series) }}
</text>
<text
v-else
class="legend-metric-title"
ref="legendTitleSvg"
x="38"
:y="graphHeight - 30"
v-if="timeSeries.length > 1"
>
{{ legendTitle }} {{ formatMetricUsage(series) }}
</text>
</g>
</template>
</g>
{{ createSeriesString(index, series) }}, {{ summaryMetrics(series) }}
</td>
<td v-else>
{{ legendTitle }} {{ formatMetricUsage(series) }}, {{ summaryMetrics(series) }}
</td>
</tr>
</table>
</div>
</template>
import _ from 'underscore';
import { scaleLinear, scaleTime } from 'd3-scale';
import { line, area, curveLinear } from 'd3-shape';
import { extent, max } from 'd3-array';
import { extent, max, sum } from 'd3-array';
import { timeMinute } from 'd3-time';
 
const d3 = { scaleLinear, scaleTime, line, area, curveLinear, extent, max, timeMinute };
const d3 = {
scaleLinear,
scaleTime,
line,
area,
curveLinear,
extent,
max,
timeMinute,
sum,
};
 
const defaultColorPalette = {
blue: ['#1f78d1', '#8fbce8'],
Loading
Loading
@@ -18,7 +28,15 @@ const defaultColorOrder = ['blue', 'orange', 'red', 'green', 'purple'];
 
const defaultStyleOrder = ['solid', 'dashed', 'dotted'];
 
function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom, yDom, lineStyle) {
function queryTimeSeries(
query,
graphWidth,
graphHeight,
graphHeightOffset,
xDom,
yDom,
lineStyle,
) {
let usedColors = [];
 
function pickColor(name) {
Loading
Loading
@@ -42,11 +60,14 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom
let metricTag = '';
let lineColor = '';
let areaColor = '';
const timeSeriesValues = timeSeries.values.map(d => d.value);
const maximumValue = d3.max(timeSeriesValues);
const accum = d3.sum(timeSeriesValues);
 
const timeSeriesScaleX = d3.scaleTime()
.range([0, graphWidth - 70]);
const timeSeriesScaleX = d3.scaleTime().range([0, graphWidth - 70]);
 
const timeSeriesScaleY = d3.scaleLinear()
const timeSeriesScaleY = d3
.scaleLinear()
.range([graphHeight - graphHeightOffset, 0]);
 
timeSeriesScaleX.domain(xDom);
Loading
Loading
@@ -55,28 +76,35 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom
 
const defined = d => !isNaN(d.value) && d.value != null;
 
const lineFunction = d3.line()
const lineFunction = d3
.line()
.defined(defined)
.curve(d3.curveLinear) // d3 v4 uses curbe instead of interpolate
.x(d => timeSeriesScaleX(d.time))
.y(d => timeSeriesScaleY(d.value));
 
const areaFunction = d3.area()
const areaFunction = d3
.area()
.defined(defined)
.curve(d3.curveLinear)
.x(d => timeSeriesScaleX(d.time))
.y0(graphHeight - graphHeightOffset)
.y1(d => timeSeriesScaleY(d.value));
 
const timeSeriesMetricLabel = timeSeries.metric[Object.keys(timeSeries.metric)[0]];
const seriesCustomizationData = query.series != null &&
const timeSeriesMetricLabel =
timeSeries.metric[Object.keys(timeSeries.metric)[0]];
const seriesCustomizationData =
query.series != null &&
_.findWhere(query.series[0].when, { value: timeSeriesMetricLabel });
 
if (seriesCustomizationData) {
metricTag = seriesCustomizationData.value || timeSeriesMetricLabel;
[lineColor, areaColor] = pickColor(seriesCustomizationData.color);
} else {
metricTag = timeSeriesMetricLabel || query.label || `series ${timeSeriesNumber + 1}`;
metricTag =
timeSeriesMetricLabel ||
query.label ||
`series ${timeSeriesNumber + 1}`;
[lineColor, areaColor] = pickColor();
}
 
Loading
Loading
@@ -89,6 +117,8 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom
areaPath: areaFunction(timeSeries.values),
timeSeriesScaleX,
values: timeSeries.values,
max: maximumValue,
average: accum / timeSeries.values.length,
lineStyle,
lineColor,
areaColor,
Loading
Loading
@@ -97,10 +127,22 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom
});
}
 
export default function createTimeSeries(queries, graphWidth, graphHeight, graphHeightOffset) {
const allValues = queries.reduce((allQueryResults, query) => allQueryResults.concat(
query.result.reduce((allResults, result) => allResults.concat(result.values), []),
), []);
export default function createTimeSeries(
queries,
graphWidth,
graphHeight,
graphHeightOffset,
) {
const allValues = queries.reduce(
(allQueryResults, query) =>
allQueryResults.concat(
query.result.reduce(
(allResults, result) => allResults.concat(result.values),
[],
),
),
[],
);
 
const xDom = d3.extent(allValues, d => d.time);
const yDom = [0, d3.max(allValues.map(d => d.value))];
Loading
Loading
@@ -108,7 +150,15 @@ export default function createTimeSeries(queries, graphWidth, graphHeight, graph
return queries.reduce((series, query, index) => {
const lineStyle = defaultStyleOrder[index % defaultStyleOrder.length];
return series.concat(
queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom, yDom, lineStyle),
queryTimeSeries(
query,
graphWidth,
graphHeight,
graphHeightOffset,
xDom,
yDom,
lineStyle,
),
);
}, []);
}
Loading
Loading
@@ -273,21 +273,6 @@
line-height: 1.2;
}
 
table {
border-collapse: collapse;
padding: 0;
margin: 0;
}
td {
vertical-align: middle;
+ td {
padding-left: 5px;
vertical-align: top;
}
}
.deploy-meta-content {
border-bottom: 1px solid $white-dark;
 
Loading
Loading
@@ -323,6 +308,21 @@
}
}
 
.prometheus-table {
border-collapse: collapse;
padding: 0;
margin: 0;
td {
vertical-align: middle;
+ td {
padding-left: 5px;
vertical-align: top;
}
}
}
.prometheus-svg-container {
position: relative;
height: 0;
Loading
Loading
@@ -330,8 +330,7 @@
padding: 0;
padding-bottom: 100%;
 
.text-metric-usage,
.legend-metric-title {
.text-metric-usage {
fill: $black;
font-weight: $gl-font-weight-normal;
font-size: 12px;
Loading
Loading
@@ -374,10 +373,6 @@
}
}
 
.text-metric-title {
font-size: 12px;
}
.y-label-text,
.x-label-text {
fill: $gray-darkest;
Loading
Loading
---
title: Add average and maximum summary statistics to the prometheus dashboard
merge_request: 17921
author:
type: changed
import Vue from 'vue';
import GraphAxis from '~/monitoring/components/graph/axis.vue';
import measurements from '~/monitoring/utils/measurements';
const createComponent = propsData => {
const Component = Vue.extend(GraphAxis);
return new Component({
propsData,
}).$mount();
};
const defaultValuesComponent = {
graphWidth: 500,
graphHeight: 300,
graphHeightOffset: 120,
margin: measurements.large.margin,
measurements: measurements.large,
yAxisLabel: 'Values',
};
function getTextFromNode(component, selector) {
return component.$el.querySelector(selector).firstChild.nodeValue.trim();
}
describe('Axis', () => {
describe('Computed props', () => {
it('textTransform', () => {
const component = createComponent(defaultValuesComponent);
expect(component.textTransform).toContain(
'translate(15, 120) rotate(-90)',
);
});
it('xPosition', () => {
const component = createComponent(defaultValuesComponent);
expect(component.xPosition).toEqual(180);
});
it('yPosition', () => {
const component = createComponent(defaultValuesComponent);
expect(component.yPosition).toEqual(240);
});
it('rectTransform', () => {
const component = createComponent(defaultValuesComponent);
expect(component.rectTransform).toContain(
'translate(0, 120) rotate(-90)',
);
});
});
it('has 2 rect-axis-text rect svg elements', () => {
const component = createComponent(defaultValuesComponent);
expect(component.$el.querySelectorAll('.rect-axis-text').length).toEqual(2);
});
it('contains text to signal the usage, title and time with multiple time series', () => {
const component = createComponent(defaultValuesComponent);
expect(getTextFromNode(component, '.y-label-text')).toEqual(
component.yAxisLabel,
);
});
});
import Vue from 'vue';
import GraphLegend from '~/monitoring/components/graph/legend.vue';
import measurements from '~/monitoring/utils/measurements';
import createTimeSeries from '~/monitoring/utils/multiple_time_series';
import { singleRowMetricsMultipleSeries, convertDatesMultipleSeries } from '../mock_data';
const createComponent = (propsData) => {
const Component = Vue.extend(GraphLegend);
return new Component({
propsData,
}).$mount();
};
const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries);
const defaultValuesComponent = {
graphWidth: 500,
graphHeight: 300,
graphHeightOffset: 120,
margin: measurements.large.margin,
measurements: measurements.large,
areaColorRgb: '#f0f0f0',
legendTitle: 'Title',
yAxisLabel: 'Values',
metricUsage: 'Value',
unitOfDisplay: 'Req/Sec',
currentDataIndex: 0,
};
const timeSeries = createTimeSeries(convertedMetrics[0].queries,
defaultValuesComponent.graphWidth, defaultValuesComponent.graphHeight,
defaultValuesComponent.graphHeightOffset);
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import {
singleRowMetricsMultipleSeries,
convertDatesMultipleSeries,
} from '../mock_data';
 
defaultValuesComponent.timeSeries = timeSeries;
function getTextFromNode(component, selector) {
return component.$el.querySelector(selector).firstChild.nodeValue.trim();
}
const convertedMetrics = convertDatesMultipleSeries(
singleRowMetricsMultipleSeries,
);
 
describe('GraphLegend', () => {
describe('Computed props', () => {
it('textTransform', () => {
const component = createComponent(defaultValuesComponent);
const defaultValuesComponent = {};
 
expect(component.textTransform).toContain('translate(15, 120) rotate(-90)');
});
const timeSeries = createTimeSeries(convertedMetrics[0].queries, 500, 300, 120);
 
it('xPosition', () => {
const component = createComponent(defaultValuesComponent);
defaultValuesComponent.timeSeries = timeSeries;
 
expect(component.xPosition).toEqual(180);
});
describe('Legend Component', () => {
let vm;
let Legend;
 
it('yPosition', () => {
const component = createComponent(defaultValuesComponent);
beforeEach(() => {
Legend = Vue.extend(GraphLegend);
});
 
expect(component.yPosition).toEqual(240);
describe('Methods', () => {
beforeEach(() => {
vm = mountComponent(Legend, {
legendTitle: 'legend',
timeSeries,
currentDataIndex: 0,
unitOfDisplay: 'Req/Sec',
});
});
 
it('rectTransform', () => {
const component = createComponent(defaultValuesComponent);
it('formatMetricUsage should contain the unit of display and the current value selected via "currentDataIndex"', () => {
const formattedMetricUsage = vm.formatMetricUsage(timeSeries[0]);
const valueFromSeries = timeSeries[0].values[vm.currentDataIndex].value;
 
expect(component.rectTransform).toContain('translate(0, 120) rotate(-90)');
expect(formattedMetricUsage.indexOf(vm.unitOfDisplay)).not.toEqual(-1);
expect(formattedMetricUsage.indexOf(valueFromSeries)).not.toEqual(-1);
});
});
 
describe('methods', () => {
it('translateLegendGroup should only change Y direction', () => {
const component = createComponent(defaultValuesComponent);
it('strokeDashArray', () => {
const dashedArray = vm.strokeDashArray('dashed');
const dottedArray = vm.strokeDashArray('dotted');
 
const translatedCoordinate = component.translateLegendGroup(1);
expect(translatedCoordinate.indexOf('translate(0, ')).not.toEqual(-1);
expect(dashedArray).toEqual('6, 3');
expect(dottedArray).toEqual('3, 3');
});
 
it('formatMetricUsage should contain the unit of display and the current value selected via "currentDataIndex"', () => {
const component = createComponent(defaultValuesComponent);
it('summaryMetrics gets the average and max of a series', () => {
const summary = vm.summaryMetrics(timeSeries[0]);
 
const formattedMetricUsage = component.formatMetricUsage(timeSeries[0]);
const valueFromSeries = timeSeries[0].values[component.currentDataIndex].value;
expect(formattedMetricUsage.indexOf(component.unitOfDisplay)).not.toEqual(-1);
expect(formattedMetricUsage.indexOf(valueFromSeries)).not.toEqual(-1);
expect(summary.indexOf('Max')).not.toEqual(-1);
expect(summary.indexOf('Avg')).not.toEqual(-1);
});
});
 
it('has 2 rect-axis-text rect svg elements', () => {
const component = createComponent(defaultValuesComponent);
expect(component.$el.querySelectorAll('.rect-axis-text').length).toEqual(2);
});
it('contains text to signal the usage, title and time with multiple time series', () => {
const component = createComponent(defaultValuesComponent);
const titles = component.$el.querySelectorAll('.legend-metric-title');
describe('View', () => {
beforeEach(() => {
vm = mountComponent(Legend, {
legendTitle: 'legend',
timeSeries,
currentDataIndex: 0,
unitOfDisplay: 'Req/Sec',
});
});
 
expect(titles[0].textContent.indexOf('1xx')).not.toEqual(-1);
expect(titles[1].textContent.indexOf('2xx')).not.toEqual(-1);
expect(getTextFromNode(component, '.y-label-text')).toEqual(component.yAxisLabel);
});
it('should render the usage, title and time with multiple time series', () => {
const titles = vm.$el.querySelectorAll('.legend-metric-title');
 
it('should contain the same number of legend groups as the timeSeries length', () => {
const component = createComponent(defaultValuesComponent);
expect(titles[0].textContent.indexOf('1xx')).not.toEqual(-1);
expect(titles[1].textContent.indexOf('2xx')).not.toEqual(-1);
});
 
expect(component.$el.querySelectorAll('.legend-group').length).toEqual(component.timeSeries.length);
it('should container the same number of rows in the table as time series', () => {
expect(vm.$el.querySelectorAll('.prometheus-table tr').length).toEqual(
vm.timeSeries.length,
);
});
});
});
Loading
Loading
@@ -2,11 +2,15 @@ import Vue from 'vue';
import Graph from '~/monitoring/components/graph.vue';
import MonitoringMixins from '~/monitoring/mixins/monitoring_mixins';
import eventHub from '~/monitoring/event_hub';
import { deploymentData, convertDatesMultipleSeries, singleRowMetricsMultipleSeries } from './mock_data';
import {
deploymentData,
convertDatesMultipleSeries,
singleRowMetricsMultipleSeries,
} from './mock_data';
 
const tagsPath = 'http://test.host/frontend-fixtures/environments-project/tags';
const projectPath = 'http://test.host/frontend-fixtures/environments-project';
const createComponent = (propsData) => {
const createComponent = propsData => {
const Component = Vue.extend(Graph);
 
return new Component({
Loading
Loading
@@ -14,7 +18,9 @@ const createComponent = (propsData) => {
}).$mount();
};
 
const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries);
const convertedMetrics = convertDatesMultipleSeries(
singleRowMetricsMultipleSeries,
);
 
describe('Graph', () => {
beforeEach(() => {
Loading
Loading
@@ -31,7 +37,9 @@ describe('Graph', () => {
projectPath,
});
 
expect(component.$el.querySelector('.text-center').innerText.trim()).toBe(component.graphData.title);
expect(component.$el.querySelector('.text-center').innerText.trim()).toBe(
component.graphData.title,
);
});
 
describe('Computed props', () => {
Loading
Loading
@@ -46,8 +54,9 @@ describe('Graph', () => {
});
 
const transformedHeight = `${component.graphHeight - 100}`;
expect(component.axisTransform.indexOf(transformedHeight))
.not.toEqual(-1);
expect(component.axisTransform.indexOf(transformedHeight)).not.toEqual(
-1,
);
});
 
it('outerViewBox gets a width and height property based on the DOM size of the element', () => {
Loading
Loading
@@ -63,11 +72,11 @@ describe('Graph', () => {
const viewBoxArray = component.outerViewBox.split(' ');
expect(typeof component.outerViewBox).toEqual('string');
expect(viewBoxArray[2]).toEqual(component.graphWidth.toString());
expect(viewBoxArray[3]).toEqual(component.graphHeight.toString());
expect(viewBoxArray[3]).toEqual((component.graphHeight - 50).toString());
});
});
 
it('sends an event to the eventhub when it has finished resizing', (done) => {
it('sends an event to the eventhub when it has finished resizing', done => {
const component = createComponent({
graphData: convertedMetrics[1],
classType: 'col-md-6',
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment