From 9155c855093143ff8f087e9db7f75a37976ee8c4 Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Mon, 5 May 2025 15:05:35 +0200 Subject: [PATCH 01/75] Fix zwave add device LR/mesh icons (#25313) Fix zwave LR/mesh icons --- .../images/z-wave-add-node/long-range.svg | 10 +++---- public/static/images/z-wave-add-node/mesh.svg | 30 +++++++++---------- .../images/z-wave-add-node/mesh_dark.svg | 29 +++++++++--------- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/public/static/images/z-wave-add-node/long-range.svg b/public/static/images/z-wave-add-node/long-range.svg index 48deddc513..32fa115cc8 100644 --- a/public/static/images/z-wave-add-node/long-range.svg +++ b/public/static/images/z-wave-add-node/long-range.svg @@ -1,13 +1,13 @@ - + - + - - + + - + diff --git a/public/static/images/z-wave-add-node/mesh.svg b/public/static/images/z-wave-add-node/mesh.svg index 92a03c444a..48fba567f4 100644 --- a/public/static/images/z-wave-add-node/mesh.svg +++ b/public/static/images/z-wave-add-node/mesh.svg @@ -1,19 +1,19 @@ - - - - - - - - + + + + + + + + - - + + - - - - - + + + + + diff --git a/public/static/images/z-wave-add-node/mesh_dark.svg b/public/static/images/z-wave-add-node/mesh_dark.svg index 1824489e47..22cda5e4f1 100644 --- a/public/static/images/z-wave-add-node/mesh_dark.svg +++ b/public/static/images/z-wave-add-node/mesh_dark.svg @@ -1,19 +1,18 @@ - - - - - - - - + + + + + + + - - + + - - - - - + + + + + From fb3a59272ddd550f34b22081c4051f5e1bba12f0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 5 May 2025 12:54:33 -0400 Subject: [PATCH 02/75] Reorder my links (#25319) --- src/panels/my/ha-panel-my.ts | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/panels/my/ha-panel-my.ts b/src/panels/my/ha-panel-my.ts index c308cc32e4..d41ef36863 100644 --- a/src/panels/my/ha-panel-my.ts +++ b/src/panels/my/ha-panel-my.ts @@ -16,6 +16,11 @@ import "../../layouts/hass-error-screen"; import type { HomeAssistant, Route } from "../../types"; import { documentationUrl } from "../../util/documentation-url"; +// When a user presses "m", the user is redirected to the first redirect +// for which holds true currentPath.startsWith(redirect.redirect) +// That's why redirects should be sorted with more specific ones first +// Or else pressing "M" will link to the higher level page. + export const getMyRedirects = (): Redirects => ({ application_credentials: { redirect: "/config/application_credentials", @@ -73,15 +78,15 @@ export const getMyRedirects = (): Redirects => ({ brand: "string", }, }, - integrations: { - redirect: "/config/integrations", - }, integration: { redirect: "/config/integrations/integration", params: { domain: "string", }, }, + integrations: { + redirect: "/config/integrations", + }, config_mqtt: { component: "mqtt", redirect: "/config/mqtt", @@ -106,10 +111,6 @@ export const getMyRedirects = (): Redirects => ({ component: "matter", redirect: "/config/matter/add", }, - config_bluetooth: { - component: "bluetooth", - redirect: "/config/bluetooth", - }, bluetooth_advertisement_monitor: { component: "bluetooth", redirect: "/config/bluetooth/advertisement-monitor", @@ -118,6 +119,10 @@ export const getMyRedirects = (): Redirects => ({ component: "bluetooth", redirect: "/config/bluetooth/connection-monitor", }, + config_bluetooth: { + component: "bluetooth", + redirect: "/config/bluetooth", + }, config_dhcp: { component: "dhcp", redirect: "/config/dhcp", @@ -252,12 +257,12 @@ export const getMyRedirects = (): Redirects => ({ // customize was removed in 2021.12, fallback to dashboard redirect: "/config/dashboard", }, - profile: { - redirect: "/profile", - }, profile_security: { redirect: "/profile/security", }, + profile: { + redirect: "/profile", + }, logbook: { component: "logbook", redirect: "/logbook", @@ -270,10 +275,6 @@ export const getMyRedirects = (): Redirects => ({ component: "media_source", redirect: "/media-browser", }, - backup: { - component: "backup", - redirect: "/config/backup", - }, backup_list: { component: "backup", redirect: "/config/backup/backups", @@ -282,6 +283,10 @@ export const getMyRedirects = (): Redirects => ({ component: "backup", redirect: "/config/backup/settings", }, + backup: { + component: "backup", + redirect: "/config/backup", + }, supervisor_snapshots: { component: "backup", redirect: "/config/backup", From 4ec5fbc9a4620aa61a45689602b4d146e38a04cd Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Mon, 5 May 2025 18:56:16 +0200 Subject: [PATCH 03/75] Do not display no areas in entity pickers (#25317) --- src/components/entity/ha-entity-combo-box.ts | 4 +--- src/components/entity/ha-entity-picker.ts | 5 +---- src/dialogs/quick-bar/ha-quick-bar.ts | 23 +++++++++++++++++--- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/components/entity/ha-entity-combo-box.ts b/src/components/entity/ha-entity-combo-box.ts index 9a89fe23d3..f0f3ede62b 100644 --- a/src/components/entity/ha-entity-combo-box.ts +++ b/src/components/entity/ha-entity-combo-box.ts @@ -314,9 +314,7 @@ export class HaEntityComboBox extends LitElement { ...hass!.states[entityId], label: "", primary: primary, - secondary: - secondary || - this.hass.localize("ui.components.device-picker.no_area"), + secondary: secondary, translated_domain: translatedDomain, sorting_label: [deviceName, entityName].filter(Boolean).join("-"), entity_name: entityName || deviceName, diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index 0cba69c515..515a5a58b4 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -162,10 +162,7 @@ export class HaEntityPicker extends LitElement { slot="start" > ${primary} - - ${secondary || - this.hass.localize("ui.components.device-picker.no_area")} - + ${secondary} ${showClearIcon ? html` Date: Mon, 5 May 2025 17:06:05 +0000 Subject: [PATCH 04/75] Update dependency @codemirror/view to v6.36.7 (#25320) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index fe500893b7..b6cd23a971 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@codemirror/legacy-modes": "6.5.1", "@codemirror/search": "6.5.10", "@codemirror/state": "6.5.2", - "@codemirror/view": "6.36.6", + "@codemirror/view": "6.36.7", "@egjs/hammerjs": "2.0.17", "@formatjs/intl-datetimeformat": "6.18.0", "@formatjs/intl-displaynames": "6.8.11", diff --git a/yarn.lock b/yarn.lock index 40ba4f821a..5331f5b96d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1242,14 +1242,14 @@ __metadata: languageName: node linkType: hard -"@codemirror/view@npm:6.36.6, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0": - version: 6.36.6 - resolution: "@codemirror/view@npm:6.36.6" +"@codemirror/view@npm:6.36.7, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0": + version: 6.36.7 + resolution: "@codemirror/view@npm:6.36.7" dependencies: "@codemirror/state": "npm:^6.5.0" style-mod: "npm:^4.1.0" w3c-keyname: "npm:^2.2.4" - checksum: 10/a98d19fe8a76557ac442cd173bac83e0a471a00db98c4a8da35c7e80e78a23f4460e57eb46a66cc60f58ae854e5e35f1f0b9c8a3919cd8ef765f37a912c2b093 + checksum: 10/0ba49a3025fbb381a8a35022135ea40363a3a3c298d41e3083bb5e263dfa4f11ff9419a46f2b78ef8e853376384ad6c7e48d2a7887e10d366e878d10b53e3b54 languageName: node linkType: hard @@ -9225,7 +9225,7 @@ __metadata: "@codemirror/legacy-modes": "npm:6.5.1" "@codemirror/search": "npm:6.5.10" "@codemirror/state": "npm:6.5.2" - "@codemirror/view": "npm:6.36.6" + "@codemirror/view": "npm:6.36.7" "@egjs/hammerjs": "npm:2.0.17" "@formatjs/intl-datetimeformat": "npm:6.18.0" "@formatjs/intl-displaynames": "npm:6.8.11" From e069875432119e6aa0c2a70d8d23f17b297a7525 Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Mon, 5 May 2025 10:09:16 -0700 Subject: [PATCH 05/75] Add energy hourly calculations to CSV report (#25315) --- src/panels/energy/ha-panel-energy.ts | 120 +++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 7 deletions(-) diff --git a/src/panels/energy/ha-panel-energy.ts b/src/panels/energy/ha-panel-energy.ts index 7bf69dbc23..cb63510b66 100644 --- a/src/panels/energy/ha-panel-energy.ts +++ b/src/panels/energy/ha-panel-energy.ts @@ -22,11 +22,14 @@ import type { DeviceConsumptionEnergyPreference, } from "../../data/energy"; import { + computeConsumptionData, getEnergyDataCollection, getEnergyGasUnit, getEnergyWaterUnit, + getSummedData, } from "../../data/energy"; import { fileDownload } from "../../util/file_download"; +import type { StatisticValue } from "../../data/recorder"; const ENERGY_LOVELACE_CONFIG: LovelaceConfig = { views: [ @@ -177,18 +180,20 @@ class PanelEnergy extends LitElement { const csv: string[] = []; csv[0] = headers; - const processStat = function (stat: string, type: string, unit: string) { + const processCsvRow = function ( + id: string, + type: string, + unit: string, + data: StatisticValue[] + ) { let n = 0; const row: string[] = []; - if (!stats[stat]) { - return; - } - row.push(stat); + row.push(id); row.push(type); row.push(unit.normalize("NFKD")); times.forEach((t) => { - if (n < stats[stat].length && stats[stat][n].start === t) { - row.push((stats[stat][n].change ?? "").toString()); + if (n < data.length && data[n].start === t) { + row.push((data[n].change ?? "").toString()); n++; } else { row.push(""); @@ -197,6 +202,14 @@ class PanelEnergy extends LitElement { csv.push(row.join(",") + "\n"); }; + const processStat = function (stat: string, type: string, unit: string) { + if (!stats[stat]) { + return; + } + + processCsvRow(stat, type, unit, stats[stat]); + }; + const currency = this.hass.config.currency; const printCategory = function ( @@ -335,6 +348,99 @@ class PanelEnergy extends LitElement { printCategory("device_consumption", devices, electricUnit); + const { summedData, compareSummedData: _ } = getSummedData( + energyData.state + ); + const { consumption, compareConsumption: __ } = computeConsumptionData( + summedData, + undefined + ); + + const processConsumptionData = function ( + type: string, + unit: string, + data: Record + ) { + const data2: StatisticValue[] = []; + + Object.entries(data).forEach(([t, value]) => { + data2.push({ + start: Number(t), + end: NaN, + change: value, + }); + }); + + processCsvRow("", type, unit, data2); + }; + + const hasSolar = !!solar_productions.length; + const hasBattery = !!battery_ins.length; + const hasGridReturn = !!grid_productions.length; + const hasGridSource = !!grid_consumptions.length; + + if (hasGridSource) { + processConsumptionData( + "calculated_consumed_grid", + electricUnit, + consumption.used_grid + ); + if (hasBattery) { + processConsumptionData( + "calculated_grid_to_battery", + electricUnit, + consumption.grid_to_battery + ); + } + } + if (hasGridReturn && hasBattery) { + processConsumptionData( + "calculated_battery_to_grid", + electricUnit, + consumption.battery_to_grid + ); + } + if (hasBattery) { + processConsumptionData( + "calculated_consumed_battery", + electricUnit, + consumption.used_battery + ); + } + + if (hasSolar) { + processConsumptionData( + "calculated_consumed_solar", + electricUnit, + consumption.used_solar + ); + if (hasBattery) { + processConsumptionData( + "calculated_solar_to_battery", + electricUnit, + consumption.solar_to_battery + ); + } + if (hasGridReturn) { + processConsumptionData( + "calculated_solar_to_grid", + electricUnit, + consumption.solar_to_grid + ); + } + } + + if ( + (hasGridSource ? 1 : 0) + (hasSolar ? 1 : 0) + (hasBattery ? 1 : 0) > + 1 + ) { + processConsumptionData( + "calculated_total_consumption", + electricUnit, + consumption.used_total + ); + } + const blob = new Blob(csv, { type: "text/csv", }); From d63f610023ee9d64d21ef1e7c862e5f35cc43247 Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Mon, 5 May 2025 19:20:22 +0200 Subject: [PATCH 06/75] Fix options and repair flow success (#25312) --- .../config-flow/step-flow-create-entry.ts | 129 +++++++++--------- 1 file changed, 66 insertions(+), 63 deletions(-) diff --git a/src/dialogs/config-flow/step-flow-create-entry.ts b/src/dialogs/config-flow/step-flow-create-entry.ts index da5ab1d183..6f59bf593d 100644 --- a/src/dialogs/config-flow/step-flow-create-entry.ts +++ b/src/dialogs/config-flow/step-flow-create-entry.ts @@ -129,70 +129,73 @@ class StepFlowCreateEntry extends LitElement { )}` : nothing} - ${devices.length === 0 - ? html`

- ${localize( - "ui.panel.config.integrations.config_flow.created_config", - { name: this.step.title } - )} -

` - : html` -
- ${devices.map( - (device) => html` -
-
- ${this.step.result?.domain - ? html`${domainToName(` - : nothing} -
- ${device.model || device.manufacturer} - ${device.model - ? html` - ${device.manufacturer} - ` - : nothing} -
-
- - -
- ` + ${devices.length === 0 && + ["options_flow", "repair_flow"].includes(this.flowConfig.flowType) + ? nothing + : devices.length === 0 + ? html`

+ ${localize( + "ui.panel.config.integrations.config_flow.created_config", + { name: this.step.title } )} -

- `} +

` + : html` +
+ ${devices.map( + (device) => html` +
+
+ ${this.step.result?.domain + ? html`${domainToName(` + : nothing} +
+ ${device.model || device.manufacturer} + ${device.model + ? html` + ${device.manufacturer} + ` + : nothing} +
+
+ + +
+ ` + )} +
+ `}
Date: Mon, 5 May 2025 13:29:24 -0400 Subject: [PATCH 07/75] Clean up network browser nav (#25321) * Clean up network browser nav * Add ha-md-list --- .../config/network/ha-config-network-dhcp.ts | 66 ----------------- .../config/network/ha-config-network-ssdp.ts | 66 ----------------- .../network/ha-config-network-zeroconf.ts | 70 ------------------- .../network/ha-config-section-network.ts | 62 ++++++++++------ src/translations/en.json | 11 ++- 5 files changed, 47 insertions(+), 228 deletions(-) delete mode 100644 src/panels/config/network/ha-config-network-dhcp.ts delete mode 100644 src/panels/config/network/ha-config-network-ssdp.ts delete mode 100644 src/panels/config/network/ha-config-network-zeroconf.ts diff --git a/src/panels/config/network/ha-config-network-dhcp.ts b/src/panels/config/network/ha-config-network-dhcp.ts deleted file mode 100644 index ef70d11903..0000000000 --- a/src/panels/config/network/ha-config-network-dhcp.ts +++ /dev/null @@ -1,66 +0,0 @@ -import "@material/mwc-button/mwc-button"; -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import "../../../components/ha-button"; -import "../../../components/ha-card"; -import { haStyle } from "../../../resources/styles"; -import type { HomeAssistant } from "../../../types"; - -@customElement("ha-config-network-dhcp") -class ConfigNetworkDHCP extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - protected render() { - return html` - -
-

- ${this.hass.localize("ui.panel.config.network.discovery.dhcp_info")} -

-
- -
- `; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - css` - ha-settings-row { - padding: 0; - } - - .card-actions { - display: flex; - flex-direction: row-reverse; - justify-content: space-between; - align-items: center; - } - `, // row-reverse so we tab first to "save" - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "ha-config-network-dhcp": ConfigNetworkDHCP; - } -} diff --git a/src/panels/config/network/ha-config-network-ssdp.ts b/src/panels/config/network/ha-config-network-ssdp.ts deleted file mode 100644 index bd7bf83568..0000000000 --- a/src/panels/config/network/ha-config-network-ssdp.ts +++ /dev/null @@ -1,66 +0,0 @@ -import "@material/mwc-button/mwc-button"; -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import "../../../components/ha-button"; -import "../../../components/ha-card"; -import { haStyle } from "../../../resources/styles"; -import type { HomeAssistant } from "../../../types"; - -@customElement("ha-config-network-ssdp") -class ConfigNetworkSSDP extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - protected render() { - return html` - -
-

- ${this.hass.localize("ui.panel.config.network.discovery.ssdp_info")} -

-
- -
- `; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - css` - ha-settings-row { - padding: 0; - } - - .card-actions { - display: flex; - flex-direction: row-reverse; - justify-content: space-between; - align-items: center; - } - `, // row-reverse so we tab first to "save" - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "ha-config-network-ssdp": ConfigNetworkSSDP; - } -} diff --git a/src/panels/config/network/ha-config-network-zeroconf.ts b/src/panels/config/network/ha-config-network-zeroconf.ts deleted file mode 100644 index db97f0d019..0000000000 --- a/src/panels/config/network/ha-config-network-zeroconf.ts +++ /dev/null @@ -1,70 +0,0 @@ -import "@material/mwc-button/mwc-button"; -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import "../../../components/ha-button"; -import "../../../components/ha-card"; -import { haStyle } from "../../../resources/styles"; -import type { HomeAssistant } from "../../../types"; - -@customElement("ha-config-network-zeroconf") -class ConfigNetworkZeroconf extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - protected render() { - return html` - -
-

- ${this.hass.localize( - "ui.panel.config.network.discovery.zeroconf_info" - )} -

-
- -
- `; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - css` - ha-settings-row { - padding: 0; - } - - .card-actions { - display: flex; - flex-direction: row-reverse; - justify-content: space-between; - align-items: center; - } - `, // row-reverse so we tab first to "save" - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "ha-config-network-zeroconf": ConfigNetworkZeroconf; - } -} diff --git a/src/panels/config/network/ha-config-section-network.ts b/src/panels/config/network/ha-config-section-network.ts index c9a3df311d..567c18eb0f 100644 --- a/src/panels/config/network/ha-config-section-network.ts +++ b/src/panels/config/network/ha-config-section-network.ts @@ -3,15 +3,18 @@ import { css, html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import "../../../layouts/hass-subpage"; +import "../../../components/ha-card"; +import "../../../components/ha-md-list"; +import "../../../components/ha-md-list-item"; +import "../../../components/ha-icon-next"; import type { HomeAssistant, Route } from "../../../types"; import "./ha-config-network"; -import "./ha-config-network-dhcp"; -import "./ha-config-network-ssdp"; -import "./ha-config-network-zeroconf"; import "./ha-config-url-form"; import "./supervisor-hostname"; import "./supervisor-network"; +const NETWORK_BROWSERS = ["dhcp", "ssdp", "zeroconf"] as const; + @customElement("ha-config-section-network") class HaConfigSectionNetwork extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -38,20 +41,38 @@ class HaConfigSectionNetwork extends LitElement { : ""} - ${isComponentLoaded(this.hass, "dhcp") - ? html`` - : ""} - ${isComponentLoaded(this.hass, "ssdp") - ? html`` - : ""} - ${isComponentLoaded(this.hass, "zeroconf") - ? html`` + ${NETWORK_BROWSERS.some((component) => + isComponentLoaded(this.hass, component) + ) + ? html` + + + ${NETWORK_BROWSERS.map( + (domain) => html` + +
+ ${this.hass.localize( + `ui.panel.config.network.discovery.${domain}` + )} +
+
+ ${this.hass.localize( + `ui.panel.config.network.discovery.${domain}_info` + )} +
+ +
+ ` + )} +
+
+ ` : ""}
@@ -68,14 +89,15 @@ class HaConfigSectionNetwork extends LitElement { supervisor-network, ha-config-url-form, ha-config-network, - ha-config-network-dhcp, - ha-config-network-ssdp, - ha-config-network-zeroconf { + .discovery-card { display: block; margin: 0 auto; margin-bottom: 24px; max-width: 600px; } + .discovery-card ha-md-list { + padding-top: 0; + } `; } diff --git a/src/translations/en.json b/src/translations/en.json index 519b6a2968..374d86b6a9 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -6401,15 +6401,14 @@ } }, "discovery": { + "title": "Network discovery", + "description": "Explore what data Home Assistant can see on the network.", "dhcp": "DHCP browser", - "dhcp_info": "The DHCP browser shows devices detected by Home Assistant using methods like DHCP, ARP+PTR lookups, and router-based device trackers. DHCP (Dynamic Host Configuration Protocol) data is received when devices join the network and request an IP address, allowing Home Assistant to discover them automatically. All devices found through these methods will appear here.", - "dhcp_browser": "View DHCP browser", + "dhcp_info": "Show devices detected by Home Assistant using methods like DHCP, ARP+PTR lookups, and router-based device trackers. DHCP (Dynamic Host Configuration Protocol) data is received when devices join the network and request an IP address.", "ssdp": "SSDP browser", - "ssdp_info": "The SSDP browser shows devices discovered by Home Assistant using SSDP/UPnP. Devices that Home Assistant has discovered will appear here.", - "ssdp_browser": "View SSDP browser", + "ssdp_info": "Show devices discovered by Home Assistant using SSDP/UPnP. Devices that Home Assistant has discovered will appear here.", "zeroconf": "Zeroconf browser", - "zeroconf_info": "The Zeroconf browser shows devices discovered by Home Assistant using mDNS. Only devices that Home Assistant is actively searching for will appear here.", - "zeroconf_browser": "View Zeroconf browser" + "zeroconf_info": "Show devices discovered by Home Assistant using mDNS. Only devices that Home Assistant is actively searching for will appear here." }, "network_adapter": "Network adapter", "network_adapter_info": "Configure which network adapters integrations will use. Currently this setting only affects multicast traffic. A restart is required for these settings to apply.", From 7434b12d9f40546cc8fffd660a2cb78be8d8ffca Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Mon, 5 May 2025 19:37:47 +0200 Subject: [PATCH 08/75] Use new entity naming in card entity picker (#25316) --- .../badge-editor/hui-dialog-create-badge.ts | 19 -- .../card-editor/hui-dialog-create-card.ts | 19 -- .../card-editor/hui-entity-picker-table.ts | 255 +++++++++++++----- .../unused-entities/hui-unused-entities.ts | 25 +- 4 files changed, 195 insertions(+), 123 deletions(-) diff --git a/src/panels/lovelace/editor/badge-editor/hui-dialog-create-badge.ts b/src/panels/lovelace/editor/badge-editor/hui-dialog-create-badge.ts index d14959e4fb..9388295802 100644 --- a/src/panels/lovelace/editor/badge-editor/hui-dialog-create-badge.ts +++ b/src/panels/lovelace/editor/badge-editor/hui-dialog-create-badge.ts @@ -4,11 +4,7 @@ import { css, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import { cache } from "lit/directives/cache"; import { classMap } from "lit/directives/class-map"; -import memoize from "memoize-one"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { computeStateName } from "../../../../common/entity/compute_state_name"; -import type { DataTableRowData } from "../../../../components/data-table/ha-data-table"; import "../../../../components/ha-dialog"; import "../../../../components/ha-dialog-header"; import "../../../../components/sl-tab-group"; @@ -137,7 +133,6 @@ export class HuiCreateDialogBadge no-label-float .hass=${this.hass} .narrow=${true} - .entities=${this._allEntities(this.hass.states)} @selected-changed=${this._handleSelectedChanged} > ` @@ -276,20 +271,6 @@ export class HuiCreateDialogBadge this.closeDialog(); } - - private _allEntities = memoize((entities) => - Object.keys(entities).map((entity) => { - const stateObj = this.hass.states[entity]; - return { - icon: "", - entity_id: entity, - stateObj, - name: computeStateName(stateObj), - domain: computeDomain(entity), - last_changed: stateObj!.last_changed, - } as DataTableRowData; - }) - ); } declare global { diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-create-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-create-card.ts index 314029fa0d..46927da9c8 100644 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-create-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-create-card.ts @@ -5,11 +5,7 @@ import { customElement, property, state } from "lit/decorators"; import { cache } from "lit/directives/cache"; import { classMap } from "lit/directives/class-map"; import { ifDefined } from "lit/directives/if-defined"; -import memoize from "memoize-one"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { computeStateName } from "../../../../common/entity/compute_state_name"; -import type { DataTableRowData } from "../../../../components/data-table/ha-data-table"; import "../../../../components/ha-dialog"; import "../../../../components/ha-dialog-header"; import "../../../../components/sl-tab-group"; @@ -157,7 +153,6 @@ export class HuiCreateDialogCard no-label-float .hass=${this.hass} narrow - .entities=${this._allEntities(this.hass.states)} @selected-changed=${this._handleSelectedChanged} > ` @@ -340,20 +335,6 @@ export class HuiCreateDialogCard this.closeDialog(); } - - private _allEntities = memoize((entities) => - Object.keys(entities).map((entity) => { - const stateObj = this.hass.states[entity]; - return { - icon: "", - entity_id: entity, - stateObj, - name: computeStateName(stateObj), - domain: computeDomain(entity), - last_changed: stateObj!.last_changed, - } as DataTableRowData; - }) - ); } declare global { diff --git a/src/panels/lovelace/editor/card-editor/hui-entity-picker-table.ts b/src/panels/lovelace/editor/card-editor/hui-entity-picker-table.ts index 5918aafef6..dd0c3a549c 100644 --- a/src/panels/lovelace/editor/card-editor/hui-entity-picker-table.ts +++ b/src/panels/lovelace/editor/card-editor/hui-entity-picker-table.ts @@ -1,9 +1,17 @@ -import type { TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; +import type { PropertyValues, TemplateResult } from "lit"; +import { css, html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators"; +import { styleMap } from "lit/directives/style-map"; import memoizeOne from "memoize-one"; import type { HASSDomEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { computeAreaName } from "../../../../common/entity/compute_area_name"; +import { computeDeviceName } from "../../../../common/entity/compute_device_name"; +import { computeDomain } from "../../../../common/entity/compute_domain"; +import { computeEntityName } from "../../../../common/entity/compute_entity_name"; +import { getEntityContext } from "../../../../common/entity/context/get_entity_context"; +import type { LocalizeFunc } from "../../../../common/translations/localize"; +import { computeRTL } from "../../../../common/util/compute_rtl"; import "../../../../components/data-table/ha-data-table"; import type { DataTableColumnContainer, @@ -12,8 +20,26 @@ import type { } from "../../../../components/data-table/ha-data-table"; import "../../../../components/entity/state-badge"; import "../../../../components/ha-relative-time"; +import { domainToName } from "../../../../data/integration"; import type { HomeAssistant } from "../../../../types"; +const ENTITY_ID_STYLE = styleMap({ + fontFamily: "var(--ha-font-family-code)", + fontSize: "var(--ha-font-size-xs)", +}); + +interface EntityPickerTableRowData extends DataTableRowData { + icon: string; + entity_id: string; + stateObj: any; + name: string; + entity_name?: string; + device_name?: string; + area_name?: string; + domain_name: string; + last_changed: string; +} + @customElement("hui-entity-picker-table") export class HuiEntityPickerTable extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -23,16 +49,69 @@ export class HuiEntityPickerTable extends LitElement { @property({ type: Boolean, attribute: "no-label-float" }) public noLabelFloat? = false; - @property({ type: Array }) public entities!: DataTableRowData[]; + @property({ type: Array }) public entities?: string[]; + + protected firstUpdated(_changedProperties: PropertyValues): void { + super.firstUpdated(_changedProperties); + this.hass.loadBackendTranslation("title"); + } + + private _data = memoizeOne( + ( + states: HomeAssistant["states"], + localize: LocalizeFunc, + entities?: string[] + ): EntityPickerTableRowData[] => + (entities || Object.keys(states)).map( + (entity) => { + const stateObj = this.hass.states[entity]; + + const { area, device } = getEntityContext(stateObj, this.hass); + + const entityName = computeEntityName(stateObj, this.hass); + const deviceName = device ? computeDeviceName(device) : undefined; + const areaName = area ? computeAreaName(area) : undefined; + const name = [deviceName, entityName].filter(Boolean).join(" "); + const domain = computeDomain(entity); + + return { + icon: "", + entity_id: entity, + stateObj, + name: name, + entity_name: entityName, + device_name: deviceName, + area_name: areaName, + domain_name: domainToName(localize, domain), + last_changed: stateObj!.last_changed, + } satisfies EntityPickerTableRowData; + } + ) + ); protected render(): TemplateResult { + const data = this._data( + this.hass.states, + this.hass.localize, + this.entities + ); + + const showEntityId = Boolean(this.hass.userData?.showEntityIdPicker); + + const columns = this._columns( + this.narrow, + computeRTL(this.hass), + showEntityId + ); + return html` { - const columns: DataTableColumnContainer = { - icon: { - title: "", - label: this.hass!.localize( - "ui.panel.lovelace.unused_entities.state_icon" + private _columns = memoizeOne( + (narrow: boolean, isRTL: boolean, showEntityId: boolean) => { + const columns: DataTableColumnContainer = { + icon: { + title: "", + label: this.hass!.localize( + "ui.panel.lovelace.unused_entities.state_icon" + ), + type: "icon", + template: (entity) => html` + + `, + }, + name: { + title: this.hass!.localize( + "ui.panel.lovelace.unused_entities.entity" + ), + sortable: true, + filterable: true, + flex: 2, + main: true, + direction: "asc", + template: (entity: any) => { + const primary = + entity.entity_name || entity.device_name || entity.entity_id; + const secondary = [ + entity.area_name, + entity.entity_name ? entity.device_name : undefined, + ] + .filter(Boolean) + .join(isRTL ? " ◂ " : " ▸ "); + return html` +
+ ${primary} + ${secondary + ? html`
${secondary}
` + : nothing} + ${narrow && showEntityId + ? html` +
+ ${entity.entity_id} +
+ ` + : nothing} +
+ `; + }, + }, + }; + + columns.entity_name = { + title: "entity_name", + filterable: true, + hidden: true, + }; + + columns.device_name = { + title: "device_name", + filterable: true, + hidden: true, + }; + + columns.area_name = { + title: "area_name", + filterable: true, + hidden: true, + }; + + columns.entity_id = { + title: this.hass!.localize( + "ui.panel.lovelace.unused_entities.entity_id" ), - type: "icon", - template: (entity) => html` - - `, - }, - name: { - title: this.hass!.localize("ui.panel.lovelace.unused_entities.entity"), sortable: true, filterable: true, - flex: 2, - main: true, - direction: "asc", - template: (entity: any) => html` -
- ${entity.name} - ${narrow - ? html`
${entity.entity_id}
` - : ""} -
+ hidden: narrow || !showEntityId, + }; + + columns.domain_name = { + title: this.hass!.localize("ui.panel.lovelace.unused_entities.domain"), + sortable: true, + filterable: true, + hidden: narrow || showEntityId, + }; + + columns.last_changed = { + title: this.hass!.localize( + "ui.panel.lovelace.unused_entities.last_changed" + ), + type: "numeric", + sortable: true, + hidden: narrow, + template: (entity) => html` + `, - }, - }; + }; - columns.entity_id = { - title: this.hass!.localize("ui.panel.lovelace.unused_entities.entity_id"), - sortable: true, - filterable: true, - hidden: narrow, - }; - - columns.domain = { - title: this.hass!.localize("ui.panel.lovelace.unused_entities.domain"), - sortable: true, - filterable: true, - hidden: narrow, - }; - - columns.last_changed = { - title: this.hass!.localize( - "ui.panel.lovelace.unused_entities.last_changed" - ), - type: "numeric", - sortable: true, - hidden: narrow, - template: (entity) => html` - - `, - }; - - return columns; - }); + return columns; + } + ); private _handleSelectionChanged( ev: HASSDomEvent @@ -134,6 +254,9 @@ export class HuiEntityPickerTable extends LitElement { --data-table-border-width: 0; height: 100%; } + ha-data-table.show-entity-id { + --data-table-row-height: 64px; + } `; } diff --git a/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts b/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts index a63d3e3a50..392f439f73 100644 --- a/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts +++ b/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts @@ -3,22 +3,19 @@ import type { PropertyValues } from "lit"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; -import { computeDomain } from "../../../../common/entity/compute_domain"; -import { computeStateName } from "../../../../common/entity/compute_state_name"; -import type { DataTableRowData } from "../../../../components/data-table/ha-data-table"; import "../../../../components/ha-fab"; import "../../../../components/ha-svg-icon"; +import type { LovelaceConfig } from "../../../../data/lovelace/config/types"; import type { HomeAssistant } from "../../../../types"; import { computeUnusedEntities } from "../../common/compute-unused-entities"; -import type { Lovelace } from "../../types"; -import "../card-editor/hui-entity-picker-table"; -import { showSuggestCardDialog } from "../card-editor/show-suggest-card-dialog"; -import { showSelectViewDialog } from "../select-view/show-select-view-dialog"; -import type { LovelaceConfig } from "../../../../data/lovelace/config/types"; import { computeCards, computeSection, } from "../../common/generate-lovelace-config"; +import type { Lovelace } from "../../types"; +import "../card-editor/hui-entity-picker-table"; +import { showSuggestCardDialog } from "../card-editor/show-suggest-card-dialog"; +import { showSelectViewDialog } from "../select-view/show-select-view-dialog"; @customElement("hui-unused-entities") export class HuiUnusedEntities extends LitElement { @@ -80,17 +77,7 @@ export class HuiUnusedEntities extends LitElement { { - const stateObj = this.hass!.states[entity]; - return { - icon: "", - entity_id: entity, - stateObj, - name: stateObj ? computeStateName(stateObj) : "Unavailable", - domain: computeDomain(entity), - last_changed: stateObj?.last_changed, - }; - }) as DataTableRowData[]} + .entities=${this._unusedEntities} @selected-changed=${this._handleSelectedChanged} > From c7882f392681fddf86da8dc4ba638cea3e5ab055 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 5 May 2025 13:48:29 -0400 Subject: [PATCH 09/75] Populate integration domain My link (#25322) * Populate integration domain My link * break out of loop * Actually just return from function * Consolidate code --- src/state/quick-bar-mixin.ts | 60 +++++++++++++++++------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/src/state/quick-bar-mixin.ts b/src/state/quick-bar-mixin.ts index 6e931a9bd7..f0effc7f03 100644 --- a/src/state/quick-bar-mixin.ts +++ b/src/state/quick-bar-mixin.ts @@ -16,6 +16,7 @@ import { extractSearchParamsObject } from "../common/url/search-params"; import { showVoiceCommandDialog } from "../dialogs/voice-command-dialog/show-ha-voice-command-dialog"; import { canOverrideAlphanumericInput } from "../common/dom/can-override-input"; import { showShortcutsDialog } from "../dialogs/shortcuts/show-shortcuts-dialog"; +import type { Redirects } from "../panels/my/ha-panel-my"; declare global { interface HASSDomEvents { @@ -143,49 +144,44 @@ export default >(superClass: T) => e.preventDefault(); const targetPath = mainWindow.location.pathname; - const isHassio = isComponentLoaded(this.hass, "hassio"); const myParams = new URLSearchParams(); - if (isHassio && targetPath.startsWith("/hassio")) { + let redirects: Redirects; + + if (targetPath.startsWith("/hassio")) { const myPanelSupervisor = await import( "../../hassio/src/hassio-my-redirect" ); - for (const [slug, redirect] of Object.entries( - myPanelSupervisor.REDIRECTS - )) { - if (targetPath.startsWith(redirect.redirect)) { - myParams.append("redirect", slug); - if (redirect.redirect === "/hassio/addon") { - myParams.append("addon", targetPath.split("/")[3]); - } - window.open( - `https://my.home-assistant.io/create-link/?${myParams.toString()}`, - "_blank" - ); - return; - } - } + redirects = myPanelSupervisor.REDIRECTS; + } else { + const myPanel = await import("../panels/my/ha-panel-my"); + redirects = myPanel.getMyRedirects(); } - const myPanel = await import("../panels/my/ha-panel-my"); + for (const [slug, redirect] of Object.entries(redirects)) { + if (!targetPath.startsWith(redirect.redirect)) { + continue; + } + myParams.append("redirect", slug); - for (const [slug, redirect] of Object.entries(myPanel.getMyRedirects())) { - if (targetPath.startsWith(redirect.redirect)) { - myParams.append("redirect", slug); - if (redirect.params) { - const params = extractSearchParamsObject(); - for (const key of Object.keys(redirect.params)) { - if (key in params) { - myParams.append(key, params[key]); - } + if (redirect.params) { + const params = extractSearchParamsObject(); + for (const key of Object.keys(redirect.params)) { + if (key in params) { + myParams.append(key, params[key]); } } - window.open( - `https://my.home-assistant.io/create-link/?${myParams.toString()}`, - "_blank" - ); - return; } + if (redirect.redirect === "/config/integrations/integration") { + myParams.append("domain", targetPath.split("/")[4]); + } else if (redirect.redirect === "/hassio/addon") { + myParams.append("addon", targetPath.split("/")[3]); + } + window.open( + `https://my.home-assistant.io/create-link/?${myParams.toString()}`, + "_blank" + ); + return; } showToast(this, { message: this.hass.localize( From 83289bdd41d8cee70fdba97d81065555d345e9d9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 09:43:21 +0200 Subject: [PATCH 10/75] Update dependency eslint to v9.26.0 (#25327) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 340 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 311 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index b6cd23a971..eb286c2e34 100644 --- a/package.json +++ b/package.json @@ -185,7 +185,7 @@ "babel-plugin-template-html-minifier": "4.1.0", "browserslist-useragent-regexp": "4.1.3", "del": "8.0.0", - "eslint": "9.25.1", + "eslint": "9.26.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-prettier": "10.1.2", "eslint-import-resolver-webpack": "0.13.10", diff --git a/yarn.lock b/yarn.lock index 5331f5b96d..eaa5ac2a2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1559,10 +1559,10 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:9.25.1": - version: 9.25.1 - resolution: "@eslint/js@npm:9.25.1" - checksum: 10/ad5812889598de32d674ef60c0e61468ac5c7f3b6ecf98b0e29d1e88d7af8ba3aab255b8c0a46bbaf654047bbd2ee5aa033db9b53e330f97615093fcccde4cbb +"@eslint/js@npm:9.26.0": + version: 9.26.0 + resolution: "@eslint/js@npm:9.26.0" + checksum: 10/863d35df8f6675250bb5a917037e0f6833965437eba4c4649633fd0b55a93e8d727bcd36e9b5cc82047898ee9348cb40363e196f333914ae3a6bb36159495212 languageName: node linkType: hard @@ -3168,6 +3168,24 @@ __metadata: languageName: node linkType: hard +"@modelcontextprotocol/sdk@npm:^1.8.0": + version: 1.11.0 + resolution: "@modelcontextprotocol/sdk@npm:1.11.0" + dependencies: + content-type: "npm:^1.0.5" + cors: "npm:^2.8.5" + cross-spawn: "npm:^7.0.3" + eventsource: "npm:^3.0.2" + express: "npm:^5.0.1" + express-rate-limit: "npm:^7.5.0" + pkce-challenge: "npm:^5.0.0" + raw-body: "npm:^3.0.0" + zod: "npm:^3.23.8" + zod-to-json-schema: "npm:^3.24.1" + checksum: 10/527413fd2b18f75e031cda7f73a662098f3c5f1224b9c6b0b903d5a1f79e23e23a4f4b8e6971bac7eb46a74ed65ae05e8e548f7b7a3f7f6d179c3f6d10825fbc + languageName: node + linkType: hard + "@module-federation/error-codes@npm:0.13.0": version: 0.13.0 resolution: "@module-federation/error-codes@npm:0.13.0" @@ -5418,6 +5436,16 @@ __metadata: languageName: node linkType: hard +"accepts@npm:^2.0.0": + version: 2.0.0 + resolution: "accepts@npm:2.0.0" + dependencies: + mime-types: "npm:^3.0.0" + negotiator: "npm:^1.0.0" + checksum: 10/ea1343992b40b2bfb3a3113fa9c3c2f918ba0f9197ae565c48d3f84d44b174f6b1d5cd9989decd7655963eb03a272abc36968cc439c2907f999bd5ef8653d5a7 + languageName: node + linkType: hard + "accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" @@ -6083,6 +6111,23 @@ __metadata: languageName: node linkType: hard +"body-parser@npm:^2.2.0": + version: 2.2.0 + resolution: "body-parser@npm:2.2.0" + dependencies: + bytes: "npm:^3.1.2" + content-type: "npm:^1.0.5" + debug: "npm:^4.4.0" + http-errors: "npm:^2.0.0" + iconv-lite: "npm:^0.6.3" + on-finished: "npm:^2.4.1" + qs: "npm:^6.14.0" + raw-body: "npm:^3.0.0" + type-is: "npm:^2.0.0" + checksum: 10/e9d844b036bd15970df00a16f373c7ed28e1ef870974a0a1d4d6ef60d70e01087cc20a0dbb2081c49a88e3c08ce1d87caf1e2898c615dffa193f63e8faa8a84e + languageName: node + linkType: hard + "bonjour-service@npm:^1.2.1": version: 1.3.0 resolution: "bonjour-service@npm:1.3.0" @@ -6771,7 +6816,16 @@ __metadata: languageName: node linkType: hard -"content-type@npm:~1.0.4, content-type@npm:~1.0.5": +"content-disposition@npm:^1.0.0": + version: 1.0.0 + resolution: "content-disposition@npm:1.0.0" + dependencies: + safe-buffer: "npm:5.2.1" + checksum: 10/0dcc1a2d7874526b0072df3011b134857b49d97a3bc135bb464a299525d4972de6f5f464fd64da6c4d8406d26a1ffb976f62afaffef7723b1021a44498d10e08 + languageName: node + linkType: hard + +"content-type@npm:^1.0.5, content-type@npm:~1.0.4, content-type@npm:~1.0.5": version: 1.0.5 resolution: "content-type@npm:1.0.5" checksum: 10/585847d98dc7fb8035c02ae2cb76c7a9bd7b25f84c447e5ed55c45c2175e83617c8813871b4ee22f368126af6b2b167df655829007b21aa10302873ea9c62662 @@ -6792,6 +6846,13 @@ __metadata: languageName: node linkType: hard +"cookie-signature@npm:^1.2.1": + version: 1.2.2 + resolution: "cookie-signature@npm:1.2.2" + checksum: 10/be44a3c9a56f3771aea3a8bd8ad8f0a8e2679bcb967478267f41a510b4eb5ec55085386ba79c706c4ac21605ca76f4251973444b90283e0eb3eeafe8a92c7708 + languageName: node + linkType: hard + "cookie@npm:0.7.1": version: 0.7.1 resolution: "cookie@npm:0.7.1" @@ -6799,7 +6860,7 @@ __metadata: languageName: node linkType: hard -"cookie@npm:~0.7.2": +"cookie@npm:^0.7.1, cookie@npm:~0.7.2": version: 0.7.2 resolution: "cookie@npm:0.7.2" checksum: 10/24b286c556420d4ba4e9bc09120c9d3db7d28ace2bd0f8ccee82422ce42322f73c8312441271e5eefafbead725980e5996cc02766dbb89a90ac7f5636ede608f @@ -6839,7 +6900,7 @@ __metadata: languageName: node linkType: hard -"cors@npm:2.8.5, cors@npm:~2.8.5": +"cors@npm:2.8.5, cors@npm:^2.8.5, cors@npm:~2.8.5": version: 2.8.5 resolution: "cors@npm:2.8.5" dependencies: @@ -6987,7 +7048,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.4.0": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.4.0": version: 4.4.0 resolution: "debug@npm:4.4.0" dependencies: @@ -7168,7 +7229,7 @@ __metadata: languageName: node linkType: hard -"depd@npm:2.0.0": +"depd@npm:2.0.0, depd@npm:^2.0.0": version: 2.0.0 resolution: "depd@npm:2.0.0" checksum: 10/c0c8ff36079ce5ada64f46cc9d6fd47ebcf38241105b6e0c98f412e8ad91f084bcf906ff644cc3a4bd876ca27a62accb8b0fff72ea6ed1a414b89d8506f4a5ca @@ -7437,6 +7498,13 @@ __metadata: languageName: node linkType: hard +"encodeurl@npm:^2.0.0, encodeurl@npm:~2.0.0": + version: 2.0.0 + resolution: "encodeurl@npm:2.0.0" + checksum: 10/abf5cd51b78082cf8af7be6785813c33b6df2068ce5191a40ca8b1afe6a86f9230af9a9ce694a5ce4665955e5c1120871826df9c128a642e09c58d592e2807fe + languageName: node + linkType: hard + "encodeurl@npm:~1.0.2": version: 1.0.2 resolution: "encodeurl@npm:1.0.2" @@ -7444,13 +7512,6 @@ __metadata: languageName: node linkType: hard -"encodeurl@npm:~2.0.0": - version: 2.0.0 - resolution: "encodeurl@npm:2.0.0" - checksum: 10/abf5cd51b78082cf8af7be6785813c33b6df2068ce5191a40ca8b1afe6a86f9230af9a9ce694a5ce4665955e5c1120871826df9c128a642e09c58d592e2807fe - languageName: node - linkType: hard - "encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -7781,7 +7842,7 @@ __metadata: languageName: node linkType: hard -"escape-html@npm:~1.0.3": +"escape-html@npm:^1.0.3, escape-html@npm:~1.0.3": version: 1.0.3 resolution: "escape-html@npm:1.0.3" checksum: 10/6213ca9ae00d0ab8bccb6d8d4e0a98e76237b2410302cf7df70aaa6591d509a2a37ce8998008cbecae8fc8ffaadf3fb0229535e6a145f3ce0b211d060decbb24 @@ -8003,9 +8064,9 @@ __metadata: languageName: node linkType: hard -"eslint@npm:9.25.1": - version: 9.25.1 - resolution: "eslint@npm:9.25.1" +"eslint@npm:9.26.0": + version: 9.26.0 + resolution: "eslint@npm:9.26.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.12.1" @@ -8013,11 +8074,12 @@ __metadata: "@eslint/config-helpers": "npm:^0.2.1" "@eslint/core": "npm:^0.13.0" "@eslint/eslintrc": "npm:^3.3.1" - "@eslint/js": "npm:9.25.1" + "@eslint/js": "npm:9.26.0" "@eslint/plugin-kit": "npm:^0.2.8" "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" "@humanwhocodes/retry": "npm:^0.4.2" + "@modelcontextprotocol/sdk": "npm:^1.8.0" "@types/estree": "npm:^1.0.6" "@types/json-schema": "npm:^7.0.15" ajv: "npm:^6.12.4" @@ -8042,6 +8104,7 @@ __metadata: minimatch: "npm:^3.1.2" natural-compare: "npm:^1.4.0" optionator: "npm:^0.9.3" + zod: "npm:^3.24.2" peerDependencies: jiti: "*" peerDependenciesMeta: @@ -8049,7 +8112,7 @@ __metadata: optional: true bin: eslint: bin/eslint.js - checksum: 10/037bbdc5cba6f72199976dcdce115b1b479b9425ee1116c08bcaf25e0de4a74a0ffe696d48610ade79c91b04ef3e707a7215a42dfba9c7d3a0b85747d5902e67 + checksum: 10/b87092cb7e87f1d0963475c1a1e15e551842ea122925cf13231e742fae565bf3582029a5b0b4aecf793f25c26ee0be3ee1f32190bc361e0c3f3633b9cbace948 languageName: node linkType: hard @@ -8119,7 +8182,7 @@ __metadata: languageName: node linkType: hard -"etag@npm:~1.8.1": +"etag@npm:^1.8.1, etag@npm:~1.8.1": version: 1.8.1 resolution: "etag@npm:1.8.1" checksum: 10/571aeb3dbe0f2bbd4e4fadbdb44f325fc75335cd5f6f6b6a091e6a06a9f25ed5392f0863c5442acb0646787446e816f13cbfc6edce5b07658541dff573cab1ff @@ -8154,6 +8217,22 @@ __metadata: languageName: node linkType: hard +"eventsource-parser@npm:^3.0.1": + version: 3.0.1 + resolution: "eventsource-parser@npm:3.0.1" + checksum: 10/2730c54c3cb47d55d2967f2ece843f9fc95d8a11c2fef6fece8d17d9080193cbe3cd9ac7b04a325977f63cbf8c1664fdd0512dec1aec601666a5c5bd8564b61f + languageName: node + linkType: hard + +"eventsource@npm:^3.0.2": + version: 3.0.6 + resolution: "eventsource@npm:3.0.6" + dependencies: + eventsource-parser: "npm:^3.0.1" + checksum: 10/ac08c7d1b21e454c7685693fe4ace53fc0b84f3cf752699a556876f2a7f33b7a12972ae33d1c407fb920d6d4aed10de52fdf0dd01902ccdf45cd5da8d55e7f88 + languageName: node + linkType: hard + "execa@npm:^5.1.1": version: 5.1.1 resolution: "execa@npm:5.1.1" @@ -8225,6 +8304,15 @@ __metadata: languageName: node linkType: hard +"express-rate-limit@npm:^7.5.0": + version: 7.5.0 + resolution: "express-rate-limit@npm:7.5.0" + peerDependencies: + express: ^4.11 || 5 || ^5.0.0-beta.1 + checksum: 10/eff34c83bf586789933a332a339b66649e2cca95c8e977d193aa8bead577d3182ac9f0e9c26f39389287539b8038890ff023f910b54ebb506a26a2ce135b92ca + languageName: node + linkType: hard + "express@npm:^4.21.2": version: 4.21.2 resolution: "express@npm:4.21.2" @@ -8264,6 +8352,41 @@ __metadata: languageName: node linkType: hard +"express@npm:^5.0.1": + version: 5.1.0 + resolution: "express@npm:5.1.0" + dependencies: + accepts: "npm:^2.0.0" + body-parser: "npm:^2.2.0" + content-disposition: "npm:^1.0.0" + content-type: "npm:^1.0.5" + cookie: "npm:^0.7.1" + cookie-signature: "npm:^1.2.1" + debug: "npm:^4.4.0" + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + etag: "npm:^1.8.1" + finalhandler: "npm:^2.1.0" + fresh: "npm:^2.0.0" + http-errors: "npm:^2.0.0" + merge-descriptors: "npm:^2.0.0" + mime-types: "npm:^3.0.0" + on-finished: "npm:^2.4.1" + once: "npm:^1.4.0" + parseurl: "npm:^1.3.3" + proxy-addr: "npm:^2.0.7" + qs: "npm:^6.14.0" + range-parser: "npm:^1.2.1" + router: "npm:^2.2.0" + send: "npm:^1.1.0" + serve-static: "npm:^2.2.0" + statuses: "npm:^2.0.1" + type-is: "npm:^2.0.1" + vary: "npm:^1.1.2" + checksum: 10/6dba00bbdf308f43a84ed3f07a7e9870d5208f2a0b8f60f39459dda089750379747819863fad250849d3c9163833f33f94ce69d73938df31e0c5a430800d7e56 + languageName: node + linkType: hard + "extend-shallow@npm:^3.0.2": version: 3.0.2 resolution: "extend-shallow@npm:3.0.2" @@ -8478,6 +8601,20 @@ __metadata: languageName: node linkType: hard +"finalhandler@npm:^2.1.0": + version: 2.1.0 + resolution: "finalhandler@npm:2.1.0" + dependencies: + debug: "npm:^4.4.0" + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + on-finished: "npm:^2.4.1" + parseurl: "npm:^1.3.3" + statuses: "npm:^2.0.1" + checksum: 10/b2bd68c310e2c463df0ab747ab05f8defbc540b8c3f2442f86e7d084ac8acbc31f8cae079931b7f5a406521501941e3395e963de848a0aaf45dd414adeb5ff4e + languageName: node + linkType: hard + "find-root@npm:^1.1.0": version: 1.1.0 resolution: "find-root@npm:1.1.0" @@ -8625,6 +8762,13 @@ __metadata: languageName: node linkType: hard +"fresh@npm:^2.0.0": + version: 2.0.0 + resolution: "fresh@npm:2.0.0" + checksum: 10/44e1468488363074641991c1340d2a10c5a6f6d7c353d89fd161c49d120c58ebf9890720f7584f509058385836e3ce50ddb60e9f017315a4ba8c6c3461813bfc + languageName: node + linkType: hard + "fs-extra@npm:11.3.0, fs-extra@npm:^11.1.1": version: 11.3.0 resolution: "fs-extra@npm:11.3.0" @@ -9329,7 +9473,7 @@ __metadata: dialog-polyfill: "npm:0.5.6" echarts: "npm:5.6.0" element-internals-polyfill: "npm:3.0.2" - eslint: "npm:9.25.1" + eslint: "npm:9.26.0" eslint-config-airbnb-base: "npm:15.0.0" eslint-config-prettier: "npm:10.1.2" eslint-import-resolver-webpack: "npm:0.13.10" @@ -9516,7 +9660,7 @@ __metadata: languageName: node linkType: hard -"http-errors@npm:2.0.0": +"http-errors@npm:2.0.0, http-errors@npm:^2.0.0": version: 2.0.0 resolution: "http-errors@npm:2.0.0" dependencies: @@ -10114,6 +10258,13 @@ __metadata: languageName: node linkType: hard +"is-promise@npm:^4.0.0": + version: 4.0.0 + resolution: "is-promise@npm:4.0.0" + checksum: 10/0b46517ad47b00b6358fd6553c83ec1f6ba9acd7ffb3d30a0bf519c5c69e7147c132430452351b8a9fc198f8dd6c4f76f8e6f5a7f100f8c77d57d9e0f4261a8a + languageName: node + linkType: hard + "is-regex@npm:^1.2.0, is-regex@npm:^1.2.1": version: 1.2.1 resolution: "is-regex@npm:1.2.1" @@ -11073,6 +11224,13 @@ __metadata: languageName: node linkType: hard +"media-typer@npm:^1.1.0": + version: 1.1.0 + resolution: "media-typer@npm:1.1.0" + checksum: 10/a58dd60804df73c672942a7253ccc06815612326dc1c0827984b1a21704466d7cde351394f47649e56cf7415e6ee2e26e000e81b51b3eebb5a93540e8bf93cbd + languageName: node + linkType: hard + "memfs@npm:^4.6.0": version: 4.17.0 resolution: "memfs@npm:4.17.0" @@ -11106,6 +11264,13 @@ __metadata: languageName: node linkType: hard +"merge-descriptors@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-descriptors@npm:2.0.0" + checksum: 10/e383332e700a94682d0125a36c8be761142a1320fc9feeb18e6e36647c9edf064271645f5669b2c21cf352116e561914fd8aa831b651f34db15ef4038c86696a + languageName: node + linkType: hard + "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -11144,7 +11309,7 @@ __metadata: languageName: node linkType: hard -"mime-db@npm:>= 1.43.0 < 2": +"mime-db@npm:>= 1.43.0 < 2, mime-db@npm:^1.54.0": version: 1.54.0 resolution: "mime-db@npm:1.54.0" checksum: 10/9e7834be3d66ae7f10eaa69215732c6d389692b194f876198dca79b2b90cbf96688d9d5d05ef7987b20f749b769b11c01766564264ea5f919c88b32a29011311 @@ -11176,6 +11341,15 @@ __metadata: languageName: node linkType: hard +"mime-types@npm:^3.0.0, mime-types@npm:^3.0.1": + version: 3.0.1 + resolution: "mime-types@npm:3.0.1" + dependencies: + mime-db: "npm:^1.54.0" + checksum: 10/fa1d3a928363723a8046c346d87bf85d35014dae4285ad70a3ff92bd35957992b3094f8417973cfe677330916c6ef30885109624f1fb3b1e61a78af509dba120 + languageName: node + linkType: hard + "mime@npm:1.6.0": version: 1.6.0 resolution: "mime@npm:1.6.0" @@ -11972,7 +12146,7 @@ __metadata: languageName: node linkType: hard -"parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": +"parseurl@npm:^1.3.3, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" checksum: 10/407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 @@ -12088,6 +12262,13 @@ __metadata: languageName: node linkType: hard +"path-to-regexp@npm:^8.0.0": + version: 8.2.0 + resolution: "path-to-regexp@npm:8.2.0" + checksum: 10/23378276a172b8ba5f5fb824475d1818ca5ccee7bbdb4674701616470f23a14e536c1db11da9c9e6d82b82c556a817bbf4eee6e41b9ed20090ef9427cbb38e13 + languageName: node + linkType: hard + "path-type@npm:^6.0.0": version: 6.0.0 resolution: "path-type@npm:6.0.0" @@ -12166,6 +12347,13 @@ __metadata: languageName: node linkType: hard +"pkce-challenge@npm:^5.0.0": + version: 5.0.0 + resolution: "pkce-challenge@npm:5.0.0" + checksum: 10/e60c06a0e0481cb82f80072053d5c479a7490758541c4226460450285dd5d72a995c44b3c553731ca7c2f64cc34b35f1d2e5f9de08d276b59899298f9efe1ddf + languageName: node + linkType: hard + "plugin-error@npm:^1.0.1": version: 1.0.1 resolution: "plugin-error@npm:1.0.1" @@ -12303,7 +12491,7 @@ __metadata: languageName: node linkType: hard -"proxy-addr@npm:~2.0.7": +"proxy-addr@npm:^2.0.7, proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" dependencies: @@ -12365,6 +12553,15 @@ __metadata: languageName: node linkType: hard +"qs@npm:^6.14.0": + version: 6.14.0 + resolution: "qs@npm:6.14.0" + dependencies: + side-channel: "npm:^1.1.0" + checksum: 10/a60e49bbd51c935a8a4759e7505677b122e23bf392d6535b8fc31c1e447acba2c901235ecb192764013cd2781723dc1f61978b5fdd93cc31d7043d31cdc01974 + languageName: node + linkType: hard + "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" @@ -12407,6 +12604,18 @@ __metadata: languageName: node linkType: hard +"raw-body@npm:^3.0.0": + version: 3.0.0 + resolution: "raw-body@npm:3.0.0" + dependencies: + bytes: "npm:3.1.2" + http-errors: "npm:2.0.0" + iconv-lite: "npm:0.6.3" + unpipe: "npm:1.0.0" + checksum: 10/2443429bbb2f9ae5c50d3d2a6c342533dfbde6b3173740b70fa0302b30914ff400c6d31a46b3ceacbe7d0925dc07d4413928278b494b04a65736fc17ca33e30c + languageName: node + linkType: hard + "rc@npm:^1.0.1, rc@npm:^1.1.6": version: 1.2.8 resolution: "rc@npm:1.2.8" @@ -12882,6 +13091,19 @@ __metadata: languageName: node linkType: hard +"router@npm:^2.2.0": + version: 2.2.0 + resolution: "router@npm:2.2.0" + dependencies: + debug: "npm:^4.4.0" + depd: "npm:^2.0.0" + is-promise: "npm:^4.0.0" + parseurl: "npm:^1.3.3" + path-to-regexp: "npm:^8.0.0" + checksum: 10/8949bd1d3da5403cc024e2989fee58d7fda0f3ffe9f2dc5b8a192f295f400b3cde307b0b554f7d44851077640f36962ca469a766b3d57410d7d96245a7ba6c91 + languageName: node + linkType: hard + "rrule@npm:2.8.1": version: 2.8.1 resolution: "rrule@npm:2.8.1" @@ -13085,6 +13307,25 @@ __metadata: languageName: node linkType: hard +"send@npm:^1.1.0, send@npm:^1.2.0": + version: 1.2.0 + resolution: "send@npm:1.2.0" + dependencies: + debug: "npm:^4.3.5" + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + etag: "npm:^1.8.1" + fresh: "npm:^2.0.0" + http-errors: "npm:^2.0.0" + mime-types: "npm:^3.0.1" + ms: "npm:^2.1.3" + on-finished: "npm:^2.4.1" + range-parser: "npm:^1.2.1" + statuses: "npm:^2.0.1" + checksum: 10/9fa3b1a3b9a06b7b4ab00c25e8228326d9665a9745753a34d1ffab8ac63c7c206727331d1dc5be73647f1b658d259a1aa8e275b0e0eee51349370af02e9da506 + languageName: node + linkType: hard + "serialize-javascript@npm:^6.0.1, serialize-javascript@npm:^6.0.2": version: 6.0.2 resolution: "serialize-javascript@npm:6.0.2" @@ -13136,6 +13377,18 @@ __metadata: languageName: node linkType: hard +"serve-static@npm:^2.2.0": + version: 2.2.0 + resolution: "serve-static@npm:2.2.0" + dependencies: + encodeurl: "npm:^2.0.0" + escape-html: "npm:^1.0.3" + parseurl: "npm:^1.3.3" + send: "npm:^1.2.0" + checksum: 10/9f1a900738c5bb02258275ce3bd1273379c4c3072b622e15d44e8f47d89a1ba2d639ec2d63b11c263ca936096b40758acb7a0d989cd6989018a65a12f9433ada + languageName: node + linkType: hard + "serve@npm:14.2.4": version: 14.2.4 resolution: "serve@npm:14.2.4" @@ -13608,7 +13861,7 @@ __metadata: languageName: node linkType: hard -"statuses@npm:2.0.1": +"statuses@npm:2.0.1, statuses@npm:^2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" checksum: 10/18c7623fdb8f646fb213ca4051be4df7efb3484d4ab662937ca6fbef7ced9b9e12842709872eb3020cc3504b93bde88935c9f6417489627a7786f24f8031cbcb @@ -14382,6 +14635,17 @@ __metadata: languageName: node linkType: hard +"type-is@npm:^2.0.0, type-is@npm:^2.0.1": + version: 2.0.1 + resolution: "type-is@npm:2.0.1" + dependencies: + content-type: "npm:^1.0.5" + media-typer: "npm:^1.1.0" + mime-types: "npm:^3.0.0" + checksum: 10/bacdb23c872dacb7bd40fbd9095e6b2fca2895eedbb689160c05534d7d4810a7f4b3fd1ae87e96133c505958f6d602967a68db5ff577b85dd6be76eaa75d58af + languageName: node + linkType: hard + "type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" @@ -14752,7 +15016,7 @@ __metadata: languageName: node linkType: hard -"vary@npm:^1, vary@npm:~1.1.2": +"vary@npm:^1, vary@npm:^1.1.2, vary@npm:~1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" checksum: 10/31389debef15a480849b8331b220782230b9815a8e0dbb7b9a8369559aed2e9a7800cd904d4371ea74f4c3527db456dc8e7ac5befce5f0d289014dbdf47b2242 @@ -16007,6 +16271,22 @@ __metadata: languageName: node linkType: hard +"zod-to-json-schema@npm:^3.24.1": + version: 3.24.5 + resolution: "zod-to-json-schema@npm:3.24.5" + peerDependencies: + zod: ^3.24.1 + checksum: 10/1af291b4c429945c9568c2e924bdb7c66ab8d139cbeb9a99b6e9fc9e1b02863f85d07759b9303714f07ceda3993dcaf0ebcb80d2c18bb2aaf5502b2c1016affd + languageName: node + linkType: hard + +"zod@npm:^3.23.8, zod@npm:^3.24.2": + version: 3.24.4 + resolution: "zod@npm:3.24.4" + checksum: 10/3d545792fa54bb27ee5dbc34a5709e81f603185fcc94c8204b5d95c20dc4c81d870ff9c51f3884a30ef05cdc601449f4c4df254ac4783f0827b1faed7c1cdb48 + languageName: node + linkType: hard + "zrender@npm:5.6.1": version: 5.6.1 resolution: "zrender@npm:5.6.1" From d618c25095f35a9522d974a3b861194d66370739 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 6 May 2025 03:49:35 -0400 Subject: [PATCH 11/75] Show voice ID in TTS media browser (#25324) * Show voice ID in TTS media browser * Apply suggestions from code review Co-authored-by: Paul Bottein * Add copy button * Now copy correct clipboard icon * Improve styling * GAP --------- Co-authored-by: Paul Bottein --- .../media-player/ha-browse-media-tts.ts | 135 ++++++++++++------ src/translations/en.json | 4 +- 2 files changed, 94 insertions(+), 45 deletions(-) diff --git a/src/components/media-player/ha-browse-media-tts.ts b/src/components/media-player/ha-browse-media-tts.ts index e6fbdd62d7..1924af09a4 100644 --- a/src/components/media-player/ha-browse-media-tts.ts +++ b/src/components/media-player/ha-browse-media-tts.ts @@ -2,6 +2,7 @@ import "@material/mwc-button/mwc-button"; import type { PropertyValues } from "lit"; import { css, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { mdiContentCopy } from "@mdi/js"; import { storage } from "../../common/decorators/storage"; import { fireEvent } from "../../common/dom/fire_event"; import type { @@ -17,6 +18,8 @@ import "../ha-language-picker"; import "../ha-tts-voice-picker"; import "../ha-card"; import { fetchCloudStatus } from "../../data/cloud"; +import { copyToClipboard } from "../../common/util/copy-clipboard"; +import { showToast } from "../../util/toast"; export interface TtsMediaPickedEvent { item: MediaPlayerItem; @@ -51,50 +54,69 @@ class BrowseMediaTTS extends LitElement { private _message?: string; protected render() { - return html` -
- - - ${this._provider?.supported_languages?.length - ? html`
- - -
` - : nothing} -
-
- - ${this.hass.localize( - `ui.components.media-browser.tts.action_${this.action}` - )} - -
-
`; + return html` + +
+ + + ${this._provider?.supported_languages?.length + ? html`
+ + +
` + : nothing} +
+
+ + ${this.hass.localize( + `ui.components.media-browser.tts.action_${this.action}` + )} + +
+
+ ${this._voice + ? html` + + ` + : nothing} + `; } protected override willUpdate(changedProps: PropertyValues): void { @@ -197,6 +219,14 @@ class BrowseMediaTTS extends LitElement { fireEvent(this, "tts-picked", { item }); } + private async _copyVoiceId(ev) { + ev.preventDefault(); + await copyToClipboard(this._voice); + showToast(this, { + message: this.hass.localize("ui.common.copied_clipboard"), + }); + } + static override styles = [ buttonLinkStyle, css` @@ -218,6 +248,23 @@ class BrowseMediaTTS extends LitElement { button.link { color: var(--primary-color); } + .footer { + font-size: var(--ha-font-size-s); + color: var(--secondary-text-color); + margin: 16px 0; + text-align: center; + } + .footer code { + font-weight: var(--ha-font-weight-bold); + } + .footer { + --mdc-icon-size: 14px; + --mdc-icon-button-size: 24px; + display: flex; + justify-content: center; + align-items: center; + gap: 6px; + } `, ]; } diff --git a/src/translations/en.json b/src/translations/en.json index 374d86b6a9..d3da5cbb65 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -920,7 +920,9 @@ "action_play": "Say", "action_pick": "Select", "set_as_default": "Set as default options", - "faild_to_store_defaults": "Failed to store defaults: {error}" + "faild_to_store_defaults": "Failed to store defaults: {error}", + "selected_voice_id": "Selected voice ID", + "copy_voice_id": "Copy voice ID" }, "pick": "Pick", "play": "Play", From ad8d3dd5985590ba368c3abdadfe753b2fcc9789 Mon Sep 17 00:00:00 2001 From: Simon Lamon <32477463+silamon@users.noreply.github.com> Date: Tue, 6 May 2025 09:52:04 +0200 Subject: [PATCH 12/75] Bump the sortable patch (#25262) --- ... => sortablejs-npm-1.15.6-3235a8f83b.patch} | 0 package.json | 2 +- yarn.lock | 18 +++++++++--------- 3 files changed, 10 insertions(+), 10 deletions(-) rename .yarn/patches/{sortablejs-npm-1.15.3-3235a8f83b.patch => sortablejs-npm-1.15.6-3235a8f83b.patch} (100%) diff --git a/.yarn/patches/sortablejs-npm-1.15.3-3235a8f83b.patch b/.yarn/patches/sortablejs-npm-1.15.6-3235a8f83b.patch similarity index 100% rename from .yarn/patches/sortablejs-npm-1.15.3-3235a8f83b.patch rename to .yarn/patches/sortablejs-npm-1.15.6-3235a8f83b.patch diff --git a/package.json b/package.json index eb286c2e34..3040aec248 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "qrcode": "1.5.4", "roboto-fontface": "0.10.0", "rrule": "2.8.1", - "sortablejs": "patch:sortablejs@npm%3A1.15.3#~/.yarn/patches/sortablejs-npm-1.15.3-3235a8f83b.patch", + "sortablejs": "patch:sortablejs@npm%3A1.15.6#~/.yarn/patches/sortablejs-npm-1.15.6-3235a8f83b.patch", "stacktrace-js": "2.0.2", "superstruct": "2.0.2", "tinykeys": "3.0.0", diff --git a/yarn.lock b/yarn.lock index eaa5ac2a2e..a593fb7e20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9526,7 +9526,7 @@ __metadata: rspack-manifest-plugin: "npm:5.0.3" serve: "npm:14.2.4" sinon: "npm:20.0.0" - sortablejs: "patch:sortablejs@npm%3A1.15.3#~/.yarn/patches/sortablejs-npm-1.15.3-3235a8f83b.patch" + sortablejs: "patch:sortablejs@npm%3A1.15.6#~/.yarn/patches/sortablejs-npm-1.15.6-3235a8f83b.patch" stacktrace-js: "npm:2.0.2" superstruct: "npm:2.0.2" tar: "npm:7.4.3" @@ -13699,17 +13699,17 @@ __metadata: languageName: node linkType: hard -"sortablejs@npm:1.15.3": - version: 1.15.3 - resolution: "sortablejs@npm:1.15.3" - checksum: 10/85d39a172ef47adedf273afa65daa8aefcbaafd43a5b5c480d8637add93033f5784da697d0d3545d9bb6e11fd71f1847f307ee26be452942f3785a683fd44bb5 +"sortablejs@npm:1.15.6": + version: 1.15.6 + resolution: "sortablejs@npm:1.15.6" + checksum: 10/3179071352662e6cff20d7d10792a934fc892a83a01ae09c7e604d2dd51daaf07283b00a8f2b13025f27959ff68a1469959bc94ef2a7049723d4c381a368a5ac languageName: node linkType: hard -"sortablejs@patch:sortablejs@npm%3A1.15.3#~/.yarn/patches/sortablejs-npm-1.15.3-3235a8f83b.patch": - version: 1.15.3 - resolution: "sortablejs@patch:sortablejs@npm%3A1.15.3#~/.yarn/patches/sortablejs-npm-1.15.3-3235a8f83b.patch::version=1.15.3&hash=fba0ad" - checksum: 10/249f4cfd2b4a811f4e1505b25d4d67a97521afabdabd2f5482f985da20785d995c2899d442ad79075c7ba547e477aef81f09b0028f12d1de468cbca4f2b8c043 +"sortablejs@patch:sortablejs@npm%3A1.15.6#~/.yarn/patches/sortablejs-npm-1.15.6-3235a8f83b.patch": + version: 1.15.6 + resolution: "sortablejs@patch:sortablejs@npm%3A1.15.6#~/.yarn/patches/sortablejs-npm-1.15.6-3235a8f83b.patch::version=1.15.6&hash=fba0ad" + checksum: 10/4d7515c6490fd9d7184a758775634b72c971f1ac739f8bf19683ad973374d6afb3adeb5dcb5c604d15faac55867b401cdb0631c0baee9f73d4c1ef82ee4318f8 languageName: node linkType: hard From 92b8cd8f459f1d78fc3d5ec7b45b9f24156a6e13 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Tue, 6 May 2025 10:57:47 +0200 Subject: [PATCH 13/75] Align side bar title with items (#25330) --- src/components/ha-sidebar.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index e3f139b62b..3f48666754 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -896,8 +896,8 @@ class HaSidebar extends SubscribeMixin(LitElement) { color: var(--sidebar-icon-color); } .title { - margin-left: 19px; - margin-inline-start: 19px; + margin-left: 3px; + margin-inline-start: 3px; margin-inline-end: initial; width: 100%; display: none; From 0729aaacb8f9acfe0519fe410e1c537a39574549 Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Tue, 6 May 2025 11:00:37 +0200 Subject: [PATCH 14/75] Revert "Keyboard accessible panel sorting" (#25331) --- src/components/ha-sidebar.ts | 71 +++----------------------- src/resources/ha-sidebar-edit-style.ts | 2 +- src/translations/en.json | 4 +- 3 files changed, 9 insertions(+), 68 deletions(-) diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 3f48666754..19c4a8d633 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -52,7 +52,6 @@ import "./user/ha-user-badge"; import "./ha-md-list"; import "./ha-md-list-item"; import type { HaMdListItem } from "./ha-md-list-item"; -import { showPromptDialog } from "../dialogs/generic/show-dialog-box"; const SHOW_AFTER_SPACER = ["config", "developer-tools"]; @@ -425,12 +424,8 @@ class HaSidebar extends SubscribeMixin(LitElement) { `; } - private _renderPanels( - panels: PanelInfo[], - selectedPanel: string, - orderable = false - ) { - return panels.map((panel, idx) => + private _renderPanels(panels: PanelInfo[], selectedPanel: string) { + return panels.map((panel) => this._renderPanel( panel.url_path, panel.url_path === this.hass.defaultPanel @@ -442,8 +437,7 @@ class HaSidebar extends SubscribeMixin(LitElement) { : panel.url_path in PANEL_ICONS ? PANEL_ICONS[panel.url_path] : undefined, - selectedPanel, - orderable ? idx : null + selectedPanel ) ); } @@ -453,8 +447,7 @@ class HaSidebar extends SubscribeMixin(LitElement) { title: string | null, icon: string | null | undefined, iconPath: string | null | undefined, - selectedPanel: string, - index: number | null + selectedPanel: string ) { return urlPath === "config" ? this._renderConfiguration(title, selectedPanel) @@ -470,20 +463,8 @@ class HaSidebar extends SubscribeMixin(LitElement) { ? html`` : html``} ${title} - ${index != null - ? html` -
${index + 1}
-
` - : nothing} ${this.editMode - ? html`
${this._renderPanels(beforeSpacer, selectedPanel, true)}
+ >
${this._renderPanels(beforeSpacer, selectedPanel)}
${this._renderSpacer()}${this._renderHiddenPanels()} `; @@ -712,28 +690,6 @@ class HaSidebar extends SubscribeMixin(LitElement) { fireEvent(this, "hass-edit-sidebar", { editMode: false }); } - private async _changePosition(ev): Promise { - ev.preventDefault(); - const oldIndex = (ev.currentTarget as any).index as number; - const name = ((ev.currentTarget as any).title as string) || ""; - - const positionString = await showPromptDialog(this, { - title: this.hass!.localize("ui.sidebar.change_position"), - text: this.hass!.localize("ui.sidebar.change_position_dialog_text", { - name, - }), - inputType: "number", - inputMin: "1", - placeholder: String(oldIndex + 1), - }); - - if (!positionString) return; - const position = parseInt(positionString); - if (isNaN(position)) return; - const newIndex = Math.max(0, position - 1); - this._panelMove(oldIndex, newIndex); - } - private async _hidePanel(ev: Event) { ev.preventDefault(); const panel = (ev.currentTarget as any).panel; @@ -984,7 +940,7 @@ class HaSidebar extends SubscribeMixin(LitElement) { ha-md-list-item .item-text { display: none; - max-width: 100%; + max-width: calc(100% - 56px); font-weight: 500; font-size: 14px; } @@ -1015,19 +971,6 @@ class HaSidebar extends SubscribeMixin(LitElement) { color: var(--text-accent-color, var(--text-primary-color)); } - .position-badge { - display: block; - width: 24px; - line-height: 24px; - box-sizing: border-box; - border-radius: 50%; - font-weight: 500; - text-align: center; - font-size: 14px; - background-color: var(--app-header-edit-background-color, #455a64); - color: var(--app-header-edit-text-color, white); - } - ha-svg-icon + .badge { position: absolute; top: 4px; diff --git a/src/resources/ha-sidebar-edit-style.ts b/src/resources/ha-sidebar-edit-style.ts index 10dc29f913..efd4ddee10 100644 --- a/src/resources/ha-sidebar-edit-style.ts +++ b/src/resources/ha-sidebar-edit-style.ts @@ -58,7 +58,7 @@ export const sidebarEditStyle = css` } :host([expanded]) .hide-panel { - display: inline-block; + display: block; } :host([expanded]) .show-panel { diff --git a/src/translations/en.json b/src/translations/en.json index d3da5cbb65..6e4810e682 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2018,9 +2018,7 @@ "sidebar_toggle": "Sidebar toggle", "done": "Done", "hide_panel": "Hide panel", - "show_panel": "Show panel", - "change_position": "Change panel position", - "change_position_dialog_text": "What position do you want to move your ''{name}'' panel to?" + "show_panel": "Show panel" }, "panel": { "my": { From 15dcdffe55298bf9eae37c91649569645c400b7a Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Tue, 6 May 2025 13:38:38 +0200 Subject: [PATCH 15/75] Add covers to overview view for area strategy (#25334) --- .../lovelace/strategies/areas/areas-overview-view-strategy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts b/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts index 40a034140b..fde3545216 100644 --- a/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts +++ b/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts @@ -50,6 +50,7 @@ export class AreasOverviewViewStrategy extends ReactiveElement { const entities = [ ...groups.lights, + ...groups.covers, ...groups.climate, ...groups.media_players, ...groups.security, From 852278e8aa95588269a160666ee898782b53f564 Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Tue, 6 May 2025 13:50:23 +0200 Subject: [PATCH 16/75] Add custom retention info to backup locations (#25318) * Add retention messages to backup locations * Fix mobile * Use join --- .../config/ha-backup-config-agents.ts | 74 +++++++++++++++---- src/translations/en.json | 5 +- 2 files changed, 62 insertions(+), 17 deletions(-) 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 687321f7c5..a9817dba96 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,5 +1,6 @@ import { mdiCog, mdiDelete, mdiHarddisk, mdiNas } from "@mdi/js"; -import { css, html, LitElement, nothing } from "lit"; +import { css, html, LitElement, nothing, type TemplateResult } from "lit"; +import { join } from "lit/directives/join"; import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../../common/dom/fire_event"; @@ -57,26 +58,51 @@ class HaBackupConfigAgents extends LitElement { ); } + const texts: (TemplateResult | string)[] = []; + + if (isNetworkMountAgent(agentId)) { + texts.push( + this.hass.localize( + "ui.panel.config.backup.agents.network_mount_agent_description" + ) + ); + } + const encryptionTurnedOff = this.agentsConfig?.[agentId]?.protected === false; if (encryptionTurnedOff) { - return html` - - - ${this.hass.localize( - "ui.panel.config.backup.agents.encryption_turned_off" - )} - - `; - } - - if (isNetworkMountAgent(agentId)) { - return this.hass.localize( - "ui.panel.config.backup.agents.network_mount_agent_description" + texts.push( + html`
+ + + ${this.hass.localize( + "ui.panel.config.backup.agents.encryption_turned_off" + )} + +
` ); } - return ""; + + const retention = this.agentsConfig?.[agentId]?.retention; + + if (retention) { + if (retention.copies === null && retention.days === null) { + texts.push( + this.hass.localize("ui.panel.config.backup.agents.retention_all") + ); + } else { + texts.push( + this.hass.localize( + `ui.panel.config.backup.agents.retention_${retention.copies ? "backups" : "days"}`, + { + count: retention.copies || retention.days, + } + ) + ); + } + } + return join(texts, html``); } private _availableAgents = memoizeOne( @@ -287,6 +313,11 @@ class HaBackupConfigAgents extends LitElement { gap: 8px; line-height: normal; } + .unencrypted-warning { + display: flex; + align-items: center; + gap: 4px; + } .dot { display: block; position: relative; @@ -294,11 +325,22 @@ class HaBackupConfigAgents extends LitElement { height: 8px; background-color: var(--disabled-color); border-radius: 50%; - flex: none; } .dot.warning { background-color: var(--warning-color); } + @media all and (max-width: 500px) { + .separator { + display: none; + } + ha-md-list-item [slot="supporting-text"] { + display: flex; + align-items: flex-start; + flex-direction: column; + justify-content: flex-start; + gap: 4px; + } + } `; } diff --git a/src/translations/en.json b/src/translations/en.json index 6e4810e682..aaa9a327be 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2491,7 +2491,10 @@ "unavailable_agents": "Unavailable locations", "no_agents": "No locations configured", "encryption_turned_off": "Encryption turned off", - "local_agent": "This system" + "local_agent": "This system", + "retention_all": "Keep all backups", + "retention_backups": "Keep {count} {count, plural,\n one {backup}\n other {backups}\n}", + "retention_days": "Keep {count} {count, plural,\n one {day}\n other {days}\n}" }, "data": { "ha_settings": "Home Assistant settings", From 00d708fbd4b249852f3404dbf35e8942b5a9a5ae Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Tue, 6 May 2025 13:52:00 +0200 Subject: [PATCH 17/75] Fix flow form padding end (#25328) * Fix flow form padding end * Use more end padding if docs are present --- .../config-flow/dialog-data-entry-flow.ts | 42 +++++++++++-------- src/dialogs/config-flow/step-flow-abort.ts | 5 ++- .../config-flow/step-flow-create-entry.ts | 5 ++- src/dialogs/config-flow/step-flow-external.ts | 10 ++++- src/dialogs/config-flow/step-flow-form.ts | 7 +++- src/dialogs/config-flow/step-flow-menu.ts | 7 +++- src/dialogs/config-flow/step-flow-progress.ts | 5 ++- src/dialogs/config-flow/styles.ts | 3 ++ 8 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/dialogs/config-flow/dialog-data-entry-flow.ts b/src/dialogs/config-flow/dialog-data-entry-flow.ts index 94959185ec..726143bdb1 100644 --- a/src/dialogs/config-flow/dialog-data-entry-flow.ts +++ b/src/dialogs/config-flow/dialog-data-entry-flow.ts @@ -1,4 +1,3 @@ -import "@material/mwc-button"; import { mdiClose, mdiHelpCircle } from "@mdi/js"; import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import type { CSSResultGroup, PropertyValues } from "lit"; @@ -177,6 +176,17 @@ class DataEntryFlowDialog extends LitElement { return nothing; } + const showDocumentationLink = + ([ + "form", + "menu", + "external", + "progress", + "data_entry_flow_progressed", + ].includes(this._step?.type as any) && + this._params.manifest?.is_built_in) || + !!this._params.manifest?.documentation; + return html` @@ -199,26 +209,18 @@ class DataEntryFlowDialog extends LitElement { : this._step === undefined ? // When we are going to next step, we render 1 round of empty // to reset the element. - "" + nothing : html`
- ${([ - "form", - "menu", - "external", - "progress", - "data_entry_flow_progressed", - ].includes(this._step?.type as any) && - this._params.manifest?.is_built_in) || - this._params.manifest?.documentation + ${showDocumentationLink ? html` @@ -229,7 +231,7 @@ class DataEntryFlowDialog extends LitElement { ` - : ""} + : nothing} ` : this._step.type === "external" @@ -250,6 +253,7 @@ class DataEntryFlowDialog extends LitElement { .flowConfig=${this._params.flowConfig} .step=${this._step} .hass=${this.hass} + .increasePaddingEnd=${showDocumentationLink} > ` : this._step.type === "abort" @@ -261,6 +265,7 @@ class DataEntryFlowDialog extends LitElement { .handler=${this._step.handler} .domain=${this._params.domain ?? this._step.handler} + .increasePaddingEnd=${showDocumentationLink} > ` : this._step.type === "progress" @@ -270,6 +275,7 @@ class DataEntryFlowDialog extends LitElement { .step=${this._step} .hass=${this.hass} .progress=${this._progress} + .increasePaddingEnd=${showDocumentationLink} > ` : this._step.type === "menu" @@ -278,6 +284,7 @@ class DataEntryFlowDialog extends LitElement { .flowConfig=${this._params.flowConfig} .step=${this._step} .hass=${this.hass} + .increasePaddingEnd=${showDocumentationLink} > ` : html` @@ -286,7 +293,8 @@ class DataEntryFlowDialog extends LitElement { .step=${this._step} .hass=${this.hass} .navigateToResult=${this._params - .navigateToResult} + .navigateToResult ?? false} + .increasePaddingEnd=${showDocumentationLink} > `} `} diff --git a/src/dialogs/config-flow/step-flow-abort.ts b/src/dialogs/config-flow/step-flow-abort.ts index fa54d4ca57..9f0ad9abb0 100644 --- a/src/dialogs/config-flow/step-flow-abort.ts +++ b/src/dialogs/config-flow/step-flow-abort.ts @@ -22,6 +22,9 @@ class StepFlowAbort extends LitElement { @property({ attribute: false }) public handler!: string; + @property({ type: Boolean, attribute: "increase-padding-end" }) + public increasePaddingEnd = false; + protected firstUpdated(changed: PropertyValues) { super.firstUpdated(changed); if (this.step.reason === "missing_credentials") { @@ -34,7 +37,7 @@ class StepFlowAbort extends LitElement { return nothing; } return html` -

+

${this.params.flowConfig.renderAbortHeader ? this.params.flowConfig.renderAbortHeader(this.hass, this.step) : this.hass.localize(`component.${this.domain}.title`)} diff --git a/src/dialogs/config-flow/step-flow-create-entry.ts b/src/dialogs/config-flow/step-flow-create-entry.ts index 6f59bf593d..327b5b783a 100644 --- a/src/dialogs/config-flow/step-flow-create-entry.ts +++ b/src/dialogs/config-flow/step-flow-create-entry.ts @@ -36,6 +36,9 @@ class StepFlowCreateEntry extends LitElement { @property({ attribute: false }) public step!: DataEntryFlowStepCreateEntry; + @property({ type: Boolean, attribute: "increase-padding-end" }) + public increasePaddingEnd = false; + public navigateToResult = false; @state() private _deviceUpdate: Record< @@ -113,7 +116,7 @@ class StepFlowCreateEntry extends LitElement { this.step.result?.entry_id ); return html` -

+

${devices.length ? localize("ui.panel.config.integrations.config_flow.assign_area", { number: devices.length, diff --git a/src/dialogs/config-flow/step-flow-external.ts b/src/dialogs/config-flow/step-flow-external.ts index 4e3b10512c..98d98c61ef 100644 --- a/src/dialogs/config-flow/step-flow-external.ts +++ b/src/dialogs/config-flow/step-flow-external.ts @@ -15,11 +15,16 @@ class StepFlowExternal extends LitElement { @property({ attribute: false }) public step!: DataEntryFlowStepExternal; + @property({ type: Boolean, attribute: "increase-padding-end" }) + public increasePaddingEnd = false; + protected render(): TemplateResult { const localize = this.hass.localize; return html` -

${this.flowConfig.renderExternalStepHeader(this.hass, this.step)}

+

+ ${this.flowConfig.renderExternalStepHeader(this.hass, this.step)} +

${this.flowConfig.renderExternalStepDescription(this.hass, this.step)}
@@ -51,6 +56,9 @@ class StepFlowExternal extends LitElement { .open-button a { text-decoration: none; } + h2.end-space { + padding-inline-end: 72px; + } `, ]; } diff --git a/src/dialogs/config-flow/step-flow-form.ts b/src/dialogs/config-flow/step-flow-form.ts index 0c6da5eda2..06ec17dc0d 100644 --- a/src/dialogs/config-flow/step-flow-form.ts +++ b/src/dialogs/config-flow/step-flow-form.ts @@ -27,6 +27,9 @@ class StepFlowForm extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; + @property({ type: Boolean, attribute: "increase-padding-end" }) + public increasePaddingEnd = false; + @state() private _loading = false; @state() private _stepData?: Record; @@ -43,7 +46,9 @@ class StepFlowForm extends LitElement { const stepData = this._stepDataProcessed; return html` -

${this.flowConfig.renderShowFormStepHeader(this.hass, this.step)}

+

+ ${this.flowConfig.renderShowFormStepHeader(this.hass, this.step)} +

${this.flowConfig.renderShowFormStepDescription(this.hass, this.step)} ${this._errorMsg diff --git a/src/dialogs/config-flow/step-flow-menu.ts b/src/dialogs/config-flow/step-flow-menu.ts index 7c1f1e35f6..b0fcd3ba64 100644 --- a/src/dialogs/config-flow/step-flow-menu.ts +++ b/src/dialogs/config-flow/step-flow-menu.ts @@ -17,6 +17,9 @@ class StepFlowMenu extends LitElement { @property({ attribute: false }) public step!: DataEntryFlowStepMenu; + @property({ type: Boolean, attribute: "increase-padding-end" }) + public increasePaddingEnd = false; + protected render(): TemplateResult { let options: string[]; let translations: Record; @@ -42,7 +45,9 @@ class StepFlowMenu extends LitElement { ); return html` -

${this.flowConfig.renderMenuHeader(this.hass, this.step)}

+

+ ${this.flowConfig.renderMenuHeader(this.hass, this.step)} +

${description ? html`
${description}
` : ""}
${options.map( diff --git a/src/dialogs/config-flow/step-flow-progress.ts b/src/dialogs/config-flow/step-flow-progress.ts index ef56fa271d..c71efcb98c 100644 --- a/src/dialogs/config-flow/step-flow-progress.ts +++ b/src/dialogs/config-flow/step-flow-progress.ts @@ -24,9 +24,12 @@ class StepFlowProgress extends LitElement { @property({ type: Number }) public progress?: number; + @property({ type: Boolean, attribute: "increase-padding-end" }) + public increasePaddingEnd = false; + protected render(): TemplateResult { return html` -

+

${this.flowConfig.renderShowFormProgressHeader(this.hass, this.step)}

diff --git a/src/dialogs/config-flow/styles.ts b/src/dialogs/config-flow/styles.ts index daaa9342af..0e2aca3e7b 100644 --- a/src/dialogs/config-flow/styles.ts +++ b/src/dialogs/config-flow/styles.ts @@ -22,6 +22,9 @@ export const configFlowContentStyles = css` text-transform: var(--mdc-typography-headline6-text-transform, inherit); box-sizing: border-box; } + h2.end-space { + padding-inline-end: 72px; + } .content, .preview { From 042cd0d3a3423ca6fe5963aab8b65fdadabcdb25 Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Tue, 6 May 2025 13:52:28 +0200 Subject: [PATCH 18/75] Fix sidebar item text width (#25332) * Fix sidebar item text width to utilize full available space * Update src/components/ha-sidebar.ts Co-authored-by: Bram Kragten --------- Co-authored-by: Bram Kragten --- src/components/ha-sidebar.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 19c4a8d633..a286613cb0 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -940,7 +940,6 @@ class HaSidebar extends SubscribeMixin(LitElement) { ha-md-list-item .item-text { display: none; - max-width: calc(100% - 56px); font-weight: 500; font-size: 14px; } From 38a5035d6848b62f57f33b1b1efdf9799c5e04fc Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Tue, 6 May 2025 15:30:04 +0200 Subject: [PATCH 19/75] Fix outlined icon button style (#25340) --- src/components/ha-outlined-icon-button.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/ha-outlined-icon-button.ts b/src/components/ha-outlined-icon-button.ts index 7e0835bc5a..2615e1fc45 100644 --- a/src/components/ha-outlined-icon-button.ts +++ b/src/components/ha-outlined-icon-button.ts @@ -6,6 +6,13 @@ import { customElement } from "lit/decorators"; @customElement("ha-outlined-icon-button") export class HaOutlinedIconButton extends IconButton { + protected override getRenderClasses() { + return { + ...super.getRenderClasses(), + outlined: true, + }; + } + static override styles = [ css` .icon-button { From 1aa1bfda2c96f4445485a378a95e867e4ea508ff Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Tue, 6 May 2025 15:56:20 +0200 Subject: [PATCH 20/75] Use middle dot 00B7 as separator (#25336) --- src/components/data-table/ha-data-table.ts | 2 +- src/dialogs/more-info/controls/more-info-cover.ts | 2 +- src/dialogs/more-info/controls/more-info-valve.ts | 2 +- .../backup/components/config/ha-backup-config-agents.ts | 2 +- src/panels/config/info/ha-config-info.ts | 2 +- src/panels/config/logs/dialog-download-logs.ts | 2 +- src/panels/config/repairs/dialog-repairs-issue-subtitle.ts | 2 +- src/panels/config/repairs/ha-config-repairs.ts | 4 ++-- .../climate/ha-state-control-climate-temperature.ts | 2 +- src/state-display/state-display.ts | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts index 39447ca320..66d7a3ba60 100644 --- a/src/components/data-table/ha-data-table.ts +++ b/src/components/data-table/ha-data-table.ts @@ -603,7 +603,7 @@ export class HaDataTable extends LitElement { .map( ([key2, column2], i) => html`${i !== 0 - ? " ⸱ " + ? " · " : nothing}${column2.template ? column2.template(row) : row[key2]}` diff --git a/src/dialogs/more-info/controls/more-info-cover.ts b/src/dialogs/more-info/controls/more-info-cover.ts index 166d5367a6..b041b44b5e 100644 --- a/src/dialogs/more-info/controls/more-info-cover.ts +++ b/src/dialogs/more-info/controls/more-info-cover.ts @@ -57,7 +57,7 @@ class MoreInfoCover extends LitElement { ); if (positionStateDisplay) { - return `${stateDisplay} ⸱ ${positionStateDisplay}`; + return `${stateDisplay} · ${positionStateDisplay}`; } return stateDisplay; } diff --git a/src/dialogs/more-info/controls/more-info-valve.ts b/src/dialogs/more-info/controls/more-info-valve.ts index 66158025c8..84a0e43eaf 100644 --- a/src/dialogs/more-info/controls/more-info-valve.ts +++ b/src/dialogs/more-info/controls/more-info-valve.ts @@ -57,7 +57,7 @@ class MoreInfoValve extends LitElement { ); if (positionStateDisplay) { - return `${stateDisplay} ⸱ ${positionStateDisplay}`; + return `${stateDisplay} · ${positionStateDisplay}`; } return stateDisplay; } 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 a9817dba96..f808d3fe99 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 @@ -102,7 +102,7 @@ class HaBackupConfigAgents extends LitElement { ); } } - return join(texts, html``); + return join(texts, html` · `); } private _availableAgents = memoizeOne( diff --git a/src/panels/config/info/ha-config-info.ts b/src/panels/config/info/ha-config-info.ts index 26acffcabd..d58f4a858e 100644 --- a/src/panels/config/info/ha-config-info.ts +++ b/src/panels/config/info/ha-config-info.ts @@ -156,7 +156,7 @@ class HaConfigInfo extends LitElement { )} - ${JS_VERSION}${JS_TYPE !== "modern" ? ` ⸱ ${JS_TYPE}` : ""} + ${JS_VERSION}${JS_TYPE !== "modern" ? ` · ${JS_TYPE}` : ""} diff --git a/src/panels/config/logs/dialog-download-logs.ts b/src/panels/config/logs/dialog-download-logs.ts index 801ef1db22..528235c4e5 100644 --- a/src/panels/config/logs/dialog-download-logs.ts +++ b/src/panels/config/logs/dialog-download-logs.ts @@ -70,7 +70,7 @@ class DownloadLogsDialog extends LitElement { ${this._dialogParams.header}${this._dialogParams.boot === 0 ? "" - : ` ⸱ ${this._dialogParams.boot === -1 ? this.hass.localize("ui.panel.config.logs.previous") : this.hass.localize("ui.panel.config.logs.startups_ago", { boot: this._dialogParams.boot * -1 })}`} + : ` · ${this._dialogParams.boot === -1 ? this.hass.localize("ui.panel.config.logs.previous") : this.hass.localize("ui.panel.config.logs.startups_ago", { boot: this._dialogParams.boot * -1 })}`}
diff --git a/src/panels/config/repairs/dialog-repairs-issue-subtitle.ts b/src/panels/config/repairs/dialog-repairs-issue-subtitle.ts index 6ea15ed6e4..d0c39bc951 100644 --- a/src/panels/config/repairs/dialog-repairs-issue-subtitle.ts +++ b/src/panels/config/repairs/dialog-repairs-issue-subtitle.ts @@ -20,7 +20,7 @@ class DialogRepairsIssueSubtitle extends LitElement { protected render() { const domainName = domainToName(this.hass.localize, this.issue.domain); const reportedBy = domainName - ? ` ⸱ ${this.hass.localize("ui.panel.config.repairs.reported_by", { + ? ` · ${this.hass.localize("ui.panel.config.repairs.reported_by", { integration: domainName, })}` : ""; diff --git a/src/panels/config/repairs/ha-config-repairs.ts b/src/panels/config/repairs/ha-config-repairs.ts index 77345f3e86..f4729b0287 100644 --- a/src/panels/config/repairs/ha-config-repairs.ts +++ b/src/panels/config/repairs/ha-config-repairs.ts @@ -100,13 +100,13 @@ class HaConfigRepairs extends LitElement { ${(issue.severity === "critical" || issue.severity === "error") && issue.created - ? " ⸱ " + ? " · " : ""} ${createdBy ? html`${createdBy}` : nothing} ${issue.ignored - ? ` ⸱ ${this.hass.localize( + ? ` · ${this.hass.localize( "ui.panel.config.repairs.dialog.ignored_in_version_short", { version: issue.dismissed_version } )}` diff --git a/src/state-control/climate/ha-state-control-climate-temperature.ts b/src/state-control/climate/ha-state-control-climate-temperature.ts index 6b2000222b..a3317dfde3 100644 --- a/src/state-control/climate/ha-state-control-climate-temperature.ts +++ b/src/state-control/climate/ha-state-control-climate-temperature.ts @@ -366,7 +366,7 @@ export class HaStateControlClimateTemperature extends LitElement { > ${this._renderTarget(this._targetTemperature.low!, "normal", true)} - + ·