Commit 2f5995f5 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo Committed by Jose Ivan Vargas

Update tasks by type stacked column data

Updates the stacked column chart data
for the tasks by type chart
parent 81e87cd5
......@@ -17,10 +17,13 @@ export default {
},
},
computed: {
seriesData() {
return {
full: this.formattedData.keys.map((val, idx) => [val, this.formattedData.values[idx]]),
};
barSeriesData() {
return [
{
name: 'full',
data: this.formattedData.keys.map((val, idx) => [val, this.formattedData.values[idx]]),
},
];
},
},
};
......@@ -30,7 +33,7 @@ export default {
<div class="gl-xs-w-full">
<gl-column-chart
v-if="formattedData.keys"
:data="seriesData"
:bars="barSeriesData"
:x-axis-title="__('Value')"
:y-axis-title="__('Number of events')"
:x-axis-type="'category'"
......
......@@ -35,18 +35,14 @@ export default {
};
},
computed: {
chartData() {
const queryData = this.graphData.metrics.reduce((acc, query) => {
barChartData() {
return this.graphData.metrics.reduce((acc, query) => {
const series = makeDataSeries(query.result || [], {
name: this.formatLegendLabel(query),
});
return acc.concat(series);
}, []);
return {
values: queryData[0].data,
};
},
chartOptions() {
const xAxis = getTimeAxisOptions({ timezone: this.timezone });
......@@ -109,7 +105,7 @@ export default {
<gl-column-chart
ref="columnChart"
v-bind="$attrs"
:data="chartData"
:bars="barChartData"
:option="chartOptions"
:width="width"
:height="height"
......
......@@ -61,14 +61,16 @@ export default {
},
computed: {
chartData() {
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]);
});
return this.graphData.metrics
.map(({ label: name, 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 { name, data: result[0].values.map(val => val[1]) };
})
.slice(0, 1);
},
xAxisTitle() {
return this.graphData.x_label !== undefined ? this.graphData.x_label : '';
......@@ -136,7 +138,7 @@ export default {
<gl-stacked-column-chart
ref="chart"
v-bind="$attrs"
:data="chartData"
:bars="chartData"
:option="chartOptions"
:x-axis-title="xAxisTitle"
:y-axis-title="yAxisTitle"
......@@ -144,7 +146,6 @@ export default {
:group-by="groupBy"
:width="width"
:height="height"
:series-names="seriesNames"
:legend-layout="legendLayout"
:legend-average-text="legendAverageText"
:legend-current-text="legendCurrentText"
......
......@@ -5,6 +5,8 @@ import { __ } from '~/locale';
import CodeCoverage from '../components/code_coverage.vue';
import SeriesDataMixin from './series_data_mixin';
const seriesDataToBarData = raw => Object.entries(raw).map(([name, data]) => ({ name, data }));
document.addEventListener('DOMContentLoaded', () => {
waitForCSSLoaded(() => {
const languagesContainer = document.getElementById('js-languages-chart');
......@@ -41,13 +43,13 @@ document.addEventListener('DOMContentLoaded', () => {
},
computed: {
seriesData() {
return { full: this.chartData.map(d => [d.label, d.value]) };
return [{ name: 'full', data: this.chartData.map(d => [d.label, d.value]) }];
},
},
render(h) {
return h(GlColumnChart, {
props: {
data: this.seriesData,
bars: this.seriesData,
xAxisTitle: __('Used programming language'),
yAxisTitle: __('Percentage'),
xAxisType: 'category',
......@@ -86,7 +88,7 @@ document.addEventListener('DOMContentLoaded', () => {
render(h) {
return h(GlColumnChart, {
props: {
data: this.seriesData,
bars: seriesDataToBarData(this.seriesData),
xAxisTitle: __('Day of month'),
yAxisTitle: __('No. of commits'),
xAxisType: 'category',
......@@ -113,13 +115,13 @@ document.addEventListener('DOMContentLoaded', () => {
acc.push([key, weekDays[key]]);
return acc;
}, []);
return { full: data };
return [{ name: 'full', data }];
},
},
render(h) {
return h(GlColumnChart, {
props: {
data: this.seriesData,
bars: this.seriesData,
xAxisTitle: __('Weekday'),
yAxisTitle: __('No. of commits'),
xAxisType: 'category',
......@@ -143,7 +145,7 @@ document.addEventListener('DOMContentLoaded', () => {
render(h) {
return h(GlColumnChart, {
props: {
data: this.seriesData,
bars: seriesDataToBarData(this.seriesData),
xAxisTitle: __('Hour (UTC)'),
yAxisTitle: __('No. of commits'),
xAxisType: 'category',
......
......@@ -45,9 +45,12 @@ export default {
},
data() {
return {
timesChartTransformedData: {
full: this.mergeLabelsAndValues(this.timesChartData.labels, this.timesChartData.values),
},
timesChartTransformedData: [
{
name: 'full',
data: this.mergeLabelsAndValues(this.timesChartData.labels, this.timesChartData.values),
},
],
};
},
computed: {
......@@ -128,7 +131,7 @@ export default {
<gl-column-chart
:height="$options.chartContainerHeight"
:option="$options.timesChartOptions"
:data="timesChartTransformedData"
:bars="timesChartTransformedData"
:y-axis-title="__('Minutes')"
:x-axis-title="__('Commit')"
x-axis-type="category"
......
......@@ -65,7 +65,7 @@ export default {
};
},
seriesData() {
return { full: this.chartData };
return [{ name: 'full', data: this.chartData }];
},
},
methods: {
......@@ -102,7 +102,7 @@ export default {
v-bind="$attrs"
:width="width"
:height="height"
:data="seriesData"
:bars="seriesData"
:x-axis-title="xAxisTitle"
:y-axis-title="yAxisTitle"
x-axis-type="category"
......
......@@ -15,21 +15,16 @@ export default {
type: Array,
required: true,
},
seriesNames: {
type: Array,
required: true,
},
},
};
</script>
<template>
<gl-stacked-column-chart
:data="data"
:bars="data"
:group-by="groupBy"
x-axis-type="category"
y-axis-type="value"
:x-axis-title="__('Date')"
:y-axis-title="s__('CycleAnalytics|Number of tasks')"
:series-names="seriesNames"
/>
</template>
......@@ -87,7 +87,6 @@ export default {
v-if="hasData"
:data="tasksByTypeChartData.data"
:group-by="tasksByTypeChartData.groupBy"
:series-names="tasksByTypeChartData.seriesNames"
/>
<gl-alert v-else variant="info" :dismissible="false" class="gl-mt-3">
{{ error }}
......
......@@ -21,5 +21,5 @@ export const tasksByTypeChartData = ({ data = [] } = {}, _, rootState = {}) => {
startDate,
endDate,
})
: { groupBy: [], data: [], seriesNames: [] };
: { groupBy: [], data: [] };
};
......@@ -253,7 +253,6 @@ export const getTasksByTypeData = ({ data = [], startDate = null, endDate = null
return {
groupBy: [],
data: [],
seriesNames: [],
};
}
......@@ -269,14 +268,19 @@ export const getTasksByTypeData = ({ data = [], startDate = null, endDate = null
const transformed = data.reduce(
(acc, curr) => {
const {
label: { title },
label: { title: name },
series,
} = curr;
acc.seriesNames = [...acc.seriesNames, title];
acc.data = [
...acc.data,
// adds 0 values for each data point and overrides with data from the series
flattenTaskByTypeSeries({ ...zeroValuesForEachDataPoint, ...Object.fromEntries(series) }),
{
name,
// adds 0 values for each data point and overrides with data from the series
data: flattenTaskByTypeSeries({
...zeroValuesForEachDataPoint,
...Object.fromEntries(series),
}),
},
];
return acc;
},
......
......@@ -206,7 +206,7 @@ export default {
:chart-data="getColumnChartData(chartKeys.main)"
>
<gl-column-chart
:data="{ full: getColumnChartData(chartKeys.main) }"
:bars="[{ name: 'full', data: getColumnChartData(chartKeys.main) }]"
:option="getColumnChartOption(chartKeys.main)"
:y-axis-title="__('Merge requests')"
:x-axis-title="__('Days')"
......@@ -257,7 +257,7 @@ export default {
"
>
<gl-column-chart
:data="{ full: getColumnChartData(chartKeys.timeBasedHistogram) }"
:bars="[{ name: 'full', data: getColumnChartData(chartKeys.timeBasedHistogram) }]"
:option="getColumnChartOption(chartKeys.timeBasedHistogram)"
:y-axis-title="s__('ProductivityAnalytics|Merge requests')"
:x-axis-title="s__('ProductivityAnalytics|Hours')"
......@@ -283,7 +283,7 @@ export default {
"
>
<gl-column-chart
:data="{ full: getColumnChartData(chartKeys.commitBasedHistogram) }"
:bars="[{ name: 'full', data: getColumnChartData(chartKeys.commitBasedHistogram) }]"
:option="getColumnChartOption(chartKeys.commitBasedHistogram)"
:y-axis-title="s__('ProductivityAanalytics|Merge requests')"
:x-axis-title="getMetricLabel(chartKeys.commitBasedHistogram)"
......
......@@ -134,7 +134,7 @@ export default {
v-if="loaded && isColumnChart"
v-bind="$attrs"
:height="$options.height"
:data="data.datasets"
:bars="data.datasets"
x-axis-type="category"
:x-axis-title="data.xAxisTitle"
:y-axis-title="data.yAxisTitle"
......@@ -145,9 +145,8 @@ export default {
v-else-if="loaded && isStackedColumnChart"
v-bind="$attrs"
:height="$options.height"
:data="data.datasets"
:bars="data.datasets"
:group-by="data.labels"
:series-names="data.seriesNames"
x-axis-type="category"
:x-axis-title="data.xAxisTitle"
:y-axis-title="data.yAxisTitle"
......
......@@ -31,10 +31,21 @@ export const transformChartDataForGlCharts = (
};
switch (type) {
case CHART_TYPES.BAR:
formattedData.datasets = [
{
name: 'all',
data: labels.map((label, i) => [label, datasets[0].data[i]]),
},
];
break;
case CHART_TYPES.STACKED_BAR:
formattedData.datasets = datasets.map(dataset => dataset.data);
formattedData.seriesNames = datasets.map(dataset => dataset.label);
formattedData.datasets.push(
...datasets.map(dataset => ({
name: dataset.label,
data: dataset.data,
})),
);
break;
case CHART_TYPES.LINE:
formattedData.datasets.push(
......@@ -48,7 +59,6 @@ export const transformChartDataForGlCharts = (
default:
formattedData.datasets = { all: labels.map((label, i) => [label, datasets[0].data[i]]) };
}
return formattedData;
};
......
......@@ -182,7 +182,7 @@ export default {
<gl-column-chart
data-qa-selector="issues_analytics_graph"
:data="{ Full: data }"
:bars="[{ name: 'Full', data }]"
:option="chartOptions"
:y-axis-title="s__('IssuesAnalytics|Issues opened')"
:x-axis-title="s__('IssuesAnalytics|Last 12 months') + ' (' + chartDateRange + ')'"
......
......@@ -3,7 +3,7 @@
exports[`Contribution Analytics Column Chart matches the snapshot 1`] = `
<div>
<gl-column-chart-stub
bars=""
bars="[object Object]"
data="[object Object]"
height="350"
lines=""
......
......@@ -2,4 +2,4 @@
exports[`TasksByTypeChart no data available should render the no data available message 1`] = `"<gl-stacked-column-chart-stub data=\\"\\" bars=\\"\\" lines=\\"\\" secondarydata=\\"\\" option=\\"[object Object]\\" presentation=\\"stacked\\" groupby=\\"\\" xaxistype=\\"category\\" xaxistitle=\\"Date\\" yaxistitle=\\"Number of tasks\\" secondarydatatitle=\\"\\" seriesnames=\\"\\" legendaveragetext=\\"Avg\\" legendmaxtext=\\"Max\\" legendmintext=\\"Min\\" legendcurrenttext=\\"Current\\" legendlayout=\\"inline\\" y-axis-type=\\"value\\"></gl-stacked-column-chart-stub>"`;
exports[`TasksByTypeChart with data available should render the loading chart 1`] = `"<gl-stacked-column-chart-stub data=\\"0,1,2,5,2,3,2,4,1\\" bars=\\"\\" lines=\\"\\" secondarydata=\\"\\" option=\\"[object Object]\\" presentation=\\"stacked\\" groupby=\\"Group 1,Group 2,Group 3\\" xaxistype=\\"category\\" xaxistitle=\\"Date\\" yaxistitle=\\"Number of tasks\\" secondarydatatitle=\\"\\" seriesnames=\\"Cool label,Normal label\\" legendaveragetext=\\"Avg\\" legendmaxtext=\\"Max\\" legendmintext=\\"Min\\" legendcurrenttext=\\"Current\\" legendlayout=\\"inline\\" y-axis-type=\\"value\\"></gl-stacked-column-chart-stub>"`;
exports[`TasksByTypeChart with data available should render the loading chart 1`] = `"<gl-stacked-column-chart-stub data=\\"\\" bars=\\"0,1,2,5,2,3,2,4,1\\" lines=\\"\\" secondarydata=\\"\\" option=\\"[object Object]\\" presentation=\\"stacked\\" groupby=\\"Group 1,Group 2,Group 3\\" xaxistype=\\"category\\" xaxistitle=\\"Date\\" yaxistitle=\\"Number of tasks\\" secondarydatatitle=\\"\\" seriesnames=\\"Cool label,Normal label\\" legendaveragetext=\\"Avg\\" legendmaxtext=\\"Max\\" legendmintext=\\"Min\\" legendcurrenttext=\\"Current\\" legendlayout=\\"inline\\" y-axis-type=\\"value\\"></gl-stacked-column-chart-stub>"`;
......@@ -83,7 +83,7 @@ describe('TypeOfWorkCharts', () => {
beforeEach(() => {
wrapper = createComponent({
initialGetters: {
tasksByTypeChartData: () => ({ groupBy: [], data: [], seriesNames: [] }),
tasksByTypeChartData: () => ({ groupBy: [], data: [] }),
},
});
});
......
......@@ -19,7 +19,7 @@ describe('Type of work getters', () => {
describe('with no data', () => {
it('returns all required properties', () => {
expect(tasksByTypeChartData()).toEqual({ groupBy: [], data: [], seriesNames: [] });
expect(tasksByTypeChartData()).toEqual({ groupBy: [], data: [] });
});
});
});
......
......@@ -227,10 +227,15 @@ describe('Cycle analytics utils', () => {
describe('getTasksByTypeData', () => {
let transformed = {};
const groupBy = getDatesInRange(startDate, endDate, toYmd);
// only return the values, drop the date which is the first paramater
const extractSeriesValues = ({ series }) => series.map(kv => kv[1]);
const extractSeriesValues = ({ label: { title: name }, series }) => {
return {
name,
data: series.map(kv => kv[1]),
};
};
const data = rawTasksByTypeData.map(extractSeriesValues);
const labels = rawTasksByTypeData.map(d => {
......@@ -241,7 +246,7 @@ describe('Cycle analytics utils', () => {
it('will return blank arrays if given no data', () => {
[{ data: [], startDate, endDate }, [], {}].forEach(chartData => {
transformed = getTasksByTypeData(chartData);
['seriesNames', 'data', 'groupBy'].forEach(key => {
['data', 'groupBy'].forEach(key => {
expect(transformed[key]).toEqual([]);
});
});
......@@ -253,17 +258,11 @@ describe('Cycle analytics utils', () => {
});
it('will return an object with the properties needed for the chart', () => {
['seriesNames', 'data', 'groupBy'].forEach(key => {
['data', 'groupBy'].forEach(key => {
expect(transformed).toHaveProperty(key);
});
});
describe('seriesNames', () => {
it('returns the names of all the labels in the dataset', () => {
expect(transformed.seriesNames).toEqual(labels);
});
});
describe('groupBy', () => {
it('returns the date groupBy as an array', () => {
expect(transformed.groupBy).toEqual(groupBy);
......@@ -289,7 +288,7 @@ describe('Cycle analytics utils', () => {
it('contains a value for each day in the groupBy', () => {
transformed.data.forEach(d => {
expect(d).toHaveLength(transformed.groupBy.length);
expect(d.data).toHaveLength(transformed.groupBy.length);
});
});
});
......
......@@ -12,9 +12,12 @@ export const chartInfo = {
export const barChartData = {
labels: ['January', 'February'],
datasets: {
all: [['January', 1], ['February', 2]],
},
datasets: [
{
name: 'all',
data: [['January', 1], ['February', 2]],
},
],
xAxisTitle: 'Months',
yAxisTitle: 'Issues',
};
......@@ -37,8 +40,16 @@ export const lineChartData = {
export const stackedBarChartData = {
labels: ['January', 'February'],
datasets: [[1, 2], [1, 2]],
seriesNames: ['Series 1', 'Series 2'],
datasets: [
{
name: 'Series 1',
data: [1, 2],
},
{
name: 'Series 2',
data: [1, 2],
},
],
xAxisTitle: 'Months',
yAxisTitle: 'Issues',
};
......
......@@ -39,22 +39,9 @@ describe('Insights helpers', () => {
datasets: [{ label: 'Dataset 1', data: [1] }, { label: 'Dataset 2', data: [2] }],
};
expect(transformChartDataForGlCharts(chart, data).datasets).toEqual([[1], [2]]);
});
it('copies the dataset labels to seriesNames for stacked bar charts', () => {
const chart = {
type: CHART_TYPES.STACKED_BAR,
query: { group_by: 'month', issuable_type: 'issue' },
};
const data = {
labels: ['January', 'February'],
datasets: [{ label: 'Dataset 1', data: [1] }, { label: 'Dataset 2', data: [2] }],
};
expect(transformChartDataForGlCharts(chart, data).seriesNames).toEqual([
'Dataset 1',
'Dataset 2',
expect(transformChartDataForGlCharts(chart, data).datasets).toEqual([
{ name: 'Dataset 1', data: [1] },
{ name: 'Dataset 2', data: [2] },
]);
});
......@@ -74,7 +61,7 @@ describe('Insights helpers', () => {
]);
});
it('creates an object of all containing an array of label / data pairs for bar charts', () => {
it('creates an array of objects containing an array of label / data pairs and a name for bar charts', () => {
const chart = {
type: CHART_TYPES.BAR,
query: { group_by: 'month', issuable_type: 'issue' },
......@@ -84,9 +71,9 @@ describe('Insights helpers', () => {
datasets: [{ data: [1, 2] }],
};
expect(transformChartDataForGlCharts(chart, data).datasets).toEqual({
all: [['January', 1], ['February', 2]],
});
expect(transformChartDataForGlCharts(chart, data).datasets).toEqual([
{ name: 'all', data: [['January', 1], ['February', 2]] },
]);
});
it('creates an object of all containing an array of label / data pairs for pie charts', () => {
......
......@@ -107,11 +107,11 @@ describe('Insights mutations', () => {
};
const transformedData = {
datasets: [[1], [2]],
datasets: [{ name: 'Dataset 1', data: [1] }, { name: 'Dataset 2', data: [2] }],
labels: ['January', 'February'],
xAxisTitle: 'Months',
yAxisTitle: 'Issues',
seriesNames: ['Dataset 1', 'Dataset 2'],
seriesNames: [],
};
beforeEach(() => {
......
......@@ -30,6 +30,7 @@ describe('Column component', () => {
},
metrics: [
{
label: 'Mock data',
result: [
{
metric: {},
......@@ -96,7 +97,7 @@ describe('Column component', () => {
describe('wrapped components', () => {
describe('GitLab UI column chart', () => {
it('receives data properties needed for proper chart render', () => {
expect(chartProps('data').values).toEqual(dataValues);
expect(chartProps('bars')).toEqual([{ name: 'Mock data', data: dataValues }]);
});
it('passes the y axis name correctly', () => {
......
......@@ -44,19 +44,19 @@ describe('Stacked column chart component', () => {
});
it('data should match the graphData y value for each series', () => {
const data = findChart().props('data');
const data = findChart().props('bars');
data.forEach((series, index) => {
const { values } = stackedColumnMockedData.metrics[index].result[0];
expect(series).toEqual(values.map(value => value[1]));
expect(series.data).toEqual(values.map(value => value[1]));
});
});
it('series names should be the same as the graphData metrics labels', () => {
const seriesNames = findChart().props('seriesNames');
it('data should be the same length as the graphData metrics labels', () => {
const barDataProp = findChart().props('bars');
expect(seriesNames).toHaveLength(stackedColumnMockedData.metrics.length);
seriesNames.forEach((name, index) => {
expect(barDataProp).toHaveLength(stackedColumnMockedData.metrics.length);
barDataProp.forEach(({ name }, index) => {
expect(stackedColumnMockedData.metrics[index].label).toBe(name);
});
});
......
......@@ -45,7 +45,7 @@ describe('ProjectsPipelinesChartsApp', () => {
expect(chart.exists()).toBeTruthy();
expect(chart.props('yAxisTitle')).toBe('Minutes');
expect(chart.props('xAxisTitle')).toBe('Commit');
expect(chart.props('data')).toBe(wrapper.vm.timesChartTransformedData);
expect(chart.props('bars')).toBe(wrapper.vm.timesChartTransformedData);
expect(chart.props('option')).toBe(wrapper.vm.$options.timesChartOptions);
});
});
......
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