Commit e2df0d24 authored by Martin Wortschack's avatar Martin Wortschack

Pass SVG path from BE to FE

- Also replace custom empty state screen with GlEmptyState
parent 796cd50d
---
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>
import { mapGetters, mapActions, mapState } from 'vuex';
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 { s__ } from '~/locale';
import { getMonthNames } from '~/lib/utils/datetime_utility';
import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
import EmptyState from './empty_state.vue';
export default {
components: {
EmptyState,
GlLoadingIcon,
GlEmptyState,
GlColumnChart,
GlChartLegend,
},
......@@ -24,6 +23,14 @@ export default {
type: HTMLDivElement,
required: true,
},
noDataEmptyStateSvgPath: {
type: String,
required: true,
},
filtersEmptyStateSvgPath: {
type: String,
required: true,
},
},
data() {
return {
......@@ -135,9 +142,7 @@ export default {
</script>
<template>
<div class="issues-analytics-wrapper" data-qa-selector="issues_analytics_wrapper">
<div v-if="loading" class="issues-analytics-loading text-center">
<gl-loading-icon :inline="true" :size="4" />
</div>
<gl-loading-icon v-if="loading" :size="4" class="issues-analytics-loading" />
<div v-if="showChart" class="issues-analytics-chart">
<h4 class="chart-title">{{ s__('IssuesAnalytics|Issues created per month') }}</h4>
......@@ -161,26 +166,26 @@ export default {
</div>
</div>
<empty-state
<gl-empty-state
v-if="showFiltersEmptyState"
image="illustrations/issues.svg"
:title="s__('IssuesAnalytics|Sorry, your filter produced no results')"
:summary="
:description="
s__(
'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"
image="illustrations/monitoring/getting_started.svg"
:title="s__('IssuesAnalytics|There are no issues for the projects in your group')"
:summary="
:description="
s__(
'IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them',
)
"
:svg-path="noDataEmptyStateSvgPath"
/>
</div>
</template>
......@@ -9,6 +9,8 @@ export default () => {
if (!el) return null;
const { endpoint, noDataEmptyStateSvgPath, filtersEmptyStateSvgPath } = el.dataset;
// Set default filters from URL
store.dispatch('issueAnalytics/setFilters', window.location.search);
......@@ -25,8 +27,10 @@ export default () => {
render(createElement) {
return createElement('issues-analytics', {
props: {
endpoint: el.dataset.endpoint,
endpoint,
filterBlockEl,
noDataEmptyStateSvgPath,
filtersEmptyStateSvgPath,
},
});
},
......
- page_title _('Issues Analytics')
= 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')
= 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';
import Vuex from 'vuex';
import { TEST_HOST } from 'helpers/test_constants';
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 { GlLoadingIcon } from '@gitlab/ui';
import { GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
import { createStore } from 'ee/issues_analytics/stores';
const localVue = createLocalVue();
......@@ -28,6 +27,8 @@ describe('Issues Analytics component', () => {
const propsData = data || {
endpoint: TEST_HOST,
filterBlockEl: document.querySelector('#mock-filter'),
noDataEmptyStateSvgPath: 'svg',
filtersEmptyStateSvgPath: 'svg',
};
return shallowMount(IssuesAnalytics, {
......@@ -50,7 +51,7 @@ describe('Issues Analytics component', () => {
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
const findChartContainer = () => wrapper.find('.issues-analytics-chart');
const findEmptyState = () => wrapper.find(EmptyState);
const findEmptyState = () => wrapper.find(GlEmptyState);
it('fetches chart data when mounted', () => {
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