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 fb894266a7..c03a6733ea 100644
--- a/src/panels/config/backup/components/ha-backup-summary-card.ts
+++ b/src/panels/config/backup/components/ha-backup-summary-card.ts
@@ -75,6 +75,7 @@ class HaBackupSummaryCard extends LitElement {
row-gap: 8px;
align-items: center;
padding: 16px;
+ padding-bottom: 8px;
width: 100%;
box-sizing: border-box;
}
@@ -145,10 +146,6 @@ class HaBackupSummaryCard extends LitElement {
}
@media all and (max-width: 550px) {
- .summary {
- flex-wrap: wrap;
- padding: 8px;
- }
.action {
width: 100%;
display: flex;
diff --git a/src/panels/config/backup/components/ha-backup-summary-status.ts b/src/panels/config/backup/components/ha-backup-summary-status.ts
deleted file mode 100644
index 9a5efdd3ba..0000000000
--- a/src/panels/config/backup/components/ha-backup-summary-status.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { differenceInDays } from "date-fns";
-import { html, LitElement } from "lit";
-import { customElement, property } from "lit/decorators";
-import memoizeOne from "memoize-one";
-import { formatShortDateTime } from "../../../../common/datetime/format_date_time";
-import type { BackupContent } from "../../../../data/backup";
-import type { ManagerStateEvent } from "../../../../data/backup_manager";
-import type { HomeAssistant } from "../../../../types";
-import "./ha-backup-summary-card";
-
-@customElement("ha-backup-summary-status")
-export class HaBackupSummaryProgress extends LitElement {
- @property({ attribute: false }) public hass!: HomeAssistant;
-
- @property({ attribute: false }) public manager!: ManagerStateEvent;
-
- @property({ attribute: false }) public backups!: BackupContent[];
-
- @property({ type: Boolean, attribute: "has-action" })
- public hasAction = false;
-
- private _lastBackup = memoizeOne((backups: BackupContent[]) => {
- const sortedBackups = backups
- // eslint-disable-next-line arrow-body-style
- .filter((backup) => {
- // TODO : only show backups with default flag
- return backup.with_automatic_settings;
- })
- .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
-
- return sortedBackups[0] as BackupContent | undefined;
- });
-
- protected render() {
- const lastBackup = this._lastBackup(this.backups);
-
- if (!lastBackup) {
- return html`
-
-
-
- `;
- }
-
- const lastBackupDate = new Date(lastBackup.date);
- const numberOfDays = differenceInDays(new Date(), lastBackupDate);
-
- // TODO : Improve time format
- const description = `Last successful backup ${formatShortDateTime(lastBackupDate, this.hass.locale, this.hass.config)} and synced to ${lastBackup.agent_ids?.length} locations`;
- if (numberOfDays > 8) {
- return html`
-
-
-
- `;
- }
- return html`
-
-
-
- `;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "ha-backup-summary-status": HaBackupSummaryProgress;
- }
-}
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 5c44183678..a667e1a4bc 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
@@ -109,9 +109,13 @@ class HaBackupOverviewBackups extends LitElement {
display: flex;
justify-content: flex-end;
}
+ .card-header {
+ padding-bottom: 8px;
+ }
.card-content {
padding-left: 0;
padding-right: 0;
+ padding-bottom: 0;
}
`,
];
diff --git a/src/panels/config/backup/components/overview/ha-backup-overview-settings.ts b/src/panels/config/backup/components/overview/ha-backup-overview-settings.ts
index dc3679f1ba..95ad7f1979 100644
--- a/src/panels/config/backup/components/overview/ha-backup-overview-settings.ts
+++ b/src/panels/config/backup/components/overview/ha-backup-overview-settings.ts
@@ -10,7 +10,11 @@ import "../../../../../components/ha-md-list";
import "../../../../../components/ha-md-list-item";
import "../../../../../components/ha-svg-icon";
import type { BackupConfig } from "../../../../../data/backup";
-import { BackupScheduleState, isLocalAgent } from "../../../../../data/backup";
+import {
+ BackupScheduleState,
+ computeBackupAgentName,
+ isLocalAgent,
+} from "../../../../../data/backup";
import { haStyle } from "../../../../../resources/styles";
import type { HomeAssistant } from "../../../../../types";
@@ -88,6 +92,14 @@ class HaBackupBackupsSummary extends LitElement {
);
if (offsiteLocations.length) {
+ if (offsiteLocations.length === 1) {
+ const name = computeBackupAgentName(
+ this.hass.localize,
+ offsiteLocations[0],
+ offsiteLocations
+ );
+ return `Upload to ${name}`;
+ }
return `Upload to ${offsiteLocations.length} off-site locations`;
}
if (hasLocal) {
@@ -184,9 +196,13 @@ class HaBackupBackupsSummary extends LitElement {
display: flex;
justify-content: flex-end;
}
+ .card-header {
+ padding-bottom: 8px;
+ }
.card-content {
padding-left: 0;
padding-right: 0;
+ padding-bottom: 0;
}
`,
];
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 5882675bf7..cf09d19114 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
@@ -1,5 +1,5 @@
import { mdiBackupRestore, mdiCalendar } from "@mdi/js";
-import { differenceInDays, setHours, setMinutes } from "date-fns";
+import { addHours, differenceInDays, setHours, setMinutes } from "date-fns";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
@@ -17,6 +17,8 @@ import { haStyle } from "../../../../../resources/styles";
import type { HomeAssistant } from "../../../../../types";
import "../ha-backup-summary-card";
+const OVERDUE_MARGIN_HOURS = 3;
+
@customElement("ha-backup-overview-summary")
class HaBackupOverviewBackups extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -25,9 +27,14 @@ class HaBackupOverviewBackups extends LitElement {
@property({ attribute: false }) public config!: BackupConfig;
+ @property({ type: Boolean }) public fetching = false;
+
private _lastBackup = memoizeOne((backups: BackupContent[]) => {
const sortedBackups = backups
- .filter((backup) => backup.with_automatic_settings)
+ .filter(
+ (backup) =>
+ backup.with_automatic_settings && !backup.failed_agent_ids?.length
+ )
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
return sortedBackups[0] as BackupContent | undefined;
@@ -60,6 +67,23 @@ class HaBackupOverviewBackups extends LitElement {
}
protected render() {
+ if (this.fetching) {
+ return html`
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ }
+
const lastBackup = this._lastBackup(this.backups);
if (!lastBackup) {
@@ -75,10 +99,9 @@ class HaBackupOverviewBackups extends LitElement {
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 lastBackupDescription = `Last successful backup ${relativeTime(lastBackupDate, this.hass.locale, now, true)} and stored to ${lastBackup.agent_ids?.length} locations.`;
const nextBackupDescription = this._nextBackupDescription(
this.config.schedule.state
);
@@ -94,51 +117,62 @@ class HaBackupOverviewBackups extends LitElement {
heading=${`Last automatic backup failed`}
status="error"
>
-
- -
+
+
- ${lastAttemptDescription}
-
- -
+ ${lastAttemptDescription}
+
+
- ${lastBackupDescription}
-
-
+ ${lastBackupDescription}
+
+
`;
}
- if (numberOfDays > 0) {
+ const numberOfDays = differenceInDays(
+ // Subtract a few hours to avoid showing as overdue if it's just a few hours (e.g. daylight saving)
+ addHours(now, -OVERDUE_MARGIN_HOURS),
+ lastBackupDate
+ );
+
+ const isOverdue =
+ (numberOfDays >= 1 &&
+ this.config.schedule.state === BackupScheduleState.DAILY) ||
+ numberOfDays >= 7;
+
+ if (isOverdue) {
return html`
-
- -
+
+
- ${lastBackupDescription}
-
- -
+ ${lastBackupDescription}
+
+
- ${nextBackupDescription}
-
-
+ ${nextBackupDescription}
+
+
`;
}
return html`
-
- -
+
+
- ${lastBackupDescription}
-
- -
+ ${lastBackupDescription}
+
+
- ${nextBackupDescription}
-
-
+ ${nextBackupDescription}
+
+
`;
}
@@ -156,25 +190,6 @@ class HaBackupOverviewBackups extends LitElement {
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;
- }
ha-svg-icon {
flex: none;
}
@@ -183,6 +198,42 @@ class HaBackupOverviewBackups extends LitElement {
justify-content: flex-end;
border-top: none;
}
+ ha-md-list {
+ background: none;
+ }
+ ha-md-list-item {
+ --md-list-item-top-space: 8px;
+ --md-list-item-bottom-space: 8px;
+ --md-list-item-one-line-container-height: 40x;
+ }
+ span.skeleton {
+ position: relative;
+ display: block;
+ width: 160px;
+ animation-fill-mode: forwards;
+ animation-iteration-count: infinite;
+ animation-name: loading;
+ animation-timing-function: linear;
+ animation-duration: 1.2s;
+ border-radius: 4px;
+ height: 20px;
+ background: linear-gradient(
+ to right,
+ rgb(247, 249, 250) 8%,
+ rgb(235, 238, 240) 18%,
+ rgb(247, 249, 250) 33%
+ )
+ 0% 0% / 936px 104px;
+ }
+
+ @keyframes loading {
+ 0% {
+ background-position: -468px 0;
+ }
+ 100% {
+ background-position: 468px 0;
+ }
+ }
`,
];
}
diff --git a/src/panels/config/backup/ha-config-backup-overview.ts b/src/panels/config/backup/ha-config-backup-overview.ts
index b7621ab9f7..40614715a6 100644
--- a/src/panels/config/backup/ha-config-backup-overview.ts
+++ b/src/panels/config/backup/ha-config-backup-overview.ts
@@ -27,7 +27,6 @@ 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-status";
import "./components/overview/ha-backup-overview-backups";
import "./components/overview/ha-backup-overview-onboarding";
import "./components/overview/ha-backup-overview-progress";
@@ -182,31 +181,23 @@ class HaConfigBackupOverview extends LitElement {
>
`
- : this.fetching
+ : this._needsOnboarding
? html`
-
-
+
`
- : this._needsOnboarding
- ? html`
-
-
- `
- : html`
-
-
- `}
+ : html`
+
+
+ `}