mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 03:06:41 +00:00
Support templates in action target (#25656)
This commit is contained in:
parent
174d54396f
commit
2dfe5f50a6
@ -276,6 +276,16 @@ export class HaServiceControl extends LitElement {
|
||||
|
||||
private _getTargetedEntities = memoizeOne((target, value) => {
|
||||
const targetSelector = target ? { target } : { target: {} };
|
||||
if (
|
||||
hasTemplate(value?.target) ||
|
||||
hasTemplate(value?.data?.entity_id) ||
|
||||
hasTemplate(value?.data?.device_id) ||
|
||||
hasTemplate(value?.data?.area_id) ||
|
||||
hasTemplate(value?.data?.floor_id) ||
|
||||
hasTemplate(value?.data?.label_id)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const targetEntities =
|
||||
ensureArray(
|
||||
value?.target?.entity_id || value?.data?.entity_id
|
||||
@ -349,8 +359,11 @@ export class HaServiceControl extends LitElement {
|
||||
|
||||
private _filterField(
|
||||
filter: ExtHassService["fields"][number]["filter"],
|
||||
targetEntities: string[]
|
||||
targetEntities: string[] | null
|
||||
) {
|
||||
if (targetEntities === null) {
|
||||
return true; // Target is a template, show all fields
|
||||
}
|
||||
if (!targetEntities.length) {
|
||||
return false;
|
||||
}
|
||||
@ -386,8 +399,21 @@ export class HaServiceControl extends LitElement {
|
||||
}
|
||||
|
||||
private _targetSelector = memoizeOne(
|
||||
(targetSelector: TargetSelector | null | undefined) =>
|
||||
targetSelector ? { target: { ...targetSelector } } : { target: {} }
|
||||
(targetSelector: TargetSelector | null | undefined, value) => {
|
||||
if (!value || (typeof value === "object" && !Object.keys(value).length)) {
|
||||
delete this._stickySelector.target;
|
||||
} else if (hasTemplate(value)) {
|
||||
if (typeof value === "string") {
|
||||
this._stickySelector.target = { template: null };
|
||||
} else {
|
||||
this._stickySelector.target = { object: null };
|
||||
}
|
||||
}
|
||||
return (
|
||||
this._stickySelector.target ??
|
||||
(targetSelector ? { target: { ...targetSelector } } : { target: {} })
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
protected render() {
|
||||
@ -482,7 +508,8 @@ export class HaServiceControl extends LitElement {
|
||||
><ha-selector
|
||||
.hass=${this.hass}
|
||||
.selector=${this._targetSelector(
|
||||
serviceData.target as TargetSelector
|
||||
serviceData.target as TargetSelector,
|
||||
this._value?.target
|
||||
)}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._targetChanged}
|
||||
@ -575,7 +602,7 @@ export class HaServiceControl extends LitElement {
|
||||
|
||||
private _hasFilteredFields(
|
||||
dataFields: ExtHassService["fields"],
|
||||
targetEntities: string[]
|
||||
targetEntities: string[] | null
|
||||
) {
|
||||
return dataFields.some(
|
||||
(dataField) =>
|
||||
@ -588,7 +615,7 @@ export class HaServiceControl extends LitElement {
|
||||
hasOptional: boolean,
|
||||
domain: string | undefined,
|
||||
serviceName: string | undefined,
|
||||
targetEntities: string[]
|
||||
targetEntities: string[] | null
|
||||
) => {
|
||||
if (
|
||||
dataField.filter &&
|
||||
@ -822,6 +849,10 @@ export class HaServiceControl extends LitElement {
|
||||
|
||||
private _targetChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
if (ev.detail.isValid === false) {
|
||||
// Don't clear an object selector that returns invalid YAML
|
||||
return;
|
||||
}
|
||||
const newValue = ev.detail.value;
|
||||
if (this._value?.target === newValue) {
|
||||
return;
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
literal,
|
||||
is,
|
||||
boolean,
|
||||
refine,
|
||||
} from "superstruct";
|
||||
import { arrayLiteralIncludes } from "../common/array/literal-includes";
|
||||
import { navigate } from "../common/navigate";
|
||||
@ -49,13 +50,18 @@ export const targetStruct = object({
|
||||
label_id: optional(union([string(), array(string())])),
|
||||
});
|
||||
|
||||
export const serviceActionStruct: Describe<ServiceAction> = assign(
|
||||
export const serviceActionStruct: Describe<ServiceActionWithTemplate> = assign(
|
||||
baseActionStruct,
|
||||
object({
|
||||
action: optional(string()),
|
||||
service_template: optional(string()),
|
||||
entity_id: optional(string()),
|
||||
target: optional(targetStruct),
|
||||
target: optional(
|
||||
union([
|
||||
targetStruct,
|
||||
refine(string(), "has_template", (val) => hasTemplate(val)),
|
||||
])
|
||||
),
|
||||
data: optional(object()),
|
||||
response_variable: optional(string()),
|
||||
metadata: optional(object()),
|
||||
@ -132,6 +138,12 @@ export interface ServiceAction extends BaseAction {
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
type ServiceActionWithTemplate = ServiceAction & {
|
||||
target?: HassServiceTarget | string;
|
||||
};
|
||||
|
||||
export type { ServiceActionWithTemplate };
|
||||
|
||||
export interface DeviceAction extends BaseAction {
|
||||
type: string;
|
||||
device_id: string;
|
||||
|
@ -42,7 +42,7 @@ export class HaServiceAction extends LitElement implements ActionElement {
|
||||
if (
|
||||
this.action &&
|
||||
Object.entries(this.action).some(
|
||||
([key, val]) => key !== "data" && hasTemplate(val)
|
||||
([key, val]) => !["data", "target"].includes(key) && hasTemplate(val)
|
||||
)
|
||||
) {
|
||||
fireEvent(
|
||||
|
@ -535,7 +535,7 @@ class HaPanelDevAction extends LitElement {
|
||||
if (
|
||||
this._serviceData &&
|
||||
Object.entries(this._serviceData).some(
|
||||
([key, val]) => key !== "data" && hasTemplate(val)
|
||||
([key, val]) => !["data", "target"].includes(key) && hasTemplate(val)
|
||||
)
|
||||
) {
|
||||
this._yamlMode = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user