summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/monitoring/stores
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 11:18:50 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 11:18:50 +0000
commit8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch)
treea77e7fe7a93de11213032ed4ab1f33a3db51b738 /app/assets/javascripts/monitoring/stores
parent00b35af3db1abfe813a778f643dad221aad51fca (diff)
downloadgitlab-ce-8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781.tar.gz
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'app/assets/javascripts/monitoring/stores')
-rw-r--r--app/assets/javascripts/monitoring/stores/actions.js16
-rw-r--r--app/assets/javascripts/monitoring/stores/getters.js22
-rw-r--r--app/assets/javascripts/monitoring/stores/index.js12
-rw-r--r--app/assets/javascripts/monitoring/stores/mutation_types.js2
-rw-r--r--app/assets/javascripts/monitoring/stores/mutations.js26
-rw-r--r--app/assets/javascripts/monitoring/stores/state.js17
-rw-r--r--app/assets/javascripts/monitoring/stores/utils.js110
-rw-r--r--app/assets/javascripts/monitoring/stores/variable_mapping.js2
8 files changed, 172 insertions, 35 deletions
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js
index 9e3edfb495d..3a9cccec438 100644
--- a/app/assets/javascripts/monitoring/stores/actions.js
+++ b/app/assets/javascripts/monitoring/stores/actions.js
@@ -3,8 +3,6 @@ import * as types from './mutation_types';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import { convertToFixedRange } from '~/lib/utils/datetime_range';
-import { parseTemplatingVariables } from './variable_mapping';
-import { mergeURLVariables } from '../utils';
import {
gqClient,
parseEnvironmentsResponse,
@@ -161,7 +159,6 @@ export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response
commit(types.SET_ALL_DASHBOARDS, all_dashboards);
commit(types.RECEIVE_METRICS_DASHBOARD_SUCCESS, dashboard);
- commit(types.SET_VARIABLES, mergeURLVariables(parseTemplatingVariables(dashboard.templating)));
commit(types.SET_ENDPOINTS, convertObjectPropsToCamelCase(metrics_data));
return dispatch('fetchDashboardData');
@@ -223,7 +220,7 @@ export const fetchPrometheusMetric = (
queryParams.step = metric.step;
}
- if (Object.keys(state.promVariables).length > 0) {
+ if (Object.keys(state.variables).length > 0) {
queryParams = {
...queryParams,
...getters.getCustomVariablesParams,
@@ -317,8 +314,7 @@ export const receiveEnvironmentsDataFailure = ({ commit }) => {
export const fetchAnnotations = ({ state, dispatch }) => {
const { start } = convertToFixedRange(state.timeRange);
- const dashboardPath =
- state.currentDashboard === '' ? DEFAULT_DASHBOARD_PATH : state.currentDashboard;
+ const dashboardPath = state.currentDashboard || DEFAULT_DASHBOARD_PATH;
return gqClient
.mutate({
mutation: getAnnotations,
@@ -373,7 +369,7 @@ export const toggleStarredValue = ({ commit, state, getters }) => {
method,
})
.then(() => {
- commit(types.RECEIVE_DASHBOARD_STARRING_SUCCESS, newStarredValue);
+ commit(types.RECEIVE_DASHBOARD_STARRING_SUCCESS, { selectedDashboard, newStarredValue });
})
.catch(() => {
commit(types.RECEIVE_DASHBOARD_STARRING_FAILURE);
@@ -419,8 +415,10 @@ export const duplicateSystemDashboard = ({ state }, payload) => {
// Variables manipulation
-export const updateVariableValues = ({ commit }, updatedVariable) => {
- commit(types.UPDATE_VARIABLE_VALUES, updatedVariable);
+export const updateVariablesAndFetchData = ({ commit, dispatch }, updatedVariable) => {
+ commit(types.UPDATE_VARIABLES, updatedVariable);
+
+ return dispatch('fetchDashboardData');
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
diff --git a/app/assets/javascripts/monitoring/stores/getters.js b/app/assets/javascripts/monitoring/stores/getters.js
index f309addee6b..b7681012472 100644
--- a/app/assets/javascripts/monitoring/stores/getters.js
+++ b/app/assets/javascripts/monitoring/stores/getters.js
@@ -1,5 +1,5 @@
import { NOT_IN_DB_PREFIX } from '../constants';
-import { addPrefixToCustomVariableParams } from './utils';
+import { addPrefixToCustomVariableParams, addDashboardMetaDataToLink } from './utils';
const metricsIdsInPanel = panel =>
panel.metrics.filter(metric => metric.metricId && metric.result).map(metric => metric.metricId);
@@ -113,6 +113,22 @@ export const filteredEnvironments = state =>
);
/**
+ * User-defined links from the yml file can have other
+ * dashboard-related metadata baked into it. This method
+ * returns modified links which will get rendered in the
+ * metrics dashboard
+ *
+ * @param {Object} state
+ * @returns {Array} modified array of links
+ */
+export const linksWithMetadata = state => {
+ const metadata = {
+ timeRange: state.timeRange,
+ };
+ return state.links?.map(addDashboardMetaDataToLink(metadata));
+};
+
+/**
* Maps an variables object to an array along with stripping
* the variable prefix.
*
@@ -133,8 +149,8 @@ export const filteredEnvironments = state =>
*/
export const getCustomVariablesParams = state =>
- Object.keys(state.promVariables).reduce((acc, variable) => {
- acc[addPrefixToCustomVariableParams(variable)] = state.promVariables[variable]?.value;
+ Object.keys(state.variables).reduce((acc, variable) => {
+ acc[addPrefixToCustomVariableParams(variable)] = state.variables[variable]?.value;
return acc;
}, {});
diff --git a/app/assets/javascripts/monitoring/stores/index.js b/app/assets/javascripts/monitoring/stores/index.js
index f08a6402aa6..213a8508aa2 100644
--- a/app/assets/javascripts/monitoring/stores/index.js
+++ b/app/assets/javascripts/monitoring/stores/index.js
@@ -15,11 +15,15 @@ export const monitoringDashboard = {
state,
};
-export const createStore = () =>
+export const createStore = (initState = {}) =>
new Vuex.Store({
modules: {
- monitoringDashboard,
+ monitoringDashboard: {
+ ...monitoringDashboard,
+ state: {
+ ...state(),
+ ...initState,
+ },
+ },
},
});
-
-export default createStore();
diff --git a/app/assets/javascripts/monitoring/stores/mutation_types.js b/app/assets/javascripts/monitoring/stores/mutation_types.js
index d60334609fd..4593461776b 100644
--- a/app/assets/javascripts/monitoring/stores/mutation_types.js
+++ b/app/assets/javascripts/monitoring/stores/mutation_types.js
@@ -3,7 +3,7 @@ export const REQUEST_METRICS_DASHBOARD = 'REQUEST_METRICS_DASHBOARD';
export const RECEIVE_METRICS_DASHBOARD_SUCCESS = 'RECEIVE_METRICS_DASHBOARD_SUCCESS';
export const RECEIVE_METRICS_DASHBOARD_FAILURE = 'RECEIVE_METRICS_DASHBOARD_FAILURE';
export const SET_VARIABLES = 'SET_VARIABLES';
-export const UPDATE_VARIABLE_VALUES = 'UPDATE_VARIABLE_VALUES';
+export const UPDATE_VARIABLES = 'UPDATE_VARIABLES';
export const REQUEST_DASHBOARD_STARRING = 'REQUEST_DASHBOARD_STARRING';
export const RECEIVE_DASHBOARD_STARRING_SUCCESS = 'RECEIVE_DASHBOARD_STARRING_SUCCESS';
diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js
index f41cf3fc477..2d63fdd6e34 100644
--- a/app/assets/javascripts/monitoring/stores/mutations.js
+++ b/app/assets/javascripts/monitoring/stores/mutations.js
@@ -1,7 +1,6 @@
import Vue from 'vue';
import { pick } from 'lodash';
import * as types from './mutation_types';
-import { selectedDashboard } from './getters';
import { mapToDashboardViewModel, normalizeQueryResult } from './utils';
import { BACKOFF_TIMEOUT } from '../../lib/utils/common_utils';
import { endpointKeys, initialStateKeys, metricStates } from '../constants';
@@ -61,8 +60,14 @@ export default {
state.emptyState = 'loading';
state.showEmptyState = true;
},
- [types.RECEIVE_METRICS_DASHBOARD_SUCCESS](state, dashboard) {
- state.dashboard = mapToDashboardViewModel(dashboard);
+ [types.RECEIVE_METRICS_DASHBOARD_SUCCESS](state, dashboardYML) {
+ const { dashboard, panelGroups, variables, links } = mapToDashboardViewModel(dashboardYML);
+ state.dashboard = {
+ dashboard,
+ panelGroups,
+ };
+ state.variables = variables;
+ state.links = links;
if (!state.dashboard.panelGroups.length) {
state.emptyState = 'noData';
@@ -76,15 +81,14 @@ export default {
[types.REQUEST_DASHBOARD_STARRING](state) {
state.isUpdatingStarredValue = true;
},
- [types.RECEIVE_DASHBOARD_STARRING_SUCCESS](state, newStarredValue) {
- const dashboard = selectedDashboard(state);
- const index = state.allDashboards.findIndex(d => d === dashboard);
+ [types.RECEIVE_DASHBOARD_STARRING_SUCCESS](state, { selectedDashboard, newStarredValue }) {
+ const index = state.allDashboards.findIndex(d => d === selectedDashboard);
state.isUpdatingStarredValue = false;
// Trigger state updates in the reactivity system for this change
// https://vuejs.org/v2/guide/reactivity.html#For-Arrays
- Vue.set(state.allDashboards, index, { ...dashboard, starred: newStarredValue });
+ Vue.set(state.allDashboards, index, { ...selectedDashboard, starred: newStarredValue });
},
[types.RECEIVE_DASHBOARD_STARRING_FAILURE](state) {
state.isUpdatingStarredValue = false;
@@ -189,11 +193,11 @@ export default {
state.expandedPanel.panel = panel;
},
[types.SET_VARIABLES](state, variables) {
- state.promVariables = variables;
+ state.variables = variables;
},
- [types.UPDATE_VARIABLE_VALUES](state, updatedVariable) {
- Object.assign(state.promVariables[updatedVariable.key], {
- ...state.promVariables[updatedVariable.key],
+ [types.UPDATE_VARIABLES](state, updatedVariable) {
+ Object.assign(state.variables[updatedVariable.key], {
+ ...state.variables[updatedVariable.key],
value: updatedVariable.value,
});
},
diff --git a/app/assets/javascripts/monitoring/stores/state.js b/app/assets/javascripts/monitoring/stores/state.js
index 9ae1da93e5f..8000f27c0d5 100644
--- a/app/assets/javascripts/monitoring/stores/state.js
+++ b/app/assets/javascripts/monitoring/stores/state.js
@@ -1,10 +1,11 @@
import invalidUrl from '~/lib/utils/invalid_url';
+import { timezones } from '../format_date';
export default () => ({
// API endpoints
- metricsEndpoint: null,
deploymentsEndpoint: null,
dashboardEndpoint: invalidUrl,
+ dashboardsEndpoint: invalidUrl,
// Dashboard request parameters
timeRange: null,
@@ -34,14 +35,24 @@ export default () => ({
panel: null,
},
allDashboards: [],
- promVariables: {},
-
+ /**
+ * User-defined custom variables are passed
+ * via the dashboard yml file.
+ */
+ variables: {},
+ /**
+ * User-defined custom links are passed
+ * via the dashboard yml file.
+ */
+ links: [],
// Other project data
+ dashboardTimezone: timezones.LOCAL,
annotations: [],
deploymentData: [],
environments: [],
environmentsSearchTerm: '',
environmentsLoading: false,
+ currentEnvironmentName: null,
// GitLab paths to other pages
projectPath: null,
diff --git a/app/assets/javascripts/monitoring/stores/utils.js b/app/assets/javascripts/monitoring/stores/utils.js
index b6817e7279a..058fab5f4fc 100644
--- a/app/assets/javascripts/monitoring/stores/utils.js
+++ b/app/assets/javascripts/monitoring/stores/utils.js
@@ -2,7 +2,11 @@ import { slugify } from '~/lib/utils/text_utility';
import createGqClient, { fetchPolicies } from '~/lib/graphql';
import { SUPPORTED_FORMATS } from '~/lib/utils/unit_format';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { NOT_IN_DB_PREFIX } from '../constants';
+import { parseTemplatingVariables } from './variable_mapping';
+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(
{},
@@ -138,6 +142,24 @@ const mapYAxisToViewModel = ({
};
/**
+ * Maps a link to its view model, expects an url and
+ * (optionally) a title.
+ *
+ * Unsafe URLs are ignored.
+ *
+ * @param {Object} Link
+ * @returns {Object} Link object with a `title`, `url` and `type`
+ *
+ */
+const mapLinksToViewModel = ({ url = null, title = '', type } = {}) => {
+ return {
+ title: title || String(url),
+ type,
+ url: url && isSafeURL(url) ? String(url) : '#',
+ };
+};
+
+/**
* Maps a metrics panel to its view model
*
* @param {Object} panel - Metrics panel
@@ -152,6 +174,7 @@ const mapPanelToViewModel = ({
y_label,
y_axis = {},
metrics = [],
+ links = [],
max_value,
}) => {
// Both `x_axis.name` and `x_label` are supported for now
@@ -171,7 +194,8 @@ const mapPanelToViewModel = ({
yAxis,
xAxis,
maxValue: max_value,
- metrics: mapToMetricsViewModel(metrics, yAxis.name),
+ links: links.map(mapLinksToViewModel),
+ metrics: mapToMetricsViewModel(metrics),
};
};
@@ -190,6 +214,66 @@ 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.
+ *
+ * As of %13.1, metadata only includes timeRange but in the
+ * future more info will be added to the links.
+ *
+ * @param {Object} metadata
+ * @returns {Function}
+ */
+export const addDashboardMetaDataToLink = metadata => link => {
+ let modifiedLink = { ...link };
+ if (metadata.timeRange) {
+ modifiedLink = {
+ ...modifiedLink,
+ url: mergeUrlParams(convertTimeRanges(metadata.timeRange, link.type), link.url),
+ };
+ }
+ return modifiedLink;
+};
+
+/**
* Maps a dashboard json object to its view model
*
* @param {Object} dashboard - Dashboard object
@@ -197,13 +281,33 @@ const mapToPanelGroupViewModel = ({ group = '', panels = [] }, i) => {
* @param {Array} dashboard.panel_groups - Panel groups array
* @returns {Object}
*/
-export const mapToDashboardViewModel = ({ dashboard = '', panel_groups = [] }) => {
+export const mapToDashboardViewModel = ({
+ dashboard = '',
+ templating = {},
+ links = [],
+ panel_groups = [],
+}) => {
return {
dashboard,
+ variables: parseTemplatingVariables(templating),
+ links: links.map(mapLinksToViewModel),
panelGroups: panel_groups.map(mapToPanelGroupViewModel),
};
};
+/**
+ * Processes a single Range vector, part of the result
+ * of type `matrix` in the form:
+ *
+ * {
+ * "metric": { "<label_name>": "<label_value>", ... },
+ * "values": [ [ <unix_time>, "<sample_value>" ], ... ]
+ * },
+ *
+ * See https://prometheus.io/docs/prometheus/latest/querying/api/#range-vectors
+ *
+ * @param {*} timeSeries
+ */
export const normalizeQueryResult = timeSeries => {
let normalizedResult = {};
diff --git a/app/assets/javascripts/monitoring/stores/variable_mapping.js b/app/assets/javascripts/monitoring/stores/variable_mapping.js
index bfb469da19e..66b9899f673 100644
--- a/app/assets/javascripts/monitoring/stores/variable_mapping.js
+++ b/app/assets/javascripts/monitoring/stores/variable_mapping.js
@@ -47,7 +47,7 @@ const textAdvancedVariableParser = advTextVar => ({
*/
const normalizeCustomVariableOptions = ({ default: defaultOpt = false, text, value }) => ({
default: defaultOpt,
- text,
+ text: text || value,
value,
});