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> <script>
import { GlButton, GlDropdown, GlDropdownItem, GlLink } from '@gitlab/ui'; import {
GlButton,
GlDropdown,
GlDropdownItem,
GlModal,
GlModalDirective,
GlLink,
} from '@gitlab/ui';
import _ from 'underscore'; import _ from 'underscore';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
...@@ -27,8 +34,11 @@ export default { ...@@ -27,8 +34,11 @@ export default {
GlDropdown, GlDropdown,
GlDropdownItem, GlDropdownItem,
GlLink, GlLink,
GlModal,
},
directives: {
GlModalDirective,
}, },
props: { props: {
externalDashboardPath: { externalDashboardPath: {
type: String, type: String,
...@@ -102,6 +112,19 @@ export default { ...@@ -102,6 +112,19 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
customMetricsAvailable: {
type: Boolean,
required: false,
default: false,
},
customMetricsPath: {
type: String,
required: true,
},
validateQueryPath: {
type: String,
required: true,
},
}, },
data() { data() {
return { return {
...@@ -111,8 +134,14 @@ export default { ...@@ -111,8 +134,14 @@ export default {
elWidth: 0, elWidth: 0,
selectedTimeWindow: '', selectedTimeWindow: '',
selectedTimeWindowKey: '', selectedTimeWindowKey: '',
formIsValid: null,
}; };
}, },
computed: {
canAddMetrics() {
return this.customMetricsAvailable && this.customMetricsPath.length;
},
},
created() { created() {
this.service = new MonitoringService({ this.service = new MonitoringService({
metricsEndpoint: this.metricsEndpoint, metricsEndpoint: this.metricsEndpoint,
...@@ -193,11 +222,20 @@ export default { ...@@ -193,11 +222,20 @@ export default {
this.state = 'unableToConnect'; this.state = 'unableToConnect';
}); });
}, },
hideAddMetricModal() {
this.$refs.addMetricModal.hide();
},
onSidebarMutation() { onSidebarMutation() {
setTimeout(() => { setTimeout(() => {
this.elWidth = this.$el.clientWidth; this.elWidth = this.$el.clientWidth;
}, sidebarAnimationDuration); }, sidebarAnimationDuration);
}, },
setFormValidity(isValid) {
this.formIsValid = isValid;
},
submitCustomMetricsForm() {
this.$refs.customMetricsForm.submit();
},
activeTimeWindow(key) { activeTimeWindow(key) {
return this.timeWindows[key] === this.selectedTimeWindow; return this.timeWindows[key] === this.selectedTimeWindow;
}, },
...@@ -205,57 +243,97 @@ export default { ...@@ -205,57 +243,97 @@ export default {
return `?time_window=${key}`; return `?time_window=${key}`;
}, },
}, },
addMetric: {
title: s__('Metrics|Add metric'),
modalId: 'add-metric',
},
}; };
</script> </script>
<template> <template>
<div v-if="!showEmptyState" class="prometheus-graphs prepend-top-default"> <div v-if="!showEmptyState" class="prometheus-graphs">
<div <div class="gl-p-3 border-bottom bg-gray-light d-flex justify-content-between">
v-if="environmentsEndpoint" <div
class="dropdowns d-flex align-items-center justify-content-between" 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> <div class="d-flex align-items-center">
<gl-dropdown <strong>{{ s__('Metrics|Environment') }}</strong>
class="prepend-left-10 js-environments-dropdown" <gl-dropdown
toggle-class="dropdown-menu-toggle" class="prepend-left-10 js-environments-dropdown"
:text="currentEnvironmentName" toggle-class="dropdown-menu-toggle"
:disabled="store.environmentsData.length === 0" :text="currentEnvironmentName"
> :disabled="store.environmentsData.length === 0"
<gl-dropdown-item >
v-for="environment in store.environmentsData" <gl-dropdown-item
:key="environment.id" v-for="environment in store.environmentsData"
:href="environment.metrics_path" :key="environment.id"
:active="environment.name === currentEnvironmentName" :active="environment.name === currentEnvironmentName"
active-class="is-active" active-class="is-active"
>{{ environment.name }}</gl-dropdown-item >{{ 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>
<div v-if="showTimeWindowDropdown" class="d-flex align-items-center"> <div class="d-flex">
<strong>{{ s__('Metrics|Show last') }}</strong> <div v-if="isEE && canAddMetrics">
<gl-dropdown <gl-button
class="prepend-left-10 js-time-window-dropdown" v-gl-modal-directive="$options.addMetric.modalId"
toggle-class="dropdown-menu-toggle" class="js-add-metric-button text-success border-success"
: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> {{ $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> </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> </div>
<graph-group <graph-group
v-for="(groupData, index) in store.groups" v-for="(groupData, index) in store.groups"
......
...@@ -48,6 +48,10 @@ ...@@ -48,6 +48,10 @@
color: $brand-info; color: $brand-info;
} }
.bg-gray-light {
background-color: $gray-light;
}
.text-break-word { .text-break-word {
word-break: break-all; word-break: break-all;
} }
...@@ -446,19 +450,13 @@ img.emoji { ...@@ -446,19 +450,13 @@ img.emoji {
} }
/** COMMON SPACING CLASSES **/ /** COMMON SPACING CLASSES **/
.gl-pl-0 { padding-left: 0; } @each $index, $padding in $spacing-scale {
.gl-pl-1 { padding-left: #{0.5 * $grid-size}; } #{'.gl-p-#{$index}'} { padding: $padding; }
.gl-pl-2 { padding-left: $grid-size; } #{'.gl-pl-#{$index}'} { padding-left: $padding; }
.gl-pl-3 { padding-left: #{2 * $grid-size}; } #{'.gl-pr-#{$index}'} { padding-right: $padding; }
.gl-pl-4 { padding-left: #{3 * $grid-size}; } #{'.gl-pt-#{$index}'} { padding-top: $padding; }
.gl-pl-5 { padding-left: #{4 * $grid-size}; } #{'.gl-pb-#{$index}'} { padding-bottom: $padding; }
}
.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}; }
/** /**
* Removes browser specific clear icon from input fields in * Removes browser specific clear icon from input fields in
......
...@@ -11,6 +11,14 @@ $default-transition-duration: 0.15s; ...@@ -11,6 +11,14 @@ $default-transition-duration: 0.15s;
$contextual-sidebar-width: 220px; $contextual-sidebar-width: 220px;
$contextual-sidebar-collapsed-width: 50px; $contextual-sidebar-collapsed-width: 50px;
$toggle-sidebar-height: 48px; $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 * Color schema
......
...@@ -5911,6 +5911,9 @@ msgstr "" ...@@ -5911,6 +5911,9 @@ msgstr ""
msgid "Metrics for environment" msgid "Metrics for environment"
msgstr "" msgstr ""
msgid "Metrics|Add metric"
msgstr ""
msgid "Metrics|Check out the CI/CD documentation on deploying to an environment" msgid "Metrics|Check out the CI/CD documentation on deploying to an environment"
msgstr "" msgstr ""
......
...@@ -20,6 +20,9 @@ const propsData = { ...@@ -20,6 +20,9 @@ const propsData = {
emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg', emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg',
environmentsEndpoint: '/root/hello-prometheus/environments/35', environmentsEndpoint: '/root/hello-prometheus/environments/35',
currentEnvironmentName: 'production', currentEnvironmentName: 'production',
customMetricsAvailable: false,
customMetricsPath: '',
validateQueryPath: '',
}; };
export default propsData; export default propsData;
...@@ -163,7 +166,7 @@ describe('Dashboard', () => { ...@@ -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({ const component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'), el: document.querySelector('.prometheus-graphs'),
propsData: { propsData: {
...@@ -178,7 +181,7 @@ describe('Dashboard', () => { ...@@ -178,7 +181,7 @@ describe('Dashboard', () => {
setTimeout(() => { setTimeout(() => {
const dropdownItems = component.$el.querySelectorAll( const dropdownItems = component.$el.querySelectorAll(
'.js-environments-dropdown .dropdown-item.is-active', '.js-environments-dropdown .dropdown-item[active="true"]',
); );
expect(dropdownItems.length).toEqual(1); 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