From 560e2c9438fea391241bfc3caf74b4d335e40f82 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 31 Jul 2024 14:54:01 +0200 Subject: [PATCH] Migrate service call element to use action key (#21506) Migrate service call element --- .../hui-service-button-element-editor.ts | 73 +++++++++++++++---- .../elements/hui-service-button-element.ts | 18 +++-- src/panels/lovelace/elements/types.ts | 4 +- src/translations/en.json | 2 +- 4 files changed, 74 insertions(+), 23 deletions(-) diff --git a/src/panels/lovelace/editor/config-elements/elements/hui-service-button-element-editor.ts b/src/panels/lovelace/editor/config-elements/elements/hui-service-button-element-editor.ts index 7f6afd193e..30110619fe 100644 --- a/src/panels/lovelace/editor/config-elements/elements/hui-service-button-element-editor.ts +++ b/src/panels/lovelace/editor/config-elements/elements/hui-service-button-element-editor.ts @@ -1,32 +1,29 @@ -import { html, LitElement, nothing } from "lit"; +import { css, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { any, assert, literal, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../../common/dom/fire_event"; -import type { SchemaUnion } from "../../../../../components/ha-form/types"; -import type { HomeAssistant } from "../../../../../types"; import "../../../../../components/ha-form/ha-form"; -import { LovelacePictureElementEditor } from "../../../types"; +import type { SchemaUnion } from "../../../../../components/ha-form/types"; +import "../../../../../components/ha-service-control"; +import { ServiceAction } from "../../../../../data/script"; +import type { HomeAssistant } from "../../../../../types"; import { ServiceButtonElementConfig } from "../../../elements/types"; -// import { UiAction } from "../../components/hui-action-editor"; +import { LovelacePictureElementEditor } from "../../../types"; const serviceButtonElementConfigStruct = object({ type: literal("service-button"), style: optional(any()), title: optional(string()), + action: optional(string()), service: optional(string()), service_data: optional(any()), + data: optional(any()), + target: optional(any()), }); const SCHEMA = [ { name: "title", required: true, selector: { text: {} } }, - /* { - name: "service", - selector: { - ui_action: { actions: ["call-service"] as UiAction[] }, - }, - }, */ - { name: "service", required: true, selector: { text: {} } }, - { name: "service_data", selector: { object: {} } }, { name: "style", selector: { object: {} } }, ] as const; @@ -44,6 +41,14 @@ export class HuiServiceButtonElementEditor this._config = config; } + private _serviceData = memoizeOne( + (config: ServiceButtonElementConfig): ServiceAction => ({ + action: config?.action ?? config?.service, + data: config?.data ?? config?.service_data, + target: config?.target, + }) + ); + protected render() { if (!this.hass || !this._config) { return nothing; @@ -57,11 +62,41 @@ export class HuiServiceButtonElementEditor .computeLabel=${this._computeLabelCallback} @value-changed=${this._valueChanged} > + `; } private _valueChanged(ev: CustomEvent): void { - fireEvent(this, "config-changed", { config: ev.detail.value }); + fireEvent(this, "config-changed", { + config: { ...this._config, ...ev.detail.value }, + }); + } + + private _serviceDataChanged(ev: CustomEvent<{ value: ServiceAction }>): void { + const config: ServiceButtonElementConfig = { + ...this._config!, + action: ev.detail.value.action, + data: ev.detail.value.data, + target: ev.detail.value.target, + }; + + if ("service" in config) { + delete config.service; + } + + if ("service_data" in config) { + delete config.service_data; + } + + fireEvent(this, "config-changed", { + config, + }); } private _computeLabelCallback = (schema: SchemaUnion) => @@ -70,6 +105,16 @@ export class HuiServiceButtonElementEditor ) || this.hass!.localize(`ui.panel.lovelace.editor.elements.${schema.name}`) || schema.name; + + static get styles() { + return css` + ha-service-control { + display: block; + margin-top: 16px; + --service-control-padding: 0; + } + `; + } } declare global { diff --git a/src/panels/lovelace/elements/hui-service-button-element.ts b/src/panels/lovelace/elements/hui-service-button-element.ts index 6c7d3508e1..73bed5d415 100644 --- a/src/panels/lovelace/elements/hui-service-button-element.ts +++ b/src/panels/lovelace/elements/hui-service-button-element.ts @@ -26,18 +26,21 @@ export class HuiServiceButtonElement private _service?: string; public setConfig(config: ServiceButtonElementConfig): void { - if (!config || !config.service) { - throw Error("Service required"); + if (!config || (!config.action && !config.service)) { + throw Error("Action required"); } - [this._domain, this._service] = config.service.split(".", 2); + [this._domain, this._service] = (config.action ?? config.service)!.split( + ".", + 2 + ); if (!this._domain) { - throw Error("Service does not have a service domain"); + throw Error("Action does not have a domain"); } if (!this._service) { - throw Error("Service does not have a service name"); + throw Error("Action does not have a action name"); } this._config = config; @@ -49,7 +52,7 @@ export class HuiServiceButtonElement } const { entity_id, label_id, floor_id, device_id, area_id } = - this._config.service_data ?? {}; + this._config.service_data ?? this._config.data ?? {}; const updatedTarget = this._config.target ?? { entity_id, label_id, @@ -65,8 +68,9 @@ export class HuiServiceButtonElement .service=${this._service} .data=${this._config.data ?? this._config.service_data} .target=${updatedTarget} - >${this._config.title} + ${this._config.title} + `; } diff --git a/src/panels/lovelace/elements/types.ts b/src/panels/lovelace/elements/types.ts index 1b433b5bd9..fcd9a44865 100644 --- a/src/panels/lovelace/elements/types.ts +++ b/src/panels/lovelace/elements/types.ts @@ -59,9 +59,11 @@ export interface ImageElementConfig extends LovelaceElementConfigBase { export interface ServiceButtonElementConfig extends LovelaceElementConfigBase { title?: string; + /* @deprecated "service" is kept for backwards compatibility. Replaced by "action". */ service?: string; + action?: string; target?: HassServiceTarget; - // "service_data" is kept for backwards compatibility. Replaced by "data". + /* @deprecated "service_data" is kept for backwards compatibility. Replaced by "data". */ service_data?: Record; data?: Record; } diff --git a/src/translations/en.json b/src/translations/en.json index d706a8d066..804fad507d 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -5996,7 +5996,7 @@ "state-badge": "State badge", "state-icon": "State icon", "state-label": "State label", - "service-button": "Service call button", + "service-button": "Perform action button", "icon": "Icon", "image": "Image", "conditional": "Conditional"