Commit 53e21504 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch 'jivanvl-add-support-stacked-column-charts' into 'master'

Add support for stacked column charts

See merge request gitlab-org/gitlab!23474
parents 065f3e03 3fb4efdd
<script>
import { GlResizeObserverDirective } from '@gitlab/ui';
import { GlStackedColumnChart } from '@gitlab/ui/dist/charts';
import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
import { chartHeight } from '../../constants';
import { graphDataValidatorForValues } from '../../utils';
export default {
components: {
GlStackedColumnChart,
},
directives: {
GlResizeObserverDirective,
},
props: {
graphData: {
type: Object,
required: true,
validator: graphDataValidatorForValues.bind(null, false),
},
},
data() {
return {
width: 0,
height: chartHeight,
svgs: {},
};
},
computed: {
chartData() {
return this.graphData.metrics.map(metric => metric.result[0].values.map(val => val[1]));
},
xAxisTitle() {
return this.graphData.x_label !== undefined ? this.graphData.x_label : '';
},
yAxisTitle() {
return this.graphData.y_label !== undefined ? this.graphData.y_label : '';
},
xAxisType() {
return this.graphData.x_type !== undefined ? this.graphData.x_type : 'category';
},
groupBy() {
return this.graphData.metrics[0].result[0].values.map(val => val[0]);
},
dataZoomConfig() {
const handleIcon = this.svgs['scroll-handle'];
return handleIcon ? { handleIcon } : {};
},
chartOptions() {
return {
dataZoom: this.dataZoomConfig,
};
},
seriesNames() {
return this.graphData.metrics.map(metric => metric.series_name);
},
},
created() {
this.setSvg('scroll-handle');
},
methods: {
setSvg(name) {
getSvgIconPathContent(name)
.then(path => {
if (path) {
this.$set(this.svgs, name, `path://${path}`);
}
})
.catch(e => {
// eslint-disable-next-line no-console, @gitlab/i18n/no-non-i18n-strings
console.error('SVG could not be rendered correctly: ', e);
});
},
onResize() {
if (!this.$refs.chart) return;
const { width } = this.$refs.chart.$el.getBoundingClientRect();
this.width = width;
},
},
};
</script>
<template>
<div v-gl-resize-observer-directive="onResize" class="prometheus-graph">
<div class="prometheus-graph-header">
<h5 ref="graphTitle" class="prometheus-graph-title">{{ graphData.title }}</h5>
<div ref="graphWidgets" class="prometheus-graph-widgets"><slot></slot></div>
</div>
<gl-stacked-column-chart
ref="chart"
v-bind="$attrs"
:data="chartData"
:option="chartOptions"
:x-axis-title="xAxisTitle"
:y-axis-title="yAxisTitle"
:x-axis-type="xAxisType"
:group-by="groupBy"
:width="width"
:height="height"
:series-names="seriesNames"
/>
</div>
</template>
......@@ -15,6 +15,7 @@ import MonitorAnomalyChart from './charts/anomaly.vue';
import MonitorSingleStatChart from './charts/single_stat.vue';
import MonitorHeatmapChart from './charts/heatmap.vue';
import MonitorColumnChart from './charts/column.vue';
import MonitorStackedColumnChart from './charts/stacked_column.vue';
import MonitorEmptyChart from './charts/empty_chart.vue';
import TrackEventDirective from '~/vue_shared/directives/track_event';
import { downloadCSVOptions, generateLinkToChartOptions } from '../utils';
......@@ -24,6 +25,7 @@ export default {
MonitorSingleStatChart,
MonitorColumnChart,
MonitorHeatmapChart,
MonitorStackedColumnChart,
MonitorEmptyChart,
Icon,
GlDropdown,
......@@ -121,6 +123,10 @@ export default {
v-else-if="isPanelType('column') && graphDataHasMetrics"
:graph-data="graphData"
/>
<monitor-stacked-column-chart
v-else-if="isPanelType('stacked-column') && graphDataHasMetrics"
:graph-data="graphData"
/>
<component
:is="monitorChartComponent"
v-else-if="graphDataHasMetrics"
......
---
title: Add support for stacked column charts
merge_request: 23474
author:
type: changed
import { shallowMount } from '@vue/test-utils';
import { GlStackedColumnChart } from '@gitlab/ui/dist/charts';
import StackedColumnChart from '~/monitoring/components/charts/stacked_column.vue';
import { stackedColumnMockedData } from '../../mock_data';
jest.mock('~/lib/utils/icon_utils', () => ({
getSvgIconPathContent: jest.fn().mockResolvedValue('mockSvgPathContent'),
}));
describe('Stacked column chart component', () => {
let wrapper;
const glStackedColumnChart = () => wrapper.find(GlStackedColumnChart);
beforeEach(() => {
wrapper = shallowMount(StackedColumnChart, {
propsData: {
graphData: stackedColumnMockedData,
},
});
});
afterEach(() => {
wrapper.destroy();
});
describe('with graphData present', () => {
it('is a Vue instance', () => {
expect(glStackedColumnChart().exists()).toBe(true);
});
it('should contain the same number of elements in the seriesNames computed prop as the graphData metrics prop', () =>
wrapper.vm
.$nextTick()
.then(expect(wrapper.vm.seriesNames).toHaveLength(stackedColumnMockedData.metrics.length)));
it('should contain the same number of elements in the groupBy computed prop as the graphData result prop', () =>
wrapper.vm
.$nextTick()
.then(
expect(wrapper.vm.groupBy).toHaveLength(
stackedColumnMockedData.metrics[0].result[0].values.length,
),
));
});
});
......@@ -665,3 +665,50 @@ export const graphDataPrometheusQueryRangeMultiTrack = {
},
],
};
export const stackedColumnMockedData = {
title: 'memories',
type: 'stacked-column',
x_label: 'x label',
y_label: 'y label',
metrics: [
{
label: 'memory_1024',
unit: 'count',
series_name: 'group 1',
prometheus_endpoint_path:
'/root/autodevops-deploy-6/-/environments/24/prometheus/api/v1/query_range?query=avg%28sum%28container_memory_usage_bytes%7Bcontainer_name%21%3D%22POD%22%2Cpod_name%3D~%22%5E%25%7Bci_environment_slug%7D-%28%5B%5Ec%5D.%2A%7Cc%28%5B%5Ea%5D%7Ca%28%5B%5En%5D%7Cn%28%5B%5Ea%5D%7Ca%28%5B%5Er%5D%7Cr%5B%5Ey%5D%29%29%29%29.%2A%7C%29-%28.%2A%29%22%2Cnamespace%3D%22%25%7Bkube_namespace%7D%22%7D%29+by+%28job%29%29+without+%28job%29+%2F+count%28avg%28container_memory_usage_bytes%7Bcontainer_name%21%3D%22POD%22%2Cpod_name%3D~%22%5E%25%7Bci_environment_slug%7D-%28%5B%5Ec%5D.%2A%7Cc%28%5B%5Ea%5D%7Ca%28%5B%5En%5D%7Cn%28%5B%5Ea%5D%7Ca%28%5B%5Er%5D%7Cr%5B%5Ey%5D%29%29%29%29.%2A%7C%29-%28.%2A%29%22%2Cnamespace%3D%22%25%7Bkube_namespace%7D%22%7D%29+without+%28job%29%29+%2F1024%2F1024',
metric_id: 'undefined_metric_of_ages_1024',
metricId: 'undefined_metric_of_ages_1024',
result: [
{
metric: {},
values: [
['2020-01-30 12:00:00', '5'],
['2020-01-30 12:01:00', '10'],
['2020-01-30 12:02:00', '15'],
],
},
],
},
{
label: 'memory_1000',
unit: 'count',
series_name: 'group 2',
prometheus_endpoint_path:
'/root/autodevops-deploy-6/-/environments/24/prometheus/api/v1/query_range?query=avg%28sum%28container_memory_usage_bytes%7Bcontainer_name%21%3D%22POD%22%2Cpod_name%3D~%22%5E%25%7Bci_environment_slug%7D-%28%5B%5Ec%5D.%2A%7Cc%28%5B%5Ea%5D%7Ca%28%5B%5En%5D%7Cn%28%5B%5Ea%5D%7Ca%28%5B%5Er%5D%7Cr%5B%5Ey%5D%29%29%29%29.%2A%7C%29-%28.%2A%29%22%2Cnamespace%3D%22%25%7Bkube_namespace%7D%22%7D%29+by+%28job%29%29+without+%28job%29+%2F+count%28avg%28container_memory_usage_bytes%7Bcontainer_name%21%3D%22POD%22%2Cpod_name%3D~%22%5E%25%7Bci_environment_slug%7D-%28%5B%5Ec%5D.%2A%7Cc%28%5B%5Ea%5D%7Ca%28%5B%5En%5D%7Cn%28%5B%5Ea%5D%7Ca%28%5B%5Er%5D%7Cr%5B%5Ey%5D%29%29%29%29.%2A%7C%29-%28.%2A%29%22%2Cnamespace%3D%22%25%7Bkube_namespace%7D%22%7D%29+without+%28job%29%29+%2F1024%2F1024',
metric_id: 'undefined_metric_of_ages_1000',
metricId: 'undefined_metric_of_ages_1000',
result: [
{
metric: {},
values: [
['2020-01-30 12:00:00', '20'],
['2020-01-30 12:01:00', '25'],
['2020-01-30 12:02:00', '30'],
],
},
],
},
],
};
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