Skip to content
代码片段 群组 项目
未验证 提交 393abe09 编辑于 作者: Daniele Rossetti's avatar Daniele Rossetti 提交者: GitLab
浏览文件

Improve metrics details UI when no data available

上级 f9c9c56b
No related branches found
No related tags found
无相关合并请求
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
import EMPTY_CHART_SVG from '@gitlab/svgs/dist/illustrations/chart-empty-state.svg?url';
import { s__ } from '~/locale';
import { createAlert } from '~/alert';
import { visitUrl, isSafeURL } from '~/lib/utils/url_utility';
......@@ -11,10 +12,12 @@ export default {
'ObservabilityMetrics|Error: Failed to load metrics details. Try reloading the page.',
),
metricType: s__('ObservabilityMetrics|Type'),
noData: s__('ObservabilityMetrics|No data found for the selected metric.'),
},
components: {
GlLoadingIcon,
MetricsChart,
GlEmptyState,
},
props: {
observabilityClient: {
......@@ -37,20 +40,17 @@ export default {
},
data() {
return {
metricData: null,
metricData: [],
loading: false,
};
},
computed: {
header() {
if (this.metricData.length > 0) {
return {
title: this.metricData[0].name,
description: this.metricData[0].description,
type: this.metricData[0].type,
};
}
return null;
return {
title: this.metricId,
type: this.metricType,
description: this.metricData[0]?.description,
};
},
},
created() {
......@@ -99,6 +99,7 @@ export default {
visitUrl(this.metricsIndexUrl);
},
},
EMPTY_CHART_SVG,
};
</script>
......@@ -107,8 +108,8 @@ export default {
<gl-loading-icon size="lg" />
</div>
<div v-else-if="metricData" data-testid="metric-details" class="gl-m-7">
<div v-if="header" data-testid="metric-header">
<div v-else data-testid="metric-details" class="gl-m-7">
<div data-testid="metric-header">
<h1 class="gl-font-size-h1 gl-my-0" data-testid="metric-title">{{ header.title }}</h1>
<p class="gl-my-0" data-testid="metric-type">
<strong>{{ $options.i18n.metricType }}:&nbsp;</strong>{{ header.type }}
......@@ -116,6 +117,13 @@ export default {
<p class="gl-my-0" data-testid="metric-description">{{ header.description }}</p>
</div>
<metrics-chart :metric-data="metricData" />
<div class="gl-my-6">
<metrics-chart v-if="metricData.length > 0" :metric-data="metricData" />
<gl-empty-state v-else :svg-path="$options.EMPTY_CHART_SVG">
<template #title>
<p class="gl-font-lg">{{ $options.i18n.noData }}</p>
</template>
</gl-empty-state>
</div>
</div>
</template>
import { GlLoadingIcon } from '@gitlab/ui';
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
import MetricsDetails from 'ee/metrics/details/metrics_details.vue';
import { createMockClient } from 'helpers/mock_observability_client';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
......@@ -20,7 +20,14 @@ describe('MetricsDetails', () => {
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findMetricDetails = () => wrapper.findComponentByTestId('metric-details');
const findHeader = () => wrapper.findComponentByTestId('metric-header');
const findHeader = () => findMetricDetails().find(`[data-testid="metric-header"]`);
const findHeaderTitle = () => findHeader().find(`[data-testid="metric-title"]`);
const findHeaderType = () => findHeader().find(`[data-testid="metric-type"]`);
const findHeaderDescription = () => findHeader().find(`[data-testid="metric-description"]`);
const findChart = () => findMetricDetails().findComponent(MetricsChart);
const findEmptyState = () => findMetricDetails().findComponent(GlEmptyState);
const props = {
metricId: METRIC_ID,
......@@ -48,6 +55,7 @@ describe('MetricsDetails', () => {
mountComponent();
expect(findLoadingIcon().exists()).toBe(true);
expect(findMetricDetails().exists()).toBe(false);
expect(observabilityClientMock.isObservabilityEnabled).toHaveBeenCalled();
});
......@@ -90,25 +98,26 @@ describe('MetricsDetails', () => {
expect(chart.props('metricData')).toEqual(mockMetricData);
});
describe('header', () => {
it('renders the details header', () => {
const header = findHeader();
expect(header.exists()).toBe(true);
expect(header.find(`[data-testid="metric-title"]`).text()).toBe(
'container_cpu_usage_seconds_total',
);
expect(header.find(`[data-testid="metric-description"]`).text()).toBe(
'System disk operations',
);
expect(header.find(`[data-testid="metric-type"]`).text()).toBe('Type:\u00a0Gauge');
});
it('renders the details header', () => {
expect(findHeader().exists()).toBe(true);
expect(findHeaderTitle().text()).toBe(METRIC_ID);
expect(findHeaderType().text()).toBe(`Type:\u00a0${METRIC_TYPE}`);
expect(findHeaderDescription().text()).toBe('System disk operations');
});
it('does not render the header if the metric data is empty', () => {
describe('with no data', () => {
beforeEach(async () => {
observabilityClientMock.fetchMetric.mockResolvedValueOnce([]);
mountComponent();
expect(findHeader().exists()).toBe(false);
await mountComponent();
});
it('only renders the title and type headers', () => {
expect(findHeaderTitle().text()).toBe(METRIC_ID);
expect(findHeaderType().text()).toBe(`Type:\u00a0${METRIC_TYPE}`);
expect(findHeaderDescription().text()).toBe('');
});
it('renders the empty state', () => {
expect(findEmptyState().exists()).toBe(true);
});
});
});
......@@ -122,23 +131,36 @@ describe('MetricsDetails', () => {
it('redirects to metricsIndexUrl', () => {
expect(visitUrl).toHaveBeenCalledWith(props.metricsIndexUrl);
});
it('does not render the metrics details', () => {
expect(findMetricDetails().exists()).toBe(false);
});
});
describe('error handling', () => {
it('if isObservabilityEnabled fails, it renders an alert and empty page', async () => {
beforeEach(async () => {
observabilityClientMock.isObservabilityEnabled.mockRejectedValueOnce('error');
await mountComponent();
});
expect(createAlert).toHaveBeenCalledWith({
message: 'Error: Failed to load metrics details. Try reloading the page.',
describe.each([
['isObservabilityEnabled', () => observabilityClientMock.isObservabilityEnabled],
['fetchMetric', () => observabilityClientMock.fetchMetric],
])('when %s fails', (_, mockFn) => {
beforeEach(async () => {
mockFn().mockRejectedValueOnce('error');
await mountComponent();
});
it('renders an alert', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'Error: Failed to load metrics details. Try reloading the page.',
});
});
it('only renders the empty state and header', () => {
expect(findMetricDetails().exists()).toBe(true);
expect(findEmptyState().exists()).toBe(true);
expect(findLoadingIcon().exists()).toBe(false);
expect(findHeader().exists()).toBe(true);
expect(findChart().exists()).toBe(false);
});
expect(findLoadingIcon().exists()).toBe(false);
expect(findMetricDetails().exists()).toBe(false);
});
});
});
......@@ -32972,6 +32972,9 @@ msgstr ""
msgid "ObservabilityMetrics|Name"
msgstr ""
 
msgid "ObservabilityMetrics|No data found for the selected metric."
msgstr ""
msgid "ObservabilityMetrics|Search metrics starting with..."
msgstr ""
 
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册