commit 5d2d401bd7e8e70c1dde136c24e2b94c5f803d5a parent 7d6cfb3a6f950e30a8c5297f3bb1021a24843dfd Author: Alexandru Marc <amarc@mozilla.com> Date: Fri, 31 Oct 2025 17:04:07 +0200 Revert "Bug 1990551 - Send tabs to other profiles from context menu. r=profiles-reviewers,fluent-reviewers,bolsson,jhirsch,sthompson" for causing bc failures @ browser_moveTabToProfile This reverts commit 3b863837a5966ebe1a6e2f548a209377b8300a7d. Diffstat:
14 files changed, 13 insertions(+), 317 deletions(-)
diff --git a/browser/base/content/browser-profiles.js b/browser/base/content/browser-profiles.js @@ -194,16 +194,6 @@ var gProfiles = { }); }, - async openTabsInProfile(aEvent, tabsToOpen) { - let profile = await SelectableProfileService.getProfile( - aEvent.target.getAttribute("profileid") - ); - SelectableProfileService.launchInstance( - profile, - tabsToOpen.map(tab => tab.linkedBrowser.currentURI.spec) - ); - }, - async handleCommand(aEvent) { switch (aEvent.target.id) { /* App menu button events */ @@ -257,16 +247,6 @@ var gProfiles = { this.launchProfile(aEvent.sourceEvent); break; } - case "Profiles:MoveTabsToProfile": { - let tabs; - if (TabContextMenu.contextTab.multiselected) { - tabs = gBrowser.selectedTabs; - } else { - tabs = [TabContextMenu.contextTab]; - } - this.openTabsInProfile(aEvent.sourceEvent, tabs); - break; - } } /* Subpanel profile events that may be triggered in FxA menu or app menu */ if (aEvent.target.classList.contains("profile-item")) { @@ -447,50 +427,4 @@ var gProfiles = { profilesList.appendChild(button); } }, - - async populateMoveTabMenu(menuPopup) { - if (!SelectableProfileService.initialized) { - return; - } - - const profiles = await SelectableProfileService.getAllProfiles(); - const currentProfile = SelectableProfileService.currentProfile; - - const separator = document.getElementById("moveTabSeparator"); - separator.hidden = profiles.length < 2; - - let existingItems = [ - ...menuPopup.querySelectorAll(":scope > menuitem[profileid]"), - ]; - - for (let profile of profiles) { - if (profile.id === currentProfile.id) { - continue; - } - - let menuitem = existingItems.shift(); - let isNewItem = !menuitem; - if (isNewItem) { - menuitem = document.createXULElement("menuitem"); - menuitem.setAttribute("tbattr", "tabbrowser-multiple-visible"); - menuitem.setAttribute("data-l10n-id", "move-to-new-profile"); - menuitem.setAttribute("command", "Profiles:MoveTabsToProfile"); - } - - menuitem.disabled = false; - menuitem.setAttribute("profileid", profile.id); - menuitem.setAttribute( - "data-l10n-args", - JSON.stringify({ profileName: profile.name }) - ); - - if (isNewItem) { - menuPopup.appendChild(menuitem); - } - } - // If there's any old item to remove, do so now. - for (let remaining of existingItems) { - remaining.remove(); - } - }, }; diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc @@ -78,7 +78,6 @@ <command id="Profiles:CreateProfile" /> <command id="Profiles:ManageProfiles" /> <command id="Profiles:LaunchProfile" /> - <command id="Profiles:MoveTabsToProfile" /> <command id="Browser:NextTab" /> <command id="Browser:PrevTab" /> <command id="Browser:ShowAllTabs" /> diff --git a/browser/base/content/browser-sets.js b/browser/base/content/browser-sets.js @@ -203,7 +203,6 @@ document.addEventListener( case "Profiles:CreateProfile": case "Profiles:ManageProfiles": case "Profiles:LaunchProfile": - case "Profiles:MoveTabsToProfile": gProfiles.handleCommand(event); break; case "Tools:Search": diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content/main-popupset.inc.xhtml @@ -75,7 +75,6 @@ tbattr="tabbrowser-multiple-visible"/> <menuitem id="context_openTabInWindow" data-lazy-l10n-id="move-to-new-window" tbattr="tabbrowser-multiple-visible"/> - <menuseparator id="moveTabSeparator" hidden="true"/> </menupopup> </menu> <menu id="context_sendTabToDevice" diff --git a/browser/base/content/main-popupset.js b/browser/base/content/main-popupset.js @@ -532,9 +532,6 @@ document.addEventListener( case "tabContextMenu": TabContextMenu.addNewBadge(); break; - case "moveTabOptionsMenu": - gProfiles.populateMoveTabMenu(event.target); - break; } }); diff --git a/browser/components/backup/BackupService.sys.mjs b/browser/components/backup/BackupService.sys.mjs @@ -3315,10 +3315,8 @@ export class BackupService extends EventTarget { profile, // Using URL Search Params on this about: page didn't work because // the RPM communication so we use the hash and parse that instead. - [ - "about:editprofile" + - (copiedProfile ? `#copiedProfileName=${copiedProfile.name}` : ""), - ] + "about:editprofile" + + (copiedProfile ? `#copiedProfileName=${copiedProfile.name}` : "") ); } diff --git a/browser/components/profiles/SelectableProfileService.sys.mjs b/browser/components/profiles/SelectableProfileService.sys.mjs @@ -631,17 +631,13 @@ class SelectableProfileServiceClass extends EventEmitter { * Launch a new Firefox instance using the given selectable profile. * * @param {SelectableProfile} aProfile The profile to launch - * @param {Array<string>} aUrls An array of urls to open in launched profile + * @param {string} aUrl A url to open in launched profile */ - launchInstance(aProfile, aUrls) { + launchInstance(aProfile, aUrl) { let args = []; - if (aUrls?.length) { - // See https://wiki.mozilla.org/Firefox/CommandLineOptions#-url_URL - // Use '-new-tab' instead of '-url' because when opening multiple URLs, - // Firefox always opens them as tabs in a new window and we want to - // attempt opening these tabs in an existing window. - args.push(...aUrls.flatMap(url => ["-new-tab", url])); + if (aUrl) { + args.push("-url", aUrl); } else { args.push(`--${COMMAND_LINE_ACTIVATE}`); } @@ -1456,7 +1452,7 @@ class SelectableProfileServiceClass extends EventEmitter { let profile = await this.#createProfile(); if (launchProfile) { - this.launchInstance(profile, ["about:newprofile"]); + this.launchInstance(profile, "about:newprofile"); } return profile; } diff --git a/browser/components/profiles/content/profile-selector.mjs b/browser/components/profiles/content/profile-selector.mjs @@ -126,7 +126,7 @@ export class ProfileSelector extends MozLitElement { await this.setLaunchArguments(profile, url ? ["-url", url] : []); await this.selectableProfileService.uninit(); } else { - this.selectableProfileService.launchInstance(profile, url ? [url] : []); + this.selectableProfileService.launchInstance(profile, url); } window.close(); diff --git a/browser/components/profiles/tests/browser/browser.toml b/browser/components/profiles/tests/browser/browser.toml @@ -45,8 +45,6 @@ skip-if = [ ["browser_menubar_profiles.js"] head = "../unit/head.js head.js" -["browser_moveTabToProfile.js"] - ["browser_notify_changes.js"] run-if = ["os != 'linux'"] # Linux clients cannot remote themselves. skip-if = ["os == 'mac' && os_version == '15.30' && arch == 'aarch64' && opt && !socketprocess_networking"] # Bug 1929273 diff --git a/browser/components/profiles/tests/browser/browser_moveTabToProfile.js b/browser/components/profiles/tests/browser/browser_moveTabToProfile.js @@ -1,220 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - https://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -const { sinon } = ChromeUtils.importESModule( - "resource://testing-common/Sinon.sys.mjs" -); -const { ObjectUtils } = ChromeUtils.importESModule( - "resource://gre/modules/ObjectUtils.sys.mjs" -); - -const EXAMPLE_URL = "https://example.com/"; - -async function addTab(url = EXAMPLE_URL) { - const tab = BrowserTestUtils.addTab(gBrowser, url, { - skipAnimation: true, - }); - const browser = gBrowser.getBrowserForTab(tab); - await BrowserTestUtils.browserLoaded(browser); - return tab; -} - -async function openContextMenu(tab) { - let contextMenu = document.getElementById("tabContextMenu"); - let openTabContextMenuPromise = BrowserTestUtils.waitForPopupEvent( - contextMenu, - "shown" - ); - - await sendAndWaitForMouseEvent(tab, { type: "contextmenu" }); - await openTabContextMenuPromise; - return contextMenu; -} - -async function openMoveTabOptionsMenuPopup(contextMenu) { - let moveTabMenuItem = contextMenu.querySelector("#context_moveTabOptions"); - let subMenu = contextMenu.querySelector("#moveTabOptionsMenu"); - let popupShown = BrowserTestUtils.waitForEvent(subMenu, "popupshown"); - - if (AppConstants.platform === "macosx") { - moveTabMenuItem.openMenu(true); - } else { - await sendAndWaitForMouseEvent(moveTabMenuItem); - } - - await popupShown; - - const separator = subMenu.querySelector("#moveTabSeparator"); - await TestUtils.waitForCondition( - () => - BrowserTestUtils.isVisible(separator) && - BrowserTestUtils.isVisible(separator.nextElementSibling) - ); - - return subMenu; -} - -async function clickMoveToProfileMenuItem(subMenu) { - let profileMenuItem = subMenu.querySelector(":scope > menuitem[profileid]"); - if (AppConstants.platform === "macosx") { - subMenu.activateItem(profileMenuItem); - } else { - await sendAndWaitForMouseEvent(profileMenuItem); - } -} - -async function sendAndWaitForMouseEvent(target, options = {}) { - let promise = BrowserTestUtils.waitForEvent(target, options.type ?? "click"); - EventUtils.synthesizeMouseAtCenter(target, options); - return promise; -} - -const execProcess = sinon.fake(); -const sendCommandLine = sinon.fake.throws(Cr.NS_ERROR_NOT_AVAILABLE); -sinon.replace( - SelectableProfileService, - "sendCommandLine", - (path, args, raise) => sendCommandLine(path, [...args], raise) -); -sinon.replace(SelectableProfileService, "execProcess", execProcess); - -registerCleanupFunction(() => { - sinon.restore(); -}); - -let lastCommandLineCallCount = 1; -async function assertCommandLineExists(expected) { - await TestUtils.waitForCondition( - () => sendCommandLine.callCount > lastCommandLineCallCount, - "Waiting for notify task to complete" - ); - - let allCommandLineCalls = sendCommandLine.getCalls(); - - lastCommandLineCallCount++; - - let expectedCount = allCommandLineCalls.reduce((count, call) => { - if (ObjectUtils.deepEqual(call.args, expected)) { - return count + 1; - } - - return count; - }, 0); - - Assert.equal(expectedCount, 1, "Found expected args"); - Assert.deepEqual( - allCommandLineCalls.find(call => ObjectUtils.deepEqual(call.args, expected)) - .args, - expected, - "Expected sendCommandLine arguments to open tab in profile" - ); -} - -add_task(async function test_moveSelectedTab() { - await initGroupDatabase(); - - const allProfiles = await SelectableProfileService.getAllProfiles(); - let otherProfile; - if (allProfiles.length < 2) { - otherProfile = await SelectableProfileService.createNewProfile(false); - } else { - otherProfile = allProfiles.find( - p => p.id !== SelectableProfileService.currentProfile.id - ); - } - - let tab2 = await addTab(EXAMPLE_URL + "2"); - - gBrowser.selectedTab = tab2; - - let contextMenu = await openContextMenu(tab2); - let subMenu = await openMoveTabOptionsMenuPopup(contextMenu); - await clickMoveToProfileMenuItem(subMenu); - - let expectedArgs = ["-new-tab", EXAMPLE_URL + "2"]; - - await assertCommandLineExists([otherProfile.path, expectedArgs, true]); - - gBrowser.removeTab(tab2); -}); - -add_task(async function test_moveNonSelectedTab() { - await initGroupDatabase(); - - const allProfiles = await SelectableProfileService.getAllProfiles(); - let otherProfile; - if (allProfiles.length < 2) { - otherProfile = await SelectableProfileService.createNewProfile(false); - } else { - otherProfile = allProfiles.find( - p => p.id !== SelectableProfileService.currentProfile.id - ); - } - - let tab2 = await addTab(EXAMPLE_URL + "2"); - let tab3 = await addTab(EXAMPLE_URL + "3"); - - gBrowser.selectedTab = tab2; - - let contextMenu = await openContextMenu(tab3); - let subMenu = await openMoveTabOptionsMenuPopup(contextMenu); - await clickMoveToProfileMenuItem(subMenu); - - let expectedArgs = ["-new-tab", EXAMPLE_URL + "3"]; - - await assertCommandLineExists([otherProfile.path, expectedArgs, true]); - - gBrowser.removeTabs([tab2, tab3]); -}); - -add_task(async function test_moveMultipleSelectedTabs() { - await initGroupDatabase(); - - const allProfiles = await SelectableProfileService.getAllProfiles(); - let otherProfile; - if (allProfiles.length < 2) { - otherProfile = await SelectableProfileService.createNewProfile(false); - } else { - otherProfile = allProfiles.find( - p => p.id !== SelectableProfileService.currentProfile.id - ); - } - - let tab2 = await addTab(EXAMPLE_URL + "2"); - let tab3 = await addTab(EXAMPLE_URL + "3"); - let tab4 = await addTab(EXAMPLE_URL + "4"); - - gBrowser.selectedTab = tab2; - - await sendAndWaitForMouseEvent(tab2); - if (AppConstants.platform === "macosx") { - await sendAndWaitForMouseEvent(tab3, { metaKey: true }); - await sendAndWaitForMouseEvent(tab4, { metaKey: true }); - } else { - await sendAndWaitForMouseEvent(tab3, { ctrlKey: true }); - await sendAndWaitForMouseEvent(tab4, { ctrlKey: true }); - } - - Assert.ok(tab2.multiselected, "Tab2 is multiselected"); - Assert.ok(tab3.multiselected, "Tab3 is multiselected"); - Assert.ok(tab4.multiselected, "Tab4 is multiselected"); - - let contextMenu = await openContextMenu(tab4); - let subMenu = await openMoveTabOptionsMenuPopup(contextMenu); - await clickMoveToProfileMenuItem(subMenu); - - let expectedArgs = [ - "-new-tab", - EXAMPLE_URL + "2", - "-new-tab", - EXAMPLE_URL + "3", - "-new-tab", - EXAMPLE_URL + "4", - ]; - - await assertCommandLineExists([otherProfile.path, expectedArgs, true]); - - gBrowser.removeTabs([tab2, tab3, tab4]); -}); diff --git a/browser/components/profiles/tests/browser/browser_test_profile_selector.js b/browser/components/profiles/tests/browser/browser_test_profile_selector.js @@ -365,7 +365,7 @@ add_task( EventUtils.synthesizeKey(key, {}, dialog); - let expected = ["-new-tab", "about:editprofile"]; + let expected = ["-url", "about:editprofile"]; Assert.equal( sendCommandLine.callCount, @@ -456,7 +456,7 @@ add_task( EventUtils.synthesizeKey(key, {}, dialog); - let expected = ["-new-tab", "about:deleteprofile"]; + let expected = ["-url", "about:deleteprofile"]; Assert.equal( sendCommandLine.callCount, diff --git a/browser/components/profiles/tests/unit/test_delete_last_profile.js b/browser/components/profiles/tests/unit/test_delete_last_profile.js @@ -53,7 +53,7 @@ add_task(async function test_delete_last_profile() { profile = profiles[0]; - let expected = ["-new-tab", "about:newprofile"]; + let expected = ["-url", "about:newprofile"]; await TestUtils.waitForCondition( () => sendCommandLine.callCount > 1, diff --git a/browser/components/profiles/tests/unit/test_selectable_profile_launch.js b/browser/components/profiles/tests/unit/test_selectable_profile_launch.js @@ -59,9 +59,9 @@ add_task(async function test_launcher() { sendCommandLine.resetHistory(); execProcess.resetHistory(); - SelectableProfileService.launchInstance(profile, ["about:profilemanager"]); + SelectableProfileService.launchInstance(profile, "about:profilemanager"); - expected = ["-new-tab", "about:profilemanager"]; + expected = ["-url", "about:profilemanager"]; Assert.equal( sendCommandLine.callCount, diff --git a/browser/locales/en-US/browser/tabContextMenu.ftl b/browser/locales/en-US/browser/tabContextMenu.ftl @@ -93,10 +93,6 @@ move-to-end = move-to-new-window = .label = Move to New Window .accesskey = W -# Variables -# $profileName (string): The name of the profile to move tab to -move-to-new-profile = - .label = Move to { $profileName } tab-context-close-multiple-tabs = .label = Close Multiple Tabs .accesskey = M