commit 91542930a6fad0c783d94d8012f1d91deef5b879
parent 152ea86547a898ab8bf3226a3e5beb8365ccadc9
Author: Chloe Zhou <chloezhouny@gmail.com>
Date: Wed, 31 Dec 2025 00:51:02 +0000
Bug 2005375 - Make aboutwelcome auto_advance time configurable r=omc-reviewers,ai-frontend-reviewers,sachung,Mardak
Add support for configurable auto_advance timing in aboutwelcome screens.
The auto_advance property now accepts both the string format and
a new object format with actionEl and actionTimeMS properties.
The new object format allows specifying custom timing and the string format continues to work with 20-second default.
Differential Revision: https://phabricator.services.mozilla.com/D277407
Diffstat:
6 files changed, 70 insertions(+), 7 deletions(-)
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
@@ -2255,6 +2255,7 @@ pref("browser.aiwindow.enabled", false);
pref("browser.aiwindow.endpoint", "https://mlpa-prod-prod-mozilla.global.ssl.fastly.net/v1");
pref("browser.aiwindow.insights", false);
pref("browser.aiwindow.insightsLogLevel", "Warn");
+pref("browser.aiwindow.firstrun.autoAdvanceMS", 3000);
pref("browser.aiwindow.firstrun.modelChoice", "");
pref("browser.aiwindow.model", "");
diff --git a/browser/components/aboutwelcome/content-src/components/MultiStageProtonScreen.jsx b/browser/components/aboutwelcome/content-src/components/MultiStageProtonScreen.jsx
@@ -19,18 +19,23 @@ import { LinkParagraph } from "./LinkParagraph";
import { ContentTiles } from "./ContentTiles";
import { InstallButton } from "./InstallButton";
+const DEFAULT_AUTO_ADVANCE_MS = 20000;
+
export const MultiStageProtonScreen = props => {
const { autoAdvance, handleAction, order } = props;
useEffect(() => {
if (autoAdvance) {
+ const value = autoAdvance?.actionEl ?? autoAdvance;
+ const timeout = autoAdvance?.actionTimeMS ?? DEFAULT_AUTO_ADVANCE_MS;
+
const timer = setTimeout(() => {
handleAction({
currentTarget: {
- value: autoAdvance,
+ value,
},
name: "AUTO_ADVANCE",
});
- }, 20000);
+ }, timeout);
return () => clearTimeout(timer);
}
return () => {};
diff --git a/browser/components/aboutwelcome/content/aboutwelcome.bundle.js b/browser/components/aboutwelcome/content/aboutwelcome.bundle.js
@@ -1080,6 +1080,7 @@ __webpack_require__.r(__webpack_exports__);
+const DEFAULT_AUTO_ADVANCE_MS = 20000;
const MultiStageProtonScreen = props => {
const {
autoAdvance,
@@ -1088,14 +1089,16 @@ const MultiStageProtonScreen = props => {
} = props;
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
if (autoAdvance) {
+ const value = autoAdvance?.actionEl ?? autoAdvance;
+ const timeout = autoAdvance?.actionTimeMS ?? DEFAULT_AUTO_ADVANCE_MS;
const timer = setTimeout(() => {
handleAction({
currentTarget: {
- value: autoAdvance
+ value
},
name: "AUTO_ADVANCE"
});
- }, 20000);
+ }, timeout);
return () => clearTimeout(timer);
}
return () => {};
diff --git a/browser/components/aboutwelcome/tests/unit/MultiStageAboutWelcome.test.jsx b/browser/components/aboutwelcome/tests/unit/MultiStageAboutWelcome.test.jsx
@@ -169,6 +169,51 @@ describe("MultiStageAboutWelcome module", () => {
telemetryStub.restore();
});
+ it("should autoAdvance with configurable time and send appropriate telemetry", () => {
+ let clock = sinon.useFakeTimers();
+ const screens = [
+ {
+ auto_advance: {
+ actionEl: "primary_button",
+ actionTimeMS: 5000,
+ },
+ content: {
+ title: "test title",
+ subtitle: "test subtitle",
+ primary_button: {
+ label: "Test Button",
+ action: {
+ navigate: true,
+ },
+ },
+ },
+ },
+ ];
+ const AUTO_ADVANCE_PROPS = {
+ defaultScreens: screens,
+ metricsFlowUri: "http://localhost/",
+ message_id: "DEFAULT_ABOUTWELCOME",
+ utm_term: "default",
+ startScreen: 0,
+ };
+ const wrapper = mount(<MultiStageAboutWelcome {...AUTO_ADVANCE_PROPS} />);
+ wrapper.update();
+ const finishStub = sandbox.stub(global, "AWFinish");
+ const telemetryStub = sinon.stub(
+ AboutWelcomeUtils,
+ "sendActionTelemetry"
+ );
+
+ assert.notCalled(finishStub);
+ clock.tick(5001);
+ assert.calledOnce(finishStub);
+ assert.calledOnce(telemetryStub);
+ assert.equal(telemetryStub.lastCall.args[2], "AUTO_ADVANCE");
+ clock.restore();
+ finishStub.restore();
+ telemetryStub.restore();
+ });
+
it("should send telemetry ping on collectSelect", () => {
const screens = [
{
diff --git a/browser/components/aiwindow/ui/content/firstrun.js b/browser/components/aiwindow/ui/content/firstrun.js
@@ -11,8 +11,11 @@ ChromeUtils.defineESModuleGetters(lazy, {
"moz-src:///browser/components/aiwindow/ui/modules/AIWindow.sys.mjs",
});
const MODEL_PREF = "browser.aiwindow.firstrun.modelChoice";
+const AUTO_ADVANCE_PREF = "browser.aiwindow.firstrun.autoAdvanceMS";
const BRAND_DARK_PURPLE = "#210340";
+const autoAdvanceMS = Services.prefs.getIntPref(AUTO_ADVANCE_PREF);
+
const AI_WINDOW_CONFIG = {
id: "AI_WINDOW_WELCOME",
template: "spotlight",
@@ -22,7 +25,10 @@ const AI_WINDOW_CONFIG = {
screens: [
{
id: "AI_WINDOW_INTRO",
- auto_advance: "primary_button",
+ auto_advance: {
+ actionEl: "primary_button",
+ actionTimeMS: autoAdvanceMS,
+ },
force_hide_steps_indicator: true,
content: {
fullscreen: true,
diff --git a/browser/components/aiwindow/ui/test/browser/browser_aiwindow_firstrun.js b/browser/components/aiwindow/ui/test/browser/browser_aiwindow_firstrun.js
@@ -14,6 +14,10 @@ async function openFirstrunPage() {
}
add_task(async function test_firstrun_welcome_screen_renders() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.aiwindow.firstrun.autoAdvanceMS", 0]],
+ });
+
const tab = await openFirstrunPage();
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
@@ -32,8 +36,7 @@ add_task(async function test_firstrun_welcome_screen_renders() {
await ContentTaskUtils.waitForCondition(
() => content.document.querySelector(".screen.AI_WINDOW_CHOOSE_MODEL"),
- "Wait for the AI Window choose model screen to be rendered",
- 25000
+ "Wait for the AI Window choose model screen to be rendered"
);
});