summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/search/store/utils.js
blob: 8e484e6964621cde2127e9b6951e00972b4c9eca (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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import { isEqual, orderBy } from 'lodash';
import AccessorUtilities from '~/lib/utils/accessor';
import { formatNumber } from '~/locale';
import { joinPaths } from '~/lib/utils/url_utility';
import { languageFilterData } from '~/search/sidebar/constants/language_filter_data';
import {
  MAX_FREQUENT_ITEMS,
  MAX_FREQUENCY,
  SIDEBAR_PARAMS,
  NUMBER_FORMATING_OPTIONS,
} from './constants';

const LANGUAGE_AGGREGATION_NAME = languageFilterData.filterParam;

function extractKeys(object, keyList) {
  return Object.fromEntries(keyList.map((key) => [key, object[key]]));
}

export const loadDataFromLS = (key) => {
  if (!AccessorUtilities.canUseLocalStorage()) {
    return [];
  }

  try {
    return JSON.parse(localStorage.getItem(key)) || [];
  } catch {
    // The LS got in a bad state, let's wipe it
    localStorage.removeItem(key);
    return [];
  }
};

export const setFrequentItemToLS = (key, data, itemData) => {
  if (!AccessorUtilities.canUseLocalStorage()) {
    return [];
  }

  const keyList = [
    'id',
    'avatar_url',
    'name',
    'full_name',
    'name_with_namespace',
    'frequency',
    'lastUsed',
  ];

  try {
    const frequentItems = data[key].map((obj) => extractKeys(obj, keyList));
    const item = extractKeys(itemData, keyList);
    const existingItemIndex = frequentItems.findIndex((i) => i.id === item.id);

    if (existingItemIndex >= 0) {
      // Up the frequency (Max 5)
      const currentFrequency = frequentItems[existingItemIndex].frequency;
      frequentItems[existingItemIndex].frequency = Math.min(currentFrequency + 1, MAX_FREQUENCY);
      frequentItems[existingItemIndex].lastUsed = new Date().getTime();
    } else {
      // Only store a max of 5 items
      if (frequentItems.length >= MAX_FREQUENT_ITEMS) {
        frequentItems.pop();
      }

      frequentItems.push({ ...item, frequency: 1, lastUsed: new Date().getTime() });
    }

    // Sort by frequency and lastUsed
    frequentItems.sort((a, b) => {
      if (a.frequency > b.frequency) {
        return -1;
      } else if (a.frequency < b.frequency) {
        return 1;
      }
      return b.lastUsed - a.lastUsed;
    });

    // Note we do not need to commit a mutation here as immediately after this we refresh the page to
    // update the search results.
    localStorage.setItem(key, JSON.stringify(frequentItems));
    return frequentItems;
  } catch {
    // The LS got in a bad state, let's wipe it
    localStorage.removeItem(key);
    return [];
  }
};

export const mergeById = (inflatedData, storedData) => {
  return inflatedData.map((data) => {
    const stored = storedData?.find((d) => d.id === data.id) || {};
    return { ...stored, ...data };
  });
};

export const isSidebarDirty = (currentQuery, urlQuery) => {
  return SIDEBAR_PARAMS.some((param) => {
    // userAddParam ensures we don't get a false dirty from null !== undefined
    const userAddedParam = !urlQuery[param] && currentQuery[param];
    const userChangedExistingParam = urlQuery[param] && urlQuery[param] !== currentQuery[param];

    if (Array.isArray(currentQuery[param]) || Array.isArray(urlQuery[param])) {
      return !isEqual(currentQuery[param], urlQuery[param]);
    }

    return userAddedParam || userChangedExistingParam;
  });
};

export const formatSearchResultCount = (count) => {
  if (!count) {
    return '0';
  }

  const countNumber = typeof count === 'string' ? parseInt(count.replace(/,/g, ''), 10) : count;
  return formatNumber(countNumber, NUMBER_FORMATING_OPTIONS);
};

export const getAggregationsUrl = () => {
  const currentUrl = new URL(window.location.href);
  currentUrl.pathname = joinPaths('/search', 'aggregations');
  return currentUrl.toString();
};

const sortLanguages = (state, entries) => {
  const queriedLanguages = state.query?.[LANGUAGE_AGGREGATION_NAME] || [];

  if (!Array.isArray(queriedLanguages) || !queriedLanguages.length) {
    return entries;
  }

  const queriedLanguagesSet = new Set(queriedLanguages);

  return orderBy(entries, [({ key }) => queriedLanguagesSet.has(key), 'count'], ['desc', 'desc']);
};

export const prepareSearchAggregations = (state, aggregationData) =>
  aggregationData.map((item) => {
    if (item?.name === LANGUAGE_AGGREGATION_NAME) {
      return {
        ...item,
        buckets: sortLanguages(state, item.buckets),
      };
    }

    return item;
  });