Commit 63e757bf authored by Dhiraj Bodicherla's avatar Dhiraj Bodicherla

Add links section in metrics dashboard

User-defined links can be specific in dashboard
yml file. This MR renders links in the metrics
dashboard
parent c8f02855
<script> <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 { mapState } from 'vuex';
import { GlIcon, GlLink } from '@gitlab/ui'; import { GlIcon, GlLink } from '@gitlab/ui';
...@@ -21,15 +15,17 @@ export default { ...@@ -21,15 +15,17 @@ export default {
<template> <template>
<div <div
ref="linksSection" ref="linksSection"
class="d-sm-flex flex-sm-wrap gl-mt-3 gl-p-2 bg-gray-light border border-radius-default" class="gl-display-sm-flex gl-flex-sm-wrap gl-mt-5 gl-p-3 gl-bg-gray-10 border gl-rounded-base links-section"
> >
<div <div
v-for="(link, key) in links" v-for="(link, key) in links"
:key="key" :key="key"
class="gl-mb-1 gl-pr-3 d-flex d-sm-block text-break-word" class="gl-mb-1 gl-mr-5 gl-display-flex gl-display-sm-block gl-hover-text-blue-600-children gl-word-break-all"
> >
<gl-link :href="link.url" class="text-plain text-decoration-none" <gl-link :href="link.url" class="gl-text-gray-900 gl-text-decoration-none!"
><gl-icon name="link" class="align-text-bottom mr-1" />{{ link.title }} ><gl-icon name="link" class="gl-text-gray-700 gl-vertical-align-text-bottom gl-mr-2" />{{
link.title
}}
</gl-link> </gl-link>
</div> </div>
</div> </div>
......
...@@ -3,8 +3,6 @@ import * as types from './mutation_types'; ...@@ -3,8 +3,6 @@ import * as types from './mutation_types';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { convertToFixedRange } from '~/lib/utils/datetime_range'; import { convertToFixedRange } from '~/lib/utils/datetime_range';
import { parseTemplatingVariables } from './variable_mapping';
import { mergeURLVariables } from '../utils';
import { import {
gqClient, gqClient,
parseEnvironmentsResponse, parseEnvironmentsResponse,
...@@ -161,7 +159,6 @@ export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response ...@@ -161,7 +159,6 @@ export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response
commit(types.SET_ALL_DASHBOARDS, all_dashboards); commit(types.SET_ALL_DASHBOARDS, all_dashboards);
commit(types.RECEIVE_METRICS_DASHBOARD_SUCCESS, dashboard); commit(types.RECEIVE_METRICS_DASHBOARD_SUCCESS, dashboard);
commit(types.SET_VARIABLES, mergeURLVariables(parseTemplatingVariables(dashboard.templating)));
commit(types.SET_ENDPOINTS, convertObjectPropsToCamelCase(metrics_data)); commit(types.SET_ENDPOINTS, convertObjectPropsToCamelCase(metrics_data));
return dispatch('fetchDashboardData'); return dispatch('fetchDashboardData');
......
...@@ -61,8 +61,14 @@ export default { ...@@ -61,8 +61,14 @@ export default {
state.emptyState = 'loading'; state.emptyState = 'loading';
state.showEmptyState = true; state.showEmptyState = true;
}, },
[types.RECEIVE_METRICS_DASHBOARD_SUCCESS](state, dashboard) { [types.RECEIVE_METRICS_DASHBOARD_SUCCESS](state, dashboardYML) {
state.dashboard = mapToDashboardViewModel(dashboard); const { dashboard, panelGroups, variables, links } = mapToDashboardViewModel(dashboardYML);
state.dashboard = {
dashboard,
panelGroups,
};
state.variables = variables;
state.links = links;
if (!state.dashboard.panelGroups.length) { if (!state.dashboard.panelGroups.length) {
state.emptyState = 'noData'; state.emptyState = 'noData';
......
...@@ -2,6 +2,7 @@ import { slugify } from '~/lib/utils/text_utility'; ...@@ -2,6 +2,7 @@ import { slugify } from '~/lib/utils/text_utility';
import createGqClient, { fetchPolicies } from '~/lib/graphql'; import createGqClient, { fetchPolicies } from '~/lib/graphql';
import { SUPPORTED_FORMATS } from '~/lib/utils/unit_format'; import { SUPPORTED_FORMATS } from '~/lib/utils/unit_format';
import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { parseTemplatingVariables } from './variable_mapping';
import { NOT_IN_DB_PREFIX } from '../constants'; import { NOT_IN_DB_PREFIX } from '../constants';
import { isSafeURL } from '~/lib/utils/url_utility'; import { isSafeURL } from '~/lib/utils/url_utility';
...@@ -217,9 +218,16 @@ const mapToPanelGroupViewModel = ({ group = '', panels = [] }, i) => { ...@@ -217,9 +218,16 @@ const mapToPanelGroupViewModel = ({ group = '', panels = [] }, i) => {
* @param {Array} dashboard.panel_groups - Panel groups array * @param {Array} dashboard.panel_groups - Panel groups array
* @returns {Object} * @returns {Object}
*/ */
export const mapToDashboardViewModel = ({ dashboard = '', panel_groups = [] }) => { export const mapToDashboardViewModel = ({
dashboard = '',
templating = {},
links = [],
panel_groups = [],
}) => {
return { return {
dashboard, dashboard,
variables: parseTemplatingVariables(templating),
links: links.map(mapLinksToViewModel),
panelGroups: panel_groups.map(mapToPanelGroupViewModel), panelGroups: panel_groups.map(mapToPanelGroupViewModel),
}; };
}; };
......
...@@ -21,6 +21,14 @@ ...@@ -21,6 +21,14 @@
} }
} }
} }
.links-section {
.gl-hover-text-blue-600-children:hover {
* {
@include gl-text-blue-600;
}
}
}
} }
.draggable { .draggable {
......
---
title: Render user-defined links in dashboard yml file on metrics dashboard
merge_request: 32895
author:
type: added
...@@ -16,6 +16,7 @@ import DashboardsDropdown from '~/monitoring/components/dashboards_dropdown.vue' ...@@ -16,6 +16,7 @@ import DashboardsDropdown from '~/monitoring/components/dashboards_dropdown.vue'
import EmptyState from '~/monitoring/components/empty_state.vue'; import EmptyState from '~/monitoring/components/empty_state.vue';
import GroupEmptyState from '~/monitoring/components/group_empty_state.vue'; import GroupEmptyState from '~/monitoring/components/group_empty_state.vue';
import DashboardPanel from '~/monitoring/components/dashboard_panel.vue'; import DashboardPanel from '~/monitoring/components/dashboard_panel.vue';
import LinksSection from '~/monitoring/components/links_section.vue';
import { createStore } from '~/monitoring/stores'; import { createStore } from '~/monitoring/stores';
import * as types from '~/monitoring/stores/mutation_types'; import * as types from '~/monitoring/stores/mutation_types';
import { import {
...@@ -24,6 +25,7 @@ import { ...@@ -24,6 +25,7 @@ import {
setMetricResult, setMetricResult,
setupStoreWithData, setupStoreWithData,
setupStoreWithVariable, setupStoreWithVariable,
setupStoreWithLinks,
} from '../store_utils'; } from '../store_utils';
import { environmentData, dashboardGitResponse, propsData } from '../mock_data'; import { environmentData, dashboardGitResponse, propsData } from '../mock_data';
import { metricsDashboardViewModel, metricsDashboardPanelCount } from '../fixture_data'; import { metricsDashboardViewModel, metricsDashboardPanelCount } from '../fixture_data';
...@@ -483,6 +485,21 @@ describe('Dashboard', () => { ...@@ -483,6 +485,21 @@ describe('Dashboard', () => {
}); });
}); });
describe('links section', () => {
beforeEach(() => {
createShallowWrapper({ hasMetrics: true });
setupStoreWithData(store);
setupStoreWithLinks(store);
return wrapper.vm.$nextTick();
});
it('shows the links section', () => {
expect(wrapper.vm.shouldShowLinksSection).toBe(true);
expect(wrapper.find(LinksSection)).toExist();
});
});
describe('single panel expands to "full screen" mode', () => { describe('single panel expands to "full screen" mode', () => {
const findExpandedPanel = () => wrapper.find({ ref: 'expandedPanel' }); const findExpandedPanel = () => wrapper.find({ ref: 'expandedPanel' });
......
...@@ -16,6 +16,8 @@ describe('mapToDashboardViewModel', () => { ...@@ -16,6 +16,8 @@ describe('mapToDashboardViewModel', () => {
expect(mapToDashboardViewModel({})).toEqual({ expect(mapToDashboardViewModel({})).toEqual({
dashboard: '', dashboard: '',
panelGroups: [], panelGroups: [],
links: [],
variables: {},
}); });
}); });
...@@ -44,6 +46,8 @@ describe('mapToDashboardViewModel', () => { ...@@ -44,6 +46,8 @@ describe('mapToDashboardViewModel', () => {
expect(mapToDashboardViewModel(response)).toEqual({ expect(mapToDashboardViewModel(response)).toEqual({
dashboard: 'Dashboard Name', dashboard: 'Dashboard Name',
links: [],
variables: {},
panelGroups: [ panelGroups: [
{ {
group: 'Group 1', group: 'Group 1',
...@@ -76,6 +80,8 @@ describe('mapToDashboardViewModel', () => { ...@@ -76,6 +80,8 @@ describe('mapToDashboardViewModel', () => {
it('key', () => { it('key', () => {
const response = { const response = {
dashboard: 'Dashboard Name', dashboard: 'Dashboard Name',
links: [],
variables: {},
panel_groups: [ panel_groups: [
{ {
group: 'Group A', group: 'Group A',
......
...@@ -38,6 +38,18 @@ export const setupStoreWithVariable = store => { ...@@ -38,6 +38,18 @@ export const setupStoreWithVariable = store => {
}); });
}; };
export const setupStoreWithLinks = store => {
store.commit(`monitoringDashboard/${types.RECEIVE_METRICS_DASHBOARD_SUCCESS}`, {
...metricsDashboardPayload,
links: [
{
title: 'GitLab Website',
url: `https://gitlab.com/website`,
},
],
});
};
export const setupStoreWithData = store => { export const setupStoreWithData = store => {
setupAllDashboards(store); setupAllDashboards(store);
setupStoreWithDashboard(store); setupStoreWithDashboard(store);
......
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