mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-13 20:36:35 +00:00
Change backup restore flow (#23354)
* Change backup restore flow * adapt and finish * Update dialog-restore-backup.ts
This commit is contained in:
parent
dc799bf691
commit
b35f9944ea
@ -1,245 +0,0 @@
|
||||
import { mdiClose } from "@mdi/js";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-dialog-header";
|
||||
import "../../../../components/ha-form/ha-form";
|
||||
import type {
|
||||
HaFormSchema,
|
||||
SchemaUnion,
|
||||
} from "../../../../components/ha-form/types";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import "../../../../components/ha-md-dialog";
|
||||
import type { HaMdDialog } from "../../../../components/ha-md-dialog";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import { fetchBackupConfig } from "../../../../data/backup";
|
||||
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { RestoreBackupEncryptionKeyDialogParams } from "./show-dialog-restore-backup-encryption-key";
|
||||
|
||||
type FormData = {
|
||||
encryption_key_type: "config" | "custom";
|
||||
custom_encryption_key: string;
|
||||
};
|
||||
|
||||
const INITIAL_DATA: FormData = {
|
||||
encryption_key_type: "config",
|
||||
custom_encryption_key: "",
|
||||
};
|
||||
|
||||
@customElement("ha-dialog-restore-backup-encryption-key")
|
||||
class DialogRestoreBackupEncryptionKey
|
||||
extends LitElement
|
||||
implements HassDialog
|
||||
{
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _params?: RestoreBackupEncryptionKeyDialogParams;
|
||||
|
||||
@state() private _formData?: FormData;
|
||||
|
||||
@state() private _backupEncryptionKey?: string;
|
||||
|
||||
@query("ha-md-dialog") private _dialog?: HaMdDialog;
|
||||
|
||||
public showDialog(_params: RestoreBackupEncryptionKeyDialogParams): void {
|
||||
this._params = _params;
|
||||
this._formData = INITIAL_DATA;
|
||||
this._fetchEncryptionKey();
|
||||
}
|
||||
|
||||
private _dialogClosed() {
|
||||
if (this._params!.cancel) {
|
||||
this._params!.cancel();
|
||||
}
|
||||
this._formData = undefined;
|
||||
this._params = undefined;
|
||||
this._backupEncryptionKey = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
private async _fetchEncryptionKey() {
|
||||
try {
|
||||
const { config } = await fetchBackupConfig(this.hass);
|
||||
this._backupEncryptionKey = config.create_backup.password || undefined;
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public closeDialog() {
|
||||
this._dialog?.close();
|
||||
}
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(hasEncryptionKey: boolean, type: "config" | "custom") =>
|
||||
[
|
||||
...(hasEncryptionKey
|
||||
? [
|
||||
{
|
||||
name: "encryption_key_type",
|
||||
selector: {
|
||||
select: {
|
||||
options: [
|
||||
{
|
||||
value: "config",
|
||||
label: "Use backup encryption key",
|
||||
},
|
||||
{
|
||||
value: "custom",
|
||||
label: "Enter encryption key",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
context: {
|
||||
filter_entity: "entity",
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(!hasEncryptionKey || type === "custom"
|
||||
? ([
|
||||
{
|
||||
name: "custom_encryption_key",
|
||||
selector: {
|
||||
text: {},
|
||||
},
|
||||
},
|
||||
] as const satisfies readonly HaFormSchema[])
|
||||
: []),
|
||||
] as const satisfies readonly HaFormSchema[]
|
||||
);
|
||||
|
||||
protected render() {
|
||||
if (!this._params || !this._formData) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const dialogTitle = "Restore backup";
|
||||
|
||||
const hasEncryptionKey = this._backupEncryptionKey != null;
|
||||
|
||||
const schema = this._schema(
|
||||
hasEncryptionKey,
|
||||
this._formData.encryption_key_type
|
||||
);
|
||||
|
||||
return html`
|
||||
<ha-md-dialog open @closed=${this._dialogClosed}>
|
||||
<ha-dialog-header slot="headline">
|
||||
<ha-icon-button
|
||||
slot="navigationIcon"
|
||||
.label=${this.hass.localize("ui.dialogs.generic.close")}
|
||||
.path=${mdiClose}
|
||||
@click=${this.closeDialog}
|
||||
></ha-icon-button>
|
||||
<span slot="title" .title=${dialogTitle}>${dialogTitle}</span>
|
||||
</ha-dialog-header>
|
||||
<div slot="content" class="content">
|
||||
<p>
|
||||
${hasEncryptionKey
|
||||
? "The backup is encrypted. Which encryption key would you like to use to decrypt the backup?"
|
||||
: "The backup is encrypted. Provide the encryption key to decrypt the backup."}
|
||||
</p>
|
||||
<ha-form
|
||||
.schema=${schema}
|
||||
.data=${this._formData}
|
||||
@value-changed=${this._valueChanged}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
>
|
||||
</ha-form>
|
||||
</div>
|
||||
<div slot="actions">
|
||||
<ha-button @click=${this.closeDialog}>Cancel</ha-button>
|
||||
<ha-button
|
||||
@click=${this._submit}
|
||||
class="danger"
|
||||
.disabled=${!this._getKey()}
|
||||
>
|
||||
Restore
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-md-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
ev.stopPropagation();
|
||||
this._formData = ev.detail.value;
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
) => {
|
||||
switch (schema.name) {
|
||||
case "encryption_key_type":
|
||||
return "";
|
||||
case "custom_encryption_key":
|
||||
return "Encryption key";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
private _getKey() {
|
||||
if (!this._formData) {
|
||||
return undefined;
|
||||
}
|
||||
const hasEncryptionKey = this._backupEncryptionKey != null;
|
||||
|
||||
if (hasEncryptionKey) {
|
||||
return this._formData.encryption_key_type === "config"
|
||||
? this._backupEncryptionKey
|
||||
: this._formData.custom_encryption_key;
|
||||
}
|
||||
|
||||
return this._formData.custom_encryption_key;
|
||||
}
|
||||
|
||||
private async _submit() {
|
||||
if (!this._formData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const key = this._getKey();
|
||||
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._params!.submit?.(key!);
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-md-dialog {
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
--dialog-content-padding: 8px 24px;
|
||||
}
|
||||
.content p {
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
ha-button.danger {
|
||||
--mdc-theme-primary: var(--error-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-dialog-restore-backup-encryption-key": DialogRestoreBackupEncryptionKey;
|
||||
}
|
||||
}
|
313
src/panels/config/backup/dialogs/dialog-restore-backup.ts
Normal file
313
src/panels/config/backup/dialogs/dialog-restore-backup.ts
Normal file
@ -0,0 +1,313 @@
|
||||
import { mdiClose } from "@mdi/js";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-circular-progress";
|
||||
import "../../../../components/ha-dialog-header";
|
||||
import "../../../../components/ha-password-field";
|
||||
|
||||
import "../../../../components/ha-alert";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import "../../../../components/ha-md-dialog";
|
||||
import type { HaMdDialog } from "../../../../components/ha-md-dialog";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import {
|
||||
fetchBackupConfig,
|
||||
getPreferredAgentForDownload,
|
||||
restoreBackup,
|
||||
} from "../../../../data/backup";
|
||||
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { RestoreBackupDialogParams } from "./show-dialog-restore-backup";
|
||||
import type { RestoreBackupStage } from "../../../../data/backup_manager";
|
||||
import { subscribeBackupEvents } from "../../../../data/backup_manager";
|
||||
|
||||
type FormData = {
|
||||
encryption_key_type: "config" | "custom";
|
||||
custom_encryption_key: string;
|
||||
};
|
||||
|
||||
const INITIAL_DATA: FormData = {
|
||||
encryption_key_type: "config",
|
||||
custom_encryption_key: "",
|
||||
};
|
||||
|
||||
const STEPS = ["confirm", "encryption", "progress"] as const;
|
||||
|
||||
@customElement("ha-dialog-restore-backup")
|
||||
class DialogRestoreBackup extends LitElement implements HassDialog {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _step?: "confirm" | "encryption" | "progress";
|
||||
|
||||
@state() private _params?: RestoreBackupDialogParams;
|
||||
|
||||
@state() private _formData?: FormData;
|
||||
|
||||
@state() private _backupEncryptionKey?: string;
|
||||
|
||||
@state() private _userPassword?: string;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
@state() private _stage?: RestoreBackupStage | null;
|
||||
|
||||
@state() private _unsub?: Promise<UnsubscribeFunc>;
|
||||
|
||||
@query("ha-md-dialog") private _dialog?: HaMdDialog;
|
||||
|
||||
public async showDialog(params: RestoreBackupDialogParams) {
|
||||
this._params = params;
|
||||
|
||||
this._formData = INITIAL_DATA;
|
||||
if (this._params.backup.protected) {
|
||||
this._backupEncryptionKey = await this._fetchEncryptionKey();
|
||||
if (!this._backupEncryptionKey) {
|
||||
this._step = STEPS[1];
|
||||
} else {
|
||||
this._step = STEPS[0];
|
||||
}
|
||||
} else {
|
||||
this._step = STEPS[0];
|
||||
}
|
||||
}
|
||||
|
||||
public closeDialog() {
|
||||
this._dialog?.close();
|
||||
}
|
||||
|
||||
private _dialogClosed() {
|
||||
this._formData = undefined;
|
||||
this._params = undefined;
|
||||
this._backupEncryptionKey = undefined;
|
||||
this._userPassword = undefined;
|
||||
this._error = undefined;
|
||||
this._stage = undefined;
|
||||
this._step = undefined;
|
||||
if (this._unsub) {
|
||||
this._unsub.then((unsub) => unsub());
|
||||
this._unsub = undefined;
|
||||
}
|
||||
window.removeEventListener("connection-status", this._connectionStatus);
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
private async _fetchEncryptionKey() {
|
||||
try {
|
||||
const { config } = await fetchBackupConfig(this.hass);
|
||||
return config.create_backup.password || undefined;
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._step || !this._params || !this._formData) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const dialogTitle = "Restore backup";
|
||||
|
||||
return html`
|
||||
<ha-md-dialog open @closed=${this._dialogClosed}>
|
||||
<ha-dialog-header slot="headline">
|
||||
<ha-icon-button
|
||||
slot="navigationIcon"
|
||||
.label=${this.hass.localize("ui.dialogs.generic.close")}
|
||||
.path=${mdiClose}
|
||||
@click=${this.closeDialog}
|
||||
></ha-icon-button>
|
||||
<span slot="title" .title=${dialogTitle}>${dialogTitle}</span>
|
||||
</ha-dialog-header>
|
||||
<div slot="content" class="content">
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: this._step === "confirm"
|
||||
? this._renderConfirm()
|
||||
: this._step === "encryption"
|
||||
? this._renderEncryption()
|
||||
: this._renderProgress()}
|
||||
</div>
|
||||
<div slot="actions">
|
||||
${this._error
|
||||
? html`<ha-button @click=${this.closeDialog}>Close</ha-button>`
|
||||
: this._step === "confirm" || this._step === "encryption"
|
||||
? this._renderConfirmActions()
|
||||
: nothing}
|
||||
</div>
|
||||
</ha-md-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderConfirm() {
|
||||
return html`<p>
|
||||
Your backup will be restored and all current data will be overwritten.
|
||||
Depending on the size of the backup, this can take a while.
|
||||
</p>`;
|
||||
}
|
||||
|
||||
private _renderEncryption() {
|
||||
return html`<p>
|
||||
${this._userPassword
|
||||
? "The provided encryption key was incorrect, please try again."
|
||||
: this._backupEncryptionKey
|
||||
? "The backup is encrypted with a different key or password than that is saved on this system. Please enter the key for this backup."
|
||||
: "The backup is encrypted. Provide the encryption key to decrypt the backup."}
|
||||
</p>
|
||||
<ha-password-field
|
||||
@change=${this._passwordChanged}
|
||||
.value=${this._userPassword || ""}
|
||||
></ha-password-field>`;
|
||||
}
|
||||
|
||||
private _renderConfirmActions() {
|
||||
return html`<ha-button @click=${this.closeDialog}>Cancel</ha-button>
|
||||
<ha-button @click=${this._restoreBackup} class="destructive"
|
||||
>Restore</ha-button
|
||||
>`;
|
||||
}
|
||||
|
||||
private _renderProgress() {
|
||||
return html`<div class="centered">
|
||||
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||
<p>
|
||||
${this.hass.connected
|
||||
? this._restoreState()
|
||||
: "Restarting Home Asssistant"}
|
||||
</p>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
private _passwordChanged(ev): void {
|
||||
this._userPassword = ev.target.value;
|
||||
}
|
||||
|
||||
private async _restoreBackup() {
|
||||
try {
|
||||
this._step = "progress";
|
||||
window.addEventListener("connection-status", this._connectionStatus);
|
||||
await this._doRestoreBackup(
|
||||
this._userPassword || this._backupEncryptionKey
|
||||
);
|
||||
this._subscribeBackupEvents();
|
||||
} catch (e: any) {
|
||||
window.removeEventListener("connection-status", this._connectionStatus);
|
||||
if (e.code === "password_incorrect") {
|
||||
this._step = "encryption";
|
||||
} else {
|
||||
this._error = e.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _connectionStatus = (ev) => {
|
||||
if (ev.detail === "connected") {
|
||||
this.closeDialog();
|
||||
}
|
||||
};
|
||||
|
||||
private _subscribeBackupEvents() {
|
||||
this._unsub = subscribeBackupEvents(this.hass!, (event) => {
|
||||
if (event.manager_state !== "restore_backup") {
|
||||
return;
|
||||
}
|
||||
if (event.state === "completed") {
|
||||
this.closeDialog();
|
||||
}
|
||||
if (event.state === "failed") {
|
||||
this._error = "Backup restore failed";
|
||||
}
|
||||
if (event.state === "in_progress") {
|
||||
this._stage = event.stage;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _restoreState() {
|
||||
switch (this._stage) {
|
||||
case "addon_repositories":
|
||||
return "Restoring add-on repositories";
|
||||
case "addons":
|
||||
return "Restoring add-ons";
|
||||
case "await_addon_restarts":
|
||||
return "Waiting for add-ons to restart";
|
||||
case "await_home_assistant_restart":
|
||||
return "Waiting for Home Assistant to restart";
|
||||
case "check_home_assistant":
|
||||
return "Checking Home Assistant configuration";
|
||||
case "docker_config":
|
||||
return "Restoring Docker configuration";
|
||||
case "download_from_agent":
|
||||
return "Downloading backup";
|
||||
case "folders":
|
||||
return "Restoring folders";
|
||||
case "home_assistant":
|
||||
return "Restoring Home Assistant";
|
||||
case "remove_delta_addons":
|
||||
return "Removing add-ons that are no longer in the backup";
|
||||
}
|
||||
return "Restoring backup";
|
||||
}
|
||||
|
||||
private async _doRestoreBackup(password?: string) {
|
||||
if (!this._params) {
|
||||
return;
|
||||
}
|
||||
|
||||
const preferedAgent = getPreferredAgentForDownload(
|
||||
this._params.backup.agent_ids!
|
||||
);
|
||||
|
||||
const { addons, database_included, homeassistant_included, folders } =
|
||||
this._params.selectedData;
|
||||
|
||||
await restoreBackup(this.hass, {
|
||||
backup_id: this._params.backup.backup_id,
|
||||
agent_id: preferedAgent,
|
||||
password,
|
||||
restore_addons: addons.map((addon) => addon.slug),
|
||||
restore_database: database_included,
|
||||
restore_folders: folders,
|
||||
restore_homeassistant: homeassistant_included,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-md-dialog {
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
}
|
||||
.content p {
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
.destructive {
|
||||
--mdc-theme-primary: var(--error-color);
|
||||
}
|
||||
.centered {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
ha-circular-progress {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-dialog-restore-backup": DialogRestoreBackup;
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
|
||||
export interface RestoreBackupEncryptionKeyDialogParams {
|
||||
submit?: (value: string) => void;
|
||||
cancel?: () => void;
|
||||
}
|
||||
|
||||
export const loadRestoreBackupEncryptionKeyDialog = () =>
|
||||
import("./dialog-restore-backup-encryption-key");
|
||||
|
||||
export const showRestoreBackupEncryptionKeyDialog = (
|
||||
element: HTMLElement,
|
||||
params: RestoreBackupEncryptionKeyDialogParams
|
||||
) =>
|
||||
new Promise<string | null>((resolve) => {
|
||||
const origCancel = params.cancel;
|
||||
const origSubmit = params.submit;
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "ha-dialog-restore-backup-encryption-key",
|
||||
dialogImport: loadRestoreBackupEncryptionKeyDialog,
|
||||
dialogParams: {
|
||||
...params,
|
||||
cancel: () => {
|
||||
resolve(null);
|
||||
if (origCancel) {
|
||||
origCancel();
|
||||
}
|
||||
},
|
||||
submit: (response) => {
|
||||
resolve(response);
|
||||
if (origSubmit) {
|
||||
origSubmit(response);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
@ -0,0 +1,23 @@
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type {
|
||||
BackupContentExtended,
|
||||
BackupData,
|
||||
} from "../../../../data/backup";
|
||||
|
||||
export interface RestoreBackupDialogParams {
|
||||
backup: BackupContentExtended;
|
||||
selectedData: BackupData;
|
||||
}
|
||||
|
||||
export const loadRestoreBackupDialog = () => import("./dialog-restore-backup");
|
||||
|
||||
export const showRestoreBackupDialog = (
|
||||
element: HTMLElement,
|
||||
params: RestoreBackupDialogParams
|
||||
) => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "ha-dialog-restore-backup",
|
||||
dialogImport: loadRestoreBackupDialog,
|
||||
dialogParams: params,
|
||||
});
|
||||
};
|
@ -15,7 +15,7 @@ import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-md-list";
|
||||
import "../../../components/ha-md-list-item";
|
||||
import { getSignedPath } from "../../../data/auth";
|
||||
import type { BackupContentExtended } from "../../../data/backup";
|
||||
import type { BackupContentExtended, BackupData } from "../../../data/backup";
|
||||
import {
|
||||
compareAgents,
|
||||
computeBackupAgentName,
|
||||
@ -24,7 +24,6 @@ import {
|
||||
getBackupDownloadUrl,
|
||||
getPreferredAgentForDownload,
|
||||
isLocalAgent,
|
||||
restoreBackup,
|
||||
} from "../../../data/backup";
|
||||
import type { HassioAddonInfo } from "../../../data/hassio/addon";
|
||||
import "../../../layouts/hass-subpage";
|
||||
@ -34,7 +33,7 @@ import { bytesToString } from "../../../util/bytes-to-string";
|
||||
import { fileDownload } from "../../../util/file_download";
|
||||
import { showConfirmationDialog } from "../../lovelace/custom-card-helpers";
|
||||
import "./components/ha-backup-data-picker";
|
||||
import { showRestoreBackupEncryptionKeyDialog } from "./dialogs/show-dialog-restore-backup-encryption-key";
|
||||
import { showRestoreBackupDialog } from "./dialogs/show-dialog-restore-backup";
|
||||
|
||||
type Agent = {
|
||||
id: string;
|
||||
@ -66,7 +65,7 @@ class HaConfigBackupDetails extends LitElement {
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
@state() private _selectedBackup?: BackupContentExtended;
|
||||
@state() private _selectedData?: BackupData;
|
||||
|
||||
@state() private _addonsInfo?: HassioAddonInfo[];
|
||||
|
||||
@ -144,7 +143,7 @@ class HaConfigBackupDetails extends LitElement {
|
||||
<ha-backup-data-picker
|
||||
.hass=${this.hass}
|
||||
.data=${this._backup}
|
||||
.value=${this._selectedBackup}
|
||||
.value=${this._selectedData}
|
||||
@value-changed=${this._selectedBackupChanged}
|
||||
.addonsInfo=${this._addonsInfo}
|
||||
>
|
||||
@ -251,57 +250,28 @@ class HaConfigBackupDetails extends LitElement {
|
||||
|
||||
private _selectedBackupChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
this._selectedBackup = ev.detail.value;
|
||||
this._selectedData = ev.detail.value;
|
||||
}
|
||||
|
||||
private _isRestoreDisabled() {
|
||||
return (
|
||||
!this._selectedBackup ||
|
||||
!this._selectedData ||
|
||||
!(
|
||||
this._selectedBackup?.database_included ||
|
||||
this._selectedBackup?.homeassistant_included ||
|
||||
this._selectedBackup.addons.length ||
|
||||
this._selectedBackup.folders.length
|
||||
this._selectedData?.database_included ||
|
||||
this._selectedData?.homeassistant_included ||
|
||||
this._selectedData.addons.length ||
|
||||
this._selectedData.folders.length
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private async _restore() {
|
||||
let password: string | undefined;
|
||||
if (this._backup?.protected) {
|
||||
const response = await showRestoreBackupEncryptionKeyDialog(this, {});
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
password = response;
|
||||
} else {
|
||||
const response = await showConfirmationDialog(this, {
|
||||
title: "Restore backup",
|
||||
text: "The backup will be restored to your instance.",
|
||||
confirmText: "Restore",
|
||||
dismissText: "Cancel",
|
||||
destructive: true,
|
||||
});
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
private _restore() {
|
||||
if (!this._backup || !this._selectedData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const preferedAgent = getPreferredAgentForDownload(
|
||||
this._backup!.agent_ids!
|
||||
);
|
||||
|
||||
const { addons, database_included, homeassistant_included, folders } =
|
||||
this._selectedBackup!;
|
||||
|
||||
await restoreBackup(this.hass, {
|
||||
backup_id: this._backup!.backup_id,
|
||||
agent_id: preferedAgent,
|
||||
password: password,
|
||||
restore_addons: addons.map((addon) => addon.slug),
|
||||
restore_database: database_included,
|
||||
restore_folders: folders,
|
||||
restore_homeassistant: homeassistant_included,
|
||||
showRestoreBackupDialog(this, {
|
||||
backup: this._backup,
|
||||
selectedData: this._selectedData,
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user