From fd32efac3575b65c8d28b04be169bbef2f37ba3b Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Thu, 19 Dec 2024 17:34:04 +0100 Subject: [PATCH] Simplify fetching logic --- .../config/backup/ha-config-backup-backups.ts | 112 ++------------ .../backup/ha-config-backup-locations.ts | 138 ------------------ .../backup/ha-config-backup-overview.ts | 65 +++------ .../backup/ha-config-backup-settings.ts | 102 ++++--------- src/panels/config/backup/ha-config-backup.ts | 68 ++++++++- 5 files changed, 124 insertions(+), 361 deletions(-) delete mode 100644 src/panels/config/backup/ha-config-backup-locations.ts diff --git a/src/panels/config/backup/ha-config-backup-backups.ts b/src/panels/config/backup/ha-config-backup-backups.ts index 2d00aed0fa79..d095f4d46e10 100644 --- a/src/panels/config/backup/ha-config-backup-backups.ts +++ b/src/panels/config/backup/ha-config-backup-backups.ts @@ -6,14 +6,14 @@ import { mdiPlus, mdiUpload, } from "@mdi/js"; -import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit"; +import type { CSSResultGroup, TemplateResult } from "lit"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property, query, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; import { relativeTime } from "../../../common/datetime/relative_time"; import { storage } from "../../../common/decorators/storage"; -import type { HASSDomEvent } from "../../../common/dom/fire_event"; +import { fireEvent, type HASSDomEvent } from "../../../common/dom/fire_event"; import { computeDomain } from "../../../common/entity/compute_domain"; import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event"; import { navigate } from "../../../common/navigate"; @@ -36,11 +36,8 @@ import "../../../components/ha-svg-icon"; import { getSignedPath } from "../../../data/auth"; import type { BackupConfig, BackupContent } from "../../../data/backup"; import { - compareAgents, computeBackupAgentName, deleteBackup, - fetchBackupConfig, - fetchBackupInfo, generateBackup, generateBackupWithAutomaticSettings, getBackupDownloadUrl, @@ -48,10 +45,6 @@ import { isLocalAgent, } from "../../../data/backup"; import type { ManagerStateEvent } from "../../../data/backup_manager"; -import { - DEFAULT_MANAGER_STATE, - subscribeBackupEvents, -} from "../../../data/backup_manager"; import type { CloudStatus } from "../../../data/cloud"; import { extractApiErrorMessage } from "../../../data/hassio/common"; import { @@ -66,7 +59,6 @@ import type { HomeAssistant, Route } from "../../../types"; import { brandsUrl } from "../../../util/brands-url"; import { bytesToString } from "../../../util/bytes-to-string"; import { fileDownload } from "../../../util/file_download"; -import { showToast } from "../../../util/toast"; import { showGenerateBackupDialog } from "./dialogs/show-dialog-generate-backup"; import { showNewBackupDialog } from "./dialogs/show-dialog-new-backup"; import { showUploadBackupDialog } from "./dialogs/show-dialog-upload-backup"; @@ -89,13 +81,13 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) { @property({ attribute: false }) public route!: Route; - @state() private _manager: ManagerStateEvent = DEFAULT_MANAGER_STATE; + @property() private manager!: ManagerStateEvent; - @state() private _backups: BackupContent[] = []; + @property() private backups: BackupContent[] = []; - @state() private _selected: string[] = []; + @property() private config?: BackupConfig; - @state() private _config?: BackupConfig; + @state() private _selected: string[] = []; @storage({ key: "backups-table-grouping", state: false, subscribe: false }) private _activeGrouping?: string = "formatted_type"; @@ -107,8 +99,6 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) { }) private _activeCollapsed: string[] = []; - private _subscribed?: Promise<() => void>; - @query("hass-tabs-subpage-data-table", true) private _dataTable!: HaTabsSubpageDataTable; @@ -251,7 +241,7 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) { protected render(): TemplateResult { const backupInProgress = - "state" in this._manager && this._manager.state === "in_progress"; + "state" in this.manager && this.manager.state === "in_progress"; return html` unsub()); - this._subscribed = undefined; - } - } - - private async _subscribeEvents() { - this._unsubscribeEvents(); - if (!this.isConnected) { - return; - } - - this._subscribed = subscribeBackupEvents(this.hass!, (event) => { - this._manager = event; - if ("state" in event) { - if (event.state === "completed" || event.state === "failed") { - this._fetchBackupInfo(); - } - if (event.state === "failed") { - let message = ""; - switch (this._manager.manager_state) { - case "create_backup": - message = "Failed to create backup"; - break; - case "restore_backup": - message = "Failed to restore backup"; - break; - case "receive_backup": - message = "Failed to upload backup"; - break; - } - if (message) { - showToast(this, { message }); - } - } - } - }); - } - - protected firstUpdated(changedProps: PropertyValues) { - super.firstUpdated(changedProps); - this._fetchBackupInfo(); - this._subscribeEvents(); - this._fetchBackupConfig(); - } - - public connectedCallback() { - super.connectedCallback(); - if (this.hasUpdated) { - this._fetchBackupInfo(); - this._subscribeEvents(); - } - } - - public disconnectedCallback(): void { - super.disconnectedCallback(); - this._unsubscribeEvents(); - } - - private async _fetchBackupInfo() { - const info = await fetchBackupInfo(this.hass); - this._backups = info.backups.map((backup) => ({ - ...backup, - agent_ids: backup.agent_ids?.sort(compareAgents), - failed_agent_ids: backup.failed_agent_ids?.sort(compareAgents), - })); - } - - private async _fetchBackupConfig() { - const { config } = await fetchBackupConfig(this.hass); - this._config = config; - } - private get _needsOnboarding() { - return !this._config?.create_backup.password; + return !this.config?.create_backup.password; } private async _uploadBackup(ev) { @@ -438,7 +354,7 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) { } private async _newBackup(): Promise { - const config = this._config!; + const config = this.config!; const type = await showNewBackupDialog(this, { config }); @@ -454,12 +370,12 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) { } await generateBackup(this.hass, params); - await this._fetchBackupInfo(); + fireEvent(this, "ha-refresh-backup-info"); return; } if (type === "automatic") { await generateBackupWithAutomaticSettings(this.hass); - await this._fetchBackupInfo(); + fireEvent(this, "ha-refresh-backup-info"); } } @@ -490,7 +406,7 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) { } await deleteBackup(this.hass, backup.backup_id); - this._fetchBackupInfo(); + fireEvent(this, "ha-refresh-backup-info"); } private async _deleteSelected() { @@ -516,7 +432,7 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) { }); return; } - await this._fetchBackupInfo(); + fireEvent(this, "ha-refresh-backup-info"); this._dataTable.clearSelection(); } diff --git a/src/panels/config/backup/ha-config-backup-locations.ts b/src/panels/config/backup/ha-config-backup-locations.ts deleted file mode 100644 index 80312f30c219..000000000000 --- a/src/panels/config/backup/ha-config-backup-locations.ts +++ /dev/null @@ -1,138 +0,0 @@ -import type { TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import "../../../components/ha-card"; -import "../../../components/ha-icon-next"; -import "../../../components/ha-md-list"; -import "../../../components/ha-md-list-item"; -import type { BackupAgent } from "../../../data/backup"; -import { fetchBackupAgentsInfo } from "../../../data/backup"; -import "../../../layouts/hass-subpage"; -import type { HomeAssistant } from "../../../types"; -import { brandsUrl } from "../../../util/brands-url"; -import { domainToName } from "../../../data/integration"; - -@customElement("ha-config-backup-locations") -class HaConfigBackupLocations extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ type: Boolean }) public narrow = false; - - @state() private _agents: BackupAgent[] = []; - - protected firstUpdated(changedProps) { - super.firstUpdated(changedProps); - this._fetchAgents(); - } - - protected render(): TemplateResult { - return html` - -
-
-

Locations

-

- To keep your data safe it is recommended your backups is at least - on two different locations and one of them is off-site. -

-
- -
- ${this._agents.length > 0 - ? html` - - ${this._agents.map((agent) => { - const [domain, name] = agent.agent_id.split("."); - const domainName = domainToName( - this.hass.localize, - domain - ); - return html` - - -
${domainName}: ${name}
- -
- `; - })} -
- ` - : html`

No sync agents configured

`} -
-
-
-
- `; - } - - private async _fetchAgents() { - const data = await fetchBackupAgentsInfo(this.hass); - this._agents = data.agents; - } - - static styles = css` - .content { - padding: 28px 20px 0; - max-width: 690px; - margin: 0 auto; - gap: 24px; - display: flex; - flex-direction: column; - } - - .header .title { - font-size: 22px; - font-style: normal; - font-weight: 400; - line-height: 28px; - color: var(--primary-text-color); - margin: 0; - margin-bottom: 8px; - } - - .header .description { - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: 20px; - letter-spacing: 0.25px; - color: var(--secondary-text-color); - margin: 0; - } - - ha-md-list { - background: none; - } - ha-md-list-item img { - width: 48px; - } - .card-content { - padding: 0; - } - `; -} - -declare global { - interface HTMLElementTagNameMap { - "ha-config-backup-locations": HaConfigBackupLocations; - } -} diff --git a/src/panels/config/backup/ha-config-backup-overview.ts b/src/panels/config/backup/ha-config-backup-overview.ts index 44b196736469..afa203244fd9 100644 --- a/src/panels/config/backup/ha-config-backup-overview.ts +++ b/src/panels/config/backup/ha-config-backup-overview.ts @@ -1,7 +1,8 @@ import { mdiDotsVertical, mdiPlus, mdiUpload } from "@mdi/js"; -import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit"; +import type { CSSResultGroup, TemplateResult } from "lit"; import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; +import { customElement, property } from "lit/decorators"; +import { fireEvent } from "../../../common/dom/fire_event"; import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event"; import "../../../components/ha-button"; import "../../../components/ha-button-menu"; @@ -13,8 +14,6 @@ import "../../../components/ha-icon-overflow-menu"; import "../../../components/ha-list-item"; import "../../../components/ha-svg-icon"; import { - fetchBackupConfig, - fetchBackupInfo, generateBackup, generateBackupWithAutomaticSettings, type BackupConfig, @@ -50,29 +49,11 @@ class HaConfigBackupOverview extends LitElement { @property({ attribute: false }) public manager!: ManagerStateEvent; - @state() private _backups: BackupContent[] = []; + @property({ attribute: false }) public backups: BackupContent[] = []; - @state() private _fetching = false; + @property({ attribute: false }) public fetching = false; - @state() private _config?: BackupConfig; - - protected firstUpdated(changedProps: PropertyValues) { - super.firstUpdated(changedProps); - this._fetching = true; - Promise.all([this._fetchBackupInfo(), this._fetchBackupConfig()]).finally( - () => { - this._fetching = false; - } - ); - } - - public connectedCallback() { - super.connectedCallback(); - if (this.hasUpdated) { - this._fetchBackupInfo(); - this._fetchBackupConfig(); - } - } + @property({ attribute: false }) public config?: BackupConfig; private async _uploadBackup(ev) { if (!shouldHandleRequestSelectedEvent(ev)) { @@ -96,19 +77,9 @@ class HaConfigBackupOverview extends LitElement { return; } - this._fetchBackupConfig(); + fireEvent(this, "ha-refresh-backup-config"); await generateBackupWithAutomaticSettings(this.hass); - await this._fetchBackupInfo(); - } - - private async _fetchBackupInfo() { - const info = await fetchBackupInfo(this.hass); - this._backups = info.backups; - } - - private async _fetchBackupConfig() { - const { config } = await fetchBackupConfig(this.hass); - this._config = config; + fireEvent(this, "ha-refresh-backup-info"); } private async _newBackup(): Promise { @@ -117,11 +88,11 @@ class HaConfigBackupOverview extends LitElement { return; } - if (!this._config) { + if (!this.config) { return; } - const config = this._config; + const config = this.config; const type = await showNewBackupDialog(this, { config }); @@ -137,17 +108,17 @@ class HaConfigBackupOverview extends LitElement { } await generateBackup(this.hass, params); - await this._fetchBackupInfo(); + fireEvent(this, "ha-refresh-backup-info"); return; } if (type === "automatic") { await generateBackupWithAutomaticSettings(this.hass); - await this._fetchBackupInfo(); + fireEvent(this, "ha-refresh-backup-info"); } } private get _needsOnboarding() { - return !this._config?.create_backup.password; + return !this.config?.create_backup.password; } protected render(): TemplateResult { @@ -186,7 +157,7 @@ class HaConfigBackupOverview extends LitElement { > ` - : this._fetching + : this.fetching ? html` `} ${!this._needsOnboarding ? html` ` : nothing} diff --git a/src/panels/config/backup/ha-config-backup-settings.ts b/src/panels/config/backup/ha-config-backup-settings.ts index ffb4c2719041..0c02e27f3c74 100644 --- a/src/panels/config/backup/ha-config-backup-settings.ts +++ b/src/panels/config/backup/ha-config-backup-settings.ts @@ -1,17 +1,12 @@ import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; +import { customElement, property } from "lit/decorators"; import { debounce } from "../../../common/util/debounce"; import "../../../components/ha-button"; import "../../../components/ha-card"; import "../../../components/ha-icon-next"; import "../../../components/ha-password-field"; -import "../../../components/ha-settings-row"; import type { BackupConfig } from "../../../data/backup"; -import { - BackupScheduleState, - fetchBackupConfig, - updateBackupConfig, -} from "../../../data/backup"; +import { updateBackupConfig } from "../../../data/backup"; import type { CloudStatus } from "../../../data/cloud"; import "../../../layouts/hass-subpage"; import type { HomeAssistant } from "../../../types"; @@ -21,27 +16,7 @@ import type { BackupConfigData } from "./components/config/ha-backup-config-data import "./components/config/ha-backup-config-encryption-key"; import "./components/config/ha-backup-config-schedule"; import type { BackupConfigSchedule } from "./components/config/ha-backup-config-schedule"; - -const INITIAL_BACKUP_CONFIG: BackupConfig = { - create_backup: { - agent_ids: [], - include_folders: [], - include_database: true, - include_addons: [], - include_all_addons: true, - password: null, - name: null, - }, - retention: { - copies: 3, - days: null, - }, - schedule: { - state: BackupScheduleState.DAILY, - }, - last_attempted_automatic_backup: null, - last_completed_automatic_backup: null, -}; +import { fireEvent } from "../../../common/dom/fire_event"; @customElement("ha-config-backup-settings") class HaConfigBackupSettings extends LitElement { @@ -51,22 +26,10 @@ class HaConfigBackupSettings extends LitElement { @property({ type: Boolean }) public narrow = false; - @state() private _backupConfig: BackupConfig = INITIAL_BACKUP_CONFIG; - - protected willUpdate(changedProps) { - super.willUpdate(changedProps); - if (!this.hasUpdated) { - this._fetchData(); - } - } - - private async _fetchData() { - const { config } = await fetchBackupConfig(this.hass); - this._backupConfig = config; - } + @property({ attribute: false }) public config?: BackupConfig; protected render() { - if (!this._backupConfig) { + if (!this.config) { return nothing; } @@ -87,7 +50,7 @@ class HaConfigBackupSettings extends LitElement {

@@ -113,7 +76,7 @@ class HaConfigBackupSettings extends LitElement {

@@ -130,7 +93,7 @@ class HaConfigBackupSettings extends LitElement {

@@ -142,8 +105,8 @@ class HaConfigBackupSettings extends LitElement { private _scheduleConfigChanged(ev) { const value = ev.detail.value as BackupConfigSchedule; - this._backupConfig = { - ...this._backupConfig, + this.config = { + ...this.config!, schedule: value.schedule, retention: value.retention, }; @@ -156,7 +119,7 @@ class HaConfigBackupSettings extends LitElement { include_all_addons, include_database, include_folders, - } = this._backupConfig.create_backup; + } = this.config!.create_backup; return { include_homeassistant: true, @@ -169,10 +132,10 @@ class HaConfigBackupSettings extends LitElement { private _dataConfigChanged(ev) { const data = ev.detail.value as BackupConfigData; - this._backupConfig = { - ...this._backupConfig, + this.config = { + ...this.config!, create_backup: { - ...this._backupConfig.create_backup, + ...this.config!.create_backup, include_database: data.include_database, include_folders: data.include_folders || null, include_all_addons: data.include_all_addons, @@ -184,10 +147,10 @@ class HaConfigBackupSettings extends LitElement { private _agentsConfigChanged(ev) { const agents = ev.detail.value as string[]; - this._backupConfig = { - ...this._backupConfig, + this.config = { + ...this.config!, create_backup: { - ...this._backupConfig.create_backup, + ...this.config!.create_backup, agent_ids: agents, }, }; @@ -196,10 +159,10 @@ class HaConfigBackupSettings extends LitElement { private _encryptionKeyChanged(ev) { const password = ev.detail.value as string; - this._backupConfig = { - ...this._backupConfig, + this.config = { + ...this.config!, create_backup: { - ...this._backupConfig.create_backup, + ...this.config!.create_backup, password: password, }, }; @@ -211,16 +174,17 @@ class HaConfigBackupSettings extends LitElement { private async _save() { await updateBackupConfig(this.hass, { create_backup: { - agent_ids: this._backupConfig.create_backup.agent_ids, - include_folders: this._backupConfig.create_backup.include_folders ?? [], - include_database: this._backupConfig.create_backup.include_database, - include_addons: this._backupConfig.create_backup.include_addons ?? [], - include_all_addons: this._backupConfig.create_backup.include_all_addons, - password: this._backupConfig.create_backup.password, + agent_ids: this.config!.create_backup.agent_ids, + include_folders: this.config!.create_backup.include_folders ?? [], + include_database: this.config!.create_backup.include_database, + include_addons: this.config!.create_backup.include_addons ?? [], + include_all_addons: this.config!.create_backup.include_all_addons, + password: this.config!.create_backup.password, }, - retention: this._backupConfig.retention, - schedule: this._backupConfig.schedule.state, + retention: this.config!.retention, + schedule: this.config!.schedule.state, }); + fireEvent(this, "ha-refresh-backup-config"); } static styles = css` @@ -233,14 +197,6 @@ class HaConfigBackupSettings extends LitElement { flex-direction: column; margin-bottom: 24px; } - ha-settings-row { - --settings-row-prefix-display: flex; - padding: 0; - } - ha-settings-row > ha-svg-icon { - align-self: center; - margin-inline-end: 16px; - } .alert { --mdc-theme-primary: var(--error-color); } diff --git a/src/panels/config/backup/ha-config-backup.ts b/src/panels/config/backup/ha-config-backup.ts index 230004feb49a..bf8be4d454d1 100644 --- a/src/panels/config/backup/ha-config-backup.ts +++ b/src/panels/config/backup/ha-config-backup.ts @@ -15,6 +15,19 @@ import type { HomeAssistant } from "../../../types"; import { showToast } from "../../../util/toast"; import "./ha-config-backup-backups"; import "./ha-config-backup-overview"; +import type { BackupConfig, BackupContent } from "../../../data/backup"; +import { + compareAgents, + fetchBackupConfig, + fetchBackupInfo, +} from "../../../data/backup"; + +declare global { + interface HASSDomEvents { + "ha-refresh-backup-info": undefined; + "ha-refresh-backup-config": undefined; + } +} @customElement("ha-config-backup") class HaConfigBackup extends SubscribeMixin(HassRouterPage) { @@ -26,6 +39,51 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) { @state() private _manager: ManagerStateEvent = DEFAULT_MANAGER_STATE; + @state() private _backups: BackupContent[] = []; + + @state() private _fetching = false; + + @state() private _config?: BackupConfig; + + protected firstUpdated(changedProps: PropertyValues) { + super.firstUpdated(changedProps); + this._fetching = true; + Promise.all([this._fetchBackupInfo(), this._fetchBackupConfig()]).finally( + () => { + this._fetching = false; + } + ); + + this.addEventListener("ha-refresh-backup-info", () => { + this._fetchBackupInfo(); + }); + this.addEventListener("ha-refresh-backup-config", () => { + this._fetchBackupConfig(); + }); + } + + public connectedCallback() { + super.connectedCallback(); + if (this.hasUpdated) { + this._fetchBackupInfo(); + this._fetchBackupConfig(); + } + } + + private async _fetchBackupInfo() { + const info = await fetchBackupInfo(this.hass); + this._backups = info.backups.map((backup) => ({ + ...backup, + agent_ids: backup.agent_ids?.sort(compareAgents), + failed_agent_ids: backup.failed_agent_ids?.sort(compareAgents), + })); + } + + private async _fetchBackupConfig() { + const { config } = await fetchBackupConfig(this.hass); + this._config = config; + } + protected routerOptions: RouterOptions = { defaultPage: "overview", routes: { @@ -41,10 +99,6 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) { tag: "ha-config-backup-details", load: () => import("./ha-config-backup-details"), }, - locations: { - tag: "ha-config-backup-locations", - load: () => import("./ha-config-backup-locations"), - }, settings: { tag: "ha-config-backup-settings", load: () => import("./ha-config-backup-settings"), @@ -58,7 +112,11 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) { pageEl.narrow = this.narrow; pageEl.cloudStatus = this.cloudStatus; pageEl.manager = this._manager; + pageEl.backups = this._backups; + pageEl.config = this._config; + pageEl.fetching = this._fetching; + pageEl.addEventListener("reload", () => {}); if ( (!changedProps || changedProps.has("route")) && this._currentPage === "details" @@ -73,7 +131,7 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) { this._manager = event; if ("state" in event) { if (event.state === "completed" || event.state === "failed") { - // this._fetchBackupInfo(); + this._fetchBackupInfo(); } if (event.state === "failed") { let message = "";