Commit 35b18fe2 authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch 'move-deployment-series-logic-outside-chart-components' into 'master'

Move deployment series logic out of charts

See merge request gitlab-org/gitlab!28825
parents 52aff747 3daea290
import { graphTypes, symbolSizes } from '../../constants';
/**
* Annotations and deployments are decoration layers on
* top of the actual chart data. We use a scatter plot to
* display this information. Each chart has its coordinate
* system based on data and irresptive of the data, these
* decorations have to be placed in specific locations.
* For this reason, annotations have their own coordinate system,
*
* As of %12.9, only deployment icons, a type of annotations, need
* to be displayed on the chart.
*
* After https://gitlab.com/gitlab-org/gitlab/-/issues/211418,
* annotations and deployments will co-exist in the same
* series as they logically belong together. Annotations will be
* passed as markLine objects.
*/
/**
* Deployment icons, a type of annotation, are displayed
* along the [min, max] range at height `pos`.
*/
const annotationsYAxisCoords = {
min: 0,
pos: 3, // 3% height of chart's grid
max: 100,
};
/**
* Annotation y axis min & max allows the deployment
* icons to position correctly in the chart
*/
export const annotationsYAxis = {
show: false,
min: annotationsYAxisCoords.min,
max: annotationsYAxisCoords.max,
axisLabel: {
// formatter fn required to trigger tooltip re-positioning
formatter: () => {},
},
};
/**
* This util method check if a particular series data point
* is of annotation type. Annotations are generally scatter
* plot charts
*
* @param {String} type series component type
* @returns {Boolean}
*/
export const isAnnotation = type => type === graphTypes.annotationsData;
/**
* This method currently supports only deployments. After
* https://gitlab.com/gitlab-org/gitlab/-/issues/211418 annotations
* support will be added in this method.
*
* This method is extracted out of the charts so that
* annotation lines can be easily supported in
* the future.
*
* @param {Array} deployments deployments data
* @returns {Object} annotation series object
*/
export const generateAnnotationsSeries = (deployments = []) => {
if (!deployments.length) {
return [];
}
const data = deployments.map(deployment => {
return {
name: 'deployments',
value: [deployment.createdAt, annotationsYAxisCoords.pos],
symbol: deployment.icon,
symbolSize: symbolSizes.default,
itemStyle: {
color: deployment.color,
},
};
});
return {
type: graphTypes.annotationsData,
yAxisIndex: 1, // annotationsYAxis index
data,
};
};
......@@ -6,29 +6,12 @@ import dateFormat from 'dateformat';
import { s__, __ } from '~/locale';
import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
import Icon from '~/vue_shared/components/icon.vue';
import {
chartHeight,
graphTypes,
lineTypes,
lineWidths,
symbolSizes,
dateFormats,
} from '../../constants';
import { chartHeight, lineTypes, lineWidths, dateFormats } from '../../constants';
import { getYAxisOptions, getChartGrid, getTooltipFormatter } from './options';
import { annotationsYAxis, generateAnnotationsSeries, isAnnotation } from './annotations';
import { makeDataSeries } from '~/helpers/monitor_helper';
import { graphDataValidatorForValues } from '../../utils';
/**
* A "virtual" coordinates system for the deployment icons.
* Deployment icons are displayed along the [min, max]
* range at height `pos`.
*/
const deploymentYAxisCoords = {
min: 0,
pos: 3, // 3% height of chart's grid
max: 100,
};
const THROTTLED_DATAZOOM_WAIT = 1000; // milliseconds
const timestampToISODate = timestamp => new Date(timestamp).toISOString();
......@@ -154,9 +137,7 @@ export default {
}, []);
},
chartOptionSeries() {
return (this.option.series || []).concat(
this.deploymentSeries ? [this.deploymentSeries] : [],
);
return (this.option.series || []).concat(generateAnnotationsSeries(this.recentDeployments));
},
chartOptions() {
const { yAxis, xAxis } = this.option;
......@@ -167,16 +148,6 @@ export default {
...yAxis,
};
const deploymentsYAxis = {
show: false,
min: deploymentYAxisCoords.min,
max: deploymentYAxisCoords.max,
axisLabel: {
// formatter fn required to trigger tooltip re-positioning
formatter: () => {},
},
};
const timeXAxis = {
name: __('Time'),
type: 'time',
......@@ -192,7 +163,7 @@ export default {
return {
series: this.chartOptionSeries,
xAxis: timeXAxis,
yAxis: [dataYAxis, deploymentsYAxis],
yAxis: [dataYAxis, annotationsYAxis],
grid: getChartGrid(),
dataZoom: [this.dataZoomConfig],
...option,
......@@ -249,29 +220,14 @@ export default {
tagUrl: tag ? `${this.tagsPath}/${ref.name}` : null,
ref: ref.name,
showDeploymentFlag: false,
icon: this.svgs.rocket,
color: this.primaryColor,
});
}
return acc;
}, []);
},
deploymentSeries() {
return {
type: graphTypes.deploymentData,
yAxisIndex: 1, // deploymentsYAxis index
data: this.recentDeployments.map(deployment => [
deployment.createdAt,
deploymentYAxisCoords.pos,
]),
symbol: this.svgs.rocket,
symbolSize: symbolSizes.default,
itemStyle: {
color: this.primaryColor,
},
};
},
tooltipYFormatter() {
// Use same format as y-axis
return getTooltipFormatter({ format: this.graphData.yAxis?.format });
......@@ -297,7 +253,7 @@ export default {
params.seriesData.forEach(dataPoint => {
if (dataPoint.value) {
const [xVal, yVal] = dataPoint.value;
this.tooltip.isDeployment = dataPoint.componentSubType === graphTypes.deploymentData;
this.tooltip.isDeployment = isAnnotation(dataPoint.componentSubType);
if (this.tooltip.isDeployment) {
const [deploy] = this.recentDeployments.filter(
deployment => deployment.createdAt === xVal,
......
......@@ -49,7 +49,7 @@ export const sidebarAnimationDuration = 300; // milliseconds.
export const chartHeight = 300;
export const graphTypes = {
deploymentData: 'scatter',
annotationsData: 'scatter',
};
export const symbolSizes = {
......
import { generateAnnotationsSeries } from '~/monitoring/components/charts/annotations';
import { deploymentData } from '../../mock_data';
describe('annotations spec', () => {
describe('generateAnnotationsSeries', () => {
it('default options', () => {
const annotations = generateAnnotationsSeries();
expect(annotations).toEqual([]);
});
it('with deployments', () => {
const annotations = generateAnnotationsSeries(deploymentData);
expect(annotations).toEqual(
expect.objectContaining({
type: 'scatter',
yAxisIndex: 1,
data: expect.any(Array),
}),
);
annotations.data.forEach(annotation => {
expect(annotation).toEqual(expect.any(Object));
});
});
});
});
......@@ -413,16 +413,24 @@ describe('Time series component', () => {
});
});
describe('deploymentSeries', () => {
describe('annotationSeries', () => {
it('utilizes deployment data', () => {
expect(timeSeriesChart.vm.deploymentSeries.yAxisIndex).toBe(1); // same as deployment y axis
expect(timeSeriesChart.vm.deploymentSeries.data).toEqual([
['2019-07-16T10:14:25.589Z', expect.any(Number)],
['2019-07-16T11:14:25.589Z', expect.any(Number)],
['2019-07-16T12:14:25.589Z', expect.any(Number)],
const annotationSeries = timeSeriesChart.vm.chartOptionSeries[0];
expect(annotationSeries.yAxisIndex).toBe(1); // same as annotations y axis
expect(annotationSeries.data).toEqual([
expect.objectContaining({
symbolSize: 14,
value: ['2019-07-16T10:14:25.589Z', expect.any(Number)],
}),
expect.objectContaining({
symbolSize: 14,
value: ['2019-07-16T11:14:25.589Z', expect.any(Number)],
}),
expect.objectContaining({
symbolSize: 14,
value: ['2019-07-16T12:14:25.589Z', expect.any(Number)],
}),
]);
expect(timeSeriesChart.vm.deploymentSeries.symbolSize).toBe(14);
});
});
......
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