Automation traces localization (#18862)

This commit is contained in:
Simon Lamon 2023-12-18 15:06:41 +01:00 committed by GitHub
parent ce983f043e
commit d762a9365f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 147 additions and 56 deletions

View File

@ -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>`;
} }

View File

@ -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}

View File

@ -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": {