From 2add88ccc23d87a92329b3ee07128389ef1c0ed4 Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Tue, 2 Jan 2024 05:07:34 -0800 Subject: [PATCH 01/32] Localize a device action string (#19203) --- src/data/script_i18n.ts | 4 +++- src/translations/en.json | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/data/script_i18n.ts b/src/data/script_i18n.ts index 1ba30198bd..4b07b84f0e 100644 --- a/src/data/script_i18n.ts +++ b/src/data/script_i18n.ts @@ -404,7 +404,9 @@ const tryDescribeAction = ( if (actionType === "device_action") { const config = action as DeviceAction; if (!config.device_id) { - return "Device action"; + return hass.localize( + `${actionTranslationBaseKey}.device_id.description.no_device` + ); } const localized = localizeDeviceAutomationAction( hass, diff --git a/src/translations/en.json b/src/translations/en.json index 0039d9926f..a3070c0787 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2990,7 +2990,8 @@ "flash": "Flash" }, "description": { - "picker": "Do something on a device. Great way to start." + "picker": "Do something on a device. Great way to start.", + "no_device": "Device action" } }, "activate_scene": { From 4fcf99faa7b6735aee1550b785a76df8e633dcca Mon Sep 17 00:00:00 2001 From: JLo Date: Tue, 2 Jan 2024 12:08:05 +0100 Subject: [PATCH 02/32] Review on automation editor text (#19223) - Added `.` to bloc descriptions - Changed "Other" into "OTher triggers" "Other conditions" and "Other actions" - Adapted a few descriptions --- src/translations/en.json | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/translations/en.json b/src/translations/en.json index a3070c0787..c176cf65c9 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2492,13 +2492,13 @@ "groups": { "entity": { "label": "Entity", - "description": "When something happens to an entity" + "description": "When something happens to an entity." }, "time_location": { "label": "Time and location", "description": "When someone enters or leaves a zone, or at a specific time." }, - "other": { "label": "Other" } + "other": { "label": "Other triggers" } }, "type": { "calendar": { @@ -2534,7 +2534,7 @@ "context_user_picked": "User firing event", "context_user_pick": "Select user", "description": { - "picker": "When an event is being received (event is an advanced concept in Home Assistant)", + "picker": "When an event is being received (event is an advanced concept in Home Assistant).", "full": "When {eventTypes} event is fired" } }, @@ -2546,7 +2546,7 @@ "enter": "Enter", "leave": "Leave", "description": { - "picker": "When an entity created by a geolocation platform appears in or disappears from a zone", + "picker": "When an entity created by a geolocation platform appears in or disappears from a zone.", "full": "When {source} {event, select, \n enter {enters}\n leave {leaves} other {} \n} {zone} {numberOfZones, plural,\n one {zone}\n other {zones}\n}" } }, @@ -2608,7 +2608,7 @@ "updated": "updated" }, "description": { - "picker": "When a persistent notification is added or removed", + "picker": "When a persistent notification is added or removed.", "full": "When a persistent notification is updated" } }, @@ -2619,7 +2619,7 @@ "sunset": "Sunset", "offset": "Offset (optional)", "description": { - "picker": "When the sun sets or rises", + "picker": "When the sun sets or rises.", "sets": "When the sun sets{hasDuration, select, \n true { offset by {duration}} \n other {}\n }", "rises": "When the sun rises{hasDuration, select, \n true { offset by {duration}} \n other {}\n }" } @@ -2648,7 +2648,7 @@ "value_template": "Value template", "for": "For", "description": { - "picker": "When a template is evaluated to true.", + "picker": "When a template evaluates to true.", "full": "When a template changes from false to true{hasDuration, select, \n true { for {duration}} \n other {}\n }" } }, @@ -2669,7 +2669,7 @@ "minutes": "Minutes", "seconds": "Seconds", "description": { - "picker": "Periodically, every defined interval of time." + "picker": "Periodically, at a defined interval." } }, "webhook": { @@ -2692,7 +2692,7 @@ "enter": "Enter", "leave": "Leave", "description": { - "picker": "When someone (or something) enters or leaves a zone", + "picker": "When someone (or something) enters or leaves a zone.", "full": "When {entity} {event, select, \n enter {enters}\n leave {leaves} other {} \n} {zone} {numberOfZones, plural,\n one {zone} \n other {zones}\n}" } } @@ -2734,7 +2734,7 @@ "label": "Time and location", "description": "If someone is in a zone or if the current time is before or after a specified time." }, - "other": { "label": "Other" }, + "other": { "label": "Other conditions" }, "building_blocks": { "label": "Building blocks", "description": "Build more complex conditions." @@ -2766,7 +2766,7 @@ "not": { "label": "Not", "description": { - "picker": "Test if a condition is not true", + "picker": "Test if a condition is not true.", "no_conditions": "Test if no condition matches", "one_condition": "Test if 1 condition does not match", "full": "Test if none of {count} conditions match" @@ -2800,7 +2800,7 @@ "label": "[%key:ui::panel::config::automation::editor::triggers::type::state::label%]", "state": "[%key:ui::panel::config::automation::editor::triggers::type::state::label%]", "description": { - "picker": "If an entity (or attribute) is in a specific state", + "picker": "If an entity (or attribute) is in a specific state.", "no_entity": "Confirm state", "full": "Confirm{hasAttribute, select, \n true { {attribute} of}\n other {}\n} {numberOfEntities, plural,\n zero {an entity is}\n one {{entities} is}\n other {{entities} are}\n} {numberOfStates, plural,\n zero {a state}\n other {{states}}\n}{hasDuration, select, \n true { for {duration}} \n other {}\n }" } @@ -2821,7 +2821,7 @@ "label": "[%key:ui::panel::config::automation::editor::triggers::type::template::label%]", "value_template": "[%key:ui::panel::config::automation::editor::triggers::type::template::value_template%]", "description": { - "picker": "If a template is evaluated to true.", + "picker": "If a template evaluates to true.", "full": "Test if template renders a value equal to true" } }, @@ -2844,7 +2844,7 @@ "sun": "Sunday" }, "description": { - "picker": "If the current time is before or after a specified time", + "picker": "If the current time is before or after a specified time.", "full": "Confirm the {hasTime, select, \n after {time is after {time_after}}\n before {time is before {time_before}}\n after_before {time is after {time_after} and before {time_before}} \n other {}\n }{hasTimeAndDay, select, \n true { and the }\n other {}\n}{hasDay, select, \n true { day is {day}}\n other {}\n}" } }, @@ -2862,7 +2862,7 @@ "entity": "[%key:ui::panel::config::automation::editor::triggers::type::zone::entity%]", "zone": "[%key:ui::panel::config::automation::editor::triggers::type::zone::label%]", "description": { - "picker": "If someone (or something) is in a zone", + "picker": "If someone (or something) is in a zone.", "full": "Confirm {entity} {numberOfEntities, plural,\n one {is}\n other {are}\n} in {zone} {numberOfZones, plural,\n one {zone} \n other {zones}\n} " } } @@ -2899,7 +2899,7 @@ "continue_on_error": "Continue on error", "groups": { "helpers": { "label": "Helpers" }, - "other": { "label": "Other" }, + "other": { "label": "Other actions" }, "building_blocks": { "label": "Building blocks", "description": "Build more complex sequences of actions." @@ -3070,14 +3070,14 @@ "response_variable": "The name of the variable to use as response", "error": "Stop because of an unexpected error", "description": { - "picker": "Stop the sequence of actions", + "picker": "Stop the sequence of actions.", "full": "Stop {hasReason, select, \n true { because: {reason}} \n other {}\n }" } }, "parallel": { "label": "Run in parallel", "description": { - "picker": "perform a sequence of actions in parallel.", + "picker": "Perform a sequence of actions in parallel.", "full": "Run {number} {number, plural,\n one {action}\n other {actions}\n} in parallel" } }, From f099f66065ead07852d268773eecb468523550eb Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 2 Jan 2024 13:36:06 +0100 Subject: [PATCH 03/32] Automation editor tweaks (#19225) * Automation editor tweaks * fix styling --- src/data/condition.ts | 1 - .../add-automation-element-dialog.ts | 145 +++++++++++++----- .../condition/ha-automation-condition.ts | 1 + .../types/ha-automation-condition-device.ts | 1 + .../show-add-automation-element-dialog.ts | 1 + .../types/ha-automation-trigger-device.ts | 1 + 6 files changed, 108 insertions(+), 42 deletions(-) diff --git a/src/data/condition.ts b/src/data/condition.ts index 44a0e21860..d8c7af44fe 100644 --- a/src/data/condition.ts +++ b/src/data/condition.ts @@ -46,7 +46,6 @@ export const CONDITION_GROUPS: AutomationElementGroup = { icon: mdiDotsHorizontal, members: { template: {}, - trigger: {}, }, }, } as const; diff --git a/src/panels/config/automation/add-automation-element-dialog.ts b/src/panels/config/automation/add-automation-element-dialog.ts index b96283a61d..31760dca1b 100644 --- a/src/panels/config/automation/add-automation-element-dialog.ts +++ b/src/panels/config/automation/add-automation-element-dialog.ts @@ -1,7 +1,14 @@ import "@material/mwc-list/mwc-list"; import { mdiClose, mdiContentPaste, mdiPlus } from "@mdi/js"; import Fuse, { IFuseOptions } from "fuse.js"; -import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; +import { + CSSResultGroup, + LitElement, + PropertyValues, + css, + html, + nothing, +} from "lit"; import { customElement, property, query, state } from "lit/decorators"; import { ifDefined } from "lit/directives/if-defined"; import { repeat } from "lit/directives/repeat"; @@ -42,6 +49,8 @@ import { AddAutomationElementDialogParams, PASTE_VALUE, } from "./show-add-automation-element-dialog"; +import { computeDomain } from "../../../common/entity/compute_domain"; +import { deepEqual } from "../../../common/util/deep-equal"; const TYPES = { trigger: { groups: TRIGGER_GROUPS, icons: TRIGGER_ICONS }, @@ -93,13 +102,15 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { @state() private _manifests?: DomainManifestLookup; + @state() private _domains?: Set; + @query("ha-dialog") private _dialog?: HaDialog; private _fullScreen = false; - private _width?: number; + @state() private _width?: number; - private _height?: number; + @state() private _height?: number; public showDialog(params): void { this._params = params; @@ -124,6 +135,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { this._prev = undefined; this._filter = ""; this._manifests = undefined; + this._domains = undefined; } private _convertToItem = ( @@ -152,6 +164,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { private _getFilteredItems = memoizeOne( ( type: AddAutomationElementDialogParams["type"], + root: AddAutomationElementDialogParams["root"], group: string | undefined, filter: string, localize: LocalizeFunc, @@ -164,6 +177,10 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { : TYPES[type].groups[group].members! : TYPES[type].groups; + if (type === "condition" && group === "other" && !root) { + groups.trigger = {}; + } + const flattenGroups = (grp: AutomationElementGroup) => Object.entries(grp).map(([key, options]) => options.members @@ -191,7 +208,9 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { private _getGroupItems = memoizeOne( ( type: AddAutomationElementDialogParams["type"], + root: AddAutomationElementDialogParams["root"], group: string | undefined, + domains: Set | undefined, localize: LocalizeFunc, services: HomeAssistant["services"], manifests?: DomainManifestLookup @@ -208,6 +227,10 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { ? TYPES[type].groups[group].members! : TYPES[type].groups; + if (type === "condition" && group === "other" && !root) { + groups.trigger = {}; + } + const result = Object.entries(groups).map(([key, options]) => this._convertToItem(key, options, type, localize) ); @@ -215,15 +238,33 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { if (type === "action") { if (!this._group) { result.unshift( - ...this._serviceGroups(localize, services, manifests, undefined) + ...this._serviceGroups( + localize, + services, + manifests, + domains, + undefined + ) ); } else if (this._group === "helpers") { result.unshift( - ...this._serviceGroups(localize, services, manifests, "helper") + ...this._serviceGroups( + localize, + services, + manifests, + domains, + "helper" + ) ); } else if (this._group === "other") { result.unshift( - ...this._serviceGroups(localize, services, manifests, "other") + ...this._serviceGroups( + localize, + services, + manifests, + domains, + "other" + ) ); } } @@ -243,42 +284,44 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { } ); - private _serviceGroups = memoizeOne( - ( - localize: LocalizeFunc, - services: HomeAssistant["services"], - manifests: DomainManifestLookup | undefined, - type: "helper" | "other" | undefined - ): ListItem[] => { - if (!services || !manifests) { - return []; - } - const result: ListItem[] = []; - Object.keys(services).forEach((domain) => { - const manifest = manifests[domain]; - if ( - (type === undefined && - manifest?.integration_type === "entity" && - !ENTITY_DOMAINS_OTHER.has(domain)) || - (type === "helper" && manifest?.integration_type === "helper") || - (type === "other" && - (ENTITY_DOMAINS_OTHER.has(domain) || - !["helper", "entity"].includes(manifest?.integration_type || ""))) - ) { - result.push({ - group: true, - icon: domainIcon(domain), - key: `${SERVICE_PREFIX}${domain}`, - name: domainToName(localize, domain, manifest), - description: "", - }); - } - }); - return result.sort((a, b) => - stringCompare(a.name, b.name, this.hass.locale.language) - ); + private _serviceGroups = ( + localize: LocalizeFunc, + services: HomeAssistant["services"], + manifests: DomainManifestLookup | undefined, + domains: Set | undefined, + type: "helper" | "other" | undefined + ): ListItem[] => { + if (!services || !manifests) { + return []; } - ); + const result: ListItem[] = []; + Object.keys(services).forEach((domain) => { + const manifest = manifests[domain]; + const domainUsed = !domains ? true : domains.has(domain); + if ( + (type === undefined && + manifest?.integration_type === "entity" && + domainUsed && + !ENTITY_DOMAINS_OTHER.has(domain)) || + (type === "helper" && manifest?.integration_type === "helper") || + (type === "other" && + (ENTITY_DOMAINS_OTHER.has(domain) || + (!domainUsed && manifest?.integration_type === "entity") || + !["helper", "entity"].includes(manifest?.integration_type || ""))) + ) { + result.push({ + group: true, + icon: domainIcon(domain), + key: `${SERVICE_PREFIX}${domain}`, + name: domainToName(localize, domain, manifest), + description: "", + }); + } + }); + return result.sort((a, b) => + stringCompare(a.name, b.name, this.hass.locale.language) + ); + }; private _services = memoizeOne( ( @@ -368,6 +411,19 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { this._height = boundingRect?.height; } + protected willUpdate(changedProperties: PropertyValues): void { + if ( + this._params?.type === "action" && + changedProperties.has("hass") && + changedProperties.get("hass")?.states !== this.hass.states + ) { + const domains = new Set(Object.keys(this.hass.states).map(computeDomain)); + if (!deepEqual(domains, this._domains)) { + this._domains = domains; + } + } + } + protected render() { if (!this._params) { return nothing; @@ -376,6 +432,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { const items = this._filter ? this._getFilteredItems( this._params.type, + this._params.root, this._group, this._filter, this.hass.localize, @@ -384,7 +441,9 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { ) : this._getGroupItems( this._params.type, + this._params.root, this._group, + this._domains, this.hass.localize, this.hass.services, this._manifests @@ -562,6 +621,10 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { ha-icon-next { width: 24px; } + mwc-list { + max-height: 468px; + max-width: 100vw; + } search-input { display: block; margin: 0 16px; diff --git a/src/panels/config/automation/condition/ha-automation-condition.ts b/src/panels/config/automation/condition/ha-automation-condition.ts index 27364b92a3..ecf4f88237 100644 --- a/src/panels/config/automation/condition/ha-automation-condition.ts +++ b/src/panels/config/automation/condition/ha-automation-condition.ts @@ -203,6 +203,7 @@ export default class HaAutomationCondition extends LitElement { showAddAutomationElementDialog(this, { type: "condition", add: this._addCondition, + root: !this.nested, clipboardItem: this._clipboard?.condition?.condition, }); } diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-device.ts b/src/panels/config/automation/condition/types/ha-automation-condition-device.ts index 71568fe02c..4593a5f701 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-device.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-device.ts @@ -168,6 +168,7 @@ export class HaDeviceCondition extends LitElement { } ha-form { + display: block; margin-top: 24px; } `; diff --git a/src/panels/config/automation/show-add-automation-element-dialog.ts b/src/panels/config/automation/show-add-automation-element-dialog.ts index c497ca85c6..5545350512 100644 --- a/src/panels/config/automation/show-add-automation-element-dialog.ts +++ b/src/panels/config/automation/show-add-automation-element-dialog.ts @@ -6,6 +6,7 @@ export interface AddAutomationElementDialogParams { type: "trigger" | "condition" | "action"; add: (key: string) => void; clipboardItem: string | undefined; + root?: boolean; group?: string; } const loadDialog = () => import("./add-automation-element-dialog"); diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts index 8b3a635752..1b94ff6138 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts @@ -174,6 +174,7 @@ export class HaDeviceTrigger extends LitElement { } ha-form { + display: block; margin-top: 24px; } `; From c125ec087a11c0b584a85b10b6907cae764c9e73 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 2 Jan 2024 16:08:26 +0100 Subject: [PATCH 04/32] Remove references to "service call" from actions (#19226) --- src/components/ha-service-control.ts | 28 ++++++++++++++----- src/data/script.ts | 2 ++ src/data/script_i18n.ts | 5 +++- .../action/ha-automation-action-row.ts | 10 ++++++- .../automation/action/ha-automation-action.ts | 1 + src/translations/en.json | 1 + 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/components/ha-service-control.ts b/src/components/ha-service-control.ts index f1ae8ee54b..119418355c 100644 --- a/src/components/ha-service-control.ts +++ b/src/components/ha-service-control.ts @@ -4,7 +4,14 @@ import { HassServices, HassServiceTarget, } from "home-assistant-js-websocket"; -import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { + css, + CSSResultGroup, + html, + LitElement, + PropertyValues, + nothing, +} from "lit"; import { customElement, property, query, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { ensureArray } from "../common/array/ensure-array"; @@ -83,6 +90,8 @@ export class HaServiceControl extends LitElement { @property({ type: Boolean }) public showAdvanced?: boolean; + @property({ type: Boolean, reflect: true }) public hidePicker?: boolean; + @state() private _value!: this["value"]; @state() private _checkedKeys = new Set(); @@ -363,12 +372,14 @@ export class HaServiceControl extends LitElement { )) || serviceData?.description; - return html` + return html`${this.hidePicker + ? nothing + : html``}
${description ? html`

${description}

` : ""} ${this._manifest @@ -735,6 +746,9 @@ export class HaServiceControl extends LitElement { margin: var(--service-control-padding, 0 16px); padding: 16px 0; } + :host([hidePicker]) p { + padding-top: 0; + } .checkbox-spacer { width: 32px; } diff --git a/src/data/script.ts b/src/data/script.ts index f0b5e7151b..08910dc88f 100644 --- a/src/data/script.ts +++ b/src/data/script.ts @@ -52,6 +52,7 @@ export const serviceActionStruct: Describe = assign( target: optional(targetStruct), data: optional(object()), response_variable: optional(string()), + metadata: optional(object()), }) ); @@ -133,6 +134,7 @@ export interface ServiceAction extends BaseAction { target?: HassServiceTarget; data?: Record; response_variable?: string; + metadata?: Record; } export interface DeviceAction extends BaseAction { diff --git a/src/data/script_i18n.ts b/src/data/script_i18n.ts index 4b07b84f0e..3d7d8c5a1d 100644 --- a/src/data/script_i18n.ts +++ b/src/data/script_i18n.ts @@ -168,8 +168,11 @@ const tryDescribeAction = ( const service = hass.localize(`component.${domain}.services.${serviceName}.name`) || hass.services[domain][serviceName]?.name; + return hass.localize( - `${actionTranslationBaseKey}.service.description.service_based_on_name`, + `${actionTranslationBaseKey}.service.description.${ + config.metadata ? "service_name" : "service_based_on_name" + }`, { name: service ? `${domainToName(hass.localize, domain)}: ${service}` diff --git a/src/panels/config/automation/action/ha-automation-action-row.ts b/src/panels/config/automation/action/ha-automation-action-row.ts index f09c901c8e..0e58c0e8b2 100644 --- a/src/panels/config/automation/action/ha-automation-action-row.ts +++ b/src/panels/config/automation/action/ha-automation-action-row.ts @@ -29,6 +29,8 @@ import { classMap } from "lit/directives/class-map"; import { storage } from "../../../../common/decorators/storage"; import { dynamicElement } from "../../../../common/dom/dynamic-element-directive"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { computeDomain } from "../../../../common/entity/compute_domain"; +import { domainIconWithoutDefault } from "../../../../common/entity/domain_icon"; import { capitalizeFirstLetter } from "../../../../common/string/capitalize-first-letter"; import { handleStructError } from "../../../../common/structs/handle-errors"; import "../../../../components/ha-alert"; @@ -190,7 +192,13 @@ export default class HaAutomationActionRow extends LitElement {

${capitalizeFirstLetter( describeAction(this.hass, this._entityReg, this.action) diff --git a/src/panels/config/automation/action/ha-automation-action.ts b/src/panels/config/automation/action/ha-automation-action.ts index dca4bab6ac..ce312a7bd3 100644 --- a/src/panels/config/automation/action/ha-automation-action.ts +++ b/src/panels/config/automation/action/ha-automation-action.ts @@ -191,6 +191,7 @@ export default class HaAutomationAction extends LitElement { } else if (isService(action)) { actions = this.actions.concat({ service: getService(action), + metadata: {}, }); } else { const elClass = customElements.get( diff --git a/src/translations/en.json b/src/translations/en.json index c176cf65c9..e771c8fe19 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2914,6 +2914,7 @@ "description": { "service_based_on_template": "Call a service based on a template on {targets}", "service_based_on_name": "Call a service ''{name}'' on {targets}", + "service_name": "''{name}'' on {targets}", "service": "Call a service", "target_template": "templated {name}", "target_unknown_entity": "unknown entity", From f2226cdec24760fce2172978f97a07b609675372 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 2 Jan 2024 18:11:34 +0100 Subject: [PATCH 05/32] Use brand icons in actions (#19227) --- src/common/const.ts | 4 ++ .../add-automation-element-dialog.ts | 39 ++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/common/const.ts b/src/common/const.ts index 66c14e64e1..68f4fa97b1 100644 --- a/src/common/const.ts +++ b/src/common/const.ts @@ -29,6 +29,7 @@ import { mdiFlash, mdiFlower, mdiFormatListBulleted, + mdiFormatListCheckbox, mdiFormTextbox, mdiGauge, mdiGoogleAssistant, @@ -64,6 +65,7 @@ import { mdiTransmissionTower, mdiWater, mdiWaterPercent, + mdiWeatherPartlyCloudy, mdiWeatherPouring, mdiWeatherRainy, mdiWeatherWindy, @@ -128,6 +130,7 @@ export const FIXED_DOMAIN_ICONS = { updater: mdiCloudUpload, vacuum: mdiRobotVacuum, wake_word: mdiChatSleep, + weather: mdiWeatherPartlyCloudy, zone: mdiMapMarkerRadius, }; @@ -166,6 +169,7 @@ export const FIXED_DEVICE_CLASS_ICONS = { precipitation_intensity: mdiWeatherPouring, pressure: mdiGauge, reactive_power: mdiFlash, + shopping_List: mdiFormatListCheckbox, signal_strength: mdiWifi, sound_pressure: mdiEarHearing, speed: mdiSpeedometer, diff --git a/src/panels/config/automation/add-automation-element-dialog.ts b/src/panels/config/automation/add-automation-element-dialog.ts index 31760dca1b..0e930b7c99 100644 --- a/src/panels/config/automation/add-automation-element-dialog.ts +++ b/src/panels/config/automation/add-automation-element-dialog.ts @@ -15,7 +15,7 @@ import { repeat } from "lit/directives/repeat"; import { styleMap } from "lit/directives/style-map"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../common/dom/fire_event"; -import { domainIcon } from "../../../common/entity/domain_icon"; +import { domainIconWithoutDefault } from "../../../common/entity/domain_icon"; import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event"; import { stringCompare } from "../../../common/string/compare"; import { LocalizeFunc } from "../../../common/translations/localize"; @@ -45,6 +45,7 @@ import { TRIGGER_GROUPS, TRIGGER_ICONS } from "../../../data/trigger"; import { HassDialog } from "../../../dialogs/make-dialog-manager"; import { haStyle, haStyleDialog } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; +import { brandsUrl } from "../../../util/brands-url"; import { AddAutomationElementDialogParams, PASTE_VALUE, @@ -68,7 +69,8 @@ interface ListItem { key: string; name: string; description: string; - icon: string; + icon?: string; + image?: string; group: boolean; } @@ -309,9 +311,17 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { (!domainUsed && manifest?.integration_type === "entity") || !["helper", "entity"].includes(manifest?.integration_type || ""))) ) { + const icon = domainIconWithoutDefault(domain); result.push({ group: true, - icon: domainIcon(domain), + icon, + image: !icon + ? brandsUrl({ + domain, + type: "icon", + darkOptimized: this.hass.themes?.darkMode, + }) + : undefined, key: `${SERVICE_PREFIX}${domain}`, name: domainToName(localize, domain, manifest), description: "", @@ -345,9 +355,17 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { const services_keys = Object.keys(services[dmn]); for (const service of services_keys) { + const icon = domainIconWithoutDefault(dmn); result.push({ group: false, - icon: domainIcon(dmn), + icon, + image: !icon + ? brandsUrl({ + domain: dmn, + type: "icon", + darkOptimized: this.hass.themes?.darkMode, + }) + : undefined, key: `${SERVICE_PREFIX}${dmn}.${service}`, name: `${domain ? "" : `${domainToName(localize, dmn)}: `}${ this.hass.localize(`component.${dmn}.services.${service}.name`) || @@ -556,7 +574,18 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { > ${item.name} ${item.description} - + ${item.icon + ? html`` + : html``} ${item.group ? html`` : html` Date: Tue, 2 Jan 2024 18:31:18 +0100 Subject: [PATCH 06/32] Change format of service description (#19229) --- src/data/script_i18n.ts | 15 ++++++++++++--- src/translations/en.json | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/data/script_i18n.ts b/src/data/script_i18n.ts index 3d7d8c5a1d..40c823bc86 100644 --- a/src/data/script_i18n.ts +++ b/src/data/script_i18n.ts @@ -169,10 +169,19 @@ const tryDescribeAction = ( hass.localize(`component.${domain}.services.${serviceName}.name`) || hass.services[domain][serviceName]?.name; + if (config.metadata) { + return hass.localize( + `${actionTranslationBaseKey}.service.description.service_name`, + { + domain: domainToName(hass.localize, domain), + name: service || config.service, + targets: formatListWithAnds(hass.locale, targets), + } + ); + } + return hass.localize( - `${actionTranslationBaseKey}.service.description.${ - config.metadata ? "service_name" : "service_based_on_name" - }`, + `${actionTranslationBaseKey}.service.description.service_based_on_name`, { name: service ? `${domainToName(hass.localize, domain)}: ${service}` diff --git a/src/translations/en.json b/src/translations/en.json index e771c8fe19..6ef41c81c1 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2914,7 +2914,7 @@ "description": { "service_based_on_template": "Call a service based on a template on {targets}", "service_based_on_name": "Call a service ''{name}'' on {targets}", - "service_name": "''{name}'' on {targets}", + "service_name": "{domain} ''{name}'' on {targets}", "service": "Call a service", "target_template": "templated {name}", "target_unknown_entity": "unknown entity", From 18b5fd59a629268bce2d5d7aa6e7fd390e1d6ab1 Mon Sep 17 00:00:00 2001 From: Josh McCarty Date: Tue, 2 Jan 2024 10:35:08 -0700 Subject: [PATCH 07/32] Add missing device classes for entity-registry-settings-editor (#19231) * Add connectivity device class for binary sensors * Add update device class * Separate connectivity and update --- src/panels/config/entities/entity-registry-settings-editor.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/panels/config/entities/entity-registry-settings-editor.ts b/src/panels/config/entities/entity-registry-settings-editor.ts index 14d88e12af..9e7213e414 100644 --- a/src/panels/config/entities/entity-registry-settings-editor.ts +++ b/src/panels/config/entities/entity-registry-settings-editor.ts @@ -118,6 +118,8 @@ const OVERRIDE_DEVICE_CLASSES = { "carbon_monoxide", "moisture", ], // Alarm + ["connectivity"], // Connectivity + ["update"], // Update ], }; From 01bd88ce101c1c0909c093d55afdaab1cd24073d Mon Sep 17 00:00:00 2001 From: JLo Date: Tue, 2 Jan 2024 18:39:55 +0100 Subject: [PATCH 08/32] New copy for device trigger in automation editor (#19232) New copy for device trigger in automation editor: "Set of conditions provided by your device. Great way to start." --- src/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations/en.json b/src/translations/en.json index 6ef41c81c1..53306cd8b7 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2760,7 +2760,7 @@ "preset_mode": "Preset mode" }, "description": { - "picker": "If a device is in a certain state. Great way to start." + "picker": "Set of conditions provided by your device. Great way to start." } }, "not": { From 8d496e1511c0ed56116da4829141239ef92e0423 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 2 Jan 2024 18:47:39 +0100 Subject: [PATCH 09/32] Update add-automation-element-dialog.ts --- src/panels/config/automation/add-automation-element-dialog.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/panels/config/automation/add-automation-element-dialog.ts b/src/panels/config/automation/add-automation-element-dialog.ts index 0e930b7c99..d498e8375c 100644 --- a/src/panels/config/automation/add-automation-element-dialog.ts +++ b/src/panels/config/automation/add-automation-element-dialog.ts @@ -528,7 +528,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { rootTabbable style=${styleMap({ width: this._width ? `${this._width}px` : "auto", - height: this._height ? `${Math.min(468, this._height)}px` : "auto", + height: this._height ? `${Math.min(670, this._height)}px` : "auto", })} > ${this._params.clipboardItem && @@ -651,7 +651,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { width: 24px; } mwc-list { - max-height: 468px; + max-height: 670px; max-width: 100vw; } search-input { From de3b9a5bb2a847cc7353ec9e960a83363b57ba25 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 2 Jan 2024 18:48:34 +0100 Subject: [PATCH 10/32] Give todo and calendar edit static header (#19233) --- src/panels/calendar/dialog-calendar-event-editor.ts | 6 +++--- src/panels/todo/dialog-todo-item-editor.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/panels/calendar/dialog-calendar-event-editor.ts b/src/panels/calendar/dialog-calendar-event-editor.ts index 7c06cac92c..e5925b1243 100644 --- a/src/panels/calendar/dialog-calendar-event-editor.ts +++ b/src/panels/calendar/dialog-calendar-event-editor.ts @@ -144,9 +144,9 @@ class DialogCalendarEventEditor extends LitElement { escapeKeyAction .heading=${createCloseHeading( this.hass, - isCreate - ? this.hass.localize("ui.components.calendar.event.add") - : this._summary + this.hass.localize( + `ui.components.calendar.event.${isCreate ? "add" : "edit"}` + ) )} >
diff --git a/src/panels/todo/dialog-todo-item-editor.ts b/src/panels/todo/dialog-todo-item-editor.ts index c81b9e4dbe..cd26ad35fc 100644 --- a/src/panels/todo/dialog-todo-item-editor.ts +++ b/src/panels/todo/dialog-todo-item-editor.ts @@ -101,9 +101,9 @@ class DialogTodoItemEditor extends LitElement { scrimClickAction .heading=${createCloseHeading( this.hass, - isCreate - ? this.hass.localize("ui.components.todo.item.add") - : this._summary + this.hass.localize( + `ui.components.todo.item.${isCreate ? "add" : "edit"}` + ) )} >
From 53dedc6c6587b2eeb9f76b53f55ccb5129e99612 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 2 Jan 2024 18:49:31 +0100 Subject: [PATCH 11/32] Bumped version to 20240102.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d1e5abd3d1..7d09a1121e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240101.0" +version = "20240102.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" From 7354988ec96e1abf1e96dc4df755cf4ea0c4e599 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 2 Jan 2024 19:58:37 +0100 Subject: [PATCH 12/32] Move notification services to main list (#19235) --- .../config/automation/add-automation-element-dialog.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/panels/config/automation/add-automation-element-dialog.ts b/src/panels/config/automation/add-automation-element-dialog.ts index d498e8375c..06a77884f1 100644 --- a/src/panels/config/automation/add-automation-element-dialog.ts +++ b/src/panels/config/automation/add-automation-element-dialog.ts @@ -90,6 +90,8 @@ const ENTITY_DOMAINS_OTHER = new Set([ "image_processing", ]); +const ENTITY_DOMAINS_MAIN = new Set(["notify"]); + @customElement("add-automation-element-dialog") class DialogAddAutomationElement extends LitElement implements HassDialog { @property({ attribute: false }) public hass!: HomeAssistant; @@ -302,11 +304,13 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { const domainUsed = !domains ? true : domains.has(domain); if ( (type === undefined && - manifest?.integration_type === "entity" && - domainUsed && - !ENTITY_DOMAINS_OTHER.has(domain)) || + (ENTITY_DOMAINS_MAIN.has(domain) || + (manifest?.integration_type === "entity" && + domainUsed && + !ENTITY_DOMAINS_OTHER.has(domain)))) || (type === "helper" && manifest?.integration_type === "helper") || (type === "other" && + !ENTITY_DOMAINS_MAIN.has(domain) && (ENTITY_DOMAINS_OTHER.has(domain) || (!domainUsed && manifest?.integration_type === "entity") || !["helper", "entity"].includes(manifest?.integration_type || ""))) From c2f3e43ee50fcabd26254ebd3412217b6f49a045 Mon Sep 17 00:00:00 2001 From: Simon Lamon <32477463+silamon@users.noreply.github.com> Date: Tue, 2 Jan 2024 20:00:19 +0100 Subject: [PATCH 13/32] Set default values for required and disabled for labeled slider (#19246) Set default values --- src/components/ha-labeled-slider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ha-labeled-slider.ts b/src/components/ha-labeled-slider.ts index 366eb4f555..5faf7a8b96 100644 --- a/src/components/ha-labeled-slider.ts +++ b/src/components/ha-labeled-slider.ts @@ -10,9 +10,9 @@ class HaLabeledSlider extends LitElement { @property() public caption?: string; - @property() public disabled?: boolean; + @property({ type: Boolean }) public disabled = false; - @property() public required?: boolean; + @property({ type: Boolean }) public required = true; @property() public min: number = 0; From 8ee4aa9e634a2f391b4aa51f2a9cfeb116ce77d8 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 3 Jan 2024 10:37:59 +0100 Subject: [PATCH 14/32] Bumped version to 20240103.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7d09a1121e..f43e4cf0dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240102.0" +version = "20240103.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" From 6e7366bf690f500f9cfa4f81aefd002c822dc9ed Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 3 Jan 2024 10:37:30 +0100 Subject: [PATCH 15/32] Calculate used domains on open of action dialog (#19255) --- .../automation/add-automation-element-dialog.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/panels/config/automation/add-automation-element-dialog.ts b/src/panels/config/automation/add-automation-element-dialog.ts index 06a77884f1..f8be65baf1 100644 --- a/src/panels/config/automation/add-automation-element-dialog.ts +++ b/src/panels/config/automation/add-automation-element-dialog.ts @@ -122,6 +122,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { if (this._params?.type === "action") { this.hass.loadBackendTranslation("services"); this._fetchManifests(); + this._calculateUsedDomains(); } this._fullScreen = matchMedia( "all and (max-width: 450px), all and (max-height: 500px)" @@ -425,6 +426,13 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { this._manifests = manifests; } + private _calculateUsedDomains() { + const domains = new Set(Object.keys(this.hass.states).map(computeDomain)); + if (!deepEqual(domains, this._domains)) { + this._domains = domains; + } + } + protected _opened(): void { // Store the width and height so that when we search, box doesn't jump const boundingRect = @@ -439,10 +447,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { changedProperties.has("hass") && changedProperties.get("hass")?.states !== this.hass.states ) { - const domains = new Set(Object.keys(this.hass.states).map(computeDomain)); - if (!deepEqual(domains, this._domains)) { - this._domains = domains; - } + this._calculateUsedDomains(); } } From c9a0ae6e2d35488304c5ad0a62b528e4c64fe615 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 3 Jan 2024 12:28:46 +0100 Subject: [PATCH 16/32] Bumped version to 20240103.1 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f43e4cf0dc..570bc96eaf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240103.0" +version = "20240103.1" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" From 336214d97f3715a866988a257edf939ec37b25d5 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 3 Jan 2024 12:20:11 +0100 Subject: [PATCH 17/32] Revert conditional rendering of condition (#19257) * Fix conditionally showing `triggered by` * revert conditional rendering * Update add-automation-element-dialog.ts * Update add-automation-element-dialog.ts --- src/data/condition.ts | 1 + .../add-automation-element-dialog.ts | 43 ++++++++----------- .../condition/ha-automation-condition.ts | 1 - .../show-add-automation-element-dialog.ts | 1 - 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/data/condition.ts b/src/data/condition.ts index d8c7af44fe..44a0e21860 100644 --- a/src/data/condition.ts +++ b/src/data/condition.ts @@ -46,6 +46,7 @@ export const CONDITION_GROUPS: AutomationElementGroup = { icon: mdiDotsHorizontal, members: { template: {}, + trigger: {}, }, }, } as const; diff --git a/src/panels/config/automation/add-automation-element-dialog.ts b/src/panels/config/automation/add-automation-element-dialog.ts index f8be65baf1..cf5874f80c 100644 --- a/src/panels/config/automation/add-automation-element-dialog.ts +++ b/src/panels/config/automation/add-automation-element-dialog.ts @@ -143,6 +143,16 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { this._domains = undefined; } + private _getGroups = ( + type: AddAutomationElementDialogParams["type"], + group: string | undefined + ): AutomationElementGroup => + group + ? isService(group) + ? {} + : TYPES[type].groups[group].members! + : TYPES[type].groups; + private _convertToItem = ( key: string, options, @@ -169,22 +179,13 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { private _getFilteredItems = memoizeOne( ( type: AddAutomationElementDialogParams["type"], - root: AddAutomationElementDialogParams["root"], group: string | undefined, filter: string, localize: LocalizeFunc, services: HomeAssistant["services"], manifests?: DomainManifestLookup ): ListItem[] => { - const groups: AutomationElementGroup = group - ? isService(group) - ? {} - : TYPES[type].groups[group].members! - : TYPES[type].groups; - - if (type === "condition" && group === "other" && !root) { - groups.trigger = {}; - } + const groups = this._getGroups(type, group); const flattenGroups = (grp: AutomationElementGroup) => Object.entries(grp).map(([key, options]) => @@ -213,7 +214,6 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { private _getGroupItems = memoizeOne( ( type: AddAutomationElementDialogParams["type"], - root: AddAutomationElementDialogParams["root"], group: string | undefined, domains: Set | undefined, localize: LocalizeFunc, @@ -221,20 +221,17 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { manifests?: DomainManifestLookup ): ListItem[] => { if (type === "action" && isService(group)) { - const result = this._services(localize, services, manifests, group); + let result = this._services(localize, services, manifests, group); if (group === `${SERVICE_PREFIX}media_player`) { - result.unshift(this._convertToItem("play_media", {}, type, localize)); + result = [ + this._convertToItem("play_media", {}, type, localize), + ...result, + ]; } return result; } - const groups: AutomationElementGroup = group - ? TYPES[type].groups[group].members! - : TYPES[type].groups; - - if (type === "condition" && group === "other" && !root) { - groups.trigger = {}; - } + const groups = this._getGroups(type, group); const result = Object.entries(groups).map(([key, options]) => this._convertToItem(key, options, type, localize) @@ -459,7 +456,6 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { const items = this._filter ? this._getFilteredItems( this._params.type, - this._params.root, this._group, this._filter, this.hass.localize, @@ -468,7 +464,6 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { ) : this._getGroupItems( this._params.type, - this._params.root, this._group, this._domains, this.hass.localize, @@ -537,7 +532,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { rootTabbable style=${styleMap({ width: this._width ? `${this._width}px` : "auto", - height: this._height ? `${Math.min(670, this._height)}px` : "auto", + height: this._height ? `${Math.min(468, this._height)}px` : "auto", })} > ${this._params.clipboardItem && @@ -660,7 +655,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog { width: 24px; } mwc-list { - max-height: 670px; + max-height: 468px; max-width: 100vw; } search-input { diff --git a/src/panels/config/automation/condition/ha-automation-condition.ts b/src/panels/config/automation/condition/ha-automation-condition.ts index ecf4f88237..27364b92a3 100644 --- a/src/panels/config/automation/condition/ha-automation-condition.ts +++ b/src/panels/config/automation/condition/ha-automation-condition.ts @@ -203,7 +203,6 @@ export default class HaAutomationCondition extends LitElement { showAddAutomationElementDialog(this, { type: "condition", add: this._addCondition, - root: !this.nested, clipboardItem: this._clipboard?.condition?.condition, }); } diff --git a/src/panels/config/automation/show-add-automation-element-dialog.ts b/src/panels/config/automation/show-add-automation-element-dialog.ts index 5545350512..c497ca85c6 100644 --- a/src/panels/config/automation/show-add-automation-element-dialog.ts +++ b/src/panels/config/automation/show-add-automation-element-dialog.ts @@ -6,7 +6,6 @@ export interface AddAutomationElementDialogParams { type: "trigger" | "condition" | "action"; add: (key: string) => void; clipboardItem: string | undefined; - root?: boolean; group?: string; } const loadDialog = () => import("./add-automation-element-dialog"); From ae0eac3415f9df2cbab002c1f09742f0ee70c573 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 3 Jan 2024 14:59:45 +0100 Subject: [PATCH 18/32] Bumped version to 20240103.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 570bc96eaf..f43e4cf0dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240103.1" +version = "20240103.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" From 22929672a069db25a0a94f230c8c9f57ac0afdd7 Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Wed, 3 Jan 2024 05:58:59 -0800 Subject: [PATCH 19/32] Remove tile pointer/ripple/index when it has no action (#19137) * Remove tile pointer/ripple/index when it has no action * update * Apply suggestions from code review Co-authored-by: Paul Bottein --------- Co-authored-by: Paul Bottein --- src/panels/lovelace/cards/hui-tile-card.ts | 27 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/panels/lovelace/cards/hui-tile-card.ts b/src/panels/lovelace/cards/hui-tile-card.ts index 1c06426d1a..b3470aeed5 100644 --- a/src/panels/lovelace/cards/hui-tile-card.ts +++ b/src/panels/lovelace/cards/hui-tile-card.ts @@ -287,21 +287,40 @@ export class HuiTileCard extends LitElement implements LovelaceCard { @eventOptions({ passive: true }) private handleRippleActivate(evt?: Event) { + if (!this.hasCardAction) return; this._rippleHandlers.startPress(evt); } private handleRippleDeactivate() { + if (!this.hasCardAction) return; this._rippleHandlers.endPress(); } private handleRippleMouseEnter() { + if (!this.hasCardAction) return; this._rippleHandlers.startHover(); } private handleRippleMouseLeave() { + if (!this.hasCardAction) return; this._rippleHandlers.endHover(); } + get hasCardAction() { + return ( + !this._config?.tap_action || + hasAction(this._config?.tap_action) || + hasAction(this._config?.hold_action) || + hasAction(this._config?.double_tap_action) + ); + } + + get hasIconAction() { + return ( + !this._config?.icon_tap_action || hasAction(this._config?.icon_tap_action) + ); + } + protected render() { if (!this._config || !this.hass) { return nothing; @@ -368,8 +387,8 @@ export class HuiTileCard extends LitElement implements LovelaceCard { hasHold: hasAction(this._config!.hold_action), hasDoubleClick: hasAction(this._config!.double_tap_action), })} - role="button" - tabindex="0" + role=${ifDefined(this.hasCardAction ? "button" : undefined)} + tabindex=${ifDefined(this.hasCardAction ? "0" : undefined)} aria-labelledby="info" @mousedown=${this.handleRippleActivate} @mouseup=${this.handleRippleDeactivate} @@ -386,8 +405,8 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
From 62dafac72b2c4fcc3975122aaa2c390dc1abcc80 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Wed, 3 Jan 2024 14:26:40 +0100 Subject: [PATCH 20/32] Display edit button for climate fan mode feature (#19259) --- .../lovelace/editor/config-elements/hui-card-features-editor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts index 49290ba571..8693be890d 100644 --- a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts @@ -81,6 +81,7 @@ const EDITABLES_FEATURE_TYPES = new Set([ "humidifier-modes", "water-heater-operation-modes", "lawn-mower-commands", + "climate-fan-modes", "climate-preset-modes", "numeric-input", "update-actions", From 2c69fe8c53cca9b1d3a1cda718b16cb06f8d23d4 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 3 Jan 2024 14:58:36 +0100 Subject: [PATCH 21/32] Fix checking todo item that dont support due date (#19262) * Fix checking todo item that dont support due date * make cleaner * Revert "make cleaner" This reverts commit fa33b3361451dd334d9f69142f9754a1ea2c1ca4. * Update dialog-todo-item-editor.ts * do check in 1 place --- src/data/todo.ts | 12 +++++++++--- src/panels/lovelace/cards/hui-todo-list-card.ts | 3 ++- src/panels/todo/dialog-todo-item-editor.ts | 12 +++++++++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/data/todo.ts b/src/data/todo.ts index 9af8ef0f4c..659c8d0c3c 100644 --- a/src/data/todo.ts +++ b/src/data/todo.ts @@ -83,9 +83,12 @@ export const updateItem = ( item: item.uid, rename: item.summary, status: item.status, - description: item.description || null, + description: item.description, due_datetime: item.due?.includes("T") ? item.due : undefined, - due_date: item.due?.includes("T") ? undefined : item.due || null, + due_date: + item.due === undefined || item.due?.includes("T") + ? undefined + : item.due, }, { entity_id } ); @@ -102,7 +105,10 @@ export const createItem = ( item: item.summary, description: item.description || undefined, due_datetime: item.due?.includes("T") ? item.due : undefined, - due_date: item.due?.includes("T") ? undefined : item.due, + due_date: + item.due === undefined || item.due?.includes("T") + ? undefined + : item.due, }, { entity_id } ); diff --git a/src/panels/lovelace/cards/hui-todo-list-card.ts b/src/panels/lovelace/cards/hui-todo-list-card.ts index 3352f7a42b..d1d62880f8 100644 --- a/src/panels/lovelace/cards/hui-todo-list-card.ts +++ b/src/panels/lovelace/cards/hui-todo-list-card.ts @@ -476,7 +476,8 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard { return; } await updateItem(this.hass!, this._entityId!, { - ...item, + uid: item.uid, + summary: item.summary, status: item.status === TodoItemStatus.NeedsAction ? TodoItemStatus.Completed diff --git a/src/panels/todo/dialog-todo-item-editor.ts b/src/panels/todo/dialog-todo-item-editor.ts index cd26ad35fc..daa5eff686 100644 --- a/src/panels/todo/dialog-todo-item-editor.ts +++ b/src/panels/todo/dialog-todo-item-editor.ts @@ -324,14 +324,20 @@ class DialogTodoItemEditor extends LitElement { (this._todoListSupportsFeature( TodoListEntityFeature.SET_DESCRIPTION_ON_ITEM ) - ? // backend should accept null to clear the field, but it doesn't now - null + ? null : undefined), due: this._due ? this._hasTime ? this._due.toISOString() : this._formatDate(this._due) - : null, + : this._todoListSupportsFeature( + TodoListEntityFeature.SET_DUE_DATETIME_ON_ITEM + ) || + this._todoListSupportsFeature( + TodoListEntityFeature.SET_DUE_DATE_ON_ITEM + ) + ? null + : undefined, status: this._checked ? TodoItemStatus.Completed : TodoItemStatus.NeedsAction, From 288d173a4d2fcf4ec665e4fffee4015550dafa67 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 3 Jan 2024 15:02:14 +0100 Subject: [PATCH 22/32] Bumped version to 20240103.3 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f43e4cf0dc..b1f2ee8ea7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240103.0" +version = "20240103.3" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" From fef2c44cb8ffe4ff3b0827365da3ba068e193ad3 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 4 Jan 2024 17:43:37 +0100 Subject: [PATCH 23/32] Bumped version to 20240104.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b1f2ee8ea7..d9414825fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20240103.3" +version = "20240104.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" From 030566c1e849997c3ec39ec82c6b86ac9c2048fc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 17:45:46 -0500 Subject: [PATCH 24/32] Update dependency marked to v11.1.1 (#19254) --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 3f4e61c243..0d2a855179 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "leaflet-draw": "1.0.4", "lit": "2.8.0", "luxon": "3.4.4", - "marked": "11.1.0", + "marked": "11.1.1", "memoize-one": "6.0.0", "node-vibrant": "3.2.1-alpha.1", "proxy-polyfill": "0.3.2", diff --git a/yarn.lock b/yarn.lock index 510c103b2e..3997cc2fa3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9679,7 +9679,7 @@ __metadata: luxon: "npm:3.4.4" magic-string: "npm:0.30.5" map-stream: "npm:0.0.7" - marked: "npm:11.1.0" + marked: "npm:11.1.1" memoize-one: "npm:6.0.0" mocha: "npm:10.2.0" node-vibrant: "npm:3.2.1-alpha.1" @@ -11655,12 +11655,12 @@ __metadata: languageName: node linkType: hard -"marked@npm:11.1.0": - version: 11.1.0 - resolution: "marked@npm:11.1.0" +"marked@npm:11.1.1": + version: 11.1.1 + resolution: "marked@npm:11.1.1" bin: marked: bin/marked.js - checksum: 4636b16283c1963a715e97578d9fd91588b11949276e633a4de53dc408bcdab7b846d2b5c2cf3239f6d2dc8affe5294a0895954b5e3d9562d77301d8847a8915 + checksum: c2e15a330ac75cca2e12e25aae09985a78ad7e96a84418964dcdd3ee776764a38812dc0e94e9fcbacac43113d1650ca7946f9dc0bab800d72181e56a37e7631e languageName: node linkType: hard From 0b20725f5f42824d67168714f50632fd11e013bc Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Wed, 3 Jan 2024 11:36:59 -0800 Subject: [PATCH 25/32] Fix select view dialog (#19267) * Fix select view dialog * add import --- .../select-view/hui-dialog-select-view.ts | 21 ++++++++++++++----- src/translations/en.json | 4 +++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts b/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts index 6a9c8eb04f..5f3e073f3a 100644 --- a/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts +++ b/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts @@ -8,6 +8,7 @@ import { stopPropagation } from "../../../../common/dom/stop_propagation"; import { createCloseHeading } from "../../../../components/ha-dialog"; import "../../../../components/ha-icon"; import "../../../../components/ha-select"; +import "../../../../components/ha-alert"; import { fetchConfig, LovelaceConfig, @@ -104,8 +105,15 @@ export class HuiDialogSelectView extends LitElement { })} ` : ""} - ${this._config - ? this._config.views.length > 1 + ${!this._config || (this._config.views || []).length < 1 + ? html`${this.hass.localize( + this._config + ? "ui.panel.lovelace.editor.select_view.no_views" + : "ui.panel.lovelace.editor.select_view.no_config" + )}` + : this._config.views.length > 1 ? html` ${this._config.views.map( @@ -125,8 +133,7 @@ export class HuiDialogSelectView extends LitElement { )} ` - : "" - : html`
No config found.
`} + : ""} ${this.hass!.localize("ui.common.cancel")} - + ${this._params.actionLabel || this.hass!.localize("ui.common.move")} diff --git a/src/translations/en.json b/src/translations/en.json index 53306cd8b7..74467bcbf1 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -5020,7 +5020,9 @@ "select_view": { "header": "Choose a view", "dashboard_label": "Dashboard", - "views_label": "View" + "views_label": "View", + "no_config": "No config found.", + "no_views": "No views in this dashboard." }, "suggest_card": { "header": "We created a suggestion for you", From efddbfcfa0941eccce4565a30c12dd689c7d6624 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 4 Jan 2024 03:21:42 +0100 Subject: [PATCH 26/32] Fix circular progress size + fix bug in assist pipeline debug (#19268) --- src/auth/ha-auth-textfield.ts | 2 +- src/components/media-player/ha-media-upload-button.ts | 2 +- src/panels/config/repairs/dialog-system-information.ts | 2 +- .../voice-assistants/debug/assist-pipeline-run-debug.ts | 7 +++++-- .../voice-assistants/debug/assist-render-pipeline-run.ts | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/auth/ha-auth-textfield.ts b/src/auth/ha-auth-textfield.ts index 123deef03f..20d5e66174 100644 --- a/src/auth/ha-auth-textfield.ts +++ b/src/auth/ha-auth-textfield.ts @@ -47,7 +47,7 @@ export class HaAuthTextField extends HaTextField { // TODO: live() directive needs casting for lit-analyzer // https://github.com/runem/lit-analyzer/pull/91/files // TODO: lit-analyzer labels min/max as (number|string) instead of string - return html` 0 ? html` `; } else if (info.type === "failed") { diff --git a/src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts b/src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts index 67b902ba65..f7df3507fa 100644 --- a/src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts +++ b/src/panels/config/voice-assistants/debug/assist-pipeline-run-debug.ts @@ -247,7 +247,7 @@ export class AssistPipelineRunDebug extends LitElement { } // Play audio when we're done. - if (updatedRun.stage === "done") { + if (updatedRun.stage === "done" && !updatedRun.error) { const url = updatedRun.tts!.tts_output!.url; const audio = new Audio(url); audio.addEventListener("ended", () => { @@ -261,7 +261,10 @@ export class AssistPipelineRunDebug extends LitElement { } }); audio.play(); - } else if (updatedRun.stage === "error") { + } else if ( + (updatedRun.stage === "done" && updatedRun.error) || + updatedRun.stage === "error" + ) { this._finished = true; } }, diff --git a/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts b/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts index 05da128692..ae455152be 100644 --- a/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts +++ b/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts @@ -90,7 +90,7 @@ const renderProgress = ( return html`❌`; } return html` - + `; } From 32fd8270d77ce80be6944d40807bcf6a6dcf1a07 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 4 Jan 2024 03:27:30 +0100 Subject: [PATCH 27/32] Fix turning valve on/off (#19269) --- src/common/const.ts | 1 + src/panels/lovelace/common/entity/turn-on-off-entity.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/common/const.ts b/src/common/const.ts index 68f4fa97b1..bc114f2f17 100644 --- a/src/common/const.ts +++ b/src/common/const.ts @@ -272,6 +272,7 @@ export const DOMAINS_TOGGLE = new Set([ "group", "automation", "humidifier", + "valve", ]); /** Domains that have a dynamic entity image / picture. */ diff --git a/src/panels/lovelace/common/entity/turn-on-off-entity.ts b/src/panels/lovelace/common/entity/turn-on-off-entity.ts index 701c2c4996..5be6beaea8 100644 --- a/src/panels/lovelace/common/entity/turn-on-off-entity.ts +++ b/src/panels/lovelace/common/entity/turn-on-off-entity.ts @@ -24,6 +24,9 @@ export const turnOnOffEntity = ( case "scene": service = "turn_on"; break; + case "valve": + service = turnOn ? "open_valve" : "close_valve"; + break; default: service = turnOn ? "turn_on" : "turn_off"; } From 8d541595b80638dc9ff5f4762bb243a8d77cce87 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Thu, 4 Jan 2024 10:54:20 +0100 Subject: [PATCH 28/32] Update getStates to support valves (#19277) --- src/common/entity/get_states.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/entity/get_states.ts b/src/common/entity/get_states.ts index 29c11ca48c..456ce27bce 100644 --- a/src/common/entity/get_states.ts +++ b/src/common/entity/get_states.ts @@ -50,6 +50,7 @@ export const FIXED_DOMAIN_STATES = { timer: ["active", "idle", "paused"], update: ["on", "off"], vacuum: ["cleaning", "docked", "error", "idle", "paused", "returning"], + valve: ["closed", "closing", "open", "opening"], weather: [ "clear-night", "cloudy", From f147a5e909bc94e6bc1ed5364d9ac8791e2002a2 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 4 Jan 2024 11:52:38 +0100 Subject: [PATCH 29/32] fix valve entities row (#19278) --- src/common/const.ts | 1 + src/data/valve.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/common/const.ts b/src/common/const.ts index bc114f2f17..2e7d2f7c77 100644 --- a/src/common/const.ts +++ b/src/common/const.ts @@ -254,6 +254,7 @@ export const DOMAINS_INPUT_ROW = [ "text", "time", "vacuum", + "valve", ]; /** States that we consider "off". */ diff --git a/src/data/valve.ts b/src/data/valve.ts index 73f5d428ae..645ca82e49 100644 --- a/src/data/valve.ts +++ b/src/data/valve.ts @@ -14,14 +14,20 @@ export const enum ValveEntityFeature { } export function isFullyOpen(stateObj: ValveEntity) { - if (stateObj.attributes.current_position !== undefined) { + if ( + stateObj.attributes.current_position !== undefined && + stateObj.attributes.current_position !== null + ) { return stateObj.attributes.current_position === 100; } return stateObj.state === "open"; } export function isFullyClosed(stateObj: ValveEntity) { - if (stateObj.attributes.current_position !== undefined) { + if ( + stateObj.attributes.current_position !== undefined && + stateObj.attributes.current_position !== null + ) { return stateObj.attributes.current_position === 0; } return stateObj.state === "closed"; From a1cf18468b2bafade0bbb4f4e0552bdc1fd955b3 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 4 Jan 2024 13:20:35 +0100 Subject: [PATCH 30/32] Remove overflow hidden from profile (#19279) --- src/panels/profile/ha-panel-profile.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/panels/profile/ha-panel-profile.ts b/src/panels/profile/ha-panel-profile.ts index 1756af4d93..9e82e842df 100644 --- a/src/panels/profile/ha-panel-profile.ts +++ b/src/panels/profile/ha-panel-profile.ts @@ -250,7 +250,6 @@ class HaPanelProfile extends LitElement { max-width: 600px; margin: 0 auto; padding-bottom: env(safe-area-inset-bottom); - overflow: hidden; } .content > * { From a31b9f1b4d952353a3f61b5905fdf6ee1eeec8ef Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 4 Jan 2024 14:24:33 +0100 Subject: [PATCH 31/32] Fix due date when no time in certain timezones (#19280) * Fix due date when no time in certain timezones * Update dialog-todo-item-editor.ts --- src/panels/lovelace/cards/hui-todo-list-card.ts | 2 +- src/panels/todo/dialog-todo-item-editor.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/panels/lovelace/cards/hui-todo-list-card.ts b/src/panels/lovelace/cards/hui-todo-list-card.ts index d1d62880f8..1d1c6b6c82 100644 --- a/src/panels/lovelace/cards/hui-todo-list-card.ts +++ b/src/panels/lovelace/cards/hui-todo-list-card.ts @@ -335,7 +335,7 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard { const due = item.due ? item.due.includes("T") ? new Date(item.due) - : endOfDay(new Date(item.due)) + : endOfDay(new Date(`${item.due}T00:00:00`)) : undefined; const today = due && !item.due!.includes("T") && isSameDay(new Date(), due); diff --git a/src/panels/todo/dialog-todo-item-editor.ts b/src/panels/todo/dialog-todo-item-editor.ts index daa5eff686..be03e260ec 100644 --- a/src/panels/todo/dialog-todo-item-editor.ts +++ b/src/panels/todo/dialog-todo-item-editor.ts @@ -60,8 +60,10 @@ class DialogTodoItemEditor extends LitElement { this._checked = entry.status === TodoItemStatus.Completed; this._summary = entry.summary; this._description = entry.description || ""; - this._due = entry.due ? new Date(entry.due) : undefined; this._hasTime = entry.due?.includes("T") || false; + this._due = entry.due + ? new Date(this._hasTime ? entry.due : `${entry.due}T00:00:00`) + : undefined; } else { this._hasTime = false; this._checked = false; From 456c011f3edc0e31e3c49434dfaf37f3f715d485 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Thu, 4 Jan 2024 16:18:16 +0100 Subject: [PATCH 32/32] Fix thermostat and humidifier card rendering when off (#19281) * Fix thermostat and humidifier card rendering when off * Fix action color --- .../ha-state-control-climate-temperature.ts | 43 +++++++++++++------ .../ha-state-control-humidifier-humidity.ts | 37 ++++++++++++---- .../state-control-circular-slider-style.ts | 13 +++++- 3 files changed, 71 insertions(+), 22 deletions(-) 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 7634fd2f2d..0264af5ec7 100644 --- a/src/state-control/climate/ha-state-control-climate-temperature.ts +++ b/src/state-control/climate/ha-state-control-climate-temperature.ts @@ -177,11 +177,20 @@ export class HaStateControlClimateTemperature extends LitElement { const action = this.stateObj.attributes.hvac_action; + const isTemperatureDisplayed = + (this.stateObj.attributes.current_temperature != null && + this.showCurrentAsPrimary) || + ((this._supportsTargetTemperature || + this._supportsTargetTemperatureRange) && + !this.showCurrentAsPrimary); + return html`

- ${action + ${action && action !== "off" ? this.hass.formatEntityAttributeValue(this.stateObj, "hvac_action") - : this.hass.formatEntityState(this.stateObj)} + : isTemperatureDisplayed + ? this.hass.formatEntityState(this.stateObj) + : nothing}

`; } @@ -315,6 +324,14 @@ export class HaStateControlClimateTemperature extends LitElement { `; } + if (this.stateObj.state !== UNAVAILABLE) { + return html` +

+ ${this.hass.formatEntityState(this.stateObj)} +

+ `; + } + return nothing; } @@ -373,6 +390,14 @@ export class HaStateControlClimateTemperature extends LitElement { return html`

`; } + private _renderInfo() { + return html` +
+ ${this._renderLabel()}${this._renderPrimary()}${this._renderSecondary()} +
+ `; + } + get _supportsTargetTemperature() { return ( supportsFeature(this.stateObj, ClimateEntityFeature.TARGET_TEMPERATURE) && @@ -447,10 +472,7 @@ export class HaStateControlClimateTemperature extends LitElement { @value-changing=${this._valueChanging} > -
- ${this._renderLabel()}${this._renderPrimary()}${this._renderSecondary()} -
- ${this._renderTemperatureButtons("value")} + ${this._renderInfo()} ${this._renderTemperatureButtons("value")}
`; } @@ -484,9 +506,7 @@ export class HaStateControlClimateTemperature extends LitElement { @high-changing=${this._valueChanging} > -
- ${this._renderLabel()}${this._renderPrimary()}${this._renderSecondary()} -
+ ${this._renderInfo()} ${this._renderTemperatureButtons(this._selectTargetTemperature, true)}
`; @@ -497,6 +517,7 @@ export class HaStateControlClimateTemperature extends LitElement { class="container${containerSizeClass}" style=${styleMap({ "--state-color": stateColor, + "--action-color": actionColor, })} > -
- ${this._renderLabel()} ${this._renderSecondary()} -
+ ${this._renderInfo()}
`; } diff --git a/src/state-control/humidifier/ha-state-control-humidifier-humidity.ts b/src/state-control/humidifier/ha-state-control-humidifier-humidity.ts index 6078180cd8..459e8d6117 100644 --- a/src/state-control/humidifier/ha-state-control-humidifier-humidity.ts +++ b/src/state-control/humidifier/ha-state-control-humidifier-humidity.ts @@ -105,11 +105,18 @@ export class HaStateControlHumidifierHumidity extends LitElement { const action = this.stateObj.attributes.action; + const isHumidityDisplayed = + (this.stateObj.attributes.current_humidity != null && + this.showCurrentAsPrimary) || + (this._targetHumidity != null && !this.showCurrentAsPrimary); + return html`

- ${action + ${action && action !== "off" ? this.hass.formatEntityAttributeValue(this.stateObj, "action") - : this.hass.formatEntityState(this.stateObj)} + : isHumidityDisplayed + ? this.hass.formatEntityState(this.stateObj) + : nothing}

`; } @@ -144,6 +151,14 @@ export class HaStateControlHumidifierHumidity extends LitElement { return this._renderTarget(this._targetHumidity!, "big"); } + if (this.stateObj.state !== UNAVAILABLE) { + return html` +

+ ${this.hass.formatEntityState(this.stateObj)} +

+ `; + } + return nothing; } @@ -225,6 +240,14 @@ export class HaStateControlHumidifierHumidity extends LitElement { `; } + private _renderInfo() { + return html` +
+ ${this._renderLabel()}${this._renderPrimary()}${this._renderSecondary()} +
+ `; + } + protected render() { const stateColor = stateColorCss(this.stateObj); const active = stateActive(this.stateObj); @@ -272,10 +295,7 @@ export class HaStateControlHumidifierHumidity extends LitElement { @value-changing=${this._valueChanging} > -
- ${this._renderLabel()}${this._renderPrimary()}${this._renderSecondary()} -
- ${this._renderButtons()} + ${this._renderInfo()} ${this._renderButtons()}
`; } @@ -284,6 +304,7 @@ export class HaStateControlHumidifierHumidity extends LitElement {
@@ -296,9 +317,7 @@ export class HaStateControlHumidifierHumidity extends LitElement { disabled > -
- ${this._renderLabel()} ${this._renderSecondary()} -
+ ${this._renderInfo()}
`; } diff --git a/src/state-control/state-control-circular-slider-style.ts b/src/state-control/state-control-circular-slider-style.ts index cc1c9366d7..b5d4d5281a 100644 --- a/src/state-control/state-control-circular-slider-style.ts +++ b/src/state-control/state-control-circular-slider-style.ts @@ -54,7 +54,6 @@ export const stateControlCircularSliderStyle = css` .label.disabled { color: var(--secondary-text-color); } - .buttons { position: absolute; bottom: 10px; @@ -67,6 +66,9 @@ export const stateControlCircularSliderStyle = css` align-items: center; justify-content: center; } + .primary-state { + font-size: 36px; + } .buttons ha-outlined-icon-button { --md-outlined-icon-button-container-width: 48px; @@ -77,6 +79,9 @@ export const stateControlCircularSliderStyle = css` .container.md ha-big-number { font-size: 44px; } + .container.md .state { + font-size: 30px; + } .container.md .info { margin-top: 12px; gap: 6px; @@ -91,6 +96,9 @@ export const stateControlCircularSliderStyle = css` .container.sm ha-big-number { font-size: 32px; } + .container.sm .state { + font-size: 26px; + } .container.sm .info { margin-top: 12px; font-size: 14px; @@ -107,6 +115,9 @@ export const stateControlCircularSliderStyle = css` .container.xs ha-big-number { font-size: 32px; } + .container.xs .state { + font-size: 16px; + } .container.xs .info { margin-top: 12px; }