diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-18 18:10:26 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-18 18:10:26 +0000 |
commit | 96c78a921fc87226239fe6a8ea89a518731dc152 (patch) | |
tree | 8cfb6d13c61d859eab529a2ad75b0603f7e1b78f /app/assets/javascripts/analytics | |
parent | 80d252c8e25dc88023e750cf2a22be6186cfd6aa (diff) | |
download | gitlab-ce-96c78a921fc87226239fe6a8ea89a518731dc152.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/analytics')
5 files changed, 214 insertions, 0 deletions
diff --git a/app/assets/javascripts/analytics/instance_statistics/components/app.vue b/app/assets/javascripts/analytics/instance_statistics/components/app.vue new file mode 100644 index 00000000000..eb0b67a1629 --- /dev/null +++ b/app/assets/javascripts/analytics/instance_statistics/components/app.vue @@ -0,0 +1,14 @@ +<script> +import InstanceCounts from './instance_counts.vue'; + +export default { + name: 'InstanceStatisticsApp', + components: { + InstanceCounts, + }, +}; +</script> + +<template> + <instance-counts /> +</template> diff --git a/app/assets/javascripts/analytics/instance_statistics/components/instance_counts.vue b/app/assets/javascripts/analytics/instance_statistics/components/instance_counts.vue new file mode 100644 index 00000000000..1147ce9af73 --- /dev/null +++ b/app/assets/javascripts/analytics/instance_statistics/components/instance_counts.vue @@ -0,0 +1,64 @@ +<script> +import * as Sentry from '@sentry/browser'; +import { s__ } from '~/locale'; +import { deprecatedCreateFlash as createFlash } from '~/flash'; +import { SUPPORTED_FORMATS, getFormatter } from '~/lib/utils/unit_format'; +import MetricCard from '~/analytics/shared/components/metric_card.vue'; +import instanceStatisticsCountQuery from '../graphql/queries/instance_statistics_count.query.graphql'; + +const defaultPrecision = 0; + +export default { + name: 'InstanceCounts', + components: { + MetricCard, + }, + data() { + return { + counts: [], + }; + }, + apollo: { + counts: { + query: instanceStatisticsCountQuery, + update(data) { + return Object.entries(data).map(([key, obj]) => { + const label = this.$options.i18n.labels[key]; + const formatter = getFormatter(SUPPORTED_FORMATS.number); + const value = obj.nodes?.length ? formatter(obj.nodes[0].count, defaultPrecision) : null; + + return { + key, + value, + label, + }; + }); + }, + error(error) { + createFlash(this.$options.i18n.loadCountsError); + Sentry.captureException(error); + }, + }, + }, + i18n: { + labels: { + users: s__('InstanceStatistics|Users'), + projects: s__('InstanceStatistics|Projects'), + groups: s__('InstanceStatistics|Groups'), + issues: s__('InstanceStatistics|Issues'), + mergeRequests: s__('InstanceStatistics|Merge Requests'), + pipelines: s__('InstanceStatistics|Pipelines'), + }, + loadCountsError: s__('Could not load instance counts. Please refresh the page to try again.'), + }, +}; +</script> + +<template> + <metric-card + :title="__('Instance Statistics')" + :metrics="counts" + :is-loading="$apollo.queries.counts.loading" + class="gl-mt-4" + /> +</template> diff --git a/app/assets/javascripts/analytics/instance_statistics/graphql/queries/instance_statistics_count.query.graphql b/app/assets/javascripts/analytics/instance_statistics/graphql/queries/instance_statistics_count.query.graphql new file mode 100644 index 00000000000..fd8282683d9 --- /dev/null +++ b/app/assets/javascripts/analytics/instance_statistics/graphql/queries/instance_statistics_count.query.graphql @@ -0,0 +1,32 @@ +query getInstanceCounts { + projects: instanceStatisticsMeasurements(identifier: PROJECTS, first: 1) { + nodes { + count + } + } + groups: instanceStatisticsMeasurements(identifier: GROUPS, first: 1) { + nodes { + count + } + } + users: instanceStatisticsMeasurements(identifier: USERS, first: 1) { + nodes { + count + } + } + issues: instanceStatisticsMeasurements(identifier: ISSUES, first: 1) { + nodes { + count + } + } + mergeRequests: instanceStatisticsMeasurements(identifier: MERGE_REQUESTS, first: 1) { + nodes { + count + } + } + pipelines: instanceStatisticsMeasurements(identifier: PIPELINES, first: 1) { + nodes { + count + } + } +} diff --git a/app/assets/javascripts/analytics/instance_statistics/index.js b/app/assets/javascripts/analytics/instance_statistics/index.js new file mode 100644 index 00000000000..0d7dcf6ace8 --- /dev/null +++ b/app/assets/javascripts/analytics/instance_statistics/index.js @@ -0,0 +1,24 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; +import InstanceStatisticsApp from './components/app.vue'; + +Vue.use(VueApollo); + +const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), +}); + +export default () => { + const el = document.getElementById('js-instance-statistics-app'); + + if (!el) return false; + + return new Vue({ + el, + apolloProvider, + render(h) { + return h(InstanceStatisticsApp); + }, + }); +}; diff --git a/app/assets/javascripts/analytics/shared/components/metric_card.vue b/app/assets/javascripts/analytics/shared/components/metric_card.vue new file mode 100644 index 00000000000..cee186c057c --- /dev/null +++ b/app/assets/javascripts/analytics/shared/components/metric_card.vue @@ -0,0 +1,80 @@ +<script> +import { + GlCard, + GlDeprecatedSkeletonLoading as GlSkeletonLoading, + GlLink, + GlIcon, + GlTooltipDirective, +} from '@gitlab/ui'; + +export default { + name: 'MetricCard', + components: { + GlCard, + GlSkeletonLoading, + GlLink, + GlIcon, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + title: { + type: String, + required: true, + }, + metrics: { + type: Array, + required: true, + }, + isLoading: { + type: Boolean, + required: false, + default: false, + }, + }, + methods: { + valueText(metric) { + const { value = null, unit = null } = metric; + if (!value || value === '-') return '-'; + return unit && value ? `${value} ${unit}` : value; + }, + }, +}; +</script> +<template> + <gl-card> + <template #header> + <strong ref="title">{{ title }}</strong> + </template> + <template #default> + <gl-skeleton-loading v-if="isLoading" class="gl-h-auto gl-py-3" /> + <div v-else ref="metricsWrapper" class="gl-display-flex"> + <div + v-for="metric in metrics" + :key="metric.key" + ref="metricItem" + class="js-metric-card-item gl-flex-grow-1 gl-text-center" + > + <gl-link v-if="metric.link" :href="metric.link"> + <h3 class="gl-my-2 gl-text-blue-700">{{ valueText(metric) }}</h3> + </gl-link> + <h3 v-else class="gl-my-2">{{ valueText(metric) }}</h3> + <p class="text-secondary gl-font-sm gl-mb-2"> + {{ metric.label }} + <span v-if="metric.tooltipText"> + + <gl-icon + v-gl-tooltip="{ title: metric.tooltipText }" + :size="14" + class="gl-vertical-align-middle" + name="question" + data-testid="tooltip" + /> + </span> + </p> + </div> + </div> + </template> + </gl-card> +</template> |