Bug 1269277 - Add Manage Device button in Synced Tabs menu/sidebar. r=markh

MozReview-Commit-ID: 2BMgLeI0DNF

--HG--
extra : rebase_source : 048e6b5ede97b4908a65997cb674153c5e34c21d
This commit is contained in:
Edouard Oger 2017-03-09 15:53:08 -05:00
Родитель 68316163f8
Коммит a28ba6f4da
8 изменённых файлов: 80 добавлений и 65 удалений

Просмотреть файл

@ -323,6 +323,13 @@ var gFxAccounts = {
this.openAccountsPage("reauth", { entrypoint: entryPoint });
},
async openDevicesManagementPage(entryPoint) {
let url = await fxAccounts.promiseAccountsManageDevicesURI(entryPoint);
switchToTabHavingURI(url, true, {
replaceQueryString: true
});
},
sendTabToDevice(url, clientId, title) {
Weave.Service.clientsEngine.sendURIToClientForDisplay(url, clientId, title);
},

Просмотреть файл

@ -478,6 +478,10 @@
<menuitem label="&syncedTabs.context.openAllInTabs.label;"
accesskey="&syncedTabs.context.openAllInTabs.accesskey;"
id="syncedTabsOpenAllInTabs"/>
<menuitem label="&syncedTabs.context.managedevices.label;"
accesskey="&syncedTabs.context.managedevices.accesskey;"
id="syncedTabsManageDevices"
oncommand="gFxAccounts.openDevicesManagementPage('syncedtabs-sidebar');"/>
<menuitem label="&syncSyncNowItem.label;"
accesskey="&syncSyncNowItem.accesskey;"
id="syncedTabsRefresh"/>

Просмотреть файл

@ -114,6 +114,10 @@
class="subviewbutton"
observes="viewTabsSidebar"
label="&appMenuRemoteTabs.sidebar.label;"/>
<toolbarbutton id="PanelUI-remotetabs-view-managedevices"
class="subviewbutton"
label="&appMenuRemoteTabs.managedevices.label;"
oncommand="gFxAccounts.openDevicesManagementPage('syncedtabs-menupanel');"/>
<toolbarbutton id="PanelUI-remotetabs-syncnow"
observes="sync-status"
class="subviewbutton"

Просмотреть файл

@ -109,6 +109,8 @@ XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
return Services.strings.createBundle("chrome://browser/locale/browser.properties");
});
XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts", "resource://gre/modules/FxAccounts.jsm");
// Seconds of idle before trying to create a bookmarks backup.
const BOOKMARKS_BACKUP_IDLE_TIME_SEC = 8 * 60;
// Minimum interval between backups. We try to not create more than one backup
@ -2302,11 +2304,11 @@ BrowserGlue.prototype = {
let body = accountsBundle.formatStringFromName("deviceConnectedBody" +
(deviceName ? "" : ".noDeviceName"),
[deviceName], 1);
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.settings.devices.uri");
function clickCallback(subject, topic, data) {
async function clickCallback(subject, topic, data) {
if (topic != "alertclickcallback")
return;
let url = await fxAccounts.promiseAccountsManageDevicesURI("device-connected-notification");
let win = RecentWindow.getMostRecentBrowserWindow({private: false});
if (!win) {
Services.appShell.hiddenDOMWindow.open(url);
@ -2316,7 +2318,7 @@ BrowserGlue.prototype = {
}
try {
AlertsService.showAlertNotification(null, title, body, true, url, clickCallback);
AlertsService.showAlertNotification(null, title, body, true, null, clickCallback);
} catch (ex) {
Cu.reportError("Error notifying of a new Sync device: " + ex);
}

Просмотреть файл

@ -524,7 +524,8 @@ TabListView.prototype = {
while (el) {
let show = false;
if (showTabOptions) {
if (el.getAttribute("id") != "syncedTabsOpenAllInTabs") {
if (el.getAttribute("id") != "syncedTabsOpenAllInTabs" &&
el.getAttribute("id") != "syncedTabsManageDevices") {
show = true;
}
} else if (el.getAttribute("id") == "syncedTabsOpenAllInTabs") {
@ -532,6 +533,8 @@ TabListView.prototype = {
show = tabs.length > 0;
} else if (el.getAttribute("id") == "syncedTabsRefresh") {
show = true;
} else if (el.getAttribute("id") == "syncedTabsManageDevices") {
show = true;
}
el.hidden = !show;

Просмотреть файл

@ -310,6 +310,7 @@ add_task(function* testSyncedTabsSidebarContextMenu() {
["menuitem#syncedTabsCopySelected", { hidden: false }],
["menuseparator", { hidden: false }],
["menuitem#syncedTabsOpenAllInTabs", { hidden: true }],
["menuitem#syncedTabsManageDevices", { hidden: true }],
["menuitem#syncedTabsRefresh", { hidden: false }],
];
yield* testContextMenu(syncedTabsDeckComponent,
@ -317,7 +318,7 @@ add_task(function* testSyncedTabsSidebarContextMenu() {
"#tab-7cqCr77ptzX3-0",
tabMenuItems);
info("Right-clicking a client should show the Open All in Tabs action");
info("Right-clicking a client should show the Open All in Tabs and Manage devices actions");
let sidebarMenuItems = [
["menuitem#syncedTabsOpenSelected", { hidden: true }],
["menuitem#syncedTabsOpenSelectedInTab", { hidden: true }],
@ -328,6 +329,7 @@ add_task(function* testSyncedTabsSidebarContextMenu() {
["menuitem#syncedTabsCopySelected", { hidden: true }],
["menuseparator", { hidden: true }],
["menuitem#syncedTabsOpenAllInTabs", { hidden: false }],
["menuitem#syncedTabsManageDevices", { hidden: false }],
["menuitem#syncedTabsRefresh", { hidden: false }],
];
yield* testContextMenu(syncedTabsDeckComponent,
@ -346,6 +348,7 @@ add_task(function* testSyncedTabsSidebarContextMenu() {
["menuitem#syncedTabsCopySelected", { hidden: true }],
["menuseparator", { hidden: true }],
["menuitem#syncedTabsOpenAllInTabs", { hidden: true }],
["menuitem#syncedTabsManageDevices", { hidden: false }],
["menuitem#syncedTabsRefresh", { hidden: false }],
];
yield* testContextMenu(syncedTabsDeckComponent,

Просмотреть файл

@ -377,6 +377,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY appMenuRemoteTabs.openprefs.label "Sync Preferences">
<!ENTITY appMenuRemoteTabs.notsignedin.label "Sign in to view a list of tabs from your other devices.">
<!ENTITY appMenuRemoteTabs.signin.label "Sign in to Sync">
<!ENTITY appMenuRemoteTabs.managedevices.label "Manage Devices…">
<!ENTITY appMenuRemoteTabs.sidebar.label "View Synced Tabs Sidebar">
<!ENTITY customizeMenu.addToToolbar.label "Add to Toolbar">
@ -785,6 +786,8 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY syncedTabs.context.openAllInTabs.label "Open All in Tabs">
<!ENTITY syncedTabs.context.openAllInTabs.accesskey "O">
<!ENTITY syncedTabs.context.managedevices.label "Manage Devices…">
<!ENTITY syncedTabs.context.managedevices.accesskey "D">
<!ENTITY syncBrand.shortName.label "Sync">

Просмотреть файл

@ -7,6 +7,8 @@ this.EXPORTED_SYMBOLS = ["fxAccounts", "FxAccounts"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.importGlobalProperties(["URL"]);
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://services-common/utils.js");
@ -59,6 +61,7 @@ var publicProperties = [
"promiseAccountsChangeProfileURI",
"promiseAccountsForceSigninURI",
"promiseAccountsManageURI",
"promiseAccountsManageDevicesURI",
"promiseAccountsSignUpURI",
"promiseAccountsSignInURI",
"removeCachedOAuthToken",
@ -1263,80 +1266,66 @@ FxAccountsInternal.prototype = {
return FxAccountsConfig.promiseAccountsSignInURI();
},
// Returns a promise that resolves with the URL to use to force a re-signin
// of the current account.
promiseAccountsForceSigninURI: Task.async(function *() {
yield FxAccountsConfig.ensureConfigured();
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.force_auth.uri");
if (this.requiresHttps() && !/^https:/.test(url)) { // Comment to un-break emacs js-mode highlighting
/**
* Pull an URL defined in the user preferences, add the current UID and email
* to the query string, add entrypoint and extra params to the query string if
* requested.
* @param {string} prefName The preference name from where to pull the URL to format.
* @param {string} [entrypoint] "entrypoint" searchParam value.
* @param {Object.<string, string>} [extraParams] Additionnal searchParam key and values.
* @returns {Promise.<string>} A promise that resolves to the formatted URL
*/
async _formatPrefURL(prefName, entrypoint, extraParams) {
let url = new URL(Services.urlFormatter.formatURLPref(prefName));
if (this.requiresHttps() && url.protocol != "https:") {
throw new Error("Firefox Accounts server must use HTTPS");
}
let currentState = this.currentAccountState;
// but we need to append the email address onto a query string.
return this.getSignedInUser().then(accountData => {
if (!accountData) {
return null;
let accountData = await this.getSignedInUser();
if (!accountData) {
return Promise.resolve(null);
}
url.searchParams.append("uid", accountData.uid);
url.searchParams.append("email", accountData.email);
if (entrypoint) {
url.searchParams.append("entrypoint", entrypoint);
}
if (extraParams) {
for (let [k, v] of Object.entries(extraParams)) {
url.searchParams.append(k, v);
}
let newQueryPortion = url.indexOf("?") == -1 ? "?" : "&";
newQueryPortion += "email=" + encodeURIComponent(accountData.email);
return url + newQueryPortion;
}).then(result => currentState.resolve(result));
}),
}
return this.currentAccountState.resolve(url.href);
},
// Returns a promise that resolves with the URL to use to force a re-signin
// of the current account.
async promiseAccountsForceSigninURI() {
await FxAccountsConfig.ensureConfigured();
return this._formatPrefURL("identity.fxaccounts.remote.force_auth.uri");
},
// Returns a promise that resolves with the URL to use to change
// the current account's profile image.
// if settingToEdit is set, the profile page should hightlight that setting
// for the user to edit.
promiseAccountsChangeProfileURI(entrypoint, settingToEdit = null) {
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.settings.uri");
async promiseAccountsChangeProfileURI(entrypoint, settingToEdit = null) {
let extraParams;
if (settingToEdit) {
url += (url.indexOf("?") == -1 ? "?" : "&") +
"setting=" + encodeURIComponent(settingToEdit);
extraParams = { setting: settingToEdit };
}
if (this.requiresHttps() && !/^https:/.test(url)) { // Comment to un-break emacs js-mode highlighting
throw new Error("Firefox Accounts server must use HTTPS");
}
let currentState = this.currentAccountState;
// but we need to append the email address onto a query string.
return this.getSignedInUser().then(accountData => {
if (!accountData) {
return null;
}
let newQueryPortion = url.indexOf("?") == -1 ? "?" : "&";
newQueryPortion += "email=" + encodeURIComponent(accountData.email);
newQueryPortion += "&uid=" + encodeURIComponent(accountData.uid);
if (entrypoint) {
newQueryPortion += "&entrypoint=" + encodeURIComponent(entrypoint);
}
return url + newQueryPortion;
}).then(result => currentState.resolve(result));
return this._formatPrefURL("identity.fxaccounts.settings.uri", entrypoint, extraParams);
},
// Returns a promise that resolves with the URL to use to manage the current
// user's FxA acct.
promiseAccountsManageURI(entrypoint) {
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.settings.uri");
if (this.requiresHttps() && !/^https:/.test(url)) { // Comment to un-break emacs js-mode highlighting
throw new Error("Firefox Accounts server must use HTTPS");
}
let currentState = this.currentAccountState;
// but we need to append the uid and email address onto a query string
// (if the server has no matching uid it will offer to sign in with the
// email address)
return this.getSignedInUser().then(accountData => {
if (!accountData) {
return null;
}
let newQueryPortion = url.indexOf("?") == -1 ? "?" : "&";
newQueryPortion += "uid=" + encodeURIComponent(accountData.uid) +
"&email=" + encodeURIComponent(accountData.email);
if (entrypoint) {
newQueryPortion += "&entrypoint=" + encodeURIComponent(entrypoint);
}
return url + newQueryPortion;
}).then(result => currentState.resolve(result));
async promiseAccountsManageURI(entrypoint) {
return this._formatPrefURL("identity.fxaccounts.settings.uri", entrypoint);
},
// Returns a promise that resolves with the URL to use to manage the devices in
// the current user's FxA acct.
async promiseAccountsManageDevicesURI(entrypoint) {
return this._formatPrefURL("identity.fxaccounts.settings.devices.uri", entrypoint);
},
/**