From 08459394a68fdd9940e26f98076a8bef7ac4f4cf Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Mon, 16 Dec 2024 14:36:59 +0100 Subject: [PATCH] Add backup sync status in detail page (#23312) --- src/data/backup.ts | 1 + .../backup/ha-config-backup-dashboard.ts | 1 + .../config/backup/ha-config-backup-details.ts | 112 +++++++++++++----- 3 files changed, 87 insertions(+), 27 deletions(-) diff --git a/src/data/backup.ts b/src/data/backup.ts index 39d7a4fc12..0b6f2d356f 100644 --- a/src/data/backup.ts +++ b/src/data/backup.ts @@ -63,6 +63,7 @@ export interface BackupContent { protected: boolean; size: number; agent_ids?: string[]; + failed_agent_ids?: string[]; with_strategy_settings: boolean; } diff --git a/src/panels/config/backup/ha-config-backup-dashboard.ts b/src/panels/config/backup/ha-config-backup-dashboard.ts index 4e72b9c55f..3f2958dda6 100644 --- a/src/panels/config/backup/ha-config-backup-dashboard.ts +++ b/src/panels/config/backup/ha-config-backup-dashboard.ts @@ -492,6 +492,7 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) { this._backups = info.backups.map((backup) => ({ ...backup, agent_ids: backup.agent_ids?.sort(compareAgents), + failed_agent_ids: backup.failed_agent_ids?.sort(compareAgents), })); } diff --git a/src/panels/config/backup/ha-config-backup-details.ts b/src/panels/config/backup/ha-config-backup-details.ts index 1d36c170c0..e9d09555f9 100644 --- a/src/panels/config/backup/ha-config-backup-details.ts +++ b/src/panels/config/backup/ha-config-backup-details.ts @@ -36,6 +36,22 @@ import { showConfirmationDialog } from "../../lovelace/custom-card-helpers"; import "./components/ha-backup-data-picker"; import { showRestoreBackupEncryptionKeyDialog } from "./dialogs/show-dialog-restore-backup-encryption-key"; +type Agent = { + id: string; + success: boolean; +}; + +const computeAgents = (agent_ids: string[], failed_agent_ids: string[]) => + [ + ...agent_ids.filter((id) => !failed_agent_ids.includes(id)), + ...failed_agent_ids, + ] + .map((id) => ({ + id, + success: !failed_agent_ids.includes(id), + })) + .sort((a, b) => compareAgents(a.id, b.id)); + @customElement("ha-config-backup-details") class HaConfigBackupDetails extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -46,6 +62,8 @@ class HaConfigBackupDetails extends LitElement { @state() private _backup?: BackupContentExtended | null; + @state() private _agents: Agent[] = []; + @state() private _error?: string; @state() private _selectedBackup?: BackupContentExtended; @@ -93,9 +111,11 @@ class HaConfigBackupDetails extends LitElement { ${this._error && html`${this._error}`} ${this._backup === null - ? html` - Backup matching ${this.backupId} not found - ` + ? html` + + Backup matching ${this.backupId} not found + + ` : !this._backup ? html`` : html` @@ -142,7 +162,9 @@ class HaConfigBackupDetails extends LitElement {
- ${this._backup.agent_ids?.map((agentId) => { + ${this._agents.map((agent) => { + const agentId = agent.id; + const success = agent.success; const domain = computeDomain(agentId); const name = computeBackupAgentName( this.hass.localize, @@ -176,25 +198,38 @@ class HaConfigBackupDetails extends LitElement { /> `}
${name}
- - - - - Download from this location - - +
+ + + + ${success ? "Backup synced" : "Backup failed"} + +
+ ${success + ? html` + + + + Download from this location + + ` + : nothing} `; })} @@ -266,10 +301,11 @@ class HaConfigBackupDetails extends LitElement { private async _fetchBackup() { try { const response = await fetchBackupDetails(this.hass, this.backupId); - this._backup = { - ...response.backup, - agent_ids: response.backup.agent_ids?.sort(compareAgents), - }; + this._backup = response.backup; + this._agents = computeAgents( + response.backup.agent_ids || [], + response.backup.failed_agent_ids || [] + ); } catch (err: any) { this._error = err?.message || "Could not fetch backup details"; } @@ -357,6 +393,28 @@ class HaConfigBackupDetails extends LitElement { ha-backup-data-picker { display: block; } + ha-md-list-item [slot="supporting-text"] { + display: flex; + align-items: center; + flex-direction: row; + gap: 8px; + line-height: normal; + } + .dot { + display: block; + position: relative; + width: 8px; + height: 8px; + background-color: var(--disabled-color); + border-radius: 50%; + flex: none; + } + .dot.success { + background-color: var(--success-color); + } + .dot.error { + background-color: var(--error-color); + } `; }