diff options
8 files changed, 144 insertions, 8 deletions
diff --git a/app/assets/javascripts/monitoring/components/charts/empty_chart.vue b/app/assets/javascripts/monitoring/components/charts/empty_chart.vue new file mode 100644 index 00000000000..73682adc4ee --- /dev/null +++ b/app/assets/javascripts/monitoring/components/charts/empty_chart.vue @@ -0,0 +1,41 @@ +<script> +import chartEmptyStateIllustration from '@gitlab/svgs/dist/illustrations/chart-empty-state.svg'; +import { chartHeight } from '../../constants'; + +export default { + props: { + graphTitle: { + type: String, + required: true, + }, + }, + data() { + return { + height: chartHeight, + }; + }, + computed: { + svgContainerStyle() { + return { + height: `${this.height}px`, + }; + }, + }, + created() { + this.chartEmptyStateIllustration = chartEmptyStateIllustration; + }, +}; +</script> +<template> + <div class="prometheus-graph col-12 col-lg-6 d-flex flex-column justify-content-center"> + <div class="prometheus-graph-header"> + <h5 ref="graphTitle" class="prometheus-graph-title">{{ graphTitle }}</h5> + </div> + <div + class="prepend-top-8 svg-w-100 d-flex align-items-center" + :style="svgContainerStyle" + v-html="chartEmptyStateIllustration" + ></div> + <h5 class="text-center prepend-top-8">{{ __('No data to display') }}</h5> + </div> +</template> diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index c7c55880040..745488255ab 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -157,9 +157,6 @@ export default { 'multipleDashboardsEnabled', 'additionalPanelTypesEnabled', ]), - groupsWithData() { - return this.groups.filter(group => this.chartsWithData(group.metrics).length > 0); - }, selectedDashboardText() { return this.currentDashboard || (this.allDashboards[0] && this.allDashboards[0].display_name); }, @@ -256,6 +253,9 @@ export default { setTimeWindowParameter(key) { return `?time_window=${key}`; }, + groupHasData(group) { + return this.chartsWithData(group.metrics).length > 0; + }, }, addMetric: { title: s__('Metrics|Add metric'), @@ -369,14 +369,15 @@ export default { </div> <div v-if="!showEmptyState"> <graph-group - v-for="groupData in groupsWithData" + v-for="groupData in groups" :key="`${groupData.group}.${groupData.priority}`" :name="groupData.group" :show-panels="showPanels" + :collapse-group="groupHasData(groupData)" > <template v-if="additionalPanelTypesEnabled"> <panel-type - v-for="(graphData, graphIndex) in chartsWithData(groupData.metrics)" + v-for="(graphData, graphIndex) in groupData.metrics" :key="`panel-type-${graphIndex}`" :graph-data="graphData" :dashboard-width="elWidth" diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue index b20ad1802f3..0f5c5b3d60f 100644 --- a/app/assets/javascripts/monitoring/components/graph_group.vue +++ b/app/assets/javascripts/monitoring/components/graph_group.vue @@ -10,6 +10,10 @@ export default { required: false, default: true, }, + collapseGroup: { + type: Boolean, + required: true, + }, }, }; </script> @@ -19,7 +23,7 @@ export default { <div class="card-header"> <h4>{{ name }}</h4> </div> - <div class="card-body prometheus-graph-group"><slot></slot></div> + <div v-if="collapseGroup" class="card-body prometheus-graph-group"><slot></slot></div> </div> <div v-else class="prometheus-graph-group"><slot></slot></div> </template> diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue index 45ee067de83..d7cd2c57871 100644 --- a/app/assets/javascripts/monitoring/components/panel_type.vue +++ b/app/assets/javascripts/monitoring/components/panel_type.vue @@ -3,11 +3,13 @@ import { mapState } from 'vuex'; import _ from 'underscore'; import MonitorAreaChart from './charts/area.vue'; import MonitorSingleStatChart from './charts/single_stat.vue'; +import MonitorEmptyChart from './charts/empty_chart.vue'; export default { components: { MonitorAreaChart, MonitorSingleStatChart, + MonitorEmptyChart, }, props: { graphData: { @@ -24,6 +26,9 @@ export default { alertWidgetAvailable() { return IS_EE && this.prometheusAlertsAvailable && this.alertsEndpoint && this.graphData; }, + graphDataHasMetrics() { + return this.graphData.queries[0].result.length > 0; + }, }, methods: { getGraphAlerts(queries) { @@ -41,9 +46,12 @@ export default { }; </script> <template> - <monitor-single-stat-chart v-if="isPanelType('single-stat')" :graph-data="graphData" /> + <monitor-single-stat-chart + v-if="isPanelType('single-stat') && graphDataHasMetrics" + :graph-data="graphData" + /> <monitor-area-chart - v-else + v-else-if="graphDataHasMetrics" :graph-data="graphData" :deployment-data="deploymentData" :project-path="projectPath" @@ -59,4 +67,5 @@ export default { @setAlerts="setAlerts" /> </monitor-area-chart> + <monitor-empty-chart v-else :graph-title="graphData.title" /> </template> diff --git a/changelogs/unreleased/jivanvl-add-chart-empty-state.yml b/changelogs/unreleased/jivanvl-add-chart-empty-state.yml new file mode 100644 index 00000000000..7b81ee82582 --- /dev/null +++ b/changelogs/unreleased/jivanvl-add-chart-empty-state.yml @@ -0,0 +1,5 @@ +--- +title: Add empty chart component +merge_request: 30682 +author: +type: fixed diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 5cd9aa7e2de..df53015390c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -6917,6 +6917,9 @@ msgstr "" msgid "No data found" msgstr "" +msgid "No data to display" +msgstr "" + msgid "No details available" msgstr "" diff --git a/spec/javascripts/monitoring/charts/empty_chart_spec.js b/spec/javascripts/monitoring/charts/empty_chart_spec.js new file mode 100644 index 00000000000..bbfca27dc5a --- /dev/null +++ b/spec/javascripts/monitoring/charts/empty_chart_spec.js @@ -0,0 +1,29 @@ +import { shallowMount } from '@vue/test-utils'; +import EmptyChart from '~/monitoring/components/charts/empty_chart.vue'; + +describe('Empty Chart component', () => { + let emptyChart; + const graphTitle = 'Memory Usage'; + + beforeEach(() => { + emptyChart = shallowMount(EmptyChart, { + propsData: { + graphTitle, + }, + }); + }); + + afterEach(() => { + emptyChart.destroy(); + }); + + it('render the chart title', () => { + expect(emptyChart.find({ ref: 'graphTitle' }).text()).toBe(graphTitle); + }); + + describe('Computed props', () => { + it('sets the height for the svg container', () => { + expect(emptyChart.vm.svgContainerStyle.height).toBe('300px'); + }); + }); +}); diff --git a/spec/javascripts/monitoring/panel_type_spec.js b/spec/javascripts/monitoring/panel_type_spec.js new file mode 100644 index 00000000000..8ce24041e97 --- /dev/null +++ b/spec/javascripts/monitoring/panel_type_spec.js @@ -0,0 +1,44 @@ +import { shallowMount } from '@vue/test-utils'; +import PanelType from '~/monitoring/components/panel_type.vue'; +import EmptyChart from '~/monitoring/components/charts/empty_chart.vue'; +import { graphDataPrometheusQueryRange } from './mock_data'; + +describe('Panel Type component', () => { + let panelType; + const dashboardWidth = 100; + + describe('When no graphData is available', () => { + let glEmptyChart; + const graphDataNoResult = graphDataPrometheusQueryRange; + graphDataNoResult.queries[0].result = []; + + beforeEach(() => { + panelType = shallowMount(PanelType, { + propsData: { + dashboardWidth, + graphData: graphDataNoResult, + }, + }); + }); + + afterEach(() => { + panelType.destroy(); + }); + + describe('Empty Chart component', () => { + beforeEach(() => { + glEmptyChart = panelType.find(EmptyChart); + }); + + it('is a Vue instance', () => { + expect(glEmptyChart.isVueInstance()).toBe(true); + }); + + it('it receives a graph title', () => { + const props = glEmptyChart.props(); + + expect(props.graphTitle).toBe(panelType.vm.graphData.title); + }); + }); + }); +}); |