mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 11:16:35 +00:00
Automation traces localization (#18862)
This commit is contained in:
parent
ce983f043e
commit
d762a9365f
@ -1,5 +1,12 @@
|
|||||||
import { dump } from "js-yaml";
|
import { dump } from "js-yaml";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
nothing,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
||||||
@ -18,6 +25,12 @@ import { traceTabStyles } from "./trace-tab-styles";
|
|||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import type { NodeInfo } from "./hat-script-graph";
|
import type { NodeInfo } from "./hat-script-graph";
|
||||||
|
|
||||||
|
const TRACE_PATH_TABS = [
|
||||||
|
"step_config",
|
||||||
|
"changed_variables",
|
||||||
|
"logbook",
|
||||||
|
] as const;
|
||||||
|
|
||||||
@customElement("ha-trace-path-details")
|
@customElement("ha-trace-path-details")
|
||||||
export class HaTracePathDetails extends LitElement {
|
export class HaTracePathDetails extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -34,7 +47,7 @@ export class HaTracePathDetails extends LitElement {
|
|||||||
|
|
||||||
@property() public trackedNodes!: Record<string, any>;
|
@property() public trackedNodes!: Record<string, any>;
|
||||||
|
|
||||||
@state() private _view: "config" | "changed_variables" | "logbook" = "config";
|
@state() private _view: (typeof TRACE_PATH_TABS)[number] = "step_config";
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
@ -43,23 +56,21 @@ export class HaTracePathDetails extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tabs top">
|
<div class="tabs top">
|
||||||
${[
|
${TRACE_PATH_TABS.map(
|
||||||
["config", "Step Config"],
|
(view) => html`
|
||||||
["changed_variables", "Changed Variables"],
|
|
||||||
["logbook", "Related logbook entries"],
|
|
||||||
].map(
|
|
||||||
([view, label]) => html`
|
|
||||||
<button
|
<button
|
||||||
.view=${view}
|
.view=${view}
|
||||||
class=${classMap({ active: this._view === view })}
|
class=${classMap({ active: this._view === view })}
|
||||||
@click=${this._showTab}
|
@click=${this._showTab}
|
||||||
>
|
>
|
||||||
${label}
|
${this.hass!.localize(
|
||||||
|
`ui.panel.config.automation.trace.tabs.${view}`
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
${this._view === "config"
|
${this._view === "step_config"
|
||||||
? this._renderSelectedConfig()
|
? this._renderSelectedConfig()
|
||||||
: this._view === "changed_variables"
|
: this._view === "changed_variables"
|
||||||
? this._renderChangedVars()
|
? this._renderChangedVars()
|
||||||
@ -71,7 +82,9 @@ export class HaTracePathDetails extends LitElement {
|
|||||||
const paths = this.trace.trace;
|
const paths = this.trace.trace;
|
||||||
|
|
||||||
if (!this.selected?.path) {
|
if (!this.selected?.path) {
|
||||||
return "Select a node on the left for more information.";
|
return this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.path.choose"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK: default choice node is not part of paths. We filter them out here by checking parent.
|
// HACK: default choice node is not part of paths. We filter them out here by checking parent.
|
||||||
@ -82,12 +95,16 @@ export class HaTracePathDetails extends LitElement {
|
|||||||
] as ChooseActionTraceStep[];
|
] as ChooseActionTraceStep[];
|
||||||
|
|
||||||
if (parentTraceInfo && parentTraceInfo[0]?.result?.choice === "default") {
|
if (parentTraceInfo && parentTraceInfo[0]?.result?.choice === "default") {
|
||||||
return "The default action was executed because no options matched.";
|
return this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.path.default_action_executed"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(this.selected.path in paths)) {
|
if (!(this.selected.path in paths)) {
|
||||||
return "This node was not executed and so no further trace information is available.";
|
return this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.path.no_further_execution"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const parts: TemplateResult[][] = [];
|
const parts: TemplateResult[][] = [];
|
||||||
@ -115,29 +132,53 @@ export class HaTracePathDetails extends LitElement {
|
|||||||
trace as any;
|
trace as any;
|
||||||
|
|
||||||
if (result?.enabled === false) {
|
if (result?.enabled === false) {
|
||||||
return html`This node was disabled and skipped during execution so
|
return html`${this.hass!.localize(
|
||||||
no further trace information is available.`;
|
"ui.panel.config.automation.trace.path.disabled_node"
|
||||||
|
)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${curPath === this.selected.path
|
${curPath === this.selected.path
|
||||||
? ""
|
? ""
|
||||||
: html`<h2>${curPath.substr(this.selected.path.length + 1)}</h2>`}
|
: html`<h2>
|
||||||
${data.length === 1 ? "" : html`<h3>Iteration ${idx + 1}</h3>`}
|
${curPath.substring(this.selected.path.length + 1)}
|
||||||
Executed:
|
</h2>`}
|
||||||
${formatDateTimeWithSeconds(
|
${data.length === 1
|
||||||
new Date(timestamp),
|
? nothing
|
||||||
this.hass.locale,
|
: html`<h3>
|
||||||
this.hass.config
|
${this.hass!.localize(
|
||||||
)}<br />
|
"ui.panel.config.automation.trace.path.iteration",
|
||||||
|
{ number: idx + 1 }
|
||||||
|
)}
|
||||||
|
</h3>`}
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.path.executed",
|
||||||
|
{
|
||||||
|
time: formatDateTimeWithSeconds(
|
||||||
|
new Date(timestamp),
|
||||||
|
this.hass.locale,
|
||||||
|
this.hass.config
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
<br />
|
||||||
${result
|
${result
|
||||||
? html`Result:
|
? html`${this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.path.result"
|
||||||
|
)}
|
||||||
<pre>${dump(result)}</pre>`
|
<pre>${dump(result)}</pre>`
|
||||||
: error
|
: error
|
||||||
? html`<div class="error">Error: ${error}</div>`
|
? html`<div class="error">
|
||||||
: ""}
|
${this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.path.error",
|
||||||
|
{
|
||||||
|
error: error,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</div>`
|
||||||
|
: nothing}
|
||||||
${Object.keys(rest).length === 0
|
${Object.keys(rest).length === 0
|
||||||
? ""
|
? nothing
|
||||||
: html`<pre>${dump(rest)}</pre>`}
|
: html`<pre>${dump(rest)}</pre>`}
|
||||||
`;
|
`;
|
||||||
})
|
})
|
||||||
@ -149,16 +190,18 @@ export class HaTracePathDetails extends LitElement {
|
|||||||
|
|
||||||
private _renderSelectedConfig() {
|
private _renderSelectedConfig() {
|
||||||
if (!this.selected?.path) {
|
if (!this.selected?.path) {
|
||||||
return "";
|
return nothing;
|
||||||
}
|
}
|
||||||
const config = getDataFromPath(this.trace!.config, this.selected.path);
|
const config = getDataFromPath(this.trace!.config, this.selected.path);
|
||||||
return config
|
return config
|
||||||
? html`<ha-code-editor
|
? html`<ha-code-editor
|
||||||
.value=${dump(config).trimRight()}
|
.value=${dump(config).trimEnd()}
|
||||||
readOnly
|
readOnly
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
></ha-code-editor>`
|
></ha-code-editor>`
|
||||||
: "Unable to find config";
|
: this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.path.unable_to_find_config"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderChangedVars() {
|
private _renderChangedVars() {
|
||||||
@ -169,10 +212,19 @@ export class HaTracePathDetails extends LitElement {
|
|||||||
<div class="padded-box">
|
<div class="padded-box">
|
||||||
${data.map(
|
${data.map(
|
||||||
(trace, idx) => html`
|
(trace, idx) => html`
|
||||||
${idx > 0 ? html`<p>Iteration ${idx + 1}</p>` : ""}
|
${idx > 0
|
||||||
|
? html`<p>
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.path.iteration",
|
||||||
|
{ number: idx + 1 }
|
||||||
|
)}
|
||||||
|
</p>`
|
||||||
|
: ""}
|
||||||
${Object.keys(trace.changed_variables || {}).length === 0
|
${Object.keys(trace.changed_variables || {}).length === 0
|
||||||
? "No variables changed"
|
? this.hass!.localize(
|
||||||
: html`<pre>${dump(trace.changed_variables).trimRight()}</pre>`}
|
"ui.panel.config.automation.trace.path.no_variables_changed"
|
||||||
|
)
|
||||||
|
: html`<pre>${dump(trace.changed_variables).trimEnd()}</pre>`}
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -186,7 +238,11 @@ export class HaTracePathDetails extends LitElement {
|
|||||||
const index = trackedPaths.indexOf(this.selected.path);
|
const index = trackedPaths.indexOf(this.selected.path);
|
||||||
|
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
return html`<div class="padded-box">Node not tracked.</div>`;
|
return html`<div class="padded-box">
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.path.node_not_tracked"
|
||||||
|
)}
|
||||||
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let entries: LogbookEntry[];
|
let entries: LogbookEntry[];
|
||||||
@ -234,7 +290,9 @@ export class HaTracePathDetails extends LitElement {
|
|||||||
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
|
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
|
||||||
`
|
`
|
||||||
: html`<div class="padded-box">
|
: html`<div class="padded-box">
|
||||||
No Logbook entries found for this step.
|
${this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.path.no_logbook_entries"
|
||||||
|
)}
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,14 @@ import {
|
|||||||
mdiRayStartArrow,
|
mdiRayStartArrow,
|
||||||
mdiRefresh,
|
mdiRefresh,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
nothing,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { repeat } from "lit/directives/repeat";
|
import { repeat } from "lit/directives/repeat";
|
||||||
@ -41,6 +48,8 @@ import { haStyle } from "../../../resources/styles";
|
|||||||
import { HomeAssistant, Route } from "../../../types";
|
import { HomeAssistant, Route } from "../../../types";
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
|
|
||||||
|
const TABS = ["details", "automation_config", "timeline", "logbook"] as const;
|
||||||
|
|
||||||
@customElement("ha-automation-trace")
|
@customElement("ha-automation-trace")
|
||||||
export class HaAutomationTrace extends LitElement {
|
export class HaAutomationTrace extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -67,12 +76,7 @@ export class HaAutomationTrace extends LitElement {
|
|||||||
|
|
||||||
@state() private _logbookEntries?: LogbookEntry[];
|
@state() private _logbookEntries?: LogbookEntry[];
|
||||||
|
|
||||||
@state() private _view:
|
@state() private _view: (typeof TABS)[number] | "blueprint" = "details";
|
||||||
| "details"
|
|
||||||
| "config"
|
|
||||||
| "timeline"
|
|
||||||
| "logbook"
|
|
||||||
| "blueprint" = "details";
|
|
||||||
|
|
||||||
@query("hat-script-graph") private _graph?: HatScriptGraph;
|
@query("hat-script-graph") private _graph?: HatScriptGraph;
|
||||||
|
|
||||||
@ -213,9 +217,15 @@ export class HaAutomationTrace extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
${this._traces === undefined
|
${this._traces === undefined
|
||||||
? html`<div class="container">Loading…</div>`
|
? html`<div class="container">
|
||||||
|
${this.hass!.localize("ui.common.loading")}
|
||||||
|
</div>`
|
||||||
: this._traces.length === 0
|
: this._traces.length === 0
|
||||||
? html`<div class="container">No traces found</div>`
|
? html`<div class="container">
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.config.automation.trace.no_traces_found"
|
||||||
|
)}
|
||||||
|
</div>`
|
||||||
: this._trace === undefined
|
: this._trace === undefined
|
||||||
? ""
|
? ""
|
||||||
: html`
|
: html`
|
||||||
@ -230,20 +240,17 @@ export class HaAutomationTrace extends LitElement {
|
|||||||
|
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<div class="tabs top">
|
<div class="tabs top">
|
||||||
${[
|
${TABS.map(
|
||||||
["details", "Step Details"],
|
(view) => html`
|
||||||
["timeline", "Trace Timeline"],
|
|
||||||
["logbook", "Related logbook entries"],
|
|
||||||
["config", "Automation Config"],
|
|
||||||
].map(
|
|
||||||
([view, label]) => html`
|
|
||||||
<button
|
<button
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
.view=${view}
|
.view=${view}
|
||||||
class=${classMap({ active: this._view === view })}
|
class=${classMap({ active: this._view === view })}
|
||||||
@click=${this._showTab}
|
@click=${this._showTab}
|
||||||
>
|
>
|
||||||
${label}
|
${this.hass!.localize(
|
||||||
|
`ui.panel.config.automation.trace.tabs.${view}`
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
@ -257,7 +264,9 @@ export class HaAutomationTrace extends LitElement {
|
|||||||
})}
|
})}
|
||||||
@click=${this._showTab}
|
@click=${this._showTab}
|
||||||
>
|
>
|
||||||
Blueprint Config
|
${this.hass!.localize(
|
||||||
|
`ui.panel.config.automation.trace.tabs.blueprint_config`
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@ -265,7 +274,7 @@ export class HaAutomationTrace extends LitElement {
|
|||||||
${this._selected === undefined ||
|
${this._selected === undefined ||
|
||||||
this._logbookEntries === undefined ||
|
this._logbookEntries === undefined ||
|
||||||
trackedNodes === undefined
|
trackedNodes === undefined
|
||||||
? ""
|
? nothing
|
||||||
: this._view === "details"
|
: this._view === "details"
|
||||||
? html`
|
? html`
|
||||||
<ha-trace-path-details
|
<ha-trace-path-details
|
||||||
@ -278,7 +287,7 @@ export class HaAutomationTrace extends LitElement {
|
|||||||
.renderedNodes=${renderedNodes!}
|
.renderedNodes=${renderedNodes!}
|
||||||
></ha-trace-path-details>
|
></ha-trace-path-details>
|
||||||
`
|
`
|
||||||
: this._view === "config"
|
: this._view === "automation_config"
|
||||||
? html`
|
? html`
|
||||||
<ha-trace-config
|
<ha-trace-config
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
|
@ -2976,7 +2976,31 @@
|
|||||||
"download_trace": "Download trace",
|
"download_trace": "Download trace",
|
||||||
"edit_automation": "Edit automation",
|
"edit_automation": "Edit automation",
|
||||||
"older_trace": "Older trace",
|
"older_trace": "Older trace",
|
||||||
"newer_trace": "Newer trace"
|
"newer_trace": "Newer trace",
|
||||||
|
"no_traces_found": "No traces found",
|
||||||
|
"tabs": {
|
||||||
|
"details": "Step Details",
|
||||||
|
"timeline": "Trace Timeline",
|
||||||
|
"logbook": "Related logbook entries",
|
||||||
|
"automation_config": "Automation Config",
|
||||||
|
"step_config": "Step Config",
|
||||||
|
"changed_variables": "Changed Variables",
|
||||||
|
"blueprint_config": "Blueprint Config"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"choose": "Select a node on the left for more information.",
|
||||||
|
"default_action_executed": "The default action was executed because no options matched.",
|
||||||
|
"no_further_execution": "This node was not executed and so no further trace information is available.",
|
||||||
|
"disabled_node": "This node was disabled and skipped during execution so no further trace information is available.",
|
||||||
|
"iteration": "Iteration {number}",
|
||||||
|
"executed": "Executed: {time}",
|
||||||
|
"error": "Error: {error}",
|
||||||
|
"result": "Result:",
|
||||||
|
"node_not_tracked": "Node not tracked.",
|
||||||
|
"no_logbook_entries": "No Logbook entries found for this step.",
|
||||||
|
"no_variables_changed": "No variables changed",
|
||||||
|
"unable_to_find_config": "Unable to find config"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"blueprint": {
|
"blueprint": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user