Bug 1772100 - Part 20: Use plain object for lazy getter in browser/components/uitour/. r=MattN

Differential Revision: https://phabricator.services.mozilla.com/D148030
This commit is contained in:
Tooru Fujisawa 2022-06-06 22:46:26 +00:00
Родитель d1b65526d4
Коммит 6193605bb3
1 изменённых файлов: 106 добавлений и 91 удалений

Просмотреть файл

@ -14,7 +14,9 @@ const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
const lazy = {};
XPCOMUtils.defineLazyModuleGetters(lazy, {
AboutReaderParent: "resource:///actors/AboutReaderParent.jsm",
AddonManager: "resource://gre/modules/AddonManager.jsm",
BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
@ -28,7 +30,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
UpdateUtils: "resource://gre/modules/UpdateUtils.jsm",
});
XPCOMUtils.defineLazyGetter(this, "fxAccounts", () => {
XPCOMUtils.defineLazyGetter(lazy, "fxAccounts", () => {
return ChromeUtils.import(
"resource://gre/modules/FxAccounts.jsm"
).getFxAccountsSingleton();
@ -52,10 +54,11 @@ const BACKGROUND_PAGE_ACTIONS_ALLOWED = new Set([
const MAX_BUTTONS = 4;
// Array of which colorway/theme ids can be activated.
XPCOMUtils.defineLazyGetter(this, "COLORWAY_IDS", () =>
[...BuiltInThemes.builtInThemeMap.keys()].filter(
XPCOMUtils.defineLazyGetter(lazy, "COLORWAY_IDS", () =>
[...lazy.BuiltInThemes.builtInThemeMap.keys()].filter(
id =>
id.endsWith("-colorway@mozilla.org") && !BuiltInThemes.themeIsExpired(id)
id.endsWith("-colorway@mozilla.org") &&
!lazy.BuiltInThemes.themeIsExpired(id)
)
);
@ -63,7 +66,7 @@ XPCOMUtils.defineLazyGetter(this, "COLORWAY_IDS", () =>
const TARGET_SEARCHENGINE_PREFIX = "searchEngine-";
// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
XPCOMUtils.defineLazyGetter(this, "log", () => {
XPCOMUtils.defineLazyGetter(lazy, "log", () => {
let { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm");
let consoleOptions = {
maxLogLevelPref: PREF_LOG_LEVEL,
@ -207,7 +210,7 @@ var UITour = {
]),
init() {
log.debug("Initializing UITour");
lazy.log.debug("Initializing UITour");
// Lazy getter is initialized here so it can be replicated any time
// in a test.
delete this.url;
@ -223,7 +226,7 @@ var UITour = {
"onWidgetReset",
"onAreaReset",
];
CustomizableUI.addListener(
lazy.CustomizableUI.addListener(
listenerMethods.reduce((listener, method) => {
listener[method] = () => this.clearAvailableTargetsCache();
return listener;
@ -251,22 +254,22 @@ var UITour = {
window = Services.wm.getMostRecentWindow("navigator:browser");
}
log.debug("onPageEvent:", aEvent.detail);
lazy.log.debug("onPageEvent:", aEvent.detail);
if (typeof aEvent.detail != "object") {
log.warn("Malformed event - detail not an object");
lazy.log.warn("Malformed event - detail not an object");
return false;
}
let action = aEvent.detail.action;
if (typeof action != "string" || !action) {
log.warn("Action not defined");
lazy.log.warn("Action not defined");
return false;
}
let data = aEvent.detail.data;
if (typeof data != "object") {
log.warn("Malformed event - data not an object");
lazy.log.warn("Malformed event - data not an object");
return false;
}
@ -275,7 +278,7 @@ var UITour = {
aEvent.pageVisibilityState == "unloaded") &&
!BACKGROUND_PAGE_ACTIONS_ALLOWED.has(action)
) {
log.warn(
lazy.log.warn(
"Ignoring disallowed action from a hidden page:",
action,
aEvent.pageVisibilityState
@ -293,7 +296,9 @@ var UITour = {
targetPromise
.then(target => {
if (!target.node) {
log.error("UITour: Target could not be resolved: " + data.target);
lazy.log.error(
"UITour: Target could not be resolved: " + data.target
);
return;
}
let effect = undefined;
@ -302,7 +307,7 @@ var UITour = {
}
this.showHighlight(window, target, effect);
})
.catch(log.error);
.catch(lazy.log.error);
break;
}
@ -316,7 +321,9 @@ var UITour = {
targetPromise
.then(target => {
if (!target.node) {
log.error("UITour: Target could not be resolved: " + data.target);
lazy.log.error(
"UITour: Target could not be resolved: " + data.target
);
return;
}
@ -352,7 +359,7 @@ var UITour = {
buttons.push(button);
if (buttons.length == MAX_BUTTONS) {
log.warn(
lazy.log.warn(
"showInfo: Reached limit of allowed number of buttons"
);
break;
@ -383,7 +390,7 @@ var UITour = {
infoOptions
);
})
.catch(log.error);
.catch(lazy.log.error);
break;
}
@ -415,7 +422,7 @@ var UITour = {
case "getConfiguration": {
if (typeof data.configuration != "string") {
log.warn("getConfiguration: No configuration option specified");
lazy.log.warn("getConfiguration: No configuration option specified");
return false;
}
@ -430,7 +437,7 @@ var UITour = {
case "setConfiguration": {
if (typeof data.configuration != "string") {
log.warn("setConfiguration: No configuration option specified");
lazy.log.warn("setConfiguration: No configuration option specified");
return false;
}
@ -440,7 +447,7 @@ var UITour = {
case "openPreferences": {
if (typeof data.pane != "string" && typeof data.pane != "undefined") {
log.warn("openPreferences: Invalid pane specified");
lazy.log.warn("openPreferences: Invalid pane specified");
return false;
}
window.openPreferences(data.pane);
@ -451,11 +458,11 @@ var UITour = {
Promise.resolve()
.then(() => {
return data.email
? FxAccounts.config.promiseEmailURI(
? lazy.FxAccounts.config.promiseEmailURI(
data.email,
data.entrypoint || "uitour"
)
: FxAccounts.config.promiseConnectAccountURI(
: lazy.FxAccounts.config.promiseConnectAccountURI(
data.entrypoint || "uitour"
);
})
@ -463,7 +470,9 @@ var UITour = {
const url = new URL(uri);
// Call our helper to validate extraURLParams and populate URLSearchParams
if (!this._populateURLParams(url, data.extraURLParams)) {
log.warn("showFirefoxAccounts: invalid campaign args specified");
lazy.log.warn(
"showFirefoxAccounts: invalid campaign args specified"
);
return;
}
// We want to replace the current tab.
@ -477,13 +486,13 @@ var UITour = {
}
case "showConnectAnotherDevice": {
FxAccounts.config
lazy.FxAccounts.config
.promiseConnectDeviceURI(data.entrypoint || "uitour")
.then(uri => {
const url = new URL(uri);
// Call our helper to validate extraURLParams and populate URLSearchParams
if (!this._populateURLParams(url, data.extraURLParams)) {
log.warn(
lazy.log.warn(
"showConnectAnotherDevice: invalid campaign args specified"
);
return;
@ -501,8 +510,8 @@ var UITour = {
case "resetFirefox": {
// Open a reset profile dialog window.
if (ResetProfile.resetSupported()) {
ResetProfile.openConfirmationDialog(window);
if (lazy.ResetProfile.resetSupported()) {
lazy.ResetProfile.openConfirmationDialog(window);
}
break;
}
@ -514,7 +523,7 @@ var UITour = {
.then(target => {
this.addNavBarWidget(target, browser, data.callbackID);
})
.catch(log.error);
.catch(lazy.log.error);
break;
}
@ -593,14 +602,14 @@ var UITour = {
}
case "forceShowReaderIcon": {
AboutReaderParent.forceShowReaderIcon(browser);
lazy.AboutReaderParent.forceShowReaderIcon(browser);
break;
}
case "toggleReaderMode": {
let targetPromise = this.getTarget(window, "readerMode-urlBar");
targetPromise.then(target => {
AboutReaderParent.toggleReaderMode({ target: target.node });
lazy.AboutReaderParent.toggleReaderMode({ target: target.node });
});
break;
}
@ -652,7 +661,7 @@ var UITour = {
},
handleEvent(aEvent) {
log.debug("handleEvent: type =", aEvent.type, "event =", aEvent);
lazy.log.debug("handleEvent: type =", aEvent.type, "event =", aEvent);
switch (aEvent.type) {
case "TabSelect": {
let window = aEvent.target.ownerGlobal;
@ -682,7 +691,7 @@ var UITour = {
},
observe(aSubject, aTopic, aData) {
log.debug("observe: aTopic =", aTopic);
lazy.log.debug("observe: aTopic =", aTopic);
switch (aTopic) {
// The browser message manager is disconnected when the <browser> is
// destroyed and we want to teardown at that point.
@ -724,7 +733,7 @@ var UITour = {
return true;
}
if (typeof extraURLParams != "string") {
log.warn("_populateURLParams: extraURLParams is not a string");
lazy.log.warn("_populateURLParams: extraURLParams is not a string");
return false;
}
let urlParams;
@ -732,14 +741,14 @@ var UITour = {
if (extraURLParams) {
urlParams = JSON.parse(extraURLParams);
if (typeof urlParams != "object") {
log.warn(
lazy.log.warn(
"_populateURLParams: extraURLParams is not a stringified object"
);
return false;
}
}
} catch (ex) {
log.warn("_populateURLParams: extraURLParams is not a JSON object");
lazy.log.warn("_populateURLParams: extraURLParams is not a JSON object");
return false;
}
if (urlParams) {
@ -754,7 +763,7 @@ var UITour = {
FLOW_BEGIN_TIME_LENGTH) ||
(urlParams.flow_id && urlParams.flow_id.length !== FLOW_ID_LENGTH)
) {
log.warn(
lazy.log.warn(
"_populateURLParams: flow parameters are not properly structured"
);
return false;
@ -777,7 +786,7 @@ var UITour = {
!validName ||
!reSimpleString.test(name)
) {
log.warn("_populateURLParams: invalid campaign param specified");
lazy.log.warn("_populateURLParams: invalid campaign param specified");
return false;
}
url.searchParams.append(name, value);
@ -789,7 +798,7 @@ var UITour = {
* Tear down a tour from a tab e.g. upon switching/closing tabs.
*/
async teardownTourForBrowser(aWindow, aBrowser, aTourPageClosing = false) {
log.debug(
lazy.log.debug(
"teardownTourForBrowser: aBrowser = ",
aBrowser,
aTourPageClosing
@ -846,7 +855,7 @@ var UITour = {
* Tear down all tours for a ChromeWindow.
*/
teardownTourForWindow(aWindow) {
log.debug("teardownTourForWindow");
lazy.log.debug("teardownTourForWindow");
aWindow.gBrowser.tabContainer.removeEventListener("TabSelect", this);
aWindow.removeEventListener("SSWindowClosing", this);
@ -861,7 +870,7 @@ var UITour = {
}
if (!allowedSchemes.has(aURI.scheme)) {
log.error("Unsafe scheme:", aURI.scheme);
lazy.log.error("Unsafe scheme:", aURI.scheme);
return false;
}
@ -884,7 +893,7 @@ var UITour = {
sendPageCallback(aBrowser, aCallbackID, aData = {}) {
let detail = { data: aData, callbackID: aCallbackID };
log.debug("sendPageCallback", detail);
lazy.log.debug("sendPageCallback", detail);
let contextToVisit = aBrowser.browsingContext;
let global = contextToVisit.currentWindowGlobal;
let actor = global.getActor("UITour");
@ -901,15 +910,15 @@ var UITour = {
},
getTarget(aWindow, aTargetName, aSticky = false) {
log.debug("getTarget:", aTargetName);
lazy.log.debug("getTarget:", aTargetName);
if (typeof aTargetName != "string" || !aTargetName) {
log.warn("getTarget: Invalid target name specified");
lazy.log.warn("getTarget: Invalid target name specified");
return Promise.reject("Invalid target name specified");
}
let targetObject = this.targets.get(aTargetName);
if (!targetObject) {
log.warn(
lazy.log.warn(
"getTarget: The specified target name is not in the allowed set"
);
return Promise.reject(
@ -926,7 +935,7 @@ var UITour = {
try {
node = targetQuery(aWindow.document);
} catch (ex) {
log.warn("getTarget: Error running target query:", ex);
lazy.log.warn("getTarget: Error running target query:", ex);
node = null;
}
} else {
@ -945,7 +954,7 @@ var UITour = {
allowAdd: targetObject.allowAdd,
});
})
.catch(log.error);
.catch(lazy.log.error);
});
},
@ -956,7 +965,7 @@ var UITour = {
let doc = aTarget.node.ownerGlobal.document;
targetElement =
doc.getElementById(aTarget.widgetName) ||
PanelMultiView.getViewNode(doc, aTarget.widgetName);
lazy.PanelMultiView.getViewNode(doc, aTarget.widgetName);
}
return targetElement.id.startsWith("appMenu-");
@ -971,7 +980,7 @@ var UITour = {
* @param {Object} aOptions Extra config arguments, example `autohide: true`.
*/
_setMenuStateForAnnotation(aWindow, aShouldOpen, aOptions = {}) {
log.debug(
lazy.log.debug(
"_setMenuStateForAnnotation: Menu is expected to be:",
aShouldOpen ? "open" : "closed"
);
@ -980,14 +989,16 @@ var UITour = {
// If the panel is in the desired state, we're done.
let panelIsOpen = menu.state != "closed";
if (aShouldOpen == panelIsOpen) {
log.debug("_setMenuStateForAnnotation: Menu already in expected state");
lazy.log.debug(
"_setMenuStateForAnnotation: Menu already in expected state"
);
return Promise.resolve();
}
// Actually show or hide the menu
let promise = null;
if (aShouldOpen) {
log.debug("_setMenuStateForAnnotation: Opening the menu");
lazy.log.debug("_setMenuStateForAnnotation: Opening the menu");
promise = new Promise(resolve => {
this.showMenu(aWindow, "appMenu", resolve, aOptions);
});
@ -995,7 +1006,7 @@ var UITour = {
// If the menu was opened explictly by api user through `Mozilla.UITour.showMenu`,
// it should be closed explictly by api user through `Mozilla.UITour.hideMenu`.
// So we shouldn't get to here to close it for the highlight/info annotation.
log.debug("_setMenuStateForAnnotation: Closing the menu");
lazy.log.debug("_setMenuStateForAnnotation: Closing the menu");
promise = new Promise(resolve => {
menu.addEventListener("popuphidden", resolve, { once: true });
this.hideMenu(aWindow, "appMenu");
@ -1065,7 +1076,8 @@ var UITour = {
let node = (aTarget.node = refreshedTarget.node);
// If the target is in the overflow panel, just return the overflow button.
if (node.closest("#widget-overflow-mainView")) {
return CustomizableUI.getWidget(node.id).forWindow(aChromeWindow).anchor;
return lazy.CustomizableUI.getWidget(node.id).forWindow(aChromeWindow)
.anchor;
}
return node;
},
@ -1129,7 +1141,7 @@ var UITour = {
highlighter.parentElement.state == "showing" ||
highlighter.parentElement.state == "open"
) {
log.debug("showHighlight: Closing previous highlight first");
lazy.log.debug("showHighlight: Closing previous highlight first");
highlighter.parentElement.hidePopup();
}
/* The "overlap" position anchors from the top-left but we want to centre highlights at their
@ -1160,7 +1172,7 @@ var UITour = {
let anchorEl = await this._correctAnchor(aChromeWindow, aTarget);
showHighlightElement(anchorEl);
} catch (e) {
log.warn(e);
lazy.log.warn(e);
}
},
@ -1311,7 +1323,7 @@ var UITour = {
let anchorEl = await this._correctAnchor(aChromeWindow, aAnchor);
showInfoElement(anchorEl);
} catch (e) {
log.warn(e);
lazy.log.warn(e);
}
},
@ -1374,7 +1386,7 @@ var UITour = {
},
showMenu(aWindow, aMenuName, aOpenCallback = null, aOptions = {}) {
log.debug("showMenu:", aMenuName);
lazy.log.debug("showMenu:", aMenuName);
function openMenuButton(aMenuBtn) {
if (!aMenuBtn || !aMenuBtn.hasMenu() || aMenuBtn.open) {
if (aOpenCallback) {
@ -1417,7 +1429,7 @@ var UITour = {
} else if (aMenuName == "pocket") {
let button = aWindow.document.getElementById("save-to-pocket-button");
if (!button) {
log.error("Can't open the pocket menu without a button");
lazy.log.error("Can't open the pocket menu without a button");
return;
}
aWindow.document.addEventListener("ViewShown", aOpenCallback, {
@ -1448,7 +1460,7 @@ var UITour = {
},
hideMenu(aWindow, aMenuName) {
log.debug("hideMenu:", aMenuName);
lazy.log.debug("hideMenu:", aMenuName);
function closeMenuButton(aMenuBtn) {
if (aMenuBtn && aMenuBtn.hasMenu()) {
aMenuBtn.openMenu(false);
@ -1525,7 +1537,7 @@ var UITour = {
}
hideMethod(win);
})
.catch(log.error);
.catch(lazy.log.error);
}
});
},
@ -1567,7 +1579,7 @@ var UITour = {
this.getAvailableTargets(aBrowser, aWindow, aCallbackID);
break;
case "colorway":
this.sendPageCallback(aBrowser, aCallbackID, COLORWAY_IDS);
this.sendPageCallback(aBrowser, aCallbackID, lazy.COLORWAY_IDS);
break;
case "search":
case "selectedSearchEngine":
@ -1619,11 +1631,11 @@ var UITour = {
this.sendPageCallback(
aBrowser,
aCallbackID,
ResetProfile.resetSupported()
lazy.ResetProfile.resetSupported()
);
break;
default:
log.error(
lazy.log.error(
"getConfiguration: Unknown configuration requested: " + aConfiguration
);
break;
@ -1647,19 +1659,19 @@ var UITour = {
let toEnable = this._prevTheme;
// Activate the allowed colorway.
if (COLORWAY_IDS.includes(aValue)) {
if (lazy.COLORWAY_IDS.includes(aValue)) {
// Save the previous theme if this is the first activation.
if (!this._prevTheme) {
this._prevTheme = (
await AddonManager.getAddonsByTypes(["theme"])
await lazy.AddonManager.getAddonsByTypes(["theme"])
).find(theme => theme.isActive);
}
toEnable = await AddonManager.getAddonByID(aValue);
toEnable = await lazy.AddonManager.getAddonByID(aValue);
}
toEnable?.enable();
break;
default:
log.error(
lazy.log.error(
"setConfiguration: Unknown configuration requested: " + aConfiguration
);
break;
@ -1671,7 +1683,7 @@ var UITour = {
// remote servers. See also `getFxAConnections()`
getFxA(aBrowser, aCallbackID) {
(async () => {
let setup = !!(await fxAccounts.getSignedInUser());
let setup = !!(await lazy.fxAccounts.getSignedInUser());
let result = { setup };
if (!setup) {
this.sendPageCallback(aBrowser, aCallbackID, result);
@ -1700,10 +1712,10 @@ var UITour = {
};
}
// And the account state.
result.accountStateOK = await fxAccounts.hasLocalSession();
result.accountStateOK = await lazy.fxAccounts.hasLocalSession();
this.sendPageCallback(aBrowser, aCallbackID, result);
})().catch(err => {
log.error(err);
lazy.log.error(err);
this.sendPageCallback(aBrowser, aCallbackID, {});
});
},
@ -1713,23 +1725,23 @@ var UITour = {
// usually hit the FxA servers to obtain this info.
getFxAConnections(aBrowser, aCallbackID) {
(async () => {
let setup = !!(await fxAccounts.getSignedInUser());
let setup = !!(await lazy.fxAccounts.getSignedInUser());
let result = { setup };
if (!setup) {
this.sendPageCallback(aBrowser, aCallbackID, result);
return;
}
// We are signed in so need to build a richer result.
let devices = fxAccounts.device.recentDeviceList;
let devices = lazy.fxAccounts.device.recentDeviceList;
// A recent device list is fine, but if we don't even have that we should
// wait for it to be fetched.
if (!devices) {
try {
await fxAccounts.device.refreshDeviceList();
await lazy.fxAccounts.device.refreshDeviceList();
} catch (ex) {
log.warn("failed to fetch device list", ex);
lazy.log.warn("failed to fetch device list", ex);
}
devices = fxAccounts.device.recentDeviceList;
devices = lazy.fxAccounts.device.recentDeviceList;
}
if (devices) {
// A falsey `devices` should be impossible, so we omit `devices` from
@ -1747,7 +1759,7 @@ var UITour = {
try {
// Each of the "account services", which we turn into a map keyed by ID.
let attachedClients = await fxAccounts.listAttachedOAuthClients();
let attachedClients = await lazy.fxAccounts.listAttachedOAuthClients();
result.accountServices = attachedClients
.filter(c => !!c.id)
.reduce((accum, c) => {
@ -1760,11 +1772,11 @@ var UITour = {
return accum;
}, {});
} catch (ex) {
log.warn("Failed to build the attached clients list", ex);
lazy.log.warn("Failed to build the attached clients list", ex);
}
this.sendPageCallback(aBrowser, aCallbackID, result);
})().catch(err => {
log.error(err);
lazy.log.error(err);
this.sendPageCallback(aBrowser, aCallbackID, {});
});
},
@ -1782,7 +1794,7 @@ var UITour = {
appinfo.distribution = distribution;
// Update channel, in a way that preserves 'beta' for RC beta builds:
appinfo.defaultUpdateChannel = UpdateUtils.getUpdateChannel(
appinfo.defaultUpdateChannel = lazy.UpdateUtils.getUpdateChannel(
false /* no partner ID */
);
@ -1814,7 +1826,7 @@ var UITour = {
// Expose Profile creation and last reset dates in weeks.
const ONE_WEEK = 7 * 24 * 60 * 60 * 1000;
let profileAge = await ProfileAge();
let profileAge = await lazy.ProfileAge();
let createdDate = await profileAge.created;
let resetDate = await profileAge.reset;
let createdWeeksAgo = Math.floor((Date.now() - createdDate) / ONE_WEEK);
@ -1827,7 +1839,7 @@ var UITour = {
this.sendPageCallback(aBrowser, aCallbackID, appinfo);
})().catch(err => {
log.error(err);
lazy.log.error(err);
this.sendPageCallback(aBrowser, aCallbackID, {});
});
},
@ -1837,7 +1849,7 @@ var UITour = {
let window = aChromeWindow;
let data = this.availableTargetsCache.get(window);
if (data) {
log.debug(
lazy.log.debug(
"getAvailableTargets: Using cached targets list",
data.targets.join(",")
);
@ -1864,7 +1876,7 @@ var UITour = {
this.availableTargetsCache.set(window, data);
this.sendPageCallback(aBrowser, aCallbackID, data);
})().catch(err => {
log.error(err);
lazy.log.error(err);
this.sendPageCallback(aBrowser, aCallbackID, {
targets: [],
});
@ -1873,31 +1885,34 @@ var UITour = {
addNavBarWidget(aTarget, aBrowser, aCallbackID) {
if (aTarget.node) {
log.error(
lazy.log.error(
"addNavBarWidget: can't add a widget already present:",
aTarget
);
return;
}
if (!aTarget.allowAdd) {
log.error("addNavBarWidget: not allowed to add this widget:", aTarget);
lazy.log.error(
"addNavBarWidget: not allowed to add this widget:",
aTarget
);
return;
}
if (!aTarget.widgetName) {
log.error(
lazy.log.error(
"addNavBarWidget: can't add a widget without a widgetName property:",
aTarget
);
return;
}
CustomizableUI.addWidgetToArea(
lazy.CustomizableUI.addWidgetToArea(
aTarget.widgetName,
CustomizableUI.AREA_NAVBAR
lazy.CustomizableUI.AREA_NAVBAR
);
BrowserUsageTelemetry.recordWidgetChange(
lazy.BrowserUsageTelemetry.recordWidgetChange(
aTarget.widgetName,
CustomizableUI.AREA_NAVBAR,
lazy.CustomizableUI.AREA_NAVBAR,
"uitour"
);
this.sendPageCallback(aBrowser, aCallbackID);
@ -1993,7 +2008,7 @@ UITour.init();
*/
const UITourHealthReport = {
recordTreatmentTag(tag, value) {
return TelemetryController.submitExternalPing(
return lazy.TelemetryController.submitExternalPing(
"uitour-tag",
{
version: 1,