mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Display an error message when disabling the button in devtools/service (#17519)
This commit is contained in:
parent
01405d96b6
commit
5455ce2e0f
@ -10,9 +10,11 @@ import { computeObjectId } from "../../../common/entity/compute_object_id";
|
||||
import { hasTemplate } from "../../../common/string/has-template";
|
||||
import { extractSearchParam } from "../../../common/url/search-params";
|
||||
import { HaProgressButton } from "../../../components/buttons/ha-progress-button";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
|
||||
import "../../../components/entity/ha-entity-picker";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-expansion-panel";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-service-control";
|
||||
@ -29,7 +31,6 @@ import { haStyle } from "../../../resources/styles";
|
||||
import "../../../styles/polymer-ha-style";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { documentationUrl } from "../../../util/documentation-url";
|
||||
import { showToast } from "../../../util/toast";
|
||||
|
||||
class HaPanelDevService extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@ -40,6 +41,10 @@ class HaPanelDevService extends LitElement {
|
||||
|
||||
@state() private _response?: Record<string, any>;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
private _yamlValid = true;
|
||||
|
||||
@storage({
|
||||
key: "panel-dev-service-state-service-data",
|
||||
state: true,
|
||||
@ -96,8 +101,6 @@ class HaPanelDevService extends LitElement {
|
||||
this._serviceData?.service
|
||||
);
|
||||
|
||||
const isValid = this._isValid(this._serviceData, fields, target);
|
||||
|
||||
const domain = this._serviceData?.service
|
||||
? computeDomain(this._serviceData?.service)
|
||||
: undefined;
|
||||
@ -138,6 +141,9 @@ class HaPanelDevService extends LitElement {
|
||||
class="card-content"
|
||||
></ha-service-control>
|
||||
`}
|
||||
${this._error !== undefined
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: nothing}
|
||||
</ha-card>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
@ -163,11 +169,7 @@ class HaPanelDevService extends LitElement {
|
||||
>`
|
||||
: ""}
|
||||
</div>
|
||||
<ha-progress-button
|
||||
.disabled=${!isValid}
|
||||
raised
|
||||
@click=${this._callService}
|
||||
>
|
||||
<ha-progress-button raised @click=${this._callService}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.services.call_service"
|
||||
)}
|
||||
@ -292,14 +294,25 @@ class HaPanelDevService extends LitElement {
|
||||
fields.filter((field) => !field.selector)
|
||||
);
|
||||
|
||||
private _isValid = memoizeOne((serviceData, fields, target): boolean => {
|
||||
private _validateServiceData = (
|
||||
serviceData,
|
||||
fields,
|
||||
target,
|
||||
yamlMode: boolean,
|
||||
localize: LocalizeFunc
|
||||
): string | undefined => {
|
||||
const errorCategory = yamlMode ? "yaml" : "ui";
|
||||
if (!serviceData?.service) {
|
||||
return false;
|
||||
return localize(
|
||||
`ui.panel.developer-tools.tabs.services.errors.${errorCategory}.no_service`
|
||||
);
|
||||
}
|
||||
const domain = computeDomain(serviceData.service);
|
||||
const service = computeObjectId(serviceData.service);
|
||||
if (!domain || !service) {
|
||||
return false;
|
||||
return localize(
|
||||
`ui.panel.developer-tools.tabs.services.errors.${errorCategory}.invalid_service`
|
||||
);
|
||||
}
|
||||
if (
|
||||
target &&
|
||||
@ -308,18 +321,24 @@ class HaPanelDevService extends LitElement {
|
||||
!serviceData.data?.device_id &&
|
||||
!serviceData.data?.area_id
|
||||
) {
|
||||
return false;
|
||||
return localize(
|
||||
`ui.panel.developer-tools.tabs.services.errors.${errorCategory}.no_target`
|
||||
);
|
||||
}
|
||||
for (const field of fields) {
|
||||
if (
|
||||
field.required &&
|
||||
(!serviceData.data || serviceData.data[field.key] === undefined)
|
||||
) {
|
||||
return false;
|
||||
return localize(
|
||||
`ui.panel.developer-tools.tabs.services.errors.${errorCategory}.missing_required_field`,
|
||||
"key",
|
||||
field.key
|
||||
);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return undefined;
|
||||
};
|
||||
|
||||
private _fields = memoizeOne(
|
||||
(
|
||||
@ -353,19 +372,47 @@ class HaPanelDevService extends LitElement {
|
||||
|
||||
private async _callService(ev) {
|
||||
const button = ev.currentTarget as HaProgressButton;
|
||||
if (!this._serviceData?.service) {
|
||||
|
||||
if (this._yamlMode && !this._yamlValid) {
|
||||
forwardHaptic("failure");
|
||||
button.actionError();
|
||||
this._error = this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.services.errors.yaml.invalid_yaml"
|
||||
);
|
||||
return;
|
||||
}
|
||||
const [domain, service] = this._serviceData.service.split(".", 2);
|
||||
|
||||
const { target, fields } = this._fields(
|
||||
this.hass.services,
|
||||
this._serviceData?.service
|
||||
);
|
||||
|
||||
this._error = this._validateServiceData(
|
||||
this._serviceData,
|
||||
fields,
|
||||
target,
|
||||
this._yamlMode,
|
||||
this.hass.localize
|
||||
);
|
||||
|
||||
if (this._error !== undefined) {
|
||||
forwardHaptic("failure");
|
||||
button.actionError();
|
||||
return;
|
||||
}
|
||||
const [domain, service] = this._serviceData!.service!.split(".", 2);
|
||||
const script: Action[] = [];
|
||||
if ("response" in this.hass.services[domain][service]) {
|
||||
if (
|
||||
this.hass.services?.[domain]?.[service] &&
|
||||
"response" in this.hass.services[domain][service]
|
||||
) {
|
||||
script.push({
|
||||
...this._serviceData,
|
||||
...this._serviceData!,
|
||||
response_variable: "service_result",
|
||||
});
|
||||
script.push({ stop: "done", response_variable: "service_result" });
|
||||
} else {
|
||||
script.push(this._serviceData);
|
||||
script.push(this._serviceData!);
|
||||
}
|
||||
try {
|
||||
this._response = (await callExecuteScript(this.hass, script)).response;
|
||||
@ -378,14 +425,12 @@ class HaPanelDevService extends LitElement {
|
||||
}
|
||||
forwardHaptic("failure");
|
||||
button.actionError();
|
||||
showToast(this, {
|
||||
message:
|
||||
this.hass.localize(
|
||||
"ui.notification_toast.service_call_failed",
|
||||
"service",
|
||||
this._serviceData.service
|
||||
) + ` ${err.message}`,
|
||||
});
|
||||
this._error =
|
||||
this.hass.localize(
|
||||
"ui.notification_toast.service_call_failed",
|
||||
"service",
|
||||
this._serviceData!.service!
|
||||
) + ` ${err.message}`;
|
||||
return;
|
||||
}
|
||||
button.actionSuccess();
|
||||
@ -393,12 +438,16 @@ class HaPanelDevService extends LitElement {
|
||||
|
||||
private _toggleYaml() {
|
||||
this._yamlMode = !this._yamlMode;
|
||||
this._yamlValid = true;
|
||||
this._error = undefined;
|
||||
}
|
||||
|
||||
private _yamlChanged(ev) {
|
||||
if (!ev.detail.isValid) {
|
||||
this._yamlValid = false;
|
||||
return;
|
||||
}
|
||||
this._yamlValid = true;
|
||||
this._serviceDataChanged(ev);
|
||||
}
|
||||
|
||||
@ -432,6 +481,9 @@ class HaPanelDevService extends LitElement {
|
||||
}
|
||||
|
||||
private _serviceDataChanged(ev) {
|
||||
if (this._serviceData?.service !== ev.detail.value.service) {
|
||||
this._error = undefined;
|
||||
}
|
||||
this._serviceData = ev.detail.value;
|
||||
this._checkUiSupported();
|
||||
}
|
||||
@ -440,6 +492,7 @@ class HaPanelDevService extends LitElement {
|
||||
ev.stopPropagation();
|
||||
this._serviceData = { service: ev.detail.value || "", data: {} };
|
||||
this._response = undefined;
|
||||
this._error = undefined;
|
||||
this._yamlEditor?.setValue(this._serviceData);
|
||||
this._checkUiSupported();
|
||||
}
|
||||
|
@ -5592,7 +5592,22 @@
|
||||
"yaml_parameters": "Parameters only available in YAML mode",
|
||||
"all_parameters": "All available parameters",
|
||||
"accepts_target": "This service accepts a target, for example: `entity_id: light.bed_light`",
|
||||
"no_template_ui_support": "The UI does not support templates, you can still use the YAML editor."
|
||||
"no_template_ui_support": "The UI does not support templates, you can still use the YAML editor.",
|
||||
"errors": {
|
||||
"ui": {
|
||||
"no_service": "No service selected, please select a service",
|
||||
"invalid_service": "Selected service is invalid, please select a valid service",
|
||||
"no_target": "This service requires a target, please select a target from the picker",
|
||||
"missing_required_field": "This service requires field {key}, please enter a valid value for {key}"
|
||||
},
|
||||
"yaml": {
|
||||
"invalid_yaml": "Service YAML contains syntax errors, please fix the syntax",
|
||||
"no_service": "No service defined, please define a service: key",
|
||||
"invalid_service": "Defined service is invalid, please provide a service in the format domain.service",
|
||||
"no_target": "This service requires a target, please define a target entity_id, device_id, or area_id under target: or data:",
|
||||
"missing_required_field": "This service requires field {key}, which must be provided under data:"
|
||||
}
|
||||
}
|
||||
},
|
||||
"states": {
|
||||
"title": "States",
|
||||
|
Loading…
x
Reference in New Issue
Block a user