Support more templates in action visual editor (#25015)

* Support more templates in action visual editor

* Make selector sticky

* typing
This commit is contained in:
karwosts 2025-04-12 05:03:44 -07:00 committed by GitHub
parent fbeb457c25
commit 6d7a40368c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 35 additions and 56 deletions

View File

@ -38,6 +38,7 @@ import "./ha-settings-row";
import "./ha-yaml-editor";
import type { HaYamlEditor } from "./ha-yaml-editor";
import "./ha-service-section-icon";
import { hasTemplate } from "../common/string/has-template";
const attributeFilter = (values: any[], attribute: any) => {
if (typeof attribute === "object") {
@ -101,6 +102,8 @@ export class HaServiceControl extends LitElement {
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
private _stickySelector: Record<string, Selector> = {};
protected willUpdate(changedProperties: PropertyValues<this>) {
if (!this.hasUpdated) {
this.hass.loadBackendTranslation("services");
@ -590,7 +593,23 @@ export class HaServiceControl extends LitElement {
return nothing;
}
const selector = dataField?.selector ?? { text: undefined };
const fieldDataHasTemplate =
this._value?.data && hasTemplate(this._value.data[dataField.key]);
const selector =
fieldDataHasTemplate &&
typeof this._value!.data![dataField.key] === "string"
? { template: null }
: fieldDataHasTemplate &&
typeof this._value!.data![dataField.key] === "object"
? { object: null }
: (this._stickySelector[dataField.key] ??
dataField?.selector ?? { text: null });
if (fieldDataHasTemplate) {
// Hold this selector type until the field is cleared
this._stickySelector[dataField.key] = selector;
}
const showOptional = showOptionalToggle(dataField);
@ -693,6 +712,7 @@ export class HaServiceControl extends LitElement {
this._checkedKeys.delete(key);
data = { ...this._value?.data };
delete data[key];
delete this._stickySelector[key];
}
if (data) {
fireEvent(this, "value-changed", {
@ -816,6 +836,10 @@ export class HaServiceControl extends LitElement {
private _serviceDataChanged(ev: CustomEvent) {
ev.stopPropagation();
if (ev.detail.isValid === false) {
// Don't clear an object selector that returns invalid YAML
return;
}
const key = (ev.currentTarget as any).key;
const value = ev.detail.value;
if (
@ -828,8 +852,13 @@ export class HaServiceControl extends LitElement {
const data = { ...this._value?.data, [key]: value };
if (value === "" || value === undefined) {
if (
value === "" ||
value === undefined ||
(typeof value === "object" && !Object.keys(value).length)
) {
delete data[key];
delete this._stickySelector[key];
}
fireEvent(this, "value-changed", {

View File

@ -1,11 +1,8 @@
import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { assert } from "superstruct";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { computeDomain } from "../../../../../common/entity/compute_domain";
import { computeObjectId } from "../../../../../common/entity/compute_object_id";
import { hasTemplate } from "../../../../../common/string/has-template";
import "../../../../../components/ha-service-control";
import type { ServiceAction } from "../../../../../data/script";
@ -27,26 +24,6 @@ export class HaServiceAction extends LitElement implements ActionElement {
@state() private _responseChecked = false;
private _fields = memoizeOne(
(
serviceDomains: HomeAssistant["services"],
domainService: string | undefined
): { fields: any } => {
if (!domainService) {
return { fields: {} };
}
const domain = computeDomain(domainService);
const service = computeObjectId(domainService);
if (!(domain in serviceDomains)) {
return { fields: {} };
}
if (!(service in serviceDomains[domain])) {
return { fields: {} };
}
return { fields: serviceDomains[domain][service].fields };
}
);
public static get defaultConfig(): ServiceAction {
return { action: "", data: {} };
}
@ -62,23 +39,11 @@ export class HaServiceAction extends LitElement implements ActionElement {
return;
}
const fields = this._fields(this.hass.services, this.action?.action).fields;
if (
this.action &&
(Object.entries(this.action).some(
Object.entries(this.action).some(
([key, val]) => key !== "data" && hasTemplate(val)
) ||
(this.action.data &&
Object.entries(this.action.data).some(([key, val]) => {
const field = fields[key];
if (
field?.selector &&
("template" in field.selector || "object" in field.selector)
) {
return false;
}
return hasTemplate(val);
})))
)
) {
fireEvent(
this,

View File

@ -528,26 +528,11 @@ class HaPanelDevAction extends LitElement {
}
private _checkUiSupported() {
const fields = this._fields(
this.hass.services,
this._serviceData?.action
).fields;
if (
this._serviceData &&
(Object.entries(this._serviceData).some(
Object.entries(this._serviceData).some(
([key, val]) => key !== "data" && hasTemplate(val)
) ||
(this._serviceData.data &&
Object.entries(this._serviceData.data).some(([key, val]) => {
const field = fields.find((f) => f.key === key);
if (
field?.selector &&
("template" in field.selector || "object" in field.selector)
) {
return false;
}
return hasTemplate(val);
})))
)
) {
this._yamlMode = true;
this._uiAvailable = false;