mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Change yaml config of UI service call actions (#21508)
This commit is contained in:
parent
0a095c6f21
commit
a88a7c5236
@ -287,11 +287,11 @@ const CONFIGS = [
|
|||||||
config: `
|
config: `
|
||||||
- type: entities
|
- type: entities
|
||||||
entities:
|
entities:
|
||||||
- type: call-service
|
- type: perform-action
|
||||||
icon: mdi:power
|
icon: mdi:power
|
||||||
name: Bed light
|
name: Bed light
|
||||||
action_name: Toggle light
|
action_name: Toggle light
|
||||||
service: light.toggle
|
action: light.toggle
|
||||||
data:
|
data:
|
||||||
entity_id: light.bed_light
|
entity_id: light.bed_light
|
||||||
- type: section
|
- type: section
|
||||||
|
@ -5,10 +5,12 @@ export interface ToggleActionConfig extends BaseActionConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CallServiceActionConfig extends BaseActionConfig {
|
export interface CallServiceActionConfig extends BaseActionConfig {
|
||||||
action: "call-service";
|
action: "call-service" | "perform-action";
|
||||||
service: string;
|
/** @deprecated "service" is kept for backwards compatibility. Replaced by "perform_action". */
|
||||||
|
service?: string;
|
||||||
|
perform_action: string;
|
||||||
target?: HassServiceTarget;
|
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>;
|
service_data?: Record<string, unknown>;
|
||||||
data?: Record<string, unknown>;
|
data?: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,9 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
|||||||
state_color: this._config.state_color,
|
state_color: this._config.state_color,
|
||||||
...(entityConf as EntityConfig),
|
...(entityConf as EntityConfig),
|
||||||
} as EntityConfig)
|
} as EntityConfig)
|
||||||
: entityConf
|
: entityConf.type === "perform-action"
|
||||||
|
? { ...entityConf, type: "call-service" }
|
||||||
|
: entityConf
|
||||||
);
|
);
|
||||||
if (this._hass) {
|
if (this._hass) {
|
||||||
element.hass = this._hass;
|
element.hass = this._hass;
|
||||||
|
@ -66,6 +66,8 @@ export interface EntitiesCardEntityConfig extends EntityConfig {
|
|||||||
| "tilt-position"
|
| "tilt-position"
|
||||||
| "brightness";
|
| "brightness";
|
||||||
action_name?: string;
|
action_name?: string;
|
||||||
|
action?: string;
|
||||||
|
/** @deprecated use "action" instead */
|
||||||
service?: string;
|
service?: string;
|
||||||
// "service_data" is kept for backwards compatibility. Replaced by "data".
|
// "service_data" is kept for backwards compatibility. Replaced by "data".
|
||||||
service_data?: Record<string, unknown>;
|
service_data?: Record<string, unknown>;
|
||||||
|
@ -56,8 +56,12 @@ export const handleAction = async (
|
|||||||
forwardHaptic("warning");
|
forwardHaptic("warning");
|
||||||
|
|
||||||
let serviceName;
|
let serviceName;
|
||||||
if (actionConfig.action === "call-service") {
|
if (
|
||||||
const [domain, service] = actionConfig.service.split(".", 2);
|
actionConfig.action === "call-service" ||
|
||||||
|
actionConfig.action === "perform-action"
|
||||||
|
) {
|
||||||
|
const [domain, service] = (actionConfig.perform_action ||
|
||||||
|
actionConfig.service)!.split(".", 2);
|
||||||
const serviceDomains = hass.services;
|
const serviceDomains = hass.services;
|
||||||
if (domain in serviceDomains && service in serviceDomains[domain]) {
|
if (domain in serviceDomains && service in serviceDomains[domain]) {
|
||||||
await hass.loadBackendTranslation("title");
|
await hass.loadBackendTranslation("title");
|
||||||
@ -145,15 +149,17 @@ export const handleAction = async (
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "perform-action":
|
||||||
case "call-service": {
|
case "call-service": {
|
||||||
if (!actionConfig.service) {
|
if (!actionConfig.perform_action && !actionConfig.service) {
|
||||||
showToast(node, {
|
showToast(node, {
|
||||||
message: hass.localize("ui.panel.lovelace.cards.actions.no_action"),
|
message: hass.localize("ui.panel.lovelace.cards.actions.no_action"),
|
||||||
});
|
});
|
||||||
forwardHaptic("failure");
|
forwardHaptic("failure");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const [domain, service] = actionConfig.service.split(".", 2);
|
const [domain, service] = (actionConfig.perform_action ||
|
||||||
|
actionConfig.service)!.split(".", 2);
|
||||||
hass.callService(
|
hass.callService(
|
||||||
domain,
|
domain,
|
||||||
service,
|
service,
|
||||||
|
@ -33,7 +33,7 @@ const DEFAULT_ACTIONS: UiAction[] = [
|
|||||||
"toggle",
|
"toggle",
|
||||||
"navigate",
|
"navigate",
|
||||||
"url",
|
"url",
|
||||||
"call-service",
|
"perform-action",
|
||||||
"assist",
|
"assist",
|
||||||
"none",
|
"none",
|
||||||
];
|
];
|
||||||
@ -98,7 +98,7 @@ export class HuiActionEditor extends LitElement {
|
|||||||
|
|
||||||
get _service(): string {
|
get _service(): string {
|
||||||
const config = this.config as CallServiceActionConfig;
|
const config = this.config as CallServiceActionConfig;
|
||||||
return config?.service || "";
|
return config?.perform_action || config?.service || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private _serviceAction = memoizeOne(
|
private _serviceAction = memoizeOne(
|
||||||
@ -127,13 +127,19 @@ export class HuiActionEditor extends LitElement {
|
|||||||
|
|
||||||
const actions = this.actions ?? DEFAULT_ACTIONS;
|
const actions = this.actions ?? DEFAULT_ACTIONS;
|
||||||
|
|
||||||
|
let action = this.config?.action || "default";
|
||||||
|
|
||||||
|
if (action === "call-service") {
|
||||||
|
action = "perform-action";
|
||||||
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<ha-select
|
<ha-select
|
||||||
.label=${this.label}
|
.label=${this.label}
|
||||||
.configValue=${"action"}
|
.configValue=${"action"}
|
||||||
@selected=${this._actionPicked}
|
@selected=${this._actionPicked}
|
||||||
.value=${this.config?.action ?? "default"}
|
.value=${action}
|
||||||
@closed=${stopPropagation}
|
@closed=${stopPropagation}
|
||||||
fixedMenuPosition
|
fixedMenuPosition
|
||||||
naturalMenuWidt
|
naturalMenuWidt
|
||||||
@ -149,10 +155,10 @@ export class HuiActionEditor extends LitElement {
|
|||||||
: nothing}
|
: nothing}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
${actions.map(
|
${actions.map(
|
||||||
(action) => html`
|
(actn) => html`
|
||||||
<mwc-list-item .value=${action}>
|
<mwc-list-item .value=${actn}>
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.action-editor.actions.${action}`
|
`ui.panel.lovelace.editor.action-editor.actions.${actn}`
|
||||||
)}
|
)}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
`
|
`
|
||||||
@ -188,7 +194,8 @@ export class HuiActionEditor extends LitElement {
|
|||||||
></ha-textfield>
|
></ha-textfield>
|
||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
${this.config?.action === "call-service"
|
${this.config?.action === "call-service" ||
|
||||||
|
this.config?.action === "perform-action"
|
||||||
? html`
|
? html`
|
||||||
<ha-service-control
|
<ha-service-control
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -234,8 +241,8 @@ export class HuiActionEditor extends LitElement {
|
|||||||
data = { url_path: this._url_path };
|
data = { url_path: this._url_path };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "call-service": {
|
case "perform-action": {
|
||||||
data = { service: this._service };
|
data = { perform_action: this._service };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "navigate": {
|
case "navigate": {
|
||||||
@ -285,7 +292,7 @@ export class HuiActionEditor extends LitElement {
|
|||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
const value = {
|
const value = {
|
||||||
...this.config!,
|
...this.config!,
|
||||||
service: ev.detail.value.service || "",
|
perform_action: ev.detail.value.service || "",
|
||||||
data: ev.detail.value.data,
|
data: ev.detail.value.data,
|
||||||
target: ev.detail.value.target || {},
|
target: ev.detail.value.target || {},
|
||||||
};
|
};
|
||||||
@ -296,6 +303,9 @@ export class HuiActionEditor extends LitElement {
|
|||||||
if ("service_data" in value) {
|
if ("service_data" in value) {
|
||||||
delete value.service_data;
|
delete value.service_data;
|
||||||
}
|
}
|
||||||
|
if ("service" in value) {
|
||||||
|
delete value.service;
|
||||||
|
}
|
||||||
|
|
||||||
fireEvent(this, "value-changed", { value });
|
fireEvent(this, "value-changed", { value });
|
||||||
}
|
}
|
||||||
|
@ -67,9 +67,10 @@ const castEntitiesRowConfigStruct = object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const callServiceEntitiesRowConfigStruct = object({
|
const callServiceEntitiesRowConfigStruct = object({
|
||||||
type: literal("call-service"),
|
type: enums(["call-service", "perform-action"]),
|
||||||
name: string(),
|
name: string(),
|
||||||
service: string(),
|
service: optional(string()),
|
||||||
|
action: optional(string()),
|
||||||
icon: optional(string()),
|
icon: optional(string()),
|
||||||
action_name: optional(string()),
|
action_name: optional(string()),
|
||||||
// "service_data" is kept for backwards compatibility. Replaced by "data".
|
// "service_data" is kept for backwards compatibility. Replaced by "data".
|
||||||
@ -149,6 +150,7 @@ const entitiesRowConfigStruct = dynamic<any>((value) => {
|
|||||||
case "buttons": {
|
case "buttons": {
|
||||||
return buttonsEntitiesRowConfigStruct;
|
return buttonsEntitiesRowConfigStruct;
|
||||||
}
|
}
|
||||||
|
case "perform-action":
|
||||||
case "call-service": {
|
case "call-service": {
|
||||||
return callServiceEntitiesRowConfigStruct;
|
return callServiceEntitiesRowConfigStruct;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,10 @@ export class HuiRowElementEditor extends HuiElementEditor<LovelaceRowConfig> {
|
|||||||
return GENERIC_ROW_TYPE;
|
return GENERIC_ROW_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.value?.type === "perform-action") {
|
||||||
|
return "call-service";
|
||||||
|
}
|
||||||
|
|
||||||
return this.value?.type;
|
return this.value?.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,8 +31,9 @@ const actionConfigStructUrl = object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const actionConfigStructService = object({
|
const actionConfigStructService = object({
|
||||||
action: literal("call-service"),
|
action: enums(["call-service", "perform-action"]),
|
||||||
service: string(),
|
service: optional(string()),
|
||||||
|
perform_action: optional(string()),
|
||||||
service_data: optional(object()),
|
service_data: optional(object()),
|
||||||
data: optional(object()),
|
data: optional(object()),
|
||||||
target: optional(
|
target: optional(
|
||||||
@ -64,6 +65,7 @@ export const actionConfigStructType = object({
|
|||||||
"toggle",
|
"toggle",
|
||||||
"more-info",
|
"more-info",
|
||||||
"call-service",
|
"call-service",
|
||||||
|
"perform-action",
|
||||||
"url",
|
"url",
|
||||||
"navigate",
|
"navigate",
|
||||||
"assist",
|
"assist",
|
||||||
@ -77,6 +79,9 @@ export const actionConfigStruct = dynamic<any>((value) => {
|
|||||||
case "call-service": {
|
case "call-service": {
|
||||||
return actionConfigStructService;
|
return actionConfigStructService;
|
||||||
}
|
}
|
||||||
|
case "perform-action": {
|
||||||
|
return actionConfigStructService;
|
||||||
|
}
|
||||||
case "navigate": {
|
case "navigate": {
|
||||||
return actionConfigStructNavigate;
|
return actionConfigStructNavigate;
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,12 @@ export interface TextConfig {
|
|||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
export interface CallServiceConfig extends EntityConfig {
|
export interface CallServiceConfig extends EntityConfig {
|
||||||
type: "call-service";
|
type: "call-service" | "perform-action";
|
||||||
service: string;
|
/** @deprecated use "action" instead */
|
||||||
|
service?: string;
|
||||||
|
action: string;
|
||||||
|
data?: Record<string, any>;
|
||||||
|
/** @deprecated use "data" instead */
|
||||||
service_data?: Record<string, any>;
|
service_data?: Record<string, any>;
|
||||||
action_name?: string;
|
action_name?: string;
|
||||||
}
|
}
|
||||||
|
@ -15,15 +15,16 @@ export class HuiCallServiceRow extends HuiButtonRow {
|
|||||||
throw new Error("No name specified");
|
throw new Error("No name specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!callServiceConfig.service) {
|
if (!callServiceConfig.action && !callServiceConfig.service) {
|
||||||
throw new Error("No service specified");
|
throw new Error("No action specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
super.setConfig({
|
super.setConfig({
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "perform-action",
|
||||||
service: callServiceConfig.service,
|
perform_action: (callServiceConfig.action ||
|
||||||
data: callServiceConfig.service_data,
|
callServiceConfig.service)!,
|
||||||
|
data: callServiceConfig.data || callServiceConfig.service_data,
|
||||||
},
|
},
|
||||||
...callServiceConfig,
|
...callServiceConfig,
|
||||||
type: "button",
|
type: "button",
|
||||||
|
@ -5672,7 +5672,7 @@
|
|||||||
"pipeline_id": "Assistant",
|
"pipeline_id": "Assistant",
|
||||||
"actions": {
|
"actions": {
|
||||||
"default_action": "Default",
|
"default_action": "Default",
|
||||||
"call-service": "Perform action",
|
"perform-action": "Perform action",
|
||||||
"more-info": "More info",
|
"more-info": "More info",
|
||||||
"toggle": "Toggle",
|
"toggle": "Toggle",
|
||||||
"navigate": "Navigate",
|
"navigate": "Navigate",
|
||||||
@ -5787,6 +5787,7 @@
|
|||||||
"entity_row": {
|
"entity_row": {
|
||||||
"divider": "Divider",
|
"divider": "Divider",
|
||||||
"call-service": "Perform action",
|
"call-service": "Perform action",
|
||||||
|
"perform-action": "Perform action",
|
||||||
"section": "Section",
|
"section": "Section",
|
||||||
"weblink": "Web link",
|
"weblink": "Web link",
|
||||||
"attribute": "Attribute",
|
"attribute": "Attribute",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user