diff --git a/src/data/lovelace.ts b/src/data/lovelace.ts index 090bb0dfc0fd..447b803decfe 100644 --- a/src/data/lovelace.ts +++ b/src/data/lovelace.ts @@ -2,6 +2,7 @@ import { Connection, getCollection, HassEventBase, + HassServiceTarget, } from "home-assistant-js-websocket"; import { HASSDomEvent } from "../common/dom/fire_event"; import { HuiErrorCard } from "../panels/lovelace/cards/hui-error-card"; @@ -120,8 +121,8 @@ export interface ToggleActionConfig extends BaseActionConfig { export interface CallServiceActionConfig extends BaseActionConfig { action: "call-service"; service: string; + target?: HassServiceTarget; service_data?: { - entity_id?: string | [string]; [key: string]: any; }; } diff --git a/src/panels/lovelace/common/handle-action.ts b/src/panels/lovelace/common/handle-action.ts index ad95273e5d73..a4339e2fe4b5 100644 --- a/src/panels/lovelace/common/handle-action.ts +++ b/src/panels/lovelace/common/handle-action.ts @@ -130,7 +130,12 @@ export const handleAction = async ( return; } const [domain, service] = actionConfig.service.split(".", 2); - hass.callService(domain, service, actionConfig.service_data); + hass.callService( + domain, + service, + actionConfig.service_data, + actionConfig.target + ); forwardHaptic("light"); break; } diff --git a/src/panels/lovelace/components/hui-action-editor.ts b/src/panels/lovelace/components/hui-action-editor.ts index 7946138d6e19..831c49373573 100644 --- a/src/panels/lovelace/components/hui-action-editor.ts +++ b/src/panels/lovelace/components/hui-action-editor.ts @@ -15,15 +15,17 @@ import { } from "lit-element"; import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/ha-help-tooltip"; -import "../../../components/ha-service-picker"; import { ActionConfig, CallServiceActionConfig, NavigateActionConfig, UrlActionConfig, } from "../../../data/lovelace"; +import { ServiceAction } from "../../../data/script"; import { HomeAssistant } from "../../../types"; import { EditorTarget } from "../editor/types"; +import "../../../components/ha-service-control"; +import memoizeOne from "memoize-one"; @customElement("hui-action-editor") export class HuiActionEditor extends LitElement { @@ -47,10 +49,15 @@ export class HuiActionEditor extends LitElement { return config.url_path || ""; } - get _service(): string { - const config = this.config as CallServiceActionConfig; - return config.service || ""; - } + private _serviceAction = memoizeOne( + (config: CallServiceActionConfig): ServiceAction => { + return { + service: config.service || "", + data: config.service_data, + target: config.target, + }; + } + ); protected render(): TemplateResult { if (!this.hass || !this.actions) { @@ -117,17 +124,13 @@ export class HuiActionEditor extends LitElement { : ""} ${this.config?.action === "call-service" ? html` - - - ${this.hass!.localize( - "ui.panel.lovelace.editor.action-editor.editor_service_data" - )} - + .value=${this._serviceAction(this.config)} + .showAdvanced=${this.hass.userData?.showAdvanced} + narrow + @value-changed=${this._serviceValueChanged} + > ` : ""} `; @@ -174,6 +177,18 @@ export class HuiActionEditor extends LitElement { } } + private _serviceValueChanged(ev: CustomEvent) { + ev.stopPropagation(); + fireEvent(this, "value-changed", { + value: { + ...this.config!, + service: ev.detail.value.service || "", + service_data: ev.detail.value.data || {}, + target: ev.detail.value.target || {}, + }, + }); + } + static get styles(): CSSResult { return css` .dropdown { diff --git a/src/panels/lovelace/editor/types.ts b/src/panels/lovelace/editor/types.ts index 2cd040cf370b..c37c3e084d25 100644 --- a/src/panels/lovelace/editor/types.ts +++ b/src/panels/lovelace/editor/types.ts @@ -120,20 +120,27 @@ const actionConfigStructConfirmation = union([ const actionConfigStructUrl = object({ action: literal("url"), - url_path: string(), + url_path: optional(string()), confirmation: optional(actionConfigStructConfirmation), }); const actionConfigStructService = object({ action: literal("call-service"), - service: string(), + service: optional(string()), service_data: optional(object()), + target: optional( + object({ + entity_id: optional(union([string(), array(string())])), + device_id: optional(union([string(), array(string())])), + area_id: optional(union([string(), array(string())])), + }) + ), confirmation: optional(actionConfigStructConfirmation), }); const actionConfigStructNavigate = object({ action: literal("navigate"), - navigation_path: string(), + navigation_path: optional(string()), confirmation: optional(actionConfigStructConfirmation), });