text: import * as Sentry from '@sentry/browser';
  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,
    parseAnnotationsResponse,
    removeLeadingSlash,
  } from './utils';
  import trackDashboardLoad from '../monitoring_tracking_helper';
  import getEnvironments from '../queries/getEnvironments.query.graphql';
  import getAnnotations from '../queries/getAnnotations.query.graphql';
  import statusCodes from '../../lib/utils/http_status';
  import { backOff, convertObjectPropsToCamelCase } from '../../lib/utils/common_utils';
  import { s__, sprintf } from '../../locale';
  
  import {
    PROMETHEUS_TIMEOUT,
    ENVIRONMENT_AVAILABLE_STATE,
    DEFAULT_DASHBOARD_PATH,
  } from '../constants';
  
  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)),
    };
  }
  
  function backOffRequest(makeRequestCallback) {
    return backOff((next, stop) => {
      makeRequestCallback()
        .then(resp => {
          if (resp.status === statusCodes.NO_CONTENT) {
            next();
          } else {
            stop(resp);
          }
        })
        .catch(stop);
    }, PROMETHEUS_TIMEOUT);
  }
  
  function getPrometheusMetricResult(prometheusEndpoint, params) {
    return backOffRequest(() => axios.get(prometheusEndpoint, { params }))
      .then(res => res.data)
      .then(response => {
        if (response.status === 'error') {
          throw new Error(response.error);
        }
  
        return response.data.result;
      });
  }
  
  // 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 setVariables = ({ commit }, variables) => {
    commit(types.SET_VARIABLES, variables);
  };
  
  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,
    });
  };
  
  // 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 }) => {
    dispatch('requestMetricsDashboard');
  
    const params = {};
    if (state.currentDashboard) {
      params.dashboard = state.currentDashboard;
    }
  
    return backOffRequest(() => axios.get(state.dashboardEndpoint, { params }))
      .then(resp => resp.data)
      .then(response => dispatch('receiveMetricsDashboardSuccess', { response }))
      .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;
            createFlash(
              sprintf(
                s__('Metrics|There was an error while retrieving metrics. %{message}'),
                { message },
                false,
              ),
            );
          } else {
            createFlash(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_VARIABLES, mergeURLVariables(parseTemplatingVariables(dashboard.templating)));
    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) {
      createFlash(s__(`Metrics|Invalid time range, please verify.`), 'warning');
      return Promise.reject();
    }
  
    const defaultQueryParams = prometheusMetricQueryParams(state.timeRange);
  
    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 = state.currentDashboard === '' ? 'default' : 'custom';
        trackDashboardLoad({
          label: `${dashboardType}_metrics_dashboard`,
          value: getters.metricsWithData().length,
        });
      })
      .catch(() => {
        createFlash(s__(`Metrics|There was an error while retrieving metrics`), '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 },
  ) => {
    const queryParams = { ...defaultQueryParams };
    if (metric.step) {
      queryParams.step = metric.step;
    }
  
    if (Object.keys(state.variables).length > 0) {
      queryParams.variables = getters.getCustomVariablesArray;
    }
  
    commit(types.REQUEST_METRIC_RESULT, { metricId: metric.metricId });
  
    return getPrometheusMetricResult(metric.prometheusEndpointPath, queryParams)
      .then(result => {
        commit(types.RECEIVE_METRIC_RESULT_SUCCESS, { metricId: metric.metricId, result });
      })
      .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 createFlash
        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) {
          createFlash(s__('Metrics|Unexpected deployment data response from prometheus endpoint'));
        }
  
        dispatch('receiveDeploymentsDataSuccess', response.deployments);
      })
      .catch(error => {
        Sentry.captureException(error);
        dispatch('receiveDeploymentsDataFailure');
        createFlash(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) {
          createFlash(
            s__('Metrics|There was an error fetching the environments data, please try again'),
          );
        }
  
        dispatch('receiveEnvironmentsDataSuccess', environments);
      })
      .catch(err => {
        Sentry.captureException(err);
        dispatch('receiveEnvironmentsDataFailure');
        createFlash(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 }) => {
    const { start } = convertToFixedRange(state.timeRange);
    const dashboardPath = state.currentDashboard || DEFAULT_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) {
          createFlash(s__('Metrics|There was an error fetching annotations. Please try again.'));
        }
  
        dispatch('receiveAnnotationsSuccess', annotations);
      })
      .catch(err => {
        Sentry.captureException(err);
        dispatch('receiveAnnotationsFailure');
        createFlash(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);
  
  // 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, 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_VARIABLES, updatedVariable);
  
    return dispatch('fetchDashboardData');
  };
  
  // prevent babel-plugin-rewire from generating an invalid default during karma tests
  export default () => {};
  