From 85e4975206eb164940910bd01c1e5fe9d76fea92 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Tue, 28 Jan 2025 13:53:02 +0100 Subject: [PATCH] Use name property when formatting backup location (#23916) --- src/data/backup.ts | 15 ++++-- .../config/ha-backup-config-agents.ts | 48 ++++++++++--------- .../components/ha-backup-agents-picker.ts | 23 ++++----- .../overview/ha-backup-overview-settings.ts | 6 ++- .../backup/dialogs/dialog-generate-backup.ts | 28 ++++++----- .../config/backup/ha-config-backup-backups.ts | 10 +++- .../config/backup/ha-config-backup-details.ts | 5 +- .../backup/ha-config-backup-overview.ts | 10 +++- .../backup/ha-config-backup-settings.ts | 5 +- src/panels/config/backup/ha-config-backup.ts | 31 +++++++++--- 10 files changed, 116 insertions(+), 65 deletions(-) diff --git a/src/data/backup.ts b/src/data/backup.ts index b5224780c2..e8bb18b7f3 100644 --- a/src/data/backup.ts +++ b/src/data/backup.ts @@ -82,6 +82,7 @@ export interface BackupMutableConfig { export interface BackupAgent { agent_id: string; + name: string; } export interface BackupContent { @@ -279,13 +280,18 @@ export const isNetworkMountAgent = (agentId: string) => { export const computeBackupAgentName = ( localize: LocalizeFunc, agentId: string, - agentIds?: string[] + agents: BackupAgent[] ) => { if (isLocalAgent(agentId)) { return localize("ui.panel.config.backup.agents.local_agent"); } - const [domain, name] = agentId.split("."); + const agent = agents.find((a) => a.agent_id === agentId); + + const domain = agentId.split(".")[0]; + const name = agent ? agent.name : agentId.split(".")[1]; + + // If it's a network mount agent, only show the name if (isNetworkMountAgent(agentId)) { return name; } @@ -293,9 +299,8 @@ export const computeBackupAgentName = ( const domainName = domainToName(localize, domain); // If there are multiple agents for a domain, show the name - const showName = agentIds - ? agentIds.filter((a) => a.split(".")[0] === domain).length > 1 - : true; + const showName = + agents.filter((a) => a.agent_id.split(".")[0] === domain).length > 1; return showName ? `${domainName}: ${name}` : domainName; }; diff --git a/src/panels/config/backup/components/config/ha-backup-config-agents.ts b/src/panels/config/backup/components/config/ha-backup-config-agents.ts index 09216f54e3..fa682f6224 100644 --- a/src/panels/config/backup/components/config/ha-backup-config-agents.ts +++ b/src/panels/config/backup/components/config/ha-backup-config-agents.ts @@ -1,18 +1,17 @@ import { mdiHarddisk, mdiNas } from "@mdi/js"; -import type { PropertyValues } from "lit"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { computeDomain } from "../../../../../common/entity/compute_domain"; import "../../../../../components/ha-md-list"; import "../../../../../components/ha-md-list-item"; import "../../../../../components/ha-svg-icon"; import "../../../../../components/ha-switch"; +import type { BackupAgent } from "../../../../../data/backup"; import { CLOUD_AGENT, - compareAgents, computeBackupAgentName, - fetchBackupAgentsInfo, isLocalAgent, isNetworkMountAgent, } from "../../../../../data/backup"; @@ -28,22 +27,16 @@ class HaBackupConfigAgents extends LitElement { @property({ attribute: false }) public cloudStatus!: CloudStatus; - @state() private _agentIds: string[] = []; + @property({ attribute: false }) public agents: BackupAgent[] = []; @state() private value?: string[]; - protected firstUpdated(_changedProperties: PropertyValues): void { - super.firstUpdated(_changedProperties); - this._fetchAgents(); - } - - private async _fetchAgents() { - const { agents } = await fetchBackupAgentsInfo(this.hass); - this._agentIds = agents - .map((agent) => agent.agent_id) - .filter((id) => id !== CLOUD_AGENT || this.cloudStatus.logged_in) - .sort(compareAgents); - } + private _availableAgents = memoizeOne( + (agents: BackupAgent[], cloudStatus: CloudStatus) => + agents.filter( + (agent) => agent.agent_id !== CLOUD_AGENT || cloudStatus.logged_in + ) + ); private get _value() { return this.value ?? DEFAULT_AGENTS; @@ -69,16 +62,18 @@ class HaBackupConfigAgents extends LitElement { } protected render() { + const agents = this._availableAgents(this.agents, this.cloudStatus); return html` - ${this._agentIds.length > 0 + ${agents.length > 0 ? html` - ${this._agentIds.map((agentId) => { + ${agents.map((agent) => { + const agentId = agent.agent_id; const domain = computeDomain(agentId); const name = computeBackupAgentName( this.hass.localize, agentId, - this._agentIds + this.agents ); const description = this._description(agentId); const noCloudSubscription = @@ -130,9 +125,11 @@ class HaBackupConfigAgents extends LitElement { })} ` - : html`

- ${this.hass.localize("ui.panel.config.backup.agents.no_agents")} -

`} + : html` +

+ ${this.hass.localize("ui.panel.config.backup.agents.no_agents")} +

+ `} `; } @@ -147,9 +144,14 @@ class HaBackupConfigAgents extends LitElement { this.value = this._value.filter((agent) => agent !== agentId); } + const availableAgents = this._availableAgents( + this.agents, + this.cloudStatus + ); + // Ensure we don't have duplicates, agents exist in the list and cloud is logged in this.value = [...new Set(this.value)] - .filter((agent) => this._agentIds.some((id) => id === agent)) + .filter((id) => availableAgents.some((agent) => agent.agent_id === id)) .filter( (id) => id !== CLOUD_AGENT || diff --git a/src/panels/config/backup/components/ha-backup-agents-picker.ts b/src/panels/config/backup/components/ha-backup-agents-picker.ts index 7c032dce79..529a5089dc 100644 --- a/src/panels/config/backup/components/ha-backup-agents-picker.ts +++ b/src/panels/config/backup/components/ha-backup-agents-picker.ts @@ -7,6 +7,7 @@ import { computeDomain } from "../../../../common/entity/compute_domain"; import "../../../../components/ha-checkbox"; import "../../../../components/ha-formfield"; import "../../../../components/ha-svg-icon"; +import type { BackupAgent } from "../../../../data/backup"; import { computeBackupAgentName, isLocalAgent, @@ -24,7 +25,7 @@ class HaBackupAgentsPicker extends LitElement { public disabled = false; @property({ attribute: false }) - public agentIds!: string[]; + public agents!: BackupAgent[]; @property({ attribute: false }) public disabledAgentIds?: string[]; @@ -35,30 +36,30 @@ class HaBackupAgentsPicker extends LitElement { render() { return html`
- ${this.agentIds.map((agent) => this._renderAgent(agent))} + ${this.agents.map((agent) => this._renderAgent(agent))}
`; } - private _renderAgent(agentId: string) { - const domain = computeDomain(agentId); + private _renderAgent(agent: BackupAgent) { + const domain = computeDomain(agent.agent_id); const name = computeBackupAgentName( this.hass.localize, - agentId, - this.agentIds + agent.agent_id, + this.agents ); const disabled = - this.disabled || this.disabledAgentIds?.includes(agentId) || false; + this.disabled || this.disabledAgentIds?.includes(agent.agent_id) || false; return html` - ${isLocalAgent(agentId) + ${isLocalAgent(agent.agent_id) ? html` ` - : isNetworkMountAgent(agentId) + : isNetworkMountAgent(agent.agent_id) ? html` ` : html` 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 499c8313eb..e083c58712 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 @@ -9,7 +9,7 @@ import "../../../../../components/ha-icon-next"; import "../../../../../components/ha-md-list"; import "../../../../../components/ha-md-list-item"; import "../../../../../components/ha-svg-icon"; -import type { BackupConfig } from "../../../../../data/backup"; +import type { BackupAgent, BackupConfig } from "../../../../../data/backup"; import { BackupScheduleRecurrence, computeBackupAgentName, @@ -25,6 +25,8 @@ class HaBackupBackupsSummary extends LitElement { @property({ attribute: false }) public config!: BackupConfig; + @property({ attribute: false }) public agents!: BackupAgent[]; + private _configure() { navigate("/config/backup/settings"); } @@ -160,7 +162,7 @@ class HaBackupBackupsSummary extends LitElement { const name = computeBackupAgentName( this.hass.localize, offsiteLocations[0], - offsiteLocations + this.agents ); return this.hass.localize( "ui.panel.config.backup.overview.settings.locations_one", diff --git a/src/panels/config/backup/dialogs/dialog-generate-backup.ts b/src/panels/config/backup/dialogs/dialog-generate-backup.ts index 8c952514c3..076ca101b4 100644 --- a/src/panels/config/backup/dialogs/dialog-generate-backup.ts +++ b/src/panels/config/backup/dialogs/dialog-generate-backup.ts @@ -18,6 +18,7 @@ import "../../../../components/ha-md-select"; import "../../../../components/ha-md-select-option"; import "../../../../components/ha-textfield"; import type { + BackupAgent, BackupConfig, GenerateBackupParams, } from "../../../../data/backup"; @@ -64,7 +65,7 @@ class DialogGenerateBackup extends LitElement implements HassDialog { @state() private _step?: "data" | "sync"; - @state() private _agentIds: string[] = []; + @state() private _agents: BackupAgent[] = []; @state() private _backupConfig?: BackupConfig; @@ -89,7 +90,7 @@ class DialogGenerateBackup extends LitElement implements HassDialog { } this._step = undefined; this._formData = undefined; - this._agentIds = []; + this._agents = []; this._backupConfig = undefined; this._params = undefined; fireEvent(this, "dialog-closed", { dialog: this.localName }); @@ -97,15 +98,14 @@ class DialogGenerateBackup extends LitElement implements HassDialog { private async _fetchAgents() { const { agents } = await fetchBackupAgentsInfo(this.hass); - this._agentIds = agents - .map((agent) => agent.agent_id) + this._agents = agents .filter( - (id) => - id !== CLOUD_AGENT || + (agent) => + agent.agent_id !== CLOUD_AGENT || (this._params?.cloudStatus?.logged_in && this._params?.cloudStatus?.active_subscription) ) - .sort(compareAgents); + .sort((a, b) => compareAgents(a.agent_id, b.agent_id)); } private async _fetchBackupConfig() { @@ -134,6 +134,10 @@ class DialogGenerateBackup extends LitElement implements HassDialog { this._step = STEPS[index + 1]; } + private get _allAgentIds() { + return this._agents.map((agent) => agent.agent_id); + } + protected willUpdate(changedProperties: PropertyValues): void { super.willUpdate(changedProperties); @@ -144,7 +148,7 @@ class DialogGenerateBackup extends LitElement implements HassDialog { // Remove disallowed agents from the list const agentsIds = this._formData.agents_mode === "all" - ? this._agentIds + ? this._allAgentIds : this._formData.agent_ids; const filteredAgents = agentsIds.filter( @@ -309,7 +313,7 @@ class DialogGenerateBackup extends LitElement implements HassDialog {
${this.hass.localize( "ui.panel.config.backup.dialogs.generate.sync.locations_options.all", - { count: this._agentIds.length } + { count: this._allAgentIds.length } )}
@@ -350,7 +354,7 @@ class DialogGenerateBackup extends LitElement implements HassDialog { .hass=${this.hass} .value=${this._formData.agent_ids} @value-changed=${this._agentsChanged} - .agentIds=${this._agentIds} + .agents=${this._agents} .disabledAgentIds=${disabledAgentIds} > @@ -385,7 +389,7 @@ class DialogGenerateBackup extends LitElement implements HassDialog { if (!this._formData) { return []; } - const allAgents = this._agentIds; + const allAgents = this._allAgentIds; return !this._formData.data.include_homeassistant ? DISALLOWED_AGENTS_NO_HA.filter((agentId) => allAgents.includes(agentId)) : []; @@ -403,7 +407,7 @@ class DialogGenerateBackup extends LitElement implements HassDialog { const params: GenerateBackupParams = { name, password, - agent_ids: agents_mode === "all" ? this._agentIds : agent_ids, + agent_ids: agents_mode === "all" ? this._allAgentIds : agent_ids, // We always include homeassistant if we include database include_homeassistant: data.include_homeassistant || data.include_database, diff --git a/src/panels/config/backup/ha-config-backup-backups.ts b/src/panels/config/backup/ha-config-backup-backups.ts index 5e1eddb86b..4ac0dfca81 100644 --- a/src/panels/config/backup/ha-config-backup-backups.ts +++ b/src/panels/config/backup/ha-config-backup-backups.ts @@ -33,7 +33,11 @@ import "../../../components/ha-icon-next"; import "../../../components/ha-icon-overflow-menu"; import "../../../components/ha-list-item"; import "../../../components/ha-svg-icon"; -import type { BackupConfig, BackupContent } from "../../../data/backup"; +import type { + BackupAgent, + BackupConfig, + BackupContent, +} from "../../../data/backup"; import { computeBackupAgentName, deleteBackup, @@ -86,6 +90,8 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) { @property({ attribute: false }) public config?: BackupConfig; + @property({ attribute: false }) public agents: BackupAgent[] = []; + @state() private _selected: string[] = []; @storage({ @@ -169,7 +175,7 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) { const name = computeBackupAgentName( this.hass.localize, agentId, - backup.agent_ids + this.agents ); if (isLocalAgent(agentId)) { return html` diff --git a/src/panels/config/backup/ha-config-backup-details.ts b/src/panels/config/backup/ha-config-backup-details.ts index 5b91462e46..9a80de3bf2 100644 --- a/src/panels/config/backup/ha-config-backup-details.ts +++ b/src/panels/config/backup/ha-config-backup-details.ts @@ -21,6 +21,7 @@ import "../../../components/ha-list-item"; import "../../../components/ha-md-list"; import "../../../components/ha-md-list-item"; import type { + BackupAgent, BackupConfig, BackupContentExtended, BackupData, @@ -70,6 +71,8 @@ class HaConfigBackupDetails extends LitElement { @property({ attribute: false }) public config?: BackupConfig; + @property({ attribute: false }) public agents: BackupAgent[] = []; + @state() private _backup?: BackupContentExtended | null; @state() private _agents: Agent[] = []; @@ -232,7 +235,7 @@ class HaConfigBackupDetails extends LitElement { const name = computeBackupAgentName( this.hass.localize, agentId, - this._backup!.agent_ids + this.agents ); return html` diff --git a/src/panels/config/backup/ha-config-backup-overview.ts b/src/panels/config/backup/ha-config-backup-overview.ts index e121d62b30..e71212917c 100644 --- a/src/panels/config/backup/ha-config-backup-overview.ts +++ b/src/panels/config/backup/ha-config-backup-overview.ts @@ -13,11 +13,14 @@ import "../../../components/ha-icon-next"; import "../../../components/ha-icon-overflow-menu"; import "../../../components/ha-list-item"; import "../../../components/ha-svg-icon"; +import type { + BackupAgent, + BackupConfig, + BackupContent, +} from "../../../data/backup"; import { generateBackup, generateBackupWithAutomaticSettings, - type BackupConfig, - type BackupContent, } from "../../../data/backup"; import type { ManagerStateEvent } from "../../../data/backup_manager"; import type { CloudStatus } from "../../../data/cloud"; @@ -53,6 +56,8 @@ class HaConfigBackupOverview extends LitElement { @property({ attribute: false }) public config?: BackupConfig; + @property({ attribute: false }) public agents: BackupAgent[] = []; + private async _uploadBackup(ev) { if (!shouldHandleRequestSelectedEvent(ev)) { return; @@ -184,6 +189,7 @@ class HaConfigBackupOverview extends LitElement { ` : nothing} diff --git a/src/panels/config/backup/ha-config-backup-settings.ts b/src/panels/config/backup/ha-config-backup-settings.ts index 958bf11663..31bba002a3 100644 --- a/src/panels/config/backup/ha-config-backup-settings.ts +++ b/src/panels/config/backup/ha-config-backup-settings.ts @@ -16,7 +16,7 @@ import "../../../components/ha-list-item"; import "../../../components/ha-alert"; import "../../../components/ha-password-field"; import "../../../components/ha-svg-icon"; -import type { BackupConfig } from "../../../data/backup"; +import type { BackupAgent, BackupConfig } from "../../../data/backup"; import { updateBackupConfig } from "../../../data/backup"; import type { CloudStatus } from "../../../data/cloud"; import "../../../layouts/hass-subpage"; @@ -39,6 +39,8 @@ class HaConfigBackupSettings extends LitElement { @property({ attribute: false }) public config?: BackupConfig; + @property({ attribute: false }) public agents: BackupAgent[] = []; + @state() private _config?: BackupConfig; protected willUpdate(changedProperties: PropertyValues): void { @@ -178,6 +180,7 @@ class HaConfigBackupSettings extends LitElement { .hass=${this.hass} .value=${this._config.create_backup.agent_ids} .cloudStatus=${this.cloudStatus} + .agents=${this.agents} @value-changed=${this._agentsConfigChanged} > ${!this._config.create_backup.agent_ids.length diff --git a/src/panels/config/backup/ha-config-backup.ts b/src/panels/config/backup/ha-config-backup.ts index c4e323656b..07cd5ff639 100644 --- a/src/panels/config/backup/ha-config-backup.ts +++ b/src/panels/config/backup/ha-config-backup.ts @@ -1,9 +1,14 @@ import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import type { PropertyValues } from "lit"; import { customElement, property, state } from "lit/decorators"; -import type { BackupConfig, BackupContent } from "../../../data/backup"; +import type { + BackupAgent, + BackupConfig, + BackupContent, +} from "../../../data/backup"; import { compareAgents, + fetchBackupAgentsInfo, fetchBackupConfig, fetchBackupInfo, } from "../../../data/backup"; @@ -41,6 +46,8 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) { @state() private _backups: BackupContent[] = []; + @state() private _agents: BackupAgent[] = []; + @state() private _fetching = false; @state() private _config?: BackupConfig; @@ -54,15 +61,20 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) { this.addEventListener("ha-refresh-backup-config", () => { this._fetchBackupConfig(); }); + this.addEventListener("ha-refresh-backup-agents", () => { + this._fetchBackupAgents(); + }); } private _fetchAll() { this._fetching = true; - Promise.all([this._fetchBackupInfo(), this._fetchBackupConfig()]).finally( - () => { - this._fetching = false; - } - ); + Promise.all([ + this._fetchBackupInfo(), + this._fetchBackupConfig(), + this._fetchBackupAgents(), + ]).finally(() => { + this._fetching = false; + }); } public connectedCallback() { @@ -70,6 +82,7 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) { if (this.hasUpdated) { this._fetchBackupInfo(); this._fetchBackupConfig(); + this._fetchBackupAgents(); } } @@ -87,6 +100,11 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) { this._config = config; } + private async _fetchBackupAgents() { + const { agents } = await fetchBackupAgentsInfo(this.hass); + this._agents = agents.sort((a, b) => compareAgents(a.agent_id, b.agent_id)); + } + protected routerOptions: RouterOptions = { defaultPage: "overview", routes: { @@ -117,6 +135,7 @@ class HaConfigBackup extends SubscribeMixin(HassRouterPage) { pageEl.manager = this._manager; pageEl.backups = this._backups; pageEl.config = this._config; + pageEl.agents = this._agents; pageEl.fetching = this._fetching; if (