mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-02 08:33:31 +01:00
Allow trace graph to scroll independently of the step-details tab (#29906)
* Allow trace graph to scroll independently * Apply independent trace graph scrolling to script trace Port the independent column scrolling and sticky nav overlay from ha-automation-trace to ha-script-trace, and add scroll-to-active-node behavior to hat-script-graph. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Re-encapsulate nav buttons inside hat-script-graph Move the up/down navigation buttons back into hat-script-graph where they belong, restoring _previousTrackedNode/_nextTrackedNode as private. Wrap the graph content in a div.graph-scroll so it scrolls independently while the button column stays fixed — the same flex-row layout the parent was using, now self-contained inside the shadow DOM. This removes the duplicated nav overlay markup and disabled-state logic from ha-automation-trace and ha-script-trace, and removes the unnecessary public surface on HatScriptGraph. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Make not-scrollable more specific. Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
This commit is contained in:
@@ -597,28 +597,30 @@ export class HatScriptGraph extends LitElement {
|
||||
: undefined;
|
||||
try {
|
||||
return html`
|
||||
<div class="parent graph-container">
|
||||
${triggerNodes
|
||||
? html`<hat-graph-branch start .short=${triggerNodes.length < 2}>
|
||||
${triggerNodes}
|
||||
</hat-graph-branch>`
|
||||
: ""}
|
||||
${conditionKey in this.trace.config
|
||||
? html`${ensureArray(this.trace.config[conditionKey])?.map(
|
||||
(condition, i) => this._renderCondition(condition, i)
|
||||
)}`
|
||||
: ""}
|
||||
${actionKey in this.trace.config
|
||||
? html`${ensureArray(this.trace.config[actionKey]).map(
|
||||
(action, i) => this._renderActionNode(action, `action/${i}`)
|
||||
)}`
|
||||
: ""}
|
||||
${"sequence" in this.trace.config
|
||||
? html`${ensureArray<Action>(this.trace.config.sequence).map(
|
||||
(action, i) =>
|
||||
this._renderActionNode(action, `sequence/${i}`, i === 0)
|
||||
)}`
|
||||
: ""}
|
||||
<div class="graph-scroll ha-scrollbar">
|
||||
<div class="parent graph-container">
|
||||
${triggerNodes
|
||||
? html`<hat-graph-branch start .short=${triggerNodes.length < 2}>
|
||||
${triggerNodes}
|
||||
</hat-graph-branch>`
|
||||
: ""}
|
||||
${conditionKey in this.trace.config
|
||||
? html`${ensureArray(this.trace.config[conditionKey])?.map(
|
||||
(condition, i) => this._renderCondition(condition, i)
|
||||
)}`
|
||||
: ""}
|
||||
${actionKey in this.trace.config
|
||||
? html`${ensureArray(this.trace.config[actionKey]).map(
|
||||
(action, i) => this._renderActionNode(action, `action/${i}`)
|
||||
)}`
|
||||
: ""}
|
||||
${"sequence" in this.trace.config
|
||||
? html`${ensureArray<Action>(this.trace.config.sequence).map(
|
||||
(action, i) =>
|
||||
this._renderActionNode(action, `sequence/${i}`, i === 0)
|
||||
)}`
|
||||
: ""}
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<ha-icon-button
|
||||
@@ -659,6 +661,20 @@ export class HatScriptGraph extends LitElement {
|
||||
protected updated(changedProps: PropertyValues<this>) {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (!changedProps.has("trace") && !changedProps.has("selected")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Scroll to active node when selection changes
|
||||
if (changedProps.has("selected")) {
|
||||
const activeNode = this.renderRoot.querySelector(
|
||||
"hat-graph-node[active], hat-graph-branch[active]"
|
||||
) as HTMLElement;
|
||||
if (activeNode) {
|
||||
activeNode.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
||||
}
|
||||
}
|
||||
|
||||
if (!changedProps.has("trace")) {
|
||||
return;
|
||||
}
|
||||
@@ -717,6 +733,8 @@ export class HatScriptGraph extends LitElement {
|
||||
return css`
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
--stroke-clr: var(--stroke-color, var(--secondary-text-color));
|
||||
--active-clr: var(--active-color, var(--primary-color));
|
||||
--track-clr: var(--track-color, var(--accent-color));
|
||||
@@ -734,6 +752,11 @@ export class HatScriptGraph extends LitElement {
|
||||
--hat-graph-node-size: ${NODE_SIZE}px;
|
||||
--hat-graph-branch-height: ${BRANCH_HEIGHT}px;
|
||||
}
|
||||
.graph-scroll {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
.graph-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -23,6 +23,8 @@ class HassSubpage extends LitElement {
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public narrow = false;
|
||||
|
||||
@property({ type: Boolean }) public scrollable = true;
|
||||
|
||||
// @ts-ignore
|
||||
@restoreScroll(".content") private _savedScrollPos?: number;
|
||||
|
||||
@@ -57,7 +59,14 @@ class HassSubpage extends LitElement {
|
||||
<slot name="toolbar-icon"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content ha-scrollbar" @scroll=${this._saveScrollPos}>
|
||||
<div
|
||||
class=${classMap({
|
||||
content: true,
|
||||
"ha-scrollbar": this.scrollable,
|
||||
"not-scrollable": !this.scrollable,
|
||||
})}
|
||||
@scroll=${this._saveScrollPos}
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div id="fab">
|
||||
@@ -163,6 +172,12 @@ class HassSubpage extends LitElement {
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.content.not-scrollable {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:host([narrow]) .content {
|
||||
width: calc(
|
||||
100% - var(--safe-area-inset-left, 0px) - var(
|
||||
|
||||
@@ -101,7 +101,12 @@ export class HaAutomationTrace extends LitElement {
|
||||
|
||||
return html`
|
||||
${devButtons}
|
||||
<hass-subpage .hass=${this.hass} .narrow=${this.narrow} .header=${title}>
|
||||
<hass-subpage
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.header=${title}
|
||||
.scrollable=${this.narrow}
|
||||
>
|
||||
${!this.narrow && stateObj?.attributes.id
|
||||
? html`
|
||||
<ha-button
|
||||
@@ -558,15 +563,19 @@ export class HaAutomationTrace extends LitElement {
|
||||
}
|
||||
|
||||
.main {
|
||||
min-height: calc(100% - var(--header-height));
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
background-color: var(--card-background-color);
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
:host([narrow]) .main {
|
||||
flex: none;
|
||||
height: auto;
|
||||
flex-direction: column;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.container {
|
||||
@@ -575,19 +584,34 @@ export class HaAutomationTrace extends LitElement {
|
||||
|
||||
.graph {
|
||||
border-right: 1px solid var(--divider-color);
|
||||
overflow-x: auto;
|
||||
max-width: 50%;
|
||||
padding-bottom: 16px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
hat-script-graph {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
:host([narrow]) .graph {
|
||||
max-width: 100%;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
overflow: visible;
|
||||
height: auto;
|
||||
}
|
||||
:host([narrow]) hat-script-graph {
|
||||
overflow: visible;
|
||||
flex: none;
|
||||
}
|
||||
.info {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
background-color: var(--card-background-color);
|
||||
}
|
||||
:host([narrow]) .info {
|
||||
overflow: visible;
|
||||
}
|
||||
.trace-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,12 @@ export class HaScriptTrace extends LitElement {
|
||||
|
||||
return html`
|
||||
${devButtons}
|
||||
<hass-subpage .hass=${this.hass} .narrow=${this.narrow} .header=${title}>
|
||||
<hass-subpage
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.header=${title}
|
||||
.scrollable=${this.narrow}
|
||||
>
|
||||
${!this.narrow && this.scriptId
|
||||
? html`
|
||||
<ha-button
|
||||
@@ -565,14 +570,18 @@ export class HaScriptTrace extends LitElement {
|
||||
}
|
||||
|
||||
.main {
|
||||
min-height: calc(100% - var(--header-height));
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
background-color: var(--card-background-color);
|
||||
}
|
||||
|
||||
:host([narrow]) .main {
|
||||
flex: none;
|
||||
height: auto;
|
||||
flex-direction: column;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.container {
|
||||
@@ -581,16 +590,34 @@ export class HaScriptTrace extends LitElement {
|
||||
|
||||
.graph {
|
||||
border-right: 1px solid var(--divider-color);
|
||||
overflow-x: auto;
|
||||
max-width: 50%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
hat-script-graph {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
:host([narrow]) .graph {
|
||||
max-width: 100%;
|
||||
overflow: visible;
|
||||
height: auto;
|
||||
}
|
||||
:host([narrow]) hat-script-graph {
|
||||
overflow: visible;
|
||||
flex: none;
|
||||
}
|
||||
.info {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
background-color: var(--card-background-color);
|
||||
}
|
||||
:host([narrow]) .info {
|
||||
overflow: visible;
|
||||
}
|
||||
.trace-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user