mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Allow and migrate action key in service action (#21503)
This commit is contained in:
parent
da2e530601
commit
78becb5440
@ -77,7 +77,7 @@ export class HaServiceControl extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public value?: {
|
||||
service: string;
|
||||
action: string;
|
||||
target?: HassServiceTarget;
|
||||
data?: Record<string, any>;
|
||||
};
|
||||
@ -112,23 +112,23 @@ export class HaServiceControl extends LitElement {
|
||||
| undefined
|
||||
| this["value"];
|
||||
|
||||
if (oldValue?.service !== this.value?.service) {
|
||||
if (oldValue?.action !== this.value?.action) {
|
||||
this._checkedKeys = new Set();
|
||||
}
|
||||
|
||||
const serviceData = this._getServiceInfo(
|
||||
this.value?.service,
|
||||
this.value?.action,
|
||||
this.hass.services
|
||||
);
|
||||
|
||||
// Fetch the manifest if we have a service selected and the service domain changed.
|
||||
// If no service is selected, clear the manifest.
|
||||
if (this.value?.service) {
|
||||
if (this.value?.action) {
|
||||
if (
|
||||
!oldValue?.service ||
|
||||
computeDomain(this.value.service) !== computeDomain(oldValue.service)
|
||||
!oldValue?.action ||
|
||||
computeDomain(this.value.action) !== computeDomain(oldValue.action)
|
||||
) {
|
||||
this._fetchManifest(computeDomain(this.value?.service));
|
||||
this._fetchManifest(computeDomain(this.value?.action));
|
||||
}
|
||||
} else {
|
||||
this._manifest = undefined;
|
||||
@ -168,7 +168,7 @@ export class HaServiceControl extends LitElement {
|
||||
this._value = this.value;
|
||||
}
|
||||
|
||||
if (oldValue?.service !== this.value?.service) {
|
||||
if (oldValue?.action !== this.value?.action) {
|
||||
let updatedDefaultValue = false;
|
||||
if (this._value && serviceData) {
|
||||
const loadDefaults = this.value && !("data" in this.value);
|
||||
@ -367,7 +367,7 @@ export class HaServiceControl extends LitElement {
|
||||
|
||||
protected render() {
|
||||
const serviceData = this._getServiceInfo(
|
||||
this._value?.service,
|
||||
this._value?.action,
|
||||
this.hass.services
|
||||
);
|
||||
|
||||
@ -392,11 +392,11 @@ export class HaServiceControl extends LitElement {
|
||||
this._value
|
||||
);
|
||||
|
||||
const domain = this._value?.service
|
||||
? computeDomain(this._value.service)
|
||||
const domain = this._value?.action
|
||||
? computeDomain(this._value.action)
|
||||
: undefined;
|
||||
const serviceName = this._value?.service
|
||||
? computeObjectId(this._value.service)
|
||||
const serviceName = this._value?.action
|
||||
? computeObjectId(this._value.action)
|
||||
: undefined;
|
||||
|
||||
const description =
|
||||
@ -410,7 +410,7 @@ export class HaServiceControl extends LitElement {
|
||||
? nothing
|
||||
: html`<ha-service-picker
|
||||
.hass=${this.hass}
|
||||
.value=${this._value?.service}
|
||||
.value=${this._value?.action}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._serviceChanged}
|
||||
></ha-service-picker>`}
|
||||
@ -596,11 +596,11 @@ export class HaServiceControl extends LitElement {
|
||||
};
|
||||
|
||||
private _localizeValueCallback = (key: string) => {
|
||||
if (!this._value?.service) {
|
||||
if (!this._value?.action) {
|
||||
return "";
|
||||
}
|
||||
return this.hass.localize(
|
||||
`component.${computeDomain(this._value.service)}.selector.${key}`
|
||||
`component.${computeDomain(this._value.action)}.selector.${key}`
|
||||
);
|
||||
};
|
||||
|
||||
@ -612,7 +612,7 @@ export class HaServiceControl extends LitElement {
|
||||
if (checked) {
|
||||
this._checkedKeys.add(key);
|
||||
const field = this._getServiceInfo(
|
||||
this._value?.service,
|
||||
this._value?.action,
|
||||
this.hass.services
|
||||
)?.fields.find((_field) => _field.key === key);
|
||||
|
||||
@ -658,7 +658,7 @@ export class HaServiceControl extends LitElement {
|
||||
|
||||
private _serviceChanged(ev: ValueChangedEvent<string>) {
|
||||
ev.stopPropagation();
|
||||
if (ev.detail.value === this._value?.service) {
|
||||
if (ev.detail.value === this._value?.action) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -424,7 +424,7 @@ export class HatScriptGraph extends LitElement {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${node.service ? undefined : mdiRoomService}
|
||||
.iconPath=${node.action ? undefined : mdiRoomService}
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
@ -432,11 +432,11 @@ export class HatScriptGraph extends LitElement {
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
>
|
||||
${node.service
|
||||
${node.action
|
||||
? html`<ha-service-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.service=${node.service}
|
||||
.service=${node.action}
|
||||
></ha-service-icon>`
|
||||
: nothing}
|
||||
</hat-graph-node>
|
||||
|
@ -6,7 +6,7 @@ import { navigate } from "../common/navigate";
|
||||
import { Context, HomeAssistant } from "../types";
|
||||
import { BlueprintInput } from "./blueprint";
|
||||
import { DeviceCondition, DeviceTrigger } from "./device_automation";
|
||||
import { Action, MODES } from "./script";
|
||||
import { Action, MODES, migrateAutomationAction } from "./script";
|
||||
|
||||
export const AUTOMATION_DEFAULT_MODE: (typeof MODES)[number] = "single";
|
||||
export const AUTOMATION_DEFAULT_MAX = 10;
|
||||
@ -28,7 +28,7 @@ export interface ManualAutomationConfig {
|
||||
description?: string;
|
||||
trigger: Trigger | Trigger[];
|
||||
condition?: Condition | Condition[];
|
||||
action: Action | Action[];
|
||||
action?: Action | Action[];
|
||||
mode?: (typeof MODES)[number];
|
||||
max?: number;
|
||||
max_exceeded?:
|
||||
@ -357,7 +357,7 @@ export const normalizeAutomationConfig = <
|
||||
>(
|
||||
config: T
|
||||
): T => {
|
||||
// Normalize data: ensure trigger, action and condition are lists
|
||||
// Normalize data: ensure triggers, actions and conditions are lists
|
||||
// Happens when people copy paste their automations into the config
|
||||
for (const key of ["trigger", "condition", "action"]) {
|
||||
const value = config[key];
|
||||
@ -365,6 +365,9 @@ export const normalizeAutomationConfig = <
|
||||
config[key] = [value];
|
||||
}
|
||||
}
|
||||
|
||||
config.action = migrateAutomationAction(config.action || []);
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
|
@ -49,7 +49,7 @@ const targetStruct = object({
|
||||
export const serviceActionStruct: Describe<ServiceAction> = assign(
|
||||
baseActionStruct,
|
||||
object({
|
||||
service: optional(string()),
|
||||
action: optional(string()),
|
||||
service_template: optional(string()),
|
||||
entity_id: optional(string()),
|
||||
target: optional(targetStruct),
|
||||
@ -62,7 +62,7 @@ export const serviceActionStruct: Describe<ServiceAction> = assign(
|
||||
const playMediaActionStruct: Describe<PlayMediaAction> = assign(
|
||||
baseActionStruct,
|
||||
object({
|
||||
service: literal("media_player.play_media"),
|
||||
action: literal("media_player.play_media"),
|
||||
target: optional(object({ entity_id: optional(string()) })),
|
||||
entity_id: optional(string()),
|
||||
data: object({ media_content_id: string(), media_content_type: string() }),
|
||||
@ -73,7 +73,7 @@ const playMediaActionStruct: Describe<PlayMediaAction> = assign(
|
||||
const activateSceneActionStruct: Describe<ServiceSceneAction> = assign(
|
||||
baseActionStruct,
|
||||
object({
|
||||
service: literal("scene.turn_on"),
|
||||
action: literal("scene.turn_on"),
|
||||
target: optional(object({ entity_id: optional(string()) })),
|
||||
entity_id: optional(string()),
|
||||
metadata: object(),
|
||||
@ -132,7 +132,7 @@ export interface EventAction extends BaseAction {
|
||||
}
|
||||
|
||||
export interface ServiceAction extends BaseAction {
|
||||
service?: string;
|
||||
action?: string;
|
||||
service_template?: string;
|
||||
entity_id?: string;
|
||||
target?: HassServiceTarget;
|
||||
@ -160,7 +160,7 @@ export interface DelayAction extends BaseAction {
|
||||
}
|
||||
|
||||
export interface ServiceSceneAction extends BaseAction {
|
||||
service: "scene.turn_on";
|
||||
action: "scene.turn_on";
|
||||
target?: { entity_id?: string };
|
||||
entity_id?: string;
|
||||
metadata: Record<string, unknown>;
|
||||
@ -191,7 +191,7 @@ export interface WaitForTriggerAction extends BaseAction {
|
||||
}
|
||||
|
||||
export interface PlayMediaAction extends BaseAction {
|
||||
service: "media_player.play_media";
|
||||
action: "media_player.play_media";
|
||||
target?: { entity_id?: string };
|
||||
entity_id?: string;
|
||||
data: { media_content_id: string; media_content_type: string };
|
||||
@ -404,7 +404,7 @@ export const getActionType = (action: Action): ActionType => {
|
||||
if ("set_conversation_response" in action) {
|
||||
return "set_conversation_response";
|
||||
}
|
||||
if ("service" in action) {
|
||||
if ("action" in action) {
|
||||
if ("metadata" in action) {
|
||||
if (is(action, activateSceneActionStruct)) {
|
||||
return "activate_scene";
|
||||
@ -425,3 +425,60 @@ export const hasScriptFields = (
|
||||
const fields = hass.services.script[computeObjectId(entityId)]?.fields;
|
||||
return fields !== undefined && Object.keys(fields).length > 0;
|
||||
};
|
||||
|
||||
export const migrateAutomationAction = (
|
||||
action: Action | Action[]
|
||||
): Action | Action[] => {
|
||||
if (Array.isArray(action)) {
|
||||
return action.map(migrateAutomationAction) as Action[];
|
||||
}
|
||||
|
||||
if ("service" in action) {
|
||||
if (!("action" in action)) {
|
||||
action.action = action.service;
|
||||
}
|
||||
delete action.service;
|
||||
}
|
||||
|
||||
if ("sequence" in action) {
|
||||
for (const sequenceAction of (action as SequenceAction).sequence) {
|
||||
migrateAutomationAction(sequenceAction);
|
||||
}
|
||||
}
|
||||
|
||||
const actionType = getActionType(action);
|
||||
|
||||
if (actionType === "parallel") {
|
||||
const _action = action as ParallelAction;
|
||||
migrateAutomationAction(_action.parallel);
|
||||
}
|
||||
|
||||
if (actionType === "choose") {
|
||||
const _action = action as ChooseAction;
|
||||
if (Array.isArray(_action.choose)) {
|
||||
for (const choice of _action.choose) {
|
||||
migrateAutomationAction(choice.sequence);
|
||||
}
|
||||
} else if (_action.choose) {
|
||||
migrateAutomationAction(_action.choose.sequence);
|
||||
}
|
||||
if (_action.default) {
|
||||
migrateAutomationAction(_action.default);
|
||||
}
|
||||
}
|
||||
|
||||
if (actionType === "repeat") {
|
||||
const _action = action as RepeatAction;
|
||||
migrateAutomationAction(_action.repeat.sequence);
|
||||
}
|
||||
|
||||
if (actionType === "if") {
|
||||
const _action = action as IfAction;
|
||||
migrateAutomationAction(_action.then);
|
||||
if (_action.else) {
|
||||
migrateAutomationAction(_action.else);
|
||||
}
|
||||
}
|
||||
|
||||
return action;
|
||||
};
|
||||
|
@ -192,7 +192,7 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
|
||||
if (
|
||||
config.service_template ||
|
||||
(config.service && isTemplate(config.service))
|
||||
(config.action && isTemplate(config.action))
|
||||
) {
|
||||
return hass.localize(
|
||||
targets.length
|
||||
@ -204,8 +204,8 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
);
|
||||
}
|
||||
|
||||
if (config.service) {
|
||||
const [domain, serviceName] = config.service.split(".", 2);
|
||||
if (config.action) {
|
||||
const [domain, serviceName] = config.action.split(".", 2);
|
||||
const service =
|
||||
hass.localize(`component.${domain}.services.${serviceName}.name`) ||
|
||||
hass.services[domain][serviceName]?.name;
|
||||
@ -217,7 +217,7 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
: `${actionTranslationBaseKey}.service.description.service_name_no_targets`,
|
||||
{
|
||||
domain: domainToName(hass.localize, domain),
|
||||
name: service || config.service,
|
||||
name: service || config.action,
|
||||
targets: formatListWithAnds(hass.locale, targets),
|
||||
}
|
||||
);
|
||||
@ -230,7 +230,7 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
{
|
||||
name: service
|
||||
? `${domainToName(hass.localize, domain)}: ${service}`
|
||||
: config.service,
|
||||
: config.action,
|
||||
targets: formatListWithAnds(hass.locale, targets),
|
||||
}
|
||||
);
|
||||
|
@ -148,7 +148,7 @@ class MoreInfoScript extends LitElement {
|
||||
const newState = this.stateObj;
|
||||
|
||||
if (newState && (!oldState || oldState.entity_id !== newState.entity_id)) {
|
||||
this._scriptData = { service: newState.entity_id, data: {} };
|
||||
this._scriptData = { action: newState.entity_id, data: {} };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,8 +87,8 @@ export const getType = (action: Action | undefined) => {
|
||||
if (!action) {
|
||||
return undefined;
|
||||
}
|
||||
if ("service" in action || "scene" in action) {
|
||||
return getActionType(action) as "activate_scene" | "service" | "play_media";
|
||||
if ("action" in action || "scene" in action) {
|
||||
return getActionType(action) as "activate_scene" | "action" | "play_media";
|
||||
}
|
||||
if (["and", "or", "not"].some((key) => key in action)) {
|
||||
return "condition" as const;
|
||||
@ -214,12 +214,12 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
<ha-expansion-panel leftChevron>
|
||||
<h3 slot="header">
|
||||
${type === "service" &&
|
||||
"service" in this.action &&
|
||||
this.action.service
|
||||
"action" in this.action &&
|
||||
this.action.action
|
||||
? html`<ha-service-icon
|
||||
class="action-icon"
|
||||
.hass=${this.hass}
|
||||
.service=${this.action.service}
|
||||
.service=${this.action.action}
|
||||
></ha-service-icon>`
|
||||
: html`<ha-svg-icon
|
||||
class="action-icon"
|
||||
|
@ -19,7 +19,7 @@ import "../../../../components/ha-sortable";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import { getService, isService } from "../../../../data/action";
|
||||
import type { AutomationClipboard } from "../../../../data/automation";
|
||||
import { Action } from "../../../../data/script";
|
||||
import { Action, migrateAutomationAction } from "../../../../data/script";
|
||||
import { HomeAssistant, ItemPath } from "../../../../types";
|
||||
import {
|
||||
PASTE_VALUE,
|
||||
@ -179,7 +179,7 @@ export default class HaAutomationAction extends LitElement {
|
||||
actions = this.actions.concat(deepClone(this._clipboard!.action));
|
||||
} else if (isService(action)) {
|
||||
actions = this.actions.concat({
|
||||
service: getService(action),
|
||||
action: getService(action),
|
||||
metadata: {},
|
||||
});
|
||||
} else {
|
||||
@ -243,7 +243,10 @@ export default class HaAutomationAction extends LitElement {
|
||||
private _actionChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const actions = [...this.actions];
|
||||
const newValue = ev.detail.value;
|
||||
const newValue =
|
||||
ev.detail.value === null
|
||||
? ev.detail.value
|
||||
: (migrateAutomationAction(ev.detail.value) as Action);
|
||||
const index = (ev.target as any).index;
|
||||
|
||||
if (newValue === null) {
|
||||
|
@ -18,7 +18,7 @@ export class HaSceneAction extends LitElement implements ActionElement {
|
||||
|
||||
public static get defaultConfig(): SceneAction {
|
||||
return {
|
||||
service: "scene.turn_on",
|
||||
action: "scene.turn_on",
|
||||
target: {
|
||||
entity_id: "",
|
||||
},
|
||||
|
@ -20,7 +20,7 @@ export class HaPlayMediaAction extends LitElement implements ActionElement {
|
||||
|
||||
public static get defaultConfig(): PlayMediaAction {
|
||||
return {
|
||||
service: "media_player.play_media",
|
||||
action: "media_player.play_media",
|
||||
target: { entity_id: "" },
|
||||
data: { media_content_id: "", media_content_type: "" },
|
||||
metadata: {},
|
||||
|
@ -67,10 +67,7 @@ export class HaServiceAction extends LitElement implements ActionElement {
|
||||
return;
|
||||
}
|
||||
|
||||
const fields = this._fields(
|
||||
this.hass.services,
|
||||
this.action?.service
|
||||
).fields;
|
||||
const fields = this._fields(this.hass.services, this.action?.action).fields;
|
||||
if (
|
||||
this.action &&
|
||||
(Object.entries(this.action).some(
|
||||
@ -110,8 +107,8 @@ export class HaServiceAction extends LitElement implements ActionElement {
|
||||
if (!this._action) {
|
||||
return nothing;
|
||||
}
|
||||
const [domain, service] = this._action.service
|
||||
? this._action.service.split(".", 2)
|
||||
const [domain, service] = this._action.action
|
||||
? this._action.action.split(".", 2)
|
||||
: [undefined, undefined];
|
||||
return html`
|
||||
<ha-service-control
|
||||
@ -168,8 +165,8 @@ export class HaServiceAction extends LitElement implements ActionElement {
|
||||
}
|
||||
const value = { ...this.action, ...ev.detail.value };
|
||||
if ("response_variable" in this.action) {
|
||||
const [domain, service] = this._action!.service
|
||||
? this._action!.service.split(".", 2)
|
||||
const [domain, service] = this._action!.action
|
||||
? this._action!.action.split(".", 2)
|
||||
: [undefined, undefined];
|
||||
if (
|
||||
domain &&
|
||||
@ -181,6 +178,7 @@ export class HaServiceAction extends LitElement implements ActionElement {
|
||||
this._responseChecked = false;
|
||||
}
|
||||
}
|
||||
|
||||
fireEvent(this, "value-changed", { value });
|
||||
}
|
||||
|
||||
|
@ -575,6 +575,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
|
||||
private _valueChanged(ev: CustomEvent<{ value: AutomationConfig }>) {
|
||||
ev.stopPropagation();
|
||||
|
||||
this._config = ev.detail.value;
|
||||
if (this._readOnly) {
|
||||
return;
|
||||
|
@ -25,7 +25,11 @@ import "../../../components/ha-service-picker";
|
||||
import "../../../components/ha-yaml-editor";
|
||||
import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
|
||||
import { forwardHaptic } from "../../../data/haptics";
|
||||
import { Action, ServiceAction } from "../../../data/script";
|
||||
import {
|
||||
Action,
|
||||
migrateAutomationAction,
|
||||
ServiceAction,
|
||||
} from "../../../data/script";
|
||||
import {
|
||||
callExecuteScript,
|
||||
serviceCallWillDisconnect,
|
||||
@ -49,14 +53,14 @@ class HaPanelDevAction extends LitElement {
|
||||
private _yamlValid = true;
|
||||
|
||||
@storage({
|
||||
key: "panel-dev-service-state-service-data",
|
||||
key: "panel-dev-action-state-service-data",
|
||||
state: true,
|
||||
subscribe: false,
|
||||
})
|
||||
private _serviceData?: ServiceAction = { service: "", target: {}, data: {} };
|
||||
private _serviceData?: ServiceAction = { action: "", target: {}, data: {} };
|
||||
|
||||
@storage({
|
||||
key: "panel-dev-service-state-yaml-mode",
|
||||
key: "panel-dev-action-state-yaml-mode",
|
||||
state: true,
|
||||
subscribe: false,
|
||||
})
|
||||
@ -72,7 +76,7 @@ class HaPanelDevAction extends LitElement {
|
||||
const serviceParam = extractSearchParam("service");
|
||||
if (serviceParam) {
|
||||
this._serviceData = {
|
||||
service: serviceParam,
|
||||
action: serviceParam,
|
||||
target: {},
|
||||
data: {},
|
||||
};
|
||||
@ -81,11 +85,11 @@ class HaPanelDevAction extends LitElement {
|
||||
this._yamlEditor?.setValue(this._serviceData)
|
||||
);
|
||||
}
|
||||
} else if (!this._serviceData?.service) {
|
||||
} else if (!this._serviceData?.action) {
|
||||
const domain = Object.keys(this.hass.services).sort()[0];
|
||||
const service = Object.keys(this.hass.services[domain]).sort()[0];
|
||||
this._serviceData = {
|
||||
service: `${domain}.${service}`,
|
||||
action: `${domain}.${service}`,
|
||||
target: {},
|
||||
data: {},
|
||||
};
|
||||
@ -101,15 +105,15 @@ class HaPanelDevAction extends LitElement {
|
||||
protected render() {
|
||||
const { target, fields } = this._fields(
|
||||
this.hass.services,
|
||||
this._serviceData?.service
|
||||
this._serviceData?.action
|
||||
);
|
||||
|
||||
const domain = this._serviceData?.service
|
||||
? computeDomain(this._serviceData?.service)
|
||||
const domain = this._serviceData?.action
|
||||
? computeDomain(this._serviceData?.action)
|
||||
: undefined;
|
||||
|
||||
const serviceName = this._serviceData?.service
|
||||
? computeObjectId(this._serviceData?.service)
|
||||
const serviceName = this._serviceData?.action
|
||||
? computeObjectId(this._serviceData?.action)
|
||||
: undefined;
|
||||
|
||||
return html`
|
||||
@ -124,7 +128,7 @@ class HaPanelDevAction extends LitElement {
|
||||
? html`<div class="card-content">
|
||||
<ha-service-picker
|
||||
.hass=${this.hass}
|
||||
.value=${this._serviceData?.service}
|
||||
.value=${this._serviceData?.action}
|
||||
@value-changed=${this._serviceChanged}
|
||||
></ha-service-picker>
|
||||
<ha-yaml-editor
|
||||
@ -229,12 +233,12 @@ class HaPanelDevAction extends LitElement {
|
||||
`
|
||||
: ""}
|
||||
</h3>
|
||||
${this._serviceData?.service
|
||||
${this._serviceData?.action
|
||||
? html` <a
|
||||
href=${documentationUrl(
|
||||
this.hass,
|
||||
"/integrations/" +
|
||||
computeDomain(this._serviceData?.service)
|
||||
computeDomain(this._serviceData?.action)
|
||||
)}
|
||||
title=${this.hass.localize(
|
||||
"ui.components.service-control.integration_doc"
|
||||
@ -316,23 +320,23 @@ class HaPanelDevAction extends LitElement {
|
||||
);
|
||||
|
||||
private _validateServiceData = (
|
||||
serviceData,
|
||||
serviceData: ServiceAction | undefined,
|
||||
fields,
|
||||
target,
|
||||
yamlMode: boolean,
|
||||
localize: LocalizeFunc
|
||||
): string | undefined => {
|
||||
const errorCategory = yamlMode ? "yaml" : "ui";
|
||||
if (!serviceData?.service) {
|
||||
if (!serviceData?.action) {
|
||||
return localize(
|
||||
`ui.panel.developer-tools.tabs.actions.errors.${errorCategory}.no_service`
|
||||
`ui.panel.developer-tools.tabs.actions.errors.${errorCategory}.no_action`
|
||||
);
|
||||
}
|
||||
const domain = computeDomain(serviceData.service);
|
||||
const service = computeObjectId(serviceData.service);
|
||||
const domain = computeDomain(serviceData.action);
|
||||
const service = computeObjectId(serviceData.action);
|
||||
if (!domain || !service) {
|
||||
return localize(
|
||||
`ui.panel.developer-tools.tabs.actions.errors.${errorCategory}.invalid_service`
|
||||
`ui.panel.developer-tools.tabs.actions.errors.${errorCategory}.invalid_action`
|
||||
);
|
||||
}
|
||||
if (
|
||||
@ -404,7 +408,7 @@ class HaPanelDevAction extends LitElement {
|
||||
|
||||
const { target, fields } = this._fields(
|
||||
this.hass.services,
|
||||
this._serviceData?.service
|
||||
this._serviceData?.action
|
||||
);
|
||||
|
||||
this._error = this._validateServiceData(
|
||||
@ -420,7 +424,7 @@ class HaPanelDevAction extends LitElement {
|
||||
button.actionError();
|
||||
return;
|
||||
}
|
||||
const [domain, service] = this._serviceData!.service!.split(".", 2);
|
||||
const [domain, service] = this._serviceData!.action!.split(".", 2);
|
||||
const script: Action[] = [];
|
||||
if (
|
||||
this.hass.services?.[domain]?.[service] &&
|
||||
@ -460,7 +464,7 @@ class HaPanelDevAction extends LitElement {
|
||||
this._error =
|
||||
localizedErrorMessage ||
|
||||
this.hass.localize("ui.notification_toast.action_failed", {
|
||||
service: this._serviceData!.service!,
|
||||
service: this._serviceData!.action!,
|
||||
}) + ` ${err.message}`;
|
||||
return;
|
||||
}
|
||||
@ -485,7 +489,7 @@ class HaPanelDevAction extends LitElement {
|
||||
private _checkUiSupported() {
|
||||
const fields = this._fields(
|
||||
this.hass.services,
|
||||
this._serviceData?.service
|
||||
this._serviceData?.action
|
||||
).fields;
|
||||
if (
|
||||
this._serviceData &&
|
||||
@ -512,16 +516,18 @@ class HaPanelDevAction extends LitElement {
|
||||
}
|
||||
|
||||
private _serviceDataChanged(ev) {
|
||||
if (this._serviceData?.service !== ev.detail.value.service) {
|
||||
if (this._serviceData?.action !== ev.detail.value.action) {
|
||||
this._error = undefined;
|
||||
}
|
||||
this._serviceData = ev.detail.value;
|
||||
this._serviceData = migrateAutomationAction(
|
||||
ev.detail.value
|
||||
) as ServiceAction;
|
||||
this._checkUiSupported();
|
||||
}
|
||||
|
||||
private _serviceChanged(ev) {
|
||||
ev.stopPropagation();
|
||||
this._serviceData = { service: ev.detail.value || "", data: {} };
|
||||
this._serviceData = { action: ev.detail.value || "", data: {} };
|
||||
this._response = undefined;
|
||||
this._error = undefined;
|
||||
this._yamlEditor?.setValue(this._serviceData);
|
||||
@ -531,14 +537,14 @@ class HaPanelDevAction extends LitElement {
|
||||
private _fillExampleData() {
|
||||
const { fields } = this._fields(
|
||||
this.hass.services,
|
||||
this._serviceData?.service
|
||||
this._serviceData?.action
|
||||
);
|
||||
const domain = this._serviceData?.service
|
||||
? computeDomain(this._serviceData?.service)
|
||||
const domain = this._serviceData?.action
|
||||
? computeDomain(this._serviceData?.action)
|
||||
: undefined;
|
||||
|
||||
const serviceName = this._serviceData?.service
|
||||
? computeObjectId(this._serviceData?.service)
|
||||
const serviceName = this._serviceData?.action
|
||||
? computeObjectId(this._serviceData?.action)
|
||||
: undefined;
|
||||
|
||||
const example = {};
|
||||
|
@ -103,7 +103,7 @@ export class HuiActionEditor extends LitElement {
|
||||
|
||||
private _serviceAction = memoizeOne(
|
||||
(config: CallServiceActionConfig): ServiceAction => ({
|
||||
service: this._service,
|
||||
action: this._service,
|
||||
...(config.data || config.service_data
|
||||
? { data: config.data ?? config.service_data }
|
||||
: null),
|
||||
|
@ -6807,17 +6807,17 @@
|
||||
"copy_clipboard_template": "Copy to clipboard (template)",
|
||||
"errors": {
|
||||
"ui": {
|
||||
"no_service": "No action selected, please select an action",
|
||||
"invalid_service": "Selected action is invalid, please select a valid action",
|
||||
"no_action": "No action selected, please select an action",
|
||||
"invalid_action": "Selected action is invalid, please select a valid action",
|
||||
"no_target": "This action requires a target, please select a target from the picker",
|
||||
"missing_required_field": "This action requires field {key}, please enter a valid value for {key}"
|
||||
},
|
||||
"yaml": {
|
||||
"invalid_yaml": "Action YAML contains syntax errors, please fix the syntax",
|
||||
"no_service": "No action defined, please define an action: key",
|
||||
"invalid_service": "Defined action is invalid, please provide an action in the format domain.action",
|
||||
"no_target": "This action requires a target, please define a target entity_id, device_id, or area_id under target: or data:",
|
||||
"missing_required_field": "This action requires field {key}, which must be provided under data:"
|
||||
"no_action": "No action defined, please define an 'action:' key",
|
||||
"invalid_action": "Defined action is invalid, please provide an action in the format domain.action",
|
||||
"no_target": "This action requires a target, please define a target 'entity_id', 'device_id', or 'area_id' under 'target:' or 'data:'",
|
||||
"missing_required_field": "This action requires field {key}, which must be provided under 'data:'"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user