diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-18 12:45:46 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-18 12:45:46 +0300 |
commit | a7b3560714b4d9cc4ab32dffcd1f74a284b93580 (patch) | |
tree | 7452bd5c3545c2fa67a28aa013835fb4fa071baf /app/assets/javascripts/cycle_analytics | |
parent | ee9173579ae56a3dbfe5afe9f9410c65bb327ca7 (diff) |
Add latest changes from gitlab-org/gitlab@14-8-stable-eev14.8.0-rc42
Diffstat (limited to 'app/assets/javascripts/cycle_analytics')
7 files changed, 57 insertions, 230 deletions
diff --git a/app/assets/javascripts/cycle_analytics/components/base.vue b/app/assets/javascripts/cycle_analytics/components/base.vue index bdfabb8e846..3d7a34581b3 100644 --- a/app/assets/javascripts/cycle_analytics/components/base.vue +++ b/app/assets/javascripts/cycle_analytics/components/base.vue @@ -1,12 +1,12 @@ <script> import { GlLoadingIcon } from '@gitlab/ui'; -import Cookies from 'js-cookie'; import { mapActions, mapState, mapGetters } from 'vuex'; +import { getCookie, setCookie } from '~/lib/utils/common_utils'; +import ValueStreamMetrics from '~/analytics/shared/components/value_stream_metrics.vue'; import { toYmd } from '~/analytics/shared/utils'; import PathNavigation from '~/cycle_analytics/components/path_navigation.vue'; import StageTable from '~/cycle_analytics/components/stage_table.vue'; import ValueStreamFilters from '~/cycle_analytics/components/value_stream_filters.vue'; -import ValueStreamMetrics from '~/cycle_analytics/components/value_stream_metrics.vue'; import UrlSync from '~/vue_shared/components/url_sync.vue'; import { __ } from '~/locale'; import { SUMMARY_METRICS_REQUEST, METRICS_REQUESTS } from '../constants'; @@ -35,7 +35,7 @@ export default { }, data() { return { - isOverviewDialogDismissed: Cookies.get(OVERVIEW_DIALOG_COOKIE), + isOverviewDialogDismissed: getCookie(OVERVIEW_DIALOG_COOKIE), }; }, computed: { @@ -134,7 +134,7 @@ export default { }, dismissOverviewDialog() { this.isOverviewDialogDismissed = true; - Cookies.set(OVERVIEW_DIALOG_COOKIE, '1', { expires: 365 }); + setCookie(OVERVIEW_DIALOG_COOKIE, '1'); }, isUserAllowed(id) { const { permissions } = this; diff --git a/app/assets/javascripts/cycle_analytics/components/metric_popover.vue b/app/assets/javascripts/cycle_analytics/components/metric_popover.vue deleted file mode 100644 index 8d90e7b2392..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/metric_popover.vue +++ /dev/null @@ -1,61 +0,0 @@ -<script> -import { GlPopover, GlLink, GlIcon } from '@gitlab/ui'; - -export default { - name: 'MetricPopover', - components: { - GlPopover, - GlLink, - GlIcon, - }, - props: { - metric: { - type: Object, - required: true, - }, - target: { - type: String, - required: true, - }, - }, - computed: { - metricLinks() { - return this.metric.links?.filter((link) => !link.docs_link) || []; - }, - docsLink() { - return this.metric.links?.find((link) => link.docs_link); - }, - }, -}; -</script> - -<template> - <gl-popover :target="target" placement="bottom"> - <template #title> - <span class="gl-display-block gl-text-left" data-testid="metric-label">{{ - metric.label - }}</span> - </template> - <div - v-for="(link, idx) in metricLinks" - :key="`link-${idx}`" - class="gl-display-flex gl-justify-content-space-between gl-text-right gl-py-1" - data-testid="metric-link" - > - <span>{{ link.label }}</span> - <gl-link :href="link.url" class="gl-font-sm"> - {{ link.name }} - </gl-link> - </div> - <span v-if="metric.description" data-testid="metric-description">{{ metric.description }}</span> - <gl-link - v-if="docsLink" - :href="docsLink.url" - class="gl-font-sm" - target="_blank" - data-testid="metric-docs-link" - >{{ docsLink.label }} - <gl-icon name="external-link" class="gl-vertical-align-middle" /> - </gl-link> - </gl-popover> -</template> diff --git a/app/assets/javascripts/cycle_analytics/components/metric_tile.vue b/app/assets/javascripts/cycle_analytics/components/metric_tile.vue new file mode 100644 index 00000000000..a5c20b237b3 --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/components/metric_tile.vue @@ -0,0 +1,51 @@ +<script> +import { GlSingleStat } from '@gitlab/ui/dist/charts'; +import { redirectTo } from '~/lib/utils/url_utility'; +import MetricPopover from '~/analytics/shared/components/metric_popover.vue'; + +export default { + name: 'MetricTile', + components: { + GlSingleStat, + MetricPopover, + }, + props: { + metric: { + type: Object, + required: true, + }, + }, + computed: { + decimalPlaces() { + const parsedFloat = parseFloat(this.metric.value); + return Number.isNaN(parsedFloat) || Number.isInteger(parsedFloat) ? 0 : 1; + }, + hasLinks() { + return this.metric.links?.length && this.metric.links[0].url; + }, + }, + methods: { + clickHandler({ links }) { + if (this.hasLinks) { + redirectTo(links[0].url); + } + }, + }, +}; +</script> +<template> + <div v-bind="$attrs"> + <gl-single-stat + :id="metric.identifier" + :value="`${metric.value}`" + :title="metric.label" + :unit="metric.unit || ''" + :should-animate="true" + :animation-decimal-places="decimalPlaces" + :class="{ 'gl-hover-cursor-pointer': hasLinks }" + tabindex="0" + @click="clickHandler(metric)" + /> + <metric-popover :metric="metric" :target="metric.identifier" /> + </div> +</template> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_table.vue b/app/assets/javascripts/cycle_analytics/components/stage_table.vue index 8f7a3f99bab..ea5a1291a17 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_table.vue +++ b/app/assets/javascripts/cycle_analytics/components/stage_table.vue @@ -266,7 +266,7 @@ export default { > <span class="gl-font-lg">·</span> <span data-testid="vsa-stage-event-date"> - {{ s__('OpenedNDaysAgo|Opened') }} + {{ s__('OpenedNDaysAgo|Created') }} <gl-link class="gl-text-black-normal" :href="item.url">{{ item.createdAt }}</gl-link> diff --git a/app/assets/javascripts/cycle_analytics/components/value_stream_metrics.vue b/app/assets/javascripts/cycle_analytics/components/value_stream_metrics.vue deleted file mode 100644 index 9671742e564..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/value_stream_metrics.vue +++ /dev/null @@ -1,110 +0,0 @@ -<script> -import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui'; -import { GlSingleStat } from '@gitlab/ui/dist/charts'; -import { flatten } from 'lodash'; -import createFlash from '~/flash'; -import { sprintf, s__ } from '~/locale'; -import { redirectTo } from '~/lib/utils/url_utility'; -import { METRICS_POPOVER_CONTENT } from '../constants'; -import { removeFlash, prepareTimeMetricsData } from '../utils'; -import MetricPopover from './metric_popover.vue'; - -const requestData = ({ request, endpoint, path, params, name }) => { - return request({ endpoint, params, requestPath: path }) - .then(({ data }) => data) - .catch(() => { - const message = sprintf( - s__( - 'ValueStreamAnalytics|There was an error while fetching value stream analytics %{requestTypeName} data.', - ), - { requestTypeName: name }, - ); - createFlash({ message }); - }); -}; - -const fetchMetricsData = (reqs = [], path, params) => { - const promises = reqs.map((r) => requestData({ ...r, path, params })); - return Promise.all(promises).then((responses) => - prepareTimeMetricsData(flatten(responses), METRICS_POPOVER_CONTENT), - ); -}; - -export default { - name: 'ValueStreamMetrics', - components: { - GlSingleStat, - GlSkeletonLoading, - MetricPopover, - }, - props: { - requestPath: { - type: String, - required: true, - }, - requestParams: { - type: Object, - required: true, - }, - requests: { - type: Array, - required: true, - }, - }, - data() { - return { - metrics: [], - isLoading: false, - }; - }, - watch: { - requestParams() { - this.fetchData(); - }, - }, - mounted() { - this.fetchData(); - }, - methods: { - fetchData() { - removeFlash(); - this.isLoading = true; - return fetchMetricsData(this.requests, this.requestPath, this.requestParams) - .then((data) => { - this.metrics = data; - this.isLoading = false; - }) - .catch(() => { - this.isLoading = false; - }); - }, - hasLinks(links) { - return links?.length && links[0].url; - }, - clickHandler({ links }) { - if (this.hasLinks(links)) { - redirectTo(links[0].url); - } - }, - }, -}; -</script> -<template> - <div class="gl-display-flex gl-flex-wrap" data-testid="vsa-time-metrics"> - <gl-skeleton-loading v-if="isLoading" class="gl-h-auto gl-py-3 gl-pr-9 gl-my-6" /> - <div v-for="metric in metrics" v-show="!isLoading" :key="metric.key" class="gl-my-6 gl-pr-9"> - <gl-single-stat - :id="metric.key" - :value="`${metric.value}`" - :title="metric.label" - :unit="metric.unit || ''" - :should-animate="true" - :animation-decimal-places="1" - :class="{ 'gl-hover-cursor-pointer': hasLinks(metric.links) }" - tabindex="0" - @click="clickHandler(metric)" - /> - <metric-popover :metric="metric" :target="metric.key" /> - </div> - </div> -</template> diff --git a/app/assets/javascripts/cycle_analytics/constants.js b/app/assets/javascripts/cycle_analytics/constants.js index 7d5822b0824..f0b2bd9dc5b 100644 --- a/app/assets/javascripts/cycle_analytics/constants.js +++ b/app/assets/javascripts/cycle_analytics/constants.js @@ -36,31 +36,6 @@ export const OVERVIEW_METRICS = { RECENT_ACTIVITY: 'RECENT_ACTIVITY', }; -export const METRICS_POPOVER_CONTENT = { - 'lead-time': { - description: s__('ValueStreamAnalytics|Median time from issue created to issue closed.'), - }, - 'cycle-time': { - description: s__( - "ValueStreamAnalytics|Median time from the earliest commit of a linked issue's merge request to when that issue is closed.", - ), - }, - 'lead-time-for-changes': { - description: s__( - 'ValueStreamAnalytics|Median time between merge request merge and deployment to a production environment for all MRs deployed in the given time period.', - ), - }, - 'new-issue': { description: s__('ValueStreamAnalytics|Number of new issues created.') }, - '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.'), - }, - commits: { - description: s__('ValueStreamAnalytics|Number of commits pushed to the default branch'), - }, -}; - export const SUMMARY_METRICS_REQUEST = [ { endpoint: METRIC_TYPE_SUMMARY, name: __('recent activity'), request: getValueStreamMetrics }, ]; diff --git a/app/assets/javascripts/cycle_analytics/utils.js b/app/assets/javascripts/cycle_analytics/utils.js index 9af63f5f9cc..428bb11b950 100644 --- a/app/assets/javascripts/cycle_analytics/utils.js +++ b/app/assets/javascripts/cycle_analytics/utils.js @@ -1,14 +1,5 @@ -import { hideFlash } from '~/flash'; import { parseSeconds } from '~/lib/utils/datetime_utility'; import { formatTimeAsSummary } from '~/lib/utils/datetime/date_format_utility'; -import { slugify } from '~/lib/utils/text_utility'; - -export const removeFlash = (type = 'alert') => { - const flashEl = document.querySelector(`.flash-${type}`); - if (flashEl) { - hideFlash(flashEl); - } -}; /** * Takes the stages and median data, combined with the selected stage, to build an @@ -80,30 +71,11 @@ export const filterStagesByHiddenStatus = (stages = [], isHidden = true) => * @typedef {Object} TransformedMetricData * @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} identifier - Slugified string based on the 'title' or the provided 'identifier' attribute * @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} 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 = [], popoverContent = {}) => - data.map(({ title: label, ...rest }) => { - const key = slugify(label); - return { - ...rest, - label, - key, - description: popoverContent[key]?.description || '', - }; - }); - const extractFeatures = (gon) => ({ cycleAnalyticsForGroups: Boolean(gon?.licensed_features?.cycleAnalyticsForGroups), }); |