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/13] 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 1ba30198bd3e..4b07b84f0ed5 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 0039d9926f56..a3070c0787b1 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/13] 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 a3070c0787b1..c176cf65c96a 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/13] 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 44a0e218609c..d8c7af44fecc 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 b96283a61dd8..31760dca1bc1 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 27364b92a3ed..ecf4f8823770 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 71568fe02c10..4593a5f70123 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 c497ca85c620..55453505121d 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 8b3a63575220..1b94ff6138b2 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/13] 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 f1ae8ee54bac..119418355c64 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 f0b5e7151b51..08910dc88fcb 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 4b07b84f0ed5..3d7d8c5a1da4 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 f09c901c8e1a..0e58c0e8b2b5 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 dca4bab6acde..ce312a7bd399 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 c176cf65c96a..e771c8fe1910 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/13] 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 66c14e64e140..68f4fa97b1c1 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 31760dca1bc1..0e930b7c9916 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/13] 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 3d7d8c5a1da4..40c823bc862f 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 e771c8fe1910..6ef41c81c129 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/13] 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 14d88e12afc7..9e7213e41475 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/13] 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 6ef41c81c129..53306cd8b77d 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/13] 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 0e930b7c9916..d498e8375cd8 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/13] 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 7c06cac92cf1..e5925b1243e2 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 c81b9e4dbec3..cd26ad35fc28 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/13] Bumped version to 20240102.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d1e5abd3d1c4..7d09a1121ede 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/13] 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 d498e8375cd8..06a77884f1c6 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/13] 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 366eb4f5555c..5faf7a8b96b2 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;