Bug 1848048 - Add a result menu to disable trending results. r=dao,fluent-reviewers,settings-reviewers,flod,Gijs

Differential Revision: https://phabricator.services.mozilla.com/D187066
This commit is contained in:
Dale Harvey 2023-09-01 08:38:54 +00:00
parent 7fef0fa64d
commit 6a30a8ed22
17 changed files with 262 additions and 28 deletions

View File

@ -441,6 +441,10 @@ pref("browser.urlbar.weather.minKeywordLength", 0);
// weather suggestions are turned on.
pref("browser.urlbar.suggest.weather", true);
// If `browser.urlbar.trending.featureGate` is true, this controls whether
// trending suggestions are turned on.
pref("browser.urlbar.suggest.trending", true);
// When `browser.urlbar.bestMatch.enabled` is true, this controls whether best
// match results are shown in the urlbar. This pref is exposed to the user in
// the UI, and it's sticky so that its user-branch value persists regardless of

View File

@ -85,7 +85,7 @@
<link rel="localization" href="toolkit/global/textActions.ftl"/>
<link rel="localization" href="toolkit/printing/printUI.ftl"/>
<!-- Untranslated FTL files -->
<link rel="localization" href="preview/firefoxSuggest.ftl" />
<link rel="localization" href="preview/enUS-searchFeatures.ftl" />
<link rel="localization" href="preview/interventions.ftl" />
#ifdef NIGHTLY_BUILD
<link rel="localization" href="preview/shopping.ftl"/>

View File

@ -51,7 +51,7 @@
<link rel="localization" href="browser/preferences/siteDataSettings.ftl"/>
<link rel="localization" href="browser/sanitize.ftl"/>
<link rel="localization" href="browser/translations.ftl"/>
<link rel="localization" href="preview/firefoxSuggest.ftl"/>
<link rel="localization" href="preview/enUS-searchFeatures.ftl"/>
<link rel="localization" href="security/certificates/certManager.ftl"/>
<link rel="localization" href="security/certificates/deviceManager.ftl"/>
<link rel="localization" href="toolkit/updates/history.ftl"/>

View File

@ -62,6 +62,10 @@
preference="browser.urlbar.showSearchSuggestionsFirst"/>
<checkbox id="showSearchSuggestionsPrivateWindows"
data-l10n-id="search-show-suggestions-private-windows"/>
<hbox align="center" id="showTrendingSuggestionsBox">
<checkbox id="showTrendingSuggestions" data-l10n-id="search-show-trending-suggestions" preference="browser.urlbar.suggest.trending" class="tail-with-learn-more" />
<html:a is="moz-support-link" support-page="google-trending-searches-on-awesomebar" />
</hbox>
<hbox id="urlBarSuggestionPermanentPBLabel"
align="center" class="indent">
<label flex="1" data-l10n-id="search-suggestions-cant-show" />

View File

@ -20,12 +20,17 @@ Preferences.addAll([
{ id: "browser.urlbar.showSearchTerms.enabled", type: "bool" },
{ id: "browser.search.separatePrivateDefault", type: "bool" },
{ id: "browser.search.separatePrivateDefault.ui.enabled", type: "bool" },
{ id: "browser.urlbar.suggest.trending", type: "bool" },
{ id: "browser.urlbar.trending.featureGate", type: "bool" },
]);
const ENGINE_FLAVOR = "text/x-moz-search-engine";
const SEARCH_TYPE = "default_search";
const SEARCH_KEY = "defaultSearch";
// The name of in built engines that support trending results.
const TRENDING_ENGINES = ["Google"];
var gEngineView = null;
var gSearchPane = {
@ -211,6 +216,8 @@ var gSearchPane = {
"urlBarSuggestionPermanentPBLabel"
);
permanentPBLabel.hidden = urlbarSuggests.hidden || !permanentPB;
this._updateTrendingCheckbox();
},
_showAddEngineButton() {
@ -224,6 +231,16 @@ var gSearchPane = {
}
},
async _updateTrendingCheckbox() {
let trendingBox = document.getElementById("showTrendingSuggestionsBox");
let trendingSupported = TRENDING_ENGINES.includes(
(await Services.search.getDefault()).name
);
trendingBox.hidden = !Preferences.get("browser.urlbar.trending.featureGate")
.value;
trendingBox.disabled = !trendingSupported;
},
/**
* Builds the default and private engines drop down lists. This is called
* each time something affects the list of engines.
@ -410,6 +427,7 @@ var gSearchPane = {
if (selectedEngine.name != engine.name) {
gSearchPane.buildDefaultEngineDropDowns();
}
gSearchPane._updateSuggestionCheckboxes();
break;
}
case "engine-default-private": {

View File

@ -31,7 +31,10 @@ add_setup(async () => {
await SearchTestUtils.useMochitestEngines(searchExtensions);
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.suggest.searches", true]],
set: [
["browser.urlbar.suggest.searches", true],
["browser.urlbar.suggest.trending", true],
],
});
SearchTestUtils.useMockIdleService();
@ -130,6 +133,53 @@ add_task(async function test_trending_telemetry() {
TelemetryTestUtils.assertKeyedScalar(scalars, "urlbar.picked.trending", 0, 1);
});
add_task(async function test_block_trending() {
Services.telemetry.clearScalars();
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.trending.featureGate", true],
["browser.urlbar.trending.requireSearchMode", false],
],
});
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: "",
waitForFocus: SimpleTest.waitForFocus,
});
Assert.equal(UrlbarTestUtils.getResultCount(window), 2);
let { result: trendingResult } = await UrlbarTestUtils.getDetailsOfResultAt(
window,
0
);
Assert.equal(trendingResult.payload.trending, true);
await UrlbarTestUtils.openResultMenuAndPressAccesskey(window, "D", {
resultIndex: 0,
});
await BrowserTestUtils.waitForCondition(
() => UrlbarTestUtils.getResultCount(window) == 1
);
let { result: heuristicResult } = await UrlbarTestUtils.getDetailsOfResultAt(
window,
0
);
Assert.notEqual(heuristicResult.payload.trending, true);
TelemetryTestUtils.assertScalar(
TelemetryTestUtils.getProcessScalars("parent", false, true),
"urlbar.trending.block",
1
);
await UrlbarTestUtils.promisePopupClose(window, () => {
EventUtils.synthesizeKey("KEY_Escape");
});
await SpecialPowers.popPrefEnv();
});
async function check_results({
featureEnabled = false,
requireSearchModeEnabled = true,

View File

@ -132,11 +132,16 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
}
}
// Show Top Sites above trending results.
let showSearchSuggestionsFirst = !(
lazy.UrlbarPrefs.get("suggest.trending") && !context.searchString
);
// Determine the result groups to use for this sort. In search mode with
// an engine, show search suggestions first.
let rootGroup = context.searchMode?.engineName
? lazy.UrlbarPrefs.makeResultGroups({ showSearchSuggestionsFirst: true })
: lazy.UrlbarPrefs.resultGroups;
let rootGroup =
context.searchMode?.engineName || !showSearchSuggestionsFirst
? lazy.UrlbarPrefs.makeResultGroups({ showSearchSuggestionsFirst })
: lazy.UrlbarPrefs.resultGroups;
lazy.logger.debug(`Groups: ${JSON.stringify(rootGroup)}`);
// Fill the root group.

View File

@ -304,6 +304,10 @@ const PREF_URLBAR_DEFAULTS = new Map([
// weather suggestions are turned on.
["suggest.weather", true],
// If `browser.urlbar.trending.featureGate` is true, this controls whether
// trending suggestions are turned on.
["suggest.trending", true],
// JSON'ed array of blocked quick suggest URL digests.
["quicksuggest.blockedDigests", ""],

View File

@ -25,6 +25,15 @@ ChromeUtils.defineESModuleGetters(lazy, {
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs",
});
const RESULT_MENU_COMMANDS = {
TRENDING_BLOCK: "trendingblock",
TRENDING_HELP: "help",
};
const TRENDING_HELP_URL =
Services.urlFormatter.formatURLPref("app.support.baseURL") +
"google-trending-searches-on-awesomebar";
/**
* Returns whether the passed in string looks like a url.
*
@ -318,6 +327,33 @@ class ProviderSearchSuggestions extends UrlbarProvider {
}
}
/**
* Returns the menu commands to be shown for trending results.
*
* @param {UrlbarResult} result
* The result to get menu comands for.
*
* @returns {Array} The commands to be shown.
*/
getResultCommands(result) {
if (result.payload.trending) {
return [
{
name: RESULT_MENU_COMMANDS.TRENDING_BLOCK,
l10n: { id: "urlbar-result-menu-trending-dont-show" },
},
{
name: "separator",
},
{
name: RESULT_MENU_COMMANDS.TRENDING_HELP,
l10n: { id: "urlbar-result-menu-trending-why" },
},
];
}
return undefined;
}
onEngagement(state, queryContext, details, controller) {
let { result } = details;
if (result?.providerName != this.name) {
@ -333,6 +369,18 @@ class ProviderSearchSuggestions extends UrlbarProvider {
console.error(`Removing form history failed: ${error}`)
);
controller.removeResult(result);
return;
}
switch (details.selType) {
case RESULT_MENU_COMMANDS.TRENDING_HELP:
// Handled by UrlbarInput
break;
case RESULT_MENU_COMMANDS.TRENDING_BLOCK:
lazy.UrlbarPrefs.set("suggest.trending", false);
this.#recordTrendingBlockedTelemetry(details.selType);
this.#replaceTrendingResultWithAcknowledgement(controller);
break;
}
}
@ -449,6 +497,24 @@ class ProviderSearchSuggestions extends UrlbarProvider {
}
try {
let payload = {
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
suggestion: [entry.value, UrlbarUtils.HIGHLIGHT.SUGGESTED],
lowerCaseSuggestion: entry.value.toLocaleLowerCase(),
tailPrefix,
tail: [tail, UrlbarUtils.HIGHLIGHT.SUGGESTED],
tailOffsetIndex: tail ? entry.tailOffsetIndex : undefined,
keyword: [alias ? alias : undefined, UrlbarUtils.HIGHLIGHT.TYPED],
trending: entry.trending,
description: entry.description || undefined,
query: [searchString.trim(), UrlbarUtils.HIGHLIGHT.NONE],
icon: !entry.value ? engine.iconURI?.spec : entry.icon,
};
if (entry.trending) {
payload.helpUrl = TRENDING_HELP_URL;
}
results.push(
Object.assign(
new lazy.UrlbarResult(
@ -456,22 +522,7 @@ class ProviderSearchSuggestions extends UrlbarProvider {
UrlbarUtils.RESULT_SOURCE.SEARCH,
...lazy.UrlbarResult.payloadAndSimpleHighlights(
queryContext.tokens,
{
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
suggestion: [entry.value, UrlbarUtils.HIGHLIGHT.SUGGESTED],
lowerCaseSuggestion: entry.value.toLocaleLowerCase(),
tailPrefix,
tail: [tail, UrlbarUtils.HIGHLIGHT.SUGGESTED],
tailOffsetIndex: tail ? entry.tailOffsetIndex : undefined,
keyword: [
alias ? alias : undefined,
UrlbarUtils.HIGHLIGHT.TYPED,
],
trending: entry.trending,
description: entry.description || undefined,
query: [searchString.trim(), UrlbarUtils.HIGHLIGHT.NONE],
icon: !entry.value ? engine.iconURI?.spec : entry.icon,
}
payload
)
),
{ isRichSuggestion: !!entry.icon }
@ -560,10 +611,42 @@ class ProviderSearchSuggestions extends UrlbarProvider {
return !!(
queryContext.searchString == "" &&
lazy.UrlbarPrefs.get("trending.featureGate") &&
lazy.UrlbarPrefs.get("suggest.trending") &&
(queryContext.searchMode ||
!lazy.UrlbarPrefs.get("trending.requireSearchMode"))
);
}
/*
* Send telemetry to indicating trending results have been hidden.
*/
#recordTrendingBlockedTelemetry() {
Services.telemetry.scalarAdd("urlbar.trending.block", 1);
}
/*
* Remove all but the first trending results and replace the
* first result with an acknowledgement that the trending suggestions
* have been turned off.
*/
#replaceTrendingResultWithAcknowledgement(controller) {
let firstResult = null;
let resultsToRemove = [];
for (let result of controller.view.visibleResults) {
if (!result.payload.trending) {
continue;
}
if (!firstResult) {
firstResult = result;
} else {
resultsToRemove.push(result);
}
}
controller.view.acknowledgeDismissal(firstResult, {
id: "urlbar-trending-dismissal-acknowledgment",
});
resultsToRemove.forEach(result => controller.removeResult(result));
}
}
function makeFormHistoryResult(queryContext, engine, entry) {

View File

@ -1518,6 +1518,9 @@ UrlbarUtils.RESULT_PAYLOAD_SCHEMA = {
engine: {
type: "string",
},
helpUrl: {
type: "string",
},
icon: {
type: "string",
},

View File

@ -2101,6 +2101,16 @@ export class UrlbarView {
return null;
}
let engineName =
row.result.payload.engine || Services.search.defaultEngine.name;
if (row.result.payload.trending) {
return {
id: "urlbar-group-trending",
args: { engine: engineName },
};
}
if (
row.result.isBestMatch &&
row.result.providerName == lazy.UrlbarProviderQuickSuggest.name
@ -2139,8 +2149,6 @@ export class UrlbarView {
case lazy.UrlbarUtils.RESULT_TYPE.SEARCH:
// Show "{ $engine } suggestions" if it's not the first label.
if (currentLabel && row.result.payload.suggestion) {
let engineName =
row.result.payload.engine || Services.search.defaultEngine.name;
return {
id: "urlbar-group-search-suggestions",
args: { engine: engineName },

View File

@ -333,3 +333,29 @@ firefox-suggest-onboarding-main-reject-option-description-3 = Leave the default
firefox-suggest-onboarding-main-submit-button = Save preferences
firefox-suggest-onboarding-main-skip-link = Not now
## Strings for trending suggestions that are currently only used in
## en-US based experiments.
# Shown in preferences to enabled and disable trending suggestions.
search-show-trending-suggestions =
.label = Show trending search suggestions
.accesskey = t
# The header shown above trending results.
# Variables:
# $engine (String): the name of the search engine providing the trending suggestions
urlbar-group-trending =
.label = Trending on { $engine }
# The result menu labels shown next to trending results.
urlbar-result-menu-trending-dont-show =
.label = Dont show trending searches
.accesskey = D
urlbar-result-menu-trending-why =
.label = Why am I seeing this?
.accesskey = W
# A message that replaces a result when the user dismisses all suggestions of a
# particular type.
urlbar-trending-dismissal-acknowledgment = Thanks for your feedback. You wont see trending searches anymore.

View File

@ -15,7 +15,7 @@
href="chrome://browser/content/urlbar/quicksuggestOnboarding.css">
<link rel="localization" href="branding/brand.ftl">
<link rel="localization" href="toolkit/branding/brandings.ftl"/>
<link rel="localization" href="preview/firefoxSuggest.ftl">
<link rel="localization" href="preview/enUS-searchFeatures.ftl">
<script src="chrome://browser/content/urlbar/quicksuggestOnboarding.js"></script>
</head>
<body id="onboardingDialog" role="dialog" aria-labelledby="introduction-title">

View File

@ -67,6 +67,7 @@ add_setup(async function () {
set: [
["browser.search.separatePrivateDefault.ui.enabled", false],
["browser.urlbar.suggest.quickactions", false],
["browser.urlbar.suggest.trending", false],
],
});
});

View File

@ -11,7 +11,7 @@
preview/ion.ftl (../components/ion/content/ion.ftl)
preview/protections.ftl (../components/protections/content/protections.ftl)
preview/interventions.ftl (../components/urlbar/content/interventions.ftl)
preview/firefoxSuggest.ftl (../components/urlbar/content/firefoxSuggest.ftl)
preview/enUS-searchFeatures.ftl (../components/urlbar/content/enUS-searchFeatures.ftl)
#ifdef NIGHTLY_BUILD
preview/shopping.ftl (../components/shopping/content/shopping.ftl)
#endif

View File

@ -113,6 +113,18 @@ search:
type: boolean
setPref: browser.search.serpEventTelemetry.enabled
description: Whether the Glean SERP event telemetry is enabled.
trendingEnabled:
type: boolean
setPref: browser.urlbar.trending.featureGate
description: Feature gate that controls whether trending suggestions are enabled.
trendingRequireSearchMode:
type: boolean
setPref: browser.urlbar.trending.requireSearchMode
description: Controls whether trending suggestions are only shown in search mode or not.
trendingMaxResultsNoSearchMode:
type: boolean
setPref: browser.urlbar.trending.maxResultsNoSearchMode
description: The maximum number of trending results mode outside search mode.
# `searchConfiguration` is for search experiment features for items that require
# isEarlyStartup to be true. These items may require a reload of the search
@ -1132,7 +1144,7 @@ glean:
A map of metric base-identifiers to booleans representing the state of the 'enabled' flag for that metric.
This variable is intended for interacting with the Glean data-control-plane via the Server Knobs functionality
to remotely configure metrics to be enabled or disabled.
gleanInternalSdk:
description: "The Glean internal SDK feature intended only for internal Glean Team use"
hasExposure: false
@ -1150,7 +1162,7 @@ gleanInternalSdk:
type: int
description: >-
Maximum number of pings that can be sent in a 60 second interval
majorRelease2022:
description: Major Release 2022
owner: firefoxview@mozilla.com

View File

@ -7139,6 +7139,22 @@ policies:
record_in_processes:
- main
urlbar.trending:
block:
bug_numbers:
- 1848048
description: >-
User has blocked seeing trending results.
expires: never
kind: uint
notification_emails:
- fx-search-telemetry@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- main
urlbar:
abandonment:
bug_numbers: