summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/analytics
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/analytics')
-rw-r--r--app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue33
-rw-r--r--app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue72
-rw-r--r--app/assets/javascripts/analytics/shared/constants.js36
-rw-r--r--app/assets/javascripts/analytics/usage_trends/components/users_chart.vue6
4 files changed, 119 insertions, 28 deletions
diff --git a/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue b/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue
index b2b033de75d..b151e1605da 100644
--- a/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue
+++ b/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue
@@ -7,6 +7,7 @@ import {
GlDropdownSectionHeader,
GlDropdownItem,
GlSearchBoxByType,
+ GlTruncate,
} from '@gitlab/ui';
import { debounce } from 'lodash';
import { filterBySearchTerm } from '~/analytics/shared/utils';
@@ -28,6 +29,7 @@ export default {
GlDropdownSectionHeader,
GlDropdownItem,
GlSearchBoxByType,
+ GlTruncate,
},
props: {
groupId: {
@@ -212,30 +214,29 @@ export default {
<gl-dropdown
ref="projectsDropdown"
class="dropdown dropdown-projects"
- toggle-class="gl-shadow-none"
+ toggle-class="gl-shadow-none gl-mb-0"
:loading="loadingDefaultProjects"
:show-clear-all="hasSelectedProjects"
show-highlighted-items-title
highlighted-items-title-class="gl-p-3"
+ block
@clear-all.stop="onClearAll"
@hide="onHide"
>
<template #button-content>
- <gl-loading-icon v-if="loadingDefaultProjects" class="gl-mr-2" />
- <div class="gl-display-flex gl-flex-grow-1">
- <gl-avatar
- v-if="isOnlyOneProjectSelected"
- :src="selectedProjects[0].avatarUrl"
- :entity-id="getEntityId(selectedProjects[0])"
- :entity-name="selectedProjects[0].name"
- :size="16"
- :shape="$options.AVATAR_SHAPE_OPTION_RECT"
- :alt="selectedProjects[0].name"
- class="gl-display-inline-flex gl-vertical-align-middle gl-mr-2"
- />
- {{ selectedProjectsLabel }}
- </div>
- <gl-icon class="gl-ml-2" name="chevron-down" />
+ <gl-loading-icon v-if="loadingDefaultProjects" class="gl-mr-2 gl-flex-shrink-0" />
+ <gl-avatar
+ v-if="isOnlyOneProjectSelected"
+ :src="selectedProjects[0].avatarUrl"
+ :entity-id="getEntityId(selectedProjects[0])"
+ :entity-name="selectedProjects[0].name"
+ :size="16"
+ :shape="$options.AVATAR_SHAPE_OPTION_RECT"
+ :alt="selectedProjects[0].name"
+ class="gl-display-inline-flex gl-vertical-align-middle gl-mr-2 gl-flex-shrink-0"
+ />
+ <gl-truncate :text="selectedProjectsLabel" class="gl-min-w-0 gl-flex-grow-1" />
+ <gl-icon class="gl-ml-2 gl-flex-shrink-0" name="chevron-down" />
</template>
<template #header>
<gl-dropdown-section-header>{{ __('Projects') }}</gl-dropdown-section-header>
diff --git a/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue b/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
index 1a3544e7677..6ac1bce4032 100644
--- a/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
+++ b/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
@@ -1,6 +1,6 @@
<script>
import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
-import { flatten, isEqual } from 'lodash';
+import { flatten, isEqual, keyBy } from 'lodash';
import createFlash from '~/flash';
import { sprintf, s__ } from '~/locale';
import { METRICS_POPOVER_CONTENT } from '../constants';
@@ -28,6 +28,23 @@ const fetchMetricsData = (reqs = [], path, params) => {
);
};
+const extractMetricsGroupData = (keyList = [], data = []) => {
+ if (!keyList.length || !data.length) return [];
+ const kv = keyBy(data, 'identifier');
+ return keyList.map((id) => kv[id] || null).filter((obj) => Boolean(obj));
+};
+
+const groupRawMetrics = (groups = [], rawData = []) => {
+ return groups.map((curr) => {
+ const { keys, ...rest } = curr;
+ return {
+ data: extractMetricsGroupData(keys, rawData),
+ keys,
+ ...rest,
+ };
+ });
+};
+
export default {
name: 'ValueStreamMetrics',
components: {
@@ -52,13 +69,24 @@ export default {
required: false,
default: null,
},
+ groupBy: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
},
data() {
return {
metrics: [],
+ groupedMetrics: [],
isLoading: false,
};
},
+ computed: {
+ hasGroupedMetrics() {
+ return Boolean(this.groupBy.length);
+ },
+ },
watch: {
requestParams(newVal, oldVal) {
if (!isEqual(newVal, oldVal)) {
@@ -76,6 +104,11 @@ export default {
return fetchMetricsData(this.requests, this.requestPath, this.requestParams)
.then((data) => {
this.metrics = this.filterFn ? this.filterFn(data) : data;
+
+ if (this.hasGroupedMetrics) {
+ this.groupedMetrics = groupRawMetrics(this.groupBy, this.metrics);
+ }
+
this.isLoading = false;
})
.catch(() => {
@@ -86,14 +119,35 @@ export default {
};
</script>
<template>
- <div class="gl-display-flex gl-flex-wrap" data-testid="vsa-metrics">
+ <div class="gl-display-flex gl-mt-6" data-testid="vsa-metrics">
<gl-skeleton-loading v-if="isLoading" class="gl-h-auto gl-py-3 gl-pr-9 gl-my-6" />
- <metric-tile
- v-for="metric in metrics"
- v-show="!isLoading"
- :key="metric.identifier"
- :metric="metric"
- class="gl-my-6 gl-pr-9"
- />
+ <template v-else>
+ <div v-if="hasGroupedMetrics" class="gl-flex-direction-column">
+ <div
+ v-for="group in groupedMetrics"
+ :key="group.key"
+ class="gl-mb-7"
+ data-testid="vsa-metrics-group"
+ >
+ <h4 class="gl-my-0">{{ group.title }}</h4>
+ <div class="gl-display-flex gl-flex-wrap">
+ <metric-tile
+ v-for="metric in group.data"
+ :key="metric.identifier"
+ :metric="metric"
+ class="gl-mt-5 gl-pr-10"
+ />
+ </div>
+ </div>
+ </div>
+ <div v-else class="gl-display-flex gl-flex-wrap gl-mb-7">
+ <metric-tile
+ v-for="metric in metrics"
+ :key="metric.identifier"
+ :metric="metric"
+ class="gl-mt-5 gl-pr-10"
+ />
+ </div>
+ </template>
</div>
</template>
diff --git a/app/assets/javascripts/analytics/shared/constants.js b/app/assets/javascripts/analytics/shared/constants.js
index 2ac144ceb5e..38d05552783 100644
--- a/app/assets/javascripts/analytics/shared/constants.js
+++ b/app/assets/javascripts/analytics/shared/constants.js
@@ -55,4 +55,40 @@ export const METRICS_POPOVER_CONTENT = {
commits: {
description: s__('ValueStreamAnalytics|Number of commits pushed to the default branch'),
},
+ 'time-to-restore-service': {
+ description: s__(
+ 'ValueStreamAnalytics|Median time an incident was open on a production environment in the given time period.',
+ ),
+ },
+ time_to_restore_service: {
+ description: s__(
+ 'ValueStreamAnalytics|Median time an incident was open on a production environment in the given time period.',
+ ),
+ },
+ 'change-failure-rate': {
+ description: s__(
+ 'ValueStreamAnalytics|Percentage of deployments that cause an incident in production.',
+ ),
+ },
+ change_failure_rate: {
+ description: s__(
+ 'ValueStreamAnalytics|Percentage of deployments that cause an incident in production.',
+ ),
+ },
};
+
+const KEY_METRICS_TITLE = s__('ValueStreamAnalytics|Key metrics');
+const KEY_METRICS_KEYS = ['lead_time', 'cycle_time', 'issues', 'commits', 'deploys'];
+
+const DORA_METRICS_TITLE = s__('ValueStreamAnalytics|DORA metrics');
+const DORA_METRICS_KEYS = [
+ 'deployment_frequency',
+ 'lead_time_for_changes',
+ 'time_to_restore_service',
+ 'change_failure_rate',
+];
+
+export const VSA_METRICS_GROUPS = [
+ { key: 'key_metrics', title: KEY_METRICS_TITLE, keys: KEY_METRICS_KEYS },
+ { key: 'dora_metrics', title: DORA_METRICS_TITLE, keys: DORA_METRICS_KEYS },
+];
diff --git a/app/assets/javascripts/analytics/usage_trends/components/users_chart.vue b/app/assets/javascripts/analytics/usage_trends/components/users_chart.vue
index 09dfcddcb73..dfe94aeb884 100644
--- a/app/assets/javascripts/analytics/usage_trends/components/users_chart.vue
+++ b/app/assets/javascripts/analytics/usage_trends/components/users_chart.vue
@@ -122,7 +122,7 @@ export default {
<div>
<h3>{{ $options.i18n.yAxisTitle }}</h3>
<gl-alert v-if="loadingError" variant="danger" :dismissible="false" class="gl-mt-3">
- {{ this.$options.i18n.loadUserChartError }}
+ {{ $options.i18n.loadUserChartError }}
</gl-alert>
<chart-skeleton-loader v-else-if="isLoading" />
<gl-alert v-else-if="!chartUserData.length" variant="info" :dismissible="false" class="gl-mt-3">
@@ -132,12 +132,12 @@ export default {
v-else
:option="options"
:include-legend-avg-max="true"
- :data="[
+ :data="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
{
name: $options.i18n.yAxisTitle,
data: chartUserData,
},
- ]"
+ ] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
/>
</div>
</template>