Commit c3fbb88d authored by Martin Wortschack's avatar Martin Wortschack Committed by Filipa Lacerda

Update axis label on scatterplot on metric change

- Updates the y axis label for the scatterplot when
the user changes the metric
parent 3f777766
...@@ -61,8 +61,9 @@ export default { ...@@ -61,8 +61,9 @@ export default {
'getColumnChartDatazoomOption', 'getColumnChartDatazoomOption',
'getScatterPlotMainData', 'getScatterPlotMainData',
'getScatterPlotMedianData', 'getScatterPlotMedianData',
'getMetricDropdownLabel', 'getMetricLabel',
'getSelectedMetric', 'getSelectedMetric',
'scatterplotYaxisLabel',
'hasNoAccessError', 'hasNoAccessError',
]), ]),
...mapGetters('table', [ ...mapGetters('table', [
...@@ -216,7 +217,7 @@ export default { ...@@ -216,7 +217,7 @@ export default {
:data="{ full: getColumnChartData(chartKeys.commitBasedHistogram) }" :data="{ full: getColumnChartData(chartKeys.commitBasedHistogram) }"
:option="getColumnChartOption(chartKeys.commitBasedHistogram)" :option="getColumnChartOption(chartKeys.commitBasedHistogram)"
:y-axis-title="s__('ProductivityAanalytics|Merge requests')" :y-axis-title="s__('ProductivityAanalytics|Merge requests')"
:x-axis-title="getMetricDropdownLabel(chartKeys.commitBasedHistogram)" :x-axis-title="getMetricLabel(chartKeys.commitBasedHistogram)"
x-axis-type="category" x-axis-type="category"
/> />
</metric-chart> </metric-chart>
...@@ -236,7 +237,7 @@ export default { ...@@ -236,7 +237,7 @@ export default {
> >
<scatterplot <scatterplot
:x-axis-title="s__('ProductivityAnalytics|Merge date')" :x-axis-title="s__('ProductivityAnalytics|Merge date')"
:y-axis-title="s__('ProductivityAnalytics|Days')" :y-axis-title="scatterplotYaxisLabel"
:scatter-data="getScatterPlotMainData" :scatter-data="getScatterPlotMainData"
:median-line-data="getScatterPlotMedianData" :median-line-data="getScatterPlotMedianData"
/> />
......
import _ from 'underscore'; import _ from 'underscore';
import { s__ } from '~/locale';
import httpStatus from '~/lib/utils/http_status'; import httpStatus from '~/lib/utils/http_status';
import { getDateInPast } from '~/lib/utils/datetime_utility'; import { getDateInPast } from '~/lib/utils/datetime_utility';
import { import {
...@@ -9,6 +10,7 @@ import { ...@@ -9,6 +10,7 @@ import {
maxColumnChartItemsPerPage, maxColumnChartItemsPerPage,
dataZoomOptions, dataZoomOptions,
scatterPlotAddonQueryDays, scatterPlotAddonQueryDays,
daysToMergeMetric,
} from '../../../constants'; } from '../../../constants';
import { getScatterPlotData, getMedianLineData } from '../../../utils'; import { getScatterPlotData, getMedianLineData } from '../../../utils';
...@@ -91,7 +93,7 @@ export const getScatterPlotMedianData = (state, getters) => ...@@ -91,7 +93,7 @@ export const getScatterPlotMedianData = (state, getters) =>
scatterPlotAddonQueryDays, scatterPlotAddonQueryDays,
); );
export const getMetricDropdownLabel = state => chartKey => export const getMetricLabel = state => chartKey =>
metricTypes.find(m => m.key === state.charts[chartKey].params.metricType).label; metricTypes.find(m => m.key === state.charts[chartKey].params.metricType).label;
export const getFilterParams = (state, getters, rootState, rootGetters) => chartKey => { export const getFilterParams = (state, getters, rootState, rootGetters) => chartKey => {
...@@ -150,6 +152,20 @@ export const getColumnChartDatazoomOption = state => chartKey => { ...@@ -150,6 +152,20 @@ export const getColumnChartDatazoomOption = state => chartKey => {
export const getSelectedMetric = state => chartKey => state.charts[chartKey].params.metricType; export const getSelectedMetric = state => chartKey => state.charts[chartKey].params.metricType;
/**
* Returns the y axis label for the scatterplot.
* This can either be "Days", "Hours" or some other metric label from the state's metricTypes.
*/
export const scatterplotYaxisLabel = (_state, getters, rootState) => {
const selectedMetric = getters.getSelectedMetric(chartKeys.scatterplot);
const metricTypesInHours = rootState.metricTypes
.filter(metric => metric.charts.indexOf(chartKeys.timeBasedHistogram) !== -1)
.map(metric => metric.key);
if (selectedMetric === daysToMergeMetric.key) return s__('ProductivityAnalytics|Days');
if (metricTypesInHours.indexOf(selectedMetric) !== -1) return s__('ProductivityAnalytics|Hours');
return getters.getMetricLabel(chartKeys.scatterplot);
};
export const hasNoAccessError = state => export const hasNoAccessError = state =>
state.charts[chartKeys.main].errorCode === httpStatus.FORBIDDEN; state.charts[chartKeys.main].errorCode === httpStatus.FORBIDDEN;
......
...@@ -3,6 +3,7 @@ import Vuex from 'vuex'; ...@@ -3,6 +3,7 @@ import Vuex from 'vuex';
import axios from 'axios'; import axios from 'axios';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import ProductivityApp from 'ee/analytics/productivity_analytics/components/app.vue'; import ProductivityApp from 'ee/analytics/productivity_analytics/components/app.vue';
import Scatterplot from 'ee/analytics/shared/components/scatterplot.vue';
import MergeRequestTable from 'ee/analytics/productivity_analytics/components/mr_table.vue'; import MergeRequestTable from 'ee/analytics/productivity_analytics/components/mr_table.vue';
import store from 'ee/analytics/productivity_analytics/store'; import store from 'ee/analytics/productivity_analytics/store';
import { chartKeys } from 'ee/analytics/productivity_analytics/constants'; import { chartKeys } from 'ee/analytics/productivity_analytics/constants';
...@@ -24,7 +25,6 @@ describe('ProductivityApp component', () => { ...@@ -24,7 +25,6 @@ describe('ProductivityApp component', () => {
}; };
const actionSpies = { const actionSpies = {
setMetricType: jest.fn(),
chartItemClicked: jest.fn(), chartItemClicked: jest.fn(),
setSortField: jest.fn(), setSortField: jest.fn(),
setMergeRequestsPage: jest.fn(), setMergeRequestsPage: jest.fn(),
...@@ -192,12 +192,17 @@ describe('ProductivityApp component', () => { ...@@ -192,12 +192,17 @@ describe('ProductivityApp component', () => {
expect(findTimeBasedMetricChart().props('chartData')).not.toEqual([]); expect(findTimeBasedMetricChart().props('chartData')).not.toEqual([]);
}); });
it('should call setMetricType when `metricTypeChange` is emitted on the metric chart', () => { describe('when the user changes the metric', () => {
findTimeBasedMetricChart().vm.$emit('metricTypeChange', 'time_to_merge'); beforeEach(() => {
jest.spyOn(store, 'dispatch');
findTimeBasedMetricChart().vm.$emit('metricTypeChange', 'time_to_merge');
});
expect(actionSpies.setMetricType).toHaveBeenCalledWith({ it('should call setMetricType when `metricTypeChange` is emitted on the metric chart', () => {
metricType: 'time_to_merge', expect(store.dispatch).toHaveBeenCalledWith('charts/setMetricType', {
chartKey: chartKeys.timeBasedHistogram, metricType: 'time_to_merge',
chartKey: chartKeys.timeBasedHistogram,
});
}); });
}); });
}); });
...@@ -228,11 +233,12 @@ describe('ProductivityApp component', () => { ...@@ -228,11 +233,12 @@ describe('ProductivityApp component', () => {
describe('when the user changes the metric', () => { describe('when the user changes the metric', () => {
beforeEach(() => { beforeEach(() => {
jest.spyOn(store, 'dispatch');
findCommitBasedMetricChart().vm.$emit('metricTypeChange', 'loc_per_commit'); findCommitBasedMetricChart().vm.$emit('metricTypeChange', 'loc_per_commit');
}); });
it('should call setMetricType when `metricTypeChange` is emitted on the metric chart', () => { it('should call setMetricType when `metricTypeChange` is emitted on the metric chart', () => {
expect(actionSpies.setMetricType).toHaveBeenCalledWith({ expect(store.dispatch).toHaveBeenCalledWith('charts/setMetricType', {
metricType: 'loc_per_commit', metricType: 'loc_per_commit',
chartKey: chartKeys.commitBasedHistogram, chartKey: chartKeys.commitBasedHistogram,
}); });
...@@ -240,7 +246,7 @@ describe('ProductivityApp component', () => { ...@@ -240,7 +246,7 @@ describe('ProductivityApp component', () => {
it("should update the chart's x axis label", () => { it("should update the chart's x axis label", () => {
const columnChart = findCommitBasedMetricChart().find(GlColumnChart); const columnChart = findCommitBasedMetricChart().find(GlColumnChart);
expect(columnChart.props('xAxisTitle')).toBe('Number of commits per MR'); expect(columnChart.props('xAxisTitle')).toBe('Number of LOCs per commit');
}); });
}); });
}); });
...@@ -274,15 +280,21 @@ describe('ProductivityApp component', () => { ...@@ -274,15 +280,21 @@ describe('ProductivityApp component', () => {
describe('when the user changes the metric', () => { describe('when the user changes the metric', () => {
beforeEach(() => { beforeEach(() => {
jest.spyOn(store, 'dispatch');
findScatterplotMetricChart().vm.$emit('metricTypeChange', 'loc_per_commit'); findScatterplotMetricChart().vm.$emit('metricTypeChange', 'loc_per_commit');
}); });
it('should call setMetricType when `metricTypeChange` is emitted on the metric chart', () => { it('should call setMetricType when `metricTypeChange` is emitted on the metric chart', () => {
expect(actionSpies.setMetricType).toHaveBeenCalledWith({ expect(store.dispatch).toHaveBeenCalledWith('charts/setMetricType', {
metricType: 'loc_per_commit', metricType: 'loc_per_commit',
chartKey: chartKeys.scatterplot, chartKey: chartKeys.scatterplot,
}); });
}); });
it("should update the chart's y axis label", () => {
const scatterplot = findScatterplotMetricChart().find(Scatterplot);
expect(scatterplot.props('yAxisTitle')).toBe('Number of LOCs per commit');
});
}); });
}); });
}); });
......
import createState from 'ee/analytics/productivity_analytics/store/modules/charts/state'; import createState from 'ee/analytics/productivity_analytics/store/modules/charts/state';
import * as getters from 'ee/analytics/productivity_analytics/store/modules/charts/getters'; import * as getters from 'ee/analytics/productivity_analytics/store/modules/charts/getters';
import { import {
metricTypes,
chartKeys, chartKeys,
columnHighlightStyle, columnHighlightStyle,
maxColumnChartItemsPerPage, maxColumnChartItemsPerPage,
...@@ -91,13 +92,13 @@ describe('Productivity analytics chart getters', () => { ...@@ -91,13 +92,13 @@ describe('Productivity analytics chart getters', () => {
}); });
}); });
describe('getMetricDropdownLabel', () => { describe('getMetricLabel', () => {
it('returns the correct label for the "time_to_last_commit" metric', () => { it('returns the correct label for the "time_to_last_commit" metric', () => {
state.charts[chartKeys.timeBasedHistogram].params = { state.charts[chartKeys.timeBasedHistogram].params = {
metricType: 'time_to_last_commit', metricType: 'time_to_last_commit',
}; };
expect(getters.getMetricDropdownLabel(state)(chartKeys.timeBasedHistogram)).toBe( expect(getters.getMetricLabel(state)(chartKeys.timeBasedHistogram)).toBe(
'Time from first comment to last commit', 'Time from first comment to last commit',
); );
}); });
...@@ -233,6 +234,44 @@ describe('Productivity analytics chart getters', () => { ...@@ -233,6 +234,44 @@ describe('Productivity analytics chart getters', () => {
}); });
}); });
describe('scatterplotYaxisLabel', () => {
const metricsInHours = ['time_to_first_comment', 'time_to_last_commit', 'time_to_merge'];
const mockRootState = {
metricTypes,
};
it('returns "Days" for "days_to_merge" metric', () => {
const mockGetters = {
getSelectedMetric: () => 'days_to_merge',
};
expect(getters.scatterplotYaxisLabel(null, mockGetters, mockRootState)).toBe('Days');
});
it.each(metricsInHours)('returns "Hours" for the "%s" metric', metric => {
const mockGetters = {
getSelectedMetric: () => metric,
};
expect(getters.scatterplotYaxisLabel(null, mockGetters, mockRootState)).toBe('Hours');
});
it.each`
metric | label
${'commits_count'} | ${'Number of commits per MR'}
${'loc_per_commit'} | ${'Number of LOCs per commit'}
${'files_touched'} | ${'Number of files touched'}
`('calls getMetricLabel for the "$metric" metric', ({ metric }) => {
const mockGetters = {
getSelectedMetric: () => metric,
getMetricLabel: jest.fn(),
};
getters.scatterplotYaxisLabel(null, mockGetters, mockRootState);
expect(mockGetters.getMetricLabel).toHaveBeenCalled();
});
});
describe('hasNoAccessError', () => { describe('hasNoAccessError', () => {
it('returns true if errorCode is set to 403', () => { it('returns true if errorCode is set to 403', () => {
state.charts[chartKeys.main].errorCode = 403; state.charts[chartKeys.main].errorCode = 403;
......
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