Bug 1298011 - Update the Synced Tabs sidebar UI when account password changed. r?markh
MozReview-Commit-ID: 2cJK8ZAQH5R
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -132,25 +132,25 @@ var gSyncUI = {
// Otherwise we are configured for legacy Sync, which has no verification
// concept.
return Promise.resolve(false);
},
// Note that we don't show login errors in a notification bar here, but do
// still need to track a login-failed state so the "Tools" menu updates
// with the correct state.
- _loginFailed() {
+ loginFailed() {
// If Sync isn't already ready, we don't want to force it to initialize
// by referencing Weave.Status - and it isn't going to be accurate before
// Sync is ready anyway.
if (!this.weaveService.ready) {
- this.log.debug("_loginFailed has sync not ready, so returning false");
+ this.log.debug("loginFailed has sync not ready, so returning false");
return false;
}
- this.log.debug("_loginFailed has sync state=${sync}",
+ this.log.debug("loginFailed has sync state=${sync}",
{ sync: Weave.Status.login});
return Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED;
},
// Kick off an update of the UI - does *not* return a promise.
updateUI() {
this._promiseUpdateUI().catch(err => {
this.log.error("updateUI failed", err);
@@ -158,17 +158,17 @@ var gSyncUI = {
},
// Updates the UI - returns a promise.
_promiseUpdateUI() {
return this._needsSetup().then(needsSetup => {
if (!gBrowser)
return Promise.resolve();
- let loginFailed = this._loginFailed();
+ let loginFailed = this.loginFailed();
// 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;
if (CloudSync && CloudSync.ready && CloudSync().adapters.count) {
document.getElementById("sync-syncnow-state").hidden = false;
@@ -261,17 +261,17 @@ var gSyncUI = {
});
},
// Handle clicking the toolbar button - which either opens the Sync setup
// pages or forces a sync now. Does *not* return a promise as it is called
// via the UI.
handleToolbarButton() {
this._needsSetup().then(needsSetup => {
- if (needsSetup || this._loginFailed()) {
+ if (needsSetup || this.loginFailed()) {
this.openSetup();
} else {
this.doSync();
}
}).catch(err => {
this.log.error("Failed to handle toolbar button command", err);
});
},
@@ -375,17 +375,17 @@ var gSyncUI = {
let email;
try {
email = Services.prefs.getCharPref("services.sync.username");
} catch (ex) {}
let needsSetup = yield this._needsSetup();
let needsVerification = yield this._needsVerification();
- let loginFailed = this._loginFailed();
+ let loginFailed = this.loginFailed();
// This is a little messy as the Sync buttons are 1/2 Sync related and
// 1/2 FxA related - so for some strings we use Sync strings, but for
// others we reach into gFxAccounts for strings.
let tooltiptext;
if (needsVerification) {
// "needs verification"
tooltiptext = gFxAccounts.strings.formatStringFromName("verifyDescription", [email], 1);
} else if (needsSetup) {
--- a/browser/components/syncedtabs/SyncedTabsDeckComponent.js
+++ b/browser/components/syncedtabs/SyncedTabsDeckComponent.js
@@ -67,16 +67,17 @@ SyncedTabsDeckComponent.prototype = {
get container() {
return this._deckView ? this._deckView.container : null;
},
init() {
Services.obs.addObserver(this, this._SyncedTabs.TOPIC_TABS_CHANGED, false);
Services.obs.addObserver(this, FxAccountsCommon.ONLOGIN_NOTIFICATION, false);
+ Services.obs.addObserver(this, "weave:service:login:change", false);
// Go ahead and trigger sync
this._SyncedTabs.syncTabs()
.catch(Cu.reportError);
this._deckView = new this._DeckView(this._window, this.tabListComponent, {
onAndroidClick: event => this.openAndroidLink(event),
oniOSClick: event => this.openiOSLink(event),
@@ -89,42 +90,44 @@ SyncedTabsDeckComponent.prototype = {
this._deckStore.setPanels(Object.keys(this.PANELS).map(k => this.PANELS[k]));
// Set the initial panel to display
this.updatePanel();
},
uninit() {
Services.obs.removeObserver(this, this._SyncedTabs.TOPIC_TABS_CHANGED);
Services.obs.removeObserver(this, FxAccountsCommon.ONLOGIN_NOTIFICATION);
+ Services.obs.removeObserver(this, "weave:service:login:change");
this._deckView.destroy();
},
observe(subject, topic, data) {
switch (topic) {
case this._SyncedTabs.TOPIC_TABS_CHANGED:
this._syncedTabsListStore.getData();
this.updatePanel();
break;
case FxAccountsCommon.ONLOGIN_NOTIFICATION:
+ case "weave:service:login:change":
this.updatePanel();
break;
default:
break;
}
},
// There's no good way to mock fxAccounts in browser tests where it's already
// been instantiated, so we have this method for stubbing.
_accountStatus() {
return this._fxAccounts.accountStatus();
},
getPanelStatus() {
return this._accountStatus().then(exists => {
- if (!exists) {
+ if (!exists || this._getChromeWindow(this._window).gSyncUI.loginFailed()) {
return this.PANELS.NOT_AUTHED_INFO;
}
if (!this._SyncedTabs.isConfiguredToSyncTabs) {
return this.PANELS.TABS_DISABLED;
}
if (!this._SyncedTabs.hasSyncedThisSession) {
return this.PANELS.TABS_FETCHING;
}
--- a/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
+++ b/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
@@ -117,46 +117,68 @@ add_task(function* testObserver() {
Assert.ok(listStore.getData.called, "gets list data");
Assert.ok(component.updatePanel.calledTwice, "triggers panel update");
Services.obs.notifyObservers(null, FxAccountsCommon.ONLOGIN_NOTIFICATION, "");
Assert.ok(component.observe.calledWith(null, FxAccountsCommon.ONLOGIN_NOTIFICATION, ""),
"component is notified of login");
Assert.equal(component.updatePanel.callCount, 3, "triggers panel update again");
+
+ Services.obs.notifyObservers(null, "weave:service:login:change", "");
+
+ Assert.ok(component.observe.calledWith(null, "weave:service:login:change", ""),
+ "component is notified of login change");
+ Assert.equal(component.updatePanel.callCount, 4, "triggers panel update again");
});
add_task(function* testPanelStatus() {
let deckStore = new SyncedTabsDeckStore();
let listStore = new SyncedTabsListStore();
let listComponent = {};
let fxAccounts = {
accountStatus() {}
};
let SyncedTabsMock = {
getTabClients() {}
};
+ let loginFailed = false;
+ let chromeWindowMock = {
+ gSyncUI: {
+ loginFailed() {
+ return loginFailed;
+ }
+ }
+ };
+ let getChromeWindowMock = sinon.stub();
+ getChromeWindowMock.returns(chromeWindowMock);
sinon.stub(listStore, "getData");
let component = new SyncedTabsDeckComponent({
fxAccounts,
deckStore,
listComponent,
SyncedTabs: SyncedTabsMock,
+ getChromeWindowMock
});
let isAuthed = false;
sinon.stub(fxAccounts, "accountStatus", () => Promise.resolve(isAuthed));
let result = yield component.getPanelStatus();
Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
isAuthed = true;
+ loginFailed = true;
+ result = yield component.getPanelStatus();
+ Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
+ loginFailed = false;
+
SyncedTabsMock.isConfiguredToSyncTabs = false;
result = yield component.getPanelStatus();
Assert.equal(result, component.PANELS.TABS_DISABLED);
SyncedTabsMock.isConfiguredToSyncTabs = true;
SyncedTabsMock.hasSyncedThisSession = false;
result = yield component.getPanelStatus();