Commit d1d4d589 authored by Mark Florian's avatar Mark Florian

Merge branch '219210-stacked-column-date-format' into 'master'

Add timezone format to the stacked column chart

See merge request gitlab-org/gitlab!33814
parents 2c45f6ed b1fcfb11
......@@ -21,6 +21,21 @@ const chartGridLeft = 75;
// Axis options
/**
* Axis types
* @see https://echarts.apache.org/en/option.html#xAxis.type
*/
export const axisTypes = {
/**
* Category axis, suitable for discrete category data.
*/
category: 'category',
/**
* Time axis, suitable for continuous time series data.
*/
time: 'time',
};
/**
* Converts .yml parameters to echarts axis options for data axis
* @param {Object} param - Dashboard .yml definition options
......@@ -61,7 +76,7 @@ export const getYAxisOptions = ({
export const getTimeAxisOptions = ({ timezone = timezones.LOCAL } = {}) => ({
name: __('Time'),
type: 'time',
type: axisTypes.time,
axisLabel: {
formatter: date => formatDate(date, { format: formats.shortTime, timezone }),
},
......
......@@ -4,6 +4,8 @@ import { GlStackedColumnChart } from '@gitlab/ui/dist/charts';
import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
import { chartHeight } from '../../constants';
import { graphDataValidatorForValues } from '../../utils';
import { getTimeAxisOptions, axisTypes } from './options';
import { timezones } from '../../format_date';
export default {
components: {
......@@ -18,6 +20,11 @@ export default {
required: true,
validator: graphDataValidatorForValues.bind(null, false),
},
timezone: {
type: String,
required: false,
default: timezones.LOCAL,
},
},
data() {
return {
......@@ -28,7 +35,14 @@ export default {
},
computed: {
chartData() {
return this.graphData.metrics.map(metric => metric.result[0].values.map(val => val[1]));
return this.graphData.metrics.map(({ result }) => {
// This needs a fix. Not only metrics[0] should be shown.
// See https://gitlab.com/gitlab-org/gitlab/-/issues/220492
if (!result || result.length === 0) {
return [];
}
return result[0].values.map(val => val[1]);
});
},
xAxisTitle() {
return this.graphData.x_label !== undefined ? this.graphData.x_label : '';
......@@ -37,10 +51,17 @@ export default {
return this.graphData.y_label !== undefined ? this.graphData.y_label : '';
},
xAxisType() {
return this.graphData.x_type !== undefined ? this.graphData.x_type : 'category';
// stacked-column component requires the x-axis to be of type `category`
return axisTypes.category;
},
groupBy() {
return this.graphData.metrics[0].result[0].values.map(val => val[0]);
// This needs a fix. Not only metrics[0] should be shown.
// See https://gitlab.com/gitlab-org/gitlab/-/issues/220492
const { result } = this.graphData.metrics[0];
if (!result || result.length === 0) {
return [];
}
return result[0].values.map(val => val[0]);
},
dataZoomConfig() {
const handleIcon = this.svgs['scroll-handle'];
......@@ -49,11 +70,15 @@ export default {
},
chartOptions() {
return {
dataZoom: this.dataZoomConfig,
xAxis: {
...getTimeAxisOptions({ timezone: this.timezone }),
type: this.xAxisType,
},
dataZoom: [this.dataZoomConfig],
};
},
seriesNames() {
return this.graphData.metrics.map(metric => metric.series_name);
return this.graphData.metrics.map(metric => metric.label);
},
},
created() {
......
---
title: Add date time format to the monitor stacked-column chart
merge_request: 33814
author:
type: changed
import { shallowMount } from '@vue/test-utils';
import timezoneMock from 'timezone-mock';
import { cloneDeep } from 'lodash';
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'),
getSvgIconPathContent: jest.fn().mockImplementation(icon => Promise.resolve(`${icon}-content`)),
}));
describe('Stacked column chart component', () => {
let wrapper;
const glStackedColumnChart = () => wrapper.find(GlStackedColumnChart);
const findChart = () => wrapper.find(GlStackedColumnChart);
beforeEach(() => {
const createWrapper = (props = {}) => {
wrapper = shallowMount(StackedColumnChart, {
propsData: {
graphData: stackedColumnMockedData,
...props,
},
});
});
};
afterEach(() => {
wrapper.destroy();
});
describe('when graphData is present', () => {
beforeEach(() => {
createWrapper();
return wrapper.vm.$nextTick();
});
it('chart is rendered', () => {
expect(findChart().exists()).toBe(true);
});
it('data should match the graphData y value for each series', () => {
const data = findChart().props('data');
data.forEach((series, index) => {
const { values } = stackedColumnMockedData.metrics[index].result[0];
expect(series).toEqual(values.map(value => value[1]));
});
});
it('series names should be the same as the graphData metrics labels', () => {
const seriesNames = findChart().props('seriesNames');
expect(seriesNames).toHaveLength(stackedColumnMockedData.metrics.length);
seriesNames.forEach((name, index) => {
expect(stackedColumnMockedData.metrics[index].label).toBe(name);
});
});
it('group by should be the same as the graphData first metric results', () => {
const groupBy = findChart().props('groupBy');
expect(groupBy).toEqual([
'2020-01-30T12:00:00.000Z',
'2020-01-30T12:01:00.000Z',
'2020-01-30T12:02:00.000Z',
]);
});
it('chart options should configure data zoom and axis label ', () => {
const chartOptions = findChart().props('option');
const xAxisType = findChart().props('xAxisType');
expect(chartOptions).toMatchObject({
dataZoom: [{ handleIcon: 'path://scroll-handle-content' }],
xAxis: {
axisLabel: { formatter: expect.any(Function) },
},
});
describe('with graphData present', () => {
it('is a Vue instance', () => {
expect(glStackedColumnChart().exists()).toBe(true);
expect(xAxisType).toBe('category');
});
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('chart options should configure category as x axis type', () => {
const chartOptions = findChart().props('option');
const xAxisType = findChart().props('xAxisType');
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,
),
));
expect(chartOptions).toMatchObject({
xAxis: {
type: 'category',
},
});
expect(xAxisType).toBe('category');
});
it('format date is correct', () => {
const { xAxis } = findChart().props('option');
expect(xAxis.axisLabel.formatter('2020-01-30T12:01:00.000Z')).toBe('12:01 PM');
});
describe('when in PT timezone', () => {
beforeAll(() => {
timezoneMock.register('US/Pacific');
});
afterAll(() => {
timezoneMock.unregister();
});
it('date is shown in local time', () => {
const { xAxis } = findChart().props('option');
expect(xAxis.axisLabel.formatter('2020-01-30T12:01:00.000Z')).toBe('4:01 AM');
});
it('date is shown in UTC', () => {
wrapper.setProps({ timezone: 'UTC' });
return wrapper.vm.$nextTick().then(() => {
const { xAxis } = findChart().props('option');
expect(xAxis.axisLabel.formatter('2020-01-30T12:01:00.000Z')).toBe('12:01 PM');
});
});
});
});
describe('when graphData has results missing', () => {
beforeEach(() => {
const graphData = cloneDeep(stackedColumnMockedData);
graphData.metrics[0].result = null;
createWrapper({ graphData });
return wrapper.vm.$nextTick();
});
it('chart is rendered', () => {
expect(findChart().exists()).toBe(true);
});
});
});
......@@ -467,9 +467,9 @@ export const stackedColumnMockedData = {
{
metric: {},
values: [
['2020-01-30 12:00:00', '5'],
['2020-01-30 12:01:00', '10'],
['2020-01-30 12:02:00', '15'],
['2020-01-30T12:00:00.000Z', '5'],
['2020-01-30T12:01:00.000Z', '10'],
['2020-01-30T12:02:00.000Z', '15'],
],
},
],
......@@ -485,9 +485,9 @@ export const stackedColumnMockedData = {
{
metric: {},
values: [
['2020-01-30 12:00:00', '20'],
['2020-01-30 12:01:00', '25'],
['2020-01-30 12:02:00', '30'],
['2020-01-30T12:00:00.000Z', '20'],
['2020-01-30T12:01:00.000Z', '25'],
['2020-01-30T12:02:00.000Z', '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