Commit 78d3f94c authored by Adriel Santiago's avatar Adriel Santiago Committed by Clement Ho

Add custom metrics form to dashboard

Use existing form to allow users to add custom metrics via the dashboard
parent f6ca3b1a
<script>
import { GlButton, GlDropdown, GlDropdownItem, GlLink } from '@gitlab/ui';
import {
GlButton,
GlDropdown,
GlDropdownItem,
GlModal,
GlModalDirective,
GlLink,
} from '@gitlab/ui';
import _ from 'underscore';
import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
......@@ -27,8 +34,11 @@ export default {
GlDropdown,
GlDropdownItem,
GlLink,
GlModal,
},
directives: {
GlModalDirective,
},
props: {
externalDashboardPath: {
type: String,
......@@ -102,6 +112,19 @@ export default {
type: Boolean,
required: true,
},
customMetricsAvailable: {
type: Boolean,
required: false,
default: false,
},
customMetricsPath: {
type: String,
required: true,
},
validateQueryPath: {
type: String,
required: true,
},
},
data() {
return {
......@@ -111,8 +134,14 @@ export default {
elWidth: 0,
selectedTimeWindow: '',
selectedTimeWindowKey: '',
formIsValid: null,
};
},
computed: {
canAddMetrics() {
return this.customMetricsAvailable && this.customMetricsPath.length;
},
},
created() {
this.service = new MonitoringService({
metricsEndpoint: this.metricsEndpoint,
......@@ -193,11 +222,20 @@ export default {
this.state = 'unableToConnect';
});
},
hideAddMetricModal() {
this.$refs.addMetricModal.hide();
},
onSidebarMutation() {
setTimeout(() => {
this.elWidth = this.$el.clientWidth;
}, sidebarAnimationDuration);
},
setFormValidity(isValid) {
this.formIsValid = isValid;
},
submitCustomMetricsForm() {
this.$refs.customMetricsForm.submit();
},
activeTimeWindow(key) {
return this.timeWindows[key] === this.selectedTimeWindow;
},
......@@ -205,57 +243,97 @@ export default {
return `?time_window=${key}`;
},
},
addMetric: {
title: s__('Metrics|Add metric'),
modalId: 'add-metric',
},
};
</script>
<template>
<div v-if="!showEmptyState" class="prometheus-graphs prepend-top-default">
<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"
>
<gl-dropdown-item
v-for="environment in store.environmentsData"
:key="environment.id"
:href="environment.metrics_path"
:active="environment.name === currentEnvironmentName"
active-class="is-active"
>{{ environment.name }}</gl-dropdown-item
<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"
>
<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>
<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>
</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
<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"
>
</gl-dropdown>
{{ $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>
</div>
<gl-button
v-if="externalDashboardPath.length"
class="js-external-dashboard-link"
variant="primary"
:href="externalDashboardPath"
>
{{ __('View full dashboard') }}
<icon name="external-link" />
</gl-button>
</div>
<graph-group
v-for="(groupData, index) in store.groups"
......
......@@ -48,6 +48,10 @@
color: $brand-info;
}
.bg-gray-light {
background-color: $gray-light;
}
.text-break-word {
word-break: break-all;
}
......@@ -446,19 +450,13 @@ img.emoji {
}
/** COMMON SPACING CLASSES **/
.gl-pl-0 { padding-left: 0; }
.gl-pl-1 { padding-left: #{0.5 * $grid-size}; }
.gl-pl-2 { padding-left: $grid-size; }
.gl-pl-3 { padding-left: #{2 * $grid-size}; }
.gl-pl-4 { padding-left: #{3 * $grid-size}; }
.gl-pl-5 { padding-left: #{4 * $grid-size}; }
.gl-pr-0 { padding-right: 0; }
.gl-pr-1 { padding-right: #{0.5 * $grid-size}; }
.gl-pr-2 { padding-right: $grid-size; }
.gl-pr-3 { padding-right: #{2 * $grid-size}; }
.gl-pr-4 { padding-right: #{3 * $grid-size}; }
.gl-pr-5 { padding-right: #{4 * $grid-size}; }
@each $index, $padding in $spacing-scale {
#{'.gl-p-#{$index}'} { padding: $padding; }
#{'.gl-pl-#{$index}'} { padding-left: $padding; }
#{'.gl-pr-#{$index}'} { padding-right: $padding; }
#{'.gl-pt-#{$index}'} { padding-top: $padding; }
#{'.gl-pb-#{$index}'} { padding-bottom: $padding; }
}
/**
* Removes browser specific clear icon from input fields in
......
......@@ -11,6 +11,14 @@ $default-transition-duration: 0.15s;
$contextual-sidebar-width: 220px;
$contextual-sidebar-collapsed-width: 50px;
$toggle-sidebar-height: 48px;
$spacing-scale: (
0: 0,
1: #{0.5 * $grid-size},
2: $grid-size,
3: #{2 * $grid-size},
4: #{3 * $grid-size},
5: #{4 * $grid-size}
);
/*
* Color schema
......
......@@ -5911,6 +5911,9 @@ msgstr ""
msgid "Metrics for environment"
msgstr ""
msgid "Metrics|Add metric"
msgstr ""
msgid "Metrics|Check out the CI/CD documentation on deploying to an environment"
msgstr ""
......
......@@ -20,6 +20,9 @@ const propsData = {
emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg',
environmentsEndpoint: '/root/hello-prometheus/environments/35',
currentEnvironmentName: 'production',
customMetricsAvailable: false,
customMetricsPath: '',
validateQueryPath: '',
};
export default propsData;
......@@ -163,7 +166,7 @@ describe('Dashboard', () => {
});
});
it('renders the environments dropdown with a single is-active element', done => {
it('renders the environments dropdown with a single active element', done => {
const component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
......@@ -178,7 +181,7 @@ describe('Dashboard', () => {
setTimeout(() => {
const dropdownItems = component.$el.querySelectorAll(
'.js-environments-dropdown .dropdown-item.is-active',
'.js-environments-dropdown .dropdown-item[active="true"]',
);
expect(dropdownItems.length).toEqual(1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment