Show generated media in action dev tools (#26927)

* Show generated image in action dev tools

* Resolve media_source_id

* Render other media content too

* Update src/panels/developer-tools/action/developer-tools-action.ts

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

* Fix

* Remove translation placeholder

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
pull/27082/head
Paulus Schoutsen 2025-09-17 13:07:32 -04:00 committed by GitHub
parent 846692bc8a
commit dfc4b0bba2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 62 additions and 6 deletions

View File

@ -2,9 +2,10 @@ import { mdiHelpCircle } from "@mdi/js";
import type { HassService } from "home-assistant-js-websocket";
import { ERR_CONNECTION_LOST } from "home-assistant-js-websocket";
import { load } from "js-yaml";
import type { CSSResultGroup } from "lit";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { until } from "lit/directives/until";
import memoizeOne from "memoize-one";
import { storage } from "../../../common/decorators/storage";
import { computeDomain } from "../../../common/entity/compute_domain";
@ -37,6 +38,7 @@ import {
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import { resolveMediaSource } from "../../../data/media_source";
@customElement("developer-tools-action")
class HaPanelDevAction extends LitElement {
@ -46,7 +48,12 @@ class HaPanelDevAction extends LitElement {
@state() private _uiAvailable = true;
@state() private _response?: Record<string, any>;
@state() private _response?: {
domain: string;
service: string;
result: Record<string, any>;
media?: Promise<TemplateResult | typeof nothing>;
};
@state() private _error?: string;
@ -199,7 +206,7 @@ class HaPanelDevAction extends LitElement {
</div>
</div>
${this._response
? html`<div class="content">
? html`<div class="content response">
<ha-card
.header=${this.hass.localize(
"ui.panel.developer-tools.tabs.actions.response"
@ -212,7 +219,7 @@ class HaPanelDevAction extends LitElement {
read-only
auto-update
has-extra-actions
.value=${this._response}
.value=${this._response.result}
>
<ha-button
appearance="plain"
@ -223,6 +230,7 @@ class HaPanelDevAction extends LitElement {
)}</ha-button
>
</ha-yaml-editor>
${until(this._response.media)}
</div>
</ha-card>
</div>`
@ -328,7 +336,7 @@ class HaPanelDevAction extends LitElement {
private async _copyTemplate(): Promise<void> {
await copyToClipboard(
`{% set ${this._serviceData?.response_variable || "action_response"} = ${JSON.stringify(this._response)} %}`
`{% set ${this._serviceData?.response_variable || "action_response"} = ${JSON.stringify(this._response!.result)} %}`
);
showToast(this, {
message: this.hass.localize("ui.common.copied_clipboard"),
@ -478,7 +486,48 @@ class HaPanelDevAction extends LitElement {
}
button.progress = true;
try {
this._response = (await callExecuteScript(this.hass, script)).response;
const result = (await callExecuteScript(this.hass, script)).response;
this._response = {
domain,
service,
result,
media:
"media_source_id" in result
? resolveMediaSource(this.hass, result.media_source_id).then(
(resolved) =>
resolved.mime_type.startsWith("image/")
? html`<img src=${resolved.url} alt="Media content" />`
: resolved.mime_type.startsWith("video/")
? html`
<video
controls
src=${resolved.url}
alt="Video content"
></video>
`
: resolved.mime_type.startsWith("audio/")
? html`
<audio
controls
src=${resolved.url}
alt="Audio content"
></audio>
`
: html`
<a
href=${resolved.url}
target="_blank"
rel="noreferrer"
><ha-button>
${this.hass.localize(
"ui.panel.developer-tools.tabs.actions.open_media"
)}
</ha-button></a
>
`
)
: undefined,
};
} catch (err: any) {
if (
err.error?.code === ERR_CONNECTION_LOST &&
@ -682,6 +731,12 @@ class HaPanelDevAction extends LitElement {
display: flex;
align-items: center;
}
.response img {
max-width: 100%;
height: auto;
margin-top: 24px;
}
`,
];
}

View File

@ -8797,6 +8797,7 @@
"accepts_target": "This action 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.",
"copy_clipboard_template": "Copy to clipboard as template",
"open_media": "Open media",
"errors": {
"ui": {
"no_action": "No action selected, please select an action",