From 76cb9ce807b828df21e06e7c7835d192ede7b1ad Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Mon, 23 Dec 2024 15:04:19 +0100 Subject: [PATCH 1/3] Change sidebar header color (#23401) --- src/components/ha-sidebar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 01e84f32ca8c..0420fcc74a59 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -871,7 +871,7 @@ class HaSidebar extends SubscribeMixin(LitElement) { border-bottom: 1px solid var(--divider-color); background-color: var( --sidebar-menu-button-background-color, - var(--primary-background-color) + inherit ); font-size: 20px; align-items: center; From 5fb384ad31cd1db3e4b5f6395a70969e8ee4fd1a Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Mon, 23 Dec 2024 15:06:36 +0100 Subject: [PATCH 2/3] Backup status banner improvement (#23400) * Improve overdue backups and don't consider backup with failed agents as success * Improve margin and loader * Improve margin * Show agent name if only one off site location is configured --- .../components/ha-backup-summary-card.ts | 5 +- .../components/ha-backup-summary-status.ts | 84 ---------- .../overview/ha-backup-overview-backups.ts | 4 + .../overview/ha-backup-overview-settings.ts | 18 ++- .../overview/ha-backup-overview-summary.ts | 147 ++++++++++++------ .../backup/ha-config-backup-overview.ts | 37 ++--- .../backup/ha-config-backup-settings.ts | 6 + 7 files changed, 141 insertions(+), 160 deletions(-) delete mode 100644 src/panels/config/backup/components/ha-backup-summary-status.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 fb894266a777..c03a6733ea34 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 9a5efdd3ba35..000000000000 --- 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 5c44183678f8..a667e1a4bc70 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 dc3679f1ba81..95ad7f19797e 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 5882675bf7c7..cf09d1911402 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" > - + ${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 b7621ab9f7f1..40614715a60f 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` + + + `} Date: Mon, 23 Dec 2024 15:06:50 +0100 Subject: [PATCH 3/3] Replace "State" with "Status" for consistency with Entity picker (#23399) The Filters pane for entities contains a "Status" section which gives several options to narrow down the list of entities, including "Disabled". For devices, however, the matching selector is currently labelled "State", although it has "Disabled" as the only choice. This conflicts with the device / entity state definition in HA and is inconsistent, getting worse in translations. --- src/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations/en.json b/src/translations/en.json index 660c03b30e32..b4264f7fb934 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -4359,7 +4359,7 @@ "error_delete": "Error deleting device", "picker": { "search": "Search {number} devices", - "state": "State", + "state": "Status", "bulk_actions": { "move_area": "Move to area", "no_area": "No area",