From de0c375ea2d6ceb4e96cdf39a453094d3fca7856 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Mon, 9 Dec 2024 13:43:08 +0100 Subject: [PATCH] Handle backup state --- src/components/ha-file-upload.ts | 17 +++- src/data/backup.ts | 17 ---- src/data/backup_manager.ts | 99 +++++++++++++++++++ .../components/ha-backup-summary-card.ts | 6 +- .../backup/ha-config-backup-dashboard.ts | 39 ++++++-- 5 files changed, 147 insertions(+), 31 deletions(-) create mode 100644 src/data/backup_manager.ts diff --git a/src/components/ha-file-upload.ts b/src/components/ha-file-upload.ts index bd55538ef9bb..f68e52f673a3 100644 --- a/src/components/ha-file-upload.ts +++ b/src/components/ha-file-upload.ts @@ -56,6 +56,21 @@ export class HaFileUpload extends LitElement { } } + private get _name() { + if (this.value === undefined) { + return ""; + } + if (typeof this.value === "string") { + return this.value; + } + const files = + this.value instanceof FileList + ? Array.from(this.value) + : ensureArray(this.value); + + return files.map((file) => file.name).join(", "); + } + public render(): TemplateResult { return html` ${this.uploading @@ -65,7 +80,7 @@ export class HaFileUpload extends LitElement { >${this.value ? this.hass?.localize( "ui.components.file-upload.uploading_name", - { name: this.value.toString() } + { name: this._name } ) : this.hass?.localize( "ui.components.file-upload.uploading" diff --git a/src/data/backup.ts b/src/data/backup.ts index ed446e226a9e..b66d1e2eaf7c 100644 --- a/src/data/backup.ts +++ b/src/data/backup.ts @@ -196,23 +196,6 @@ export const uploadBackup = async ( } }; -type BackupEvent = BackupProgressEvent; - -type BackupProgressEvent = { - event_type: "backup_progress"; - done: boolean; - stage: string; - success?: boolean; -}; - -export const subscribeBackupEvents = ( - hass: HomeAssistant, - callback: (event: BackupEvent) => void -) => - hass.connection.subscribeMessage(callback, { - type: "backup/subscribe_events", - }); - export const getPreferredAgentForDownload = (agents: string[]) => { const localAgents = agents.filter( (agent) => agent.split(".")[0] === "backup" diff --git a/src/data/backup_manager.ts b/src/data/backup_manager.ts new file mode 100644 index 000000000000..f91d50607bfe --- /dev/null +++ b/src/data/backup_manager.ts @@ -0,0 +1,99 @@ +import type { HomeAssistant } from "../types"; + +export enum BackupManagerState { + IDLE = "idle", + CREATE_BACKUP = "create_backup", + RECEIVE_BACKUP = "receive_backup", + RESTORE_BACKUP = "restore_backup", +} + +export enum CreateBackupStage { + ADDON_REPOSITORIES = "addon_repositories", + ADDONS = "addons", + AWAIT_ADDON_RESTARTS = "await_addon_restarts", + DOCKER_CONFIG = "docker_config", + FINISHING_FILE = "finishing_file", + FOLDERS = "folders", + HOME_ASSISTANT = "home_assistant", + UPLOAD_TO_AGENTS = "upload_to_agents", +} + +export enum CreateBackupState { + COMPLETED = "completed", + FAILED = "failed", + IN_PROGRESS = "in_progress", +} + +export enum ReceiveBackupStage { + RECEIVE_FILE = "receive_file", + UPLOAD_TO_AGENTS = "upload_to_agents", +} + +export enum ReceiveBackupState { + COMPLETED = "completed", + FAILED = "failed", + IN_PROGRESS = "in_progress", +} + +export enum RestoreBackupStage { + ADDON_REPOSITORIES = "addon_repositories", + ADDONS = "addons", + AWAIT_ADDON_RESTARTS = "await_addon_restarts", + AWAIT_HOME_ASSISTANT_RESTART = "await_home_assistant_restart", + CHECK_HOME_ASSISTANT = "check_home_assistant", + DOCKER_CONFIG = "docker_config", + DOWNLOAD_FROM_AGENT = "download_from_agent", + FOLDERS = "folders", + HOME_ASSISTANT = "home_assistant", + REMOVE_DELTA_ADDONS = "remove_delta_addons", +} + +export enum RestoreBackupState { + COMPLETED = "completed", + FAILED = "failed", + IN_PROGRESS = "in_progress", +} + +type IdleEvent = { + manager_state: BackupManagerState.IDLE; +}; + +type CreateBackupEvent = { + manager_state: BackupManagerState.CREATE_BACKUP; + stage: CreateBackupStage | null; + state: CreateBackupState; +}; + +type ReceiveBackupEvent = { + manager_state: BackupManagerState.RECEIVE_BACKUP; + stage: ReceiveBackupStage | null; + state: ReceiveBackupState; +}; + +type RestoreBackupEvent = { + manager_state: BackupManagerState.RESTORE_BACKUP; + stage: RestoreBackupStage | null; + state: RestoreBackupState; +}; + +export type ManagerStateEvent = + | IdleEvent + | CreateBackupEvent + | ReceiveBackupEvent + | RestoreBackupEvent; + +export const subscribeBackupEvents = ( + hass: HomeAssistant, + callback: (event: ManagerStateEvent) => void +) => + hass.connection.subscribeMessage(callback, { + type: "backup/subscribe_events", + }); + +export const isBackupInProgress = (state: ManagerStateEvent) => + (state.manager_state === BackupManagerState.CREATE_BACKUP && + state.state === CreateBackupState.IN_PROGRESS) || + (state.manager_state === BackupManagerState.RECEIVE_BACKUP && + state.state === ReceiveBackupState.IN_PROGRESS) || + (state.manager_state === BackupManagerState.RESTORE_BACKUP && + state.state === RestoreBackupState.IN_PROGRESS); diff --git a/src/panels/config/backup/components/ha-backup-summary-card.ts b/src/panels/config/backup/components/ha-backup-summary-card.ts index 8ac74ed9302a..0efef8c3b5be 100644 --- a/src/panels/config/backup/components/ha-backup-summary-card.ts +++ b/src/panels/config/backup/components/ha-backup-summary-card.ts @@ -25,7 +25,7 @@ const ICONS: Record = { @customElement("ha-backup-summary-card") class HaBackupSummaryCard extends LitElement { @property() - public title!: string; + public heading!: string; @property() public description!: string; @@ -49,7 +49,7 @@ class HaBackupSummaryCard extends LitElement { `}
-

${this.title}

+

${this.heading}

${this.description}

${this.hasAction @@ -116,7 +116,7 @@ class HaBackupSummaryCard extends LitElement { flex: 1; min-width: 0; } - .title { + .heading { font-size: 22px; font-style: normal; font-weight: 400; diff --git a/src/panels/config/backup/ha-config-backup-dashboard.ts b/src/panels/config/backup/ha-config-backup-dashboard.ts index c6cfea082cf2..d57a3ab5c3e3 100644 --- a/src/panels/config/backup/ha-config-backup-dashboard.ts +++ b/src/panels/config/backup/ha-config-backup-dashboard.ts @@ -13,6 +13,7 @@ import memoizeOne from "memoize-one"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { relativeTime } from "../../../common/datetime/relative_time"; import type { HASSDomEvent } from "../../../common/dom/fire_event"; +import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event"; import { navigate } from "../../../common/navigate"; import type { LocalizeFunc } from "../../../common/translations/localize"; import type { @@ -43,9 +44,14 @@ import { generateBackup, getBackupDownloadUrl, getPreferredAgentForDownload, - subscribeBackupEvents, updateBackupConfig, } from "../../../data/backup"; +import type { ManagerStateEvent } from "../../../data/backup_manager"; +import { + BackupManagerState, + isBackupInProgress, + subscribeBackupEvents, +} from "../../../data/backup_manager"; import { extractApiErrorMessage } from "../../../data/hassio/common"; import { showAlertDialog, @@ -62,9 +68,8 @@ import { fileDownload } from "../../../util/file_download"; import "./components/ha-backup-summary-card"; import { showGenerateBackupDialog } from "./dialogs/show-dialog-generate-backup"; import { showNewBackupDialog } from "./dialogs/show-dialog-new-backup"; -import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event"; -import { showUploadBackupDialog } from "./dialogs/show-dialog-upload-backup"; import { showSetBackupEncryptionKeyDialog } from "./dialogs/show-dialog-set-backup-encryption-key"; +import { showUploadBackupDialog } from "./dialogs/show-dialog-upload-backup"; @customElement("ha-config-backup-dashboard") class HaConfigBackupDashboard extends SubscribeMixin(LitElement) { @@ -74,7 +79,9 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) { @property({ attribute: false }) public route!: Route; - @state() private _backupInProgress = false; + @state() private _manager: ManagerStateEvent = { + manager_state: BackupManagerState.IDLE, + }; @state() private _backups: BackupContent[] = []; @@ -172,6 +179,8 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) { } protected render(): TemplateResult { + const backupInProgress = isBackupInProgress(this._manager); + return html` { - if (event.event_type === "backup_progress" && event.done) { + this._manager = event; + const isProgress = isBackupInProgress(this._manager); + if (isProgress !== this._isProgress) { + this._isProgress = isProgress; this._fetchBackupInfo(); } }); @@ -336,7 +350,6 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) { private async _fetchBackupInfo() { const info = await fetchBackupInfo(this.hass); this._backups = info.backups; - this._backupInProgress = info.backing_up; } private async _fetchBackupConfig() { @@ -391,6 +404,12 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) { return; } + if (!isComponentLoaded(this.hass, "hassio")) { + delete params.include_folders; + delete params.include_all_addons; + delete params.include_addons; + } + this._generateBackup(params); return; }