All files / ee/app/assets/javascripts/issues_analytics utils.js

100% Statements 30/30
84.61% Branches 11/13
100% Functions 6/6
100% Lines 27/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101                              4x 31x                       4x 28x         28x 28x     28x   28x 31x   31x 6x   6x 4x     6x   25x       28x                                       4x 222x 222x 5214x   222x 222x       2607x 2607x 2607x   2607x               222x    
import { isEmpty, mapKeys } from 'lodash';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { RENAMED_FILTER_KEYS_DEFAULT } from 'ee/issues_analytics/constants';
import { dateFormats } from '~/analytics/shared/constants';
import dateFormat from '~/lib/dateformat';
import { getMonthNames, newDate } from '~/lib/utils/datetime_utility';
 
/**
 * Returns an object with renamed filter keys.
 *
 * @param {Object} filters - Filters with keys to be renamed
 * @param {Object} newKeys - Map of old keys to new keys
 *
 * @returns {Object}
 */
const renameFilterKeys = (filters, newKeys) =>
  mapKeys(filters, (value, key) => newKeys[key] ?? key);
 
/**
 * This util method takes the global page filters and transforms parameters which
 * are not standardized between the internal issue analytics api and the public
 * issues api.
 *
 * @param {Object} filters - the global filters used to fetch issues data
 * @param {Object} renamedKeys - map of keys to be renamed
 *
 * @returns {Object} - the transformed filters for the public api
 */
export const transformFilters = (filters = {}, renamedKeys = RENAMED_FILTER_KEYS_DEFAULT) => {
  let formattedFilters = convertObjectPropsToCamelCase(filters, {
    deep: true,
    dropKeys: ['scope', 'include_subepics'],
  });
 
  Eif (!isEmpty(renamedKeys)) {
    formattedFilters = renameFilterKeys(formattedFilters, renamedKeys);
  }
 
  const newFilters = {};
 
  Object.entries(formattedFilters).forEach(([key, val]) => {
    const negatedFilterMatch = key.match(/^not\[(.+)\]/);
 
    if (negatedFilterMatch) {
      const negatedFilterKey = negatedFilterMatch[1];
 
      if (!newFilters.not) {
        newFilters.not = {};
      }
 
      Object.assign(newFilters.not, { [negatedFilterKey]: val });
    } else {
      newFilters[key] = val;
    }
  });
 
  return newFilters;
};
 
/**
 * @typedef {Object} monthDataItem
 * @property {Date} fromDate
 * @property {Date} toDate
 * @property {String} month - abbreviated month
 * @property {Number} year
 */
 
/**
 * Accepts a date range and an Issue Analytics count query type and
 * generates the data needed to build the GraphQL query for the chart
 *
 * @param startDate - start date for the date range
 * @param endDate - end date for the date range
 * @param format - format to be used by date range
 * @return {monthDataItem[]} - date range data
 */
export const generateChartDateRangeData = (startDate, endDate, format = dateFormats.isoDate) => {
  const chartDateRangeData = [];
  const abbrMonthNames = getMonthNames(true);
  const formatDate = (date) => dateFormat(date, format, true);
 
  for (
    let fromDate = newDate(startDate);
    fromDate < endDate;
    fromDate.setMonth(fromDate.getMonth() + 1, 1)
  ) {
    let toDate = newDate(fromDate);
    toDate.setMonth(toDate.getMonth() + 1, 1);
    if (toDate > endDate) toDate = endDate;
 
    chartDateRangeData.push({
      fromDate: formatDate(fromDate),
      toDate: formatDate(toDate),
      month: abbrMonthNames[fromDate.getMonth()],
      year: fromDate.getFullYear(),
    });
  }
 
  return chartDateRangeData;
};