fune/browser/components/newtab/lib/FeatureCalloutMessages.jsm
Meg Viar a3e99a2057 Bug 1806425 - Make value of source in Feature Callout and page in its telementry more consistent r=jprickett,aminomancer
Unify the values of "source" and "page" as used in FeatureCallout.sys.mjs:
- Explicitly pass in a value for "page" when instantiating a Feature Callout and use this for the value of "page" when sending Feature Callout telemetry and as the "source" when making calls to `sendTriggerMessage`. This avoids the risk of including non-about: page URLs or PDF file extensions in our telemetry.
- Set the value of "page" in an HTML data attribute that can be accessed for use in about:welcome telemetry for Spotlight and Feature Callouts.
- Update references to the page value previously used as the page/source for telemetry from `about:firefoxview` Feature Callouts from "firefoxview"  to "about:firefoxview"
- Pass the token "chrome" when creating a callout from the browser chrome and update references to the source in PDF.js messages' targeting
- Update the page value expected in automated tests as needed

Differential Revision: https://phabricator.services.mozilla.com/D165910
2023-01-20 16:53:30 +00:00

639 lines
20 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Eventually, make this a messaging system
// provider instead of adding these message
// into OnboardingMessageProvider.jsm
const FIREFOX_VIEW_PREF = "browser.firefox-view.feature-tour";
const PDFJS_PREF = "browser.pdfjs.feature-tour";
// Empty screens are included as placeholders to ensure step
// indicator shows the correct number of total steps in the tour
const EMPTY_SCREEN = { content: {} };
const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000;
// Generate a JEXL targeting string based on the current screen
// id found in a given Feature Callout tour progress preference
// and the `complete` property being true
const matchCurrentScreenTargeting = (prefName, screenId) => {
return `'${prefName}' | preferenceValue | regExpMatch('(?<=screen\"\:)"(.*)(?=",)')[1] == '${screenId}' && '${prefName}' | preferenceValue | regExpMatch('(?<=complete\"\:)(.*)(?=})')[1] != "true"`;
};
/**
* add24HourImpressionJEXLTargeting -
* Creates a "hasn't been viewed in > 24 hours"
* JEXL string and adds it to each message specified
*
* @param {array} messageIds - IDs of messages that the targeting string will be added to
* @param {string} prefix - The prefix of messageIDs that will used to create the JEXL string
* @param {array} messages - The array of messages that will be edited
* @returns {array} - The array of messages with the appropriate targeting strings edited
*/
function add24HourImpressionJEXLTargeting(
messageIds,
prefix,
uneditedMessages
) {
let noImpressionsIn24HoursString = uneditedMessages
.filter(message => message.id.startsWith(prefix))
.map(
message =>
// If the last impression is null or if epoch time
// of the impression is < current time - 24hours worth of MS
`(messageImpressions.${message.id}[messageImpressions.${
message.id
} | length - 1] == null || messageImpressions.${
message.id
}[messageImpressions.${message.id} | length - 1] < ${Date.now() -
ONE_DAY_IN_MS})`
)
.join(" && ");
// We're appending the string here instead of using
// template strings to avoid a recursion error from
// using the 'messages' variable within itself
return uneditedMessages.map(message => {
if (messageIds.includes(message.id)) {
message.targeting += `&& ${noImpressionsIn24HoursString}`;
}
return message;
});
}
// Exporting the about:firefoxview messages as a method here
// acts as a safety guard against mutations of the original objects
const MESSAGES = () => {
let messages = [
{
id: "FIREFOX_VIEW_SPOTLIGHT",
template: "spotlight",
content: {
id: "FIREFOX_VIEW_PROMO",
template: "multistage",
modal: "tab",
screens: [
{
id: "DEFAULT_MODAL_UI",
content: {
title: {
fontSize: "32px",
fontWeight: 400,
string_id: "firefoxview-spotlight-promo-title",
},
subtitle: {
fontSize: "15px",
fontWeight: 400,
marginBlock: "10px",
marginInline: "40px",
string_id: "firefoxview-spotlight-promo-subtitle",
},
logo: { height: "48px" },
primary_button: {
label: {
string_id: "firefoxview-spotlight-promo-primarybutton",
},
action: {
type: "SET_PREF",
data: {
pref: {
name: FIREFOX_VIEW_PREF,
value: JSON.stringify({
screen: "FEATURE_CALLOUT_1",
complete: false,
}),
},
},
navigate: true,
},
},
secondary_button: {
label: {
string_id: "firefoxview-spotlight-promo-secondarybutton",
},
action: {
type: "SET_PREF",
data: {
pref: {
name: FIREFOX_VIEW_PREF,
value: JSON.stringify({
screen: "",
complete: true,
}),
},
},
navigate: true,
},
},
},
},
],
},
priority: 3,
trigger: {
id: "featureCalloutCheck",
},
frequency: {
// Add the highest possible cap to ensure impressions are recorded while allowing the Spotlight to sync across windows/tabs with Firefox View open
lifetime: 100,
},
targeting: `!inMr2022Holdback && source == "about:firefoxview" &&
!'browser.newtabpage.activity-stream.asrouter.providers.cfr'|preferenceIsUserSet &&
'browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features'|preferenceValue &&
${matchCurrentScreenTargeting(
FIREFOX_VIEW_PREF,
"FIREFOX_VIEW_SPOTLIGHT"
)}`,
},
{
id: "FIREFOX_VIEW_FEATURE_TOUR_1_NO_CWS",
template: "feature_callout",
content: {
id: "FIREFOX_VIEW_FEATURE_TOUR",
template: "multistage",
backdrop: "transparent",
transitions: false,
disableHistoryUpdates: true,
screens: [
{
id: "FEATURE_CALLOUT_1",
parent_selector: "#tab-pickup-container",
content: {
position: "callout",
arrow_position: "top",
title: {
string_id: "callout-firefox-view-tab-pickup-title",
},
subtitle: {
string_id: "callout-firefox-view-tab-pickup-subtitle",
},
logo: {
imageURL: "chrome://browser/content/callout-tab-pickup.svg",
darkModeImageURL:
"chrome://browser/content/callout-tab-pickup-dark.svg",
height: "128px",
},
primary_button: {
label: {
string_id: "callout-primary-advance-button-label",
},
action: {
type: "SET_PREF",
data: {
pref: {
name: FIREFOX_VIEW_PREF,
value: JSON.stringify({
screen: "FEATURE_CALLOUT_2",
complete: false,
}),
},
},
},
},
dismiss_button: {
action: {
type: "SET_PREF",
data: {
pref: {
name: FIREFOX_VIEW_PREF,
value: JSON.stringify({
screen: "",
complete: true,
}),
},
},
},
},
},
},
EMPTY_SCREEN,
],
},
priority: 3,
targeting: `!inMr2022Holdback && source == "about:firefoxview" && ${matchCurrentScreenTargeting(
FIREFOX_VIEW_PREF,
"FEATURE_CALLOUT_1"
)}`,
trigger: { id: "featureCalloutCheck" },
},
{
id: "FIREFOX_VIEW_FEATURE_TOUR_2_NO_CWS",
template: "feature_callout",
content: {
id: "FIREFOX_VIEW_FEATURE_TOUR",
startScreen: 1,
template: "multistage",
backdrop: "transparent",
transitions: false,
disableHistoryUpdates: true,
screens: [
EMPTY_SCREEN,
{
id: "FEATURE_CALLOUT_2",
parent_selector: "#recently-closed-tabs-container",
content: {
position: "callout",
arrow_position: "bottom",
title: {
string_id: "callout-firefox-view-recently-closed-title",
},
subtitle: {
string_id: "callout-firefox-view-recently-closed-subtitle",
},
primary_button: {
label: {
string_id: "callout-primary-complete-button-label",
},
action: {
type: "SET_PREF",
data: {
pref: {
name: FIREFOX_VIEW_PREF,
value: JSON.stringify({
screen: "",
complete: true,
}),
},
},
},
},
dismiss_button: {
action: {
type: "SET_PREF",
data: {
pref: {
name: FIREFOX_VIEW_PREF,
value: JSON.stringify({
screen: "",
complete: true,
}),
},
},
},
},
},
},
],
},
priority: 3,
targeting: `!inMr2022Holdback && source == "about:firefoxview" && ${matchCurrentScreenTargeting(
FIREFOX_VIEW_PREF,
"FEATURE_CALLOUT_2"
)}`,
trigger: { id: "featureCalloutCheck" },
},
{
id: "FIREFOX_VIEW_TAB_PICKUP_REMINDER",
template: "feature_callout",
content: {
id: "FIREFOX_VIEW_TAB_PICKUP_REMINDER",
template: "multistage",
backdrop: "transparent",
transitions: false,
disableHistoryUpdates: true,
screens: [
{
id: "FIREFOX_VIEW_TAB_PICKUP_REMINDER",
parent_selector: "#tab-pickup-container",
content: {
position: "callout",
arrow_position: "top",
title: {
string_id:
"continuous-onboarding-firefox-view-tab-pickup-title",
},
subtitle: {
string_id:
"continuous-onboarding-firefox-view-tab-pickup-subtitle",
},
logo: {
imageURL: "chrome://browser/content/callout-tab-pickup.svg",
darkModeImageURL:
"chrome://browser/content/callout-tab-pickup-dark.svg",
height: "128px",
},
primary_button: {
label: {
string_id: "mr1-onboarding-get-started-primary-button-label",
},
action: {
type: "CLICK_ELEMENT",
navigate: true,
data: {
selector:
"#tab-pickup-container button.primary:not(#error-state-button)",
},
},
},
dismiss_button: {
action: {
navigate: true,
},
},
},
},
],
},
priority: 2,
targeting: `!inMr2022Holdback && source == "about:firefoxview" && "browser.firefox-view.view-count" | preferenceValue > 2
&& (("identity.fxaccounts.enabled" | preferenceValue == false) || !(("services.sync.engine.tabs" | preferenceValue == true) && ("services.sync.username" | preferenceValue))) && (!messageImpressions.FIREFOX_VIEW_SPOTLIGHT[messageImpressions.FIREFOX_VIEW_SPOTLIGHT | length - 1] || messageImpressions.FIREFOX_VIEW_SPOTLIGHT[messageImpressions.FIREFOX_VIEW_SPOTLIGHT | length - 1] < currentDate|date - ${ONE_DAY_IN_MS})`,
frequency: {
lifetime: 1,
},
trigger: { id: "featureCalloutCheck" },
},
{
id: "PDFJS_FEATURE_TOUR_1_A",
template: "feature_callout",
content: {
id: "PDFJS_FEATURE_TOUR",
template: "multistage",
backdrop: "transparent",
transitions: false,
disableHistoryUpdates: true,
screens: [
{
id: "FEATURE_CALLOUT_1_A",
parent_selector: "hbox#browser",
content: {
position: "callout",
callout_position_override: {
top: "45px",
right: "55px",
},
arrow_position: "top-end",
title: {
string_id: "callout-pdfjs-edit-title",
},
subtitle: {
string_id: "callout-pdfjs-edit-body-a",
},
primary_button: {
label: {
string_id: "callout-pdfjs-edit-button",
},
action: {
type: "SET_PREF",
data: {
pref: {
name: PDFJS_PREF,
value: JSON.stringify({
screen: "FEATURE_CALLOUT_2_A",
complete: false,
}),
},
},
},
},
dismiss_button: {
action: {
type: "SET_PREF",
data: {
pref: {
name: PDFJS_PREF,
value: JSON.stringify({
screen: "",
complete: true,
}),
},
},
},
},
},
},
EMPTY_SCREEN,
],
},
priority: 1,
targeting: `source == "chrome" && ${matchCurrentScreenTargeting(
PDFJS_PREF,
"FEATURE_CALLOUT_1_A"
)}`,
trigger: { id: "featureCalloutCheck" },
},
{
id: "PDFJS_FEATURE_TOUR_2_A",
template: "feature_callout",
content: {
id: "PDFJS_FEATURE_TOUR",
startScreen: 1,
template: "multistage",
backdrop: "transparent",
transitions: false,
disableHistoryUpdates: true,
screens: [
EMPTY_SCREEN,
{
id: "FEATURE_CALLOUT_2_A",
parent_selector: "hbox#browser",
content: {
position: "callout",
callout_position_override: {
top: "45px",
right: "25px",
},
arrow_position: "top-end",
title: {
string_id: "callout-pdfjs-draw-title",
},
subtitle: {
string_id: "callout-pdfjs-draw-body-a",
},
primary_button: {
label: {
string_id: "callout-pdfjs-draw-button",
},
action: {
type: "SET_PREF",
data: {
pref: {
name: PDFJS_PREF,
value: JSON.stringify({
screen: "",
complete: true,
}),
},
},
},
},
dismiss_button: {
action: {
type: "SET_PREF",
data: {
pref: {
name: PDFJS_PREF,
value: JSON.stringify({
screen: "",
complete: true,
}),
},
},
},
},
},
},
],
},
priority: 1,
targeting: `source == "chrome" && ${matchCurrentScreenTargeting(
PDFJS_PREF,
"FEATURE_CALLOUT_2_A"
)}`,
trigger: { id: "featureCalloutCheck" },
},
{
id: "PDFJS_FEATURE_TOUR_1_B",
template: "feature_callout",
content: {
id: "PDFJS_FEATURE_TOUR",
template: "multistage",
backdrop: "transparent",
transitions: false,
disableHistoryUpdates: true,
screens: [
{
id: "FEATURE_CALLOUT_1_B",
parent_selector: "hbox#browser",
content: {
position: "callout",
callout_position_override: {
top: "45px",
right: "55px",
},
arrow_position: "top-end",
title: {
string_id: "callout-pdfjs-edit-title",
},
subtitle: {
string_id: "callout-pdfjs-edit-body-b",
},
primary_button: {
label: {
string_id: "callout-pdfjs-edit-button",
},
action: {
type: "SET_PREF",
data: {
pref: {
name: PDFJS_PREF,
value: JSON.stringify({
screen: "FEATURE_CALLOUT_2_B",
complete: false,
}),
},
},
},
},
dismiss_button: {
action: {
type: "SET_PREF",
data: {
pref: {
name: PDFJS_PREF,
value: JSON.stringify({
screen: "",
complete: true,
}),
},
},
},
},
},
},
EMPTY_SCREEN,
],
},
priority: 1,
targeting: `source == "chrome" && ${matchCurrentScreenTargeting(
PDFJS_PREF,
"FEATURE_CALLOUT_1_B"
)}`,
trigger: { id: "featureCalloutCheck" },
},
{
id: "PDFJS_FEATURE_TOUR_2_B",
template: "feature_callout",
content: {
id: "PDFJS_FEATURE_TOUR",
startScreen: 1,
template: "multistage",
backdrop: "transparent",
transitions: false,
disableHistoryUpdates: true,
screens: [
EMPTY_SCREEN,
{
id: "FEATURE_CALLOUT_2_B",
parent_selector: "hbox#browser",
content: {
position: "callout",
callout_position_override: {
top: "45px",
right: "25px",
},
arrow_position: "top-end",
title: {
string_id: "callout-pdfjs-draw-title",
},
subtitle: {
string_id: "callout-pdfjs-draw-body-b",
},
primary_button: {
label: {
string_id: "callout-pdfjs-draw-button",
},
action: {
type: "SET_PREF",
data: {
pref: {
name: PDFJS_PREF,
value: JSON.stringify({
screen: "",
complete: true,
}),
},
},
},
},
dismiss_button: {
action: {
type: "SET_PREF",
data: {
pref: {
name: PDFJS_PREF,
value: JSON.stringify({
screen: "",
complete: true,
}),
},
},
},
},
},
},
],
},
priority: 1,
targeting: `source == "chrome" && ${matchCurrentScreenTargeting(
PDFJS_PREF,
"FEATURE_CALLOUT_2_B"
)}`,
trigger: { id: "featureCalloutCheck" },
},
];
messages = add24HourImpressionJEXLTargeting(
["FIREFOX_VIEW_TAB_PICKUP_REMINDER"],
"FIREFOX_VIEW",
messages
);
return messages;
};
const FeatureCalloutMessages = {
getMessages() {
return MESSAGES();
},
};
const EXPORTED_SYMBOLS = ["FeatureCalloutMessages"];