diff options
Diffstat (limited to 'app/assets/javascripts/monitoring/stores/actions.js')
-rw-r--r-- | app/assets/javascripts/monitoring/stores/actions.js | 576 |
1 files changed, 0 insertions, 576 deletions
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js deleted file mode 100644 index 32e85262882..00000000000 --- a/app/assets/javascripts/monitoring/stores/actions.js +++ /dev/null @@ -1,576 +0,0 @@ -import * as Sentry from '@sentry/browser'; -import { createAlert } from '~/alert'; -import axios from '~/lib/utils/axios_utils'; -import { convertToFixedRange } from '~/lib/utils/datetime_range'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; -import { s__, sprintf } from '~/locale'; -import { ENVIRONMENT_AVAILABLE_STATE, OVERVIEW_DASHBOARD_PATH, VARIABLE_TYPES } from '../constants'; -import trackDashboardLoad from '../monitoring_tracking_helper'; -import getAnnotations from '../queries/get_annotations.query.graphql'; -import getDashboardValidationWarnings from '../queries/get_dashboard_validation_warnings.query.graphql'; -import getEnvironments from '../queries/get_environments.query.graphql'; -import { getDashboard, getPrometheusQueryData } from '../requests'; - -import * as types from './mutation_types'; -import { - gqClient, - parseEnvironmentsResponse, - parseAnnotationsResponse, - removeLeadingSlash, -} from './utils'; - -const axiosCancelToken = axios.CancelToken; -let cancelTokenSource; - -function prometheusMetricQueryParams(timeRange) { - const { start, end } = convertToFixedRange(timeRange); - - const timeDiff = (new Date(end) - new Date(start)) / 1000; - const minStep = 60; - const queryDataPoints = 600; - - return { - start_time: start, - end_time: end, - step: Math.max(minStep, Math.ceil(timeDiff / queryDataPoints)), - }; -} - -/** - * Extract error messages from API or HTTP request errors. - * - * - API errors are in `error.response.data.message` - * - HTTP (axios) errors are in `error.message` - * - * @param {Object} error - * @returns {String} User friendly error message - */ -function extractErrorMessage(error) { - const message = error?.response?.data?.message; - return message ?? error.message; -} - -// Setup - -export const setGettingStartedEmptyState = ({ commit }) => { - commit(types.SET_GETTING_STARTED_EMPTY_STATE); -}; - -export const setInitialState = ({ commit }, initialState) => { - commit(types.SET_INITIAL_STATE, initialState); -}; - -export const setTimeRange = ({ commit }, timeRange) => { - commit(types.SET_TIME_RANGE, timeRange); -}; - -export const filterEnvironments = ({ commit, dispatch }, searchTerm) => { - commit(types.SET_ENVIRONMENTS_FILTER, searchTerm); - dispatch('fetchEnvironmentsData'); -}; - -export const setShowErrorBanner = ({ commit }, enabled) => { - commit(types.SET_SHOW_ERROR_BANNER, enabled); -}; - -export const setExpandedPanel = ({ commit }, { group, panel }) => { - commit(types.SET_EXPANDED_PANEL, { group, panel }); -}; - -export const clearExpandedPanel = ({ commit }) => { - commit(types.SET_EXPANDED_PANEL, { - group: null, - panel: null, - }); -}; - -export const setCurrentDashboard = ({ commit }, { currentDashboard }) => { - commit(types.SET_CURRENT_DASHBOARD, currentDashboard); -}; - -// All Data - -/** - * Fetch all dashboard data. - * - * @param {Object} store - * @returns A promise that resolves when the dashboard - * skeleton has been loaded. - */ -export const fetchData = ({ dispatch }) => { - dispatch('fetchEnvironmentsData'); - dispatch('fetchDashboard'); - dispatch('fetchAnnotations'); -}; - -// Metrics dashboard - -export const fetchDashboard = ({ state, commit, dispatch, getters }) => { - dispatch('requestMetricsDashboard'); - - const params = {}; - if (getters.fullDashboardPath) { - params.dashboard = getters.fullDashboardPath; - } - - return getDashboard(state.dashboardEndpoint, params) - .then((response) => { - dispatch('receiveMetricsDashboardSuccess', { response }); - /** - * After the dashboard is fetched, there can be non-blocking invalid syntax - * in the dashboard file. This call will fetch such syntax warnings - * and surface a warning on the UI. If the invalid syntax is blocking, - * the `fetchDashboard` returns a 404 with error messages that are displayed - * on the UI. - */ - dispatch('fetchDashboardValidationWarnings'); - }) - .catch((error) => { - Sentry.captureException(error); - - commit(types.SET_ALL_DASHBOARDS, error.response?.data?.all_dashboards ?? []); - dispatch('receiveMetricsDashboardFailure', error); - - if (state.showErrorBanner) { - if (error.response.data && error.response.data.message) { - const { message } = error.response.data; - createAlert({ - message: sprintf( - s__('Metrics|There was an error while retrieving metrics. %{message}'), - { message }, - false, - ), - }); - } else { - createAlert({ - message: s__('Metrics|There was an error while retrieving metrics'), - }); - } - } - }); -}; - -export const requestMetricsDashboard = ({ commit }) => { - commit(types.REQUEST_METRICS_DASHBOARD); -}; -export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response }) => { - const { all_dashboards, dashboard, metrics_data } = response; - - commit(types.SET_ALL_DASHBOARDS, all_dashboards); - commit(types.RECEIVE_METRICS_DASHBOARD_SUCCESS, dashboard); - commit(types.SET_ENDPOINTS, convertObjectPropsToCamelCase(metrics_data)); - - return dispatch('fetchDashboardData'); -}; -export const receiveMetricsDashboardFailure = ({ commit }, error) => { - commit(types.RECEIVE_METRICS_DASHBOARD_FAILURE, error); -}; - -// Metrics - -/** - * Loads timeseries data: Prometheus data points and deployment data from the project - * @param {Object} Vuex store - */ -export const fetchDashboardData = ({ state, dispatch, getters }) => { - dispatch('fetchDeploymentsData'); - - if (!state.timeRange) { - createAlert({ - message: s__(`Metrics|Invalid time range, please verify.`), - type: 'warning', - }); - return Promise.reject(); - } - - // Time range params must be pre-calculated once for all metrics and options - // A subsequent call, may calculate a different time range - const defaultQueryParams = prometheusMetricQueryParams(state.timeRange); - - dispatch('fetchVariableMetricLabelValues', { defaultQueryParams }); - - const promises = []; - state.dashboard.panelGroups.forEach((group) => { - group.panels.forEach((panel) => { - panel.metrics.forEach((metric) => { - promises.push(dispatch('fetchPrometheusMetric', { metric, defaultQueryParams })); - }); - }); - }); - - return Promise.all(promises) - .then(() => { - const dashboardType = getters.fullDashboardPath === '' ? 'default' : 'custom'; - trackDashboardLoad({ - label: `${dashboardType}_metrics_dashboard`, - value: getters.metricsWithData().length, - }); - }) - .catch(() => { - createAlert({ - message: s__(`Metrics|There was an error while retrieving metrics`), - type: 'warning', - }); - }); -}; - -/** - * Returns list of metrics in data.result - * {"status":"success", "data":{"resultType":"matrix","result":[]}} - * - * @param {metric} metric - */ -export const fetchPrometheusMetric = ( - { commit, state, getters }, - { metric, defaultQueryParams }, -) => { - let queryParams = { ...defaultQueryParams }; - if (metric.step) { - queryParams.step = metric.step; - } - - if (state.variables.length > 0) { - queryParams = { - ...queryParams, - ...getters.getCustomVariablesParams, - }; - } - - commit(types.REQUEST_METRIC_RESULT, { metricId: metric.metricId }); - - return getPrometheusQueryData(metric.prometheusEndpointPath, queryParams) - .then((data) => { - commit(types.RECEIVE_METRIC_RESULT_SUCCESS, { metricId: metric.metricId, data }); - }) - .catch((error) => { - Sentry.captureException(error); - - commit(types.RECEIVE_METRIC_RESULT_FAILURE, { metricId: metric.metricId, error }); - // Continue to throw error so the dashboard can notify using createAlert - throw error; - }); -}; - -// Deployments - -export const fetchDeploymentsData = ({ state, dispatch }) => { - if (!state.deploymentsEndpoint) { - return Promise.resolve([]); - } - return axios - .get(state.deploymentsEndpoint) - .then((resp) => resp.data) - .then((response) => { - if (!response || !response.deployments) { - createAlert({ - message: s__('Metrics|Unexpected deployment data response from prometheus endpoint'), - }); - } - - dispatch('receiveDeploymentsDataSuccess', response.deployments); - }) - .catch((error) => { - Sentry.captureException(error); - dispatch('receiveDeploymentsDataFailure'); - createAlert({ - message: s__('Metrics|There was an error getting deployment information.'), - }); - }); -}; -export const receiveDeploymentsDataSuccess = ({ commit }, data) => { - commit(types.RECEIVE_DEPLOYMENTS_DATA_SUCCESS, data); -}; -export const receiveDeploymentsDataFailure = ({ commit }) => { - commit(types.RECEIVE_DEPLOYMENTS_DATA_FAILURE); -}; - -// Environments - -export const fetchEnvironmentsData = ({ state, dispatch }) => { - dispatch('requestEnvironmentsData'); - return gqClient - .mutate({ - mutation: getEnvironments, - variables: { - projectPath: removeLeadingSlash(state.projectPath), - search: state.environmentsSearchTerm, - states: [ENVIRONMENT_AVAILABLE_STATE], - }, - }) - .then((resp) => - parseEnvironmentsResponse(resp.data?.project?.data?.environments, state.projectPath), - ) - .then((environments) => { - if (!environments) { - createAlert({ - message: s__( - 'Metrics|There was an error fetching the environments data, please try again', - ), - }); - } - - dispatch('receiveEnvironmentsDataSuccess', environments); - }) - .catch((err) => { - Sentry.captureException(err); - dispatch('receiveEnvironmentsDataFailure'); - createAlert({ - message: s__('Metrics|There was an error getting environments information.'), - }); - }); -}; -export const requestEnvironmentsData = ({ commit }) => { - commit(types.REQUEST_ENVIRONMENTS_DATA); -}; -export const receiveEnvironmentsDataSuccess = ({ commit }, data) => { - commit(types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS, data); -}; -export const receiveEnvironmentsDataFailure = ({ commit }) => { - commit(types.RECEIVE_ENVIRONMENTS_DATA_FAILURE); -}; - -export const fetchAnnotations = ({ state, dispatch, getters }) => { - const { start } = convertToFixedRange(state.timeRange); - const dashboardPath = getters.fullDashboardPath || OVERVIEW_DASHBOARD_PATH; - return gqClient - .mutate({ - mutation: getAnnotations, - variables: { - projectPath: removeLeadingSlash(state.projectPath), - environmentName: state.currentEnvironmentName, - dashboardPath, - startingFrom: start, - }, - }) - .then( - (resp) => resp.data?.project?.environments?.nodes?.[0].metricsDashboard?.annotations.nodes, - ) - .then(parseAnnotationsResponse) - .then((annotations) => { - if (!annotations) { - createAlert({ - message: s__('Metrics|There was an error fetching annotations. Please try again.'), - }); - } - - dispatch('receiveAnnotationsSuccess', annotations); - }) - .catch((err) => { - Sentry.captureException(err); - dispatch('receiveAnnotationsFailure'); - createAlert({ - message: s__('Metrics|There was an error getting annotations information.'), - }); - }); -}; - -export const receiveAnnotationsSuccess = ({ commit }, data) => - commit(types.RECEIVE_ANNOTATIONS_SUCCESS, data); -export const receiveAnnotationsFailure = ({ commit }) => commit(types.RECEIVE_ANNOTATIONS_FAILURE); - -export const fetchDashboardValidationWarnings = ({ state, dispatch, getters }) => { - /** - * Normally, the overview dashboard won't throw any validation warnings. - * - * However, if a bug sneaks into the overview dashboard making it invalid, - * this might come handy for our clients - */ - const dashboardPath = getters.fullDashboardPath || OVERVIEW_DASHBOARD_PATH; - return gqClient - .mutate({ - mutation: getDashboardValidationWarnings, - variables: { - projectPath: removeLeadingSlash(state.projectPath), - environmentName: state.currentEnvironmentName, - dashboardPath, - }, - }) - .then((resp) => resp.data?.project?.environments?.nodes?.[0]?.metricsDashboard || undefined) - .then(({ schemaValidationWarnings } = {}) => { - const hasWarnings = schemaValidationWarnings && schemaValidationWarnings.length !== 0; - /** - * The payload of the dispatch is a boolean, because at the moment a standard - * warning message is shown instead of the warnings the BE returns - */ - dispatch('receiveDashboardValidationWarningsSuccess', hasWarnings || false); - }) - .catch((err) => { - Sentry.captureException(err); - dispatch('receiveDashboardValidationWarningsFailure'); - createAlert({ - message: s__( - 'Metrics|There was an error getting dashboard validation warnings information.', - ), - }); - }); -}; - -export const receiveDashboardValidationWarningsSuccess = ({ commit }, hasWarnings) => - commit(types.RECEIVE_DASHBOARD_VALIDATION_WARNINGS_SUCCESS, hasWarnings); -export const receiveDashboardValidationWarningsFailure = ({ commit }) => - commit(types.RECEIVE_DASHBOARD_VALIDATION_WARNINGS_FAILURE); - -// Dashboard manipulation - -export const toggleStarredValue = ({ commit, state, getters }) => { - const { selectedDashboard } = getters; - - if (state.isUpdatingStarredValue) { - // Prevent repeating requests for the same change - return; - } - if (!selectedDashboard) { - return; - } - - const method = selectedDashboard.starred ? 'DELETE' : 'POST'; - const url = selectedDashboard.user_starred_path; - const newStarredValue = !selectedDashboard.starred; - - commit(types.REQUEST_DASHBOARD_STARRING); - - axios({ - url, - method, - }) - .then(() => { - commit(types.RECEIVE_DASHBOARD_STARRING_SUCCESS, { selectedDashboard, newStarredValue }); - }) - .catch(() => { - commit(types.RECEIVE_DASHBOARD_STARRING_FAILURE); - }); -}; - -/** - * Set a new array of metrics to a panel group - * @param {*} data An object containing - * - `key` with a unique panel key - * - `metrics` with the metrics array - */ -export const setPanelGroupMetrics = ({ commit }, data) => { - commit(types.SET_PANEL_GROUP_METRICS, data); -}; - -export const duplicateSystemDashboard = ({ state }, payload) => { - const params = { - dashboard: payload.dashboard, - file_name: payload.fileName, - branch: payload.branch, - commit_message: payload.commitMessage, - }; - - return axios - .post(state.dashboardsEndpoint, params) - .then((response) => response.data) - .then((data) => data.dashboard) - .catch((error) => { - Sentry.captureException(error); - - const { response } = error; - - if (response && response.data && response.data.error) { - throw sprintf(s__('Metrics|There was an error creating the dashboard. %{error}'), { - error: response.data.error, - }); - } else { - throw s__('Metrics|There was an error creating the dashboard.'); - } - }); -}; - -// Variables manipulation - -export const updateVariablesAndFetchData = ({ commit, dispatch }, updatedVariable) => { - commit(types.UPDATE_VARIABLE_VALUE, updatedVariable); - - return dispatch('fetchDashboardData'); -}; - -export const fetchVariableMetricLabelValues = ({ state, commit }, { defaultQueryParams }) => { - const { start_time, end_time } = defaultQueryParams; - const optionsRequests = []; - - state.variables.forEach((variable) => { - if (variable.type === VARIABLE_TYPES.metric_label_values) { - const { prometheusEndpointPath, label } = variable.options; - - const optionsRequest = getPrometheusQueryData(prometheusEndpointPath, { - start_time, - end_time, - }) - .then((data) => { - commit(types.UPDATE_VARIABLE_METRIC_LABEL_VALUES, { variable, label, data }); - }) - .catch(() => { - createAlert({ - message: sprintf( - s__('Metrics|There was an error getting options for variable "%{name}".'), - { - name: variable.name, - }, - ), - }); - }); - optionsRequests.push(optionsRequest); - } - }); - - return Promise.all(optionsRequests); -}; - -// Panel Builder - -export const setPanelPreviewTimeRange = ({ commit }, timeRange) => { - commit(types.SET_PANEL_PREVIEW_TIME_RANGE, timeRange); -}; - -export const fetchPanelPreview = ({ state, commit, dispatch }, panelPreviewYml) => { - if (!panelPreviewYml) { - return null; - } - - commit(types.SET_PANEL_PREVIEW_IS_SHOWN, true); - commit(types.REQUEST_PANEL_PREVIEW, panelPreviewYml); - - return axios - .post(state.panelPreviewEndpoint, { panel_yaml: panelPreviewYml }) - .then(({ data }) => { - commit(types.RECEIVE_PANEL_PREVIEW_SUCCESS, data); - - dispatch('fetchPanelPreviewMetrics'); - }) - .catch((error) => { - commit(types.RECEIVE_PANEL_PREVIEW_FAILURE, extractErrorMessage(error)); - }); -}; - -export const fetchPanelPreviewMetrics = ({ state, commit }) => { - if (cancelTokenSource) { - cancelTokenSource.cancel(); - } - cancelTokenSource = axiosCancelToken.source(); - - const defaultQueryParams = prometheusMetricQueryParams(state.panelPreviewTimeRange); - - state.panelPreviewGraphData.metrics.forEach((metric, index) => { - commit(types.REQUEST_PANEL_PREVIEW_METRIC_RESULT, { index }); - - const params = { ...defaultQueryParams }; - if (metric.step) { - params.step = metric.step; - } - return getPrometheusQueryData(metric.prometheusEndpointPath, params, { - cancelToken: cancelTokenSource.token, - }) - .then((data) => { - commit(types.RECEIVE_PANEL_PREVIEW_METRIC_RESULT_SUCCESS, { index, data }); - }) - .catch((error) => { - Sentry.captureException(error); - - commit(types.RECEIVE_PANEL_PREVIEW_METRIC_RESULT_FAILURE, { index, error }); - // Continue to throw error so the panel builder can notify using createAlert - throw error; - }); - }); -}; |