Update script more info (#19899)

* Update script more info

* Fixes

* Update styling

* remarks

* Always show cancel button

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
Paulus Schoutsen 2024-02-28 11:07:26 -05:00 committed by GitHub
parent 3ef1110109
commit 5287061699
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 138 additions and 66 deletions

View File

@ -127,9 +127,11 @@ export class HaControlButton extends LitElement {
opacity 180ms ease-in-out; opacity 180ms ease-in-out;
opacity: var(--control-button-background-opacity); opacity: var(--control-button-background-opacity);
} }
.button ::slotted(*) { .button {
transition: color 180ms ease-in-out; transition: color 180ms ease-in-out;
color: var(--control-button-icon-color); color: var(--control-button-icon-color);
}
.button ::slotted(*) {
pointer-events: none; pointer-events: none;
} }
.button:disabled { .button:disabled {

View File

@ -16,6 +16,8 @@ export class HaMoreInfoStateHeader extends LitElement {
@property({ attribute: false }) public stateOverride?: string; @property({ attribute: false }) public stateOverride?: string;
@property({ attribute: false }) public changedOverride?: number;
@state() private _absoluteTime = false; @state() private _absoluteTime = false;
private _localizeState(): TemplateResult | string { private _localizeState(): TemplateResult | string {
@ -50,13 +52,13 @@ export class HaMoreInfoStateHeader extends LitElement {
? html` ? html`
<ha-absolute-time <ha-absolute-time
.hass=${this.hass} .hass=${this.hass}
.datetime=${this.stateObj.last_changed} .datetime=${this.changedOverride ?? this.stateObj.last_changed}
></ha-absolute-time> ></ha-absolute-time>
` `
: html` : html`
<ha-relative-time <ha-relative-time
.hass=${this.hass} .hass=${this.hass}
.datetime=${this.stateObj.last_changed} .datetime=${this.changedOverride ?? this.stateObj.last_changed}
capitalize capitalize
></ha-relative-time> ></ha-relative-time>
`} `}

View File

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

View File

@ -1,3 +1,4 @@
import { mdiPlay, mdiStop } from "@mdi/js";
import "@material/mwc-button"; import "@material/mwc-button";
import { HassEntity } from "home-assistant-js-websocket"; import { HassEntity } from "home-assistant-js-websocket";
import { import {
@ -8,28 +9,54 @@ import {
nothing, nothing,
PropertyValues, PropertyValues,
} from "lit"; } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-relative-time"; import "../../../components/ha-relative-time";
import "../../../components/ha-service-control"; import "../../../components/ha-service-control";
import "../../../components/ha-control-button";
import "../../../components/ha-control-button-group";
import "../../../components/entity/state-info"; import "../../../components/entity/state-info";
import { HomeAssistant } from "../../../types"; import { HomeAssistant } from "../../../types";
import { canRun, ScriptEntity } from "../../../data/script"; import { canRun, ScriptEntity } from "../../../data/script";
import { isUnavailableState } from "../../../data/entity"; import { isUnavailableState } from "../../../data/entity";
import { computeObjectId } from "../../../common/entity/compute_object_id"; import { computeObjectId } from "../../../common/entity/compute_object_id";
import { listenMediaQuery } from "../../../common/dom/media_query";
import "../components/ha-more-info-state-header";
@customElement("more-info-script") @customElement("more-info-script")
class MoreInfoScript extends LitElement { class MoreInfoScript extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public stateObj?: HassEntity; @property({ attribute: false }) public stateObj?: ScriptEntity;
private _scriptData: Record<string, any> = {}; @state() private _scriptData: Record<string, any> = {};
@state() private narrow = false;
private _unsubMediaQuery?: () => void;
public connectedCallback(): void {
super.connectedCallback();
this._unsubMediaQuery = listenMediaQuery(
"(max-width: 870px)",
(matches) => {
this.narrow = matches;
}
);
}
public disconnectedCallback(): void {
super.disconnectedCallback();
if (this._unsubMediaQuery) {
this._unsubMediaQuery();
this._unsubMediaQuery = undefined;
}
}
protected render() { protected render() {
if (!this.hass || !this.stateObj) { if (!this.hass || !this.stateObj) {
return nothing; return nothing;
} }
const stateObj = this.stateObj as ScriptEntity; const stateObj = this.stateObj;
const fields = const fields =
this.hass.services.script[computeObjectId(this.stateObj.entity_id)] this.hass.services.script[computeObjectId(this.stateObj.entity_id)]
@ -37,64 +64,74 @@ class MoreInfoScript extends LitElement {
const hasFields = fields && Object.keys(fields).length > 0; const hasFields = fields && Object.keys(fields).length > 0;
const current = stateObj.attributes.current || 0;
const isQueued = stateObj.attributes.mode === "queued";
const isParallel = stateObj.attributes.mode === "parallel";
const hasQueue = isQueued && current > 1;
return html` return html`
<div class="flex"> <ha-more-info-state-header
<state-info .stateObj=${stateObj}
.hass=${this.hass} .hass=${this.hass}
.stateObj=${stateObj} .stateOverride=${current > 0
inDialog ? isParallel && current > 1
></state-info> ? this.hass.localize("ui.card.script.running_parallel", {
${stateObj.state === "on" active: current,
? html`<mwc-button @click=${this._cancelScript}> })
${stateObj.attributes.mode !== "single" && : this.hass.localize("ui.card.script.running_single")
(stateObj.attributes.current || 0) > 0 : this.hass.localize("ui.card.script.idle")}
? this.hass.localize("ui.card.script.cancel_multiple", { .changedOverride=${this.stateObj.attributes.last_triggered || 0}
number: stateObj.attributes.current, ></ha-more-info-state-header>
})
: this.hass.localize("ui.card.script.cancel")} <div class=${`queue ${hasQueue ? "has-queue" : ""}`}>
</mwc-button>` ${hasQueue
: nothing} ? html`
${stateObj.state === "off" || stateObj.attributes.max ${this.hass.localize("ui.card.script.running_queued", {
? html`<mwc-button queued: current - 1,
@click=${this._runScript} })}
.disabled=${isUnavailableState(stateObj.state) || `
!canRun(stateObj)} : ""}
>
${this.hass!.localize("ui.card.script.run")}
</mwc-button>`
: nothing}
</div> </div>
${hasFields ${hasFields
? html` ? html`
<ha-service-control <div class="fields">
hidePicker <div class="title">
hideDescription ${this.hass.localize("ui.card.script.run_script")}
.hass=${this.hass} </div>
.value=${this._scriptData} <ha-service-control
.showAdvanced=${this.hass.userData?.showAdvanced} hidePicker
@value-changed=${this._scriptDataChanged} hideDescription
></ha-service-control> .hass=${this.hass}
.value=${this._scriptData}
.showAdvanced=${this.hass.userData?.showAdvanced}
.narrow=${this.narrow}
@value-changed=${this._scriptDataChanged}
></ha-service-control>
</div>
` `
: nothing} : nothing}
<hr /> <ha-control-button-group>
<div class="flex"> <ha-control-button
<div> @click=${this._cancelScript}
${this.hass.localize( .disabled=${!current}
"ui.dialogs.more_info_control.script.last_triggered" class="cancel-button"
)}: >
</div> <ha-svg-icon .path=${mdiStop}></ha-svg-icon>
${this.stateObj.attributes.last_triggered ${(isQueued || isParallel) && current > 1
? html` ? this.hass.localize("ui.card.script.cancel_all")
<ha-relative-time : this.hass.localize("ui.card.script.cancel")}
.hass=${this.hass} </ha-control-button>
.datetime=${this.stateObj.attributes.last_triggered} <ha-control-button
capitalize class="run-button"
></ha-relative-time> @click=${this._runScript}
` .disabled=${isUnavailableState(stateObj.state) || !this._canRun()}
: this.hass.localize("ui.components.relative_time.never")} >
</div> <ha-svg-icon .path=${mdiPlay}></ha-svg-icon>
${this.hass!.localize("ui.card.script.run")}
</ha-control-button>
</ha-control-button-group>
`; `;
} }
@ -139,17 +176,41 @@ class MoreInfoScript extends LitElement {
this._scriptData = { ...this._scriptData, ...ev.detail.value }; this._scriptData = { ...this._scriptData, ...ev.detail.value };
} }
private _canRun() {
if (
canRun(this.stateObj!) ||
// Restart can also always runs. Just cancels other run.
this.stateObj!.attributes.mode === "restart"
) {
return true;
}
return false;
}
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return css` return css`
.flex { .queue {
display: flex; visibility: hidden;
justify-content: space-between; color: var(--secondary-text-color);
text-align: center;
margin-bottom: 16px;
height: 21px;
}
.queue.has-queue {
visibility: visible;
}
.fields {
padding: 16px;
border: 1px solid var(--divider-color);
border-radius: 8px;
margin-bottom: 16px; margin-bottom: 16px;
} }
hr { .fields .title {
border-color: var(--divider-color); font-weight: bold;
border-bottom: none; }
margin: 16px 0; ha-control-button ha-svg-icon {
z-index: -1;
margin-right: 4px;
} }
ha-service-control { ha-service-control {
--service-control-padding: 0; --service-control-padding: 0;

View File

@ -218,8 +218,14 @@
}, },
"script": { "script": {
"run": "[%key:ui::card::service::run%]", "run": "[%key:ui::card::service::run%]",
"running_single": "Running…",
"running_queued": "{queued} queued",
"running_parallel": "{active} Running…",
"cancel": "Cancel", "cancel": "Cancel",
"cancel_multiple": "Cancel {number}" "cancel_multiple": "Cancel {number}",
"cancel_all": "Cancel all",
"idle": "Idle",
"run_script": "Run script"
}, },
"service": { "service": {
"run": "Run" "run": "Run"