Commit 092445a4 authored by Clement Ho's avatar Clement Ho

Merge branch 'prettify-monitoring-code' into 'master'

Clean up monitoring components

See merge request gitlab-org/gitlab-ce!18030
parents d3520573 b95c1850
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import Flash from '../../flash'; import Flash from '../../flash';
import MonitoringService from '../services/monitoring_service'; import MonitoringService from '../services/monitoring_service';
import GraphGroup from './graph_group.vue'; import GraphGroup from './graph_group.vue';
import Graph from './graph.vue'; import Graph from './graph.vue';
import EmptyState from './empty_state.vue'; import EmptyState from './empty_state.vue';
import MonitoringStore from '../stores/monitoring_store'; import MonitoringStore from '../stores/monitoring_store';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
export default { export default {
components: { components: {
Graph, Graph,
GraphGroup, GraphGroup,
EmptyState, EmptyState,
}, },
props: { props: {
hasMetrics: { hasMetrics: {
type: Boolean, type: Boolean,
...@@ -82,7 +81,6 @@ ...@@ -82,7 +81,6 @@
required: true, required: true,
}, },
}, },
data() { data() {
return { return {
store: new MonitoringStore(), store: new MonitoringStore(),
...@@ -94,7 +92,6 @@ ...@@ -94,7 +92,6 @@
resizeThrottled: {}, resizeThrottled: {},
}; };
}, },
created() { created() {
this.service = new MonitoringService({ this.service = new MonitoringService({
metricsEndpoint: this.metricsEndpoint, metricsEndpoint: this.metricsEndpoint,
...@@ -103,13 +100,11 @@ ...@@ -103,13 +100,11 @@
eventHub.$on('toggleAspectRatio', this.toggleAspectRatio); eventHub.$on('toggleAspectRatio', this.toggleAspectRatio);
eventHub.$on('hoverChanged', this.hoverChanged); eventHub.$on('hoverChanged', this.hoverChanged);
}, },
beforeDestroy() { beforeDestroy() {
eventHub.$off('toggleAspectRatio', this.toggleAspectRatio); eventHub.$off('toggleAspectRatio', this.toggleAspectRatio);
eventHub.$off('hoverChanged', this.hoverChanged); eventHub.$off('hoverChanged', this.hoverChanged);
window.removeEventListener('resize', this.resizeThrottled, false); window.removeEventListener('resize', this.resizeThrottled, false);
}, },
mounted() { mounted() {
this.resizeThrottled = _.throttle(this.resize, 600); this.resizeThrottled = _.throttle(this.resize, 600);
if (!this.hasMetrics) { if (!this.hasMetrics) {
...@@ -119,14 +114,13 @@ ...@@ -119,14 +114,13 @@
window.addEventListener('resize', this.resizeThrottled, false); window.addEventListener('resize', this.resizeThrottled, false);
} }
}, },
methods: { methods: {
getGraphsData() { getGraphsData() {
this.state = 'loading'; this.state = 'loading';
Promise.all([ Promise.all([
this.service.getGraphsData() this.service.getGraphsData().then(data => this.store.storeMetrics(data)),
.then(data => this.store.storeMetrics(data)), this.service
this.service.getDeploymentData() .getDeploymentData()
.then(data => this.store.storeDeploymentData(data)) .then(data => this.store.storeDeploymentData(data))
.catch(() => new Flash('Error getting deployment information.')), .catch(() => new Flash('Error getting deployment information.')),
]) ])
...@@ -137,13 +131,13 @@ ...@@ -137,13 +131,13 @@
} }
this.showEmptyState = false; this.showEmptyState = false;
}) })
.catch(() => { this.state = 'unableToConnect'; }); .catch(() => {
this.state = 'unableToConnect';
});
}, },
resize() { resize() {
this.updateAspectRatio = true; this.updateAspectRatio = true;
}, },
toggleAspectRatio() { toggleAspectRatio() {
this.updatedAspectRatios = this.updatedAspectRatios += 1; this.updatedAspectRatios = this.updatedAspectRatios += 1;
if (this.store.getMetricsCount() === this.updatedAspectRatios) { if (this.store.getMetricsCount() === this.updatedAspectRatios) {
...@@ -151,12 +145,11 @@ ...@@ -151,12 +145,11 @@
this.updatedAspectRatios = 0; this.updatedAspectRatios = 0;
} }
}, },
hoverChanged(data) { hoverChanged(data) {
this.hoverData = data; this.hoverData = data;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
export default { export default {
props: { props: {
documentationPath: { documentationPath: {
type: String, type: String,
...@@ -79,13 +79,12 @@ ...@@ -79,13 +79,12 @@
currentState() { currentState() {
return this.states[this.selectedState]; return this.states[this.selectedState];
}, },
showButtonDescription() { showButtonDescription() {
if (this.selectedState === 'unableToConnect') return true; if (this.selectedState === 'unableToConnect') return true;
return false; return false;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { scaleLinear, scaleTime } from 'd3-scale'; import { scaleLinear, scaleTime } from 'd3-scale';
import { axisLeft, axisBottom } from 'd3-axis'; import { axisLeft, axisBottom } from 'd3-axis';
import { max, extent } from 'd3-array'; import { max, extent } from 'd3-array';
import { select } from 'd3-selection'; import { select } from 'd3-selection';
import GraphLegend from './graph/legend.vue'; import GraphLegend from './graph/legend.vue';
import GraphFlag from './graph/flag.vue'; import GraphFlag from './graph/flag.vue';
import GraphDeployment from './graph/deployment.vue'; import GraphDeployment from './graph/deployment.vue';
import GraphPath from './graph/path.vue'; import GraphPath from './graph/path.vue';
import MonitoringMixin from '../mixins/monitoring_mixins'; import MonitoringMixin from '../mixins/monitoring_mixins';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import measurements from '../utils/measurements'; import measurements from '../utils/measurements';
import { bisectDate, timeScaleFormat } from '../utils/date_time_formatters'; import { bisectDate, timeScaleFormat } from '../utils/date_time_formatters';
import createTimeSeries from '../utils/multiple_time_series'; import createTimeSeries from '../utils/multiple_time_series';
import bp from '../../breakpoints'; import bp from '../../breakpoints';
const d3 = { scaleLinear, scaleTime, axisLeft, axisBottom, max, extent, select }; const d3 = { scaleLinear, scaleTime, axisLeft, axisBottom, max, extent, select };
export default { export default {
components: { components: {
GraphLegend, GraphLegend,
GraphFlag, GraphFlag,
GraphDeployment, GraphDeployment,
GraphPath, GraphPath,
}, },
mixins: [MonitoringMixin], mixins: [MonitoringMixin],
props: { props: {
graphData: { graphData: {
type: Object, type: Object,
...@@ -63,7 +61,6 @@ ...@@ -63,7 +61,6 @@
default: false, default: false,
}, },
}, },
data() { data() {
return { return {
baseGraphHeight: 450, baseGraphHeight: 450,
...@@ -90,31 +87,25 @@ ...@@ -90,31 +87,25 @@
realPixelRatio: 1, realPixelRatio: 1,
}; };
}, },
computed: { computed: {
outerViewBox() { outerViewBox() {
return `0 0 ${this.baseGraphWidth} ${this.baseGraphHeight}`; return `0 0 ${this.baseGraphWidth} ${this.baseGraphHeight}`;
}, },
innerViewBox() { innerViewBox() {
return `0 0 ${this.baseGraphWidth - 150} ${this.baseGraphHeight}`; return `0 0 ${this.baseGraphWidth - 150} ${this.baseGraphHeight}`;
}, },
axisTransform() { axisTransform() {
return `translate(70, ${this.graphHeight - 100})`; return `translate(70, ${this.graphHeight - 100})`;
}, },
paddingBottomRootSvg() { paddingBottomRootSvg() {
return { return {
paddingBottom: `${(Math.ceil(this.baseGraphHeight * 100) / this.baseGraphWidth) || 0}%`, paddingBottom: `${Math.ceil(this.baseGraphHeight * 100) / this.baseGraphWidth || 0}%`,
}; };
}, },
deploymentFlagData() { deploymentFlagData() {
return this.reducedDeploymentData.find(deployment => deployment.showDeploymentFlag); return this.reducedDeploymentData.find(deployment => deployment.showDeploymentFlag);
}, },
}, },
watch: { watch: {
updateAspectRatio() { updateAspectRatio() {
if (this.updateAspectRatio) { if (this.updateAspectRatio) {
...@@ -125,16 +116,13 @@ ...@@ -125,16 +116,13 @@
eventHub.$emit('toggleAspectRatio'); eventHub.$emit('toggleAspectRatio');
} }
}, },
hoverData() { hoverData() {
this.positionFlag(); this.positionFlag();
}, },
}, },
mounted() { mounted() {
this.draw(); this.draw();
}, },
methods: { methods: {
draw() { draw() {
const breakpointSize = bp.getBreakpointSize(); const breakpointSize = bp.getBreakpointSize();
...@@ -148,19 +136,17 @@ ...@@ -148,19 +136,17 @@
this.unitOfDisplay = query.unit || ''; this.unitOfDisplay = query.unit || '';
this.yAxisLabel = this.graphData.y_label || 'Values'; this.yAxisLabel = this.graphData.y_label || 'Values';
this.legendTitle = query.label || 'Average'; this.legendTitle = query.label || 'Average';
this.graphWidth = this.$refs.baseSvg.clientWidth - this.graphWidth = this.$refs.baseSvg.clientWidth - this.margin.left - this.margin.right;
this.margin.left - this.margin.right;
this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom; this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom;
this.baseGraphHeight = this.graphHeight; this.baseGraphHeight = this.graphHeight;
this.baseGraphWidth = this.graphWidth; this.baseGraphWidth = this.graphWidth;
// pixel offsets inside the svg and outside are not 1:1 // pixel offsets inside the svg and outside are not 1:1
this.realPixelRatio = (this.$refs.baseSvg.clientWidth / this.baseGraphWidth); this.realPixelRatio = this.$refs.baseSvg.clientWidth / this.baseGraphWidth;
this.renderAxesPaths(); this.renderAxesPaths();
this.formatDeployments(); this.formatDeployments();
}, },
handleMouseOverGraph(e) { handleMouseOverGraph(e) {
let point = this.$refs.graphData.createSVGPoint(); let point = this.$refs.graphData.createSVGPoint();
point.x = e.clientX; point.x = e.clientX;
...@@ -174,7 +160,7 @@ ...@@ -174,7 +160,7 @@
const d1 = firstTimeSeries.values[overlayIndex]; const d1 = firstTimeSeries.values[overlayIndex];
if (d0 === undefined || d1 === undefined) return; if (d0 === undefined || d1 === undefined) return;
const evalTime = timeValueOverlay - d0[0] > d1[0] - timeValueOverlay; const evalTime = timeValueOverlay - d0[0] > d1[0] - timeValueOverlay;
const hoveredDataIndex = evalTime ? overlayIndex : (overlayIndex - 1); const hoveredDataIndex = evalTime ? overlayIndex : overlayIndex - 1;
const hoveredDate = firstTimeSeries.values[hoveredDataIndex].time; const hoveredDate = firstTimeSeries.values[hoveredDataIndex].time;
const currentDeployXPos = this.mouseOverDeployInfo(point.x); const currentDeployXPos = this.mouseOverDeployInfo(point.x);
...@@ -183,7 +169,6 @@ ...@@ -183,7 +169,6 @@
currentDeployXPos, currentDeployXPos,
}); });
}, },
renderAxesPaths() { renderAxesPaths() {
this.timeSeries = createTimeSeries( this.timeSeries = createTimeSeries(
this.graphData.queries, this.graphData.queries,
...@@ -198,39 +183,47 @@ ...@@ -198,39 +183,47 @@
this.baseGraphHeight = this.baseGraphHeight += (this.timeSeries.length - 3) * 20; this.baseGraphHeight = this.baseGraphHeight += (this.timeSeries.length - 3) * 20;
} }
const axisXScale = d3.scaleTime() const axisXScale = d3.scaleTime().range([0, this.graphWidth - 70]);
.range([0, this.graphWidth - 70]); const axisYScale = d3.scaleLinear().range([this.graphHeight - this.graphHeightOffset, 0]);
const axisYScale = d3.scaleLinear()
.range([this.graphHeight - this.graphHeightOffset, 0]);
const allValues = this.timeSeries.reduce((all, { values }) => all.concat(values), []); const allValues = this.timeSeries.reduce((all, { values }) => all.concat(values), []);
axisXScale.domain(d3.extent(allValues, d => d.time)); axisXScale.domain(d3.extent(allValues, d => d.time));
axisYScale.domain([0, d3.max(allValues.map(d => d.value))]); axisYScale.domain([0, d3.max(allValues.map(d => d.value))]);
const xAxis = d3.axisBottom() const xAxis = d3
.axisBottom()
.scale(axisXScale) .scale(axisXScale)
.ticks(this.graphWidth / 120) .ticks(this.graphWidth / 120)
.tickFormat(timeScaleFormat); .tickFormat(timeScaleFormat);
const yAxis = d3.axisLeft() const yAxis = d3
.axisLeft()
.scale(axisYScale) .scale(axisYScale)
.ticks(measurements.yTicks); .ticks(measurements.yTicks);
d3.select(this.$refs.baseSvg).select('.x-axis').call(xAxis); d3
.select(this.$refs.baseSvg)
.select('.x-axis')
.call(xAxis);
const width = this.graphWidth; const width = this.graphWidth;
d3.select(this.$refs.baseSvg).select('.y-axis').call(yAxis) d3
.select(this.$refs.baseSvg)
.select('.y-axis')
.call(yAxis)
.selectAll('.tick') .selectAll('.tick')
.each(function createTickLines(d, i) { .each(function createTickLines(d, i) {
if (i > 0) { if (i > 0) {
d3.select(this).select('line') d3
.select(this)
.select('line')
.attr('x2', width) .attr('x2', width)
.attr('class', 'axis-tick'); .attr('class', 'axis-tick');
} // Avoid adding the class to the first tick, to prevent coloring } // Avoid adding the class to the first tick, to prevent coloring
}); // This will select all of the ticks once they're rendered }); // This will select all of the ticks once they're rendered
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
export default { export default {
props: { props: {
deploymentData: { deploymentData: {
type: Array, type: Array,
...@@ -14,19 +14,17 @@ ...@@ -14,19 +14,17 @@
required: true, required: true,
}, },
}, },
computed: { computed: {
calculatedHeight() { calculatedHeight() {
return this.graphHeight - this.graphHeightOffset; return this.graphHeight - this.graphHeightOffset;
}, },
}, },
methods: { methods: {
transformDeploymentGroup(deployment) { transformDeploymentGroup(deployment) {
return `translate(${Math.floor(deployment.xPos) - 5}, 20)`; return `translate(${Math.floor(deployment.xPos) - 5}, 20)`;
}, },
}, },
}; };
</script> </script>
<template> <template>
<g class="deploy-info"> <g class="deploy-info">
......
<script> <script>
import { dateFormat, timeFormat } from '../../utils/date_time_formatters'; import { dateFormat, timeFormat } from '../../utils/date_time_formatters';
import { formatRelevantDigits } from '../../../lib/utils/number_utils'; import { formatRelevantDigits } from '../../../lib/utils/number_utils';
import icon from '../../../vue_shared/components/icon.vue'; import icon from '../../../vue_shared/components/icon.vue';
export default { export default {
components: { components: {
icon, icon,
}, },
...@@ -54,24 +54,21 @@ ...@@ -54,24 +54,21 @@
required: true, required: true,
}, },
}, },
computed: { computed: {
formatTime() { formatTime() {
return this.deploymentFlagData ? return this.deploymentFlagData
timeFormat(this.deploymentFlagData.time) : ? timeFormat(this.deploymentFlagData.time)
timeFormat(this.currentData.time); : timeFormat(this.currentData.time);
}, },
formatDate() { formatDate() {
return this.deploymentFlagData ? return this.deploymentFlagData
dateFormat(this.deploymentFlagData.time) : ? dateFormat(this.deploymentFlagData.time)
dateFormat(this.currentData.time); : dateFormat(this.currentData.time);
}, },
cursorStyle() { cursorStyle() {
const xCoordinate = this.deploymentFlagData ? const xCoordinate = this.deploymentFlagData
this.deploymentFlagData.xPos : ? this.deploymentFlagData.xPos
this.currentXCoordinate; : this.currentXCoordinate;
const offsetTop = 20 * this.realPixelRatio; const offsetTop = 20 * this.realPixelRatio;
const offsetLeft = (70 + xCoordinate) * this.realPixelRatio; const offsetLeft = (70 + xCoordinate) * this.realPixelRatio;
...@@ -83,7 +80,6 @@ ...@@ -83,7 +80,6 @@
height: `${height}px`, height: `${height}px`,
}; };
}, },
flagOrientation() { flagOrientation() {
if (this.currentXCoordinate * this.realPixelRatio > 120) { if (this.currentXCoordinate * this.realPixelRatio > 120) {
return 'left'; return 'left';
...@@ -91,20 +87,17 @@ ...@@ -91,20 +87,17 @@
return 'right'; return 'right';
}, },
}, },
methods: { methods: {
seriesMetricValue(series) { seriesMetricValue(series) {
const index = this.deploymentFlagData ? const index = this.deploymentFlagData
this.deploymentFlagData.seriesIndex : ? this.deploymentFlagData.seriesIndex
this.currentDataIndex; : this.currentDataIndex;
const value = series.values[index] && const value = series.values[index] && series.values[index].value;
series.values[index].value;
if (isNaN(value)) { if (isNaN(value)) {
return '-'; return '-';
} }
return `${formatRelevantDigits(value)}${this.unitOfDisplay}`; return `${formatRelevantDigits(value)}${this.unitOfDisplay}`;
}, },
seriesMetricLabel(index, series) { seriesMetricLabel(index, series) {
if (this.timeSeries.length < 2) { if (this.timeSeries.length < 2) {
return this.legendTitle; return this.legendTitle;
...@@ -114,14 +107,13 @@ ...@@ -114,14 +107,13 @@
} }
return `series ${index + 1}`; return `series ${index + 1}`;
}, },
strokeDashArray(type) { strokeDashArray(type) {
if (type === 'dashed') return '6, 3'; if (type === 'dashed') return '6, 3';
if (type === 'dotted') return '3, 3'; if (type === 'dotted') return '3, 3';
return null; return null;
}, },
}, },
}; };
</script> </script>
<template> <template>
......
<script> <script>
import { formatRelevantDigits } from '../../../lib/utils/number_utils'; import { formatRelevantDigits } from '../../../lib/utils/number_utils';
export default { export default {
props: { props: {
graphWidth: { graphWidth: {
type: Number, type: Number,
...@@ -55,29 +55,24 @@ ...@@ -55,29 +55,24 @@
}, },
computed: { computed: {
textTransform() { textTransform() {
const yCoordinate = (((this.graphHeight - this.margin.top) const yCoordinate =
+ this.measurements.axisLabelLineOffset) / 2) || 0; (this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 || 0;
return `translate(15, ${yCoordinate}) rotate(-90)`; return `translate(15, ${yCoordinate}) rotate(-90)`;
}, },
rectTransform() { rectTransform() {
const yCoordinate = (((this.graphHeight - this.margin.top) const yCoordinate =
+ this.measurements.axisLabelLineOffset) / 2) (this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset) / 2 +
+ (this.yLabelWidth / 2) || 0; this.yLabelWidth / 2 || 0;
return `translate(0, ${yCoordinate}) rotate(-90)`; return `translate(0, ${yCoordinate}) rotate(-90)`;
}, },
xPosition() { xPosition() {
return (((this.graphWidth + this.measurements.axisLabelLineOffset) / 2) return (this.graphWidth + this.measurements.axisLabelLineOffset) / 2 - this.margin.right || 0;
- this.margin.right) || 0;
}, },
yPosition() { yPosition() {
return ((this.graphHeight - this.margin.top) + this.measurements.axisLabelLineOffset) || 0; return this.graphHeight - this.margin.top + this.measurements.axisLabelLineOffset || 0;
}, },
}, },
mounted() { mounted() {
this.$nextTick(() => { this.$nextTick(() => {
...@@ -96,32 +91,29 @@ ...@@ -96,32 +91,29 @@
}, },
methods: { methods: {
translateLegendGroup(index) { translateLegendGroup(index) {
return `translate(0, ${12 * (index)})`; return `translate(0, ${12 * index})`;
}, },
formatMetricUsage(series) { formatMetricUsage(series) {
const value = series.values[this.currentDataIndex] && const value =
series.values[this.currentDataIndex].value; series.values[this.currentDataIndex] && series.values[this.currentDataIndex].value;
if (isNaN(value)) { if (isNaN(value)) {
return '-'; return '-';
} }
return `${formatRelevantDigits(value)} ${this.unitOfDisplay}`; return `${formatRelevantDigits(value)} ${this.unitOfDisplay}`;
}, },
createSeriesString(index, series) { createSeriesString(index, series) {
if (series.metricTag) { if (series.metricTag) {
return `${series.metricTag} ${this.formatMetricUsage(series)}`; return `${series.metricTag} ${this.formatMetricUsage(series)}`;
} }
return `${this.legendTitle} series ${index + 1} ${this.formatMetricUsage(series)}`; return `${this.legendTitle} series ${index + 1} ${this.formatMetricUsage(series)}`;
}, },
strokeDashArray(type) { strokeDashArray(type) {
if (type === 'dashed') return '6, 3'; if (type === 'dashed') return '6, 3';
if (type === 'dotted') return '3, 3'; if (type === 'dotted') return '3, 3';
return null; return null;
}, },
}, },
}; };
</script> </script>
<template> <template>
<g class="axis-label-container"> <g class="axis-label-container">
......
<script> <script>
export default { export default {
props: { props: {
generatedLinePath: { generatedLinePath: {
type: String, type: String,
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
return null; return null;
}, },
}, },
}; };
</script> </script>
<template> <template>
<g> <g>
......
<script> <script>
export default { export default {
props: { props: {
name: { name: {
type: String, type: String,
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
default: true, default: true,
}, },
}, },
}; };
</script> </script>
<template> <template>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment