Bug 1920489 - Set up pref branch for introducing tools to users r=sidebar-reviewers,Gijs

Differential Revision: https://phabricator.services.mozilla.com/D237763
This commit is contained in:
Sarah Clements
2025-03-18 16:59:47 +00:00
parent bddbb9c0bf
commit c4493b2334
7 changed files with 218 additions and 0 deletions

View File

@@ -2097,6 +2097,9 @@ pref("sidebar.revamp.round-content-area", false);
pref("sidebar.animation.enabled", true); pref("sidebar.animation.enabled", true);
pref("sidebar.animation.duration-ms", 200); pref("sidebar.animation.duration-ms", 200);
pref("sidebar.animation.expand-on-hover.duration-ms", 400); pref("sidebar.animation.expand-on-hover.duration-ms", 400);
// The sidebar.main.tools pref cannot be changed.
// Use the sidebar.newTool.migration. pref branch to introduce a new "tool" to the sidebar launcher;
// see https://firefox-source-docs.mozilla.org/browser/components/sidebar/docs/index.html for instructions.
pref("sidebar.main.tools", "aichat,syncedtabs,history"); pref("sidebar.main.tools", "aichat,syncedtabs,history");
pref("sidebar.verticalTabs", false); pref("sidebar.verticalTabs", false);
pref("sidebar.visibility", "always-show"); pref("sidebar.visibility", "always-show");

View File

@@ -7,6 +7,7 @@ import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const BACKUP_STATE_PREF = "sidebar.backupState"; const BACKUP_STATE_PREF = "sidebar.backupState";
const VISIBILITY_SETTING_PREF = "sidebar.visibility"; const VISIBILITY_SETTING_PREF = "sidebar.visibility";
const SIDEBAR_TOOLS = "sidebar.main.tools";
const lazy = {}; const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, { ChromeUtils.defineESModuleGetters(lazy, {
@@ -31,6 +32,16 @@ XPCOMUtils.defineLazyPreferenceGetter(
} }
); );
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"sidebarRevampEnabled",
"sidebar.revamp",
false,
() => SidebarManager.updateDefaultTools()
);
XPCOMUtils.defineLazyPreferenceGetter(lazy, "sidebarTools", SIDEBAR_TOOLS);
export const SidebarManager = { export const SidebarManager = {
/** /**
* Handle startup tasks like telemetry, adding listeners. * Handle startup tasks like telemetry, adding listeners.
@@ -78,6 +89,12 @@ export const SidebarManager = {
); );
}); });
Services.prefs.addObserver(
"sidebar.newTool.migration.",
this.updateDefaultTools.bind(this)
);
this.updateDefaultTools();
// if there's no user visibility pref, we may need to update it to the default value for the tab orientation // if there's no user visibility pref, we may need to update it to the default value for the tab orientation
const shouldResetVisibility = !Services.prefs.prefHasUserValue( const shouldResetVisibility = !Services.prefs.prefHasUserValue(
VISIBILITY_SETTING_PREF VISIBILITY_SETTING_PREF
@@ -101,6 +118,55 @@ export const SidebarManager = {
} }
}, },
/**
* Appends any new tools defined on the sidebar.newTool.migration pref branch
* to the sidebar.main.tools pref one time as a way of introducing a new tool
* to the launcher without overwriting what a user had previously customized.
*/
updateDefaultTools() {
if (!lazy.sidebarRevampEnabled) {
return;
}
let tools = lazy.sidebarTools;
for (const pref of Services.prefs.getChildList(
"sidebar.newTool.migration."
)) {
try {
let options = JSON.parse(Services.prefs.getStringPref(pref));
let newTool = pref.split(".")[3];
// ensure we only add this tool once
if (options?.alreadyShown || lazy.sidebarTools.includes(newTool)) {
continue;
}
if (options?.visibilityPref) {
// Will only add the tool to the launcher if the panel governing a panels sidebar visibility
// is first enabled
let visibilityPrefValue = Services.prefs.getBoolPref(
options.visibilityPref
);
if (!visibilityPrefValue) {
Services.prefs.addObserver(
options.visibilityPref,
this.updateDefaultTools.bind(this)
);
continue;
}
}
tools = tools + "," + newTool;
options.alreadyShown = true;
Services.prefs.setStringPref(pref, JSON.stringify(options));
} catch (ex) {
console.error("Failed to handle pref " + pref, ex);
}
}
if (tools.length > lazy.sidebarTools.length) {
Services.prefs.setStringPref(SIDEBAR_TOOLS, tools);
}
},
/** /**
* Provide a system-level "backup" state to be stored for those using "Never * Provide a system-level "backup" state to be stored for those using "Never
* remember history" or "Clear history when browser closes". * remember history" or "Clear history when browser closes".

View File

@@ -0,0 +1,20 @@
.. _components/sidebar:
=========
Sidebar
=========
The new sidebar builds on existing legacy sidebar code treating ``browser-sidebar.js`` as a `SidebarController`. As part of the new sidebar and vertical tabs project, we've added new components including top-level system module `SidebarManager.sys.mjs` and a per window state manager, `SidebarState.sys.ms`. We've added new UI components that use a combination of moz components and custom lit components. The sidebar team maintains the existing synced tabs and history panels.
Introducing a new panel
~~~~~~~~~~~~~~~~~~~~~~~
Every panel that is registered and enabled in ``browser-sidebar.js``` and the ```defaultTools``` map will show as an option in the Customize Sidebar menu (which is a sidebar panel that contains settings).
The launcher is a container for tools (ie, icons that when clicked open or close the associated panel). Registering a panel - which should be behind a pref until it is ready to be introduced - does not automatically add a new icon to the launcher.
A tool can be added once for all users by adding it to the designated pref branch ``sidebar.newTool.migration.`` in ``profile/firefox.js``. So an example would be ``pref("sidebar.newTool.migration.bookmarks", '{}')``. The pref suffix (``bookmarks`` in this example) is the ``toolID`` that should match what you added as the value portion of the relevant entry in the ``defaultTools`` map in ``browser-sidebar.js``. It's important to note that if you have a pref governing the visibility of your sidebar panel, it will need to be enabled at the same time in order to be shown in a user's launcher - either via a nimbus rollout or in-tree.
If you only want to add this item if the pref governing visibility is true, you can pass the pref you want to observe, e.g. ``pref("sidebar.newTool.migration.reviewchecker", '{ "visibilityPref": "browser.shopping.experience2023.integratedSidebar"}')`` where ``browser.shopping.experience2023.integratedSidebar`` is the pref controlling the visibility of the review checker panel.
In both cases, the tool will be introduced to the launcher one time (appended to a user's customized list of tools) and any customization after that (ie, removing it) takes precedence. If it's not removed, it will persist after that session.

View File

@@ -16,3 +16,5 @@ EXTRA_JS_MODULES += [
] ]
XPCSHELL_TESTS_MANIFESTS += ["tests/unit/xpcshell.toml"] XPCSHELL_TESTS_MANIFESTS += ["tests/unit/xpcshell.toml"]
SPHINX_TREES["docs"] = "docs"

View File

@@ -73,6 +73,8 @@ skip-if = [
"os == 'win' && os_version == '11.26100' && opt", # Bug 1898739 "os == 'win' && os_version == '11.26100' && opt", # Bug 1898739
] ]
["browser_tools_migration.js"]
["browser_tools_overflow.js"] ["browser_tools_overflow.js"]
["browser_verticalTabs_widget_placements.js"] ["browser_verticalTabs_widget_placements.js"]

View File

@@ -0,0 +1,124 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
add_setup(async () => {
await SpecialPowers.pushPrefEnv({
set: [
["sidebar.main.tools", "syncedtabs,history"],
["sidebar.newTool.migration.bookmarks", "{}"],
["browser.ml.chat.enabled", false],
[
"sidebar.newTool.migration.aichat",
JSON.stringify({
visibilityPref: "browser.ml.chat.enabled",
}),
],
],
});
});
add_task(async function test_one_time_tool_migration() {
const sidebar = document.querySelector("sidebar-main");
let tools = Services.prefs.getStringPref("sidebar.main.tools");
is(
tools.split(",").length,
3,
"Three tools are in the sidebar.main.tools pref"
);
is(
sidebar.toolButtons.length,
3,
"Three default tools are visible in the launcher"
);
await toggleSidebarPanel(window, "viewCustomizeSidebar");
let customizeDocument = window.SidebarController.browser.contentDocument;
const customizeComponent =
customizeDocument.querySelector("sidebar-customize");
let bookmarksInput = Array.from(customizeComponent.toolInputs).find(
input => input.name === "viewBookmarksSidebar"
);
ok(
bookmarksInput.checked,
"The bookmarks input is checked in the Customize Sidebar menu."
);
let prefValue = JSON.parse(
Services.prefs.getStringPref("sidebar.newTool.migration.bookmarks")
);
bookmarksInput.click();
await BrowserTestUtils.waitForMutationCondition(
bookmarksInput,
{ attributes: true, attributeFilter: ["checked"] },
() => !bookmarksInput.checked
);
ok(
prefValue.alreadyShown,
"Pref property has been updated after being added to tools."
);
is(sidebar.toolButtons.length, 2, "Two tools are now shown in the launcher");
});
add_task(async function test_check_visibility_enabled() {
const sidebar = document.querySelector("sidebar-main");
let tools = Services.prefs.getStringPref("sidebar.main.tools");
is(
tools.split(",").length,
2,
"Two tools are in the sidebar.main.tools pref"
);
is(sidebar.toolButtons.length, 2, "Two tools are shown in the launcher");
let prefValue = JSON.parse(
Services.prefs.getStringPref("sidebar.newTool.migration.aichat")
);
ok(!prefValue.alreadyShown, "aichat pref property was not already shown.");
// enable aichat panel visibility
await SpecialPowers.pushPrefEnv({
set: [["browser.ml.chat.enabled", true]],
});
let customizeDocument = window.SidebarController.browser.contentDocument;
const customizeComponent =
customizeDocument.querySelector("sidebar-customize");
let aichatInput = Array.from(customizeComponent.toolInputs).find(
input => input.name === "viewGenaiChatSidebar"
);
await BrowserTestUtils.waitForMutationCondition(
aichatInput,
{ attributes: true, attributeFilter: ["checked"] },
() => aichatInput.checked
);
let bookmarksInput = Array.from(customizeComponent.toolInputs).find(
input => input.name === "viewBookmarksSidebar"
);
ok(
!bookmarksInput.checked,
"The bookmarks input is not checked in the Customize Sidebar menu."
);
is(
sidebar.toolButtons.length,
3,
"Three tools are now shown in the launcher"
);
prefValue = JSON.parse(
Services.prefs.getStringPref("sidebar.newTool.migration.aichat")
);
ok(
prefValue.alreadyShown,
"aichat pref property is now marked as already shown."
);
});

View File

@@ -37,3 +37,4 @@ This is the nascent documentation of the Firefox front-end code.
/toolkit/themes/shared/design-system/docs/README.design-tokens.stories /toolkit/themes/shared/design-system/docs/README.design-tokens.stories
/toolkit/themes/shared/design-system/docs/README.json-design-tokens.stories /toolkit/themes/shared/design-system/docs/README.json-design-tokens.stories
components/backup/docs/index components/backup/docs/index
components/sidebar/docs/index