304 lines
8.9 KiB
JavaScript
304 lines
8.9 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/. */
|
|
|
|
import { html, ifDefined } from "chrome://global/content/vendor/lit.all.mjs";
|
|
import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
|
|
|
|
// eslint-disable-next-line import/no-unassigned-import
|
|
import "chrome://global/content/elements/moz-message-bar.mjs";
|
|
|
|
import { ERRORS } from "chrome://browser/content/backup/backup-constants.mjs";
|
|
|
|
/**
|
|
* Any recovery error messaging should be defined in Fluent with both
|
|
* a `heading` attribute and a `message` attribute.
|
|
*/
|
|
const RECOVERY_ERROR_L10N_IDS = Object.freeze({
|
|
[ERRORS.UNAUTHORIZED]: "restore-from-backup-error-incorrect-password",
|
|
[ERRORS.CORRUPTED_ARCHIVE]: "restore-from-backup-error-corrupt-file",
|
|
[ERRORS.UNSUPPORTED_BACKUP_VERSION]:
|
|
"restore-from-backup-error-unsupported-version",
|
|
[ERRORS.UNINITIALIZED]: "restore-from-backup-error-recovery-failed",
|
|
[ERRORS.FILE_SYSTEM_ERROR]: "restore-from-backup-error-recovery-failed",
|
|
[ERRORS.DECRYPTION_FAILED]: "restore-from-backup-error-recovery-failed",
|
|
[ERRORS.RECOVERY_FAILED]: "restore-from-backup-error-recovery-failed",
|
|
[ERRORS.UNKNOWN]: "restore-from-backup-error-went-wrong",
|
|
[ERRORS.INTERNAL_ERROR]: "restore-from-backup-error-went-wrong",
|
|
[ERRORS.UNSUPPORTED_APPLICATION]:
|
|
"restore-from-backup-error-unsupported-application",
|
|
});
|
|
|
|
/**
|
|
* @param {number} errorCode
|
|
* Error code from backup-constants.mjs:ERRORS
|
|
* @returns {string}
|
|
* L10N ID for error messaging for the given error code; the L10N
|
|
* ID should have both a `heading` and a `message` attribute
|
|
*/
|
|
function getRecoveryErrorL10nId(errorCode) {
|
|
return (
|
|
RECOVERY_ERROR_L10N_IDS[errorCode] ??
|
|
RECOVERY_ERROR_L10N_IDS[ERRORS.UNKNOWN]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* The widget for allowing users to select and restore from a
|
|
* a backup file.
|
|
*/
|
|
export default class RestoreFromBackup extends MozLitElement {
|
|
#placeholderFileIconURL = "chrome://global/skin/icons/page-portrait.svg";
|
|
|
|
static properties = {
|
|
backupFilePath: { type: String },
|
|
backupFileToRestore: { type: String, reflect: true },
|
|
backupFileInfo: { type: Object },
|
|
_fileIconURL: { type: String },
|
|
recoveryInProgress: { type: Boolean },
|
|
recoveryErrorCode: { type: Number },
|
|
};
|
|
|
|
static get queries() {
|
|
return {
|
|
filePicker: "#backup-filepicker-input",
|
|
passwordInput: "#backup-password-input",
|
|
cancelButtonEl: "#restore-from-backup-cancel-button",
|
|
confirmButtonEl: "#restore-from-backup-confirm-button",
|
|
chooseButtonEl: "#backup-filepicker-button",
|
|
errorMessageEl: "#restore-from-backup-error",
|
|
};
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
this._fileIconURL = "";
|
|
}
|
|
|
|
/**
|
|
* 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 })
|
|
);
|
|
|
|
if (this.backupFileToRestore && !this.backupFileInfo) {
|
|
this.getBackupFileInfo();
|
|
}
|
|
|
|
this.addEventListener("BackupUI:SelectNewFilepickerPath", this);
|
|
}
|
|
|
|
handleEvent(event) {
|
|
if (event.type == "BackupUI:SelectNewFilepickerPath") {
|
|
let { path, iconURL } = event.detail;
|
|
this.backupFileToRestore = path;
|
|
this._fileIconURL = iconURL;
|
|
}
|
|
}
|
|
|
|
willUpdate(changedProperties) {
|
|
if (changedProperties.has("backupFileToRestore")) {
|
|
this.backupFileInfo = null;
|
|
this.getBackupFileInfo();
|
|
}
|
|
}
|
|
|
|
async handleChooseBackupFile() {
|
|
this.dispatchEvent(
|
|
new CustomEvent("BackupUI:ShowFilepicker", {
|
|
bubbles: true,
|
|
detail: {
|
|
win: window.browsingContext,
|
|
filter: "filterHTML",
|
|
displayDirectoryPath: this.backupFileToRestore,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
|
|
getBackupFileInfo() {
|
|
let backupFile = this.backupFileToRestore;
|
|
if (!backupFile) {
|
|
return;
|
|
}
|
|
this.dispatchEvent(
|
|
new CustomEvent("getBackupFileInfo", {
|
|
bubbles: true,
|
|
composed: true,
|
|
detail: {
|
|
backupFile,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
|
|
handleCancel() {
|
|
this.dispatchEvent(
|
|
new CustomEvent("dialogCancel", {
|
|
bubbles: true,
|
|
composed: true,
|
|
})
|
|
);
|
|
}
|
|
|
|
handleConfirm() {
|
|
let backupFile = this.backupFileToRestore;
|
|
if (!backupFile || this.recoveryInProgress) {
|
|
return;
|
|
}
|
|
let backupPassword = this.passwordInput?.value;
|
|
this.dispatchEvent(
|
|
new CustomEvent("restoreFromBackupConfirm", {
|
|
bubbles: true,
|
|
composed: true,
|
|
detail: {
|
|
backupFile,
|
|
backupPassword,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
|
|
controlsTemplate() {
|
|
let iconURL =
|
|
this.backupFileToRestore &&
|
|
(this._fileIconURL || this.#placeholderFileIconURL);
|
|
return html`
|
|
<fieldset id="backup-restore-controls">
|
|
<fieldset id="backup-filepicker-controls">
|
|
<label
|
|
id="backup-filepicker-label"
|
|
for="backup-filepicker-input"
|
|
data-l10n-id="restore-from-backup-filepicker-label"
|
|
></label>
|
|
<div id="backup-filepicker">
|
|
<input
|
|
id="backup-filepicker-input"
|
|
type="text"
|
|
readonly
|
|
value=${this.backupFileToRestore}
|
|
style="background-image: url(${ifDefined(iconURL)})"
|
|
/>
|
|
<moz-button
|
|
id="backup-filepicker-button"
|
|
@click=${this.handleChooseBackupFile}
|
|
data-l10n-id="restore-from-backup-file-choose-button"
|
|
aria-controls="backup-filepicker-input"
|
|
></moz-button>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<fieldset id="password-entry-controls">
|
|
${this.backupFileInfo?.isEncrypted
|
|
? this.passwordEntryTemplate()
|
|
: null}
|
|
</fieldset>
|
|
</fieldset>
|
|
`;
|
|
}
|
|
|
|
passwordEntryTemplate() {
|
|
return html` <fieldset id="backup-password">
|
|
<label id="backup-password-label" for="backup-password-input">
|
|
<span
|
|
id="backup-password-span"
|
|
data-l10n-id="restore-from-backup-password-label"
|
|
></span>
|
|
<input type="password" id="backup-password-input" />
|
|
</label>
|
|
<label
|
|
id="backup-password-description"
|
|
data-l10n-id="restore-from-backup-password-description"
|
|
></label>
|
|
</fieldset>`;
|
|
}
|
|
|
|
contentTemplate() {
|
|
let buttonL10nId = !this.recoveryInProgress
|
|
? "restore-from-backup-confirm-button"
|
|
: "restore-from-backup-restoring-button";
|
|
|
|
return html`
|
|
<div
|
|
id="restore-from-backup-wrapper"
|
|
aria-labelledby="restore-from-backup-header"
|
|
aria-describedby="restore-from-backup-description"
|
|
>
|
|
<h1
|
|
id="restore-from-backup-header"
|
|
class="heading-medium"
|
|
data-l10n-id="restore-from-backup-header"
|
|
></h1>
|
|
<main id="restore-from-backup-content">
|
|
${this.recoveryErrorCode ? this.errorTemplate() : null}
|
|
${this.backupFileInfo ? this.descriptionTemplate() : null}
|
|
${this.controlsTemplate()}
|
|
</main>
|
|
|
|
<moz-button-group id="restore-from-backup-button-group">
|
|
<moz-button
|
|
id="restore-from-backup-cancel-button"
|
|
@click=${this.handleCancel}
|
|
data-l10n-id="restore-from-backup-cancel-button"
|
|
></moz-button>
|
|
<moz-button
|
|
id="restore-from-backup-confirm-button"
|
|
@click=${this.handleConfirm}
|
|
type="primary"
|
|
data-l10n-id=${buttonL10nId}
|
|
?disabled=${!this.backupFileToRestore || this.recoveryInProgress}
|
|
></moz-button>
|
|
</moz-button-group>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
descriptionTemplate() {
|
|
let { date } = this.backupFileInfo;
|
|
let dateTime = date && new Date(date).getTime();
|
|
return html`
|
|
<div id="restore-from-backup-description">
|
|
<span
|
|
id="restore-from-backup-description-span"
|
|
data-l10n-id="restore-from-backup-description-with-metadata"
|
|
data-l10n-args=${JSON.stringify({
|
|
date: dateTime,
|
|
})}
|
|
></span>
|
|
<a
|
|
id="restore-from-backup-learn-more-link"
|
|
is="moz-support-link"
|
|
support-page="todo-backup"
|
|
data-l10n-id="restore-from-backup-support-link"
|
|
></a>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
errorTemplate() {
|
|
return html`
|
|
<moz-message-bar
|
|
id="restore-from-backup-error"
|
|
type="error"
|
|
data-l10n-id=${getRecoveryErrorL10nId(this.recoveryErrorCode)}
|
|
>
|
|
</moz-message-bar>
|
|
`;
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<link
|
|
rel="stylesheet"
|
|
href="chrome://browser/content/backup/restore-from-backup.css"
|
|
/>
|
|
${this.contentTemplate()}
|
|
`;
|
|
}
|
|
}
|
|
|
|
customElements.define("restore-from-backup", RestoreFromBackup);
|