2018-03-17 18:26:18 +05:30
|
|
|
<script>
|
2019-07-31 22:56:46 +05:30
|
|
|
import {
|
|
|
|
GlButton,
|
|
|
|
GlDropdown,
|
|
|
|
GlDropdownItem,
|
|
|
|
GlModal,
|
|
|
|
GlModalDirective,
|
|
|
|
GlLink,
|
|
|
|
} from '@gitlab/ui';
|
2019-07-07 11:18:12 +05:30
|
|
|
import _ from 'underscore';
|
2018-11-08 19:23:39 +05:30
|
|
|
import { s__ } from '~/locale';
|
|
|
|
import Icon from '~/vue_shared/components/icon.vue';
|
2019-07-07 11:18:12 +05:30
|
|
|
import '~/vue_shared/mixins/is_ee';
|
2019-07-31 22:56:46 +05:30
|
|
|
import { getParameterValues } from '~/lib/utils/url_utility';
|
2018-05-09 12:01:36 +05:30
|
|
|
import Flash from '../../flash';
|
|
|
|
import MonitoringService from '../services/monitoring_service';
|
2019-02-15 15:39:39 +05:30
|
|
|
import MonitorAreaChart from './charts/area.vue';
|
2018-05-09 12:01:36 +05:30
|
|
|
import GraphGroup from './graph_group.vue';
|
|
|
|
import EmptyState from './empty_state.vue';
|
|
|
|
import MonitoringStore from '../stores/monitoring_store';
|
2019-07-31 22:56:46 +05:30
|
|
|
import { timeWindows, timeWindowsKeyNames } from '../constants';
|
2019-07-07 11:18:12 +05:30
|
|
|
import { getTimeDiff } from '../utils';
|
2019-03-02 22:35:43 +05:30
|
|
|
|
|
|
|
const sidebarAnimationDuration = 150;
|
|
|
|
let sidebarMutationObserver;
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
export default {
|
|
|
|
components: {
|
2019-02-15 15:39:39 +05:30
|
|
|
MonitorAreaChart,
|
2018-05-09 12:01:36 +05:30
|
|
|
GraphGroup,
|
|
|
|
EmptyState,
|
2018-11-08 19:23:39 +05:30
|
|
|
Icon,
|
2019-07-31 22:56:46 +05:30
|
|
|
GlButton,
|
2019-07-07 11:18:12 +05:30
|
|
|
GlDropdown,
|
|
|
|
GlDropdownItem,
|
2019-07-31 22:56:46 +05:30
|
|
|
GlLink,
|
|
|
|
GlModal,
|
|
|
|
},
|
|
|
|
directives: {
|
|
|
|
GlModalDirective,
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
props: {
|
2019-07-31 22:56:46 +05:30
|
|
|
externalDashboardPath: {
|
|
|
|
type: String,
|
|
|
|
required: false,
|
|
|
|
default: '',
|
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
hasMetrics: {
|
|
|
|
type: Boolean,
|
|
|
|
required: false,
|
|
|
|
default: true,
|
2018-03-17 18:26:18 +05:30
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
showPanels: {
|
|
|
|
type: Boolean,
|
|
|
|
required: false,
|
|
|
|
default: true,
|
2018-03-17 18:26:18 +05:30
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
documentationPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
2018-03-17 18:26:18 +05:30
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
settingsPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
clustersPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
tagsPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
projectPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
metricsEndpoint: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
deploymentEndpoint: {
|
|
|
|
type: String,
|
|
|
|
required: false,
|
|
|
|
default: null,
|
|
|
|
},
|
|
|
|
emptyGettingStartedSvgPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
emptyLoadingSvgPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
emptyNoDataSvgPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
emptyUnableToConnectSvgPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
2018-11-08 19:23:39 +05:30
|
|
|
environmentsEndpoint: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
currentEnvironmentName: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
2019-07-07 11:18:12 +05:30
|
|
|
showTimeWindowDropdown: {
|
|
|
|
type: Boolean,
|
|
|
|
required: true,
|
|
|
|
},
|
2019-07-31 22:56:46 +05:30
|
|
|
customMetricsAvailable: {
|
|
|
|
type: Boolean,
|
|
|
|
required: false,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
customMetricsPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
validateQueryPath: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
store: new MonitoringStore(),
|
|
|
|
state: 'gettingStarted',
|
|
|
|
showEmptyState: true,
|
2018-12-05 23:21:45 +05:30
|
|
|
elWidth: 0,
|
2019-07-07 11:18:12 +05:30
|
|
|
selectedTimeWindow: '',
|
2019-07-31 22:56:46 +05:30
|
|
|
selectedTimeWindowKey: '',
|
|
|
|
formIsValid: null,
|
2018-05-09 12:01:36 +05:30
|
|
|
};
|
|
|
|
},
|
2019-07-31 22:56:46 +05:30
|
|
|
computed: {
|
|
|
|
canAddMetrics() {
|
|
|
|
return this.customMetricsAvailable && this.customMetricsPath.length;
|
|
|
|
},
|
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
created() {
|
|
|
|
this.service = new MonitoringService({
|
|
|
|
metricsEndpoint: this.metricsEndpoint,
|
|
|
|
deploymentEndpoint: this.deploymentEndpoint,
|
2018-11-08 19:23:39 +05:30
|
|
|
environmentsEndpoint: this.environmentsEndpoint,
|
2018-05-09 12:01:36 +05:30
|
|
|
});
|
2019-07-07 11:18:12 +05:30
|
|
|
this.timeWindows = timeWindows;
|
2019-07-31 22:56:46 +05:30
|
|
|
this.selectedTimeWindowKey =
|
|
|
|
_.escape(getParameterValues('time_window')[0]) || timeWindowsKeyNames.eightHours;
|
|
|
|
|
|
|
|
// Set default time window if the selectedTimeWindowKey is bogus
|
|
|
|
if (!Object.keys(this.timeWindows).includes(this.selectedTimeWindowKey)) {
|
|
|
|
this.selectedTimeWindowKey = timeWindowsKeyNames.eightHours;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.selectedTimeWindow = this.timeWindows[this.selectedTimeWindowKey];
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
beforeDestroy() {
|
2019-03-02 22:35:43 +05:30
|
|
|
if (sidebarMutationObserver) {
|
|
|
|
sidebarMutationObserver.disconnect();
|
|
|
|
}
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
mounted() {
|
2019-07-31 22:56:46 +05:30
|
|
|
const startEndWindow = getTimeDiff(this.timeWindows[this.selectedTimeWindowKey]);
|
2019-07-07 11:18:12 +05:30
|
|
|
this.servicePromises = [
|
|
|
|
this.service
|
2019-07-31 22:56:46 +05:30
|
|
|
.getGraphsData(startEndWindow)
|
2019-07-07 11:18:12 +05:30
|
|
|
.then(data => this.store.storeMetrics(data))
|
|
|
|
.catch(() => Flash(s__('Metrics|There was an error while retrieving metrics'))),
|
|
|
|
this.service
|
|
|
|
.getDeploymentData()
|
|
|
|
.then(data => this.store.storeDeploymentData(data))
|
|
|
|
.catch(() => Flash(s__('Metrics|There was an error getting deployment information.'))),
|
|
|
|
];
|
2018-05-09 12:01:36 +05:30
|
|
|
if (!this.hasMetrics) {
|
|
|
|
this.state = 'gettingStarted';
|
|
|
|
} else {
|
2019-07-07 11:18:12 +05:30
|
|
|
if (this.environmentsEndpoint) {
|
|
|
|
this.servicePromises.push(
|
|
|
|
this.service
|
|
|
|
.getEnvironmentsData()
|
|
|
|
.then(data => this.store.storeEnvironmentsData(data))
|
|
|
|
.catch(() =>
|
|
|
|
Flash(s__('Metrics|There was an error getting environments information.')),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
2018-05-09 12:01:36 +05:30
|
|
|
this.getGraphsData();
|
2019-03-02 22:35:43 +05:30
|
|
|
sidebarMutationObserver = new MutationObserver(this.onSidebarMutation);
|
|
|
|
sidebarMutationObserver.observe(document.querySelector('.layout-page'), {
|
|
|
|
attributes: true,
|
|
|
|
childList: false,
|
|
|
|
subtree: false,
|
|
|
|
});
|
2018-05-09 12:01:36 +05:30
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
2019-07-07 11:18:12 +05:30
|
|
|
getGraphAlerts(queries) {
|
|
|
|
if (!this.allAlerts) return {};
|
|
|
|
const metricIdsForChart = queries.map(q => q.metricId);
|
|
|
|
return _.pick(this.allAlerts, alert => metricIdsForChart.includes(alert.metricId));
|
|
|
|
},
|
|
|
|
getGraphAlertValues(queries) {
|
|
|
|
return Object.values(this.getGraphAlerts(queries));
|
2019-02-15 15:39:39 +05:30
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
getGraphsData() {
|
|
|
|
this.state = 'loading';
|
2019-07-07 11:18:12 +05:30
|
|
|
Promise.all(this.servicePromises)
|
2018-05-09 12:01:36 +05:30
|
|
|
.then(() => {
|
|
|
|
if (this.store.groups.length < 1) {
|
|
|
|
this.state = 'noData';
|
|
|
|
return;
|
|
|
|
}
|
2018-12-13 13:39:08 +05:30
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
this.showEmptyState = false;
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
this.state = 'unableToConnect';
|
|
|
|
});
|
|
|
|
},
|
2019-07-31 22:56:46 +05:30
|
|
|
hideAddMetricModal() {
|
|
|
|
this.$refs.addMetricModal.hide();
|
2019-07-07 11:18:12 +05:30
|
|
|
},
|
2019-03-02 22:35:43 +05:30
|
|
|
onSidebarMutation() {
|
|
|
|
setTimeout(() => {
|
|
|
|
this.elWidth = this.$el.clientWidth;
|
|
|
|
}, sidebarAnimationDuration);
|
2018-03-17 18:26:18 +05:30
|
|
|
},
|
2019-07-31 22:56:46 +05:30
|
|
|
setFormValidity(isValid) {
|
|
|
|
this.formIsValid = isValid;
|
|
|
|
},
|
|
|
|
submitCustomMetricsForm() {
|
|
|
|
this.$refs.customMetricsForm.submit();
|
|
|
|
},
|
2019-07-07 11:18:12 +05:30
|
|
|
activeTimeWindow(key) {
|
|
|
|
return this.timeWindows[key] === this.selectedTimeWindow;
|
|
|
|
},
|
2019-07-31 22:56:46 +05:30
|
|
|
setTimeWindowParameter(key) {
|
|
|
|
return `?time_window=${key}`;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
addMetric: {
|
|
|
|
title: s__('Metrics|Add metric'),
|
|
|
|
modalId: 'add-metric',
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
};
|
2018-03-17 18:26:18 +05:30
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
2019-07-31 22:56:46 +05:30
|
|
|
<div v-if="!showEmptyState" class="prometheus-graphs">
|
|
|
|
<div class="gl-p-3 border-bottom bg-gray-light d-flex justify-content-between">
|
|
|
|
<div
|
|
|
|
v-if="environmentsEndpoint"
|
|
|
|
class="dropdowns d-flex align-items-center justify-content-between"
|
|
|
|
>
|
|
|
|
<div class="d-flex align-items-center">
|
|
|
|
<strong>{{ s__('Metrics|Environment') }}</strong>
|
|
|
|
<gl-dropdown
|
|
|
|
class="prepend-left-10 js-environments-dropdown"
|
|
|
|
toggle-class="dropdown-menu-toggle"
|
|
|
|
:text="currentEnvironmentName"
|
|
|
|
:disabled="store.environmentsData.length === 0"
|
2019-07-07 11:18:12 +05:30
|
|
|
>
|
2019-07-31 22:56:46 +05:30
|
|
|
<gl-dropdown-item
|
|
|
|
v-for="environment in store.environmentsData"
|
|
|
|
:key="environment.id"
|
|
|
|
:active="environment.name === currentEnvironmentName"
|
|
|
|
active-class="is-active"
|
|
|
|
>{{ environment.name }}</gl-dropdown-item
|
|
|
|
>
|
|
|
|
</gl-dropdown>
|
|
|
|
</div>
|
|
|
|
<div v-if="showTimeWindowDropdown" class="d-flex align-items-center">
|
|
|
|
<strong>{{ s__('Metrics|Show last') }}</strong>
|
|
|
|
<gl-dropdown
|
|
|
|
class="prepend-left-10 js-time-window-dropdown"
|
|
|
|
toggle-class="dropdown-menu-toggle"
|
|
|
|
:text="selectedTimeWindow"
|
|
|
|
>
|
|
|
|
<gl-dropdown-item
|
|
|
|
v-for="(value, key) in timeWindows"
|
|
|
|
:key="key"
|
|
|
|
:active="activeTimeWindow(key)"
|
|
|
|
><gl-link :href="setTimeWindowParameter(key)">{{ value }}</gl-link></gl-dropdown-item
|
|
|
|
>
|
|
|
|
</gl-dropdown>
|
|
|
|
</div>
|
2019-07-07 11:18:12 +05:30
|
|
|
</div>
|
2019-07-31 22:56:46 +05:30
|
|
|
<div class="d-flex">
|
|
|
|
<div v-if="isEE && canAddMetrics">
|
|
|
|
<gl-button
|
|
|
|
v-gl-modal-directive="$options.addMetric.modalId"
|
|
|
|
class="js-add-metric-button text-success border-success"
|
2019-07-07 11:18:12 +05:30
|
|
|
>
|
2019-07-31 22:56:46 +05:30
|
|
|
{{ $options.addMetric.title }}
|
|
|
|
</gl-button>
|
|
|
|
<gl-modal
|
|
|
|
ref="addMetricModal"
|
|
|
|
:modal-id="$options.addMetric.modalId"
|
|
|
|
:title="$options.addMetric.title"
|
|
|
|
>
|
|
|
|
<form ref="customMetricsForm" :action="customMetricsPath" method="post">
|
|
|
|
<custom-metrics-form-fields
|
|
|
|
:validate-query-path="validateQueryPath"
|
|
|
|
form-operation="post"
|
|
|
|
@formValidation="setFormValidity"
|
|
|
|
/>
|
|
|
|
</form>
|
|
|
|
<div slot="modal-footer">
|
|
|
|
<gl-button @click="hideAddMetricModal">
|
|
|
|
{{ __('Cancel') }}
|
|
|
|
</gl-button>
|
|
|
|
<gl-button
|
|
|
|
:disabled="!formIsValid"
|
|
|
|
variant="success"
|
|
|
|
@click="submitCustomMetricsForm"
|
|
|
|
>
|
|
|
|
{{ __('Save changes') }}
|
|
|
|
</gl-button>
|
|
|
|
</div>
|
|
|
|
</gl-modal>
|
|
|
|
</div>
|
|
|
|
<gl-button
|
|
|
|
v-if="externalDashboardPath.length"
|
|
|
|
class="js-external-dashboard-link prepend-left-8"
|
|
|
|
variant="primary"
|
|
|
|
:href="externalDashboardPath"
|
|
|
|
>
|
|
|
|
{{ __('View full dashboard') }}
|
|
|
|
<icon name="external-link" />
|
|
|
|
</gl-button>
|
2018-11-08 19:23:39 +05:30
|
|
|
</div>
|
|
|
|
</div>
|
2018-03-17 18:26:18 +05:30
|
|
|
<graph-group
|
|
|
|
v-for="(groupData, index) in store.groups"
|
|
|
|
:key="index"
|
|
|
|
:name="groupData.group"
|
2018-03-27 19:54:05 +05:30
|
|
|
:show-panels="showPanels"
|
2018-03-17 18:26:18 +05:30
|
|
|
>
|
2019-03-02 22:35:43 +05:30
|
|
|
<monitor-area-chart
|
2018-12-05 23:21:45 +05:30
|
|
|
v-for="(graphData, graphIndex) in groupData.metrics"
|
|
|
|
:key="graphIndex"
|
2018-03-17 18:26:18 +05:30
|
|
|
:graph-data="graphData"
|
|
|
|
:deployment-data="store.deploymentData"
|
2019-07-07 11:18:12 +05:30
|
|
|
:thresholds="getGraphAlertValues(graphData.queries)"
|
2019-03-02 22:35:43 +05:30
|
|
|
:container-width="elWidth"
|
2019-02-15 15:39:39 +05:30
|
|
|
group-id="monitor-area-chart"
|
2019-07-07 11:18:12 +05:30
|
|
|
>
|
|
|
|
<alert-widget
|
|
|
|
v-if="isEE && prometheusAlertsAvailable && alertsEndpoint && graphData"
|
|
|
|
:alerts-endpoint="alertsEndpoint"
|
|
|
|
:relevant-queries="graphData.queries"
|
|
|
|
:alerts-to-manage="getGraphAlerts(graphData.queries)"
|
|
|
|
@setAlerts="setAlerts"
|
|
|
|
/>
|
|
|
|
</monitor-area-chart>
|
2018-03-17 18:26:18 +05:30
|
|
|
</graph-group>
|
|
|
|
</div>
|
|
|
|
<empty-state
|
|
|
|
v-else
|
|
|
|
:selected-state="state"
|
|
|
|
:documentation-path="documentationPath"
|
|
|
|
:settings-path="settingsPath"
|
|
|
|
:clusters-path="clustersPath"
|
|
|
|
:empty-getting-started-svg-path="emptyGettingStartedSvgPath"
|
|
|
|
:empty-loading-svg-path="emptyLoadingSvgPath"
|
2018-05-09 12:01:36 +05:30
|
|
|
:empty-no-data-svg-path="emptyNoDataSvgPath"
|
2018-03-17 18:26:18 +05:30
|
|
|
:empty-unable-to-connect-svg-path="emptyUnableToConnectSvgPath"
|
|
|
|
/>
|
|
|
|
</template>
|