From b3ad67dc224403c463fbea5ddb5f01dcacf3cb02 Mon Sep 17 00:00:00 2001 From: Kohei Yoshino Date: Mon, 24 Sep 2018 15:55:28 -0400 Subject: Bug 1473417 - Show often/recently used products/components on New Bug page --- .../en/default/global/choose-product.html.tmpl | 12 ++- extensions/BMO/web/js/new-bug-frequent-comp.js | 111 +++++++++++++++++++++ extensions/BMO/web/styles/choose_product.css | 19 ++++ template/en/default/global/header.html.tmpl | 4 + 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 extensions/BMO/web/js/new-bug-frequent-comp.js diff --git a/extensions/BMO/template/en/default/global/choose-product.html.tmpl b/extensions/BMO/template/en/default/global/choose-product.html.tmpl index 163c71f5c..74c9f7b0d 100644 --- a/extensions/BMO/template/en/default/global/choose-product.html.tmpl +++ b/extensions/BMO/template/en/default/global/choose-product.html.tmpl @@ -36,7 +36,10 @@ "extensions/BMO/web/styles/choose_product.css", "extensions/ProdCompSearch/web/styles/prod_comp_search.css", ]; - javascript_urls = [ "extensions/ProdCompSearch/web/js/prod_comp_search.js" ]; + javascript_urls = [ + "extensions/BMO/web/js/new-bug-frequent-comp.js", + "extensions/ProdCompSearch/web/js/prod_comp_search.js", + ]; cgi = Bugzilla.cgi; classification = cgi.param('classification'); @@ -68,6 +71,13 @@ %] +[% IF NOT is_describe %] + +[% END %] +

or choose from the following selections

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', + `` + ); + } 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; diff --git a/template/en/default/global/header.html.tmpl b/template/en/default/global/header.html.tmpl index 9db9a1404..4c6069c74 100644 --- a/template/en/default/global/header.html.tmpl +++ b/template/en/default/global/header.html.tmpl @@ -107,6 +107,10 @@ [% END %] [%- js_BUGZILLA = { + user => { + # TODO: Move all properties form bug_modal/header.html.tmpl + login => user.login, + }, param => { maxattachmentsize => Param('maxattachmentsize'), maxusermatches => Param('maxusermatches'), -- cgit v1.2.3-24-g4f1b