mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 03:36:44 +00:00
Add trace details foundation (#8716)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
ee38c419de
commit
40cf4c8d32
@ -12,9 +12,11 @@ import { buttonLinkStyle } from "../../resources/styles";
|
||||
import "../ha-svg-icon";
|
||||
|
||||
@customElement("ha-timeline")
|
||||
class HaTimeline extends LitElement {
|
||||
export class HaTimeline extends LitElement {
|
||||
@property({ type: Boolean, reflect: true }) public label = false;
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public raised = false;
|
||||
|
||||
@property({ type: Boolean }) public lastItem = false;
|
||||
|
||||
@property({ type: String }) public icon?: string;
|
||||
@ -86,6 +88,10 @@ class HaTimeline extends LitElement {
|
||||
--timeline-ball-color,
|
||||
var(--timeline-color, var(--secondary-text-color))
|
||||
);
|
||||
border-radius: 50%;
|
||||
}
|
||||
:host([raised]) ha-svg-icon {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
.line {
|
||||
flex: 1;
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
internalProperty,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
@ -15,6 +16,7 @@ import {
|
||||
} from "../../data/trace";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "./ha-timeline";
|
||||
import type { HaTimeline } from "./ha-timeline";
|
||||
import {
|
||||
mdiCheckCircleOutline,
|
||||
mdiCircle,
|
||||
@ -30,6 +32,7 @@ import {
|
||||
getActionType,
|
||||
} from "../../data/script";
|
||||
import relativeTime from "../../common/datetime/relative_time";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
|
||||
const LOGBOOK_ENTRIES_BEFORE_FOLD = 2;
|
||||
|
||||
@ -242,7 +245,7 @@ class ActionRenderer {
|
||||
const isTopLevel = path.split("/").length === 2;
|
||||
|
||||
if (!isTopLevel && !actionType) {
|
||||
this._renderEntry(path.replace(/\//g, " "));
|
||||
this._renderEntry(path, path.replace(/\//g, " "));
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
@ -254,7 +257,7 @@ class ActionRenderer {
|
||||
return this._handleChoose(index);
|
||||
}
|
||||
|
||||
this._renderEntry(data.alias || actionType);
|
||||
this._renderEntry(path, data.alias || actionType);
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
@ -273,7 +276,8 @@ class ActionRenderer {
|
||||
// +3: 'sequence'
|
||||
// +4: executed sequence
|
||||
|
||||
const startLevel = this.keys[index].split("/").length - 1;
|
||||
const choosePath = this.keys[index];
|
||||
const startLevel = choosePath.split("/").length - 1;
|
||||
|
||||
const chooseTrace = this._getItem(index)[0] as ChooseActionTrace;
|
||||
const defaultExecuted = chooseTrace.result.choice === "default";
|
||||
@ -283,14 +287,14 @@ class ActionRenderer {
|
||||
const name = chooseConfig.alias || "Choose";
|
||||
|
||||
if (defaultExecuted) {
|
||||
this._renderEntry(`${name}: Default action executed`);
|
||||
this._renderEntry(choosePath, `${name}: Default action executed`);
|
||||
} else {
|
||||
const choiceConfig = this._getDataFromPath(
|
||||
`${this.keys[index]}/choose/${chooseTrace.result.choice}`
|
||||
) as ChooseActionChoice;
|
||||
const choiceName =
|
||||
choiceConfig.alias || `Choice ${chooseTrace.result.choice}`;
|
||||
this._renderEntry(`${name}: ${choiceName} executed`);
|
||||
this._renderEntry(choosePath, `${name}: ${choiceName} executed`);
|
||||
}
|
||||
|
||||
let i;
|
||||
@ -328,9 +332,9 @@ class ActionRenderer {
|
||||
return i;
|
||||
}
|
||||
|
||||
private _renderEntry(description: string) {
|
||||
private _renderEntry(path: string, description: string) {
|
||||
this.entries.push(html`
|
||||
<ha-timeline .icon=${mdiRecordCircleOutline}>
|
||||
<ha-timeline .icon=${mdiRecordCircleOutline} data-path=${path}>
|
||||
${description}
|
||||
</ha-timeline>
|
||||
`);
|
||||
@ -345,9 +349,11 @@ class ActionRenderer {
|
||||
export class HaAutomationTracer extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) private trace?: AutomationTraceExtended;
|
||||
@property({ attribute: false }) public trace?: AutomationTraceExtended;
|
||||
|
||||
@property({ attribute: false }) private logbookEntries?: LogbookEntry[];
|
||||
@property({ attribute: false }) public logbookEntries?: LogbookEntry[];
|
||||
|
||||
@internalProperty() private _selectedPath?: string;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.trace) {
|
||||
@ -374,6 +380,7 @@ export class HaAutomationTracer extends LitElement {
|
||||
.icon=${value[0].result.result
|
||||
? mdiCheckCircleOutline
|
||||
: mdiStopCircleOutline}
|
||||
data-path=${path}
|
||||
>
|
||||
${getDataFromPath(this.trace!.config, path).alias ||
|
||||
pathToName(path)}
|
||||
@ -442,12 +449,53 @@ export class HaAutomationTracer extends LitElement {
|
||||
return html`${entries}`;
|
||||
}
|
||||
|
||||
protected updated(props) {
|
||||
super.updated(props);
|
||||
|
||||
// Pick first path when we load a new trace.
|
||||
if (props.has("trace")) {
|
||||
const element = this.shadowRoot!.querySelector<HaTimeline>(
|
||||
"ha-timeline[data-path]"
|
||||
);
|
||||
if (element) {
|
||||
fireEvent(this, "value-changed", { value: element.dataset.path });
|
||||
this._selectedPath = element.dataset.path;
|
||||
}
|
||||
}
|
||||
|
||||
this.shadowRoot!.querySelectorAll<HaTimeline>(
|
||||
"ha-timeline[data-path]"
|
||||
).forEach((el) => {
|
||||
el.style.setProperty(
|
||||
"--timeline-ball-color",
|
||||
this._selectedPath === el.dataset.path ? "var(--primary-color)" : null
|
||||
);
|
||||
if (el.dataset.upgraded) {
|
||||
return;
|
||||
}
|
||||
el.dataset.upgraded = "1";
|
||||
el.addEventListener("click", () => {
|
||||
this._selectedPath = el.dataset.path;
|
||||
fireEvent(this, "value-changed", { value: el.dataset.path });
|
||||
});
|
||||
el.addEventListener("mouseover", () => {
|
||||
el.raised = true;
|
||||
});
|
||||
el.addEventListener("mouseout", () => {
|
||||
el.raised = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
css`
|
||||
ha-timeline[lastItem].condition {
|
||||
--timeline-ball-color: var(--error-color);
|
||||
}
|
||||
ha-timeline[data-path] {
|
||||
cursor: pointer;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { safeDump } from "js-yaml";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
@ -12,6 +13,7 @@ import { AutomationEntity } from "../../../../data/automation";
|
||||
import {
|
||||
AutomationTrace,
|
||||
AutomationTraceExtended,
|
||||
getDataFromPath,
|
||||
loadTrace,
|
||||
loadTraces,
|
||||
} from "../../../../data/trace";
|
||||
@ -48,6 +50,8 @@ export class HaAutomationTrace extends LitElement {
|
||||
|
||||
@internalProperty() private _runId?: string;
|
||||
|
||||
@internalProperty() private _path?: string;
|
||||
|
||||
@internalProperty() private _trace?: AutomationTraceExtended;
|
||||
|
||||
@internalProperty() private _logbookEntries?: LogbookEntry[];
|
||||
@ -107,10 +111,31 @@ export class HaAutomationTrace extends LitElement {
|
||||
.hass=${this.hass}
|
||||
.trace=${this._trace}
|
||||
.logbookEntries=${this._logbookEntries}
|
||||
@value-changed=${this._pickPath}
|
||||
></hat-trace>
|
||||
`}
|
||||
</div>
|
||||
</ha-card>
|
||||
${!this._path || !this._trace
|
||||
? ""
|
||||
: html`
|
||||
<div class="details">
|
||||
<ha-card header="Config">
|
||||
<pre class="config card-content">
|
||||
${safeDump(getDataFromPath(this._trace.config, this._path))}</pre
|
||||
>
|
||||
</ha-card>
|
||||
<ha-card header="Trace">
|
||||
<pre class="trace card-content">
|
||||
${safeDump(
|
||||
(this._path.split("/")[0] === "condition"
|
||||
? this._trace.condition_trace
|
||||
: this._trace.action_trace)[this._path]
|
||||
)}</pre
|
||||
>
|
||||
</ha-card>
|
||||
</div>
|
||||
`}
|
||||
</hass-tabs-subpage>
|
||||
`;
|
||||
}
|
||||
@ -162,6 +187,11 @@ export class HaAutomationTrace extends LitElement {
|
||||
|
||||
private _pickTrace(ev) {
|
||||
this._runId = ev.target.value;
|
||||
this._path = undefined;
|
||||
}
|
||||
|
||||
private _pickPath(ev) {
|
||||
this._path = ev.detail.value;
|
||||
}
|
||||
|
||||
private async _loadTraces(runId?: string) {
|
||||
@ -179,6 +209,7 @@ export class HaAutomationTrace extends LitElement {
|
||||
!this._traces.some((trace) => trace.run_id === this._runId)
|
||||
) {
|
||||
this._runId = undefined;
|
||||
this._path = undefined;
|
||||
|
||||
// If we came here from a trace passed into the url, clear it.
|
||||
if (runId) {
|
||||
@ -254,6 +285,17 @@ export class HaAutomationTrace extends LitElement {
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
margin: 0 16px;
|
||||
}
|
||||
.details > * {
|
||||
flex: 1 1 0px;
|
||||
}
|
||||
.details > *:first-child {
|
||||
margin-right: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user