Commit 8f9b89d0 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '208479-requests-for-svgs-returning-404-in-issues-analytics-feature' into 'master'

Resolve "Requests for SVGs returning 404 in Issues Analytics feature"

Closes #208479

See merge request gitlab-org/gitlab!26219
parents 83764276 e2df0d24
---
title: 'Issue Analytics: Fix svg illustration path for empty state'
merge_request: 26219
author:
type: fixed
<script>
import { imagePath } from '~/lib/utils/common_utils';
export default {
props: {
title: {
type: String,
required: true,
},
summary: {
type: String,
required: true,
},
image: {
type: String,
required: true,
},
},
computed: {
imagePath() {
return imagePath(this.image);
},
},
};
</script>
<template>
<div class="row empty-state">
<div class="col-12">
<div class="svg-content"><img class="content-image" :src="imagePath" /></div>
</div>
<div class="col-12">
<div class="text-content">
<h4 class="content-title text-center">{{ title }}</h4>
<p class="content-summary">{{ summary }}</p>
</div>
</div>
</div>
</template>
<script> <script>
import { mapGetters, mapActions, mapState } from 'vuex'; import { mapGetters, mapActions, mapState } from 'vuex';
import { engineeringNotation, sum, average } from '@gitlab/ui/src/utils/number_utils'; import { engineeringNotation, sum, average } from '@gitlab/ui/src/utils/number_utils';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
import { GlColumnChart, GlChartLegend } from '@gitlab/ui/dist/charts'; import { GlColumnChart, GlChartLegend } from '@gitlab/ui/dist/charts';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { getMonthNames } from '~/lib/utils/datetime_utility'; import { getMonthNames } from '~/lib/utils/datetime_utility';
import { getSvgIconPathContent } from '~/lib/utils/icon_utils'; import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
import EmptyState from './empty_state.vue';
export default { export default {
components: { components: {
EmptyState,
GlLoadingIcon, GlLoadingIcon,
GlEmptyState,
GlColumnChart, GlColumnChart,
GlChartLegend, GlChartLegend,
}, },
...@@ -24,6 +23,14 @@ export default { ...@@ -24,6 +23,14 @@ export default {
type: HTMLDivElement, type: HTMLDivElement,
required: true, required: true,
}, },
noDataEmptyStateSvgPath: {
type: String,
required: true,
},
filtersEmptyStateSvgPath: {
type: String,
required: true,
},
}, },
data() { data() {
return { return {
...@@ -135,9 +142,7 @@ export default { ...@@ -135,9 +142,7 @@ export default {
</script> </script>
<template> <template>
<div class="issues-analytics-wrapper" data-qa-selector="issues_analytics_wrapper"> <div class="issues-analytics-wrapper" data-qa-selector="issues_analytics_wrapper">
<div v-if="loading" class="issues-analytics-loading text-center"> <gl-loading-icon v-if="loading" :size="4" class="issues-analytics-loading" />
<gl-loading-icon :inline="true" :size="4" />
</div>
<div v-if="showChart" class="issues-analytics-chart"> <div v-if="showChart" class="issues-analytics-chart">
<h4 class="chart-title">{{ s__('IssuesAnalytics|Issues created per month') }}</h4> <h4 class="chart-title">{{ s__('IssuesAnalytics|Issues created per month') }}</h4>
...@@ -161,26 +166,26 @@ export default { ...@@ -161,26 +166,26 @@ export default {
</div> </div>
</div> </div>
<empty-state <gl-empty-state
v-if="showFiltersEmptyState" v-if="showFiltersEmptyState"
image="illustrations/issues.svg"
:title="s__('IssuesAnalytics|Sorry, your filter produced no results')" :title="s__('IssuesAnalytics|Sorry, your filter produced no results')"
:summary=" :description="
s__( s__(
'IssuesAnalytics|To widen your search, change or remove filters in the filter bar above', 'IssuesAnalytics|To widen your search, change or remove filters in the filter bar above',
) )
" "
:svg-path="filtersEmptyStateSvgPath"
/> />
<empty-state <gl-empty-state
v-if="showNoDataEmptyState" v-if="showNoDataEmptyState"
image="illustrations/monitoring/getting_started.svg"
:title="s__('IssuesAnalytics|There are no issues for the projects in your group')" :title="s__('IssuesAnalytics|There are no issues for the projects in your group')"
:summary=" :description="
s__( s__(
'IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them', 'IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them',
) )
" "
:svg-path="noDataEmptyStateSvgPath"
/> />
</div> </div>
</template> </template>
...@@ -9,6 +9,8 @@ export default () => { ...@@ -9,6 +9,8 @@ export default () => {
if (!el) return null; if (!el) return null;
const { endpoint, noDataEmptyStateSvgPath, filtersEmptyStateSvgPath } = el.dataset;
// Set default filters from URL // Set default filters from URL
store.dispatch('issueAnalytics/setFilters', window.location.search); store.dispatch('issueAnalytics/setFilters', window.location.search);
...@@ -25,8 +27,10 @@ export default () => { ...@@ -25,8 +27,10 @@ export default () => {
render(createElement) { render(createElement) {
return createElement('issues-analytics', { return createElement('issues-analytics', {
props: { props: {
endpoint: el.dataset.endpoint, endpoint,
filterBlockEl, filterBlockEl,
noDataEmptyStateSvgPath,
filtersEmptyStateSvgPath,
}, },
}); });
}, },
......
- page_title _('Issues Analytics') - page_title _('Issues Analytics')
= render 'shared/issuable/search_bar', type: :issues_analytics, show_sorting_dropdown: false = render 'shared/issuable/search_bar', type: :issues_analytics, show_sorting_dropdown: false
#js-issues-analytics{ data: { endpoint: group_issues_analytics_path(@group) } } #js-issues-analytics{ data: { endpoint: group_issues_analytics_path(@group), no_data_empty_state_svg_path: image_path('illustrations/monitoring/getting_started.svg'), filters_empty_state_svg_path: image_path('illustrations/issues.svg') } }
- page_title _('Issues Analytics') - page_title _('Issues Analytics')
= render 'shared/issuable/search_bar', type: :issues_analytics, show_sorting_dropdown: false = render 'shared/issuable/search_bar', type: :issues_analytics, show_sorting_dropdown: false
#js-issues-analytics{ data: { endpoint: project_analytics_issues_analytics_path(@project) } } #js-issues-analytics{ data: { endpoint: project_analytics_issues_analytics_path(@project), no_data_empty_state_svg_path: image_path('illustrations/monitoring/getting_started.svg'), filters_empty_state_svg_path: image_path('illustrations/issues.svg') } }
...@@ -3,9 +3,8 @@ import MockAdapter from 'axios-mock-adapter'; ...@@ -3,9 +3,8 @@ import MockAdapter from 'axios-mock-adapter';
import Vuex from 'vuex'; import Vuex from 'vuex';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import IssuesAnalytics from 'ee/issues_analytics/components/issues_analytics.vue'; import IssuesAnalytics from 'ee/issues_analytics/components/issues_analytics.vue';
import EmptyState from 'ee/issues_analytics/components/empty_state.vue';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
import { createStore } from 'ee/issues_analytics/stores'; import { createStore } from 'ee/issues_analytics/stores';
const localVue = createLocalVue(); const localVue = createLocalVue();
...@@ -28,6 +27,8 @@ describe('Issues Analytics component', () => { ...@@ -28,6 +27,8 @@ describe('Issues Analytics component', () => {
const propsData = data || { const propsData = data || {
endpoint: TEST_HOST, endpoint: TEST_HOST,
filterBlockEl: document.querySelector('#mock-filter'), filterBlockEl: document.querySelector('#mock-filter'),
noDataEmptyStateSvgPath: 'svg',
filtersEmptyStateSvgPath: 'svg',
}; };
return shallowMount(IssuesAnalytics, { return shallowMount(IssuesAnalytics, {
...@@ -50,7 +51,7 @@ describe('Issues Analytics component', () => { ...@@ -50,7 +51,7 @@ describe('Issues Analytics component', () => {
const findLoadingIcon = () => wrapper.find(GlLoadingIcon); const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
const findChartContainer = () => wrapper.find('.issues-analytics-chart'); const findChartContainer = () => wrapper.find('.issues-analytics-chart');
const findEmptyState = () => wrapper.find(EmptyState); const findEmptyState = () => wrapper.find(GlEmptyState);
it('fetches chart data when mounted', () => { it('fetches chart data when mounted', () => {
expect(store.dispatch).toHaveBeenCalledWith('issueAnalytics/fetchChartData', TEST_HOST); expect(store.dispatch).toHaveBeenCalledWith('issueAnalytics/fetchChartData', TEST_HOST);
......
import Vue from 'vue';
import EmptyState from 'ee/issues_analytics/components/empty_state.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Empty state component', () => {
let vm;
const Component = Vue.extend(EmptyState);
const props = {
image: 'illustrations/issues.svg',
title: 'Hello World',
summary: 'Lorem, ipsum dolor sit amet consectetur adipisicing elit.',
};
beforeEach(() => {
vm = mountComponent(Component, props);
});
it('renders the image', () => {
expect(vm.$el.querySelector('.content-image').src).toContain(props.image);
});
it('renders the title', () => {
expect(vm.$el.querySelector('.content-title').textContent.trim()).toEqual(props.title);
});
it('renders the summary', () => {
expect(vm.$el.querySelector('.content-summary').textContent.trim()).toEqual(props.summary);
});
});
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