diff options
Diffstat (limited to 'app/assets/javascripts/monitoring/utils.js')
-rw-r--r-- | app/assets/javascripts/monitoring/utils.js | 402 |
1 files changed, 0 insertions, 402 deletions
diff --git a/app/assets/javascripts/monitoring/utils.js b/app/assets/javascripts/monitoring/utils.js deleted file mode 100644 index 5f4d2703d21..00000000000 --- a/app/assets/javascripts/monitoring/utils.js +++ /dev/null @@ -1,402 +0,0 @@ -import { pickBy, mapKeys } from 'lodash'; -import { parseBoolean } from '~/lib/utils/common_utils'; -import { - timeRangeParamNames, - timeRangeFromParams, - timeRangeToParams, -} from '~/lib/utils/datetime_range'; -import { - queryToObject, - mergeUrlParams, - removeParams, - updateHistory, -} from '~/lib/utils/url_utility'; -import { VARIABLE_PREFIX } from './constants'; - -/** - * Extracts the initial state and props from HTML dataset - * and places them in separate objects to setup bundle. - * @param {*} dataset - */ -export const stateAndPropsFromDataset = (dataset = {}) => { - const { - currentDashboard, - deploymentsEndpoint, - dashboardEndpoint, - dashboardsEndpoint, - panelPreviewEndpoint, - dashboardTimezone, - canAccessOperationsSettings, - operationsSettingsPath, - projectPath, - externalDashboardUrl, - currentEnvironmentName, - customDashboardBasePath, - addDashboardDocumentationPath, - ...dataProps - } = dataset; - - // HTML attributes are always strings, parse other types. - dataProps.hasMetrics = parseBoolean(dataProps.hasMetrics); - dataProps.customMetricsAvailable = parseBoolean(dataProps.customMetricsAvailable); - - return { - initState: { - currentDashboard, - deploymentsEndpoint, - dashboardEndpoint, - dashboardsEndpoint, - panelPreviewEndpoint, - dashboardTimezone, - canAccessOperationsSettings, - operationsSettingsPath, - projectPath, - externalDashboardUrl, - currentEnvironmentName, - customDashboardBasePath, - addDashboardDocumentationPath, - }, - dataProps, - }; -}; - -/** - * 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', 'embedded']; - -/** - * 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 - * of a valid format or not. - * @param {Object} graphData the graph data response from a prometheus request - * @returns {boolean} whether the graphData format is correct - */ -export const graphDataValidatorForValues = (isValues, graphData) => { - const responseValueKeyName = isValues ? 'value' : 'values'; - return ( - Array.isArray(graphData.metrics) && - graphData.metrics.filter((query) => { - if (Array.isArray(query.result)) { - return ( - query.result.filter((res) => Array.isArray(res[responseValueKeyName])).length === - query.result.length - ); - } - return false; - }).length === graphData.metrics.filter((query) => query.result).length - ); -}; - -/** - * Checks that element that triggered event is located on cluster health check dashboard - * @param {HTMLElement} element to check against - * @returns {boolean} - */ -const isClusterHealthBoard = () => (document.body.dataset.page || '').includes(':clusters:show'); - -/** - * Tracks snowplow event when user generates link to metric chart - * @param {String} chart link that will be sent as a property for the event - * @return {Object} config object for event tracking - */ -export const generateLinkToChartOptions = (chartLink) => { - const isCLusterHealthBoard = isClusterHealthBoard(); - - const category = isCLusterHealthBoard - ? 'Cluster Monitoring' // eslint-disable-line @gitlab/require-i18n-strings - : 'Incident Management::Embedded metrics'; - const action = isCLusterHealthBoard - ? 'generate_link_to_cluster_metric_chart' - : 'generate_link_to_metrics_chart'; - - return { category, action, label: 'Chart link', property: chartLink }; // eslint-disable-line @gitlab/require-i18n-strings -}; - -/** - * Tracks snowplow event when user downloads CSV of cluster metric - * @param {String} chart title that will be sent as a property for the event - * @return {Object} config object for event tracking - */ -export const downloadCSVOptions = (title) => { - const isCLusterHealthBoard = isClusterHealthBoard(); - - const category = isCLusterHealthBoard - ? 'Cluster Monitoring' // eslint-disable-line @gitlab/require-i18n-strings - : 'Incident Management::Embedded metrics'; - const action = isCLusterHealthBoard - ? 'download_csv_of_cluster_metric_chart' - : 'download_csv_of_metrics_dashboard_chart'; - - return { category, action, label: 'Chart title', property: title }; // eslint-disable-line @gitlab/require-i18n-strings -}; -/* eslint-enable @gitlab/require-i18n-strings */ - -/** - * Generate options for snowplow to track adding a new metric via the dashboard - * custom metric modal - * @return {Object} config object for event tracking - */ -export const getAddMetricTrackingOptions = () => ({ - category: document.body.dataset.page, - action: 'click_button', - label: 'add_new_metric', - property: 'modal', -}); - -/** - * This function validates the graph data contains exactly 3 metrics plus - * value validations from graphDataValidatorForValues. - * @param {Object} isValues - * @param {Object} graphData the graph data response from a prometheus request - * @returns {boolean} true if the data is valid - */ -export const graphDataValidatorForAnomalyValues = (graphData) => { - const anomalySeriesCount = 3; // metric, upper, lower - return ( - graphData.metrics && - graphData.metrics.length === anomalySeriesCount && - graphDataValidatorForValues(false, graphData) - ); -}; - -/** - * Returns a time range from the current URL params - * - * @returns {Object|null} The time range defined by the - * current URL, reading from search query or `window.location.search`. - * Returns `null` if no parameters form a time range. - */ -export const timeRangeFromUrl = (search = window.location.search) => { - const params = queryToObject(search, { legacySpacesDecode: true }); - return timeRangeFromParams(params); -}; - -/** - * Variable labels are used as names for the dropdowns and also - * as URL params. Prefixing the name reduces the risk of - * collision with other URL params - * - * @param {String} label label for the template variable - * @returns {String} - */ -export const addPrefixToLabel = (label) => `${VARIABLE_PREFIX}${label}`; - -/** - * Before the templating variables are passed to the backend the - * prefix needs to be removed. - * - * This method removes the prefix at the beginning of the string. - * - * @param {String} label label to remove prefix from - * @returns {String} - */ -export const removePrefixFromLabel = (label) => - (label || '').replace(new RegExp(`^${VARIABLE_PREFIX}`), ''); - -/** - * Convert parsed template variables to an object - * with just keys and values. Prepare the variables - * to be added to the URL. Keys of the object will - * have a prefix so that these params can be - * differentiated from other URL params. - * - * @param {Object} variables - * @returns {Object} - */ -export const convertVariablesForURL = (variables) => - variables.reduce((acc, { name, value }) => { - if (value !== null) { - acc[addPrefixToLabel(name)] = value; - } - return acc; - }, {}); - -/** - * User-defined variables from the URL are extracted. The variables - * begin with a constant prefix so that it doesn't collide with - * other URL params. - * - * @param {String} search URL - * @returns {Object} The custom variables defined by the user in the URL - */ -export const templatingVariablesFromUrl = (search = window.location.search) => { - const params = queryToObject(search, { legacySpacesDecode: true }); - // pick the params with variable prefix - const paramsWithVars = pickBy(params, (val, key) => key.startsWith(VARIABLE_PREFIX)); - // remove the prefix before storing in the Vuex store - return mapKeys(paramsWithVars, (val, key) => removePrefixFromLabel(key)); -}; - -/** - * Update the URL with variables. This usually get triggered when - * the user interacts with the dynamic input elements in the monitoring - * dashboard header. - * - * @param {Object} variables user defined variables - */ -export const setCustomVariablesFromUrl = (variables) => { - // prep the variables to append to URL - const parsedVariables = convertVariablesForURL(variables); - // update the URL - updateHistory({ - url: mergeUrlParams(parsedVariables, window.location.href), - title: document.title, - }); -}; - -/** - * Returns a URL with no time range based on the current URL. - * - * @param {String} New URL - */ -export const removeTimeRangeParams = (url = window.location.href) => - removeParams(timeRangeParamNames, url); - -/** - * Returns a URL for the a different time range based on the - * current URL and a time range. - * - * @param {String} New URL - */ -export const timeRangeToUrl = (timeRange, url = window.location.href) => { - const toUrl = removeTimeRangeParams(url); - const params = timeRangeToParams(timeRange); - return mergeUrlParams(params, toUrl); -}; - -/** - * Locates a panel (and its corresponding group) given a (URL) search query. Returns - * it as payload for the store to set the right expandaded panel. - * - * Params used to locate a panel are: - * - group: Group identifier - * - title: Panel title - * - y_label: Panel y_label - * - * @param {Object} dashboard - Dashboard reference from the Vuex store - * @param {String} search - URL location search query - * @returns {Object} payload - Payload for expanded panel to be displayed - * @returns {String} payload.group - Group where panel is located - * @returns {Object} payload.panel - Dashboard panel (graphData) reference - * @throws Will throw an error if Panel cannot be located. - */ -export const expandedPanelPayloadFromUrl = (dashboard, search = window.location.search) => { - const params = queryToObject(search, { legacySpacesDecode: true }); - - // Search for the panel if any of the search params is identified - if (params.group || params.title || params.y_label) { - const panelGroup = dashboard.panelGroups.find(({ group }) => params.group === group); - const panel = panelGroup.panels.find( - // eslint-disable-next-line camelcase - ({ y_label, title }) => y_label === params.y_label && title === params.title, - ); - - if (!panel) { - // eslint-disable-next-line @gitlab/require-i18n-strings - throw new Error('Panel could no found by URL parameters.'); - } - return { group: panelGroup.group, panel }; - } - return null; -}; - -/** - * Convert panel information to a URL for the user to - * bookmark or share highlighting a specific panel. - * - * If no group/panel is set, the dashboard URL is returned. - * - * @param {?String} dashboard - Dashboard path, used as identifier for a dashboard - * @param {?Object} variables - Custom variables that came from the URL - * @param {?String} group - Group Identifier - * @param {?Object} panel - Panel object from the dashboard - * @param {?String} url - Base URL including current search params - * @returns Dashboard URL which expands a panel (chart) - */ -export const panelToUrl = ( - dashboard = null, - variables, - group, - panel, - url = window.location.href, -) => { - const params = { - dashboard, - ...variables, - }; - - if (group && panel) { - params.group = group; - params.title = panel.title; - params.y_label = panel.y_label; - } else { - // Remove existing parameters if any - params.group = null; - params.title = null; - params.y_label = null; - } - - return mergeUrlParams(params, url); -}; - -/** - * Get the metric value from first data point. - * Currently only used for bar charts - * - * @param {Array} values data points - * @returns {Number} - */ -const metricValueMapper = (values) => values[0]?.[1]; - -/** - * Get the metric name from metric object - * Currently only used for bar charts - * e.g. { handler: '/query' } - * { method: 'get' } - * - * @param {Object} metric metric object - * @returns {String} - */ -const metricNameMapper = (metric) => Object.values(metric)?.[0]; - -/** - * Parse metric object to extract metric value and name in - * [<metric-value>, <metric-name>] format. - * Currently only used for bar charts - * - * @param {Object} param0 metric object - * @returns {Array} - */ -const resultMapper = ({ metric, values = [] }) => [ - metricValueMapper(values), - metricNameMapper(metric), -]; - -/** - * Bar charts graph data parser to massage data from - * backend to a format acceptable by bar charts component - * in GitLab UI - * - * e.g. - * { - * SLO: [ - * [98, 'api'], - * [99, 'web'], - * [99, 'database'] - * ] - * } - * - * @param {Array} data series information - * @returns {Object} - */ -export const barChartsDataParser = (data = []) => - data?.reduce( - (acc, { result = [], label }) => ({ - ...acc, - [label]: result.map(resultMapper), - }), - {}, - ); |