Commit 7092ea29 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch '321573-vsa-use-single-stat-for-overview-metrics' into 'master'

[VSA] Use single stat for overview metrics

See merge request gitlab-org/gitlab!59732
parents b17e364e 4e0be565
<script>
import MetricCard from '~/analytics/shared/components/metric_card.vue';
import { OVERVIEW_METRICS } from '../constants';
import TimeMetricsCard from './time_metrics_card.vue';
......@@ -7,7 +6,6 @@ export default {
name: 'OverviewActivity',
components: {
TimeMetricsCard,
MetricCard,
},
props: {
groupPath: {
......@@ -23,26 +21,18 @@ export default {
};
</script>
<template>
<div class="js-recent-activity gl-mt-3 gl-display-flex">
<div class="gl-flex-fill-1 gl-pr-2">
<time-metrics-card
#default="{ metrics, loading }"
:group-path="groupPath"
:additional-params="requestParams"
:request-type="$options.overviewMetrics.TIME_SUMMARY"
>
<metric-card :title="__('Time')" :metrics="metrics" :is-loading="loading" />
</time-metrics-card>
</div>
<div class="gl-flex-fill-1 gl-pl-2">
<time-metrics-card
#default="{ metrics, loading }"
:group-path="groupPath"
:additional-params="requestParams"
:request-type="$options.overviewMetrics.RECENT_ACTIVITY"
>
<metric-card :title="__('Recent Activity')" :metrics="metrics" :is-loading="loading" />
</time-metrics-card>
</div>
<div class="gl-display-flex gl-sm-flex-direction-column" data-testid="vsa-time-metrics">
<time-metrics-card
class="gl-display-flex gl-my-6"
:group-path="groupPath"
:additional-params="requestParams"
:request-type="$options.overviewMetrics.TIME_SUMMARY"
/>
<time-metrics-card
class="gl-display-flex gl-my-6"
:group-path="groupPath"
:additional-params="requestParams"
:request-type="$options.overviewMetrics.RECENT_ACTIVITY"
/>
</div>
</template>
<script>
import { GlDeprecatedSkeletonLoading as GlSkeletonLoading, GlPopover } from '@gitlab/ui';
import { GlSingleStat } from '@gitlab/ui/dist/charts';
import Api from 'ee/api';
import MetricCard from '~/analytics/shared/components/metric_card.vue';
import createFlash from '~/flash';
import { sprintf, __, s__ } from '~/locale';
import { OVERVIEW_METRICS } from '../constants';
import { removeFlash, prepareTimeMetricsData } from '../utils';
const I18N_TEXT = {
'lead-time': s__('ValueStreamAnalytics|Median time from issue created to issue closed.'),
'cycle-time': s__('ValueStreamAnalytics|Median time from first commit to issue closed.'),
const POPOVER_CONTENT = {
'lead-time': {
description: s__('ValueStreamAnalytics|Median time from issue created to issue closed.'),
},
'cycle-time': {
description: s__('ValueStreamAnalytics|Median time from first commit to issue closed.'),
},
'new-issues': { description: s__('ValueStreamAnalytics|Number of new issues created.') },
deploys: { description: s__('ValueStreamAnalytics|Total number of deploys to production.') },
'deployment-frequency': {
description: s__('ValueStreamAnalytics|Average number of deployments to production per day.'),
},
};
const requestData = ({ requestType, groupPath, additionalParams }) => {
......@@ -20,7 +30,9 @@ const requestData = ({ requestType, groupPath, additionalParams }) => {
export default {
name: 'TimeMetricsCard',
components: {
MetricCard,
GlSkeletonLoading,
GlSingleStat,
GlPopover,
},
props: {
groupPath: {
......@@ -58,7 +70,7 @@ export default {
this.loading = true;
return requestData(this)
.then(({ data }) => {
this.data = prepareTimeMetricsData(data, I18N_TEXT);
this.data = prepareTimeMetricsData(data, POPOVER_CONTENT);
})
.catch(() => {
const requestTypeName =
......@@ -79,11 +91,32 @@ export default {
});
},
},
render() {
return this.$scopedSlots.default({
metrics: this.data,
loading: this.loading,
});
},
};
</script>
<template>
<div>
<div v-if="loading" class="gl-h-auto gl-py-3 gl-pr-9">
<gl-skeleton-loading />
</div>
<template v-else>
<div v-for="metric in data" :key="metric.key" class="gl-pr-9">
<gl-single-stat
:id="metric.key"
:value="`${metric.value}`"
:title="metric.label"
:unit="metric.unit || ''"
:should-animate="true"
tabindex="0"
/>
<gl-popover :target="metric.key" placement="bottom">
<template #title>
<span class="gl-display-block gl-text-left">{{ metric.label }}</span>
</template>
<span v-if="metric.description">{{ metric.description }}</span>
</gl-popover>
</div>
</template>
</div>
</template>
......@@ -458,25 +458,25 @@ export const transformStagesForPathNavigation = ({ stages, medians, selectedStag
* @property {String} label - Title of the metric measured
* @property {String} value - String representing the decimal point value, e.g '1.5'
* @property {String} key - Slugified string based on the 'title'
* @property {String} [tooltipText] - String to display for aa tooltip
* @property {String} [unit] - String representing the decimal point value, e.g '1.5'
* @property {String} description - String to display for a description
* @property {String} unit - String representing the decimal point value, e.g '1.5'
*/
/**
* Prepares metric data to be rendered in the metric_card component
*
* @param {MetricData[]} data - The metric data to be rendered
* @param {Object} [tooltipText] - Key value pair of strings to display in the tooltip
* @param {Object} popoverContent - Key value pair of data to display in the popover
* @returns {TransformedMetricData[]} An array of metrics ready to render in the metric_card
*/
export const prepareTimeMetricsData = (data = [], tooltipText = {}) =>
export const prepareTimeMetricsData = (data = [], popoverContent = {}) =>
data.map(({ title: label, ...rest }) => {
const key = slugify(label);
return {
...rest,
label,
key,
tooltipText: tooltipText[key] || '',
description: popoverContent[key]?.description || '',
};
});
---
title: Replace metric card with GlSingleStat in VSA
merge_request: 59732
author:
type: changed
......@@ -20,7 +20,7 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
stage_nav_selector = '.stage-nav'
path_nav_selector = '.js-path-navigation'
filter_bar_selector = '.js-filter-bar'
card_metric_selector = '.js-recent-activity .js-metric-card-item'
card_metric_selector = '[data-testid="vsa-time-metrics"] .gl-single-stat'
new_issues_count = 3
new_issues_count.times do |i|
......@@ -83,13 +83,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
wait_for_requests
end
it 'will display activity metrics' do
page.within(find('.js-recent-activity')) do
expect(page).to have_content(_('Recent Activity'))
expect(page).to have_content(_('Time'))
end
end
it 'displays the recent activity' do
deploys_count = page.all(card_metric_selector)[3]
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Metrics renders the recent activity 1`] = `"<time-metrics-card-stub grouppath=\\"foo\\" additionalparams=\\"[object Object]\\" requesttype=\\"RECENT_ACTIVITY\\"></time-metrics-card-stub>"`;
exports[`Metrics renders the recent activity 1`] = `"<time-metrics-card-stub grouppath=\\"foo\\" additionalparams=\\"[object Object]\\" requesttype=\\"RECENT_ACTIVITY\\" class=\\"gl-display-flex gl-my-6\\"></time-metrics-card-stub>"`;
exports[`Metrics renders the time summary 1`] = `"<time-metrics-card-stub grouppath=\\"foo\\" additionalparams=\\"[object Object]\\" requesttype=\\"TIME_SUMMARY\\"></time-metrics-card-stub>"`;
exports[`Metrics renders the time summary 1`] = `"<time-metrics-card-stub grouppath=\\"foo\\" additionalparams=\\"[object Object]\\" requesttype=\\"TIME_SUMMARY\\" class=\\"gl-display-flex gl-my-6\\"></time-metrics-card-stub>"`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TimeMetricsCard Recent activity renders the Recent activity metric 1`] = `"<div><span>4 </span><span>- </span><span>- per day</span></div>"`;
exports[`TimeMetricsCard Recent activity renders the Recent activity metric 1`] = `
"<div>
<div class=\\"gl-pr-9\\">
<gl-single-stat-stub title=\\"New Issues\\" value=\\"4\\" unit=\\"\\" variant=\\"muted\\" shouldanimate=\\"true\\" animationdecimalplaces=\\"0\\" id=\\"new-issues\\" tabindex=\\"0\\"></gl-single-stat-stub>
<gl-popover-stub cssclasses=\\"\\" target=\\"new-issues\\" placement=\\"bottom\\"> <span>Number of new issues created.</span></gl-popover-stub>
</div>
<div class=\\"gl-pr-9\\">
<gl-single-stat-stub title=\\"Deploys\\" value=\\"-\\" unit=\\"\\" variant=\\"muted\\" shouldanimate=\\"true\\" animationdecimalplaces=\\"0\\" id=\\"deploys\\" tabindex=\\"0\\"></gl-single-stat-stub>
<gl-popover-stub cssclasses=\\"\\" target=\\"deploys\\" placement=\\"bottom\\"> <span>Total number of deploys to production.</span></gl-popover-stub>
</div>
<div class=\\"gl-pr-9\\">
<gl-single-stat-stub title=\\"Deployment Frequency\\" value=\\"-\\" unit=\\"per day\\" variant=\\"muted\\" shouldanimate=\\"true\\" animationdecimalplaces=\\"0\\" id=\\"deployment-frequency\\" tabindex=\\"0\\"></gl-single-stat-stub>
<gl-popover-stub cssclasses=\\"\\" target=\\"deployment-frequency\\" placement=\\"bottom\\"> <span>Average number of deployments to production per day.</span></gl-popover-stub>
</div>
</div>"
`;
exports[`TimeMetricsCard Time summary renders the Time summary metric 1`] = `"<div><span>4.5 days</span><span>3.0 days</span></div>"`;
exports[`TimeMetricsCard Time summary renders the Time summary metric 1`] = `
"<div>
<div class=\\"gl-pr-9\\">
<gl-single-stat-stub title=\\"Lead Time\\" value=\\"4.5\\" unit=\\"days\\" variant=\\"muted\\" shouldanimate=\\"true\\" animationdecimalplaces=\\"0\\" id=\\"lead-time\\" tabindex=\\"0\\"></gl-single-stat-stub>
<gl-popover-stub cssclasses=\\"\\" target=\\"lead-time\\" placement=\\"bottom\\"> <span>Median time from issue created to issue closed.</span></gl-popover-stub>
</div>
<div class=\\"gl-pr-9\\">
<gl-single-stat-stub title=\\"Cycle Time\\" value=\\"3.0\\" unit=\\"days\\" variant=\\"muted\\" shouldanimate=\\"true\\" animationdecimalplaces=\\"0\\" id=\\"cycle-time\\" tabindex=\\"0\\"></gl-single-stat-stub>
<gl-popover-stub cssclasses=\\"\\" target=\\"cycle-time\\" placement=\\"bottom\\"> <span>Median time from first commit to issue closed.</span></gl-popover-stub>
</div>
</div>"
`;
......@@ -11,11 +11,6 @@ describe('TimeMetricsCard', () => {
const { full_path: groupPath } = group;
let wrapper;
const template = `
<div slot-scope="{ metrics }">
<span v-for="metric in metrics">{{metric.value}} {{metric.unit}}</span>
</div>`;
const createComponent = ({ additionalParams = {}, requestType } = {}) => {
return shallowMount(TimeMetricsCard, {
propsData: {
......@@ -23,9 +18,6 @@ describe('TimeMetricsCard', () => {
additionalParams,
requestType,
},
scopedSlots: {
default: template,
},
});
};
......
......@@ -376,7 +376,7 @@ describe('Value Stream Analytics utils', () => {
beforeEach(() => {
prepared = prepareTimeMetricsData(timeMetricsData, {
[firstKey]: 'Is a value that is good',
[firstKey]: { description: 'Is a value that is good' },
});
});
......@@ -388,10 +388,10 @@ describe('Value Stream Analytics utils', () => {
expect(prepared).toMatchObject([{ label: 'Lead Time' }, { label: 'Cycle Time' }]);
});
it('will add a tooltip text using the key if it is provided', () => {
it('will add a popover description using the key if it is provided', () => {
expect(prepared).toMatchObject([
{ tooltipText: 'Is a value that is good' },
{ tooltipText: '' },
{ description: 'Is a value that is good' },
{ description: '' },
]);
});
});
......
......@@ -26500,9 +26500,6 @@ msgstr ""
msgid "Recent"
msgstr ""
msgid "Recent Activity"
msgstr ""
msgid "Recent Deliveries"
msgstr ""
......@@ -35153,12 +35150,21 @@ msgstr ""
msgid "ValueStreamAnalytics|&lt;1m"
msgstr ""
msgid "ValueStreamAnalytics|Average number of deployments to production per day."
msgstr ""
msgid "ValueStreamAnalytics|Median time from first commit to issue closed."
msgstr ""
msgid "ValueStreamAnalytics|Median time from issue created to issue closed."
msgstr ""
msgid "ValueStreamAnalytics|Number of new issues created."
msgstr ""
msgid "ValueStreamAnalytics|Total number of deploys to production."
msgstr ""
msgid "ValueStreamEvent|Stage time (median)"
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