From 71ae61f8794ed2cde39c52001b5c7e9c1cb4e593 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Sun, 5 Apr 2020 00:09:22 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../components/charts/annotations.js | 86 +++++++++++++++++++ .../components/charts/time_series.vue | 58 ++----------- .../javascripts/monitoring/constants.js | 2 +- .../components/charts/annotations_spec.js | 27 ++++++ .../components/charts/time_series_spec.js | 24 ++++-- 5 files changed, 137 insertions(+), 60 deletions(-) create mode 100644 app/assets/javascripts/monitoring/components/charts/annotations.js create mode 100644 spec/frontend/monitoring/components/charts/annotations_spec.js diff --git a/app/assets/javascripts/monitoring/components/charts/annotations.js b/app/assets/javascripts/monitoring/components/charts/annotations.js new file mode 100644 index 00000000000..cc2b2bd0900 --- /dev/null +++ b/app/assets/javascripts/monitoring/components/charts/annotations.js @@ -0,0 +1,86 @@ +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, + }; +}; diff --git a/app/assets/javascripts/monitoring/components/charts/time_series.vue b/app/assets/javascripts/monitoring/components/charts/time_series.vue index 0ddd690ce0c..73c63a0580f 100644 --- a/app/assets/javascripts/monitoring/components/charts/time_series.vue +++ b/app/assets/javascripts/monitoring/components/charts/time_series.vue @@ -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, diff --git a/app/assets/javascripts/monitoring/constants.js b/app/assets/javascripts/monitoring/constants.js index 6609946e02e..b2911bcae8f 100644 --- a/app/assets/javascripts/monitoring/constants.js +++ b/app/assets/javascripts/monitoring/constants.js @@ -49,7 +49,7 @@ export const sidebarAnimationDuration = 300; // milliseconds. export const chartHeight = 300; export const graphTypes = { - deploymentData: 'scatter', + annotationsData: 'scatter', }; export const symbolSizes = { diff --git a/spec/frontend/monitoring/components/charts/annotations_spec.js b/spec/frontend/monitoring/components/charts/annotations_spec.js new file mode 100644 index 00000000000..100b13eabf4 --- /dev/null +++ b/spec/frontend/monitoring/components/charts/annotations_spec.js @@ -0,0 +1,27 @@ +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)); + }); + }); + }); +}); diff --git a/spec/frontend/monitoring/components/charts/time_series_spec.js b/spec/frontend/monitoring/components/charts/time_series_spec.js index 129d6eda7cf..84b74ef659e 100644 --- a/spec/frontend/monitoring/components/charts/time_series_spec.js +++ b/spec/frontend/monitoring/components/charts/time_series_spec.js @@ -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); }); });