Commit 3de27184 authored by Dhiraj Bodicherla's avatar Dhiraj Bodicherla Committed by Andrew Fontaine

Support user-defined links in metrics dashboard

This MR parses user-defined links in metrics dashboards
and saves to Vuex store. This MR creates a links section
Vue component but does not use it yet. Also, backend
support for links validation is added
parent cf05dc9b
...@@ -15,6 +15,7 @@ import GraphGroup from './graph_group.vue'; ...@@ -15,6 +15,7 @@ import GraphGroup from './graph_group.vue';
import EmptyState from './empty_state.vue'; import EmptyState from './empty_state.vue';
import GroupEmptyState from './group_empty_state.vue'; import GroupEmptyState from './group_empty_state.vue';
import VariablesSection from './variables_section.vue'; import VariablesSection from './variables_section.vue';
import LinksSection from './links_section.vue';
import TrackEventDirective from '~/vue_shared/directives/track_event'; import TrackEventDirective from '~/vue_shared/directives/track_event';
import { import {
...@@ -38,6 +39,7 @@ export default { ...@@ -38,6 +39,7 @@ export default {
EmptyState, EmptyState,
GroupEmptyState, GroupEmptyState,
VariablesSection, VariablesSection,
LinksSection,
}, },
directives: { directives: {
GlModal: GlModalDirective, GlModal: GlModalDirective,
...@@ -154,12 +156,16 @@ export default { ...@@ -154,12 +156,16 @@ export default {
'showEmptyState', 'showEmptyState',
'expandedPanel', 'expandedPanel',
'variables', 'variables',
'links',
'currentDashboard', 'currentDashboard',
]), ]),
...mapGetters('monitoringDashboard', ['selectedDashboard', 'getMetricStates']), ...mapGetters('monitoringDashboard', ['selectedDashboard', 'getMetricStates']),
shouldShowVariablesSection() { shouldShowVariablesSection() {
return Object.keys(this.variables).length > 0; return Object.keys(this.variables).length > 0;
}, },
shouldShowLinksSection() {
return Object.keys(this.links).length > 0;
},
}, },
watch: { watch: {
dashboard(newDashboard) { dashboard(newDashboard) {
...@@ -309,6 +315,7 @@ export default { ...@@ -309,6 +315,7 @@ export default {
@setRearrangingPanels="onSetRearrangingPanels" @setRearrangingPanels="onSetRearrangingPanels"
/> />
<variables-section v-if="shouldShowVariablesSection && !showEmptyState" /> <variables-section v-if="shouldShowVariablesSection && !showEmptyState" />
<links-section v-if="shouldShowLinksSection && !showEmptyState" />
<div v-if="!showEmptyState"> <div v-if="!showEmptyState">
<dashboard-panel <dashboard-panel
v-show="expandedPanel.panel" v-show="expandedPanel.panel"
......
<script>
/**
* This component generates user-defined links in the
* dashboard yml file. However, this component will be
* used in the metrics dashboard after
* https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32895
*/
import { mapState } from 'vuex';
import { GlIcon, GlLink } from '@gitlab/ui';
export default {
components: {
GlIcon,
GlLink,
},
computed: {
...mapState('monitoringDashboard', ['links']),
},
};
</script>
<template>
<div
ref="linksSection"
class="d-sm-flex flex-sm-wrap gl-mt-3 gl-p-2 bg-gray-light border border-radius-default"
>
<div
v-for="(link, key) in links"
:key="key"
class="gl-mb-1 gl-pr-3 d-flex d-sm-block text-break-word"
>
<gl-link :href="link.url" class="text-plain text-decoration-none"
><gl-icon name="link" class="align-text-bottom mr-1" />{{ link.title }}
</gl-link>
</div>
</div>
</template>
...@@ -36,10 +36,14 @@ export default () => ({ ...@@ -36,10 +36,14 @@ export default () => ({
allDashboards: [], allDashboards: [],
/** /**
* User-defined custom variables are passed * User-defined custom variables are passed
* via the dashboard.yml file. * via the dashboard yml file.
*/ */
variables: {}, variables: {},
/**
* User-defined custom links are passed
* via the dashboard yml file.
*/
links: {},
// Other project data // Other project data
annotations: [], annotations: [],
deploymentData: [], deploymentData: [],
......
...@@ -4,7 +4,7 @@ module PerformanceMonitoring ...@@ -4,7 +4,7 @@ module PerformanceMonitoring
class PrometheusDashboard class PrometheusDashboard
include ActiveModel::Model include ActiveModel::Model
attr_accessor :dashboard, :panel_groups, :path, :environment, :priority, :templating attr_accessor :dashboard, :panel_groups, :path, :environment, :priority, :templating, :links
validates :dashboard, presence: true validates :dashboard, presence: true
validates :panel_groups, presence: true validates :panel_groups, presence: true
......
...@@ -132,6 +132,8 @@ exports[`Dashboard template matches the default snapshot 1`] = ` ...@@ -132,6 +132,8 @@ exports[`Dashboard template matches the default snapshot 1`] = `
<!----> <!---->
<!---->
<empty-state-stub <empty-state-stub
clusterspath="/path/to/clusters" clusterspath="/path/to/clusters"
documentationpath="/path/to/docs" documentationpath="/path/to/docs"
......
import { shallowMount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui';
import { createStore } from '~/monitoring/stores';
import LinksSection from '~/monitoring/components/links_section.vue';
describe('Links Section component', () => {
let store;
let wrapper;
const createShallowWrapper = () => {
wrapper = shallowMount(LinksSection, {
store,
});
};
const setState = links => {
store.state.monitoringDashboard = {
...store.state.monitoringDashboard,
showEmptyState: false,
links,
};
};
const findLinks = () => wrapper.findAll(GlLink);
beforeEach(() => {
store = createStore();
createShallowWrapper();
});
it('does not render a section if no links are present', () => {
setState();
return wrapper.vm.$nextTick(() => {
expect(findLinks()).not.toExist();
});
});
it('renders a link inside a section', () => {
setState([
{
title: 'GitLab Website',
url: 'https://gitlab.com',
},
]);
return wrapper.vm.$nextTick(() => {
expect(findLinks()).toHaveLength(1);
const firstLink = findLinks().at(0);
expect(firstLink.attributes('href')).toBe('https://gitlab.com');
expect(firstLink.text()).toBe('GitLab Website');
});
});
it('renders multiple links inside a section', () => {
const links = new Array(10)
.fill(null)
.map((_, i) => ({ title: `Title ${i}`, url: `https://gitlab.com/projects/${i}` }));
setState(links);
return wrapper.vm.$nextTick(() => {
expect(findLinks()).toHaveLength(10);
});
});
});
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