Commit 14d0e17e authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'support-grafana-links-in-metrics-dashboard' into 'master'

Support grafana links

See merge request gitlab-org/gitlab!34003
parents 3d7cf2f6 88c404a9
export const BYTES_IN_KIB = 1024;
export const HIDDEN_CLASS = 'hidden';
export const DATETIME_RANGE_TYPES = {
fixed: 'fixed',
anchored: 'anchored',
rolling: 'rolling',
open: 'open',
invalid: 'invalid',
};
import dateformat from 'dateformat';
import { pick, omit, isEqual, isEmpty } from 'lodash';
import { DATETIME_RANGE_TYPES } from './constants';
import { secondsToMilliseconds } from './datetime_utility';
const MINIMUM_DATE = new Date(0);
......@@ -153,18 +154,22 @@ export function getRangeType(range) {
const { start, end, anchor, duration } = range;
if ((start || end) && !anchor && !duration) {
return isValidDateString(start) && isValidDateString(end) ? 'fixed' : 'invalid';
return isValidDateString(start) && isValidDateString(end)
? DATETIME_RANGE_TYPES.fixed
: DATETIME_RANGE_TYPES.invalid;
}
if (anchor && duration) {
return isValidDateString(anchor) && isValidDuration(duration) ? 'anchored' : 'invalid';
return isValidDateString(anchor) && isValidDuration(duration)
? DATETIME_RANGE_TYPES.anchored
: DATETIME_RANGE_TYPES.invalid;
}
if (duration && !anchor) {
return isValidDuration(duration) ? 'rolling' : 'invalid';
return isValidDuration(duration) ? DATETIME_RANGE_TYPES.rolling : DATETIME_RANGE_TYPES.invalid;
}
if (anchor && !duration) {
return isValidDateString(anchor) ? 'open' : 'invalid';
return isValidDateString(anchor) ? DATETIME_RANGE_TYPES.open : DATETIME_RANGE_TYPES.invalid;
}
return 'invalid';
return DATETIME_RANGE_TYPES.invalid;
}
/**
......
......@@ -127,6 +127,14 @@ export const lineWidths = {
default: 2,
};
/**
* User-defined links can be passed in dashboard yml file.
* These are the supported type of links.
*/
export const linkTypes = {
GRAFANA: 'grafana',
};
/**
* These Vuex store properties are allowed to be
* replaced dynamically after component has been created
......
......@@ -3,8 +3,9 @@ import createGqClient, { fetchPolicies } from '~/lib/graphql';
import { SUPPORTED_FORMATS } from '~/lib/utils/unit_format';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { parseTemplatingVariables } from './variable_mapping';
import { NOT_IN_DB_PREFIX } from '../constants';
import { timeRangeToParams } from '~/lib/utils/datetime_range';
import { NOT_IN_DB_PREFIX, linkTypes } from '../constants';
import { DATETIME_RANGE_TYPES } from '~/lib/utils/constants';
import { timeRangeToParams, getRangeType } from '~/lib/utils/datetime_range';
import { isSafeURL, mergeUrlParams } from '~/lib/utils/url_utility';
export const gqClient = createGqClient(
......@@ -147,12 +148,13 @@ const mapYAxisToViewModel = ({
* Unsafe URLs are ignored.
*
* @param {Object} Link
* @returns {Object} Link object with a `title` and `url`.
* @returns {Object} Link object with a `title`, `url` and `type`
*
*/
const mapLinksToViewModel = ({ url = null, title = '' } = {}) => {
const mapLinksToViewModel = ({ url = null, title = '', type } = {}) => {
return {
title: title || String(url),
type,
url: url && isSafeURL(url) ? String(url) : '#',
};
};
......@@ -211,6 +213,46 @@ const mapToPanelGroupViewModel = ({ group = '', panels = [] }, i) => {
};
};
/**
* Convert dashboard time range to Grafana
* dashboards time range.
*
* @param {Object} timeRange
* @returns {Object}
*/
export const convertToGrafanaTimeRange = timeRange => {
const timeRangeType = getRangeType(timeRange);
if (timeRangeType === DATETIME_RANGE_TYPES.fixed) {
return {
from: new Date(timeRange.start).getTime(),
to: new Date(timeRange.end).getTime(),
};
} else if (timeRangeType === DATETIME_RANGE_TYPES.rolling) {
const { seconds } = timeRange.duration;
return {
from: `now-${seconds}s`,
to: 'now',
};
}
// fallback to returning the time range as is
return timeRange;
};
/**
* Convert dashboard time ranges to other supported
* link formats.
*
* @param {Object} timeRange metrics dashboard time range
* @param {String} type type of link
* @returns {String}
*/
export const convertTimeRanges = (timeRange, type) => {
if (type === linkTypes.GRAFANA) {
return convertToGrafanaTimeRange(timeRange);
}
return timeRangeToParams(timeRange);
};
/**
* Adds dashboard-related metadata to the user-defined links.
*
......@@ -225,7 +267,7 @@ export const addDashboardMetaDataToLink = metadata => link => {
if (metadata.timeRange) {
modifiedLink = {
...modifiedLink,
url: mergeUrlParams(timeRangeToParams(metadata.timeRange), link.url),
url: mergeUrlParams(convertTimeRanges(metadata.timeRange, link.type), link.url),
};
}
return modifiedLink;
......
---
title: Support user-defined Grafana links in metrics dashboard
merge_request: 34003
author:
type: added
......@@ -6,6 +6,8 @@ import {
removeLeadingSlash,
mapToDashboardViewModel,
normalizeQueryResult,
convertToGrafanaTimeRange,
addDashboardMetaDataToLink,
} from '~/monitoring/stores/utils';
import { annotationsData } from '../mock_data';
import { NOT_IN_DB_PREFIX } from '~/monitoring/constants';
......@@ -522,3 +524,86 @@ describe('removeLeadingSlash', () => {
});
});
});
describe('user-defined links utils', () => {
const mockRelativeTimeRange = {
metricsDashboard: {
duration: {
seconds: 86400,
},
},
grafana: {
from: 'now-86400s',
to: 'now',
},
};
const mockAbsoluteTimeRange = {
metricsDashboard: {
start: '2020-06-08T16:13:01.995Z',
end: '2020-06-08T21:12:32.243Z',
},
grafana: {
from: 1591632781995,
to: 1591650752243,
},
};
describe('convertToGrafanaTimeRange', () => {
it('converts relative timezone to grafana timezone', () => {
expect(convertToGrafanaTimeRange(mockRelativeTimeRange.metricsDashboard)).toEqual(
mockRelativeTimeRange.grafana,
);
});
it('converts absolute timezone to grafana timezone', () => {
expect(convertToGrafanaTimeRange(mockAbsoluteTimeRange.metricsDashboard)).toEqual(
mockAbsoluteTimeRange.grafana,
);
});
});
describe('addDashboardMetaDataToLink', () => {
const link = { title: 'title', url: 'https://gitlab.com' };
const grafanaLink = { ...link, type: 'grafana' };
it('adds relative time range to link w/o type for metrics dashboards', () => {
const adder = addDashboardMetaDataToLink({
timeRange: mockRelativeTimeRange.metricsDashboard,
});
expect(adder(link)).toMatchObject({
title: 'title',
url: 'https://gitlab.com?duration_seconds=86400',
});
});
it('adds relative time range to Grafana type links', () => {
const adder = addDashboardMetaDataToLink({
timeRange: mockRelativeTimeRange.metricsDashboard,
});
expect(adder(grafanaLink)).toMatchObject({
title: 'title',
url: 'https://gitlab.com?from=now-86400s&to=now',
});
});
it('adds absolute time range to link w/o type for metrics dashboard', () => {
const adder = addDashboardMetaDataToLink({
timeRange: mockAbsoluteTimeRange.metricsDashboard,
});
expect(adder(link)).toMatchObject({
title: 'title',
url:
'https://gitlab.com?start=2020-06-08T16%3A13%3A01.995Z&end=2020-06-08T21%3A12%3A32.243Z',
});
});
it('adds absolute time range to Grafana type links', () => {
const adder = addDashboardMetaDataToLink({
timeRange: mockAbsoluteTimeRange.metricsDashboard,
});
expect(adder(grafanaLink)).toMatchObject({
title: 'title',
url: 'https://gitlab.com?from=1591632781995&to=1591650752243',
});
});
});
});
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