Bug 1546980 - Add ratings and user counts to discopane r=mstriemer,flod
☠☠ backed out by 2f3479842f91 ☠ ☠
authorRob Wu <rob@robwu.nl>
Mon, 06 May 2019 10:41:34 +0000
changeset 472705 56f4b00581076b591e83e69dbb20735f15b5a2ee
parent 472704 2209fbf12d8b8cb749316b7cfa55222c9a93844a
child 472706 c372247f4432fe0244a26e91d2bc28429ae67ab6
push id35976
push useropoprus@mozilla.com
push dateMon, 06 May 2019 21:44:12 +0000
treeherdermozilla-central@e9f5f01d8b8e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstriemer, flod
bugs1546980
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1546980 - Add ratings and user counts to discopane r=mstriemer,flod Differential Revision: https://phabricator.services.mozilla.com/D29481
toolkit/locales/en-US/toolkit/about/aboutAddons.ftl
toolkit/mozapps/extensions/content/aboutaddons.css
toolkit/mozapps/extensions/content/aboutaddons.html
toolkit/mozapps/extensions/content/aboutaddons.js
toolkit/mozapps/extensions/content/rating-star.css
toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js
--- a/toolkit/locales/en-US/toolkit/about/aboutAddons.ftl
+++ b/toolkit/locales/en-US/toolkit/about/aboutAddons.ftl
@@ -362,16 +362,20 @@ discopane-notice-recommendations =
 discopane-notice-learn-more = Learn more
 
 privacy-policy = Privacy Policy
 
 # Refers to the author of an add-on, shown below the name of the add-on.
 # Variables:
 #   $author (string) - The name of the add-on developer.
 created-by-author = by <a data-l10n-name="author">{ $author }</a>
+# Shows the number of daily users of the add-on.
+# Variables:
+#   $dailyUsers (number) - The number of daily users.
+user-count = Users: { $dailyUsers }
 install-extension-button = Add to { -brand-product-name }
 install-theme-button = Install Theme
 # The label of the button that appears after installing an add-on. Upon click,
 # the detailed add-on view is opened, from where the add-on can be managed.
 manage-addon-button = Manage
 find-more-addons = Find more add-ons
 
 ## Add-on actions
--- a/toolkit/mozapps/extensions/content/aboutaddons.css
+++ b/toolkit/mozapps/extensions/content/aboutaddons.css
@@ -137,16 +137,24 @@ recommended-addon-card .addon-descriptio
   flex-direction: column;
 }
 
 .disco-addon-author {
   font-size: 12px;
   font-weight: normal;
 }
 
+.disco-description-statistics {
+  margin-top: 1em;
+  display: grid;
+  grid-template-columns: repeat(2, max-content);
+  grid-column-gap: 2em;
+  align-items: center;
+}
+
 .disco-cta-button {
   font-size: 14px;
   flex-shrink: 0;
   flex-grow: 0;
   align-self: baseline;
 }
 
 .disco-cta-button[action="install-addon"]::before {
--- a/toolkit/mozapps/extensions/content/aboutaddons.html
+++ b/toolkit/mozapps/extensions/content/aboutaddons.html
@@ -64,16 +64,20 @@
       <button class="disco-cta-button" data-l10n-id="manage-addon-button" action="manage-addon"></button>
     </template>
 
     <template name="addon-description-in-disco-card">
       <div>
         <strong class="disco-description-intro"></strong>
         <span class="disco-description-main"></span>
       </div>
+      <div class="disco-description-statistics">
+        <five-star-rating></five-star-rating>
+        <span class="disco-user-count"></span>
+      </div>
     </template>
 
     <template name="addon-details">
       <div class="addon-detail-description"></div>
       <div class="addon-detail-contribute">
         <label data-l10n-id="detail-contributions-description"></label>
         <button
           class="addon-detail-contribute-button"
--- a/toolkit/mozapps/extensions/content/aboutaddons.js
+++ b/toolkit/mozapps/extensions/content/aboutaddons.js
@@ -190,16 +190,19 @@ class DiscoAddonWrapper {
     // The property names and values should have the same semantics as
     // AddonWrapper, to ease the reuse of helper functions in this file.
     this.id = repositoryAddon.id;
     this.type = repositoryAddon.type;
     this.name = repositoryAddon.name;
     this.screenshots = repositoryAddon.screenshots;
     this.sourceURI = repositoryAddon.sourceURI;
     this.creator = repositoryAddon.creator;
+    this.averageRating = repositoryAddon.averageRating;
+
+    this.dailyUsers = details.addon.average_daily_users;
 
     this.editorialHeading = details.heading_text;
     this.editorialDescription = details.description_text;
     this.iconURL = details.addon.icon_url;
     this.amoListingUrl = details.addon.url;
   }
 }
 
@@ -1218,17 +1221,33 @@ class RecommendedAddonCard extends HTMLE
     // the add-on's original description that would normally appear on a card.
     card.querySelector(".disco-description-main")
       .textContent = addon.editorialDescription;
     if (addon.editorialHeading) {
       card.querySelector(".disco-description-intro").textContent =
         addon.editorialHeading;
     }
 
-    // TODO: Append ratings and user count to description.
+    let hasStats = false;
+    if (addon.averageRating) {
+      hasStats = true;
+      card.querySelector("five-star-rating").rating = addon.averageRating;
+    } else {
+      card.querySelector("five-star-rating").hidden = true;
+    }
+
+    if (addon.dailyUsers) {
+      hasStats = true;
+      let userCountElem = card.querySelector(".disco-user-count");
+      document.l10n.setAttributes(userCountElem, "user-count", {
+        dailyUsers: addon.dailyUsers,
+      });
+    }
+
+    card.querySelector(".disco-description-statistics").hidden = !hasStats;
   }
 
   registerButtons(card, addon) {
     let installButton = card.querySelector("[action='install-addon']");
     if (addon.type == "theme") {
       document.l10n.setAttributes(installButton, "install-theme-button");
     } else {
       document.l10n.setAttributes(installButton, "install-extension-button");
--- a/toolkit/mozapps/extensions/content/rating-star.css
+++ b/toolkit/mozapps/extensions/content/rating-star.css
@@ -3,16 +3,20 @@
   --rating-star-spacing: 0.3ch;
 
   display: inline-grid;
   grid-template-columns: repeat(5, var(--rating-star-size));
   grid-column-gap: var(--rating-star-spacing);
   align-content: center;
 }
 
+:host([hidden]) {
+  display: none;
+}
+
 .rating-star {
   display: inline-block;
   width: var(--rating-star-size);
   height: var(--rating-star-size);
   background-image: url("chrome://mozapps/skin/extensions/rating-star.svg#empty");
   background-position: center;
   background-repeat: no-repeat;
   background-size: 100%;
--- a/toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js
@@ -34,16 +34,18 @@ AddonTestUtils.initMochitest(this);
 // stored in API_RESPONSE_FILE.
 function getTestExpectationFromApiResult(result) {
   return {
     typeIsTheme: result.addon.type === "statictheme",
     addonName: result.addon.name,
     authorName: result.addon.authors[0].name,
     editorialHead: result.heading_text,
     editorialBody: result.description_text,
+    dailyUsers: result.addon.average_daily_users,
+    rating: result.addon.ratings.average,
   };
 }
 
 /**
  * An internal server to support testing against the AMO API.
  *
  * // Start serving at http://example.com
  * let amoServer = new MockAPIServer("example.com");
@@ -439,16 +441,34 @@ add_task(async function discopane_with_r
       ok(card.querySelector(".card-heading-image").offsetWidth,
          "Preview image must be visible");
     } else {
       // Extension button + extended description.
       ok(installButton.matches("[data-l10n-id='install-extension-button'"),
          "Has extension install button");
       checkContent(".disco-description-intro", expectations.editorialHead);
       checkContent(".disco-description-main", expectations.editorialBody);
+
+      let ratingElem = card.querySelector("five-star-rating");
+      if (expectations.rating) {
+        is(ratingElem.rating, expectations.rating, "Expected rating value");
+        ok(ratingElem.offsetWidth, "Rating element is visible");
+      } else {
+        is(ratingElem.offsetWidth, 0, "Rating element is not visible");
+      }
+
+      let userCountElem = card.querySelector(".disco-user-count");
+      if (expectations.dailyUsers) {
+        Assert.deepEqual(
+          win.document.l10n.getAttributes(userCountElem),
+          {id: "user-count", args: {dailyUsers: expectations.dailyUsers}},
+          "Card count should be rendered");
+      } else {
+        is(userCountElem.offsetWidth, 0, "User count element is not visible");
+      }
     }
   }
 
   Assert.deepEqual(amoServer.requestCounters, {
     // The discovery API should be fetched only once.
     discoapi: 1,
     // Every card has either one extension icon, or one theme preview.
     png: apiResultArray.length,