diff options
Diffstat (limited to 'extensions/BMO/web')
-rw-r--r-- | extensions/BMO/web/js/new-bug-frequent-comp.js | 111 | ||||
-rw-r--r-- | extensions/BMO/web/styles/choose_product.css | 19 |
2 files changed, 130 insertions, 0 deletions
diff --git a/extensions/BMO/web/js/new-bug-frequent-comp.js b/extensions/BMO/web/js/new-bug-frequent-comp.js new file mode 100644 index 000000000..4ca1fcf89 --- /dev/null +++ b/extensions/BMO/web/js/new-bug-frequent-comp.js @@ -0,0 +1,111 @@ +/* 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; + + try { + const results = await this.fetch(); + + this.$message.remove(); + this.$results.insertAdjacentHTML('beforeend', + `<ul>${results.map(({ product, component }) => ( + `<li><a href="/enter_bug.cgi?product=${encodeURIComponent(product)}&component=` + + `${encodeURIComponent(component)}">${product.htmlEncode()} :: ${component.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 }); diff --git a/extensions/BMO/web/styles/choose_product.css b/extensions/BMO/web/styles/choose_product.css index 5fd8c49e7..a4ecf749f 100644 --- a/extensions/BMO/web/styles/choose_product.css +++ b/extensions/BMO/web/styles/choose_product.css @@ -16,6 +16,22 @@ text-align: left; } +#frequent-components ul { + display: flex; + flex-wrap: wrap; + justify-content: center; + margin: 8px auto; + padding: 0; + list-style-type: none; + white-space: nowrap; +} + +#frequent-components li { + flex: none; + margin: 8px 16px; + padding: 0; +} + #product-list { margin: 32px 0; } @@ -55,6 +71,7 @@ } @media screen and (min-width: 1024px) { + #frequent-components ul, #product-list .tile { width: 960px; } @@ -65,6 +82,7 @@ } @media screen and (min-width: 768px) and (max-width: 1023px) { + #frequent-components ul, #product-list .tile { width: 720px; } @@ -75,6 +93,7 @@ } @media screen and (max-width: 767px) { + #frequent-components ul, #product-list .tile { width: auto; max-width: 480px; |