forked from mirrors/gecko-dev
This adds a `quickSuggestScoreMap` Nimbus variable that lets experiments
override suggestion scores. It maps from telemetry types to score values. For
example:
```
"quickSuggestScoreMap": {
"amo": 0.25,
"adm_sponsored": 0.3
}
```
In this example, addon suggestions will always have a score of 0.25, and
sponsored suggestions will always have a score of 0.3. Of course, different
branches within an experiment and different experiments can set different
scores.
While working on this, I saw we have a bug when we try to look up the
`BaseFeature` for a result. To do the lookup, we look up the result's
`telemetryType` in `FEATURE_NAMES_BY_TELEMETRY_TYPE`. That's a problem for `adm`
suggestions because the `telemetryType` will be either `adm_sponsored` or
`adm_nonsponsored`, but neither of those is present in
`FEATURE_NAMES_BY_TELEMETRY_TYPE` -- only `adm` is.
To fix it, I added back the `provider` property to result payloads that I
previously removed, and I added `BaseFeature.merinoProvider` so each feature can
specify its Merino provider. Then, `QuickSuggest` can build a map from Merino
provider names to features, allowing us to look up features without needing to
hardcode something like `FEATURE_NAMES_BY_TELEMETRY_TYPE` or
`FEATURE_NAMES_BY_MERINO_PROVIDER`.
Since I added back the `provider` property, I had to update a lot of tests. (As
a follow up, it would be nice to centralize the creation of expected result
objects in the test helper.)
I also added `BaseFeature.getSuggestionTelemetryType()` to help implement the
score map and to better formalize the idea that telemetry types are an important
property that all quick suggest results should include.
Differential Revision: https://phabricator.services.mozilla.com/D181709
194 lines
6.4 KiB
JavaScript
194 lines
6.4 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/. */
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
|
|
UrlbarUtils: "resource:///modules/UrlbarUtils.sys.mjs",
|
|
});
|
|
|
|
/**
|
|
* Base class for quick suggest features. It can be extended to implement a
|
|
* feature that is part of the larger quick suggest feature and that should be
|
|
* enabled only when quick suggest is enabled.
|
|
*
|
|
* You can extend this class as an alternative to implementing your feature
|
|
* directly in `QuickSuggest`. Doing so has the following advantages:
|
|
*
|
|
* - If your feature is gated on a Nimbus variable or preference, `QuickSuggest`
|
|
* will manage its lifetime automatically. This is really only useful if the
|
|
* feature has state that must be initialized when the feature is enabled and
|
|
* uninitialized when it's disabled.
|
|
*
|
|
* - Encapsulation. You can keep all the code related to your feature in one
|
|
* place, without mixing it with unrelated code and cluttering up
|
|
* `QuickSuggest`. You can also test it in isolation from `QuickSuggest`.
|
|
*
|
|
* - Remote settings management. You can register your feature with
|
|
* `QuickSuggestRemoteSettings` and it will be called at appropriate times to
|
|
* sync from remote settings.
|
|
*
|
|
* - If your feature also serves suggestions from remote settings, you can
|
|
* implement one method, `queryRemoteSettings()`, to hook into
|
|
* `UrlbarProviderQuickSuggest`.
|
|
*
|
|
* - Your feature will automatically get its own logger.
|
|
*
|
|
* To register your subclass with `QuickSuggest`, add it to the `FEATURES` const
|
|
* in QuickSuggest.sys.mjs.
|
|
*/
|
|
export class BaseFeature {
|
|
/**
|
|
* {boolean}
|
|
* Whether the feature should be enabled. Typically the subclass will check
|
|
* the values of one or more Nimbus variables or preferences. `QuickSuggest`
|
|
* will access this getter only when the quick suggest feature as a whole is
|
|
* enabled. Otherwise the subclass feature will be disabled automatically.
|
|
*/
|
|
get shouldEnable() {
|
|
throw new Error("`shouldEnable` must be overridden");
|
|
}
|
|
|
|
/**
|
|
* @returns {Array}
|
|
* If the subclass's `shouldEnable` implementation depends on preferences
|
|
* instead of Nimbus variables, the subclass should override this getter and
|
|
* return their names in this array so that `enable()` can be called when
|
|
* they change. Names should be in the same format that `UrlbarPrefs.get()`
|
|
* expects.
|
|
*/
|
|
get enablingPreferences() {
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @returns {string}
|
|
* If the feature manages suggestions served by Merino, the subclass should
|
|
* override this getter and return the name of the specific Merino provider
|
|
* that serves them.
|
|
*/
|
|
get merinoProvider() {
|
|
return "";
|
|
}
|
|
|
|
/**
|
|
* This method should initialize or uninitialize any state related to the
|
|
* feature.
|
|
*
|
|
* @param {boolean} enabled
|
|
* Whether the feature should be enabled or not.
|
|
*/
|
|
enable(enabled) {}
|
|
|
|
/**
|
|
* If the feature manages suggestions from remote settings that should be
|
|
* returned by UrlbarProviderQuickSuggest, the subclass should override this
|
|
* method. It should return remote settings suggestions matching the given
|
|
* search string.
|
|
*
|
|
* @param {string} searchString
|
|
* The search string.
|
|
* @returns {Array}
|
|
* An array of matching suggestions, or null if not implemented.
|
|
*/
|
|
async queryRemoteSettings(searchString) {
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* If the feature manages data in remote settings, the subclass should
|
|
* override this method. It should fetch the data and build whatever data
|
|
* structures are necessary to support the feature.
|
|
*
|
|
* @param {RemoteSettings} rs
|
|
* The `RemoteSettings` client object.
|
|
*/
|
|
async onRemoteSettingsSync(rs) {}
|
|
|
|
/**
|
|
* If the feature manages suggestions that either aren't served by Merino or
|
|
* whose telemetry type is different from `merinoProvider`, the subclass
|
|
* should override this method. It should return the telemetry type for the
|
|
* given suggestion. A telemetry type uniquely identifies a type of suggestion
|
|
* as well as the kind of `UrlbarResult` instances created from it.
|
|
*
|
|
* @param {object} suggestion
|
|
* A suggestion from either remote settings or Merino.
|
|
* @returns {string}
|
|
* The suggestion's telemetry type.
|
|
*/
|
|
getSuggestionTelemetryType(suggestion) {
|
|
return this.merinoProvider;
|
|
}
|
|
|
|
/**
|
|
* If the feature corresponds to a type of suggestion, the subclass should
|
|
* override this method. It should return a new `UrlbarResult` for a given
|
|
* suggestion, which can come from either remote settings or Merino.
|
|
*
|
|
* @param {UrlbarQueryContext} queryContext
|
|
* The query context.
|
|
* @param {object} suggestion
|
|
* The suggestion from either remote settings or Merino.
|
|
* @param {string} searchString
|
|
* The search string that was used to fetch the suggestion. It may be
|
|
* different from `queryContext.searchString` due to trimming, lower-casing,
|
|
* etc. This is included as a param in case it's useful.
|
|
* @returns {UrlbarResult}
|
|
* A new result for the suggestion.
|
|
*/
|
|
async makeResult(queryContext, suggestion, searchString) {
|
|
return null;
|
|
}
|
|
|
|
// Methods not designed for overriding below
|
|
|
|
/**
|
|
* @returns {Logger}
|
|
* The feature's logger.
|
|
*/
|
|
get logger() {
|
|
if (!this._logger) {
|
|
this._logger = lazy.UrlbarUtils.getLogger({
|
|
prefix: `QuickSuggest.${this.name}`,
|
|
});
|
|
}
|
|
return this._logger;
|
|
}
|
|
|
|
/**
|
|
* @returns {boolean}
|
|
* Whether the feature is enabled. The enabled status is automatically
|
|
* managed by `QuickSuggest` and subclasses should not override this.
|
|
*/
|
|
get isEnabled() {
|
|
return this.#isEnabled;
|
|
}
|
|
|
|
/**
|
|
* @returns {string}
|
|
* The feature's name.
|
|
*/
|
|
get name() {
|
|
return this.constructor.name;
|
|
}
|
|
|
|
/**
|
|
* Enables or disables the feature according to `shouldEnable` and whether
|
|
* quick suggest is enabled. If the feature is already enabled appropriately,
|
|
* does nothing.
|
|
*/
|
|
update() {
|
|
let enable =
|
|
lazy.UrlbarPrefs.get("quickSuggestEnabled") && this.shouldEnable;
|
|
if (enable != this.isEnabled) {
|
|
this.logger.info(`Setting enabled = ${enable}`);
|
|
this.enable(enable);
|
|
this.#isEnabled = enable;
|
|
}
|
|
}
|
|
|
|
#isEnabled = false;
|
|
}
|