Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/monitoring/components')
-rw-r--r--app/assets/javascripts/monitoring/components/embed.vue99
-rw-r--r--app/assets/javascripts/monitoring/components/embeds/embed_group.vue101
-rw-r--r--app/assets/javascripts/monitoring/components/embeds/metric_embed.vue131
-rw-r--r--app/assets/javascripts/monitoring/components/panel_type.vue22
4 files changed, 253 insertions, 100 deletions
diff --git a/app/assets/javascripts/monitoring/components/embed.vue b/app/assets/javascripts/monitoring/components/embed.vue
deleted file mode 100644
index 6182b570e76..00000000000
--- a/app/assets/javascripts/monitoring/components/embed.vue
+++ /dev/null
@@ -1,99 +0,0 @@
-<script>
-import { mapActions, mapState, mapGetters } from 'vuex';
-import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue';
-import { convertToFixedRange } from '~/lib/utils/datetime_range';
-import { timeRangeFromUrl, removeTimeRangeParams } from '../utils';
-import { sidebarAnimationDuration } from '../constants';
-import { defaultTimeRange } from '~/vue_shared/constants';
-
-let sidebarMutationObserver;
-
-export default {
- components: {
- PanelType,
- },
- props: {
- dashboardUrl: {
- type: String,
- required: true,
- },
- },
- data() {
- const timeRange = timeRangeFromUrl(this.dashboardUrl) || defaultTimeRange;
- return {
- timeRange: convertToFixedRange(timeRange),
- elWidth: 0,
- };
- },
- computed: {
- ...mapState('monitoringDashboard', ['dashboard']),
- ...mapGetters('monitoringDashboard', ['metricsWithData']),
- charts() {
- if (!this.dashboard || !this.dashboard.panelGroups) {
- return [];
- }
- const groupWithMetrics = this.dashboard.panelGroups.find(group =>
- group.panels.find(chart => this.chartHasData(chart)),
- ) || { panels: [] };
-
- return groupWithMetrics.panels.filter(chart => this.chartHasData(chart));
- },
- isSingleChart() {
- return this.charts.length === 1;
- },
- },
- mounted() {
- this.setInitialState();
- this.setTimeRange(this.timeRange);
- this.fetchDashboard();
-
- sidebarMutationObserver = new MutationObserver(this.onSidebarMutation);
- sidebarMutationObserver.observe(document.querySelector('.layout-page'), {
- attributes: true,
- childList: false,
- subtree: false,
- });
- },
- beforeDestroy() {
- if (sidebarMutationObserver) {
- sidebarMutationObserver.disconnect();
- }
- },
- methods: {
- ...mapActions('monitoringDashboard', [
- 'setTimeRange',
- 'fetchDashboard',
- 'setEndpoints',
- 'setFeatureFlags',
- 'setShowErrorBanner',
- ]),
- chartHasData(chart) {
- return chart.metrics.some(metric => this.metricsWithData().includes(metric.metricId));
- },
- onSidebarMutation() {
- setTimeout(() => {
- this.elWidth = this.$el.clientWidth;
- }, sidebarAnimationDuration);
- },
- setInitialState() {
- this.setEndpoints({
- dashboardEndpoint: removeTimeRangeParams(this.dashboardUrl),
- });
- this.setShowErrorBanner(false);
- },
- },
-};
-</script>
-<template>
- <div class="metrics-embed" :class="{ 'd-inline-flex col-lg-6 p-0': isSingleChart }">
- <div v-if="charts.length" class="row w-100 m-n2 pb-4">
- <panel-type
- v-for="(graphData, graphIndex) in charts"
- :key="`panel-type-${graphIndex}`"
- class="w-100"
- :graph-data="graphData"
- :group-id="dashboardUrl"
- />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/monitoring/components/embeds/embed_group.vue b/app/assets/javascripts/monitoring/components/embeds/embed_group.vue
new file mode 100644
index 00000000000..b8562afe441
--- /dev/null
+++ b/app/assets/javascripts/monitoring/components/embeds/embed_group.vue
@@ -0,0 +1,101 @@
+<script>
+import { mapState, mapActions, mapGetters } from 'vuex';
+import sum from 'lodash/sum';
+import { GlButton, GlCard, GlIcon } from '@gitlab/ui';
+import { n__ } from '~/locale';
+import { monitoringDashboard } from '~/monitoring/stores';
+import MetricEmbed from './metric_embed.vue';
+
+export default {
+ components: {
+ GlButton,
+ GlCard,
+ GlIcon,
+ MetricEmbed,
+ },
+ props: {
+ urls: {
+ type: Array,
+ required: true,
+ validator: urls => urls.length > 0,
+ },
+ },
+ data() {
+ return {
+ isCollapsed: false,
+ };
+ },
+ computed: {
+ ...mapState('embedGroup', ['module']),
+ ...mapGetters('embedGroup', ['metricsWithData']),
+ arrowIconName() {
+ return this.isCollapsed ? 'chevron-right' : 'chevron-down';
+ },
+ bodyClass() {
+ return ['border-top', 'pl-3', 'pt-3', { 'd-none': this.isCollapsed }];
+ },
+ buttonLabel() {
+ return this.isCollapsed
+ ? n__('View chart', 'View charts', this.numCharts)
+ : n__('Hide chart', 'Hide charts', this.numCharts);
+ },
+ containerClass() {
+ return this.isSingleChart ? 'col-lg-12' : 'col-lg-6';
+ },
+ numCharts() {
+ if (this.metricsWithData === null) {
+ return 0;
+ }
+ return sum(this.metricsWithData);
+ },
+ isSingleChart() {
+ return this.numCharts === 1;
+ },
+ },
+ created() {
+ this.urls.forEach((url, index) => {
+ const name = this.getNamespace(index);
+ this.$store.registerModule(name, monitoringDashboard);
+ this.addModule(name);
+ });
+ },
+ methods: {
+ ...mapActions('embedGroup', ['addModule']),
+ getNamespace(id) {
+ return `monitoringDashboard/${id}`;
+ },
+ toggleCollapsed() {
+ this.isCollapsed = !this.isCollapsed;
+ },
+ },
+};
+</script>
+<template>
+ <gl-card
+ v-show="numCharts > 0"
+ class="collapsible-card border p-0 mb-3"
+ header-class="d-flex align-items-center border-bottom-0 py-2"
+ :body-class="bodyClass"
+ >
+ <template #header>
+ <gl-button
+ class="collapsible-card-btn d-flex text-decoration-none"
+ :aria-label="buttonLabel"
+ variant="link"
+ @click="toggleCollapsed"
+ >
+ <gl-icon class="mr-1" :name="arrowIconName" />
+ {{ buttonLabel }}
+ </gl-button>
+ </template>
+ <div class="d-flex flex-wrap">
+ <metric-embed
+ v-for="(url, index) in urls"
+ :key="`${index}/${url}`"
+ :dashboard-url="url"
+ :namespace="getNamespace(index)"
+ :container-class="containerClass"
+ />
+ </div>
+ </gl-card>
+</template>
diff --git a/app/assets/javascripts/monitoring/components/embeds/metric_embed.vue b/app/assets/javascripts/monitoring/components/embeds/metric_embed.vue
new file mode 100644
index 00000000000..8a44e6bd737
--- /dev/null
+++ b/app/assets/javascripts/monitoring/components/embeds/metric_embed.vue
@@ -0,0 +1,131 @@
+<script>
+import { mapState, mapActions } from 'vuex';
+import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue';
+import { convertToFixedRange } from '~/lib/utils/datetime_range';
+import { defaultTimeRange } from '~/vue_shared/constants';
+import { timeRangeFromUrl, removeTimeRangeParams } from '../../utils';
+import { sidebarAnimationDuration } from '../../constants';
+
+let sidebarMutationObserver;
+
+export default {
+ components: {
+ PanelType,
+ },
+ props: {
+ containerClass: {
+ type: String,
+ required: false,
+ default: 'col-lg-12',
+ },
+ dashboardUrl: {
+ type: String,
+ required: true,
+ },
+ namespace: {
+ type: String,
+ required: false,
+ default: 'monitoringDashboard',
+ },
+ },
+ data() {
+ const timeRange = timeRangeFromUrl(this.dashboardUrl) || defaultTimeRange;
+ return {
+ timeRange: convertToFixedRange(timeRange),
+ elWidth: 0,
+ };
+ },
+ computed: {
+ ...mapState({
+ dashboard(state) {
+ return state[this.namespace].dashboard;
+ },
+ metricsWithData(state, getters) {
+ return getters[`${this.namespace}/metricsWithData`]();
+ },
+ }),
+ charts() {
+ if (!this.dashboard || !this.dashboard.panelGroups) {
+ return [];
+ }
+ return this.dashboard.panelGroups.reduce(
+ (acc, currentGroup) => acc.concat(currentGroup.panels.filter(this.chartHasData)),
+ [],
+ );
+ },
+ isSingleChart() {
+ return this.charts.length === 1;
+ },
+ embedClass() {
+ return this.isSingleChart ? this.containerClass : 'col-lg-12';
+ },
+ panelClass() {
+ return this.isSingleChart ? 'col-lg-12' : 'col-lg-6';
+ },
+ },
+ mounted() {
+ this.setInitialState();
+ this.setTimeRange(this.timeRange);
+ this.fetchDashboard();
+
+ sidebarMutationObserver = new MutationObserver(this.onSidebarMutation);
+ sidebarMutationObserver.observe(document.querySelector('.layout-page'), {
+ attributes: true,
+ childList: false,
+ subtree: false,
+ });
+ },
+ beforeDestroy() {
+ if (sidebarMutationObserver) {
+ sidebarMutationObserver.disconnect();
+ }
+ },
+ methods: {
+ // Use function args to support dynamic namespaces in mapXXX helpers. Pattern described
+ // in https://github.com/vuejs/vuex/issues/863#issuecomment-329510765
+ ...mapActions({
+ setTimeRange(dispatch, payload) {
+ return dispatch(`${this.namespace}/setTimeRange`, payload);
+ },
+ fetchDashboard(dispatch, payload) {
+ return dispatch(`${this.namespace}/fetchDashboard`, payload);
+ },
+ setEndpoints(dispatch, payload) {
+ return dispatch(`${this.namespace}/setEndpoints`, payload);
+ },
+ setFeatureFlags(dispatch, payload) {
+ return dispatch(`${this.namespace}/setFeatureFlags`, payload);
+ },
+ setShowErrorBanner(dispatch, payload) {
+ return dispatch(`${this.namespace}/setShowErrorBanner`, payload);
+ },
+ }),
+ chartHasData(chart) {
+ return chart.metrics.some(metric => this.metricsWithData.includes(metric.metricId));
+ },
+ onSidebarMutation() {
+ setTimeout(() => {
+ this.elWidth = this.$el.clientWidth;
+ }, sidebarAnimationDuration);
+ },
+ setInitialState() {
+ this.setEndpoints({
+ dashboardEndpoint: removeTimeRangeParams(this.dashboardUrl),
+ });
+ this.setShowErrorBanner(false);
+ },
+ },
+};
+</script>
+<template>
+ <div class="metrics-embed p-0 d-flex flex-wrap" :class="embedClass">
+ <panel-type
+ v-for="(graphData, graphIndex) in charts"
+ :key="`panel-type-${graphIndex}`"
+ :class="panelClass"
+ :graph-data="graphData"
+ :group-id="dashboardUrl"
+ :namespace="namespace"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue
index da305c7dda3..d6d60c2d5da 100644
--- a/app/assets/javascripts/monitoring/components/panel_type.vue
+++ b/app/assets/javascripts/monitoring/components/panel_type.vue
@@ -68,6 +68,11 @@ export default {
required: false,
default: 'panel-type-chart',
},
+ namespace: {
+ type: String,
+ required: false,
+ default: 'monitoringDashboard',
+ },
},
data() {
return {
@@ -76,7 +81,22 @@ export default {
};
},
computed: {
- ...mapState('monitoringDashboard', ['deploymentData', 'projectPath', 'logsPath', 'timeRange']),
+ // Use functions to support dynamic namespaces in mapXXX helpers. Pattern described
+ // in https://github.com/vuejs/vuex/issues/863#issuecomment-329510765
+ ...mapState({
+ deploymentData(state) {
+ return state[this.namespace].deploymentData;
+ },
+ projectPath(state) {
+ return state[this.namespace].projectPath;
+ },
+ logsPath(state) {
+ return state[this.namespace].logsPath;
+ },
+ timeRange(state) {
+ return state[this.namespace].timeRange;
+ },
+ }),
title() {
return this.graphData.title || '';
},