Show script fields in Script more info dialog (#19879)

* Show script fields in more info dialog

* Apply suggestions from code review

Co-authored-by: Bram Kragten <mail@bramkragten.nl>

* Guard for state obj changes

* Update src/components/ha-service-control.ts

Co-authored-by: Marc Geurts <geurtsmarc@hotmail.com>

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
Co-authored-by: Marc Geurts <geurtsmarc@hotmail.com>
This commit is contained in:
Paulus Schoutsen 2024-02-27 09:05:28 -05:00 committed by GitHub
parent 8fe7711634
commit d6d61a4137
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 166 additions and 29 deletions

View File

@ -93,6 +93,8 @@ export class HaServiceControl extends LitElement {
@property({ type: Boolean, reflect: true }) public hidePicker = false;
@property({ type: Boolean }) public hideDescription = false;
@state() private _value!: this["value"];
@state() private _checkedKeys = new Set();
@ -373,7 +375,8 @@ export class HaServiceControl extends LitElement {
)) ||
serviceData?.description;
return html`${this.hidePicker
return html`
${this.hidePicker
? nothing
: html`<ha-service-picker
.hass=${this.hass}
@ -381,29 +384,33 @@ export class HaServiceControl extends LitElement {
.disabled=${this.disabled}
@value-changed=${this._serviceChanged}
></ha-service-picker>`}
<div class="description">
${description ? html`<p>${description}</p>` : ""}
${this._manifest
? html` <a
href=${this._manifest.is_built_in
? documentationUrl(
this.hass,
`/integrations/${this._manifest.domain}`
)
: this._manifest.documentation}
title=${this.hass.localize(
"ui.components.service-control.integration_doc"
)}
target="_blank"
rel="noreferrer"
>
<ha-icon-button
.path=${mdiHelpCircle}
class="help-icon"
></ha-icon-button>
</a>`
: ""}
</div>
${this.hideDescription
? nothing
: html`
<div class="description">
${description ? html`<p>${description}</p>` : ""}
${this._manifest
? html` <a
href=${this._manifest.is_built_in
? documentationUrl(
this.hass,
`/integrations/${this._manifest.domain}`
)
: this._manifest.documentation}
title=${this.hass.localize(
"ui.components.service-control.integration_doc"
)}
target="_blank"
rel="noreferrer"
>
<ha-icon-button
.path=${mdiHelpCircle}
class="help-icon"
></ha-icon-button>
</a>`
: nothing}
</div>
`}
${serviceData && "target" in serviceData
? html`<ha-settings-row .narrow=${this.narrow}>
${hasOptional
@ -517,7 +524,8 @@ export class HaServiceControl extends LitElement {
></ha-selector>
</ha-settings-row>`
: "";
})}`;
})}
`;
}
private _localizeValueCallback = (key: string) => {

View File

@ -5,7 +5,7 @@ import { computeGroupDomain, GroupEntity } from "../../data/group";
import { CONTINUOUS_DOMAINS } from "../../data/logbook";
import { HomeAssistant } from "../../types";
export const DOMAINS_NO_INFO = ["camera", "configurator"];
export const DOMAINS_NO_INFO = ["camera", "configurator", "script"];
/**
* Entity domains that should be editable *if* they have an id present;
* {@see shouldShowEditIcon}.

View File

@ -1,8 +1,21 @@
import "@material/mwc-button";
import { HassEntity } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import {
css,
CSSResultGroup,
html,
LitElement,
nothing,
PropertyValues,
} from "lit";
import { customElement, property } from "lit/decorators";
import "../../../components/ha-relative-time";
import "../../../components/ha-service-control";
import "../../../components/entity/state-info";
import { HomeAssistant } from "../../../types";
import { canRun, ScriptEntity } from "../../../data/script";
import { isUnavailableState } from "../../../data/entity";
import { computeObjectId } from "../../../common/entity/compute_object_id";
@customElement("more-info-script")
class MoreInfoScript extends LitElement {
@ -10,12 +23,61 @@ class MoreInfoScript extends LitElement {
@property({ attribute: false }) public stateObj?: HassEntity;
private _scriptData: Record<string, any> = {};
protected render() {
if (!this.hass || !this.stateObj) {
return nothing;
}
const stateObj = this.stateObj as ScriptEntity;
const fields =
this.hass.services.script[computeObjectId(this.stateObj.entity_id)]
?.fields;
const hasFields = fields && Object.keys(fields).length > 0;
return html`
<div class="flex">
<state-info
.hass=${this.hass}
.stateObj=${stateObj}
inDialog
></state-info>
${stateObj.state === "on"
? html`<mwc-button @click=${this._cancelScript}>
${stateObj.attributes.mode !== "single" &&
(stateObj.attributes.current || 0) > 0
? this.hass.localize("ui.card.script.cancel_multiple", {
number: stateObj.attributes.current,
})
: this.hass.localize("ui.card.script.cancel")}
</mwc-button>`
: nothing}
${stateObj.state === "off" || stateObj.attributes.max
? html`<mwc-button
@click=${this._runScript}
.disabled=${isUnavailableState(stateObj.state) ||
!canRun(stateObj)}
>
${this.hass!.localize("ui.card.script.run")}
</mwc-button>`
: nothing}
</div>
${hasFields
? html`
<ha-service-control
hidePicker
hideDescription
.hass=${this.hass}
.value=${this._scriptData}
.showAdvanced=${this.hass.userData?.showAdvanced}
@value-changed=${this._scriptDataChanged}
></ha-service-control>
`
: nothing}
<hr />
<div class="flex">
<div>
@ -36,17 +98,63 @@ class MoreInfoScript extends LitElement {
`;
}
protected override willUpdate(changedProperties: PropertyValues): void {
super.willUpdate(changedProperties);
if (!changedProperties.has("stateObj")) {
return;
}
const oldState = changedProperties.get("stateObj") as
| HassEntity
| undefined;
const newState = this.stateObj;
if (newState && (!oldState || oldState.entity_id !== newState.entity_id)) {
this._scriptData = { service: newState.entity_id, data: {} };
}
}
private _cancelScript(ev: Event) {
ev.stopPropagation();
this._callService("turn_off");
}
private async _runScript(ev: Event) {
ev.stopPropagation();
this.hass.callService(
"script",
computeObjectId(this.stateObj!.entity_id),
this._scriptData
);
}
private _callService(service: string): void {
this.hass.callService("script", service, {
entity_id: this.stateObj!.entity_id,
});
}
private _scriptDataChanged(ev: CustomEvent): void {
this._scriptData = { ...this._scriptData, ...ev.detail.value };
}
static get styles(): CSSResultGroup {
return css`
.flex {
display: flex;
justify-content: space-between;
margin-bottom: 16px;
}
hr {
border-color: var(--divider-color);
border-bottom: none;
margin: 16px 0;
}
ha-service-control {
--service-control-padding: 0;
--service-control-items-border-top: none;
}
`;
}
}

View File

@ -15,6 +15,8 @@ import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { ActionRowConfig, LovelaceRow } from "./types";
import { computeObjectId } from "../../../common/entity/compute_object_id";
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
@customElement("hui-script-entity-row")
class HuiScriptEntityRow extends LitElement implements LovelaceRow {
@ -92,7 +94,15 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
private _runScript(ev): void {
ev.stopPropagation();
this._callService("turn_on");
const fields =
this.hass!.services.script[computeObjectId(this._config!.entity)]?.fields;
if (fields && Object.keys(fields).length > 0) {
showMoreInfoDialog(this, { entityId: this._config!.entity });
} else {
this._callService("turn_on");
}
}
private _callService(service: string): void {

View File

@ -8,6 +8,8 @@ import { isUnavailableState } from "../data/entity";
import { canRun, ScriptEntity } from "../data/script";
import { haStyle } from "../resources/styles";
import { HomeAssistant } from "../types";
import { computeObjectId } from "../common/entity/compute_object_id";
import { showMoreInfoDialog } from "../dialogs/more-info/show-ha-more-info-dialog";
@customElement("state-card-script")
class StateCardScript extends LitElement {
@ -56,7 +58,16 @@ class StateCardScript extends LitElement {
private _runScript(ev: Event) {
ev.stopPropagation();
this._callService("turn_on");
const fields =
this.hass!.services.script[computeObjectId(this.stateObj.entity_id)]
?.fields;
if (fields && Object.keys(fields).length > 0) {
showMoreInfoDialog(this, { entityId: this.stateObj.entity_id });
} else {
this._callService("turn_on");
}
}
private _callService(service: string): void {