Add icon and description for network mount locations (#23390)

* Use custom icon and name for network storage

* Add note to local backup location dialog
This commit is contained in:
Paul Bottein 2024-12-23 11:53:31 +01:00 committed by GitHub
parent 52e1f9315e
commit 6afcd4d770
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 127 additions and 48 deletions

View File

@ -220,6 +220,11 @@ export const CLOUD_AGENT = "cloud.cloud";
export const isLocalAgent = (agentId: string) => export const isLocalAgent = (agentId: string) =>
[CORE_LOCAL_AGENT, HASSIO_LOCAL_AGENT].includes(agentId); [CORE_LOCAL_AGENT, HASSIO_LOCAL_AGENT].includes(agentId);
export const isNetworkMountAgent = (agentId: string) => {
const [domain, name] = agentId.split(".");
return domain === "hassio" && name !== "local";
};
export const computeBackupAgentName = ( export const computeBackupAgentName = (
localize: LocalizeFunc, localize: LocalizeFunc,
agentId: string, agentId: string,
@ -229,6 +234,11 @@ export const computeBackupAgentName = (
return "This system"; return "This system";
} }
const [domain, name] = agentId.split("."); const [domain, name] = agentId.split(".");
if (isNetworkMountAgent(agentId)) {
return name;
}
const domainName = domainToName(localize, domain); const domainName = domainToName(localize, domain);
// If there are multiple agents for a domain, show the name // If there are multiple agents for a domain, show the name
@ -242,7 +252,23 @@ export const computeBackupAgentName = (
export const compareAgents = (a: string, b: string) => { export const compareAgents = (a: string, b: string) => {
const isLocalA = isLocalAgent(a); const isLocalA = isLocalAgent(a);
const isLocalB = isLocalAgent(b); const isLocalB = isLocalAgent(b);
return isLocalA === isLocalB ? a.localeCompare(b) : isLocalA ? -1 : 1; const isNetworkMountAgentA = isNetworkMountAgent(a);
const isNetworkMountAgentB = isNetworkMountAgent(b);
const getPriority = (isLocal: boolean, isNetworkMount: boolean) => {
if (isLocal) return 1;
if (isNetworkMount) return 2;
return 3;
};
const priorityA = getPriority(isLocalA, isNetworkMountAgentA);
const priorityB = getPriority(isLocalB, isNetworkMountAgentB);
if (priorityA !== priorityB) {
return priorityA - priorityB;
}
return a.localeCompare(b);
}; };
export const generateEncryptionKey = () => { export const generateEncryptionKey = () => {

View File

@ -1,4 +1,4 @@
import { mdiHarddisk } from "@mdi/js"; import { mdiHarddisk, mdiNas } from "@mdi/js";
import type { PropertyValues } from "lit"; import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit"; import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
@ -14,6 +14,7 @@ import {
computeBackupAgentName, computeBackupAgentName,
fetchBackupAgentsInfo, fetchBackupAgentsInfo,
isLocalAgent, isLocalAgent,
isNetworkMountAgent,
} from "../../../../../data/backup"; } from "../../../../../data/backup";
import type { CloudStatus } from "../../../../../data/cloud"; import type { CloudStatus } from "../../../../../data/cloud";
import type { HomeAssistant } from "../../../../../types"; import type { HomeAssistant } from "../../../../../types";
@ -52,6 +53,9 @@ class HaBackupConfigAgents extends LitElement {
if (agentId === CLOUD_AGENT) { if (agentId === CLOUD_AGENT) {
return "It stores one backup. The oldest backups are deleted."; return "It stores one backup. The oldest backups are deleted.";
} }
if (isNetworkMountAgent(agentId)) {
return "Network storage";
}
return ""; return "";
} }
@ -75,20 +79,27 @@ class HaBackupConfigAgents extends LitElement {
<ha-svg-icon .path=${mdiHarddisk} slot="start"> <ha-svg-icon .path=${mdiHarddisk} slot="start">
</ha-svg-icon> </ha-svg-icon>
` `
: html` : isNetworkMountAgent(agentId)
<img ? html`
.src=${brandsUrl({ <ha-svg-icon
domain, .path=${mdiNas}
type: "icon", slot="start"
useFallback: true, ></ha-svg-icon>
darkOptimized: this.hass.themes?.darkMode, `
})} : html`
crossorigin="anonymous" <img
referrerpolicy="no-referrer" .src=${brandsUrl({
alt="" domain,
slot="start" type: "icon",
/> useFallback: true,
`} darkOptimized: this.hass.themes?.darkMode,
})}
crossorigin="anonymous"
referrerpolicy="no-referrer"
alt=""
slot="start"
/>
`}
<div slot="headline">${name}</div> <div slot="headline">${name}</div>
${description ${description
? html`<div slot="supporting-text">${description}</div>` ? html`<div slot="supporting-text">${description}</div>`

View File

@ -1,4 +1,4 @@
import { mdiHarddisk } from "@mdi/js"; import { mdiHarddisk, mdiNas } from "@mdi/js";
import { css, html, LitElement } from "lit"; import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map"; import { classMap } from "lit/directives/class-map";
@ -7,7 +7,11 @@ import { computeDomain } from "../../../../common/entity/compute_domain";
import "../../../../components/ha-checkbox"; import "../../../../components/ha-checkbox";
import "../../../../components/ha-formfield"; import "../../../../components/ha-formfield";
import "../../../../components/ha-svg-icon"; import "../../../../components/ha-svg-icon";
import { computeBackupAgentName, isLocalAgent } from "../../../../data/backup"; import {
computeBackupAgentName,
isLocalAgent,
isNetworkMountAgent,
} from "../../../../data/backup";
import type { HomeAssistant } from "../../../../types"; import type { HomeAssistant } from "../../../../types";
import { brandsUrl } from "../../../../util/brands-url"; import { brandsUrl } from "../../../../util/brands-url";
@ -54,20 +58,22 @@ class HaBackupAgentsPicker extends LitElement {
? html` ? html`
<ha-svg-icon .path=${mdiHarddisk} slot="start"> </ha-svg-icon> <ha-svg-icon .path=${mdiHarddisk} slot="start"> </ha-svg-icon>
` `
: html` : isNetworkMountAgent(agentId)
<img ? html` <ha-svg-icon .path=${mdiNas} slot="start"></ha-svg-icon> `
.src=${brandsUrl({ : html`
domain, <img
type: "icon", .src=${brandsUrl({
useFallback: true, domain,
darkOptimized: this.hass.themes?.darkMode, type: "icon",
})} useFallback: true,
crossorigin="anonymous" darkOptimized: this.hass.themes?.darkMode,
referrerpolicy="no-referrer" })}
alt="" crossorigin="anonymous"
slot="start" referrerpolicy="no-referrer"
/> alt=""
`} slot="start"
/>
`}
${name} ${name}
</span> </span>
<ha-checkbox <ha-checkbox

View File

@ -5,6 +5,7 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-button"; import "../../../../components/ha-button";
import { createCloseHeading } from "../../../../components/ha-dialog"; import { createCloseHeading } from "../../../../components/ha-dialog";
import "../../../../components/ha-form/ha-form"; import "../../../../components/ha-form/ha-form";
import "../../../../components/ha-alert";
import type { import type {
HaFormSchema, HaFormSchema,
SchemaUnion, SchemaUnion,
@ -83,6 +84,11 @@ class LocalBackupLocationDialog extends LitElement {
@value-changed=${this._valueChanged} @value-changed=${this._valueChanged}
dialogInitialFocus dialogInitialFocus
></ha-form> ></ha-form>
<ha-alert alert-type="info">
${this.hass.localize(
`ui.panel.config.backup.dialogs.local_backup_location.note`
)}
</ha-alert>
<ha-button <ha-button
slot="secondaryAction" slot="secondaryAction"
@click=${this.closeDialog} @click=${this.closeDialog}
@ -139,6 +145,10 @@ class LocalBackupLocationDialog extends LitElement {
ha-dialog { ha-dialog {
--mdc-dialog-max-width: 500px; --mdc-dialog-max-width: 500px;
} }
ha-form {
display: block;
margin-bottom: 16px;
}
`, `,
]; ];
} }

View File

@ -3,6 +3,7 @@ import {
mdiDotsVertical, mdiDotsVertical,
mdiDownload, mdiDownload,
mdiHarddisk, mdiHarddisk,
mdiNas,
mdiPlus, mdiPlus,
mdiUpload, mdiUpload,
} from "@mdi/js"; } from "@mdi/js";
@ -43,6 +44,7 @@ import {
getBackupDownloadUrl, getBackupDownloadUrl,
getPreferredAgentForDownload, getPreferredAgentForDownload,
isLocalAgent, isLocalAgent,
isNetworkMountAgent,
} from "../../../data/backup"; } from "../../../data/backup";
import type { ManagerStateEvent } from "../../../data/backup_manager"; import type { ManagerStateEvent } from "../../../data/backup_manager";
import type { CloudStatus } from "../../../data/cloud"; import type { CloudStatus } from "../../../data/cloud";
@ -183,6 +185,15 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
></ha-svg-icon> ></ha-svg-icon>
`; `;
} }
if (isNetworkMountAgent(agentId)) {
return html`
<ha-svg-icon
.path=${mdiNas}
title=${name}
slot="graphic"
></ha-svg-icon>
`;
}
const domain = computeDomain(agentId); const domain = computeDomain(agentId);
return html` return html`
<img <img

View File

@ -1,5 +1,11 @@
import type { ActionDetail } from "@material/mwc-list"; import type { ActionDetail } from "@material/mwc-list";
import { mdiDelete, mdiDotsVertical, mdiDownload, mdiHarddisk } from "@mdi/js"; import {
mdiDelete,
mdiDotsVertical,
mdiDownload,
mdiHarddisk,
mdiNas,
} from "@mdi/js";
import { css, html, LitElement, nothing } from "lit"; import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { formatDateTime } from "../../../common/datetime/format_date_time"; import { formatDateTime } from "../../../common/datetime/format_date_time";
@ -24,6 +30,7 @@ import {
getBackupDownloadUrl, getBackupDownloadUrl,
getPreferredAgentForDownload, getPreferredAgentForDownload,
isLocalAgent, isLocalAgent,
isNetworkMountAgent,
} from "../../../data/backup"; } from "../../../data/backup";
import type { HassioAddonInfo } from "../../../data/hassio/addon"; import type { HassioAddonInfo } from "../../../data/hassio/addon";
import "../../../layouts/hass-subpage"; import "../../../layouts/hass-subpage";
@ -184,21 +191,28 @@ class HaConfigBackupDetails extends LitElement {
> >
</ha-svg-icon> </ha-svg-icon>
` `
: html` : isNetworkMountAgent(agentId)
<img ? html`
.src=${brandsUrl({ <ha-svg-icon
domain, .path=${mdiNas}
type: "icon", slot="start"
useFallback: true, ></ha-svg-icon>
darkOptimized: `
this.hass.themes?.darkMode, : html`
})} <img
crossorigin="anonymous" .src=${brandsUrl({
referrerpolicy="no-referrer" domain,
alt="" type: "icon",
slot="start" useFallback: true,
/> darkOptimized:
`} this.hass.themes?.darkMode,
})}
crossorigin="anonymous"
referrerpolicy="no-referrer"
alt=""
slot="start"
/>
`}
<div slot="headline">${name}</div> <div slot="headline">${name}</div>
<div slot="supporting-text"> <div slot="supporting-text">
<span <span

View File

@ -2214,6 +2214,7 @@
"local_backup_location": { "local_backup_location": {
"title": "Change local backup location", "title": "Change local backup location",
"description": "Change the default location where local backups are stored on your Home Assistant instance.", "description": "Change the default location where local backups are stored on your Home Assistant instance.",
"note": "This location will be used when you create a backup using the supervisor actions in an automation for example.",
"options": { "options": {
"default_backup_mount": { "default_backup_mount": {
"name": "Default location" "name": "Default location"