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

Migrate service call element
pull/21511/head
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 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}
></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 {
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>) =>
@ -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 {

View File

@ -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}</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 {
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<string, unknown>;
data?: Record<string, unknown>;
}

View File

@ -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"