diff --git a/hassio/src/backups/hassio-backups.ts b/hassio/src/backups/hassio-backups.ts index 8e8aebb183..382f8ec669 100644 --- a/hassio/src/backups/hassio-backups.ts +++ b/hassio/src/backups/hassio-backups.ts @@ -3,11 +3,11 @@ import { ActionDetail } from "@material/mwc-list"; import "@material/mwc-list/mwc-list-item"; import { mdiBackupRestore, mdiDelete, mdiDotsVertical, mdiPlus } from "@mdi/js"; import { - css, CSSResultGroup, - html, LitElement, PropertyValues, + css, + html, nothing, } from "lit"; import { customElement, property, query, state } from "lit/decorators"; @@ -26,9 +26,9 @@ import "../../../src/components/ha-fab"; import "../../../src/components/ha-icon-button"; import "../../../src/components/ha-svg-icon"; import { + HassioBackup, fetchHassioBackups, friendlyFolderName, - HassioBackup, reloadHassioBackups, removeBackup, } from "../../../src/data/hassio/backup"; @@ -43,6 +43,7 @@ import type { HaTabsSubpageDataTable } from "../../../src/layouts/hass-tabs-subp import { haStyle } from "../../../src/resources/styles"; import { HomeAssistant, Route } from "../../../src/types"; import { showBackupUploadDialog } from "../dialogs/backup/show-dialog-backup-upload"; +import { showHassioBackupLocationDialog } from "../dialogs/backup/show-dialog-hassio-backu-location"; import { showHassioBackupDialog } from "../dialogs/backup/show-dialog-hassio-backup"; import { showHassioCreateBackupDialog } from "../dialogs/backup/show-dialog-hassio-create-backup"; import { supervisorTabs } from "../hassio-tabs"; @@ -204,6 +205,9 @@ export class HassioBackups extends LitElement { ${this.supervisor.localize("common.reload")} + + ${this.supervisor.localize("dialog.backup_location.title")} + ${atLeastVersion(this.hass.config.version, 0, 116) ? html` ${this.supervisor.localize("backup.upload_backup")} @@ -270,6 +274,9 @@ export class HassioBackups extends LitElement { this.refreshData(); break; case 1: + showHassioBackupLocationDialog(this, { supervisor: this.supervisor }); + break; + case 2: this._showUploadBackupDialog(); break; } diff --git a/hassio/src/dialogs/backup/dialog-hassio-backup-location.ts b/hassio/src/dialogs/backup/dialog-hassio-backup-location.ts new file mode 100644 index 0000000000..18292149bd --- /dev/null +++ b/hassio/src/dialogs/backup/dialog-hassio-backup-location.ts @@ -0,0 +1,154 @@ +import "@material/mwc-button/mwc-button"; +import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; +import { fireEvent } from "../../../../src/common/dom/fire_event"; +import "../../../../src/components/ha-dialog"; +import "../../../../src/components/ha-form/ha-form"; +import type { SchemaUnion } from "../../../../src/components/ha-form/types"; +import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; +import { changeMountOptions } from "../../../../src/data/supervisor/mounts"; +import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; +import { HomeAssistant } from "../../../../src/types"; +import { HassioBackupLocationDialogParams } from "./show-dialog-hassio-backu-location"; + +const SCHEMA = memoizeOne( + () => + [ + { + name: "default_backup_mount", + required: true, + selector: { backup_location: {} }, + }, + ] as const +); + +@customElement("dialog-hassio-backup-location") +class HassioBackupLocationDialog extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) + public _dialogParams?: HassioBackupLocationDialogParams; + + @state() private _data?: { default_backup_mount: string | null }; + + @state() private _waiting?: boolean; + + @state() private _error?: string; + + public async showDialog( + dialogParams: HassioBackupLocationDialogParams + ): Promise { + this._dialogParams = dialogParams; + } + + public closeDialog(): void { + this._data = undefined; + this._error = undefined; + this._waiting = undefined; + this._dialogParams = undefined; + fireEvent(this, "dialog-closed", { dialog: this.localName }); + } + + protected render() { + if (!this._dialogParams) { + return nothing; + } + return html` + + ${this._error + ? html`${this._error}` + : nothing} + + + + ${this._dialogParams.supervisor.localize("common.cancel")} + + + ${this._dialogParams.supervisor.localize("common.save")} + + + `; + } + + private _computeLabelCallback = ( + // @ts-ignore + schema: SchemaUnion> + ): string => + this._dialogParams!.supervisor.localize( + `dialog.backup_location.options.${schema.name}.name` + ) || schema.name; + + private _computeHelperCallback = ( + // @ts-ignore + schema: SchemaUnion> + ): string => + this._dialogParams!.supervisor.localize( + `dialog.backup_location.options.${schema.name}.description` + ); + + private _valueChanged(ev: CustomEvent) { + const newLocation = ev.detail.value.default_backup_mount; + this._data = { + default_backup_mount: newLocation === "/backup" ? null : newLocation, + }; + } + + private async _changeMount() { + if (!this._data) { + return; + } + this._error = undefined; + this._waiting = true; + try { + await changeMountOptions(this.hass, this._data); + } catch (err: any) { + this._error = extractApiErrorMessage(err); + this._waiting = false; + return; + } + this.closeDialog(); + } + + static get styles(): CSSResultGroup { + return [ + haStyle, + haStyleDialog, + css` + .delete-btn { + --mdc-theme-primary: var(--error-color); + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "dialog-hassio-backup-location": HassioBackupLocationDialog; + } +} diff --git a/hassio/src/dialogs/backup/show-dialog-hassio-backu-location.ts b/hassio/src/dialogs/backup/show-dialog-hassio-backu-location.ts new file mode 100644 index 0000000000..43a82f1141 --- /dev/null +++ b/hassio/src/dialogs/backup/show-dialog-hassio-backu-location.ts @@ -0,0 +1,17 @@ +import { fireEvent } from "../../../../src/common/dom/fire_event"; +import { Supervisor } from "../../../../src/data/supervisor/supervisor"; + +export interface HassioBackupLocationDialogParams { + supervisor: Supervisor; +} + +export const showHassioBackupLocationDialog = ( + element: HTMLElement, + dialogParams: HassioBackupLocationDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-hassio-backup-location", + dialogImport: () => import("./dialog-hassio-backup-location"), + dialogParams, + }); +}; diff --git a/src/components/ha-mount-picker.ts b/src/components/ha-mount-picker.ts index d7bdc80af5..6e0da26b4a 100644 --- a/src/components/ha-mount-picker.ts +++ b/src/components/ha-mount-picker.ts @@ -55,9 +55,10 @@ class HaMountPicker extends LitElement { graphic="icon" .value=${__BACKUP_DATA_DISK__} > - ${this.hass.localize("ui.components.mount-picker.use_datadisk")} + + ${this.hass.localize("ui.components.mount-picker.use_datadisk") || + "Use data disk for backup"} + `; return html` @@ -91,7 +92,7 @@ class HaMountPicker extends LitElement { ? `:${mount.port}` : nothing}${mount.type === SupervisorMountType.NFS ? mount.path - : ` :${mount.share}`} ${mount.state !== SupervisorMountState.ACTIVE ? html`