Bug 1422106 - Show broken heart when unverified in synced tabs sidebar/panel. r?markh draft
authorEdouard Oger <eoger@fastmail.com>
Thu, 30 Nov 2017 16:01:40 -0500
changeset 708610 5140daeb6b09288d07a367e6521155655c74d6e1
parent 708379 c0c5e19a32b8b1b74b9dc0360800aec01665f9b0
child 743201 4b062070da6658bd6b177dded40e8d9f826edb6a
push id92394
push userbmo:eoger@fastmail.com
push dateWed, 06 Dec 2017 21:31:54 +0000
reviewersmarkh
bugs1422106
milestone59.0a1
Bug 1422106 - Show broken heart when unverified in synced tabs sidebar/panel. r?markh MozReview-Commit-ID: BDTdmcIOHmn
browser/base/content/browser-menubar.inc
browser/base/content/browser-sets.inc
browser/base/content/browser-sync.js
browser/base/content/test/sync/browser_sync.js
browser/components/customizableui/content/panelUI.inc.xul
browser/components/customizableui/test/browser_synced_tabs_menu.js
browser/components/syncedtabs/SyncedTabsDeckComponent.js
browser/components/syncedtabs/sidebar.xhtml
browser/components/syncedtabs/test/browser/browser_sidebar_syncedtabslist.js
browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
browser/locales/en-US/chrome/browser/browser.dtd
browser/modules/test/browser/browser_BrowserUITelemetry_syncedtabs.js
browser/themes/shared/customizableui/panelUI.inc.css
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -472,22 +472,27 @@
                         key="key_openDownloads"
                         command="Tools:Downloads"/>
               <menuitem id="menu_openAddons"
                         label="&addons.label;"
                         accesskey="&addons.accesskey;"
                         key="key_openAddons"
                         command="Tools:Addons"/>
 
-              <!-- only one of sync-setup, sync-syncnowitem or sync-reauthitem will be showing at once -->
+              <!-- only one of sync-setup, sync-unverifieditem, sync-syncnowitem or sync-reauthitem will be showing at once -->
               <menuitem id="sync-setup"
                         label="&syncSignIn.label;"
                         accesskey="&syncSignIn.accesskey;"
                         observes="sync-setup-state"
                         oncommand="gSync.openPrefs('menubar')"/>
+              <menuitem id="sync-unverifieditem"
+                        label="&syncSignIn.label;"
+                        accesskey="&syncSignIn.accesskey;"
+                        observes="sync-unverified-state"
+                        oncommand="gSync.openPrefs('menubar')"/>
               <menuitem id="sync-syncnowitem"
                         label="&syncSyncNowItem.label;"
                         accesskey="&syncSyncNowItem.accesskey;"
                         observes="sync-syncnow-state"
                         oncommand="gSync.doSync(event);"/>
               <menuitem id="sync-reauthitem"
                         label="&syncReAuthItem.label;"
                         accesskey="&syncReAuthItem.accesskey;"
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -161,16 +161,17 @@
     <!-- Sync broadcasters -->
     <!-- A broadcaster of a number of attributes suitable for "sync now" UI -
         A 'syncstatus' attribute is set while actively syncing, and the label
         attribute which changes from "sync now" to "syncing" etc. -->
     <broadcaster id="sync-status"/>
     <!-- broadcasters of the "hidden" attribute to reflect setup state for
          menus -->
     <broadcaster id="sync-setup-state"/>
+    <broadcaster id="sync-unverified-state" hidden="true"/>
     <broadcaster id="sync-syncnow-state" hidden="true"/>
     <broadcaster id="sync-reauth-state" hidden="true"/>
     <broadcaster id="viewTabsSidebar" autoCheck="false" sidebartitle="&syncedTabs.sidebar.label;"
                  type="checkbox" group="sidebar"
                  sidebarurl="chrome://browser/content/syncedtabs/sidebar.xhtml"
                  oncommand="SidebarUI.toggle('viewTabsSidebar');"/>
     <broadcaster id="workOfflineMenuitemState"/>
 
--- a/browser/base/content/browser-sync.js
+++ b/browser/base/content/browser-sync.js
@@ -213,23 +213,25 @@ var gSync = {
 
   updateStateBroadcasters(state) {
     const status = state.status;
 
     // Start off with a clean slate
     document.getElementById("sync-reauth-state").hidden = true;
     document.getElementById("sync-setup-state").hidden = true;
     document.getElementById("sync-syncnow-state").hidden = true;
+    document.getElementById("sync-unverified-state").hidden = true;
 
     if (status == UIState.STATUS_LOGIN_FAILED) {
       // unhiding this element makes the menubar show the login failure state.
       document.getElementById("sync-reauth-state").hidden = false;
-    } else if (status == UIState.STATUS_NOT_CONFIGURED ||
-               status == UIState.STATUS_NOT_VERIFIED) {
+    } else if (status == UIState.STATUS_NOT_CONFIGURED) {
       document.getElementById("sync-setup-state").hidden = false;
+    } else if (status == UIState.STATUS_NOT_VERIFIED) {
+      document.getElementById("sync-unverified-state").hidden = false;
     } else {
       document.getElementById("sync-syncnow-state").hidden = false;
     }
   },
 
   updateSyncStatus(state) {
     const broadcaster = document.getElementById("sync-status");
     const syncingUI = broadcaster.getAttribute("syncstatus") == "active";
--- a/browser/base/content/test/sync/browser_sync.js
+++ b/browser/base/content/test/sync/browser_sync.js
@@ -103,18 +103,18 @@ add_task(async function test_ui_state_un
   checkPanelUIStatusBar({
     label: expectedLabel,
     tooltip: tooltipText,
     fxastatus: "unverified",
     avatarURL: null,
     syncing: false,
     syncNowTooltip: tooltipText
   });
-  checkRemoteTabsPanel("PanelUI-remotetabs-setupsync", false);
-  checkMenuBarItem("sync-setup");
+  checkRemoteTabsPanel("PanelUI-remotetabs-unverified", false);
+  checkMenuBarItem("sync-unverifieditem");
 });
 
 add_task(async function test_ui_state_loginFailed() {
   let state = {
     status: UIState.STATUS_LOGIN_FAILED,
     email: "foo@bar.com"
   };
 
@@ -171,26 +171,27 @@ function checkPanelUIStatusBar({label, t
   if (syncing != undefined && syncNowTooltip != undefined) {
     checkSyncNowButton("appMenu-fxa-icon", syncing, syncNowTooltip);
   }
 }
 
 function checkRemoteTabsPanel(expectedShownItemId, syncing, syncNowTooltip) {
   checkItemsVisiblities(["PanelUI-remotetabs-main",
                          "PanelUI-remotetabs-setupsync",
-                         "PanelUI-remotetabs-reauthsync"],
+                         "PanelUI-remotetabs-reauthsync",
+                         "PanelUI-remotetabs-unverified"],
                         expectedShownItemId);
 
   if (syncing != undefined && syncNowTooltip != undefined) {
     checkSyncNowButton("PanelUI-remotetabs-syncnow", syncing, syncNowTooltip);
   }
 }
 
 function checkMenuBarItem(expectedShownItemId) {
-  checkItemsVisiblities(["sync-setup", "sync-syncnowitem", "sync-reauthitem"],
+  checkItemsVisiblities(["sync-setup", "sync-syncnowitem", "sync-reauthitem", "sync-unverifieditem"],
                         expectedShownItemId);
 }
 
 function checkSyncNowButton(buttonId, syncing, tooltip = null) {
   const remoteTabsButton = document.getElementById(buttonId);
 
   is(remoteTabsButton.getAttribute("syncstatus"), syncing ? "active" : "", "button active has the right value");
   if (tooltip) {
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -486,16 +486,27 @@
                 class="PanelUI-remotetabs-instruction-box"
                 observes="sync-reauth-state">
             <image class="fxaSyncIllustrationIssue"/>
             <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label>
             <toolbarbutton class="PanelUI-remotetabs-button"
                            label="&appMenuRemoteTabs.signin.label;"
                            oncommand="gSync.openPrefs('synced-tabs');"/>
           </vbox>
+          <vbox id="PanelUI-remotetabs-unverified"
+                flex="1"
+                align="center"
+                class="PanelUI-remotetabs-instruction-box"
+                observes="sync-unverified-state">
+            <image class="fxaSyncIllustrationIssue"/>
+            <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.unverified.label;</label>
+            <toolbarbutton class="PanelUI-remotetabs-button"
+                           label="&appMenuRemoteTabs.signin.label;"
+                           oncommand="gSync.openPrefs('synced-tabs');"/>
+          </vbox>
         </hbox>
       </vbox>
     </panelview>
 
     <panelview id="PanelUI-bookmarks" flex="1" class="PanelUI-subView">
       <vbox class="panel-subview-body">
         <toolbarbutton id="panelMenuBookmarkThisPage"
                        class="subviewbutton subviewbutton-iconic"
--- a/browser/components/customizableui/test/browser_synced_tabs_menu.js
+++ b/browser/components/customizableui/test/browser_synced_tabs_menu.js
@@ -134,16 +134,23 @@ async function asyncCleanup() {
 
 // When Sync is not setup.
 add_task(async function() {
   gSync.updateAllUI({ status: UIState.STATUS_NOT_CONFIGURED });
   await openPrefsFromMenuPanel("PanelUI-remotetabs-setupsync", "synced-tabs");
 });
 add_task(asyncCleanup);
 
+// When Sync is configured in an unverified state.
+add_task(async function() {
+  gSync.updateAllUI({ status: UIState.STATUS_NOT_VERIFIED, email: "foo@bar.com" });
+  await openPrefsFromMenuPanel("PanelUI-remotetabs-unverified", "synced-tabs");
+});
+add_task(asyncCleanup);
+
 // When Sync is configured in a "needs reauthentication" state.
 add_task(async function() {
   gSync.updateAllUI({ status: UIState.STATUS_LOGIN_FAILED, email: "foo@bar.com" });
   await openPrefsFromMenuPanel("PanelUI-remotetabs-reauthsync", "synced-tabs");
 });
 
 // Test the Connect Another Device button
 add_task(async function() {
--- a/browser/components/syncedtabs/SyncedTabsDeckComponent.js
+++ b/browser/components/syncedtabs/SyncedTabsDeckComponent.js
@@ -58,16 +58,17 @@ function SyncedTabsDeckComponent({
 
 SyncedTabsDeckComponent.prototype = {
   PANELS: {
     TABS_CONTAINER: "tabs-container",
     TABS_FETCHING: "tabs-fetching",
     NOT_AUTHED_INFO: "notAuthedInfo",
     SINGLE_DEVICE_INFO: "singleDeviceInfo",
     TABS_DISABLED: "tabs-disabled",
+    UNVERIFIED: "unverified"
   },
 
   get container() {
     return this._deckView ? this._deckView.container : null;
   },
 
   init() {
     Services.obs.addObserver(this, this._SyncedTabs.TOPIC_TABS_CHANGED);
@@ -125,19 +126,22 @@ SyncedTabsDeckComponent.prototype = {
   // There's no good way to mock fxAccounts in browser tests where it's already
   // been instantiated, so we have this method for stubbing.
   _getSignedInUser() {
     return this._fxAccounts.getSignedInUser();
   },
 
   getPanelStatus() {
     return this._getSignedInUser().then(user => {
-      if (!user || !user.verified || this._SyncedTabs.loginFailed) {
+      if (!user || this._SyncedTabs.loginFailed) {
         return this.PANELS.NOT_AUTHED_INFO;
       }
+      if (!user.verified) {
+        return this.PANELS.UNVERIFIED;
+      }
       if (!this._SyncedTabs.isConfiguredToSyncTabs) {
         return this.PANELS.TABS_DISABLED;
       }
       if (!this._SyncedTabs.hasSyncedThisSession) {
         return this.PANELS.TABS_FETCHING;
       }
       return this._SyncedTabs.getTabClients().then(clients => {
         if (clients.length) {
--- a/browser/components/syncedtabs/sidebar.xhtml
+++ b/browser/components/syncedtabs/sidebar.xhtml
@@ -75,16 +75,21 @@
         <div class="tabs-fetching sync-state">
           <!-- Show intentionally blank panel, see bug 1239845 -->
         </div>
         <div class="notAuthedInfo sync-state">
           <div class="syncIllustration"></div>
           <p class="instructions">&syncedTabs.sidebar.notsignedin.label;</p>
           <button class="button sync-prefs">&fxaSignIn.label;</button>
         </div>
+        <div class="unverified sync-state">
+          <div class="syncIllustration"></div>
+          <p class="instructions">&syncedTabs.sidebar.unverified.label;</p>
+          <button class="button sync-prefs">&syncedTabs.sidebar.openprefs.label;</button>
+        </div>
         <div class="singleDeviceInfo sync-state">
           <div class="syncIllustrationIssue"></div>
           <p class="instructions">&syncedTabs.sidebar.noclients.subtitle;</p>
           <button class="button connect-device">&syncedTabs.sidebar.connectAnotherDevice;</button>
         </div>
         <div class="tabs-disabled sync-state">
           <div class="syncIllustrationIssue"></div>
           <p class="instructions">&syncedTabs.sidebar.tabsnotsyncing.label;</p>
--- a/browser/components/syncedtabs/test/browser/browser_sidebar_syncedtabslist.js
+++ b/browser/components/syncedtabs/test/browser/browser_sidebar_syncedtabslist.js
@@ -223,16 +223,22 @@ add_task(async function testSyncedTabsSi
 
   syncedTabsDeckComponent._getSignedInUser.restore();
   sinon.stub(syncedTabsDeckComponent, "_getSignedInUser", () => Promise.resolve(account));
   await syncedTabsDeckComponent.updatePanel();
   selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
   Assert.ok(selectedPanel.classList.contains("notAuthedInfo"),
     "not-authed panel is selected");
 
+  account = {verified: false};
+  await syncedTabsDeckComponent.updatePanel();
+  selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
+  Assert.ok(selectedPanel.classList.contains("unverified"),
+    "unverified panel is selected");
+
   account = {verified: true};
   await syncedTabsDeckComponent.updatePanel();
   selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected");
   Assert.ok(selectedPanel.classList.contains("tabs-disabled"),
     "tabs disabled panel is selected");
 
   SyncedTabs._internal.isConfiguredToSyncTabs = true;
   await syncedTabsDeckComponent.updatePanel();
--- a/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
+++ b/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
@@ -154,17 +154,17 @@ add_task(async function testPanelStatus(
   let account = null;
   sinon.stub(fxAccounts, "getSignedInUser", () => Promise.resolve(account));
   let result = await component.getPanelStatus();
   Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
 
   account = {verified: false};
 
   result = await component.getPanelStatus();
-  Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
+  Assert.equal(result, component.PANELS.UNVERIFIED);
 
   account = {verified: true};
 
   SyncedTabsMock.loginFailed = true;
   result = await component.getPanelStatus();
   Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
   SyncedTabsMock.loginFailed = false;
 
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -376,16 +376,17 @@ These should match what Safari and other
      when Sync is configured but syncing tabs is disabled. -->
 <!ENTITY appMenuRemoteTabs.tabsnotsyncing.label "Turn on tab syncing to view a list of tabs from your other devices.">
 <!-- LOCALIZATION NOTE (appMenuRemoteTabs.noclients.label): This is shown
      when Sync is configured but this appears to be the only device attached to
      the account. We also show links to download Firefox for android/ios. -->
 <!ENTITY appMenuRemoteTabs.noclients.subtitle "Want to see your tabs from other devices here?">
 <!ENTITY appMenuRemoteTabs.openprefs.label "Sync Preferences">
 <!ENTITY appMenuRemoteTabs.notsignedin.label "Sign in to view a list of tabs from your other devices.">
+<!ENTITY appMenuRemoteTabs.unverified.label "Your account needs to be verified.">
 <!ENTITY appMenuRemoteTabs.signin.label "Sign in to Sync">
 <!ENTITY appMenuRemoteTabs.managedevices.label "Manage Devices…">
 <!ENTITY appMenuRemoteTabs.sidebar.label "View Synced Tabs Sidebar">
 <!ENTITY appMenuRemoteTabs.connectdevice.label "Connect Another Device">
 
 <!ENTITY appMenuRecentHighlights.label "Recent Highlights">
 
 <!ENTITY customizeMenu.addToToolbar.label "Add to Toolbar">
@@ -789,16 +790,17 @@ you can use these alternative items. Oth
 
 <!-- LOCALIZATION NOTE (syncTabsMenu3.label): This appears in the history menu -->
 <!ENTITY syncTabsMenu3.label     "Synced Tabs">
 
 <!ENTITY syncedTabs.sidebar.label              "Synced Tabs">
 <!ENTITY syncedTabs.sidebar.noclients.label    "Sign in to Firefox from your other devices to view their tabs here.">
 <!ENTITY syncedTabs.sidebar.noclients.subtitle "Want to see your tabs from other devices here?">
 <!ENTITY syncedTabs.sidebar.notsignedin.label  "Sign in to view a list of tabs from your other devices.">
+<!ENTITY syncedTabs.sidebar.unverified.label   "Your account needs to be verified.">
 <!ENTITY syncedTabs.sidebar.notabs.label       "No open tabs">
 <!ENTITY syncedTabs.sidebar.openprefs.label    "Open &syncBrand.shortName.label; Preferences">
 <!-- LOCALIZATION NOTE (syncedTabs.sidebar.tabsnotsyncing.label): This is shown
      when Sync is configured but syncing tabs is disabled. -->
 <!ENTITY syncedTabs.sidebar.tabsnotsyncing.label       "Turn on tab syncing to view a list of tabs from your other devices.">
 <!ENTITY syncedTabs.sidebar.searchPlaceholder  "Search synced tabs">
 <!ENTITY syncedTabs.sidebar.connectAnotherDevice  "Connect Another Device">
 
--- a/browser/modules/test/browser/browser_BrowserUITelemetry_syncedtabs.js
+++ b/browser/modules/test/browser/browser_BrowserUITelemetry_syncedtabs.js
@@ -31,23 +31,25 @@ function mockSyncedTabs() {
   };
 
   let oldInternal = SyncedTabs._internal;
   SyncedTabs._internal = mockedInternal;
 
   // configure our broadcasters so we are in the right state.
   document.getElementById("sync-reauth-state").hidden = true;
   document.getElementById("sync-setup-state").hidden = true;
+  document.getElementById("sync-unverified-state").hidden = true;
   document.getElementById("sync-syncnow-state").hidden = false;
 
   registerCleanupFunction(() => {
     SyncedTabs._internal = oldInternal;
 
     document.getElementById("sync-reauth-state").hidden = true;
     document.getElementById("sync-setup-state").hidden = false;
+    document.getElementById("sync-unverified-state").hidden = true;
     document.getElementById("sync-syncnow-state").hidden = true;
   });
 }
 
 mockSyncedTabs();
 
 function promiseTabsUpdated() {
   return new Promise(resolve => {
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -713,16 +713,17 @@ toolbarbutton[constrain-size="true"][cui
   min-width: 19em;
 }
 
 /* Work around bug 1224412 - these boxes will cause scrollbars to appear when
    the panel is anchored to a toolbar button.
 */
 #PanelUI-remotetabs[mainview] #PanelUI-remotetabs-setupsync,
 #PanelUI-remotetabs[mainview] #PanelUI-remotetabs-reauthsync,
+#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-unverified,
 #PanelUI-remotetabs[mainview] #PanelUI-remotetabs-nodevicespane,
 #PanelUI-remotetabs[mainview] #PanelUI-remotetabs-tabsdisabledpane {
   min-height: calc(var(--panel-ui-sync-illustration-height) +
                    20px + /* margin of .PanelUI-remotetabs-button */
                    16px + /* padding of .PanelUI-remotetabs-button */
                    30px + /* margin of .PanelUI-remotetabs-instruction-label */
                    30px + 15px + /* padding of .PanelUI-remotetabs-instruction-box */
                    11em);