Commit afa5bff1 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera

Merge branch '235453-add-visual-error-handling-to-mr-analytics-throughput-chart' into 'master'

Add visual error handling to MR analytics Throughput chart

See merge request gitlab-org/gitlab!39196
parents f2b05afe 772c2675
...@@ -3,7 +3,7 @@ import { GlAreaChart } from '@gitlab/ui/dist/charts'; ...@@ -3,7 +3,7 @@ import { GlAreaChart } from '@gitlab/ui/dist/charts';
import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
import { getDateInPast } from '~/lib/utils/datetime_utility'; import { getDateInPast } from '~/lib/utils/datetime_utility';
import throughputChartQueryBuilder from '../graphql/throughput_chart_query_builder'; import throughputChartQueryBuilder from '../graphql/throughput_chart_query_builder';
import { DEFAULT_NUMBER_OF_DAYS, THROUGHPUT_STRINGS } from '../constants'; import { DEFAULT_NUMBER_OF_DAYS, THROUGHPUT_CHART_STRINGS } from '../constants';
export default { export default {
name: 'ThroughputChart', name: 'ThroughputChart',
...@@ -18,6 +18,7 @@ export default { ...@@ -18,6 +18,7 @@ export default {
throughputChartData: [], throughputChartData: [],
startDate: getDateInPast(new Date(), DEFAULT_NUMBER_OF_DAYS), startDate: getDateInPast(new Date(), DEFAULT_NUMBER_OF_DAYS),
endDate: new Date(), endDate: new Date(),
hasError: false,
}; };
}, },
apollo: { apollo: {
...@@ -30,13 +31,16 @@ export default { ...@@ -30,13 +31,16 @@ export default {
fullPath: this.fullPath, fullPath: this.fullPath,
}; };
}, },
error() {
this.hasError = true;
},
}, },
}, },
computed: { computed: {
chartOptions() { chartOptions() {
return { return {
xAxis: { xAxis: {
name: THROUGHPUT_STRINGS.X_AXIS_TITLE, name: THROUGHPUT_CHART_STRINGS.X_AXIS_TITLE,
type: 'category', type: 'category',
axisLabel: { axisLabel: {
formatter: value => { formatter: value => {
...@@ -45,33 +49,42 @@ export default { ...@@ -45,33 +49,42 @@ export default {
}, },
}, },
yAxis: { yAxis: {
name: THROUGHPUT_STRINGS.Y_AXIS_TITLE, name: THROUGHPUT_CHART_STRINGS.Y_AXIS_TITLE,
}, },
}; };
}, },
formattedThroughputChartData() { formattedThroughputChartData() {
if (!this.throughputChartData) return [];
const data = Object.keys(this.throughputChartData) const data = Object.keys(this.throughputChartData)
.slice(0, -1) // Remove the __typeName key .slice(0, -1) // Remove the __typeName key
.map(value => [value, this.throughputChartData[value].count]); .map(value => [value, this.throughputChartData[value].count]);
return [ return [
{ {
name: THROUGHPUT_STRINGS.Y_AXIS_TITLE, name: THROUGHPUT_CHART_STRINGS.Y_AXIS_TITLE,
data, data,
}, },
]; ];
}, },
chartDataLoading() { chartDataLoading() {
return this.$apollo.queries.throughputChartData.loading; return !this.hasError && this.$apollo.queries.throughputChartData.loading;
}, },
chartDataAvailable() { chartDataAvailable() {
return this.formattedThroughputChartData[0].data.length; return this.formattedThroughputChartData[0]?.data.length;
},
alertDetails() {
return {
class: this.hasError ? 'danger' : 'info',
message: this.hasError
? THROUGHPUT_CHART_STRINGS.ERROR_FETCHING_DATA
: THROUGHPUT_CHART_STRINGS.NO_DATA,
};
}, },
}, },
strings: { strings: {
chartTitle: THROUGHPUT_STRINGS.CHART_TITLE, chartTitle: THROUGHPUT_CHART_STRINGS.CHART_TITLE,
chartDescription: THROUGHPUT_STRINGS.CHART_DESCRIPTION, chartDescription: THROUGHPUT_CHART_STRINGS.CHART_DESCRIPTION,
noData: THROUGHPUT_STRINGS.NO_DATA,
}, },
}; };
</script> </script>
...@@ -87,6 +100,8 @@ export default { ...@@ -87,6 +100,8 @@ export default {
:data="formattedThroughputChartData" :data="formattedThroughputChartData"
:option="chartOptions" :option="chartOptions"
/> />
<gl-alert v-else :dismissible="false" class="gl-mt-4">{{ $options.strings.noData }}</gl-alert> <gl-alert v-else :variant="alertDetails.class" :dismissible="false" class="gl-mt-4">{{
alertDetails.message
}}</gl-alert>
</div> </div>
</template> </template>
import { __ } from '~/locale'; import { __ } from '~/locale';
export const DEFAULT_NUMBER_OF_DAYS = 365; export const DEFAULT_NUMBER_OF_DAYS = 365;
export const THROUGHPUT_STRINGS = { export const THROUGHPUT_CHART_STRINGS = {
CHART_TITLE: __('Throughput'), CHART_TITLE: __('Throughput'),
Y_AXIS_TITLE: __('Merge Requests merged'), Y_AXIS_TITLE: __('Merge Requests merged'),
X_AXIS_TITLE: __('Month'), X_AXIS_TITLE: __('Month'),
CHART_DESCRIPTION: __('The number of merge requests merged by month.'), CHART_DESCRIPTION: __('The number of merge requests merged by month.'),
NO_DATA: __('There is no data available.'), NO_DATA: __('There is no chart data available.'),
ERROR_FETCHING_DATA: __('There was an error while fetching the chart data.'),
}; };
...@@ -2,7 +2,7 @@ import { shallowMount } from '@vue/test-utils'; ...@@ -2,7 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
import { GlAreaChart } from '@gitlab/ui/dist/charts'; import { GlAreaChart } from '@gitlab/ui/dist/charts';
import ThroughputChart from 'ee/analytics/merge_request_analytics/components/throughput_chart.vue'; import ThroughputChart from 'ee/analytics/merge_request_analytics/components/throughput_chart.vue';
import { THROUGHPUT_STRINGS } from 'ee/analytics/merge_request_analytics/constants'; import { THROUGHPUT_CHART_STRINGS } from 'ee/analytics/merge_request_analytics/constants';
import { throughputChartData } from '../mock_data'; import { throughputChartData } from '../mock_data';
const fullPath = 'gitlab-org/gitlab'; const fullPath = 'gitlab-org/gitlab';
...@@ -48,20 +48,20 @@ describe('ThroughputChart', () => { ...@@ -48,20 +48,20 @@ describe('ThroughputChart', () => {
it('displays the chart title', () => { it('displays the chart title', () => {
const chartTitle = wrapper.find('[data-testid="chartTitle"').text(); const chartTitle = wrapper.find('[data-testid="chartTitle"').text();
expect(chartTitle).toBe(THROUGHPUT_STRINGS.CHART_TITLE); expect(chartTitle).toBe(THROUGHPUT_CHART_STRINGS.CHART_TITLE);
}); });
it('displays the chart description', () => { it('displays the chart description', () => {
const chartDescription = wrapper.find('[data-testid="chartDescription"').text(); const chartDescription = wrapper.find('[data-testid="chartDescription"').text();
expect(chartDescription).toBe(THROUGHPUT_STRINGS.CHART_DESCRIPTION); expect(chartDescription).toBe(THROUGHPUT_CHART_STRINGS.CHART_DESCRIPTION);
}); });
it('displays an empty state message when there is no data', () => { it('displays an empty state message when there is no data', () => {
const alert = wrapper.find(GlAlert); const alert = wrapper.find(GlAlert);
expect(alert.exists()).toBe(true); expect(alert.exists()).toBe(true);
expect(alert.text()).toBe(THROUGHPUT_STRINGS.NO_DATA); expect(alert.text()).toBe(THROUGHPUT_CHART_STRINGS.NO_DATA);
}); });
it('does not display a loading icon', () => { it('does not display a loading icon', () => {
...@@ -86,7 +86,7 @@ describe('ThroughputChart', () => { ...@@ -86,7 +86,7 @@ describe('ThroughputChart', () => {
displaysComponent(GlAreaChart, false); displaysComponent(GlAreaChart, false);
}); });
it('does not display the no data message', () => { it('does not display a no data message', () => {
displaysComponent(GlAlert, false); displaysComponent(GlAlert, false);
}); });
}); });
...@@ -104,8 +104,29 @@ describe('ThroughputChart', () => { ...@@ -104,8 +104,29 @@ describe('ThroughputChart', () => {
displaysComponent(GlLoadingIcon, false); displaysComponent(GlLoadingIcon, false);
}); });
it('does not display the no data message', () => { it('does not display a no data message', () => {
displaysComponent(GlAlert, false); displaysComponent(GlAlert, false);
}); });
}); });
describe('with errors', () => {
beforeEach(() => {
createComponent({ data: { hasError: true } });
});
it('does not display the chart', () => {
displaysComponent(GlAreaChart, false);
});
it('does not display a loading icon', () => {
displaysComponent(GlLoadingIcon, false);
});
it('displays an error message', () => {
const alert = wrapper.find(GlAlert);
expect(alert.exists()).toBe(true);
expect(alert.text()).toBe(THROUGHPUT_CHART_STRINGS.ERROR_FETCHING_DATA);
});
});
}); });
...@@ -24482,7 +24482,7 @@ msgstr "" ...@@ -24482,7 +24482,7 @@ msgstr ""
msgid "There is already a repository with that name on disk" msgid "There is already a repository with that name on disk"
msgstr "" msgstr ""
msgid "There is no data available." msgid "There is no chart data available."
msgstr "" msgstr ""
msgid "There is no data available. Please change your selection." msgid "There is no data available. Please change your selection."
...@@ -24653,6 +24653,9 @@ msgstr "" ...@@ -24653,6 +24653,9 @@ msgstr ""
msgid "There was an error when unsubscribing from this label." msgid "There was an error when unsubscribing from this label."
msgstr "" msgstr ""
msgid "There was an error while fetching the chart data."
msgstr ""
msgid "There was an error while fetching value stream analytics data." msgid "There was an error while fetching value stream analytics data."
msgstr "" msgstr ""
......
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