зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1694257 - Add ability for targeted defaults for AboutWelcome r=k88hudson
Differential Revision: https://phabricator.services.mozilla.com/D106418
This commit is contained in:
Родитель
d8f842d8c1
Коммит
2bb63845fa
|
@ -15,6 +15,8 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
ExperimentAPI: "resource://nimbus/ExperimentAPI.jsm",
|
ExperimentAPI: "resource://nimbus/ExperimentAPI.jsm",
|
||||||
shortURL: "resource://activity-stream/lib/ShortURL.jsm",
|
shortURL: "resource://activity-stream/lib/ShortURL.jsm",
|
||||||
TippyTopProvider: "resource://activity-stream/lib/TippyTopProvider.jsm",
|
TippyTopProvider: "resource://activity-stream/lib/TippyTopProvider.jsm",
|
||||||
|
AboutWelcomeDefaults:
|
||||||
|
"resource://activity-stream/aboutwelcome/lib/AboutWelcomeDefaults.jsm",
|
||||||
});
|
});
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
||||||
|
@ -156,10 +158,6 @@ class AboutWelcomeChild extends JSWindowActorChild {
|
||||||
defineAs: "AWGetFeatureConfig",
|
defineAs: "AWGetFeatureConfig",
|
||||||
});
|
});
|
||||||
|
|
||||||
Cu.exportFunction(this.AWGetAttributionData.bind(this), window, {
|
|
||||||
defineAs: "AWGetAttributionData",
|
|
||||||
});
|
|
||||||
|
|
||||||
Cu.exportFunction(this.AWGetFxAMetricsFlowURI.bind(this), window, {
|
Cu.exportFunction(this.AWGetFxAMetricsFlowURI.bind(this), window, {
|
||||||
defineAs: "AWGetFxAMetricsFlowURI",
|
defineAs: "AWGetFxAMetricsFlowURI",
|
||||||
});
|
});
|
||||||
|
@ -216,79 +214,15 @@ class AboutWelcomeChild extends JSWindowActorChild {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAddonInfo(attrbObj) {
|
|
||||||
let { content, source } = attrbObj;
|
|
||||||
try {
|
|
||||||
if (!content || source !== "addons.mozilla.org") {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// Attribution data can be double encoded
|
|
||||||
while (content.includes("%")) {
|
|
||||||
try {
|
|
||||||
const result = decodeURIComponent(content);
|
|
||||||
if (result === content) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
content = result;
|
|
||||||
} catch (e) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return await this.sendQuery("AWPage:GET_ADDON_FROM_REPOSITORY", content);
|
|
||||||
} catch (e) {
|
|
||||||
Cu.reportError(
|
|
||||||
"Failed to get the latest add-on version for Return to AMO"
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hasAMOAttribution(attributionData) {
|
|
||||||
return (
|
|
||||||
attributionData &&
|
|
||||||
attributionData.campaign === "non-fx-button" &&
|
|
||||||
attributionData.source === "addons.mozilla.org"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async formatAttributionData(attribution) {
|
|
||||||
let result = {};
|
|
||||||
if (this.hasAMOAttribution(attribution)) {
|
|
||||||
let extraProps = await this.getAddonInfo(attribution);
|
|
||||||
if (extraProps) {
|
|
||||||
result = {
|
|
||||||
template: "return_to_amo",
|
|
||||||
extraProps,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAttributionData() {
|
|
||||||
return Cu.cloneInto(
|
|
||||||
await this.formatAttributionData(
|
|
||||||
await this.sendQuery("AWPage:GET_ATTRIBUTION_DATA")
|
|
||||||
),
|
|
||||||
this.contentWindow
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
AWGetAttributionData() {
|
|
||||||
return this.wrapPromise(this.getAttributionData());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send initial data to page including experiment information
|
* Send initial data to page including experiment information
|
||||||
*/
|
*/
|
||||||
AWGetFeatureConfig() {
|
async getAWContent() {
|
||||||
// Note that we specifically don't wait for `ready` so if
|
|
||||||
// about:welcome loads outside of the "FirstStartup" scenario this will likely not be ready
|
|
||||||
let experimentMetadata =
|
let experimentMetadata =
|
||||||
ExperimentAPI.getExperimentMetaData({
|
ExperimentAPI.getExperimentMetaData({
|
||||||
featureId: "aboutwelcome",
|
featureId: "aboutwelcome",
|
||||||
}) || {};
|
}) || {};
|
||||||
let featureConfig = aboutWelcomeFeature.getValue({ defaultValue: {} });
|
let featureConfig = aboutWelcomeFeature.getValue() || {};
|
||||||
|
|
||||||
if (experimentMetadata?.slug) {
|
if (experimentMetadata?.slug) {
|
||||||
log.debug(
|
log.debug(
|
||||||
|
@ -296,18 +230,35 @@ class AboutWelcomeChild extends JSWindowActorChild {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
log.debug("Loading about:welcome without experiment");
|
log.debug("Loading about:welcome without experiment");
|
||||||
}
|
let attributionData = await this.sendQuery("AWPage:GET_ATTRIBUTION_DATA");
|
||||||
return Cu.cloneInto(
|
if (attributionData) {
|
||||||
{
|
log.debug("Loading about:welcome with attribution data");
|
||||||
// All experimentation right now is using the multistage template
|
featureConfig = { ...attributionData, ...featureConfig };
|
||||||
template: "multistage",
|
} else {
|
||||||
...experimentMetadata,
|
log.debug("Loading about:welcome with default data");
|
||||||
|
let defaults = AboutWelcomeDefaults.getDefaults();
|
||||||
|
// FeatureConfig (from prefs or experiments) has higher precendence
|
||||||
|
// to defaults. But the `screens` property isn't defined we shouldn't
|
||||||
|
// override the default with `null`
|
||||||
|
let screens = featureConfig.screens || defaults.screens;
|
||||||
|
featureConfig = {
|
||||||
|
...defaults,
|
||||||
...featureConfig,
|
...featureConfig,
|
||||||
},
|
screens,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cu.cloneInto(
|
||||||
|
{ ...experimentMetadata, ...featureConfig },
|
||||||
this.contentWindow
|
this.contentWindow
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AWGetFeatureConfig() {
|
||||||
|
return this.wrapPromise(this.getAWContent());
|
||||||
|
}
|
||||||
|
|
||||||
AWGetFxAMetricsFlowURI() {
|
AWGetFxAMetricsFlowURI() {
|
||||||
return this.wrapPromise(this.sendQuery("AWPage:FXA_METRICS_FLOW_URI"));
|
return this.wrapPromise(this.sendQuery("AWPage:FXA_METRICS_FLOW_URI"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ const { XPCOMUtils } = ChromeUtils.import(
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
AddonManager: "resource://gre/modules/AddonManager.jsm",
|
AddonManager: "resource://gre/modules/AddonManager.jsm",
|
||||||
AddonRepository: "resource://gre/modules/addons/AddonRepository.jsm",
|
|
||||||
FxAccounts: "resource://gre/modules/FxAccounts.jsm",
|
FxAccounts: "resource://gre/modules/FxAccounts.jsm",
|
||||||
MigrationUtils: "resource:///modules/MigrationUtils.jsm",
|
MigrationUtils: "resource:///modules/MigrationUtils.jsm",
|
||||||
OS: "resource://gre/modules/osfile.jsm",
|
OS: "resource://gre/modules/osfile.jsm",
|
||||||
|
@ -21,7 +20,8 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
"resource://messaging-system/lib/SpecialMessageActions.jsm",
|
"resource://messaging-system/lib/SpecialMessageActions.jsm",
|
||||||
AboutWelcomeTelemetry:
|
AboutWelcomeTelemetry:
|
||||||
"resource://activity-stream/aboutwelcome/lib/AboutWelcomeTelemetry.jsm",
|
"resource://activity-stream/aboutwelcome/lib/AboutWelcomeTelemetry.jsm",
|
||||||
AttributionCode: "resource:///modules/AttributionCode.jsm",
|
AboutWelcomeDefaults:
|
||||||
|
"resource://activity-stream/aboutwelcome/lib/AboutWelcomeDefaults.jsm",
|
||||||
PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
|
PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
|
||||||
Region: "resource://gre/modules/Region.jsm",
|
Region: "resource://gre/modules/Region.jsm",
|
||||||
});
|
});
|
||||||
|
@ -224,8 +224,6 @@ class AboutWelcomeParent extends JSWindowActorParent {
|
||||||
break;
|
break;
|
||||||
case "AWPage:FXA_METRICS_FLOW_URI":
|
case "AWPage:FXA_METRICS_FLOW_URI":
|
||||||
return FxAccounts.config.promiseMetricsFlowURI("aboutwelcome");
|
return FxAccounts.config.promiseMetricsFlowURI("aboutwelcome");
|
||||||
case "AWPage:GET_ATTRIBUTION_DATA":
|
|
||||||
return AttributionCode.getAttrDataAsync();
|
|
||||||
case "AWPage:IMPORTABLE_SITES":
|
case "AWPage:IMPORTABLE_SITES":
|
||||||
return getImportableSites();
|
return getImportableSites();
|
||||||
case "AWPage:TELEMETRY_EVENT":
|
case "AWPage:TELEMETRY_EVENT":
|
||||||
|
@ -235,16 +233,9 @@ class AboutWelcomeParent extends JSWindowActorParent {
|
||||||
this.AboutWelcomeObserver.terminateReason =
|
this.AboutWelcomeObserver.terminateReason =
|
||||||
AWTerminate.ADDRESS_BAR_NAVIGATED;
|
AWTerminate.ADDRESS_BAR_NAVIGATED;
|
||||||
break;
|
break;
|
||||||
case "AWPage:GET_ADDON_FROM_REPOSITORY":
|
case "AWPage:GET_ATTRIBUTION_DATA":
|
||||||
const [addonInfo] = await AddonRepository.getAddonsByIDs([data]);
|
let attributionData = await AboutWelcomeDefaults.getAttributionContent();
|
||||||
if (addonInfo.sourceURI.scheme !== "https") {
|
return attributionData;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
name: addonInfo.name,
|
|
||||||
url: addonInfo.sourceURI.spec,
|
|
||||||
iconURL: addonInfo.icons["64"] || addonInfo.icons["32"],
|
|
||||||
};
|
|
||||||
case "AWPage:SELECT_THEME":
|
case "AWPage:SELECT_THEME":
|
||||||
return AddonManager.getAddonByID(
|
return AddonManager.getAddonByID(
|
||||||
LIGHT_WEIGHT_THEMES[data]
|
LIGHT_WEIGHT_THEMES[data]
|
||||||
|
|
|
@ -102,7 +102,6 @@ __webpack_require__.r(__webpack_exports__);
|
||||||
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
|
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
|
||||||
/* harmony import */ var _components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
/* harmony import */ var _components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
||||||
/* harmony import */ var _components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
|
/* harmony import */ var _components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
|
||||||
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(7);
|
|
||||||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
@ -113,7 +112,6 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
|
class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -189,9 +187,8 @@ class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComp
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // Computes messageId and UTMTerm info used in telemetry
|
||||||
|
|
||||||
AboutWelcome.defaultProps = _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_4__["DEFAULT_WELCOME_CONTENT"]; // Computes messageId and UTMTerm info used in telemetry
|
|
||||||
|
|
||||||
function ComputeTelemetryInfo(welcomeContent, experimentId, branchId) {
|
function ComputeTelemetryInfo(welcomeContent, experimentId, branchId) {
|
||||||
let messageId = welcomeContent.template === "return_to_amo" ? "RTAMO_DEFAULT_WELCOME" : "DEFAULT_ABOUTWELCOME";
|
let messageId = welcomeContent.template === "return_to_amo" ? "RTAMO_DEFAULT_WELCOME" : "DEFAULT_ABOUTWELCOME";
|
||||||
|
@ -212,36 +209,18 @@ function ComputeTelemetryInfo(welcomeContent, experimentId, branchId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function retrieveRenderContent() {
|
async function retrieveRenderContent() {
|
||||||
var _aboutWelcomeProps;
|
// Feature config includes:
|
||||||
|
// user prefs
|
||||||
// Check for featureConfig and retrieve content
|
// experiment data
|
||||||
const featureConfig = await window.AWGetFeatureConfig();
|
// attribution data
|
||||||
let aboutWelcomeProps;
|
// defaults
|
||||||
|
let featureConfig = await window.AWGetFeatureConfig();
|
||||||
if (!featureConfig.screens) {
|
|
||||||
const attribution = await window.AWGetAttributionData();
|
|
||||||
aboutWelcomeProps = {
|
|
||||||
template: attribution.template,
|
|
||||||
...attribution.extraProps
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// If screens is defined then we have multi stage AW content to show
|
|
||||||
aboutWelcomeProps = featureConfig.screens ? featureConfig : {};
|
|
||||||
} // Set design if exists in featureConfig
|
|
||||||
|
|
||||||
|
|
||||||
if (featureConfig.design && !((_aboutWelcomeProps = aboutWelcomeProps) !== null && _aboutWelcomeProps !== void 0 && _aboutWelcomeProps.design)) {
|
|
||||||
aboutWelcomeProps = { ...aboutWelcomeProps,
|
|
||||||
design: featureConfig.design
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let {
|
let {
|
||||||
messageId,
|
messageId,
|
||||||
UTMTerm
|
UTMTerm
|
||||||
} = ComputeTelemetryInfo(aboutWelcomeProps, featureConfig.slug, featureConfig.branch && featureConfig.branch.slug);
|
} = ComputeTelemetryInfo(featureConfig, featureConfig.slug, featureConfig.branch && featureConfig.branch.slug);
|
||||||
return {
|
return {
|
||||||
aboutWelcomeProps,
|
featureConfig,
|
||||||
messageId,
|
messageId,
|
||||||
UTMTerm
|
UTMTerm
|
||||||
};
|
};
|
||||||
|
@ -249,7 +228,7 @@ async function retrieveRenderContent() {
|
||||||
|
|
||||||
async function mount() {
|
async function mount() {
|
||||||
let {
|
let {
|
||||||
aboutWelcomeProps,
|
featureConfig: aboutWelcomeProps,
|
||||||
messageId,
|
messageId,
|
||||||
UTMTerm
|
UTMTerm
|
||||||
} = await retrieveRenderContent();
|
} = await retrieveRenderContent();
|
||||||
|
@ -880,7 +859,6 @@ const HelpText = props => {
|
||||||
__webpack_require__.r(__webpack_exports__);
|
__webpack_require__.r(__webpack_exports__);
|
||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AboutWelcomeUtils", function() { return AboutWelcomeUtils; });
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AboutWelcomeUtils", function() { return AboutWelcomeUtils; });
|
||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DEFAULT_RTAMO_CONTENT", function() { return DEFAULT_RTAMO_CONTENT; });
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DEFAULT_RTAMO_CONTENT", function() { return DEFAULT_RTAMO_CONTENT; });
|
||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DEFAULT_WELCOME_CONTENT", function() { return DEFAULT_WELCOME_CONTENT; });
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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,
|
* 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/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
@ -985,172 +963,6 @@ const DEFAULT_RTAMO_CONTENT = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const DEFAULT_WELCOME_CONTENT = {
|
|
||||||
template: "multistage",
|
|
||||||
screens: [{
|
|
||||||
id: "AW_SET_DEFAULT",
|
|
||||||
order: 0,
|
|
||||||
content: {
|
|
||||||
zap: true,
|
|
||||||
title: {
|
|
||||||
string_id: "onboarding-multistage-set-default-header"
|
|
||||||
},
|
|
||||||
subtitle: {
|
|
||||||
string_id: "onboarding-multistage-set-default-subtitle"
|
|
||||||
},
|
|
||||||
primary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-set-default-primary-button-label"
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
navigate: true,
|
|
||||||
type: "SET_DEFAULT_BROWSER"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
secondary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-set-default-secondary-button-label"
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
navigate: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
secondary_button_top: {
|
|
||||||
text: {
|
|
||||||
string_id: "onboarding-multistage-welcome-secondary-button-text"
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-welcome-secondary-button-label"
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
data: {
|
|
||||||
entrypoint: "activity-stream-firstrun"
|
|
||||||
},
|
|
||||||
type: "SHOW_FIREFOX_ACCOUNTS",
|
|
||||||
addFlowParams: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "AW_IMPORT_SETTINGS",
|
|
||||||
order: 1,
|
|
||||||
content: {
|
|
||||||
zap: true,
|
|
||||||
help_text: {
|
|
||||||
text: {
|
|
||||||
string_id: "onboarding-import-sites-disclaimer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
string_id: "onboarding-multistage-import-header"
|
|
||||||
},
|
|
||||||
subtitle: {
|
|
||||||
string_id: "onboarding-multistage-import-subtitle"
|
|
||||||
},
|
|
||||||
tiles: {
|
|
||||||
type: "topsites",
|
|
||||||
showTitles: true
|
|
||||||
},
|
|
||||||
primary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-import-primary-button-label"
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
type: "SHOW_MIGRATION_WIZARD",
|
|
||||||
navigate: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
secondary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-import-secondary-button-label"
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
navigate: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "AW_CHOOSE_THEME",
|
|
||||||
order: 2,
|
|
||||||
content: {
|
|
||||||
zap: true,
|
|
||||||
title: {
|
|
||||||
string_id: "onboarding-multistage-theme-header"
|
|
||||||
},
|
|
||||||
subtitle: {
|
|
||||||
string_id: "onboarding-multistage-theme-subtitle"
|
|
||||||
},
|
|
||||||
tiles: {
|
|
||||||
type: "theme",
|
|
||||||
action: {
|
|
||||||
theme: "<event>"
|
|
||||||
},
|
|
||||||
data: [{
|
|
||||||
theme: "automatic",
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-theme-label-automatic"
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
string_id: "onboarding-multistage-theme-tooltip-automatic-2"
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
string_id: "onboarding-multistage-theme-description-automatic-2"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
theme: "light",
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-theme-label-light"
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
string_id: "onboarding-multistage-theme-tooltip-light-2"
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
string_id: "onboarding-multistage-theme-description-light"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
theme: "dark",
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-theme-label-dark"
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
string_id: "onboarding-multistage-theme-tooltip-dark-2"
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
string_id: "onboarding-multistage-theme-description-dark"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
theme: "alpenglow",
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-theme-label-alpenglow"
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
string_id: "onboarding-multistage-theme-tooltip-alpenglow-2"
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
string_id: "onboarding-multistage-theme-description-alpenglow"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
primary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-theme-primary-button-label2"
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
navigate: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
secondary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-theme-secondary-button-label"
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
theme: "automatic",
|
|
||||||
navigate: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
/* 8 */
|
/* 8 */
|
||||||
|
|
|
@ -0,0 +1,314 @@
|
||||||
|
/* 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";
|
||||||
|
|
||||||
|
const EXPORTED_SYMBOLS = ["AboutWelcomeDefaults"];
|
||||||
|
|
||||||
|
const { XPCOMUtils } = ChromeUtils.import(
|
||||||
|
"resource://gre/modules/XPCOMUtils.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
|
Services: "resource://gre/modules/Services.jsm",
|
||||||
|
ShellService: "resource:///modules/ShellService.jsm",
|
||||||
|
AttributionCode: "resource:///modules/AttributionCode.jsm",
|
||||||
|
AddonRepository: "resource://gre/modules/addons/AddonRepository.jsm",
|
||||||
|
});
|
||||||
|
|
||||||
|
const DID_SEE_ABOUT_WELCOME_PREF = "trailhead.firstrun.didSeeAboutWelcome";
|
||||||
|
|
||||||
|
const DEFAULT_WELCOME_CONTENT = {
|
||||||
|
template: "multistage",
|
||||||
|
screens: [
|
||||||
|
{
|
||||||
|
id: "AW_SET_DEFAULT",
|
||||||
|
order: 0,
|
||||||
|
content: {
|
||||||
|
zap: true,
|
||||||
|
title: {
|
||||||
|
string_id: "onboarding-multistage-set-default-header",
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
string_id: "onboarding-multistage-set-default-subtitle",
|
||||||
|
},
|
||||||
|
primary_button: {
|
||||||
|
label: {
|
||||||
|
string_id: "onboarding-multistage-set-default-primary-button-label",
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
navigate: true,
|
||||||
|
type: "SET_DEFAULT_BROWSER",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
secondary_button: {
|
||||||
|
label: {
|
||||||
|
string_id:
|
||||||
|
"onboarding-multistage-set-default-secondary-button-label",
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
navigate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
secondary_button_top: {
|
||||||
|
text: {
|
||||||
|
string_id: "onboarding-multistage-welcome-secondary-button-text",
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
string_id: "onboarding-multistage-welcome-secondary-button-label",
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
data: {
|
||||||
|
entrypoint: "activity-stream-firstrun",
|
||||||
|
},
|
||||||
|
type: "SHOW_FIREFOX_ACCOUNTS",
|
||||||
|
addFlowParams: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "AW_IMPORT_SETTINGS",
|
||||||
|
order: 1,
|
||||||
|
content: {
|
||||||
|
zap: true,
|
||||||
|
help_text: {
|
||||||
|
text: {
|
||||||
|
string_id: "onboarding-import-sites-disclaimer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
string_id: "onboarding-multistage-import-header",
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
string_id: "onboarding-multistage-import-subtitle",
|
||||||
|
},
|
||||||
|
tiles: {
|
||||||
|
type: "topsites",
|
||||||
|
showTitles: true,
|
||||||
|
},
|
||||||
|
primary_button: {
|
||||||
|
label: {
|
||||||
|
string_id: "onboarding-multistage-import-primary-button-label",
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
type: "SHOW_MIGRATION_WIZARD",
|
||||||
|
navigate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
secondary_button: {
|
||||||
|
label: {
|
||||||
|
string_id: "onboarding-multistage-import-secondary-button-label",
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
navigate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "AW_CHOOSE_THEME",
|
||||||
|
order: 2,
|
||||||
|
content: {
|
||||||
|
zap: true,
|
||||||
|
title: {
|
||||||
|
string_id: "onboarding-multistage-theme-header",
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
string_id: "onboarding-multistage-theme-subtitle",
|
||||||
|
},
|
||||||
|
tiles: {
|
||||||
|
type: "theme",
|
||||||
|
action: {
|
||||||
|
theme: "<event>",
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
theme: "automatic",
|
||||||
|
label: {
|
||||||
|
string_id: "onboarding-multistage-theme-label-automatic",
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
string_id: "onboarding-multistage-theme-tooltip-automatic-2",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
string_id:
|
||||||
|
"onboarding-multistage-theme-description-automatic-2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
theme: "light",
|
||||||
|
label: {
|
||||||
|
string_id: "onboarding-multistage-theme-label-light",
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
string_id: "onboarding-multistage-theme-tooltip-light-2",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
string_id: "onboarding-multistage-theme-description-light",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
theme: "dark",
|
||||||
|
label: {
|
||||||
|
string_id: "onboarding-multistage-theme-label-dark",
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
string_id: "onboarding-multistage-theme-tooltip-dark-2",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
string_id: "onboarding-multistage-theme-description-dark",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
theme: "alpenglow",
|
||||||
|
label: {
|
||||||
|
string_id: "onboarding-multistage-theme-label-alpenglow",
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
string_id: "onboarding-multistage-theme-tooltip-alpenglow-2",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
string_id: "onboarding-multistage-theme-description-alpenglow",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
primary_button: {
|
||||||
|
label: {
|
||||||
|
string_id: "onboarding-multistage-theme-primary-button-label2",
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
navigate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
secondary_button: {
|
||||||
|
label: {
|
||||||
|
string_id: "onboarding-multistage-theme-secondary-button-label",
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
theme: "automatic",
|
||||||
|
navigate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to determine if Windows platform supports
|
||||||
|
// automated pinning to taskbar.
|
||||||
|
// See https://searchfox.org/mozilla-central/rev/002023eb262be9db3479142355e1675645d52d52/browser/components/shell/nsIWindowsShellService.idl#17
|
||||||
|
function canPinCurrentAppToTaskbar() {
|
||||||
|
try {
|
||||||
|
ShellService.QueryInterface(
|
||||||
|
Ci.nsIWindowsShellService
|
||||||
|
).checkPinCurrentAppToTaskbar();
|
||||||
|
return true;
|
||||||
|
} catch (e) {}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAddonFromRepository(data) {
|
||||||
|
const [addonInfo] = await AddonRepository.getAddonsByIDs([data]);
|
||||||
|
if (addonInfo.sourceURI.scheme !== "https") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: addonInfo.name,
|
||||||
|
url: addonInfo.sourceURI.spec,
|
||||||
|
iconURL: addonInfo.icons["64"] || addonInfo.icons["32"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAddonInfo(attrbObj) {
|
||||||
|
let { content, source } = attrbObj;
|
||||||
|
try {
|
||||||
|
if (!content || source !== "addons.mozilla.org") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Attribution data can be double encoded
|
||||||
|
while (content.includes("%")) {
|
||||||
|
try {
|
||||||
|
const result = decodeURIComponent(content);
|
||||||
|
if (result === content) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
content = result;
|
||||||
|
} catch (e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return await getAddonFromRepository(content);
|
||||||
|
} catch (e) {
|
||||||
|
Cu.reportError("Failed to get the latest add-on version for Return to AMO");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasAMOAttribution(attributionData) {
|
||||||
|
return (
|
||||||
|
attributionData &&
|
||||||
|
attributionData.campaign === "non-fx-button" &&
|
||||||
|
attributionData.source === "addons.mozilla.org"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function formatAttributionData(attribution) {
|
||||||
|
if (hasAMOAttribution(attribution)) {
|
||||||
|
let extraProps = await getAddonInfo(attribution);
|
||||||
|
if (extraProps) {
|
||||||
|
return extraProps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAttributionContent() {
|
||||||
|
let attributionContent = await formatAttributionData(
|
||||||
|
await AttributionCode.getAttrDataAsync()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (attributionContent) {
|
||||||
|
return { ...attributionContent, template: "return_to_amo" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RULES = [
|
||||||
|
{
|
||||||
|
description: "Windows pin to task bar screen",
|
||||||
|
getDefaults() {
|
||||||
|
if (
|
||||||
|
!Services.prefs.getBoolPref(DID_SEE_ABOUT_WELCOME_PREF, true) &&
|
||||||
|
canPinCurrentAppToTaskbar()
|
||||||
|
) {
|
||||||
|
return { ...DEFAULT_WELCOME_CONTENT };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Default AW content",
|
||||||
|
getDefaults() {
|
||||||
|
return { ...DEFAULT_WELCOME_CONTENT };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function getDefaults() {
|
||||||
|
for (const rule of RULES) {
|
||||||
|
const result = rule.getDefaults();
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AboutWelcomeDefaults = {
|
||||||
|
getDefaults,
|
||||||
|
getAttributionContent,
|
||||||
|
};
|
|
@ -7,8 +7,6 @@ import ReactDOM from "react-dom";
|
||||||
import { MultiStageAboutWelcome } from "./components/MultiStageAboutWelcome";
|
import { MultiStageAboutWelcome } from "./components/MultiStageAboutWelcome";
|
||||||
import { ReturnToAMO } from "./components/ReturnToAMO";
|
import { ReturnToAMO } from "./components/ReturnToAMO";
|
||||||
|
|
||||||
import { DEFAULT_WELCOME_CONTENT } from "../lib/aboutwelcome-utils";
|
|
||||||
|
|
||||||
class AboutWelcome extends React.PureComponent {
|
class AboutWelcome extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -81,8 +79,6 @@ class AboutWelcome extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AboutWelcome.defaultProps = DEFAULT_WELCOME_CONTENT;
|
|
||||||
|
|
||||||
// Computes messageId and UTMTerm info used in telemetry
|
// Computes messageId and UTMTerm info used in telemetry
|
||||||
function ComputeTelemetryInfo(welcomeContent, experimentId, branchId) {
|
function ComputeTelemetryInfo(welcomeContent, experimentId, branchId) {
|
||||||
let messageId =
|
let messageId =
|
||||||
|
@ -105,36 +101,27 @@ function ComputeTelemetryInfo(welcomeContent, experimentId, branchId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function retrieveRenderContent() {
|
async function retrieveRenderContent() {
|
||||||
// Check for featureConfig and retrieve content
|
// Feature config includes:
|
||||||
const featureConfig = await window.AWGetFeatureConfig();
|
// user prefs
|
||||||
let aboutWelcomeProps;
|
// experiment data
|
||||||
|
// attribution data
|
||||||
if (!featureConfig.screens) {
|
// defaults
|
||||||
const attribution = await window.AWGetAttributionData();
|
let featureConfig = await window.AWGetFeatureConfig();
|
||||||
aboutWelcomeProps = {
|
|
||||||
template: attribution.template,
|
|
||||||
...attribution.extraProps,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// If screens is defined then we have multi stage AW content to show
|
|
||||||
aboutWelcomeProps = featureConfig.screens ? featureConfig : {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set design if exists in featureConfig
|
|
||||||
if (featureConfig.design && !aboutWelcomeProps?.design) {
|
|
||||||
aboutWelcomeProps = { ...aboutWelcomeProps, design: featureConfig.design };
|
|
||||||
}
|
|
||||||
|
|
||||||
let { messageId, UTMTerm } = ComputeTelemetryInfo(
|
let { messageId, UTMTerm } = ComputeTelemetryInfo(
|
||||||
aboutWelcomeProps,
|
featureConfig,
|
||||||
featureConfig.slug,
|
featureConfig.slug,
|
||||||
featureConfig.branch && featureConfig.branch.slug
|
featureConfig.branch && featureConfig.branch.slug
|
||||||
);
|
);
|
||||||
return { aboutWelcomeProps, messageId, UTMTerm };
|
return { featureConfig, messageId, UTMTerm };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function mount() {
|
async function mount() {
|
||||||
let { aboutWelcomeProps, messageId, UTMTerm } = await retrieveRenderContent();
|
let {
|
||||||
|
featureConfig: aboutWelcomeProps,
|
||||||
|
messageId,
|
||||||
|
UTMTerm,
|
||||||
|
} = await retrieveRenderContent();
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<AboutWelcome
|
<AboutWelcome
|
||||||
messageId={messageId}
|
messageId={messageId}
|
||||||
|
|
|
@ -80,163 +80,3 @@ export const DEFAULT_RTAMO_CONTENT = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_WELCOME_CONTENT = {
|
|
||||||
template: "multistage",
|
|
||||||
screens: [
|
|
||||||
{
|
|
||||||
id: "AW_SET_DEFAULT",
|
|
||||||
order: 0,
|
|
||||||
content: {
|
|
||||||
zap: true,
|
|
||||||
title: {
|
|
||||||
string_id: "onboarding-multistage-set-default-header",
|
|
||||||
},
|
|
||||||
subtitle: { string_id: "onboarding-multistage-set-default-subtitle" },
|
|
||||||
primary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-set-default-primary-button-label",
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
navigate: true,
|
|
||||||
type: "SET_DEFAULT_BROWSER",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
secondary_button: {
|
|
||||||
label: {
|
|
||||||
string_id:
|
|
||||||
"onboarding-multistage-set-default-secondary-button-label",
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
navigate: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
secondary_button_top: {
|
|
||||||
text: {
|
|
||||||
string_id: "onboarding-multistage-welcome-secondary-button-text",
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-welcome-secondary-button-label",
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
data: { entrypoint: "activity-stream-firstrun" },
|
|
||||||
type: "SHOW_FIREFOX_ACCOUNTS",
|
|
||||||
addFlowParams: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "AW_IMPORT_SETTINGS",
|
|
||||||
order: 1,
|
|
||||||
content: {
|
|
||||||
zap: true,
|
|
||||||
help_text: {
|
|
||||||
text: { string_id: "onboarding-import-sites-disclaimer" },
|
|
||||||
},
|
|
||||||
title: { string_id: "onboarding-multistage-import-header" },
|
|
||||||
subtitle: { string_id: "onboarding-multistage-import-subtitle" },
|
|
||||||
tiles: {
|
|
||||||
type: "topsites",
|
|
||||||
showTitles: true,
|
|
||||||
},
|
|
||||||
primary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-import-primary-button-label",
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
type: "SHOW_MIGRATION_WIZARD",
|
|
||||||
navigate: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
secondary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-import-secondary-button-label",
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
navigate: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "AW_CHOOSE_THEME",
|
|
||||||
order: 2,
|
|
||||||
content: {
|
|
||||||
zap: true,
|
|
||||||
title: { string_id: "onboarding-multistage-theme-header" },
|
|
||||||
subtitle: { string_id: "onboarding-multistage-theme-subtitle" },
|
|
||||||
tiles: {
|
|
||||||
type: "theme",
|
|
||||||
action: {
|
|
||||||
theme: "<event>",
|
|
||||||
},
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
theme: "automatic",
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-theme-label-automatic",
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
string_id: "onboarding-multistage-theme-tooltip-automatic-2",
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
string_id:
|
|
||||||
"onboarding-multistage-theme-description-automatic-2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
theme: "light",
|
|
||||||
label: { string_id: "onboarding-multistage-theme-label-light" },
|
|
||||||
tooltip: {
|
|
||||||
string_id: "onboarding-multistage-theme-tooltip-light-2",
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
string_id: "onboarding-multistage-theme-description-light",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
theme: "dark",
|
|
||||||
label: { string_id: "onboarding-multistage-theme-label-dark" },
|
|
||||||
tooltip: {
|
|
||||||
string_id: "onboarding-multistage-theme-tooltip-dark-2",
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
string_id: "onboarding-multistage-theme-description-dark",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
theme: "alpenglow",
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-theme-label-alpenglow",
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
string_id: "onboarding-multistage-theme-tooltip-alpenglow-2",
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
string_id: "onboarding-multistage-theme-description-alpenglow",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
primary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-theme-primary-button-label2",
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
navigate: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
secondary_button: {
|
|
||||||
label: {
|
|
||||||
string_id: "onboarding-multistage-theme-secondary-button-label",
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
theme: "automatic",
|
|
||||||
navigate: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
|
@ -847,15 +847,15 @@ add_task(async function test_AWMultistage_Import() {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function test_onContentMessage() {
|
add_task(async function test_updatesPrefOnAWOpen() {
|
||||||
Services.prefs.setBoolPref(DID_SEE_ABOUT_WELCOME_PREF, false);
|
Services.prefs.setBoolPref(DID_SEE_ABOUT_WELCOME_PREF, false);
|
||||||
await setAboutWelcomePref(true);
|
await setAboutWelcomePref(true);
|
||||||
|
|
||||||
await openAboutWelcome();
|
await openAboutWelcome();
|
||||||
Assert.equal(
|
await BrowserTestUtils.waitForCondition(
|
||||||
Services.prefs.getBoolPref(DID_SEE_ABOUT_WELCOME_PREF, false),
|
() =>
|
||||||
true,
|
Services.prefs.getBoolPref(DID_SEE_ABOUT_WELCOME_PREF, false) === true,
|
||||||
"Pref was set"
|
"Updated pref to seen AW"
|
||||||
);
|
);
|
||||||
Services.prefs.clearUserPref(DID_SEE_ABOUT_WELCOME_PREF);
|
Services.prefs.clearUserPref(DID_SEE_ABOUT_WELCOME_PREF);
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,10 +5,10 @@ import {
|
||||||
} from "content-src/aboutwelcome/components/MultiStageAboutWelcome";
|
} from "content-src/aboutwelcome/components/MultiStageAboutWelcome";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { shallow, mount } from "enzyme";
|
import { shallow, mount } from "enzyme";
|
||||||
import {
|
import { AboutWelcomeDefaults } from "aboutwelcome/lib/AboutWelcomeDefaults.jsm";
|
||||||
DEFAULT_WELCOME_CONTENT,
|
import { AboutWelcomeUtils } from "content-src/lib/aboutwelcome-utils";
|
||||||
AboutWelcomeUtils,
|
|
||||||
} from "content-src/lib/aboutwelcome-utils";
|
const DEFAULT_WELCOME_CONTENT = AboutWelcomeDefaults.getDefaults();
|
||||||
|
|
||||||
describe("MultiStageAboutWelcome module", () => {
|
describe("MultiStageAboutWelcome module", () => {
|
||||||
let globals;
|
let globals;
|
||||||
|
|
|
@ -4,10 +4,16 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { AboutWelcomeChild } = ChromeUtils.import(
|
const { AboutWelcomeDefaults } = ChromeUtils.import(
|
||||||
"resource:///actors/AboutWelcomeChild.jsm"
|
"resource://activity-stream/aboutwelcome/lib/AboutWelcomeDefaults.jsm"
|
||||||
);
|
);
|
||||||
const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
||||||
|
const { AttributionCode } = ChromeUtils.import(
|
||||||
|
"resource:///modules/AttributionCode.jsm"
|
||||||
|
);
|
||||||
|
const { AddonRepository } = ChromeUtils.import(
|
||||||
|
"resource://gre/modules/addons/AddonRepository.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
const TEST_ATTRIBUTION_DATA = {
|
const TEST_ATTRIBUTION_DATA = {
|
||||||
source: "addons.mozilla.org",
|
source: "addons.mozilla.org",
|
||||||
|
@ -17,22 +23,32 @@ const TEST_ATTRIBUTION_DATA = {
|
||||||
};
|
};
|
||||||
|
|
||||||
add_task(async function test_handleAddonInfoNotFound() {
|
add_task(async function test_handleAddonInfoNotFound() {
|
||||||
let AWChild = new AboutWelcomeChild();
|
let sandbox = sinon.createSandbox();
|
||||||
const stub = sinon.stub(AWChild, "getAddonInfo").resolves(null);
|
const stub = sandbox.stub(AttributionCode, "getAttrDataAsync").resolves(null);
|
||||||
let result = await AWChild.formatAttributionData(TEST_ATTRIBUTION_DATA);
|
let result = await AboutWelcomeDefaults.getAttributionContent();
|
||||||
equal(stub.callCount, 1, "Call was made");
|
equal(stub.callCount, 1, "Call was made");
|
||||||
equal(result.template, undefined, "No template returned");
|
equal(result, null, "No data is returned");
|
||||||
|
|
||||||
|
sandbox.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function test_formatAttributionData() {
|
add_task(async function test_formatAttributionData() {
|
||||||
let AWChild = new AboutWelcomeChild();
|
let sandbox = sinon.createSandbox();
|
||||||
const TEST_ADDON_INFO = {
|
const TEST_ADDON_INFO = {
|
||||||
|
sourceURI: { scheme: "https", spec: "https://test.xpi" },
|
||||||
name: "Test Add-on",
|
name: "Test Add-on",
|
||||||
url: "https://test.xpi",
|
icons: { "64": "http://test.svg" },
|
||||||
iconURL: "http://test.svg",
|
|
||||||
};
|
};
|
||||||
sinon.stub(AWChild, "getAddonInfo").resolves(TEST_ADDON_INFO);
|
sandbox
|
||||||
let result = await AWChild.formatAttributionData(TEST_ATTRIBUTION_DATA);
|
.stub(AttributionCode, "getAttrDataAsync")
|
||||||
|
.resolves(TEST_ATTRIBUTION_DATA);
|
||||||
|
sandbox.stub(AddonRepository, "getAddonsByIDs").resolves([TEST_ADDON_INFO]);
|
||||||
|
let result = await AboutWelcomeDefaults.getAttributionContent(
|
||||||
|
TEST_ATTRIBUTION_DATA
|
||||||
|
);
|
||||||
|
equal(AddonRepository.getAddonsByIDs.callCount, 1, "Retrieve addon content");
|
||||||
equal(result.template, "return_to_amo", "RTAMO template returned");
|
equal(result.template, "return_to_amo", "RTAMO template returned");
|
||||||
equal(result.extraProps, TEST_ADDON_INFO, "AddonInfo returned");
|
equal(result.name, TEST_ADDON_INFO.name, "AddonInfo returned");
|
||||||
|
|
||||||
|
sandbox.restore();
|
||||||
});
|
});
|
||||||
|
|
|
@ -324,7 +324,7 @@ class ExperimentFeature {
|
||||||
static MANIFEST = MANIFEST;
|
static MANIFEST = MANIFEST;
|
||||||
constructor(featureId, manifest) {
|
constructor(featureId, manifest) {
|
||||||
this.featureId = featureId;
|
this.featureId = featureId;
|
||||||
this.defaultPrefValues = {};
|
this.prefGetters = {};
|
||||||
this.manifest = manifest || ExperimentFeature.MANIFEST[featureId];
|
this.manifest = manifest || ExperimentFeature.MANIFEST[featureId];
|
||||||
if (!this.manifest) {
|
if (!this.manifest) {
|
||||||
Cu.reportError(
|
Cu.reportError(
|
||||||
|
@ -353,7 +353,7 @@ class ExperimentFeature {
|
||||||
const { type, fallbackPref } = variables[key];
|
const { type, fallbackPref } = variables[key];
|
||||||
if (fallbackPref) {
|
if (fallbackPref) {
|
||||||
XPCOMUtils.defineLazyPreferenceGetter(
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
this.defaultPrefValues,
|
this.prefGetters,
|
||||||
key,
|
key,
|
||||||
fallbackPref,
|
fallbackPref,
|
||||||
null,
|
null,
|
||||||
|
@ -369,6 +369,22 @@ class ExperimentFeature {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getUserPrefsValues() {
|
||||||
|
let userPrefs = {};
|
||||||
|
Object.keys(this.manifest?.variables || {}).forEach(variable => {
|
||||||
|
if (
|
||||||
|
this.manifest.variables[variable].fallbackPref &&
|
||||||
|
Services.prefs.prefHasUserValue(
|
||||||
|
this.manifest.variables[variable].fallbackPref
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
userPrefs[variable] = this.prefGetters[variable];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return userPrefs;
|
||||||
|
}
|
||||||
|
|
||||||
ready() {
|
ready() {
|
||||||
return ExperimentAPI.ready();
|
return ExperimentAPI.ready();
|
||||||
}
|
}
|
||||||
|
@ -405,18 +421,18 @@ class ExperimentFeature {
|
||||||
* @param {{sendExposureEvent: boolean, defaultValue?: any}} options
|
* @param {{sendExposureEvent: boolean, defaultValue?: any}} options
|
||||||
* @returns {obj} The feature value
|
* @returns {obj} The feature value
|
||||||
*/
|
*/
|
||||||
getValue({ sendExposureEvent, defaultValue = null } = {}) {
|
getValue({ sendExposureEvent } = {}) {
|
||||||
|
// Any user pref will override any other configuration
|
||||||
|
let userPrefs = this._getUserPrefsValues();
|
||||||
const branch = ExperimentAPI.activateBranch({
|
const branch = ExperimentAPI.activateBranch({
|
||||||
featureId: this.featureId,
|
featureId: this.featureId,
|
||||||
sendExposureEvent,
|
sendExposureEvent,
|
||||||
});
|
});
|
||||||
if (branch?.feature?.value) {
|
if (branch?.feature?.value) {
|
||||||
return branch.feature.value;
|
return { ...branch.feature.value, ...userPrefs };
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.keys(this.defaultPrefValues).length
|
return this.prefGetters;
|
||||||
? this.defaultPrefValues
|
|
||||||
: defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recordExposureEvent() {
|
recordExposureEvent() {
|
||||||
|
@ -442,11 +458,12 @@ class ExperimentFeature {
|
||||||
featureId: this.featureId,
|
featureId: this.featureId,
|
||||||
}),
|
}),
|
||||||
fallbackPrefs:
|
fallbackPrefs:
|
||||||
this.defaultPrefValues &&
|
this.prefGetters &&
|
||||||
Object.keys(this.defaultPrefValues).map(prefName => [
|
Object.keys(this.prefGetters).map(prefName => [
|
||||||
prefName,
|
prefName,
|
||||||
this.defaultPrefValues[prefName],
|
this.prefGetters[prefName],
|
||||||
]),
|
]),
|
||||||
|
userPrefs: this._getUserPrefsValues(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,8 +67,7 @@ Defaults values inline:
|
||||||
```jsx
|
```jsx
|
||||||
feature.isEnabled({ defaultValue: true });
|
feature.isEnabled({ defaultValue: true });
|
||||||
|
|
||||||
// Default values work here too
|
const { skipFocus } = feature.getValue() || {};
|
||||||
const { skipFocus } = feature.getValue({ defaultValue: { skipFocus: false } });
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Listen to changes:
|
Listen to changes:
|
||||||
|
|
|
@ -37,6 +37,11 @@ async function setupForExperimentFeature() {
|
||||||
return { sandbox, manager };
|
return { sandbox, manager };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setDefaultBranch(pref, value) {
|
||||||
|
let branch = Services.prefs.getDefaultBranch("");
|
||||||
|
branch.setStringPref(pref, value);
|
||||||
|
}
|
||||||
|
|
||||||
const TEST_FALLBACK_PREF = "testprefbranch.config";
|
const TEST_FALLBACK_PREF = "testprefbranch.config";
|
||||||
const FAKE_FEATURE_MANIFEST = {
|
const FAKE_FEATURE_MANIFEST = {
|
||||||
enabledFallbackPref: "testprefbranch.enabled",
|
enabledFallbackPref: "testprefbranch.enabled",
|
||||||
|
@ -106,14 +111,6 @@ add_task(async function test_ExperimentFeature_getValue() {
|
||||||
|
|
||||||
const featureInstance = new ExperimentFeature("foo", FAKE_FEATURE_MANIFEST);
|
const featureInstance = new ExperimentFeature("foo", FAKE_FEATURE_MANIFEST);
|
||||||
|
|
||||||
Services.prefs.clearUserPref("testprefbranch.value");
|
|
||||||
|
|
||||||
Assert.deepEqual(
|
|
||||||
featureInstance.getValue({ defaultValue: { hello: 1 } }),
|
|
||||||
{ hello: 1 },
|
|
||||||
"should return the defaultValue if no fallback pref is set"
|
|
||||||
);
|
|
||||||
|
|
||||||
Services.prefs.setStringPref(TEST_FALLBACK_PREF, `{"bar": 123}`);
|
Services.prefs.setStringPref(TEST_FALLBACK_PREF, `{"bar": 123}`);
|
||||||
|
|
||||||
Assert.deepEqual(
|
Assert.deepEqual(
|
||||||
|
@ -145,7 +142,7 @@ add_task(
|
||||||
|
|
||||||
manager.store.addExperiment(expected);
|
manager.store.addExperiment(expected);
|
||||||
|
|
||||||
Services.prefs.setStringPref(TEST_FALLBACK_PREF, `{"bar": 123}`);
|
setDefaultBranch(TEST_FALLBACK_PREF, `{"bar": 123}`);
|
||||||
|
|
||||||
Assert.deepEqual(
|
Assert.deepEqual(
|
||||||
featureInstance.getValue(),
|
featureInstance.getValue(),
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { ExperimentAPI, ExperimentFeature } = ChromeUtils.import(
|
||||||
|
"resource://nimbus/ExperimentAPI.jsm"
|
||||||
|
);
|
||||||
|
const { ExperimentFakes } = ChromeUtils.import(
|
||||||
|
"resource://testing-common/NimbusTestUtils.jsm"
|
||||||
|
);
|
||||||
|
const { TestUtils } = ChromeUtils.import(
|
||||||
|
"resource://testing-common/TestUtils.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
const { XPCOMUtils } = ChromeUtils.import(
|
||||||
|
"resource://gre/modules/XPCOMUtils.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
|
async function setupForExperimentFeature() {
|
||||||
|
const sandbox = sinon.createSandbox();
|
||||||
|
const manager = ExperimentFakes.manager();
|
||||||
|
await manager.onStartup();
|
||||||
|
|
||||||
|
sandbox.stub(ExperimentAPI, "_store").get(() => manager.store);
|
||||||
|
|
||||||
|
return { sandbox, manager };
|
||||||
|
}
|
||||||
|
|
||||||
|
const FEATURE_ID = "aboutwelcome";
|
||||||
|
const TEST_FALLBACK_PREF = "browser.aboutwelcome.screens";
|
||||||
|
const FAKE_FEATURE_MANIFEST = {
|
||||||
|
variables: {
|
||||||
|
screens: {
|
||||||
|
type: "json",
|
||||||
|
fallbackPref: TEST_FALLBACK_PREF,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
add_task(async function test_ExperimentFeature_getValue_prefsOverDefaults() {
|
||||||
|
const { sandbox } = await setupForExperimentFeature();
|
||||||
|
|
||||||
|
const featureInstance = new ExperimentFeature(
|
||||||
|
FEATURE_ID,
|
||||||
|
FAKE_FEATURE_MANIFEST
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref(TEST_FALLBACK_PREF);
|
||||||
|
|
||||||
|
Assert.equal(
|
||||||
|
featureInstance.getValue().screens?.length,
|
||||||
|
undefined,
|
||||||
|
"pref is not set"
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.prefs.setStringPref(TEST_FALLBACK_PREF, "[]");
|
||||||
|
|
||||||
|
Assert.deepEqual(
|
||||||
|
featureInstance.getValue().screens.length,
|
||||||
|
0,
|
||||||
|
"should return the user pref value over the defaults"
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref(TEST_FALLBACK_PREF);
|
||||||
|
sandbox.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_ExperimentFeature_getValue_prefsOverExperiment() {
|
||||||
|
const { sandbox, manager } = await setupForExperimentFeature();
|
||||||
|
const recipe = ExperimentFakes.experiment("awexperiment", {
|
||||||
|
branch: {
|
||||||
|
slug: "treatment",
|
||||||
|
feature: {
|
||||||
|
featureId: "aboutwelcome",
|
||||||
|
enabled: true,
|
||||||
|
value: { screens: ["test-value"] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
manager.store.addExperiment(recipe);
|
||||||
|
|
||||||
|
const featureInstance = new ExperimentFeature(
|
||||||
|
FEATURE_ID,
|
||||||
|
FAKE_FEATURE_MANIFEST
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref(TEST_FALLBACK_PREF);
|
||||||
|
|
||||||
|
Assert.ok(
|
||||||
|
!!featureInstance.getValue().screens,
|
||||||
|
"should return the AW experiment value"
|
||||||
|
);
|
||||||
|
|
||||||
|
Assert.equal(
|
||||||
|
featureInstance.getValue().screens[0],
|
||||||
|
"test-value",
|
||||||
|
"should return the AW experiment value"
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.prefs.setStringPref(TEST_FALLBACK_PREF, "[]");
|
||||||
|
|
||||||
|
Assert.deepEqual(
|
||||||
|
featureInstance.getValue().screens.length,
|
||||||
|
0,
|
||||||
|
"should return the user pref value"
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.prefs.clearUserPref(TEST_FALLBACK_PREF);
|
||||||
|
manager.store._deleteForTests(recipe.slug);
|
||||||
|
sandbox.restore();
|
||||||
|
});
|
|
@ -15,5 +15,6 @@ support-files =
|
||||||
[test_SharedDataMap.js]
|
[test_SharedDataMap.js]
|
||||||
[test_ExperimentAPI.js]
|
[test_ExperimentAPI.js]
|
||||||
[test_ExperimentAPI_ExperimentFeature.js]
|
[test_ExperimentAPI_ExperimentFeature.js]
|
||||||
|
[test_ExperimentAPI_ExperimentFeature_getValue.js]
|
||||||
[test_RemoteSettingsExperimentLoader.js]
|
[test_RemoteSettingsExperimentLoader.js]
|
||||||
[test_RemoteSettingsExperimentLoader_updateRecipes.js]
|
[test_RemoteSettingsExperimentLoader_updateRecipes.js]
|
||||||
|
|
Загрузка…
Ссылка в новой задаче