summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue17
-rw-r--r--app/assets/javascripts/operation_settings/components/external_dashboard.vue57
-rw-r--r--app/assets/javascripts/operation_settings/index.js26
-rw-r--r--app/assets/javascripts/pages/projects/settings/operations/show/index.js2
-rw-r--r--app/controllers/projects/environments_controller.rb1
-rw-r--r--app/controllers/projects/settings/operations_controller.rb4
-rw-r--r--app/views/projects/settings/operations/_external_dashboard.html.haml2
-rw-r--r--app/views/projects/settings/operations/show.html.haml1
-rw-r--r--locale/gitlab.pot15
-rw-r--r--spec/frontend/operation_settings/components/external_dashboard_spec.js100
-rw-r--r--spec/javascripts/monitoring/dashboard_spec.js62
11 files changed, 286 insertions, 1 deletions
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 33f6afc9c2d..a2bf58d007c 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdown, GlDropdownItem, GlLink } from '@gitlab/ui';
+import { GlButton, GlDropdown, GlDropdownItem, GlLink } from '@gitlab/ui';
import _ from 'underscore';
import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
@@ -23,12 +23,18 @@ export default {
GraphGroup,
EmptyState,
Icon,
+ GlButton,
GlDropdown,
GlDropdownItem,
GlLink,
},
props: {
+ externalDashboardPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
hasMetrics: {
type: Boolean,
required: false,
@@ -241,6 +247,15 @@ export default {
>
</gl-dropdown>
</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"
diff --git a/app/assets/javascripts/operation_settings/components/external_dashboard.vue b/app/assets/javascripts/operation_settings/components/external_dashboard.vue
new file mode 100644
index 00000000000..0a87d193b72
--- /dev/null
+++ b/app/assets/javascripts/operation_settings/components/external_dashboard.vue
@@ -0,0 +1,57 @@
+<script>
+import { GlButton, GlFormGroup, GlFormInput, GlLink } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlButton,
+ GlFormGroup,
+ GlFormInput,
+ GlLink,
+ },
+ props: {
+ externalDashboardPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ externalDashboardHelpPagePath: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <section class="settings expanded">
+ <div class="settings-header">
+ <h4 class="js-section-header">
+ {{ s__('ExternalMetrics|External Dashboard') }}
+ </h4>
+ <p class="js-section-sub-header">
+ {{
+ s__(
+ 'ExternalMetrics|Add a button to the metrics dashboard linking directly to your existing external dashboards.',
+ )
+ }}
+ <gl-link :href="externalDashboardHelpPagePath">{{ __('Learn more') }}</gl-link>
+ </p>
+ </div>
+ <div class="settings-content">
+ <form>
+ <gl-form-group
+ :label="s__('ExternalMetrics|Full dashboard URL')"
+ :description="s__('ExternalMetrics|Enter the URL of the dashboard you want to link to')"
+ >
+ <gl-form-input
+ :value="externalDashboardPath"
+ placeholder="https://my-org.gitlab.io/my-dashboards"
+ />
+ </gl-form-group>
+ <gl-button variant="success">
+ {{ __('Save Changes') }}
+ </gl-button>
+ </form>
+ </div>
+ </section>
+</template>
diff --git a/app/assets/javascripts/operation_settings/index.js b/app/assets/javascripts/operation_settings/index.js
new file mode 100644
index 00000000000..1171f3ece9f
--- /dev/null
+++ b/app/assets/javascripts/operation_settings/index.js
@@ -0,0 +1,26 @@
+import Vue from 'vue';
+import ExternalDashboardForm from './components/external_dashboard.vue';
+
+export default () => {
+ /**
+ * This check can be removed when we remove
+ * the :grafana_dashboard_link feature flag
+ */
+ if (!gon.features.grafanaDashboardLink) {
+ return null;
+ }
+
+ const el = document.querySelector('.js-operation-settings');
+
+ return new Vue({
+ el,
+ render(createElement) {
+ return createElement(ExternalDashboardForm, {
+ props: {
+ ...el.dataset,
+ expanded: false,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/pages/projects/settings/operations/show/index.js b/app/assets/javascripts/pages/projects/settings/operations/show/index.js
index 73c745179be..5270a7924ec 100644
--- a/app/assets/javascripts/pages/projects/settings/operations/show/index.js
+++ b/app/assets/javascripts/pages/projects/settings/operations/show/index.js
@@ -1,5 +1,7 @@
import mountErrorTrackingForm from '~/error_tracking_settings';
+import mountOperationSettings from '~/operation_settings';
document.addEventListener('DOMContentLoaded', () => {
mountErrorTrackingForm();
+ mountOperationSettings();
});
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index d8812c023ca..5a4adea497b 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -14,6 +14,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
push_frontend_feature_flag(:metrics_time_window)
push_frontend_feature_flag(:environment_metrics_use_prometheus_endpoint)
push_frontend_feature_flag(:environment_metrics_show_multiple_dashboards)
+ push_frontend_feature_flag(:grafana_dashboard_link)
end
def index
diff --git a/app/controllers/projects/settings/operations_controller.rb b/app/controllers/projects/settings/operations_controller.rb
index 5cfb0ac307d..b5c77e5bbf4 100644
--- a/app/controllers/projects/settings/operations_controller.rb
+++ b/app/controllers/projects/settings/operations_controller.rb
@@ -5,6 +5,10 @@ module Projects
class OperationsController < Projects::ApplicationController
before_action :authorize_update_environment!
+ before_action do
+ push_frontend_feature_flag(:grafana_dashboard_link)
+ end
+
helper_method :error_tracking_setting
def show
diff --git a/app/views/projects/settings/operations/_external_dashboard.html.haml b/app/views/projects/settings/operations/_external_dashboard.html.haml
new file mode 100644
index 00000000000..2fbb9195a04
--- /dev/null
+++ b/app/views/projects/settings/operations/_external_dashboard.html.haml
@@ -0,0 +1,2 @@
+.js-operation-settings{ data: { external_dashboard: { path: '',
+ help_page_path: help_page_path('user/project/operations/link_to_external_dashboard') } } }
diff --git a/app/views/projects/settings/operations/show.html.haml b/app/views/projects/settings/operations/show.html.haml
index 6f777305a54..edc2c58a8ed 100644
--- a/app/views/projects/settings/operations/show.html.haml
+++ b/app/views/projects/settings/operations/show.html.haml
@@ -4,4 +4,5 @@
= render_if_exists 'projects/settings/operations/incidents'
= render 'projects/settings/operations/error_tracking', expanded: true
+= render 'projects/settings/operations/external_dashboard'
= render_if_exists 'projects/settings/operations/tracing'
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 43c88848126..05e56f2b89d 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4115,6 +4115,18 @@ msgstr ""
msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
msgstr ""
+msgid "ExternalMetrics|Add a button to the metrics dashboard linking directly to your existing external dashboards."
+msgstr ""
+
+msgid "ExternalMetrics|Enter the URL of the dashboard you want to link to"
+msgstr ""
+
+msgid "ExternalMetrics|External Dashboard"
+msgstr ""
+
+msgid "ExternalMetrics|Full dashboard URL"
+msgstr ""
+
msgid "ExternalWikiService|External Wiki"
msgstr ""
@@ -10565,6 +10577,9 @@ msgstr ""
msgid "View file @ "
msgstr ""
+msgid "View full dashboard"
+msgstr ""
+
msgid "View group labels"
msgstr ""
diff --git a/spec/frontend/operation_settings/components/external_dashboard_spec.js b/spec/frontend/operation_settings/components/external_dashboard_spec.js
new file mode 100644
index 00000000000..de1dd219fe0
--- /dev/null
+++ b/spec/frontend/operation_settings/components/external_dashboard_spec.js
@@ -0,0 +1,100 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlButton, GlLink, GlFormGroup, GlFormInput } from '@gitlab/ui';
+import ExternalDashboard from '~/operation_settings/components/external_dashboard.vue';
+import { TEST_HOST } from 'helpers/test_constants';
+
+describe('operation settings external dashboard component', () => {
+ let wrapper;
+ const externalDashboardPath = `http://mock-external-domain.com/external/dashboard/path`;
+ const externalDashboardHelpPagePath = `${TEST_HOST}/help/page/path`;
+
+ beforeEach(() => {
+ wrapper = shallowMount(ExternalDashboard, {
+ propsData: {
+ externalDashboardPath,
+ externalDashboardHelpPagePath,
+ },
+ });
+ });
+
+ it('renders header text', () => {
+ expect(wrapper.find('.js-section-header').text()).toBe('External Dashboard');
+ });
+
+ describe('sub-header', () => {
+ let subHeader;
+
+ beforeEach(() => {
+ subHeader = wrapper.find('.js-section-sub-header');
+ });
+
+ it('renders descriptive text', () => {
+ expect(subHeader.text()).toContain(
+ 'Add a button to the metrics dashboard linking directly to your existing external dashboards.',
+ );
+ });
+
+ it('renders help page link', () => {
+ const link = subHeader.find(GlLink);
+
+ expect(link.text()).toBe('Learn more');
+ expect(link.attributes().href).toBe(externalDashboardHelpPagePath);
+ });
+ });
+
+ describe('form', () => {
+ let form;
+
+ beforeEach(() => {
+ form = wrapper.find('form');
+ });
+
+ describe('external dashboard url', () => {
+ describe('input label', () => {
+ let formGroup;
+
+ beforeEach(() => {
+ formGroup = form.find(GlFormGroup);
+ });
+
+ it('uses label text', () => {
+ expect(formGroup.attributes().label).toBe('Full dashboard URL');
+ });
+
+ it('uses description text', () => {
+ expect(formGroup.attributes().description).toBe(
+ 'Enter the URL of the dashboard you want to link to',
+ );
+ });
+ });
+
+ describe('input field', () => {
+ let input;
+
+ beforeEach(() => {
+ input = form.find(GlFormInput);
+ });
+
+ it('defaults to externalDashboardPath prop', () => {
+ expect(input.attributes().value).toBe(externalDashboardPath);
+ });
+
+ it('uses a placeholder', () => {
+ expect(input.attributes().placeholder).toBe('https://my-org.gitlab.io/my-dashboards');
+ });
+ });
+
+ describe('submit button', () => {
+ let submit;
+
+ beforeEach(() => {
+ submit = form.find(GlButton);
+ });
+
+ it('renders button label', () => {
+ expect(submit.text()).toBe('Save Changes');
+ });
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js
index 5c28840d3a4..fc722867b0b 100644
--- a/spec/javascripts/monitoring/dashboard_spec.js
+++ b/spec/javascripts/monitoring/dashboard_spec.js
@@ -37,6 +37,9 @@ describe('Dashboard', () => {
window.gon = {
...window.gon,
ee: false,
+ features: {
+ grafanaDashboardLink: true,
+ },
};
mock = new MockAdapter(axios);
@@ -323,4 +326,63 @@ describe('Dashboard', () => {
.catch(done.fail);
});
});
+
+ describe('external dashboard link', () => {
+ let component;
+
+ beforeEach(() => {
+ mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
+ });
+
+ afterEach(() => {
+ component.$destroy();
+ });
+
+ describe('with feature flag enabled', () => {
+ beforeEach(() => {
+ component = new DashboardComponent({
+ el: document.querySelector('.prometheus-graphs'),
+ propsData: {
+ ...propsData,
+ hasMetrics: true,
+ showPanels: false,
+ showTimeWindowDropdown: false,
+ externalDashboardPath: '/mockPath',
+ },
+ });
+ });
+
+ it('shows the link', done => {
+ setTimeout(() => {
+ expect(component.$el.querySelector('.js-external-dashboard-link').innerText).toContain(
+ 'View full dashboard',
+ );
+ done();
+ });
+ });
+ });
+
+ describe('without feature flage enabled', () => {
+ beforeEach(() => {
+ window.gon.features.grafanaDashboardLink = false;
+ component = new DashboardComponent({
+ el: document.querySelector('.prometheus-graphs'),
+ propsData: {
+ ...propsData,
+ hasMetrics: true,
+ showPanels: false,
+ showTimeWindowDropdown: false,
+ externalDashboardPath: '',
+ },
+ });
+ });
+
+ it('does not show the link', done => {
+ setTimeout(() => {
+ expect(component.$el.querySelector('.js-external-dashboard-link')).toBe(null);
+ done();
+ });
+ });
+ });
+ });
});