summaryrefslogtreecommitdiffstats
path: root/extensions/BMO/web/js/new-bug-frequent-comp.js
blob: 88879738dc91fb68660a976c247335f89b1a5dbc (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
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This Source Code Form is "Incompatible With Secondary Licenses", as
 * defined by the Mozilla Public License, v. 2.0. */

/**
 * Reference or define the Bugzilla app namespace.
 * @namespace
 */
var Bugzilla = Bugzilla || {}; // eslint-disable-line no-var

/**
 * Show the current user's most-used components on the New Bug page.
 */
Bugzilla.NewBugFrequentComp = class NewBugFrequentComp {
  /**
   * Initialize a new NewBugFrequentComp instance.
   */
  constructor() {
    this.$container = document.querySelector('#frequent-components');

    if (this.$container && BUGZILLA.user.login) {
      this.init();
    }
  }

  /**
   * Initialize the UI.
   */
  async init() {
    this.$results = this.$container.querySelector('.results');
    this.$message = this.$results.appendChild(document.createElement('p'));
    this.$message.textContent = 'Loading...';
    this.$results.setAttribute('aria-busy', 'true');
    this.$container.hidden = false;

    // Get the current params that may contain `cloned_bug_id` and `format`
    const current_params = new URLSearchParams(location.search);

    try {
      const links = (await this.fetch()).map(({ product, component }) => {
        const params = new URLSearchParams(current_params);

        params.append('product', product);
        params.append('component', component);

        return {
          href: `/enter_bug.cgi?${params.toString()}`,
          text: `${product} :: ${component}`,
        };
      });

      this.$message.remove();
      this.$results.insertAdjacentHTML('beforeend',
        `<ul>${links.map(({ href, text }) =>
          `<li><a href="${href.htmlEncode()}">${text.htmlEncode()}</a></li>`
        ).join('')}</ul>`
      );
    } catch (error) {
      this.$message.textContent = error.message || 'Your frequent components could not be retrieved.';
    }

    this.$results.removeAttribute('aria-busy');
  }

  /**
   * Retrieve frequently used components.
   * @param {Number} [max=10] Maximum number of results.
   * @returns {Promise} Results or error.
   */
  async fetch(max = 10) {
    const params = new URLSearchParams({
      email1: BUGZILLA.user.login,
      emailreporter1: '1',
      emailtype1: 'exact',
      chfield: '[Bug creation]',
      chfieldfrom: '-1y',
      chfieldto: 'Now',
      include_fields: 'product,component',
    });

    return new Promise((resolve, reject) => {
      bugzilla_ajax({
        url: `/rest/bug?${params.toString()}`
      }, response => {
        if (!response.bugs) {
          reject(new Error('Your frequent components could not be retrieved.'));

          return;
        }

        if (!response.bugs.length) {
          reject(new Error(('Your frequent components could not be found.')));

          return;
        }

        const results = [];

        for (const { product, component } of response.bugs) {
          const index = results.findIndex(result => product === result.product && component === result.component);

          if (index > -1) {
            results[index].count++;
          } else {
            results.push({ product, component, count: 1 });
          }
        }

        // Sort in descending order
        results.sort((a, b) => (a.count < b.count ? 1 : a.count > b.count ? -1 : 0));

        resolve(results.slice(0, max));
      }, () => {
        reject(new Error('Your frequent components could not be retrieved.'));
      });
    });
  }
};

window.addEventListener('DOMContentLoaded', () => new Bugzilla.NewBugFrequentComp(), { once: true });