Commit 7b7c25ed authored by Paul Slaughter's avatar Paul Slaughter

Merge branch 'jivanvl-use-metrics-url-query-param' into 'master'

Filter out custom variables from Url

See merge request gitlab-org/gitlab!30560
parents 4b8e359c f49b7225
...@@ -4,6 +4,7 @@ import Dashboard from '~/monitoring/components/dashboard.vue'; ...@@ -4,6 +4,7 @@ import Dashboard from '~/monitoring/components/dashboard.vue';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import { getParameterValues } from '~/lib/utils/url_utility'; import { getParameterValues } from '~/lib/utils/url_utility';
import store from './stores'; import store from './stores';
import { promCustomVariablesFromUrl } from './utils';
Vue.use(GlToast); Vue.use(GlToast);
...@@ -13,6 +14,8 @@ export default (props = {}) => { ...@@ -13,6 +14,8 @@ export default (props = {}) => {
if (el && el.dataset) { if (el && el.dataset) {
const [currentDashboard] = getParameterValues('dashboard'); const [currentDashboard] = getParameterValues('dashboard');
store.dispatch('monitoringDashboard/setVariables', promCustomVariablesFromUrl());
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Vue({ new Vue({
el, el,
......
...@@ -80,6 +80,10 @@ export const setTimeRange = ({ commit }, timeRange) => { ...@@ -80,6 +80,10 @@ export const setTimeRange = ({ commit }, timeRange) => {
commit(types.SET_TIME_RANGE, timeRange); commit(types.SET_TIME_RANGE, timeRange);
}; };
export const setVariables = ({ commit }, variables) => {
commit(types.SET_PROM_QUERY_VARIABLES, variables);
};
export const filterEnvironments = ({ commit, dispatch }, searchTerm) => { export const filterEnvironments = ({ commit, dispatch }, searchTerm) => {
commit(types.SET_ENVIRONMENTS_FILTER, searchTerm); commit(types.SET_ENVIRONMENTS_FILTER, searchTerm);
dispatch('fetchEnvironmentsData'); dispatch('fetchEnvironmentsData');
...@@ -218,12 +222,16 @@ export const fetchDashboardData = ({ state, dispatch, getters }) => { ...@@ -218,12 +222,16 @@ export const fetchDashboardData = ({ state, dispatch, getters }) => {
* *
* @param {metric} metric * @param {metric} metric
*/ */
export const fetchPrometheusMetric = ({ commit }, { metric, defaultQueryParams }) => { export const fetchPrometheusMetric = ({ commit, state }, { metric, defaultQueryParams }) => {
const queryParams = { ...defaultQueryParams }; const queryParams = { ...defaultQueryParams };
if (metric.step) { if (metric.step) {
queryParams.step = metric.step; queryParams.step = metric.step;
} }
if (state.promVariables.length > 0) {
queryParams.variables = state.promVariables;
}
commit(types.REQUEST_METRIC_RESULT, { metricId: metric.metricId }); commit(types.REQUEST_METRIC_RESULT, { metricId: metric.metricId });
return getPrometheusMetricResult(metric.prometheusEndpointPath, queryParams) return getPrometheusMetricResult(metric.prometheusEndpointPath, queryParams)
......
// Dashboard "skeleton", groups, panels and metrics // Dashboard "skeleton", groups, panels, metrics, query variables
export const REQUEST_METRICS_DASHBOARD = 'REQUEST_METRICS_DASHBOARD'; export const REQUEST_METRICS_DASHBOARD = 'REQUEST_METRICS_DASHBOARD';
export const RECEIVE_METRICS_DASHBOARD_SUCCESS = 'RECEIVE_METRICS_DASHBOARD_SUCCESS'; export const RECEIVE_METRICS_DASHBOARD_SUCCESS = 'RECEIVE_METRICS_DASHBOARD_SUCCESS';
export const RECEIVE_METRICS_DASHBOARD_FAILURE = 'RECEIVE_METRICS_DASHBOARD_FAILURE'; export const RECEIVE_METRICS_DASHBOARD_FAILURE = 'RECEIVE_METRICS_DASHBOARD_FAILURE';
export const SET_PROM_QUERY_VARIABLES = 'SET_PROM_QUERY_VARIABLES';
// Annotations // Annotations
export const RECEIVE_ANNOTATIONS_SUCCESS = 'RECEIVE_ANNOTATIONS_SUCCESS'; export const RECEIVE_ANNOTATIONS_SUCCESS = 'RECEIVE_ANNOTATIONS_SUCCESS';
......
...@@ -51,6 +51,18 @@ const emptyStateFromError = error => { ...@@ -51,6 +51,18 @@ const emptyStateFromError = error => {
return metricStates.UNKNOWN_ERROR; return metricStates.UNKNOWN_ERROR;
}; };
/**
* Maps an variables object to an array
* @returns {Array} The custom variables array to be send to the API
* in the format of [variable1, variable1_value]
* @param {Object} variables - Custom variables provided by the user
*/
const transformVariablesObjectArray = variables =>
Object.entries(variables)
.flat()
.map(encodeURIComponent);
export default { export default {
/** /**
* Dashboard panels structure and global state * Dashboard panels structure and global state
...@@ -169,4 +181,7 @@ export default { ...@@ -169,4 +181,7 @@ export default {
state.expandedPanel.group = group; state.expandedPanel.group = group;
state.expandedPanel.panel = panel; state.expandedPanel.panel = panel;
}, },
[types.SET_PROM_QUERY_VARIABLES](state, variables) {
state.promVariables = transformVariablesObjectArray(variables);
},
}; };
...@@ -33,6 +33,7 @@ export default () => ({ ...@@ -33,6 +33,7 @@ export default () => ({
panel: null, panel: null,
}, },
allDashboards: [], allDashboards: [],
promVariables: [],
// Other project data // Other project data
annotations: [], annotations: [],
......
import { omit } from 'lodash';
import { queryToObject, mergeUrlParams, removeParams } from '~/lib/utils/url_utility'; import { queryToObject, mergeUrlParams, removeParams } from '~/lib/utils/url_utility';
import { import {
timeRangeParamNames, timeRangeParamNames,
...@@ -5,6 +6,13 @@ import { ...@@ -5,6 +6,13 @@ import {
timeRangeToParams, timeRangeToParams,
} from '~/lib/utils/datetime_range'; } from '~/lib/utils/datetime_range';
/**
* List of non time range url parameters
* This will be removed once we add support for free text variables
* via the dashboard yaml files in https://gitlab.com/gitlab-org/gitlab/-/issues/215689
*/
export const dashboardParams = ['dashboard', 'group', 'title', 'y_label'];
/** /**
* This method is used to validate if the graph data format for a chart component * This method is used to validate if the graph data format for a chart component
* that needs a time series as a response from a prometheus query (queryRange) is * that needs a time series as a response from a prometheus query (queryRange) is
...@@ -113,6 +121,21 @@ export const timeRangeFromUrl = (search = window.location.search) => { ...@@ -113,6 +121,21 @@ export const timeRangeFromUrl = (search = window.location.search) => {
return timeRangeFromParams(params); return timeRangeFromParams(params);
}; };
/**
* Returns an array with user defined variables from the URL
*
* @returns {Array} The custom variables defined by the
* user in the URL
* @param {String} New URL
*/
export const promCustomVariablesFromUrl = (search = window.location.search) => {
const params = queryToObject(search);
const paramsToRemove = timeRangeParamNames.concat(dashboardParams);
return omit(params, paramsToRemove);
};
/** /**
* Returns a URL with no time range based on the current URL. * Returns a URL with no time range based on the current URL.
* *
......
---
title: In metrics dashboard use custom variables from URL in queries
merge_request: 30560
author:
type: added
...@@ -25,6 +25,7 @@ import { ...@@ -25,6 +25,7 @@ import {
clearExpandedPanel, clearExpandedPanel,
setGettingStartedEmptyState, setGettingStartedEmptyState,
duplicateSystemDashboard, duplicateSystemDashboard,
setVariables,
} from '~/monitoring/stores/actions'; } from '~/monitoring/stores/actions';
import { import {
gqClient, gqClient,
...@@ -392,6 +393,29 @@ describe('Monitoring store actions', () => { ...@@ -392,6 +393,29 @@ describe('Monitoring store actions', () => {
); );
}); });
}); });
describe('setVariables', () => {
let mockedState;
beforeEach(() => {
mockedState = storeState();
});
it('should commit SET_PROM_QUERY_VARIABLES mutation', done => {
testAction(
setVariables,
{ pod: 'POD' },
mockedState,
[
{
type: types.SET_PROM_QUERY_VARIABLES,
payload: { pod: 'POD' },
},
],
[],
done,
);
});
});
describe('fetchDashboard', () => { describe('fetchDashboard', () => {
let dispatch; let dispatch;
let state; let state;
......
...@@ -364,4 +364,18 @@ describe('Monitoring mutations', () => { ...@@ -364,4 +364,18 @@ describe('Monitoring mutations', () => {
expect(stateCopy.expandedPanel.panel).toEqual(null); expect(stateCopy.expandedPanel.panel).toEqual(null);
}); });
}); });
describe('SET_PROM_QUERY_VARIABLES', () => {
it('stores an empty variables array when no custom variables are given', () => {
mutations[types.SET_PROM_QUERY_VARIABLES](stateCopy, {});
expect(stateCopy.promVariables).toEqual([]);
});
it('stores variables in the key key_value format in the array', () => {
mutations[types.SET_PROM_QUERY_VARIABLES](stateCopy, { pod: 'POD', stage: 'main ops' });
expect(stateCopy.promVariables).toEqual(['pod', 'POD', 'stage', 'main%20ops']);
});
});
}); });
...@@ -169,6 +169,43 @@ describe('monitoring/utils', () => { ...@@ -169,6 +169,43 @@ describe('monitoring/utils', () => {
}); });
}); });
describe('promCustomVariablesFromUrl', () => {
const { promCustomVariablesFromUrl } = monitoringUtils;
beforeEach(() => {
jest.spyOn(urlUtils, 'queryToObject');
});
afterEach(() => {
urlUtils.queryToObject.mockRestore();
});
it('returns an object with only the custom variables', () => {
urlUtils.queryToObject.mockReturnValueOnce({
dashboard: '.gitlab/dashboards/custom_dashboard.yml',
y_label: 'memory usage',
group: 'kubernetes',
title: 'Kubernetes memory total',
start: '2020-05-06',
end: '2020-05-07',
duration_seconds: '86400',
direction: 'left',
anchor: 'top',
pod: 'POD',
});
expect(promCustomVariablesFromUrl()).toEqual(expect.objectContaining({ pod: 'POD' }));
});
it('returns an empty object when no custom variables are present', () => {
urlUtils.queryToObject.mockReturnValueOnce({
dashboard: '.gitlab/dashboards/custom_dashboard.yml',
});
expect(promCustomVariablesFromUrl()).toStrictEqual({});
});
});
describe('removeTimeRangeParams', () => { describe('removeTimeRangeParams', () => {
const { removeTimeRangeParams } = monitoringUtils; const { removeTimeRangeParams } = monitoringUtils;
......
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