Bug 1824851 - Remove the legacy XUL-based migration dialog. r=kpatenio

This also gets rid of some Histograms and Scalars that only the legacy wizard was
using, and also gets rid of the "legacy_wizard" object for migration wizard events.

Differential Revision: https://phabricator.services.mozilla.com/D191227
This commit is contained in:
Mike Conley 2023-10-23 16:08:06 +00:00
Родитель b68697c09d
Коммит ab9f35e995
11 изменённых файлов: 66 добавлений и 1092 удалений

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

@ -59,7 +59,6 @@ browser/base/content/pageinfo/pageInfo.xhtml
browser/base/content/webext-panels.xhtml
browser/base/content/webrtcLegacyIndicator.xhtml
browser/components/downloads/content/contentAreaDownloadsView.xhtml
browser/components/migration/content/migration.xhtml
browser/components/places/content/bookmarkProperties.xhtml
browser/components/places/content/bookmarksSidebar.xhtml
browser/components/places/content/historySidebar.xhtml

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

@ -73,11 +73,6 @@ var gExceptionPaths = [
// CSS files are referenced inside JS in an html template
"chrome://browser/content/aboutlogins/components/",
// These files are for the old migration wizard which will be removed
// shortly.
"chrome://browser/content/migration/migration.xhtml",
"chrome://browser/content/migration/migration.js",
];
// These are not part of the omni.ja file, so we find them only when running

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

@ -675,8 +675,6 @@ class MigrationUtils {
* source-selection page will be displayed, either with the default
* browser selected, if it could be detected and if there is a
* migrator for it, or with the first option selected as a fallback
* (The first option is hardcoded to be the most common browser for
* the OS we run on. See migration.xhtml).
* @param {string|null} [aProfileToMigrate=null]
* If set, the migration wizard will import from the profile indicated.
* @throws
@ -1071,12 +1069,12 @@ class MigrationUtils {
* Enum for the entrypoint that is being used to start migration.
* Callers can use the MIGRATION_ENTRYPOINTS getter to use these.
*
* These values are what's written into the FX_MIGRATION_ENTRY_POINT
* histogram after a migration.
* These values are what's written into the
* FX_MIGRATION_ENTRY_POINT_CATEGORICAL histogram after a migration.
*
* @see MIGRATION_ENTRYPOINTS
* @readonly
* @enum {number}
* @enum {string}
*/
#MIGRATION_ENTRYPOINTS_ENUM = Object.freeze({
/** The entrypoint was not supplied */
@ -1124,54 +1122,8 @@ class MigrationUtils {
}
/**
* Translates an entrypoint string into the proper numeric value for the legacy
* FX_MIGRATION_ENTRY_POINT histogram.
*
* @param {string} entrypoint
* The entrypoint to translate from MIGRATION_ENTRYPOINTS.
* @returns {number}
* The numeric value for the legacy FX_MIGRATION_ENTRY_POINT histogram.
*/
getLegacyMigrationEntrypoint(entrypoint) {
switch (entrypoint) {
case this.MIGRATION_ENTRYPOINTS.FIRSTRUN: {
return 1;
}
case this.MIGRATION_ENTRYPOINTS.FXREFRESH: {
return 2;
}
case this.MIGRATION_ENTRYPOINTS.PLACES: {
return 3;
}
case this.MIGRATION_ENTRYPOINTS.PASSWORDS: {
return 4;
}
case this.MIGRATION_ENTRYPOINTS.NEWTAB: {
return 5;
}
case this.MIGRATION_ENTRYPOINTS.FILE_MENU: {
return 6;
}
case this.MIGRATION_ENTRYPOINTS.HELP_MENU: {
return 7;
}
case this.MIGRATION_ENTRYPOINTS.BOOKMARKS_TOOLBAR: {
return 8;
}
case this.MIGRATION_ENTRYPOINTS.PREFERENCES: {
return 9;
}
case this.MIGRATION_ENTRYPOINTS.UNKNOWN:
// Intentional fall-through
default: {
return 0; // Unknown
}
}
}
/**
* Enum for the numeric value written to the FX_MIGRATION_SOURCE_BROWSER,
* and FX_STARTUP_MIGRATION_EXISTING_DEFAULT_BROWSER histograms.
* Enum for the numeric value written to the FX_MIGRATION_SOURCE_BROWSER.
* histogram
*
* @see getSourceIdForTelemetry
* @readonly

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

@ -1,832 +0,0 @@
/* 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 { AppConstants } = ChromeUtils.importESModule(
"resource://gre/modules/AppConstants.sys.mjs"
);
const { MigrationUtils } = ChromeUtils.importESModule(
"resource:///modules/MigrationUtils.sys.mjs"
);
const { MigratorBase } = ChromeUtils.importESModule(
"resource:///modules/MigratorBase.sys.mjs"
);
/**
* Map from data types that match Ci.nsIBrowserProfileMigrator's types to
* prefixes for strings used to label these data types in the migration
* dialog. We use these strings with -checkbox and -label suffixes for the
* checkboxes on the "importItems" page, and for the labels on the "migrating"
* and "done" pages, respectively.
*/
const kDataToStringMap = new Map([
["cookies", "browser-data-cookies"],
["history", "browser-data-history"],
["formdata", "browser-data-formdata"],
["passwords", "browser-data-passwords"],
["bookmarks", "browser-data-bookmarks"],
["otherdata", "browser-data-otherdata"],
["session", "browser-data-session"],
["payment_methods", "browser-data-payment-methods"],
]);
var MigrationWizard = {
/* exported MigrationWizard */
_source: "", // Source Profile Migrator ContractID suffix
_itemsFlags: MigrationUtils.resourceTypes.ALL, // Selected Import Data Sources (16-bit bitfield)
_selectedProfile: null, // Selected Profile name to import from
_wiz: null,
_migrator: null,
_autoMigrate: null,
_receivedPermissions: new Set(),
_succeededMigrationEventArgs: null,
_openedTime: null,
init() {
Services.telemetry.setEventRecordingEnabled("browser.migration", true);
let os = Services.obs;
os.addObserver(this, "Migration:Started");
os.addObserver(this, "Migration:ItemBeforeMigrate");
os.addObserver(this, "Migration:ItemAfterMigrate");
os.addObserver(this, "Migration:ItemError");
os.addObserver(this, "Migration:Ended");
this._wiz = document.querySelector("wizard");
let args = window.arguments[0]?.wrappedJSObject || {};
let entrypoint =
args.entrypoint || MigrationUtils.MIGRATION_ENTRYPOINTS.UNKNOWN;
Services.telemetry
.getHistogramById("FX_MIGRATION_ENTRY_POINT_CATEGORICAL")
.add(entrypoint);
// The legacy entrypoint Histogram wasn't categorical, so we translate to the right
// numeric value before writing it. We'll keep this Histogram around to ensure a
// smooth transition to the new FX_MIGRATION_ENTRY_POINT_CATEGORICAL categorical
// histogram.
let entryPointId = MigrationUtils.getLegacyMigrationEntrypoint(entrypoint);
Services.telemetry
.getHistogramById("FX_MIGRATION_ENTRY_POINT")
.add(entryPointId);
// If the caller passed openedTime, that means this is the first time that
// the migration wizard is opening, and we want to measure its performance.
// Stash the time that opening was invoked so that we can measure the
// total elapsed time when the source list is shown.
if (args.openedTime) {
this._openedTime = args.openedTime;
}
this.isInitialMigration =
entrypoint == MigrationUtils.MIGRATION_ENTRYPOINTS.FIRSTRUN;
// Record that the uninstaller requested a profile refresh
if (Services.env.get("MOZ_UNINSTALLER_PROFILE_REFRESH")) {
Services.env.set("MOZ_UNINSTALLER_PROFILE_REFRESH", "");
Services.telemetry.scalarSet(
"migration.uninstaller_profile_refresh",
true
);
}
this._source = args.migratorKey;
this._migrator =
args.migrator instanceof MigratorBase ? args.migrator : null;
this._autoMigrate = !!args.isStartupMigration;
this._skipImportSourcePage = !!args.skipSourceSelection;
if (this._migrator && args.profileId) {
let sourceProfiles = this.spinResolve(this._migrator.getSourceProfiles());
this._selectedProfile = sourceProfiles.find(
profile => profile.id == args.profileId
);
}
if (this._autoMigrate) {
// Show the "nothing" option in the automigrate case to provide an
// easily identifiable way to avoid migration and create a new profile.
document.getElementById("nothing").hidden = false;
}
this._setSourceForDataLocalization();
document.addEventListener("wizardcancel", function () {
MigrationWizard.onWizardCancel();
});
document
.getElementById("selectProfile")
.addEventListener("pageshow", function () {
MigrationWizard.onSelectProfilePageShow();
});
document
.getElementById("importItems")
.addEventListener("pageshow", function () {
MigrationWizard.onImportItemsPageShow();
});
document
.getElementById("migrating")
.addEventListener("pageshow", function () {
MigrationWizard.onMigratingPageShow();
});
document.getElementById("done").addEventListener("pageshow", function () {
MigrationWizard.onDonePageShow();
});
document
.getElementById("selectProfile")
.addEventListener("pagerewound", function () {
MigrationWizard.onSelectProfilePageRewound();
});
document
.getElementById("importItems")
.addEventListener("pagerewound", function () {
MigrationWizard.onImportItemsPageRewound();
});
document
.getElementById("selectProfile")
.addEventListener("pageadvanced", function () {
MigrationWizard.onSelectProfilePageAdvanced();
});
document
.getElementById("importItems")
.addEventListener("pageadvanced", function () {
MigrationWizard.onImportItemsPageAdvanced();
});
document
.getElementById("importPermissions")
.addEventListener("pageadvanced", function (e) {
MigrationWizard.onImportPermissionsPageAdvanced(e);
});
document
.getElementById("importSource")
.addEventListener("pageadvanced", function (e) {
MigrationWizard.onImportSourcePageAdvanced(e);
});
this.recordEvent("opened");
this.onImportSourcePageShow();
},
uninit() {
var os = Services.obs;
os.removeObserver(this, "Migration:Started");
os.removeObserver(this, "Migration:ItemBeforeMigrate");
os.removeObserver(this, "Migration:ItemAfterMigrate");
os.removeObserver(this, "Migration:ItemError");
os.removeObserver(this, "Migration:Ended");
os.notifyObservers(this, "MigrationWizard:Destroyed");
MigrationUtils.finishMigration();
},
/**
* Used for recording telemetry in the migration wizard.
*
* @param {string} type
* The type of event being recorded.
* @param {object} args
* The data to pass to telemetry when the event is recorded.
*/
recordEvent(type, args = null) {
Services.telemetry.recordEvent(
"browser.migration",
type,
"legacy_wizard",
null,
args
);
},
spinResolve(promise) {
let canAdvance = this._wiz.canAdvance;
let canRewind = this._wiz.canRewind;
this._wiz.canAdvance = false;
this._wiz.canRewind = false;
let result = MigrationUtils.spinResolve(promise);
this._wiz.canAdvance = canAdvance;
this._wiz.canRewind = canRewind;
return result;
},
_setSourceForDataLocalization() {
this._sourceForDataLocalization = this._source;
// Ensure consistency for various channels, brandings and versions of
// Chromium and MS Edge.
if (this._sourceForDataLocalization) {
this._sourceForDataLocalization = this._sourceForDataLocalization
.replace(/^(chromium-edge-beta|chromium-edge)$/, "edge")
.replace(/^(canary|chromium|chrome-beta|chrome-dev)$/, "chrome");
}
},
onWizardCancel() {
MigrationUtils.forceExitSpinResolve();
return true;
},
// 1 - Import Source
onImportSourcePageShow() {
this._wiz.canRewind = false;
var selectedMigrator = null;
this._availableMigrators = [];
// Figure out what source apps are are available to import from:
var group = document.getElementById("importSourceGroup");
for (var i = 0; i < group.childNodes.length; ++i) {
var migratorKey = group.childNodes[i].id;
if (migratorKey != "nothing") {
var migrator = this.spinResolve(
MigrationUtils.getMigrator(migratorKey)
);
if (migrator?.enabled) {
// Save this as the first selectable item, if we don't already have
// one, or if it is the migrator that was passed to us.
if (!selectedMigrator || this._source == migratorKey) {
selectedMigrator = group.childNodes[i];
}
let profiles = this.spinResolve(migrator.getSourceProfiles());
if (profiles?.length) {
Services.telemetry.keyedScalarAdd(
"migration.discovered_migrators",
migratorKey,
profiles.length
);
} else {
Services.telemetry.keyedScalarAdd(
"migration.discovered_migrators",
migratorKey,
1
);
}
this._availableMigrators.push([migratorKey, migrator]);
} else {
// Hide this option
group.childNodes[i].hidden = true;
}
}
}
if (this.isInitialMigration) {
Services.telemetry
.getHistogramById("FX_STARTUP_MIGRATION_BROWSER_COUNT")
.add(this._availableMigrators.length);
let defaultBrowser = MigrationUtils.getMigratorKeyForDefaultBrowser();
// This will record 0 for unknown default browser IDs.
defaultBrowser = MigrationUtils.getSourceIdForTelemetry(defaultBrowser);
Services.telemetry
.getHistogramById("FX_STARTUP_MIGRATION_EXISTING_DEFAULT_BROWSER")
.add(defaultBrowser);
}
if (selectedMigrator) {
group.selectedItem = selectedMigrator;
} else {
this.recordEvent("no_browsers_found");
// We didn't find a migrator, notify the user
document.getElementById("noSources").hidden = false;
this._wiz.canAdvance = false;
document.getElementById("importAll").hidden = true;
}
// This must be the first time we're opening the migration wizard,
// and we want to know how long it took to get to this point, where
// we're showing the source list.
if (this._openedTime !== null) {
let elapsed = Cu.now() - this._openedTime;
Services.telemetry.scalarSet(
"migration.time_to_produce_legacy_migrator_list",
elapsed
);
}
// Advance to the next page if the caller told us to.
if (this._migrator && this._skipImportSourcePage) {
this._wiz.advance();
this._wiz.canRewind = false;
}
},
onImportSourcePageAdvanced(event) {
var newSource =
document.getElementById("importSourceGroup").selectedItem.id;
this.recordEvent("browser_selected", { migrator_key: newSource });
if (newSource == "nothing") {
// Need to do telemetry here because we're closing the dialog before we get to
// do actual migration. For actual migration, this doesn't happen until after
// migration takes place.
Services.telemetry
.getHistogramById("FX_MIGRATION_SOURCE_BROWSER")
.add(MigrationUtils.getSourceIdForTelemetry("nothing"));
this._wiz.cancel();
event.preventDefault();
}
if (!this._migrator || newSource != this._source) {
// Create the migrator for the selected source.
this._migrator = this.spinResolve(MigrationUtils.getMigrator(newSource));
this._itemsFlags = MigrationUtils.resourceTypes.ALL;
this._selectedProfile = null;
}
this._source = newSource;
this._setSourceForDataLocalization();
// check for more than one source profile
var sourceProfiles = this.spinResolve(this._migrator.getSourceProfiles());
if (this._skipImportSourcePage) {
this._updateNextPageForPermissions();
} else if (sourceProfiles && sourceProfiles.length > 1) {
this._wiz.currentPage.next = "selectProfile";
} else {
if (this._autoMigrate) {
this._updateNextPageForPermissions();
} else {
this._wiz.currentPage.next = "importItems";
}
if (sourceProfiles && sourceProfiles.length == 1) {
this._selectedProfile = sourceProfiles[0];
} else {
this._selectedProfile = null;
}
}
},
// 2 - [Profile Selection]
onSelectProfilePageShow() {
// Disabling this for now, since we ask about import sources in automigration
// too and don't want to disable the back button
// if (this._autoMigrate)
// document.documentElement.getButton("back").disabled = true;
var profiles = document.getElementById("profiles");
while (profiles.hasChildNodes()) {
profiles.firstChild.remove();
}
// Note that this block is still reached even if the user chose 'From File'
// and we canceled the dialog. When that happens, _migrator will be null.
if (this._migrator) {
var sourceProfiles = this.spinResolve(this._migrator.getSourceProfiles());
for (let profile of sourceProfiles) {
var item = document.createXULElement("radio");
item.id = profile.id;
item.setAttribute("label", profile.name);
profiles.appendChild(item);
}
}
profiles.selectedItem = this._selectedProfile
? document.getElementById(this._selectedProfile.id)
: profiles.firstChild;
},
onSelectProfilePageRewound() {
var profiles = document.getElementById("profiles");
let sourceProfiles = this.spinResolve(this._migrator.getSourceProfiles());
this._selectedProfile =
sourceProfiles.find(profile => profile.id == profiles.selectedItem.id) ||
null;
},
onSelectProfilePageAdvanced() {
this.recordEvent("profile_selected", {
migrator_key: this._source,
});
var profiles = document.getElementById("profiles");
let sourceProfiles = this.spinResolve(this._migrator.getSourceProfiles());
this._selectedProfile =
sourceProfiles.find(profile => profile.id == profiles.selectedItem.id) ||
null;
// If we're automigrating or just doing bookmarks don't show the item selection page
if (this._autoMigrate) {
this._updateNextPageForPermissions();
}
},
// 3 - ImportItems
onImportItemsPageShow() {
var dataSources = document.getElementById("dataSources");
while (dataSources.hasChildNodes()) {
dataSources.firstChild.remove();
}
var items = this.spinResolve(
this._migrator.getMigrateData(this._selectedProfile)
);
for (let itemType of kDataToStringMap.keys()) {
let itemValue = MigrationUtils.resourceTypes[itemType.toUpperCase()];
if (items & itemValue) {
let checkbox = document.createXULElement("checkbox");
checkbox.id = itemValue;
checkbox.setAttribute("native", true);
document.l10n.setAttributes(
checkbox,
kDataToStringMap.get(itemType) + "-checkbox",
{ browser: this._sourceForDataLocalization }
);
dataSources.appendChild(checkbox);
if (!this._itemsFlags || this._itemsFlags & itemValue) {
checkbox.checked = true;
}
}
}
},
onImportItemsPageRewound() {
this._wiz.canAdvance = true;
this.onImportItemsPageAdvanced(true /* viaRewind */);
},
onImportItemsPageAdvanced(viaRewind = false) {
let extraKeys = {
migrator_key: this._source,
history: "0",
formdata: "0",
passwords: "0",
bookmarks: "0",
payment_methods: "0",
// "other" will get incremented, so we keep this as a number for
// now, and will cast to a string before submitting to Event telemetry.
other: 0,
configured: "0",
};
var dataSources = document.getElementById("dataSources");
this._itemsFlags = 0;
for (var i = 0; i < dataSources.childNodes.length; ++i) {
var checkbox = dataSources.childNodes[i];
if (checkbox.localName == "checkbox" && checkbox.checked) {
let flag = parseInt(checkbox.id);
switch (flag) {
case MigrationUtils.resourceTypes.HISTORY:
extraKeys.history = "1";
break;
case MigrationUtils.resourceTypes.FORMDATA:
extraKeys.formdata = "1";
break;
case MigrationUtils.resourceTypes.PASSWORDS:
extraKeys.passwords = "1";
break;
case MigrationUtils.resourceTypes.BOOKMARKS:
extraKeys.bookmarks = "1";
break;
case MigrationUtils.resourceTypes.PAYMENT_METHODS:
extraKeys.payment_methods = "1";
break;
default:
extraKeys.other++;
}
this._itemsFlags |= parseInt(checkbox.id);
}
}
extraKeys.other = String(extraKeys.other);
if (!viaRewind) {
this.recordEvent("resources_selected", extraKeys);
}
this._updateNextPageForPermissions();
},
onImportItemCommand() {
var items = document.getElementById("dataSources");
var checkboxes = items.getElementsByTagName("checkbox");
var oneChecked = false;
for (var i = 0; i < checkboxes.length; ++i) {
if (checkboxes[i].checked) {
oneChecked = true;
break;
}
}
this._wiz.canAdvance = oneChecked;
this._updateNextPageForPermissions();
},
_updateNextPageForPermissions() {
// We would like to just go straight to work:
this._wiz.currentPage.next = "migrating";
// If we already have permissions, this is easy:
if (this._receivedPermissions.has(this._source)) {
return;
}
// Otherwise, if we're on mojave or later and importing from
// Safari, prompt for the bookmarks file.
// We may add other browser/OS combos here in future.
if (
this._source == "safari" &&
AppConstants.isPlatformAndVersionAtLeast("macosx", "18") &&
(this._itemsFlags & MigrationUtils.resourceTypes.BOOKMARKS ||
this._itemsFlags == MigrationUtils.resourceTypes.ALL)
) {
let havePermissions = this.spinResolve(this._migrator.hasPermissions());
if (!havePermissions) {
this._wiz.currentPage.next = "importPermissions";
this.recordEvent("safari_perms");
}
}
},
// 3b: permissions. This gets invoked when the user clicks "Next"
async onImportPermissionsPageAdvanced(event) {
// We're done if we have permission:
if (this._receivedPermissions.has(this._source)) {
return;
}
// The wizard helper is sync, and we need to check some stuff, so just stop
// advancing for now and prompt the user, then advance the wizard if everything
// worked.
event.preventDefault();
await this._migrator.getPermissions(window);
if (await this._migrator.hasPermissions()) {
this._receivedPermissions.add(this._source);
// Re-enter (we'll then allow the advancement through the early return above)
this._wiz.advance();
}
// if we didn't have permissions after the `getPermissions` call, the user
// cancelled the dialog. Just no-op out now; the user can re-try by clicking
// the 'Continue' button again, or go back and pick a different browser.
},
// 4 - Migrating
onMigratingPageShow() {
this._wiz.getButton("cancel").disabled = true;
this._wiz.canRewind = false;
this._wiz.canAdvance = false;
// When automigrating, show all of the data that can be received from this source.
if (this._autoMigrate) {
this._itemsFlags = this.spinResolve(
this._migrator.getMigrateData(this._selectedProfile)
);
}
this._listItems("migratingItems");
setTimeout(() => this.onMigratingMigrate(), 0);
},
async onMigratingMigrate() {
await this._migrator.migrate(
this._itemsFlags,
this._autoMigrate,
this._selectedProfile
);
Services.telemetry
.getHistogramById("FX_MIGRATION_SOURCE_BROWSER")
.add(MigrationUtils.getSourceIdForTelemetry(this._source));
if (!this._autoMigrate) {
let hist = Services.telemetry.getKeyedHistogramById("FX_MIGRATION_USAGE");
let exp = 0;
let items = this._itemsFlags;
while (items) {
if (items & 1) {
hist.add(this._source, exp);
}
items = items >> 1;
exp++;
}
}
},
_listItems(aID) {
var items = document.getElementById(aID);
while (items.hasChildNodes()) {
items.firstChild.remove();
}
for (let itemType of kDataToStringMap.keys()) {
let itemValue = MigrationUtils.resourceTypes[itemType.toUpperCase()];
if (this._itemsFlags & itemValue) {
var label = document.createXULElement("label");
label.id = itemValue + "_migrated";
try {
document.l10n.setAttributes(
label,
kDataToStringMap.get(itemType) + "-label",
{ browser: this._sourceForDataLocalization }
);
items.appendChild(label);
} catch (e) {
// if the block above throws, we've enumerated all the import data types we
// currently support and are now just wasting time, break.
break;
}
}
}
},
recordResourceMigration(obj, resourceType) {
// Sometimes, the resourceType that gets passed here is a string, which
// is bizarre. We'll hold our nose and accept either a string or a
// number.
resourceType = parseInt(resourceType, 10);
switch (resourceType) {
case MigrationUtils.resourceTypes.HISTORY:
obj.history = "1";
break;
case MigrationUtils.resourceTypes.FORMDATA:
obj.formdata = "1";
break;
case MigrationUtils.resourceTypes.PASSWORDS:
obj.passwords = "1";
break;
case MigrationUtils.resourceTypes.BOOKMARKS:
obj.bookmarks = "1";
break;
case MigrationUtils.resourceTypes.PAYMENT_METHODS:
obj.payment_methods = "1";
break;
default:
obj.other++;
}
},
recordMigrationStartEvent(resourceFlags) {
let extraKeys = {
migrator_key: this._source,
history: "0",
formdata: "0",
passwords: "0",
bookmarks: "0",
payment_methods: "0",
// "other" will get incremented, so we keep this as a number for
// now, and will cast to a string before submitting to Event telemetry.
other: 0,
};
for (let resourceTypeKey in MigrationUtils.resourceTypes) {
let resourceType = MigrationUtils.resourceTypes[resourceTypeKey];
if (resourceFlags & resourceType) {
this.recordResourceMigration(extraKeys, resourceType);
}
}
extraKeys.other = String(extraKeys.other);
this.recordEvent("migration_started", extraKeys);
},
observe(aSubject, aTopic, aData) {
var label;
switch (aTopic) {
case "Migration:Started":
this._succeededMigrationEventArgs = {
migrator_key: this._source,
history: "0",
formdata: "0",
passwords: "0",
bookmarks: "0",
payment_methods: "0",
// "other" will get incremented, so we keep this as a number for
// now, and will cast to a string before submitting to Event telemetry.
other: 0,
};
this.recordMigrationStartEvent(this._itemsFlags);
break;
case "Migration:ItemBeforeMigrate":
label = document.getElementById(aData + "_migrated");
if (label) {
label.setAttribute("style", "font-weight: bold");
}
break;
case "Migration:ItemAfterMigrate":
this.recordResourceMigration(this._succeededMigrationEventArgs, aData);
label = document.getElementById(aData + "_migrated");
if (label) {
label.removeAttribute("style");
}
break;
case "Migration:Ended":
this._succeededMigrationEventArgs.other = String(
this._succeededMigrationEventArgs.other
);
this.recordEvent(
"migration_finished",
this._succeededMigrationEventArgs
);
if (this.isInitialMigration) {
// Ensure errors in reporting data recency do not affect the rest of the migration.
try {
this.reportDataRecencyTelemetry();
} catch (ex) {
console.error(ex);
}
}
if (this._autoMigrate) {
// We're done now.
this._wiz.canAdvance = true;
this._wiz.advance();
setTimeout(close, 5000);
} else {
this._wiz.canAdvance = true;
var nextButton = this._wiz.getButton("next");
nextButton.click();
}
break;
case "Migration:ItemError":
let type = "undefined";
let numericType = parseInt(aData);
switch (numericType) {
case MigrationUtils.resourceTypes.COOKIES:
type = "cookies";
break;
case MigrationUtils.resourceTypes.HISTORY:
type = "history";
break;
case MigrationUtils.resourceTypes.FORMDATA:
type = "form data";
break;
case MigrationUtils.resourceTypes.PASSWORDS:
type = "passwords";
break;
case MigrationUtils.resourceTypes.BOOKMARKS:
type = "bookmarks";
break;
case MigrationUtils.resourceTypes.PAYMENT_METHODS:
type = "payment methods";
break;
case MigrationUtils.resourceTypes.OTHERDATA:
type = "misc. data";
break;
}
Services.console.logStringMessage(
"some " + type + " did not successfully migrate."
);
Services.telemetry
.getKeyedHistogramById("FX_MIGRATION_ERRORS")
.add(this._source, Math.log2(numericType));
break;
}
},
onDonePageShow() {
this._wiz.getButton("cancel").disabled = true;
this._wiz.canRewind = false;
this._listItems("doneItems");
},
reportDataRecencyTelemetry() {
let histogram = Services.telemetry.getKeyedHistogramById(
"FX_STARTUP_MIGRATION_DATA_RECENCY"
);
let lastUsedPromises = [];
for (let [key, migrator] of this._availableMigrators) {
// No block-scoped let in for...of loop conditions, so get the source:
let localKey = key;
lastUsedPromises.push(
migrator.getLastUsedDate().then(date => {
const ONE_YEAR = 24 * 365;
let diffInHours = Math.round((Date.now() - date) / (60 * 60 * 1000));
if (diffInHours > ONE_YEAR) {
diffInHours = ONE_YEAR;
}
histogram.add(localKey, diffInHours);
return [localKey, diffInHours];
})
);
}
Promise.all(lastUsedPromises).then(migratorUsedTimeDiff => {
// Sort low to high.
migratorUsedTimeDiff.sort(
([keyA, diffA], [keyB, diffB]) => diffA - diffB
); /* eslint no-unused-vars: off */
let usedMostRecentBrowser =
migratorUsedTimeDiff.length &&
this._source == migratorUsedTimeDiff[0][0];
let usedRecentBrowser = Services.telemetry.getKeyedHistogramById(
"FX_STARTUP_MIGRATION_USED_RECENT_BROWSER"
);
usedRecentBrowser.add(this._source, usedMostRecentBrowser);
});
},
};

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

@ -1,113 +0,0 @@
<?xml version="1.0"?>
# 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/.
<window id="migrationWizard"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
data-l10n-id="migration-wizard"
windowtype="Browser:MigrationWizard"
onload="MigrationWizard.init()"
onunload="MigrationWizard.uninit()"
style="min-width: 40em;"
buttons="accept,cancel">
<linkset>
<html:link rel="stylesheet" href="chrome://global/skin/global.css" />
<html:link rel="localization" href="branding/brand.ftl"/>
<html:link rel="localization" href="toolkit/global/wizard.ftl"/>
<html:link rel="localization" href="browser/migration.ftl"/>
</linkset>
<script src="chrome://global/content/customElements.js"/>
<script src="chrome://browser/content/migration/migration.js"/>
<wizard data-branded="true">
<wizardpage id="importSource" pageid="importSource" next="selectProfile"
data-header-label-id="import-source-page-title">
<description id="importAll" control="importSourceGroup" data-l10n-id="import-from"></description>
<description id="importBookmarks" control="importSourceGroup" data-l10n-id="import-from-bookmarks" hidden="true" ></description>
<radiogroup id="importSourceGroup" align="start">
# NB: if you add items to this list, please also assign them a unique migrator ID in MigrationUtils.jsm
<radio id="firefox" data-l10n-id="import-from-firefox"/>
#ifdef XP_WIN
<radio id="chromium-edge" data-l10n-id="import-from-edge"/>
<radio id="edge" data-l10n-id="import-from-edge-legacy" />
<radio id="chromium-edge-beta" data-l10n-id="import-from-edge-beta"/>
<radio id="ie" data-l10n-id="import-from-ie"/>
<radio id="opera" data-l10n-id="import-from-opera"/>
<radio id="brave" data-l10n-id="import-from-brave"/>
<radio id="chrome" data-l10n-id="import-from-chrome"/>
<radio id="chrome-beta" data-l10n-id="import-from-chrome-beta"/>
<radio id="chromium" data-l10n-id="import-from-chromium"/>
<radio id="canary" data-l10n-id="import-from-canary" />
<radio id="vivaldi" data-l10n-id="import-from-vivaldi"/>
<radio id="chromium-360se" data-l10n-id="import-from-360se"/>
<radio id="opera-gx" data-l10n-id="import-from-opera-gx"/>
#elifdef XP_MACOSX
<radio id="safari" data-l10n-id="import-from-safari"/>
<radio id="opera" data-l10n-id="import-from-opera"/>
<radio id="brave" data-l10n-id="import-from-brave"/>
<radio id="chrome" data-l10n-id="import-from-chrome"/>
<radio id="chromium-edge" data-l10n-id="import-from-edge"/>
<radio id="chromium-edge-beta" data-l10n-id="import-from-edge-beta"/>
<radio id="chromium" data-l10n-id="import-from-chromium"/>
<radio id="canary" data-l10n-id="import-from-canary"/>
<radio id="vivaldi" data-l10n-id="import-from-vivaldi"/>
<radio id="opera-gx" data-l10n-id="import-from-opera-gx"/>
#elifdef XP_UNIX
<radio id="opera" data-l10n-id="import-from-opera"/>
<radio id="vivaldi" data-l10n-id="import-from-vivaldi"/>
<radio id="brave" data-l10n-id="import-from-brave"/>
<radio id="chrome" data-l10n-id="import-from-chrome"/>
<radio id="chrome-beta" data-l10n-id="import-from-chrome-beta"/>
<radio id="chrome-dev" data-l10n-id="import-from-chrome-dev"/>
<radio id="chromium" data-l10n-id="import-from-chromium"/>
#endif
<radio id="nothing" data-l10n-id="import-from-nothing" hidden="true"/>
</radiogroup>
<label id="noSources" hidden="true" data-l10n-id="no-migration-sources"></label>
</wizardpage>
<wizardpage id="selectProfile" pageid="selectProfile"
data-header-label-id="import-select-profile-page-title"
next="importItems">
<description control="profiles" data-l10n-id="import-select-profile-description"></description>
<radiogroup id="profiles" align="start"/>
</wizardpage>
<wizardpage id="importItems" pageid="importItems"
data-header-label-id="import-items-page-title"
next="migrating"
oncommand="MigrationWizard.onImportItemCommand();">
<description control="dataSources" data-l10n-id="import-items-description"></description>
<vbox id="dataSources" style="overflow: auto; appearance: auto; -moz-default-appearance: listbox" align="start" flex="1" role="group"/>
</wizardpage>
<wizardpage id="importPermissions" pageid="importPermissions"
data-header-label-id="import-permissions-page-title"
next="migrating">
<description data-l10n-id="import-safari-permissions-string"></description>
</wizardpage>
<wizardpage id="migrating" pageid="migrating"
data-header-label-id="import-migrating-page-title"
next="done">
<description control="migratingItems" data-l10n-id="import-migrating-description"></description>
<vbox id="migratingItems" style="overflow: auto;" align="start" role="group"/>
</wizardpage>
<wizardpage id="done" pageid="done"
data-header-label-id="import-done-page-title">
<description control="doneItems" data-l10n-id="import-done-description"></description>
<vbox id="doneItems" style="overflow: auto;" align="start" role="group"/>
</wizardpage>
</wizard>
</window>

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

@ -3,8 +3,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
* content/browser/migration/migration.xhtml (content/migration.xhtml)
content/browser/migration/migration.js (content/migration.js)
content/browser/aboutWelcomeBack.xhtml (content/aboutWelcomeBack.xhtml)
content/browser/migration/migration-dialog-window.html (content/migration-dialog-window.html)
content/browser/migration/migration-dialog-window.js (content/migration-dialog-window.js)

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

@ -41,11 +41,11 @@ add_task(async function test_entrypoints() {
await showThenCloseMigrationWizardViaEntrypoint(
MigrationUtils.MIGRATION_ENTRYPOINTS.BOOKMARKS
);
let entrypointId = MigrationUtils.getLegacyMigrationEntrypoint(
let entrypointIndex = getEntrypointHistogramIndex(
MigrationUtils.MIGRATION_ENTRYPOINTS.BOOKMARKS
);
TelemetryTestUtils.assertHistogram(histogram, entrypointId, 1);
TelemetryTestUtils.assertHistogram(histogram, entrypointIndex, 1);
histogram = TelemetryTestUtils.getAndClearHistogram(HISTOGRAM_ID);
@ -54,19 +54,19 @@ add_task(async function test_entrypoints() {
await showThenCloseMigrationWizardViaEntrypoint(
MigrationUtils.MIGRATION_ENTRYPOINTS.PREFERENCES
);
entrypointId = MigrationUtils.getLegacyMigrationEntrypoint(
entrypointIndex = getEntrypointHistogramIndex(
MigrationUtils.MIGRATION_ENTRYPOINTS.PREFERENCES
);
TelemetryTestUtils.assertHistogram(histogram, entrypointId, 1);
TelemetryTestUtils.assertHistogram(histogram, entrypointIndex, 1);
histogram = TelemetryTestUtils.getAndClearHistogram(HISTOGRAM_ID);
// Finally, check the fallback by passing in something invalid as an entrypoint.
await showThenCloseMigrationWizardViaEntrypoint(undefined);
entrypointId = MigrationUtils.getLegacyMigrationEntrypoint(
entrypointIndex = getEntrypointHistogramIndex(
MigrationUtils.MIGRATION_ENTRYPOINTS.UNKNOWN
);
TelemetryTestUtils.assertHistogram(histogram, entrypointId, 1);
TelemetryTestUtils.assertHistogram(histogram, entrypointIndex, 1);
});

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

@ -485,3 +485,50 @@ function assertQuantitiesShown(
}
}
}
/**
* Translates an entrypoint string into the proper numeric value for the
* FX_MIGRATION_ENTRY_POINT_CATEGORICAL histogram.
*
* @param {string} entrypoint
* The entrypoint to translate from MIGRATION_ENTRYPOINTS.
* @returns {number}
* The numeric index value for the FX_MIGRATION_ENTRY_POINT_CATEGORICAL
* histogram.
*/
function getEntrypointHistogramIndex(entrypoint) {
switch (entrypoint) {
case MigrationUtils.MIGRATION_ENTRYPOINTS.FIRSTRUN: {
return 1;
}
case MigrationUtils.MIGRATION_ENTRYPOINTS.FXREFRESH: {
return 2;
}
case MigrationUtils.MIGRATION_ENTRYPOINTS.PLACES: {
return 3;
}
case MigrationUtils.MIGRATION_ENTRYPOINTS.PASSWORDS: {
return 4;
}
case MigrationUtils.MIGRATION_ENTRYPOINTS.NEWTAB: {
return 5;
}
case MigrationUtils.MIGRATION_ENTRYPOINTS.FILE_MENU: {
return 6;
}
case MigrationUtils.MIGRATION_ENTRYPOINTS.HELP_MENU: {
return 7;
}
case MigrationUtils.MIGRATION_ENTRYPOINTS.BOOKMARKS_TOOLBAR: {
return 8;
}
case MigrationUtils.MIGRATION_ENTRYPOINTS.PREFERENCES: {
return 9;
}
case MigrationUtils.MIGRATION_ENTRYPOINTS.UNKNOWN:
// Intentional fall-through
default: {
return 0; // Unknown
}
}
}

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

@ -1008,7 +1008,7 @@ browser.launched_to_handle:
browser.migration:
opened:
objects: ["legacy_wizard", "wizard"]
objects: ["wizard"]
description: >
Recorded when the migration wizard opens.
bug_numbers:
@ -1021,7 +1021,7 @@ browser.migration:
release_channel_collection: opt-out
expiry_version: never
no_browsers_found:
objects: ["legacy_wizard", "wizard"]
objects: ["wizard"]
description: >
Recorded when the migration wizard reports that there are no browsers to migrate from.
bug_numbers:
@ -1034,7 +1034,7 @@ browser.migration:
release_channel_collection: opt-out
expiry_version: never
browser_selected:
objects: ["legacy_wizard", "wizard"]
objects: ["wizard"]
description: >
Recorded when the user selects a browser to migrate from.
bug_numbers:
@ -1049,7 +1049,7 @@ browser.migration:
extra_keys:
migrator_key: The key of the browser that was selected.
profile_selected:
objects: ["legacy_wizard", "wizard"]
objects: ["wizard"]
description: >
Recorded when the user selects a profile to migrate from. If the browser doesn't
support multiple profiles, this will not be recorded.
@ -1065,7 +1065,7 @@ browser.migration:
extra_keys:
migrator_key: The key of the browser that had a profile selected for it.
resources_selected:
objects: ["legacy_wizard", "wizard"]
objects: ["wizard"]
description: >
Recorded when the user selects resources from the browser / profile to import.
bug_numbers:
@ -1114,7 +1114,7 @@ browser.migration:
extra_keys:
migrator_key: The key of the migrator that will perform the migration.
safari_perms:
objects: ["legacy_wizard", "wizard"]
objects: ["wizard"]
description: >
Recorded if the user is on macOS, chose to migrate from Safari, and was presented with
the page of the wizard requesting permission to read from the Safari profile folder.
@ -1143,7 +1143,7 @@ browser.migration:
release_channel_collection: opt-out
expiry_version: never
migration_started:
objects: ["legacy_wizard", "wizard"]
objects: ["wizard"]
description: >
Recorded when the user begins a migration.
bug_numbers:
@ -1171,7 +1171,7 @@ browser.migration:
"1" if extensions are being migrated. "0" otherwise.
other: A count of the number of other resource types that are being migrated.
migration_finished:
objects: ["legacy_wizard", "wizard"]
objects: ["wizard"]
description: >
Recorded when the user finishes a migration.
bug_numbers:

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

@ -8670,17 +8670,6 @@
"kind": "boolean",
"description": "THUMBNAILS: Thumbnail found"
},
"FX_MIGRATION_ENTRY_POINT": {
"record_in_processes": ["main"],
"products": ["firefox"],
"bug_numbers": [731025, 1584261, 1643431, 1665442, 1678204],
"alert_emails": ["gijs@mozilla.com", "mak@mozilla.com"],
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 10,
"releaseChannelCollection": "opt-out",
"description": "Where the migration wizard was entered from. 0=Other/catch-all, 1=first-run, 2=refresh-firefox, 3=Places window, 4=Password manager, 5=New tab, 6=File menu, 7=Help menu, 8=Bookmarks toolbar"
},
"FX_MIGRATION_ENTRY_POINT_CATEGORICAL": {
"record_in_processes": ["main"],
"products": ["firefox"],
@ -8916,52 +8905,6 @@
"releaseChannelCollection": "opt-out",
"description": "Results of login import from a CSV/TSV file, by category"
},
"FX_STARTUP_MIGRATION_BROWSER_COUNT": {
"record_in_processes": ["main"],
"products": ["firefox"],
"bug_numbers": [1275114],
"alert_emails": ["gijs@mozilla.com"],
"expires_in_version": "65",
"kind": "enumerated",
"n_values": 15,
"releaseChannelCollection": "opt-out",
"description": "Number of browsers from which the user could migrate on initial profile migration. Only available on release builds during firstrun."
},
"FX_STARTUP_MIGRATION_EXISTING_DEFAULT_BROWSER": {
"record_in_processes": ["main"],
"products": ["firefox"],
"bug_numbers": [1275114],
"alert_emails": ["gijs@mozilla.com"],
"expires_in_version": "65",
"kind": "enumerated",
"n_values": 15,
"releaseChannelCollection": "opt-out",
"description": "The browser that was the default on the initial profile migration. The values correspond to the internal browser ID (see MigrationUtils.jsm)"
},
"FX_STARTUP_MIGRATION_DATA_RECENCY": {
"record_in_processes": ["main"],
"products": ["firefox"],
"bug_numbers": [1276694],
"alert_emails": ["gijs@mozilla.com"],
"expires_in_version": "65",
"keyed": true,
"kind": "exponential",
"n_buckets": 50,
"high": 8760,
"releaseChannelCollection": "opt-out",
"description": "The 'last modified' time of the data we imported on the initial profile migration (time delta with 'now' at the time of migration, in hours). Collected for all browsers for which migration data is available, and stored keyed by browser identifier (e.g. 'ie', 'edge', 'safari', etc.)."
},
"FX_STARTUP_MIGRATION_USED_RECENT_BROWSER": {
"record_in_processes": ["main"],
"products": ["firefox"],
"bug_numbers": [1276694],
"alert_emails": ["gijs@mozilla.com"],
"expires_in_version": "65",
"keyed": true,
"kind": "boolean",
"releaseChannelCollection": "opt-out",
"description": "Whether the browser we migrated from was the browser with the most recent data. Keyed by that browser's identifier (e.g. 'ie', 'edge', 'safari', etc.)."
},
"FX_ABOUTHOME_CACHE_CONSTRUCTION": {
"record_in_processes": ["content"],
"products": ["firefox"],

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

@ -8385,21 +8385,6 @@ migration:
- 'firefox'
record_in_processes:
- main
time_to_produce_legacy_migrator_list:
bug_numbers:
- 1840917
description: >
The amount of time it took in milliseconds to produce the list of migrators in the
legacy migration wizard.
expires: never
kind: uint
notification_emails:
- mconley@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
record_in_processes:
- main
time_to_produce_migrator_list:
bug_numbers:
- 1840917