summaryrefslogtreecommitdiffstats
path: root/browser/components/backup/content
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/backup/content')
-rw-r--r--browser/components/backup/content/BackupManifest.1.schema.json82
-rw-r--r--browser/components/backup/content/backup-settings.mjs47
-rw-r--r--browser/components/backup/content/backup-settings.stories.mjs32
-rw-r--r--browser/components/backup/content/debug.html18
-rw-r--r--browser/components/backup/content/debug.js54
5 files changed, 233 insertions, 0 deletions
diff --git a/browser/components/backup/content/BackupManifest.1.schema.json b/browser/components/backup/content/BackupManifest.1.schema.json
new file mode 100644
index 0000000000..51418988fe
--- /dev/null
+++ b/browser/components/backup/content/BackupManifest.1.schema.json
@@ -0,0 +1,82 @@
+{
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "$id": "file:///BackupManifest.schema.json",
+ "title": "BackupManifest",
+ "description": "A schema for the backup-manifest.json file for profile backups created by the BackupService",
+ "type": "object",
+ "properties": {
+ "version": {
+ "type": "integer",
+ "description": "Version of the backup manifest structure"
+ },
+ "meta": {
+ "type": "object",
+ "description": "Metadata about the backup",
+ "properties": {
+ "date": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Date and time that the backup was created"
+ },
+ "appName": {
+ "type": "string",
+ "description": "Name of the application that the backup was created for."
+ },
+ "appVersion": {
+ "type": "string",
+ "description": "Full version string for the app instance that the backup was created on"
+ },
+ "buildID": {
+ "type": "string",
+ "description": "Build ID for the app instance that the backup was created on"
+ },
+ "profileName": {
+ "type": "string",
+ "description": "The name given to the profile that was backed up"
+ },
+ "machineName": {
+ "type": "string",
+ "description": "The name of the machine that the backup was created on"
+ },
+ "osName": {
+ "type": "string",
+ "description": "The OS name that the backup was created on"
+ },
+ "osVersion": {
+ "type": "string",
+ "description": "The OS version that the backup was created on"
+ },
+ "accountID": {
+ "type": "string",
+ "description": "The ID for the account that the user profile was signed into when backing up. Optional."
+ },
+ "accountEmail": {
+ "type": "string",
+ "description": "The email address for the account that the user profile was signed into when backing up. Optional."
+ },
+ "legacyClientID": {
+ "type": "string",
+ "description": "The legacy telemetry client ID for the profile that the backup was created on."
+ }
+ },
+ "required": [
+ "date",
+ "appName",
+ "appVersion",
+ "buildID",
+ "profileName",
+ "machineName",
+ "osName",
+ "osVersion",
+ "legacyClientID"
+ ]
+ },
+ "resources": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object"
+ }
+ }
+ },
+ "required": ["version", "resources", "meta"]
+}
diff --git a/browser/components/backup/content/backup-settings.mjs b/browser/components/backup/content/backup-settings.mjs
new file mode 100644
index 0000000000..c34d87dbc7
--- /dev/null
+++ b/browser/components/backup/content/backup-settings.mjs
@@ -0,0 +1,47 @@
+/* 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/. */
+
+import { html } from "chrome://global/content/vendor/lit.all.mjs";
+import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
+
+/**
+ * The widget for managing the BackupService that is embedded within the main
+ * document of about:settings / about:preferences.
+ */
+export default class BackupSettings extends MozLitElement {
+ static properties = {
+ backupServiceState: { type: Object },
+ };
+
+ /**
+ * Creates a BackupSettings instance and sets the initial default
+ * state.
+ */
+ constructor() {
+ super();
+ this.backupServiceState = {
+ backupInProgress: false,
+ };
+ }
+
+ /**
+ * Dispatches the BackupUI:InitWidget custom event upon being attached to the
+ * DOM, which registers with BackupUIChild for BackupService state updates.
+ */
+ connectedCallback() {
+ super.connectedCallback();
+ this.dispatchEvent(
+ new CustomEvent("BackupUI:InitWidget", { bubbles: true })
+ );
+ }
+
+ render() {
+ return html`<div>
+ Backup in progress:
+ ${this.backupServiceState.backupInProgress ? "Yes" : "No"}
+ </div>`;
+ }
+}
+
+customElements.define("backup-settings", BackupSettings);
diff --git a/browser/components/backup/content/backup-settings.stories.mjs b/browser/components/backup/content/backup-settings.stories.mjs
new file mode 100644
index 0000000000..2a87c361bc
--- /dev/null
+++ b/browser/components/backup/content/backup-settings.stories.mjs
@@ -0,0 +1,32 @@
+/* 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/. */
+
+// eslint-disable-next-line import/no-unresolved
+import { html } from "lit.all.mjs";
+// eslint-disable-next-line import/no-unassigned-import
+import "./backup-settings.mjs";
+
+export default {
+ title: "Domain-specific UI Widgets/Backup/Backup Settings",
+ component: "backup-settings",
+ argTypes: {},
+};
+
+const Template = ({ backupServiceState }) => html`
+ <backup-settings .backupServiceState=${backupServiceState}></backup-settings>
+`;
+
+export const BackingUpNotInProgress = Template.bind({});
+BackingUpNotInProgress.args = {
+ backupServiceState: {
+ backupInProgress: false,
+ },
+};
+
+export const BackingUpInProgress = Template.bind({});
+BackingUpInProgress.args = {
+ backupServiceState: {
+ backupInProgress: true,
+ },
+};
diff --git a/browser/components/backup/content/debug.html b/browser/components/backup/content/debug.html
index 5d6517cf2a..55034d4a5c 100644
--- a/browser/components/backup/content/debug.html
+++ b/browser/components/backup/content/debug.html
@@ -36,7 +36,25 @@
<section id="controls">
<h2>Controls</h2>
<button id="create-backup">Create backup</button>
+ <p>
+ Clicking "Create backup" will create a backup, and then attempt to
+ show an OS notification with the total time it took to create it. This
+ notification may not appear if your OS has not granted the browser to
+ display notifications.
+ </p>
+ <p id="last-backup-status"></p>
<button id="open-backup-folder">Open backups folder</button>
+ <button id="recover-from-staging">
+ Recover from staging folder and launch
+ </button>
+ <p>
+ Clicking "Recover from staging folder and launch" will open a file
+ picker to allow you to select a staging folder. Once selected, a new
+ user profile will be created and the data stores from the staging
+ folder will be copied into that new profile. The new profile will then
+ be launched.
+ </p>
+ <p id="last-recovery-status"></p>
</section>
</main>
diff --git a/browser/components/backup/content/debug.js b/browser/components/backup/content/debug.js
index fd673818c0..7a2cea9640 100644
--- a/browser/components/backup/content/debug.js
+++ b/browser/components/backup/content/debug.js
@@ -26,13 +26,31 @@ let DebugUI = {
}
},
+ secondsToHms(seconds) {
+ let h = Math.floor(seconds / 3600);
+ let m = Math.floor((seconds % 3600) / 60);
+ let s = Math.floor((seconds % 3600) % 60);
+ return `${h}h ${m}m ${s}s`;
+ },
+
async onButtonClick(button) {
switch (button.id) {
case "create-backup": {
let service = BackupService.get();
+ let lastBackupStatus = document.querySelector("#last-backup-status");
+ lastBackupStatus.textContent = "Creating backup...";
+
+ let then = Cu.now();
button.disabled = true;
await service.createBackup();
+ let totalTimeSeconds = (Cu.now() - then) / 1000;
button.disabled = false;
+ new Notification(`Backup created`, {
+ body: `Total time ${this.secondsToHms(totalTimeSeconds)}`,
+ });
+ lastBackupStatus.textContent = `Backup created - total time: ${this.secondsToHms(
+ totalTimeSeconds
+ )}`;
break;
}
case "open-backup-folder": {
@@ -52,6 +70,42 @@ let DebugUI = {
break;
}
+ case "recover-from-staging": {
+ let backupsDir = PathUtils.join(PathUtils.profileDir, "backups");
+ let fp = Cc["@mozilla.org/filepicker;1"].createInstance(
+ Ci.nsIFilePicker
+ );
+ fp.init(
+ window.browsingContext,
+ "Choose a staging folder",
+ Ci.nsIFilePicker.modeGetFolder
+ );
+ fp.displayDirectory = await IOUtils.getDirectory(backupsDir);
+ let result = await new Promise(resolve => fp.open(resolve));
+ if (result == Ci.nsIFilePicker.returnCancel) {
+ break;
+ }
+
+ let path = fp.file.path;
+ let lastRecoveryStatus = document.querySelector(
+ "#last-recovery-status"
+ );
+ lastRecoveryStatus.textContent = "Recovering from backup...";
+
+ let service = BackupService.get();
+ try {
+ let newProfile = await service.recoverFromBackup(
+ path,
+ true /* shouldLaunch */
+ );
+ lastRecoveryStatus.textContent = `Created profile ${newProfile.name} at ${newProfile.rootDir.path}`;
+ } catch (e) {
+ lastRecoveryStatus.textContent(
+ `Failed to recover: ${e.message} Check the console for the full exception.`
+ );
+ throw e;
+ }
+ }
}
},
};