commit ef6d47f01dadd7a13f3e6add1eecb9c271289df3
parent b816837e56eb521aece170d928923de0b0403460
Author: Harsheet <hsohaney@mozilla.com>
Date: Sun, 16 Nov 2025 21:14:12 +0000
Bug 1996070 - (part 1) Move backup enable status states and error codes to the BackupService internal state and remove privileged instances from the backup UI. r=cdupuis
Differential Revision: https://phabricator.services.mozilla.com/D272692
Diffstat:
7 files changed, 81 insertions(+), 47 deletions(-)
diff --git a/browser/components/DesktopActorRegistry.sys.mjs b/browser/components/DesktopActorRegistry.sys.mjs
@@ -238,6 +238,7 @@ let JSWINDOWACTORS = {
"BackupUI:RerunEncryption": { wantUntrusted: true },
"BackupUI:ShowBackupLocation": { wantUntrusted: true },
"BackupUI:EditBackupLocation": { wantUntrusted: true },
+ "BackupUI:ErrorBarDismissed": { wantUntrusted: true },
},
},
includeChrome: true,
diff --git a/browser/components/backup/BackupService.sys.mjs b/browser/components/backup/BackupService.sys.mjs
@@ -189,6 +189,19 @@ XPCOMUtils.defineLazyPreferenceGetter(
5
);
+XPCOMUtils.defineLazyPreferenceGetter(
+ lazy,
+ "backupErrorCode",
+ BACKUP_ERROR_CODE_PREF_NAME,
+ ERRORS.NONE,
+ function onUpdateBackupErrorCode(_pref, _prevVal, newVal) {
+ let bs = BackupService.init();
+ if (bs) {
+ bs.onUpdateBackupErrorCode(newVal);
+ }
+ }
+);
+
XPCOMUtils.defineLazyServiceGetter(
lazy,
"idleService",
@@ -782,7 +795,6 @@ export class BackupService extends EventTarget {
lastBackupFileName: "",
supportBaseLink: Services.urlFormatter.formatURLPref("app.support.baseURL"),
recoveryInProgress: false,
- recoveryErrorCode: 0,
/**
* Every file we load successfully is going to get a restore ID which is
* basically the identifier for that profile restore event. If we actually
@@ -791,6 +803,10 @@ export class BackupService extends EventTarget {
* restored.
*/
restoreID: null,
+ recoveryErrorCode: ERRORS.NONE,
+ backupErrorCode: lazy.backupErrorCode,
+ archiveEnabledStatus: this.archiveEnabledStatus.enabled,
+ restoreEnabledStatus: this.restoreEnabledStatus.enabled,
};
/**
@@ -1696,6 +1712,7 @@ export class BackupService extends EventTarget {
})
);
+ this.stateUpdate();
throw e;
} finally {
this.#backupInProgress = false;
@@ -3525,6 +3542,20 @@ export class BackupService extends EventTarget {
}
/**
+ * Updates backupErrorCode in the backup service state. Should be called every time
+ * the value for browser.backup.errorCode changes.
+ *
+ * @param {number} newErrorCode
+ * Any of the ERROR code's from backup-constants.mjs
+ */
+ onUpdateBackupErrorCode(newErrorCode) {
+ lazy.logConsole.debug(`Updating backup error code to ${newErrorCode}`);
+
+ this.#_state.backupErrorCode = newErrorCode;
+ this.stateUpdate();
+ }
+
+ /**
* Returns the moz-icon URL of a file. To get the moz-icon URL, the
* file path is convered to a fileURI. If there is a problem retreiving
* the moz-icon due to an invalid file path, return null instead.
@@ -4090,6 +4121,11 @@ export class BackupService extends EventTarget {
* 2. If archive is disabled, clean up any backup files
*/
#handleStatusChange() {
+ // Update the BackupService state before notifying observers about the
+ // state change
+ this.#_state.archiveEnabledStatus = this.archiveEnabledStatus.enabled;
+ this.#_state.restoreEnabledStatus = this.restoreEnabledStatus.enabled;
+
this.#notifyStatusObservers();
if (!this.archiveEnabledStatus.enabled) {
diff --git a/browser/components/backup/actors/BackupUIChild.sys.mjs b/browser/components/backup/actors/BackupUIChild.sys.mjs
@@ -138,6 +138,8 @@ export class BackupUIChild extends JSWindowActorChild {
this.sendAsyncMessage("ShowBackupLocation");
} else if (event.type == "BackupUI:EditBackupLocation") {
this.sendAsyncMessage("EditBackupLocation");
+ } else if (event.type == "BackupUI:ErrorBarDismissed") {
+ this.sendAsyncMessage("ErrorBarDismissed");
}
}
diff --git a/browser/components/backup/actors/BackupUIParent.sys.mjs b/browser/components/backup/actors/BackupUIParent.sys.mjs
@@ -18,6 +18,8 @@ ChromeUtils.defineLazyGetter(lazy, "logConsole", function () {
});
});
+const BACKUP_ERROR_CODE_PREF_NAME = "browser.backup.errorCode";
+
/**
* A JSWindowActor that is responsible for marshalling information between
* the BackupService singleton and any registered UI widgets that need to
@@ -49,6 +51,7 @@ export class BackupUIParent extends JSWindowActorParent {
*/
actorCreated() {
this.#bs.addEventListener("BackupService:StateUpdate", this);
+ Services.obs.addObserver(this.sendState, "backup-service-status-updated");
// Note that loadEncryptionState is an async function.
// This function is no-op if the encryption state was already loaded.
this.#bs.loadEncryptionState();
@@ -59,6 +62,10 @@ export class BackupUIParent extends JSWindowActorParent {
*/
didDestroy() {
this.#bs.removeEventListener("BackupService:StateUpdate", this);
+ Services.obs.removeObserver(
+ this.sendState,
+ "backup-service-status-updated"
+ );
}
/**
@@ -263,6 +270,12 @@ export class BackupUIParent extends JSWindowActorParent {
e
);
}
+ } else if (message.name == "ErrorBarDismissed") {
+ Services.prefs.setIntPref(BACKUP_ERROR_CODE_PREF_NAME, lazy.ERRORS.NONE);
+ } else if (message.name == "SetEmbeddedComponentPersistentData") {
+ this.#bs.setEmbeddedComponentPersistentData(message.data);
+ } else if (message.name == "FlushEmbeddedComponentPersistentData") {
+ this.#bs.setEmbeddedComponentPersistentData({});
}
return null;
diff --git a/browser/components/backup/content/backup-settings.mjs b/browser/components/backup/content/backup-settings.mjs
@@ -7,12 +7,6 @@ import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
import { getErrorL10nId } from "chrome://browser/content/backup/backup-errors.mjs";
import { ERRORS } from "chrome://browser/content/backup/backup-constants.mjs";
-const lazy = {};
-
-ChromeUtils.defineESModuleGetters(lazy, {
- BackupService: "resource:///modules/backup/BackupService.sys.mjs",
-});
-
// eslint-disable-next-line import/no-unassigned-import
import "chrome://browser/content/backup/turn-on-scheduled-backups.mjs";
// eslint-disable-next-line import/no-unassigned-import
@@ -24,15 +18,12 @@ import "chrome://browser/content/backup/enable-backup-encryption.mjs";
// eslint-disable-next-line import/no-unassigned-import
import "chrome://browser/content/backup/disable-backup-encryption.mjs";
-const BACKUP_ERROR_CODE_PREF_NAME = "browser.backup.errorCode";
-
/**
* The widget for managing the BackupService that is embedded within the main
* document of about:settings / about:preferences.
*/
export default class BackupSettings extends MozLitElement {
#placeholderIconURL = "chrome://global/skin/icons/page-portrait.svg";
- #backupService = lazy.BackupService.init();
inProgressTimeout = null;
showInProgress = false;
@@ -41,10 +32,7 @@ export default class BackupSettings extends MozLitElement {
static properties = {
backupServiceState: { type: Object },
- backupErrorCode: { type: Number },
_enableEncryptionTypeAttr: { type: String },
- _archiveEnabled: { type: Boolean },
- _restoreEnabled: { type: Boolean },
};
static get queries() {
@@ -111,18 +99,14 @@ export default class BackupSettings extends MozLitElement {
supportBaseLink: "",
backupInProgress: false,
recoveryInProgress: false,
- recoveryErrorCode: 0,
+ recoveryErrorCode: ERRORS.NONE,
+ backupErrorCode: ERRORS.NONE,
+ archiveEnabledStatus: false,
+ restoreEnabledStatus: false,
};
- this.backupErrorCode = this.#readBackupErrorPref();
this._enableEncryptionTypeAttr = "";
- this.updateArchiveAndRestoreState();
}
- updateArchiveAndRestoreState = () => {
- this._archiveEnabled = this.#backupService.archiveEnabledStatus.enabled;
- this._restoreEnabled = this.#backupService.restoreEnabledStatus.enabled;
- };
-
/**
* Dispatches the BackupUI:InitWidget custom event upon being attached to the
* DOM, which registers with BackupUIChild for BackupService state updates.
@@ -133,34 +117,16 @@ export default class BackupSettings extends MozLitElement {
new CustomEvent("BackupUI:InitWidget", { bubbles: true })
);
- Services.obs.addObserver(
- this.updateArchiveAndRestoreState,
- "backup-service-status-updated"
- );
-
- this._cleanupObs = () => {
- Services.obs.removeObserver(
- this.updateArchiveAndRestoreState,
- "backup-service-status-updated"
- );
- window.removeEventListener("unload", this._cleanupObs);
- };
-
- window.addEventListener("unload", this._cleanupObs, { once: true });
-
this.addEventListener("dialogCancel", this);
this.addEventListener("restoreFromBackupConfirm", this);
this.addEventListener("restoreFromBackupChooseFile", this);
}
- #readBackupErrorPref() {
- return Services.prefs.getIntPref(BACKUP_ERROR_CODE_PREF_NAME);
- }
-
handleErrorBarDismiss = () => {
// Reset the pref and reactive state; Lit will re-render without the bar.
- Services.prefs.setIntPref(BACKUP_ERROR_CODE_PREF_NAME, ERRORS.NONE);
- this.backupErrorCode = 0;
+ this.dispatchEvent(
+ new CustomEvent("BackupUI:ErrorBarDismissed", { bubbles: true })
+ );
};
handleEvent(event) {
@@ -476,7 +442,7 @@ export default class BackupSettings extends MozLitElement {
}
errorBarTemplate() {
- const l10nId = getErrorL10nId(this.backupErrorCode);
+ const l10nId = getErrorL10nId(this.backupServiceState.backupErrorCode);
return html`
<moz-message-bar
type="error"
@@ -536,13 +502,15 @@ export default class BackupSettings extends MozLitElement {
rel="stylesheet"
href="chrome://browser/content/backup/backup-settings.css"
/>
- ${this.backupErrorCode ? this.errorBarTemplate() : null}
+ ${this.backupServiceState.backupErrorCode
+ ? this.errorBarTemplate()
+ : null}
${this.showInProgress ? this.inProgressMessageBarTemplate() : null}
${this.turnOnScheduledBackupsDialogTemplate()}
${this.turnOffScheduledBackupsDialogTemplate()}
${this.enableBackupEncryptionDialogTemplate()}
${this.disableBackupEncryptionDialogTemplate()}
- ${this._archiveEnabled
+ ${this.backupServiceState.archiveEnabledStatus
? html` <section id="scheduled-backups">
<div class="backups-control">
<span
@@ -584,7 +552,9 @@ export default class BackupSettings extends MozLitElement {
: null}
</section>`
: null}
- ${this._restoreEnabled ? this.restoreFromBackupTemplate() : null} `;
+ ${this.backupServiceState.restoreEnabledStatus
+ ? this.restoreFromBackupTemplate()
+ : null} `;
}
}
diff --git a/browser/components/backup/content/backup-settings.stories.mjs b/browser/components/backup/content/backup-settings.stories.mjs
@@ -28,6 +28,9 @@ ScheduledBackupsDisabled.args = {
fileName: "Documents",
},
scheduledBackupsEnabled: false,
+ backupErrorCode: 0,
+ archiveEnabledStatus: true,
+ restoreEnabledStatus: true,
},
};
@@ -40,6 +43,9 @@ ScheduledBackupsEnabled.args = {
fileName: "Documents",
},
scheduledBackupsEnabled: true,
+ backupErrorCode: 0,
+ archiveEnabledStatus: true,
+ restoreEnabledStatus: true,
},
};
@@ -54,6 +60,9 @@ ExistingBackup.args = {
scheduledBackupsEnabled: true,
lastBackupDate: 1719625747,
lastBackupFileName: "FirefoxBackup_default_123123123.html",
+ backupErrorCode: 0,
+ archiveEnabledStatus: true,
+ restoreEnabledStatus: true,
},
};
@@ -69,5 +78,8 @@ EncryptionEnabled.args = {
encryptionEnabled: true,
lastBackupDate: 1719625747,
lastBackupFileName: "FirefoxBackup_default_123123123.html",
+ backupErrorCode: 0,
+ archiveEnabledStatus: true,
+ restoreEnabledStatus: true,
},
};
diff --git a/browser/components/storybook/component-status/components.json b/browser/components/storybook/component-status/components.json
@@ -1,5 +1,5 @@
{
- "generatedAt": "2025-11-12T19:18:35.085Z",
+ "generatedAt": "2025-11-14T18:02:05.239Z",
"count": 29,
"items": [
{