2021-05-25 21:29:32 +02:00
|
|
|
import { ActionDetail } from "@material/mwc-list";
|
|
|
|
import "@material/mwc-list/mwc-list-item";
|
2021-06-08 17:57:53 +02:00
|
|
|
import { mdiClose, mdiDotsVertical } from "@mdi/js";
|
2023-02-28 11:02:47 +01:00
|
|
|
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
2021-05-25 21:29:32 +02:00
|
|
|
import { customElement, property, query, state } from "lit/decorators";
|
2023-02-28 11:02:47 +01:00
|
|
|
import { atLeastVersion } from "../../../../src/common/config/version";
|
2020-09-29 20:30:25 +02:00
|
|
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
2023-02-28 11:02:47 +01:00
|
|
|
import { stopPropagation } from "../../../../src/common/dom/stop_propagation";
|
2021-05-26 21:56:27 +02:00
|
|
|
import { slugify } from "../../../../src/common/string/slugify";
|
2021-05-25 21:29:32 +02:00
|
|
|
import "../../../../src/components/buttons/ha-progress-button";
|
2021-08-27 16:45:05 +02:00
|
|
|
import "../../../../src/components/ha-alert";
|
2021-05-25 21:29:32 +02:00
|
|
|
import "../../../../src/components/ha-button-menu";
|
2021-06-08 17:57:53 +02:00
|
|
|
import "../../../../src/components/ha-header-bar";
|
2021-10-14 15:44:20 +02:00
|
|
|
import "../../../../src/components/ha-icon-button";
|
2020-04-14 18:05:45 +02:00
|
|
|
import { getSignedPath } from "../../../../src/data/auth";
|
2020-01-26 20:37:20 +01:00
|
|
|
import {
|
2021-08-12 11:56:13 +02:00
|
|
|
fetchHassioBackupInfo,
|
|
|
|
HassioBackupDetail,
|
2023-03-09 11:32:52 +01:00
|
|
|
removeBackup,
|
2021-08-12 11:56:13 +02:00
|
|
|
} from "../../../../src/data/hassio/backup";
|
2023-02-28 11:02:47 +01:00
|
|
|
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
2021-02-08 16:18:33 +01:00
|
|
|
import {
|
|
|
|
showAlertDialog,
|
|
|
|
showConfirmationDialog,
|
|
|
|
} from "../../../../src/dialogs/generic/show-dialog-box";
|
2021-05-21 09:09:31 +02:00
|
|
|
import { HassDialog } from "../../../../src/dialogs/make-dialog-manager";
|
2020-09-29 20:30:25 +02:00
|
|
|
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
2020-01-26 20:37:20 +01:00
|
|
|
import { HomeAssistant } from "../../../../src/types";
|
2021-06-07 10:15:43 +02:00
|
|
|
import { fileDownload } from "../../../../src/util/file_download";
|
2021-08-12 11:56:13 +02:00
|
|
|
import "../../components/supervisor-backup-content";
|
|
|
|
import type { SupervisorBackupContent } from "../../components/supervisor-backup-content";
|
|
|
|
import { HassioBackupDialogParams } from "./show-dialog-hassio-backup";
|
2019-04-10 00:50:02 +02:00
|
|
|
|
2021-08-12 11:56:13 +02:00
|
|
|
@customElement("dialog-hassio-backup")
|
|
|
|
class HassioBackupDialog
|
2021-05-21 09:09:31 +02:00
|
|
|
extends LitElement
|
2021-08-12 11:56:13 +02:00
|
|
|
implements HassDialog<HassioBackupDialogParams>
|
2021-07-15 12:08:04 +02:00
|
|
|
{
|
2021-11-04 13:47:30 +01:00
|
|
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
2020-04-14 18:05:45 +02:00
|
|
|
|
2021-05-07 22:16:14 +02:00
|
|
|
@state() private _error?: string;
|
2020-04-14 18:05:45 +02:00
|
|
|
|
2021-08-12 11:56:13 +02:00
|
|
|
@state() private _backup?: HassioBackupDetail;
|
2020-04-14 18:05:45 +02:00
|
|
|
|
2021-08-12 11:56:13 +02:00
|
|
|
@state() private _dialogParams?: HassioBackupDialogParams;
|
2020-04-14 18:05:45 +02:00
|
|
|
|
2021-08-12 11:56:13 +02:00
|
|
|
@state() private _restoringBackup = false;
|
2020-04-14 18:05:45 +02:00
|
|
|
|
2021-08-12 11:56:13 +02:00
|
|
|
@query("supervisor-backup-content")
|
|
|
|
private _backupContent!: SupervisorBackupContent;
|
2020-04-14 18:05:45 +02:00
|
|
|
|
2022-01-25 17:36:35 +01:00
|
|
|
public async showDialog(dialogParams: HassioBackupDialogParams) {
|
|
|
|
this._backup = await fetchHassioBackupInfo(this.hass, dialogParams.slug);
|
|
|
|
this._dialogParams = dialogParams;
|
2021-08-12 11:56:13 +02:00
|
|
|
this._restoringBackup = false;
|
2020-01-26 20:37:20 +01:00
|
|
|
}
|
|
|
|
|
2021-05-21 09:09:31 +02:00
|
|
|
public closeDialog() {
|
2021-08-12 11:56:13 +02:00
|
|
|
this._backup = undefined;
|
2021-05-25 21:29:32 +02:00
|
|
|
this._dialogParams = undefined;
|
2021-08-12 11:56:13 +02:00
|
|
|
this._restoringBackup = false;
|
2021-05-25 21:29:32 +02:00
|
|
|
this._error = undefined;
|
2021-05-21 09:09:31 +02:00
|
|
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
|
|
|
}
|
|
|
|
|
2023-02-28 11:02:47 +01:00
|
|
|
protected render() {
|
2021-08-12 11:56:13 +02:00
|
|
|
if (!this._dialogParams || !this._backup) {
|
2023-02-28 11:02:47 +01:00
|
|
|
return nothing;
|
2020-01-26 20:37:20 +01:00
|
|
|
}
|
2018-05-15 19:31:47 +02:00
|
|
|
return html`
|
2021-05-25 21:29:32 +02:00
|
|
|
<ha-dialog
|
|
|
|
open
|
2021-05-26 11:10:27 +02:00
|
|
|
scrimClickAction
|
|
|
|
@closed=${this.closeDialog}
|
2022-02-03 15:54:37 +01:00
|
|
|
.heading=${this._backup.name}
|
2021-05-25 21:29:32 +02:00
|
|
|
>
|
2021-06-08 17:57:53 +02:00
|
|
|
<div slot="heading">
|
|
|
|
<ha-header-bar>
|
2021-08-12 11:56:13 +02:00
|
|
|
<span slot="title">${this._backup.name}</span>
|
2021-10-14 15:44:20 +02:00
|
|
|
<ha-icon-button
|
2022-01-25 17:36:35 +01:00
|
|
|
.label=${this.hass?.localize("ui.common.close") || "Close"}
|
2021-10-14 15:44:20 +02:00
|
|
|
.path=${mdiClose}
|
|
|
|
slot="actionItems"
|
|
|
|
dialogAction="cancel"
|
|
|
|
></ha-icon-button>
|
2021-06-08 17:57:53 +02:00
|
|
|
</ha-header-bar>
|
|
|
|
</div>
|
2021-08-12 11:56:13 +02:00
|
|
|
${this._restoringBackup
|
2021-05-25 21:29:32 +02:00
|
|
|
? html` <ha-circular-progress active></ha-circular-progress>`
|
2021-08-12 11:56:13 +02:00
|
|
|
: html`<supervisor-backup-content
|
2021-05-25 21:29:32 +02:00
|
|
|
.hass=${this.hass}
|
|
|
|
.supervisor=${this._dialogParams.supervisor}
|
2021-08-12 11:56:13 +02:00
|
|
|
.backup=${this._backup}
|
2021-06-08 17:57:53 +02:00
|
|
|
.onboarding=${this._dialogParams.onboarding || false}
|
|
|
|
.localize=${this._dialogParams.localize}
|
2022-02-21 17:02:55 +01:00
|
|
|
dialogInitialFocus
|
2021-05-25 21:29:32 +02:00
|
|
|
>
|
2021-08-12 11:56:13 +02:00
|
|
|
</supervisor-backup-content>`}
|
2021-08-27 16:45:05 +02:00
|
|
|
${this._error
|
|
|
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
|
|
|
: ""}
|
2021-05-25 21:29:32 +02:00
|
|
|
|
|
|
|
<mwc-button
|
2021-08-12 11:56:13 +02:00
|
|
|
.disabled=${this._restoringBackup}
|
2021-05-25 21:29:32 +02:00
|
|
|
slot="secondaryAction"
|
|
|
|
@click=${this._restoreClicked}
|
|
|
|
>
|
|
|
|
Restore
|
|
|
|
</mwc-button>
|
|
|
|
|
2021-06-08 17:57:53 +02:00
|
|
|
${!this._dialogParams.onboarding
|
|
|
|
? html`<ha-button-menu
|
|
|
|
fixed
|
|
|
|
slot="primaryAction"
|
|
|
|
@action=${this._handleMenuAction}
|
2021-09-30 17:46:03 +02:00
|
|
|
@closed=${stopPropagation}
|
2021-06-08 17:57:53 +02:00
|
|
|
>
|
2021-10-14 15:44:20 +02:00
|
|
|
<ha-icon-button
|
2022-01-25 17:36:35 +01:00
|
|
|
.label=${this.hass!.localize("ui.common.menu") || "Menu"}
|
2021-10-14 15:44:20 +02:00
|
|
|
.path=${mdiDotsVertical}
|
|
|
|
slot="trigger"
|
|
|
|
></ha-icon-button>
|
2022-01-25 17:36:35 +01:00
|
|
|
<mwc-list-item
|
|
|
|
>${this._dialogParams.supervisor?.localize(
|
|
|
|
"backup.download_backup"
|
|
|
|
)}</mwc-list-item
|
|
|
|
>
|
|
|
|
<mwc-list-item class="error"
|
|
|
|
>${this._dialogParams.supervisor?.localize(
|
|
|
|
"backup.delete_backup_title"
|
|
|
|
)}</mwc-list-item
|
|
|
|
>
|
2021-06-08 17:57:53 +02:00
|
|
|
</ha-button-menu>`
|
|
|
|
: ""}
|
2020-05-08 13:10:24 +02:00
|
|
|
</ha-dialog>
|
2020-01-26 20:37:20 +01:00
|
|
|
`;
|
|
|
|
}
|
|
|
|
|
2021-05-07 22:16:14 +02:00
|
|
|
static get styles(): CSSResultGroup {
|
2020-01-26 20:37:20 +01:00
|
|
|
return [
|
2020-09-29 20:30:25 +02:00
|
|
|
haStyle,
|
2020-01-26 20:37:20 +01:00
|
|
|
haStyleDialog,
|
|
|
|
css`
|
2021-05-25 21:29:32 +02:00
|
|
|
ha-circular-progress {
|
|
|
|
display: block;
|
|
|
|
text-align: center;
|
2020-09-29 20:30:25 +02:00
|
|
|
}
|
2021-06-08 17:57:53 +02:00
|
|
|
ha-header-bar {
|
|
|
|
--mdc-theme-on-primary: var(--primary-text-color);
|
|
|
|
--mdc-theme-primary: var(--mdc-theme-surface);
|
|
|
|
flex-shrink: 0;
|
|
|
|
display: block;
|
|
|
|
}
|
2021-10-20 10:41:56 +02:00
|
|
|
ha-icon-button {
|
|
|
|
color: var(--secondary-text-color);
|
|
|
|
}
|
2020-01-26 20:37:20 +01:00
|
|
|
`,
|
|
|
|
];
|
2018-05-15 19:31:47 +02:00
|
|
|
}
|
2018-02-08 22:16:13 +01:00
|
|
|
|
2021-05-25 21:29:32 +02:00
|
|
|
private _handleMenuAction(ev: CustomEvent<ActionDetail>) {
|
|
|
|
switch (ev.detail.index) {
|
|
|
|
case 0:
|
|
|
|
this._downloadClicked();
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
this._deleteClicked();
|
|
|
|
break;
|
|
|
|
}
|
2018-02-08 22:16:13 +01:00
|
|
|
}
|
|
|
|
|
2021-05-25 21:29:32 +02:00
|
|
|
private async _restoreClicked() {
|
2021-08-12 11:56:13 +02:00
|
|
|
const backupDetails = this._backupContent.backupDetails();
|
|
|
|
this._restoringBackup = true;
|
|
|
|
if (this._backupContent.backupType === "full") {
|
|
|
|
await this._fullRestoreClicked(backupDetails);
|
2021-05-25 21:29:32 +02:00
|
|
|
} else {
|
2021-08-12 11:56:13 +02:00
|
|
|
await this._partialRestoreClicked(backupDetails);
|
2021-05-25 21:29:32 +02:00
|
|
|
}
|
2021-08-12 11:56:13 +02:00
|
|
|
this._restoringBackup = false;
|
2018-02-08 22:16:13 +01:00
|
|
|
}
|
|
|
|
|
2021-08-12 11:56:13 +02:00
|
|
|
private async _partialRestoreClicked(backupDetails) {
|
2021-02-08 16:18:33 +01:00
|
|
|
if (
|
2021-05-25 21:29:32 +02:00
|
|
|
this._dialogParams?.supervisor !== undefined &&
|
|
|
|
this._dialogParams?.supervisor.info.state !== "running"
|
2021-02-08 16:18:33 +01:00
|
|
|
) {
|
|
|
|
await showAlertDialog(this, {
|
2021-08-12 11:56:13 +02:00
|
|
|
title: "Could not restore backup",
|
|
|
|
text: `Restoring a backup is not possible right now because the system is in ${this._dialogParams?.supervisor.info.state} state.`,
|
2021-02-08 16:18:33 +01:00
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2020-08-24 18:36:47 +02:00
|
|
|
if (
|
|
|
|
!(await showConfirmationDialog(this, {
|
2021-08-12 11:56:13 +02:00
|
|
|
title: "Are you sure you want partially to restore this backup?",
|
2020-09-29 20:30:25 +02:00
|
|
|
confirmText: "restore",
|
|
|
|
dismissText: "cancel",
|
2020-08-24 18:36:47 +02:00
|
|
|
}))
|
|
|
|
) {
|
2018-02-08 22:16:13 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-01-26 20:37:20 +01:00
|
|
|
|
2021-05-25 21:29:32 +02:00
|
|
|
if (!this._dialogParams?.onboarding) {
|
2022-07-11 12:50:37 +02:00
|
|
|
try {
|
|
|
|
await this.hass!.callApi(
|
|
|
|
"POST",
|
|
|
|
|
|
|
|
`hassio/${
|
|
|
|
atLeastVersion(this.hass!.config.version, 2021, 9)
|
|
|
|
? "backups"
|
|
|
|
: "snapshots"
|
|
|
|
}/${this._backup!.slug}/restore/partial`,
|
|
|
|
backupDetails
|
|
|
|
);
|
|
|
|
this.closeDialog();
|
|
|
|
} catch (error: any) {
|
|
|
|
this._error = error.body.message;
|
|
|
|
}
|
2020-09-29 20:30:25 +02:00
|
|
|
} else {
|
|
|
|
fireEvent(this, "restoring");
|
2022-07-11 12:50:37 +02:00
|
|
|
await fetch(`/api/hassio/backups/${this._backup!.slug}/restore/partial`, {
|
2020-09-29 20:30:25 +02:00
|
|
|
method: "POST",
|
2021-08-12 11:56:13 +02:00
|
|
|
body: JSON.stringify(backupDetails),
|
2020-09-29 20:30:25 +02:00
|
|
|
});
|
2021-05-21 09:09:31 +02:00
|
|
|
this.closeDialog();
|
2020-09-29 20:30:25 +02:00
|
|
|
}
|
2018-02-08 22:16:13 +01:00
|
|
|
}
|
|
|
|
|
2021-08-12 11:56:13 +02:00
|
|
|
private async _fullRestoreClicked(backupDetails) {
|
2021-02-08 16:18:33 +01:00
|
|
|
if (
|
2021-05-25 21:29:32 +02:00
|
|
|
this._dialogParams?.supervisor !== undefined &&
|
|
|
|
this._dialogParams?.supervisor.info.state !== "running"
|
2021-02-08 16:18:33 +01:00
|
|
|
) {
|
|
|
|
await showAlertDialog(this, {
|
2021-08-12 11:56:13 +02:00
|
|
|
title: "Could not restore backup",
|
|
|
|
text: `Restoring a backup is not possible right now because the system is in ${this._dialogParams?.supervisor.info.state} state.`,
|
2021-02-08 16:18:33 +01:00
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2020-08-24 18:36:47 +02:00
|
|
|
if (
|
|
|
|
!(await showConfirmationDialog(this, {
|
|
|
|
title:
|
2021-08-12 11:56:13 +02:00
|
|
|
"Are you sure you want to wipe your system and restore this backup?",
|
2020-09-29 20:30:25 +02:00
|
|
|
confirmText: "restore",
|
|
|
|
dismissText: "cancel",
|
2020-08-24 18:36:47 +02:00
|
|
|
}))
|
|
|
|
) {
|
2018-02-08 22:16:13 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-01-26 20:37:20 +01:00
|
|
|
|
2021-05-25 21:29:32 +02:00
|
|
|
if (!this._dialogParams?.onboarding) {
|
2021-11-04 13:47:30 +01:00
|
|
|
this.hass!.callApi(
|
|
|
|
"POST",
|
|
|
|
`hassio/${
|
|
|
|
atLeastVersion(this.hass!.config.version, 2021, 9)
|
|
|
|
? "backups"
|
|
|
|
: "snapshots"
|
|
|
|
}/${this._backup!.slug}/restore/full`,
|
|
|
|
backupDetails
|
|
|
|
).then(
|
|
|
|
() => {
|
|
|
|
this.closeDialog();
|
|
|
|
},
|
|
|
|
(error) => {
|
|
|
|
this._error = error.body.message;
|
|
|
|
}
|
|
|
|
);
|
2020-09-29 20:30:25 +02:00
|
|
|
} else {
|
|
|
|
fireEvent(this, "restoring");
|
2021-08-12 11:56:13 +02:00
|
|
|
fetch(`/api/hassio/backups/${this._backup!.slug}/restore/full`, {
|
2020-09-29 20:30:25 +02:00
|
|
|
method: "POST",
|
2021-08-12 11:56:13 +02:00
|
|
|
body: JSON.stringify(backupDetails),
|
2020-09-29 20:30:25 +02:00
|
|
|
});
|
2021-05-21 09:09:31 +02:00
|
|
|
this.closeDialog();
|
2020-09-29 20:30:25 +02:00
|
|
|
}
|
2018-02-08 22:16:13 +01:00
|
|
|
}
|
|
|
|
|
2020-08-24 18:36:47 +02:00
|
|
|
private async _deleteClicked() {
|
|
|
|
if (
|
|
|
|
!(await showConfirmationDialog(this, {
|
2021-08-12 11:56:13 +02:00
|
|
|
title: "Are you sure you want to delete this backup?",
|
2020-09-29 20:30:25 +02:00
|
|
|
confirmText: "delete",
|
|
|
|
dismissText: "cancel",
|
2020-08-24 18:36:47 +02:00
|
|
|
}))
|
|
|
|
) {
|
2018-02-08 22:16:13 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-01-26 20:37:20 +01:00
|
|
|
|
2023-03-09 11:32:52 +01:00
|
|
|
try {
|
|
|
|
await removeBackup(this.hass!, this._backup!.slug);
|
|
|
|
if (this._dialogParams!.onDelete) {
|
|
|
|
this._dialogParams!.onDelete();
|
2021-11-04 13:47:30 +01:00
|
|
|
}
|
2023-03-09 11:32:52 +01:00
|
|
|
this.closeDialog();
|
|
|
|
} catch (err: any) {
|
|
|
|
this._error = err.body.message;
|
|
|
|
}
|
2018-02-08 22:16:13 +01:00
|
|
|
}
|
|
|
|
|
2020-01-26 20:37:20 +01:00
|
|
|
private async _downloadClicked() {
|
|
|
|
let signedPath: { path: string };
|
2018-11-21 19:28:48 +01:00
|
|
|
try {
|
|
|
|
signedPath = await getSignedPath(
|
2021-11-04 13:47:30 +01:00
|
|
|
this.hass!,
|
2021-08-12 11:56:13 +02:00
|
|
|
`/api/hassio/${
|
2021-11-04 13:47:30 +01:00
|
|
|
atLeastVersion(this.hass!.config.version, 2021, 9)
|
2021-08-12 11:56:13 +02:00
|
|
|
? "backups"
|
|
|
|
: "snapshots"
|
|
|
|
}/${this._backup!.slug}/download`
|
2018-11-21 19:28:48 +01:00
|
|
|
);
|
2021-09-30 12:39:03 +02:00
|
|
|
} catch (err: any) {
|
2021-05-25 21:29:32 +02:00
|
|
|
await showAlertDialog(this, {
|
|
|
|
text: extractApiErrorMessage(err),
|
|
|
|
});
|
2018-11-21 19:28:48 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-01-26 20:37:20 +01:00
|
|
|
|
2020-10-08 15:06:42 +02:00
|
|
|
if (window.location.href.includes("ui.nabu.casa")) {
|
|
|
|
const confirm = await showConfirmationDialog(this, {
|
|
|
|
title: "Potential slow download",
|
2021-08-12 11:56:13 +02:00
|
|
|
text: "Downloading backups over the Nabu Casa URL will take some time, it is recomended to use your local URL instead, do you want to continue?",
|
2020-10-08 15:06:42 +02:00
|
|
|
confirmText: "continue",
|
|
|
|
dismissText: "cancel",
|
|
|
|
});
|
|
|
|
if (!confirm) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-07 10:15:43 +02:00
|
|
|
fileDownload(
|
|
|
|
signedPath.path,
|
2021-08-12 11:56:13 +02:00
|
|
|
`home_assistant_backup_${slugify(this._computeName)}.tar`
|
2021-06-07 10:15:43 +02:00
|
|
|
);
|
2018-02-08 22:16:13 +01:00
|
|
|
}
|
|
|
|
|
2020-01-26 20:37:20 +01:00
|
|
|
private get _computeName() {
|
2021-08-12 11:56:13 +02:00
|
|
|
return this._backup
|
|
|
|
? this._backup.name || this._backup.slug
|
|
|
|
: "Unnamed backup";
|
2018-02-08 22:16:13 +01:00
|
|
|
}
|
2019-04-07 17:45:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
declare global {
|
|
|
|
interface HTMLElementTagNameMap {
|
2021-08-12 11:56:13 +02:00
|
|
|
"dialog-hassio-backup": HassioBackupDialog;
|
2018-02-08 22:16:13 +01:00
|
|
|
}
|
|
|
|
}
|