From 41e6f5ad332d462f74b230a7859dd8d0155d8878 Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Thu, 19 Dec 2024 17:09:51 +0100
Subject: [PATCH 1/6] Add summary card
---
.../components/ha-backup-summary-card.ts | 9 +-
.../overview/ha-backup-overview-backups.ts | 3 +
.../overview/ha-backup-overview-onboarding.ts | 104 ++++++++++
.../ha-backup-overview-progress.ts} | 17 +-
.../overview/ha-backup-overview-summary.ts | 192 ++++++++++++++++++
.../dialogs/dialog-backup-onboarding.ts | 20 +-
.../backup/dialogs/dialog-new-backup.ts | 8 +-
.../dialogs/show-dialog-backup_onboarding.ts | 1 +
.../backup/ha-config-backup-overview.ts | 74 ++++---
src/panels/config/backup/ha-config-backup.ts | 47 ++++-
10 files changed, 413 insertions(+), 62 deletions(-)
create mode 100644 src/panels/config/backup/components/overview/ha-backup-overview-onboarding.ts
rename src/panels/config/backup/components/{ha-backup-summary-progress.ts => overview/ha-backup-overview-progress.ts} (85%)
create mode 100644 src/panels/config/backup/components/overview/ha-backup-overview-summary.ts
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 1054f0b06146..fb894266a777 100644
--- a/src/panels/config/backup/components/ha-backup-summary-card.ts
+++ b/src/panels/config/backup/components/ha-backup-summary-card.ts
@@ -1,5 +1,5 @@
import {
- mdiAlertCircleCheckOutline,
+ mdiAlertCircleOutline,
mdiAlertOutline,
mdiCheck,
mdiInformationOutline,
@@ -16,7 +16,7 @@ type SummaryStatus = "success" | "error" | "info" | "warning" | "loading";
const ICONS: Record = {
success: mdiCheck,
- error: mdiAlertCircleCheckOutline,
+ error: mdiAlertCircleOutline,
warning: mdiAlertOutline,
info: mdiInformationOutline,
loading: mdiSync,
@@ -60,6 +60,9 @@ class HaBackupSummaryCard extends LitElement {
`
: nothing}
+
+
+
`;
}
@@ -71,7 +74,7 @@ class HaBackupSummaryCard extends LitElement {
column-gap: 16px;
row-gap: 8px;
align-items: center;
- padding: 20px;
+ padding: 16px;
width: 100%;
box-sizing: border-box;
}
diff --git a/src/panels/config/backup/components/overview/ha-backup-overview-backups.ts b/src/panels/config/backup/components/overview/ha-backup-overview-backups.ts
index c79a0aeeaeae..82f72082c02f 100644
--- a/src/panels/config/backup/components/overview/ha-backup-overview-backups.ts
+++ b/src/panels/config/backup/components/overview/ha-backup-overview-backups.ts
@@ -1,3 +1,4 @@
+import { mdiCalendarSync, mdiGestureTap } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
@@ -62,6 +63,7 @@ class HaBackupOverviewBackups extends LitElement {
+
${automaticStats.count} automatic backups
@@ -71,6 +73,7 @@ class HaBackupOverviewBackups extends LitElement {
+
${manualStats.count} manual backups
${bytesToString(manualStats.size, 1)} in total
diff --git a/src/panels/config/backup/components/overview/ha-backup-overview-onboarding.ts b/src/panels/config/backup/components/overview/ha-backup-overview-onboarding.ts
new file mode 100644
index 000000000000..b030c8b7d899
--- /dev/null
+++ b/src/panels/config/backup/components/overview/ha-backup-overview-onboarding.ts
@@ -0,0 +1,104 @@
+import { mdiInformationOutline } from "@mdi/js";
+import type { CSSResultGroup } from "lit";
+import { css, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import { fireEvent } from "../../../../../common/dom/fire_event";
+import "../../../../../components/ha-button";
+import "../../../../../components/ha-card";
+import "../../../../../components/ha-svg-icon";
+import { haStyle } from "../../../../../resources/styles";
+import type { HomeAssistant } from "../../../../../types";
+
+declare global {
+ // for fire event
+ interface HASSDomEvents {
+ "button-click": undefined;
+ }
+}
+
+@customElement("ha-backup-overview-onboarding")
+class HaBackupOverviewBackups extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ private async _setup() {
+ fireEvent(this, "button-click");
+ }
+
+ render() {
+ return html`
+
+
+
+
+ Backups are essential to a reliable smart home. They protect your
+ setup against failures and allows you to quickly have a working
+ system again. It is recommended to create a daily backup and keep
+ copies of the last 3 days on two different locations. And one of
+ them is off-site.
+
+
+
+
+ Set up automatic backups
+
+
+
+ `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return [
+ haStyle,
+ css`
+ .card-header {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 16px;
+ }
+ .icon {
+ position: relative;
+ border-radius: 20px;
+ width: 40px;
+ height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+ }
+ .icon::before {
+ display: block;
+ content: "";
+ position: absolute;
+ inset: 0;
+ background-color: var(--primary-color);
+ opacity: 0.2;
+ }
+ .icon ha-svg-icon {
+ color: var(--primary-color);
+ width: 24px;
+ height: 24px;
+ }
+ p {
+ margin: 0;
+ }
+ .card-actions {
+ display: flex;
+ justify-content: flex-end;
+ border-top: none;
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-backup-overview-onboarding": HaBackupOverviewBackups;
+ }
+}
diff --git a/src/panels/config/backup/components/ha-backup-summary-progress.ts b/src/panels/config/backup/components/overview/ha-backup-overview-progress.ts
similarity index 85%
rename from src/panels/config/backup/components/ha-backup-summary-progress.ts
rename to src/panels/config/backup/components/overview/ha-backup-overview-progress.ts
index 63a0a9aa6b45..b9bfeffff6ac 100644
--- a/src/panels/config/backup/components/ha-backup-summary-progress.ts
+++ b/src/panels/config/backup/components/overview/ha-backup-overview-progress.ts
@@ -1,18 +1,15 @@
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
-import type { ManagerStateEvent } from "../../../../data/backup_manager";
-import type { HomeAssistant } from "../../../../types";
-import "./ha-backup-summary-card";
+import type { ManagerStateEvent } from "../../../../../data/backup_manager";
+import type { HomeAssistant } from "../../../../../types";
+import "../ha-backup-summary-card";
-@customElement("ha-backup-summary-progress")
-export class HaBackupSummaryProgress extends LitElement {
+@customElement("ha-backup-overview-progress")
+export class HaBackupOverviewProgress extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public manager!: ManagerStateEvent;
- @property({ type: Boolean, attribute: "has-action" })
- public hasAction = false;
-
private get _heading() {
switch (this.manager.manager_state) {
case "create_backup":
@@ -93,9 +90,7 @@ export class HaBackupSummaryProgress extends LitElement {
.heading=${this._heading}
.description=${this._description}
status="loading"
- .hasAction=${this.hasAction}
>
-
`;
}
@@ -103,6 +98,6 @@ export class HaBackupSummaryProgress extends LitElement {
declare global {
interface HTMLElementTagNameMap {
- "ha-backup-summary-progress": HaBackupSummaryProgress;
+ "ha-backup-overview-progress": HaBackupOverviewProgress;
}
}
diff --git a/src/panels/config/backup/components/overview/ha-backup-overview-summary.ts b/src/panels/config/backup/components/overview/ha-backup-overview-summary.ts
new file mode 100644
index 000000000000..a46282881971
--- /dev/null
+++ b/src/panels/config/backup/components/overview/ha-backup-overview-summary.ts
@@ -0,0 +1,192 @@
+import { mdiBackupRestore, mdiCalendar } from "@mdi/js";
+import { differenceInDays, setHours, setMinutes } from "date-fns";
+import type { CSSResultGroup } from "lit";
+import { css, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import memoizeOne from "memoize-one";
+import { formatTime } from "../../../../../common/datetime/format_time";
+import { relativeTime } from "../../../../../common/datetime/relative_time";
+import "../../../../../components/ha-button";
+import "../../../../../components/ha-card";
+import "../../../../../components/ha-md-list";
+import "../../../../../components/ha-md-list-item";
+import "../../../../../components/ha-svg-icon";
+import type { BackupConfig, BackupContent } from "../../../../../data/backup";
+import { BackupScheduleState } from "../../../../../data/backup";
+import { haStyle } from "../../../../../resources/styles";
+import type { HomeAssistant } from "../../../../../types";
+import "../ha-backup-summary-card";
+
+@customElement("ha-backup-overview-summary")
+class HaBackupOverviewBackups extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ attribute: false }) public backups: BackupContent[] = [];
+
+ @property({ attribute: false }) public config!: BackupConfig;
+
+ private _lastBackup = memoizeOne((backups: BackupContent[]) => {
+ const sortedBackups = backups
+ .filter((backup) => backup.with_automatic_settings)
+ .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
+
+ return sortedBackups[0] as BackupContent | undefined;
+ });
+
+ private _nextBackupDescription(schedule: BackupScheduleState) {
+ const newDate = setMinutes(setHours(new Date(), 4), 45);
+ const time = formatTime(newDate, this.hass.locale, this.hass.config);
+
+ switch (schedule) {
+ case BackupScheduleState.DAILY:
+ return `Next automatic backup tomorrow at ${time}`;
+ case BackupScheduleState.MONDAY:
+ return `Next automatic backup next Monday at ${time}`;
+ case BackupScheduleState.TUESDAY:
+ return `Next automatic backup next Thuesday at ${time}`;
+ case BackupScheduleState.WEDNESDAY:
+ return `Next automatic backup next Wednesday at ${time}`;
+ case BackupScheduleState.THURSDAY:
+ return `Next automatic backup next Thursday at ${time}`;
+ case BackupScheduleState.FRIDAY:
+ return `Next automatic backup next Friday at ${time}`;
+ case BackupScheduleState.SATURDAY:
+ return `Next automatic backup next Saturday at ${time}`;
+ case BackupScheduleState.SUNDAY:
+ return `Next automatic backup next Sunday at ${time}`;
+ default:
+ return "No automatic backup scheduled";
+ }
+ }
+
+ protected render() {
+ const lastBackup = this._lastBackup(this.backups);
+
+ if (!lastBackup) {
+ return html`
+
+
+ `;
+ }
+
+ const lastBackupDate = new Date(lastBackup.date);
+
+ const numberOfDays = differenceInDays(new Date(), lastBackupDate);
+ const now = new Date();
+
+ const lastBackupDescription = `Last successful backup ${relativeTime(lastBackupDate, this.hass.locale, now, true)} and synced to ${lastBackup.agent_ids?.length} locations.`;
+ const nextBackupDescription = this._nextBackupDescription(
+ this.config.schedule.state
+ );
+
+ const lastAttempt = this.config.last_attempted_automatic_backup
+ ? new Date(this.config.last_attempted_automatic_backup)
+ : undefined;
+
+ if (lastAttempt && lastAttempt > lastBackupDate) {
+ const lastAttemptDescription = `The last automatic backup trigged ${relativeTime(lastAttempt, this.hass.locale, now, true)} wasn't successful.`;
+ return html`
+
+
+ -
+
+ ${lastAttemptDescription}
+
+ -
+
+ ${lastBackupDescription}
+
+
+
+ `;
+ }
+
+ if (numberOfDays > 0) {
+ return html`
+
+
+ -
+
+ ${lastBackupDescription}
+
+ -
+
+ ${nextBackupDescription}
+
+
+
+ `;
+ }
+ return html`
+
+
+ -
+
+ ${lastBackupDescription}
+
+ -
+
+ ${nextBackupDescription}
+
+
+
+ `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return [
+ haStyle,
+ css`
+ .card-header {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 16px;
+ }
+ p {
+ margin: 0;
+ }
+ .list {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ padding: 8px 24px 24px 24px;
+ margin: 0;
+ }
+ .item {
+ display: flex;
+ flex-direction: row;
+ gap: 16px;
+ align-items: center;
+ color: var(--secondary-text-color);
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 20px;
+ letter-spacing: 0.25px;
+ }
+ .card-actions {
+ display: flex;
+ justify-content: flex-end;
+ border-top: none;
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-backup-overview-summary": HaBackupOverviewBackups;
+ }
+}
diff --git a/src/panels/config/backup/dialogs/dialog-backup-onboarding.ts b/src/panels/config/backup/dialogs/dialog-backup-onboarding.ts
index 512932468bf9..e373a3ad361a 100644
--- a/src/panels/config/backup/dialogs/dialog-backup-onboarding.ts
+++ b/src/panels/config/backup/dialogs/dialog-backup-onboarding.ts
@@ -82,6 +82,8 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
@state() private _step?: Step;
+ @state() private _steps: Step[] = [];
+
@state() private _params?: BackupOnboardingDialogParams;
@query("ha-md-dialog") private _dialog!: HaMdDialog;
@@ -90,7 +92,8 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
public showDialog(params: BackupOnboardingDialogParams): void {
this._params = params;
- this._step = STEPS[0];
+ this._steps = params.showIntro ? STEPS.concat() : STEPS.slice(1);
+ this._step = this._steps[0];
this._config = RECOMMENDED_CONFIG;
// Enable local location by default
@@ -117,6 +120,7 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
}
this._opened = false;
this._step = undefined;
+ this._steps = [];
this._config = undefined;
this._params = undefined;
}
@@ -158,19 +162,19 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
}
private _previousStep() {
- const index = STEPS.indexOf(this._step!);
+ const index = this._steps.indexOf(this._step!);
if (index === 0) {
return;
}
- this._step = STEPS[index - 1];
+ this._step = this._steps[index - 1];
}
private _nextStep() {
- const index = STEPS.indexOf(this._step!);
- if (index === STEPS.length - 1) {
+ const index = this._steps.indexOf(this._step!);
+ if (index === this._steps.length - 1) {
return;
}
- this._step = STEPS[index + 1];
+ this._step = this._steps[index + 1];
}
protected render() {
@@ -178,8 +182,8 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
return nothing;
}
- const isLastStep = this._step === STEPS[STEPS.length - 1];
- const isFirstStep = this._step === STEPS[0];
+ const isLastStep = this._step === this._steps[this._steps.length - 1];
+ const isFirstStep = this._step === this._steps[0];
return html`
diff --git a/src/panels/config/backup/dialogs/dialog-new-backup.ts b/src/panels/config/backup/dialogs/dialog-new-backup.ts
index 363a365ea9d6..0ac81c454ade 100644
--- a/src/panels/config/backup/dialogs/dialog-new-backup.ts
+++ b/src/panels/config/backup/dialogs/dialog-new-backup.ts
@@ -1,4 +1,4 @@
-import { mdiClose, mdiCog, mdiPencil } from "@mdi/js";
+import { mdiCalendarSync, mdiClose, mdiGestureTap } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
@@ -7,6 +7,7 @@ import "../../../../components/ha-dialog-header";
import "../../../../components/ha-icon-button";
import "../../../../components/ha-icon-next";
import "../../../../components/ha-md-dialog";
+import type { HaMdDialog } from "../../../../components/ha-md-dialog";
import "../../../../components/ha-md-list";
import "../../../../components/ha-md-list-item";
import "../../../../components/ha-svg-icon";
@@ -14,7 +15,6 @@ import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
import { haStyle, haStyleDialog } from "../../../../resources/styles";
import type { HomeAssistant } from "../../../../types";
import type { NewBackupDialogParams } from "./show-dialog-new-backup";
-import type { HaMdDialog } from "../../../../components/ha-md-dialog";
@customElement("ha-dialog-new-backup")
class DialogNewBackup extends LitElement implements HassDialog {
@@ -75,7 +75,7 @@ class DialogNewBackup extends LitElement implements HassDialog {
type="button"
.disabled=${!this._params.config.create_backup.password}
>
-
+
Automatic backup
Create a backup with the data and locations you have configured.
@@ -83,7 +83,7 @@ class DialogNewBackup extends LitElement implements HassDialog {
-
+
Manual backup
Select data and locations for a manual backup.
diff --git a/src/panels/config/backup/dialogs/show-dialog-backup_onboarding.ts b/src/panels/config/backup/dialogs/show-dialog-backup_onboarding.ts
index 578f80bf1344..7955d29ddba7 100644
--- a/src/panels/config/backup/dialogs/show-dialog-backup_onboarding.ts
+++ b/src/panels/config/backup/dialogs/show-dialog-backup_onboarding.ts
@@ -4,6 +4,7 @@ import type { CloudStatus } from "../../../../data/cloud";
export interface BackupOnboardingDialogParams {
submit?: (value: boolean) => void;
cancel?: () => void;
+ showIntro?: boolean;
cloudStatus: CloudStatus;
}
diff --git a/src/panels/config/backup/ha-config-backup-overview.ts b/src/panels/config/backup/ha-config-backup-overview.ts
index fb49f5612057..44b196736469 100644
--- a/src/panels/config/backup/ha-config-backup-overview.ts
+++ b/src/panels/config/backup/ha-config-backup-overview.ts
@@ -21,17 +21,18 @@ import {
type BackupContent,
} from "../../../data/backup";
import type { ManagerStateEvent } from "../../../data/backup_manager";
-import { DEFAULT_MANAGER_STATE } from "../../../data/backup_manager";
import type { CloudStatus } from "../../../data/cloud";
import "../../../layouts/hass-subpage";
import "../../../layouts/hass-tabs-subpage-data-table";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant, Route } from "../../../types";
import "./components/ha-backup-summary-card";
-import "./components/ha-backup-summary-progress";
import "./components/ha-backup-summary-status";
import "./components/overview/ha-backup-overview-backups";
+import "./components/overview/ha-backup-overview-onboarding";
+import "./components/overview/ha-backup-overview-progress";
import "./components/overview/ha-backup-overview-settings";
+import "./components/overview/ha-backup-overview-summary";
import { showBackupOnboardingDialog } from "./dialogs/show-dialog-backup_onboarding";
import { showGenerateBackupDialog } from "./dialogs/show-dialog-generate-backup";
import { showNewBackupDialog } from "./dialogs/show-dialog-new-backup";
@@ -47,7 +48,7 @@ class HaConfigBackupOverview extends LitElement {
@property({ attribute: false }) public route!: Route;
- @state() private _manager: ManagerStateEvent = DEFAULT_MANAGER_STATE;
+ @property({ attribute: false }) public manager!: ManagerStateEvent;
@state() private _backups: BackupContent[] = [];
@@ -57,8 +58,12 @@ class HaConfigBackupOverview extends LitElement {
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
- this._fetchBackupInfo();
- this._fetchBackupConfig();
+ this._fetching = true;
+ Promise.all([this._fetchBackupInfo(), this._fetchBackupConfig()]).finally(
+ () => {
+ this._fetching = false;
+ }
+ );
}
public connectedCallback() {
@@ -77,9 +82,15 @@ class HaConfigBackupOverview extends LitElement {
await showUploadBackupDialog(this, {});
}
- private async _setupAutomaticBackup() {
+ private _handleOnboardingButtonClick(ev) {
+ ev.stopPropagation();
+ this._setupAutomaticBackup(false);
+ }
+
+ private async _setupAutomaticBackup(showIntro: boolean) {
const success = await showBackupOnboardingDialog(this, {
cloudStatus: this.cloudStatus,
+ showIntro: showIntro,
});
if (!success) {
return;
@@ -102,7 +113,7 @@ class HaConfigBackupOverview extends LitElement {
private async _newBackup(): Promise {
if (this._needsOnboarding) {
- this._setupAutomaticBackup();
+ this._setupAutomaticBackup(true);
return;
}
@@ -141,7 +152,7 @@ class HaConfigBackupOverview extends 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`
- ${this._fetching
+ ${backupInProgress
? html`
-
-
+
`
- : backupInProgress
+ : this._fetching
? html`
-
-
+
`
: this._needsOnboarding
? html`
-
-
- Set up automatic backups
-
-
+
`
: html`
-
-
+
`}
[] {
+ return [
+ 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 });
+ }
+ }
+ }
+ }),
+ ];
+ }
}
declare global {
From fd32efac3575b65c8d28b04be169bbef2f37ba3b Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Thu, 19 Dec 2024 17:34:04 +0100
Subject: [PATCH 2/6] 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`
-
-
-
-
-
- ${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 = "";
From d7ecf921464ac40713430e10720dd508c01a7a9e Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Thu, 19 Dec 2024 18:57:39 +0100
Subject: [PATCH 3/6] Add state config
---
.../config/backup/ha-config-backup-backups.ts | 6 +-
.../backup/ha-config-backup-settings.ts | 66 +++++++++++--------
2 files changed, 43 insertions(+), 29 deletions(-)
diff --git a/src/panels/config/backup/ha-config-backup-backups.ts b/src/panels/config/backup/ha-config-backup-backups.ts
index d095f4d46e10..219d3f27fa36 100644
--- a/src/panels/config/backup/ha-config-backup-backups.ts
+++ b/src/panels/config/backup/ha-config-backup-backups.ts
@@ -81,11 +81,11 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public route!: Route;
- @property() private manager!: ManagerStateEvent;
+ @property() public manager!: ManagerStateEvent;
- @property() private backups: BackupContent[] = [];
+ @property() public backups: BackupContent[] = [];
- @property() private config?: BackupConfig;
+ @property() public config?: BackupConfig;
@state() private _selected: string[] = [];
diff --git a/src/panels/config/backup/ha-config-backup-settings.ts b/src/panels/config/backup/ha-config-backup-settings.ts
index 0c02e27f3c74..b2dab22d3683 100644
--- a/src/panels/config/backup/ha-config-backup-settings.ts
+++ b/src/panels/config/backup/ha-config-backup-settings.ts
@@ -1,5 +1,7 @@
+import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
-import { customElement, property } from "lit/decorators";
+import { customElement, property, state } from "lit/decorators";
+import { fireEvent } from "../../../common/dom/fire_event";
import { debounce } from "../../../common/util/debounce";
import "../../../components/ha-button";
import "../../../components/ha-card";
@@ -16,7 +18,6 @@ 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";
-import { fireEvent } from "../../../common/dom/fire_event";
@customElement("ha-config-backup-settings")
class HaConfigBackupSettings extends LitElement {
@@ -28,8 +29,22 @@ class HaConfigBackupSettings extends LitElement {
@property({ attribute: false }) public config?: BackupConfig;
+ @state() private _config?: BackupConfig;
+
+ protected willUpdate(changedProperties: PropertyValues): void {
+ super.willUpdate(changedProperties);
+ if (changedProperties.has("config")) {
+ this._config = this.config;
+ }
+ }
+
+ protected firstUpdated(_changedProperties: PropertyValues): void {
+ super.firstUpdated(_changedProperties);
+ fireEvent(this, "ha-refresh-backup-config");
+ }
+
protected render() {
- if (!this.config) {
+ if (!this._config) {
return nothing;
}
@@ -50,7 +65,7 @@ class HaConfigBackupSettings extends LitElement {
@@ -76,7 +91,7 @@ class HaConfigBackupSettings extends LitElement {
@@ -93,7 +108,7 @@ class HaConfigBackupSettings extends LitElement {
@@ -105,8 +120,8 @@ class HaConfigBackupSettings extends LitElement {
private _scheduleConfigChanged(ev) {
const value = ev.detail.value as BackupConfigSchedule;
- this.config = {
- ...this.config!,
+ this._config = {
+ ...this._config!,
schedule: value.schedule,
retention: value.retention,
};
@@ -119,7 +134,7 @@ class HaConfigBackupSettings extends LitElement {
include_all_addons,
include_database,
include_folders,
- } = this.config!.create_backup;
+ } = this._config!.create_backup;
return {
include_homeassistant: true,
@@ -132,8 +147,8 @@ class HaConfigBackupSettings extends LitElement {
private _dataConfigChanged(ev) {
const data = ev.detail.value as BackupConfigData;
- this.config = {
- ...this.config!,
+ this._config = {
+ ...this._config!,
create_backup: {
...this.config!.create_backup,
include_database: data.include_database,
@@ -147,10 +162,10 @@ class HaConfigBackupSettings extends LitElement {
private _agentsConfigChanged(ev) {
const agents = ev.detail.value as string[];
- this.config = {
- ...this.config!,
+ this._config = {
+ ...this._config!,
create_backup: {
- ...this.config!.create_backup,
+ ...this._config!.create_backup,
agent_ids: agents,
},
};
@@ -159,10 +174,10 @@ class HaConfigBackupSettings extends LitElement {
private _encryptionKeyChanged(ev) {
const password = ev.detail.value as string;
- this.config = {
- ...this.config!,
+ this._config = {
+ ...this._config!,
create_backup: {
- ...this.config!.create_backup,
+ ...this._config!.create_backup,
password: password,
},
};
@@ -174,17 +189,16 @@ class HaConfigBackupSettings extends LitElement {
private async _save() {
await updateBackupConfig(this.hass, {
create_backup: {
- 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,
+ 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.config!.retention,
- schedule: this.config!.schedule.state,
+ retention: this._config!.retention,
+ schedule: this._config!.schedule.state,
});
- fireEvent(this, "ha-refresh-backup-config");
}
static styles = css`
From 2a53db31a6db62c9f7a575170d8284ae44a8032d Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Thu, 19 Dec 2024 19:11:48 +0100
Subject: [PATCH 4/6] Fix config refresh
---
src/panels/config/backup/ha-config-backup-backups.ts | 6 +++---
src/panels/config/backup/ha-config-backup-settings.ts | 6 +-----
2 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/src/panels/config/backup/ha-config-backup-backups.ts b/src/panels/config/backup/ha-config-backup-backups.ts
index 219d3f27fa36..c89d39f46a35 100644
--- a/src/panels/config/backup/ha-config-backup-backups.ts
+++ b/src/panels/config/backup/ha-config-backup-backups.ts
@@ -81,11 +81,11 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public route!: Route;
- @property() public manager!: ManagerStateEvent;
+ @property({ attribute: false }) public manager!: ManagerStateEvent;
- @property() public backups: BackupContent[] = [];
+ @property({ attribute: false }) public backups: BackupContent[] = [];
- @property() public config?: BackupConfig;
+ @property({ attribute: false }) public config?: BackupConfig;
@state() private _selected: string[] = [];
diff --git a/src/panels/config/backup/ha-config-backup-settings.ts b/src/panels/config/backup/ha-config-backup-settings.ts
index b2dab22d3683..c0c40ce565e1 100644
--- a/src/panels/config/backup/ha-config-backup-settings.ts
+++ b/src/panels/config/backup/ha-config-backup-settings.ts
@@ -38,11 +38,6 @@ class HaConfigBackupSettings extends LitElement {
}
}
- protected firstUpdated(_changedProperties: PropertyValues): void {
- super.firstUpdated(_changedProperties);
- fireEvent(this, "ha-refresh-backup-config");
- }
-
protected render() {
if (!this._config) {
return nothing;
@@ -199,6 +194,7 @@ class HaConfigBackupSettings extends LitElement {
retention: this._config!.retention,
schedule: this._config!.schedule.state,
});
+ fireEvent(this, "ha-refresh-backup-config");
}
static styles = css`
From 06c15d6af1c7ddd41760f19f1006339f40ccd272 Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Thu, 19 Dec 2024 19:15:03 +0100
Subject: [PATCH 5/6] Fix icons
---
.../backup/components/overview/ha-backup-overview-summary.ts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/panels/config/backup/components/overview/ha-backup-overview-summary.ts b/src/panels/config/backup/components/overview/ha-backup-overview-summary.ts
index a46282881971..5882675bf7c7 100644
--- a/src/panels/config/backup/components/overview/ha-backup-overview-summary.ts
+++ b/src/panels/config/backup/components/overview/ha-backup-overview-summary.ts
@@ -175,6 +175,9 @@ class HaBackupOverviewBackups extends LitElement {
line-height: 20px;
letter-spacing: 0.25px;
}
+ ha-svg-icon {
+ flex: none;
+ }
.card-actions {
display: flex;
justify-content: flex-end;
From 870db98749231e6fee4b40c7dadd841bab537ae6 Mon Sep 17 00:00:00 2001
From: Paul Bottein
Date: Thu, 19 Dec 2024 19:36:41 +0100
Subject: [PATCH 6/6] only if config undefined
---
src/panels/config/backup/ha-config-backup-settings.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/panels/config/backup/ha-config-backup-settings.ts b/src/panels/config/backup/ha-config-backup-settings.ts
index c0c40ce565e1..f249af35eb16 100644
--- a/src/panels/config/backup/ha-config-backup-settings.ts
+++ b/src/panels/config/backup/ha-config-backup-settings.ts
@@ -33,7 +33,7 @@ class HaConfigBackupSettings extends LitElement {
protected willUpdate(changedProperties: PropertyValues): void {
super.willUpdate(changedProperties);
- if (changedProperties.has("config")) {
+ if (changedProperties.has("config") && !this._config) {
this._config = this.config;
}
}