summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/cycle_analytics/utils.js
blob: 3c6267bac06b29ea0c7eb7b9e3a275995525be27 (plain)
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import dateFormat from 'dateformat';
import { dateFormats } from '~/analytics/shared/constants';
import { hideFlash } from '~/flash';
import { getDateInPast } from '~/lib/utils/datetime/date_calculation_utility';
import { parseSeconds } from '~/lib/utils/datetime_utility';
import { formatTimeAsSummary } from '~/lib/utils/datetime/date_format_utility';
import { slugify } from '~/lib/utils/text_utility';

export const removeFlash = (type = 'alert') => {
  const flashEl = document.querySelector(`.flash-${type}`);
  if (flashEl) {
    hideFlash(flashEl);
  }
};

/**
 * Takes the stages and median data, combined with the selected stage, to build an
 * array which is formatted to proivde the data required for the path navigation.
 *
 * @param {Array} stages - The stages available to the group / project
 * @param {Object} medians - The median values for the stages available to the group / project
 * @param {Object} stageCounts - The total item count for the stages available
 * @param {Object} selectedStage - The currently selected stage
 * @returns {Array} An array of stages formatted with data required for the path navigation
 */
export const transformStagesForPathNavigation = ({
  stages,
  medians,
  stageCounts = {},
  selectedStage,
}) => {
  const formattedStages = stages.map((stage) => {
    return {
      metric: medians[stage?.id],
      selected: stage?.id === selectedStage?.id, // Also could null === null cause an issue here?
      stageCount: stageCounts && stageCounts[stage?.id],
      icon: null,
      ...stage,
    };
  });

  return formattedStages;
};

/**
 * Takes a raw median value in seconds and converts it to a string representation
 * ie. converts 172800 => 2d (2 days)
 *
 * @param {Number} Median - The number of seconds for the median calculation
 * @returns {String} String representation ie 2w
 */
export const medianTimeToParsedSeconds = (value) =>
  formatTimeAsSummary({
    ...parseSeconds(value, { daysPerWeek: 7, hoursPerDay: 24 }),
    seconds: value,
  });

/**
 * Takes the raw median value arrays and converts them into a useful object
 * containing the string for display in the path navigation
 * ie. converts [{ id: 'test', value: 172800 }] => { 'test': '2d' }
 *
 * @param {Array} Medians - Array of stage median objects, each contains a `id`, `value` and `error`
 * @returns {Object} Returns key value pair with the stage name and its display median value
 */
export const formatMedianValues = (medians = []) =>
  medians.reduce((acc, { id, value = 0 }) => {
    return {
      ...acc,
      [id]: value ? medianTimeToParsedSeconds(value) : '-',
    };
  }, {});

export const filterStagesByHiddenStatus = (stages = [], isHidden = true) =>
  stages.filter(({ hidden = false }) => hidden === isHidden);

const toIsoFormat = (d) => dateFormat(d, dateFormats.isoDate);

/**
 * Takes an integer specifying the number of days to subtract
 * from the date specified will return the 2 dates, formatted as ISO dates
 *
 * @param {Number} daysInPast - Number of days in the past to subtract
 * @param {Date} [today=new Date] - Date to subtract days from, defaults to today
 * @returns {Object} Returns 'now' and the 'past' date formatted as ISO dates
 */
export const calculateFormattedDayInPast = (daysInPast, today = new Date()) => {
  return {
    now: toIsoFormat(today),
    past: toIsoFormat(getDateInPast(today, daysInPast)),
  };
};

/**
 * @typedef {Object} MetricData
 * @property {String} title - Title of the metric measured
 * @property {String} value - String representing the decimal point value, e.g '1.5'
 * @property {String} [unit] - String representing the decimal point value, e.g '1.5'
 *
 * @typedef {Object} TransformedMetricData
 * @property {String} label - Title of the metric measured
 * @property {String} value - String representing the decimal point value, e.g '1.5'
 * @property {String} key - Slugified string based on the 'title'
 * @property {String} description - String to display for a description
 * @property {String} unit - String representing the decimal point value, e.g '1.5'
 */

/**
 * Prepares metric data to be rendered in the metric_card component
 *
 * @param {MetricData[]} data - The metric data to be rendered
 * @param {Object} popoverContent - Key value pair of data to display in the popover
 * @returns {TransformedMetricData[]} An array of metrics ready to render in the metric_card
 */

export const prepareTimeMetricsData = (data = [], popoverContent = {}) =>
  data.map(({ title: label, ...rest }) => {
    const key = slugify(label);
    return {
      ...rest,
      label,
      key,
      description: popoverContent[key]?.description || '',
    };
  });