Migrate service call element to use action key (#21506)

Migrate service call element
This commit is contained in:
Bram Kragten 2024-07-31 14:54:01 +02:00 committed by GitHub
parent 78becb5440
commit 560e2c9438
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 74 additions and 23 deletions

View File

@ -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 { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { any, assert, literal, object, optional, string } from "superstruct"; import { any, assert, literal, object, optional, string } from "superstruct";
import { fireEvent } from "../../../../../common/dom/fire_event"; 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 "../../../../../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 { ServiceButtonElementConfig } from "../../../elements/types";
// import { UiAction } from "../../components/hui-action-editor"; import { LovelacePictureElementEditor } from "../../../types";
const serviceButtonElementConfigStruct = object({ const serviceButtonElementConfigStruct = object({
type: literal("service-button"), type: literal("service-button"),
style: optional(any()), style: optional(any()),
title: optional(string()), title: optional(string()),
action: optional(string()),
service: optional(string()), service: optional(string()),
service_data: optional(any()), service_data: optional(any()),
data: optional(any()),
target: optional(any()),
}); });
const SCHEMA = [ const SCHEMA = [
{ name: "title", required: true, selector: { text: {} } }, { 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: {} } }, { name: "style", selector: { object: {} } },
] as const; ] as const;
@ -44,6 +41,14 @@ export class HuiServiceButtonElementEditor
this._config = config; 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() { protected render() {
if (!this.hass || !this._config) { if (!this.hass || !this._config) {
return nothing; return nothing;
@ -57,11 +62,41 @@ export class HuiServiceButtonElementEditor
.computeLabel=${this._computeLabelCallback} .computeLabel=${this._computeLabelCallback}
@value-changed=${this._valueChanged} @value-changed=${this._valueChanged}
></ha-form> ></ha-form>
<ha-service-control
.hass=${this.hass}
.value=${this._serviceData(this._config)}
.showAdvanced=${this.hass.userData?.showAdvanced}
narrow
@value-changed=${this._serviceDataChanged}
></ha-service-control>
`; `;
} }
private _valueChanged(ev: CustomEvent): void { 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<typeof SCHEMA>) => private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) =>
@ -70,6 +105,16 @@ export class HuiServiceButtonElementEditor
) || ) ||
this.hass!.localize(`ui.panel.lovelace.editor.elements.${schema.name}`) || this.hass!.localize(`ui.panel.lovelace.editor.elements.${schema.name}`) ||
schema.name; schema.name;
static get styles() {
return css`
ha-service-control {
display: block;
margin-top: 16px;
--service-control-padding: 0;
}
`;
}
} }
declare global { declare global {

View File

@ -26,18 +26,21 @@ export class HuiServiceButtonElement
private _service?: string; private _service?: string;
public setConfig(config: ServiceButtonElementConfig): void { public setConfig(config: ServiceButtonElementConfig): void {
if (!config || !config.service) { if (!config || (!config.action && !config.service)) {
throw Error("Service required"); 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) { if (!this._domain) {
throw Error("Service does not have a service domain"); throw Error("Action does not have a domain");
} }
if (!this._service) { if (!this._service) {
throw Error("Service does not have a service name"); throw Error("Action does not have a action name");
} }
this._config = config; this._config = config;
@ -49,7 +52,7 @@ export class HuiServiceButtonElement
} }
const { entity_id, label_id, floor_id, device_id, area_id } = 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 ?? { const updatedTarget = this._config.target ?? {
entity_id, entity_id,
label_id, label_id,
@ -65,8 +68,9 @@ export class HuiServiceButtonElement
.service=${this._service} .service=${this._service}
.data=${this._config.data ?? this._config.service_data} .data=${this._config.data ?? this._config.service_data}
.target=${updatedTarget} .target=${updatedTarget}
>${this._config.title}</ha-call-service-button
> >
${this._config.title}
</ha-call-service-button>
`; `;
} }

View File

@ -59,9 +59,11 @@ export interface ImageElementConfig extends LovelaceElementConfigBase {
export interface ServiceButtonElementConfig extends LovelaceElementConfigBase { export interface ServiceButtonElementConfig extends LovelaceElementConfigBase {
title?: string; title?: string;
/* @deprecated "service" is kept for backwards compatibility. Replaced by "action". */
service?: string; service?: string;
action?: string;
target?: HassServiceTarget; 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<string, unknown>; service_data?: Record<string, unknown>;
data?: Record<string, unknown>; data?: Record<string, unknown>;
} }

View File

@ -5996,7 +5996,7 @@
"state-badge": "State badge", "state-badge": "State badge",
"state-icon": "State icon", "state-icon": "State icon",
"state-label": "State label", "state-label": "State label",
"service-button": "Service call button", "service-button": "Perform action button",
"icon": "Icon", "icon": "Icon",
"image": "Image", "image": "Image",
"conditional": "Conditional" "conditional": "Conditional"