mirror of
https://github.com/home-assistant/frontend.git
synced 2026-09-19 11:48:08 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
682a2712b0 | ||
|
|
2c7077eb45 |
@@ -93,9 +93,9 @@ export class HaAutomationRowEventChip extends LitElement {
|
||||
}
|
||||
|
||||
:host([variant="neutral"]) {
|
||||
--background-color: var(--ha-color-fill-neutral-normal-resting);
|
||||
--background-color-hover: var(--ha-color-fill-neutral-normal-hover);
|
||||
--text-color: var(--ha-color-on-neutral-normal);
|
||||
--background-color: var(--ha-color-fill-neutral-loud-resting);
|
||||
--background-color-hover: var(--ha-color-fill-neutral-loud-hover);
|
||||
--text-color: var(--ha-color-on-neutral-loud);
|
||||
}
|
||||
|
||||
:host([variant="success"]) {
|
||||
|
||||
@@ -152,7 +152,7 @@ export class HaAutomationRow extends LitElement {
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
:host([building-block]) .leading-icon-wrapper {
|
||||
background-color: var(--ha-color-fill-neutral-loud-resting);
|
||||
border: 1px solid var(--ha-color-border-neutral-normal);
|
||||
border-radius: var(--ha-border-radius-md);
|
||||
padding: var(--ha-space-1);
|
||||
margin-top: 10px;
|
||||
@@ -172,7 +172,6 @@ export class HaAutomationRow extends LitElement {
|
||||
:host([building-block]) ::slotted([slot="leading-icon"].action-icon),
|
||||
:host([building-block]) ::slotted(#condition-icon) {
|
||||
--mdc-icon-size: var(--ha-space-5);
|
||||
color: var(--white-color);
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
:host([collapsed]) .expand-button {
|
||||
@@ -185,9 +184,16 @@ export class HaAutomationRow extends LitElement {
|
||||
outline-offset: -2px;
|
||||
outline-width: 2px;
|
||||
}
|
||||
:host([disabled]) .row {
|
||||
border-top-right-radius: var(--ha-border-radius-square);
|
||||
border-top-left-radius: var(--ha-border-radius-square);
|
||||
:host([disabled]) .row,
|
||||
:host([disabled]) ::slotted([slot="leading-icon"]) {
|
||||
color: var(--ha-color-text-disabled);
|
||||
}
|
||||
:host([disabled]) .leading-icon-wrapper {
|
||||
opacity: 0.6;
|
||||
}
|
||||
:host([disabled]) ::slotted([slot="header"]) {
|
||||
opacity: 0.6;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.header {
|
||||
position: relative;
|
||||
|
||||
@@ -12,7 +12,6 @@ import type { HaECOption } from "../../resources/echarts/echarts";
|
||||
import { measureTextWidth } from "../../util/text";
|
||||
import "./ha-chart-base";
|
||||
import "./ha-chart-tooltip-marker";
|
||||
import { NODE_SIZE } from "../trace/hat-graph-const";
|
||||
import "../ha-alert";
|
||||
|
||||
export interface Node {
|
||||
@@ -43,6 +42,7 @@ const OVERFLOW_MARGIN = 5;
|
||||
const FONT_SIZE = 12;
|
||||
const NODE_GAP = 6;
|
||||
const LABEL_DISTANCE = 5;
|
||||
const NODE_SIZE = 30;
|
||||
const LABEL_MIN_MARGIN = 5;
|
||||
const BIDI_MARKS = /[\u200E\u200F\u202A-\u202E\u2066-\u2069]/g;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing, svg } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import type { HASSDomTargetEvent } from "../../common/dom/fire_event";
|
||||
import { BRANCH_HEIGHT, SPACING } from "./hat-graph-const";
|
||||
|
||||
interface BranchConfig {
|
||||
@@ -10,6 +10,9 @@ interface BranchConfig {
|
||||
start: boolean;
|
||||
end: boolean;
|
||||
track: boolean;
|
||||
// A branch the run entered but never finished, because a step in it raised.
|
||||
// Its incoming curve is tracked, everything leaving it is not.
|
||||
trackEnd: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,34 +35,85 @@ export class HatGraphBranch extends LitElement {
|
||||
|
||||
private _maxHeight = 0;
|
||||
|
||||
private _updateBranches(ev: HASSDomTargetEvent<HTMLSlotElement>) {
|
||||
@query("#branches slot") private _slot?: HTMLSlotElement;
|
||||
|
||||
// The branch children are Lit rendered by the parent, so their track
|
||||
// attribute can flip (another trace, another run) without a slot change,
|
||||
// and nested nodes can change without the assigned elements changing.
|
||||
private _trackObserver = new MutationObserver((mutations) => {
|
||||
if (
|
||||
mutations.some(
|
||||
(m) =>
|
||||
m.type === "childList" || (m.target as Element).parentElement === this
|
||||
)
|
||||
) {
|
||||
this._updateBranches();
|
||||
}
|
||||
});
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._trackObserver.observe(this, {
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
childList: true,
|
||||
attributeFilter: ["track", "unfinished"],
|
||||
});
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._trackObserver.disconnect();
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
// The branches are read from the DOM, so they are refreshed on every
|
||||
// update to pick up size changes as well.
|
||||
this._updateBranches();
|
||||
}
|
||||
|
||||
private _updateBranches() {
|
||||
if (!this._slot) {
|
||||
return;
|
||||
}
|
||||
let total_width = 0;
|
||||
const heights: number[] = [];
|
||||
const branches: BranchConfig[] = [];
|
||||
(ev.target as HTMLSlotElement).assignedElements().forEach((c) => {
|
||||
this._slot.assignedElements().forEach((c) => {
|
||||
const width = c.clientWidth;
|
||||
const height = c.clientHeight;
|
||||
const track = c.hasAttribute("track");
|
||||
branches.push({
|
||||
x: width / 2 + total_width,
|
||||
height,
|
||||
start: c.hasAttribute("graph-start"),
|
||||
end: c.hasAttribute("graph-end"),
|
||||
track: c.hasAttribute("track"),
|
||||
track,
|
||||
trackEnd: track && !c.hasAttribute("unfinished"),
|
||||
});
|
||||
total_width += width;
|
||||
heights.push(height);
|
||||
});
|
||||
const maxHeight = Math.max(...heights);
|
||||
// Tracked branches are drawn last, so they are never covered by the
|
||||
// untracked ones where the paths overlap.
|
||||
branches.sort(
|
||||
(a, b) =>
|
||||
Number(a.trackEnd) - Number(b.trackEnd) ||
|
||||
Number(a.track) - Number(b.track)
|
||||
);
|
||||
if (
|
||||
total_width === this._totalWidth &&
|
||||
maxHeight === this._maxHeight &&
|
||||
JSON.stringify(branches) === JSON.stringify(this._branches)
|
||||
) {
|
||||
// Nothing changed, don't trigger another update.
|
||||
return;
|
||||
}
|
||||
this._totalWidth = total_width;
|
||||
this._maxHeight = Math.max(...heights);
|
||||
this._branches = branches.sort((a, b) => {
|
||||
if (a.track && !b.track) {
|
||||
return 1;
|
||||
}
|
||||
if (a.track && b.track) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
this._maxHeight = maxHeight;
|
||||
this._branches = branches;
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -79,7 +133,9 @@ export class HatGraphBranch extends LitElement {
|
||||
})}
|
||||
d="
|
||||
M ${this._totalWidth / 2} 0
|
||||
L ${branch.x} ${BRANCH_HEIGHT}
|
||||
C ${this._totalWidth / 2} ${BRANCH_HEIGHT / 2}
|
||||
${branch.x} ${BRANCH_HEIGHT / 2}
|
||||
${branch.x} ${BRANCH_HEIGHT}
|
||||
"/>
|
||||
`
|
||||
)}
|
||||
@@ -94,7 +150,7 @@ export class HatGraphBranch extends LitElement {
|
||||
return svg`
|
||||
<path
|
||||
class=${classMap({
|
||||
track: branch.track,
|
||||
track: branch.trackEnd,
|
||||
})}
|
||||
d="
|
||||
M ${branch.x} ${branch.height}
|
||||
@@ -115,12 +171,14 @@ export class HatGraphBranch extends LitElement {
|
||||
return svg`
|
||||
<path
|
||||
class=${classMap({
|
||||
track: branch.track,
|
||||
track: branch.trackEnd,
|
||||
})}
|
||||
d="
|
||||
M ${branch.x} 0
|
||||
V ${SPACING}
|
||||
L ${this._totalWidth / 2} ${BRANCH_HEIGHT + SPACING}
|
||||
C ${branch.x} ${SPACING + BRANCH_HEIGHT / 2}
|
||||
${this._totalWidth / 2} ${SPACING + BRANCH_HEIGHT / 2}
|
||||
${this._totalWidth / 2} ${BRANCH_HEIGHT + SPACING}
|
||||
"/>
|
||||
`;
|
||||
})}
|
||||
@@ -161,14 +219,19 @@ export class HatGraphBranch extends LitElement {
|
||||
}
|
||||
#bottom {
|
||||
height: calc(var(--hat-graph-branch-height) + var(--hat-graph-spacing));
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
path {
|
||||
stroke: var(--stroke-clr);
|
||||
stroke-width: 2;
|
||||
stroke: var(--connector-clr, var(--stroke-clr));
|
||||
stroke-width: 1;
|
||||
stroke-dasharray: 4 3;
|
||||
fill: none;
|
||||
}
|
||||
path.track {
|
||||
stroke: var(--track-clr);
|
||||
stroke-width: 2;
|
||||
stroke-dasharray: none;
|
||||
}
|
||||
:host([disabled]) path {
|
||||
stroke: var(--disabled-clr);
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
export const SPACING = 10;
|
||||
export const NODE_SIZE = 30;
|
||||
export const NODE_SIZE = 36;
|
||||
export const NODE_RADIUS = 12;
|
||||
export const BRANCH_HEIGHT = 20;
|
||||
export const ICON_SIZE = 24;
|
||||
// Building blocks are rotated 45deg, so their diagonal (size * sqrt(2)) is
|
||||
// bigger than the node box: the node svg is allowed to overflow for them.
|
||||
export const BUILDING_BLOCK_SIZE = 30;
|
||||
export const BUILDING_BLOCK_RADIUS = 6;
|
||||
export const BUILDING_BLOCK_ICON_SIZE = 20;
|
||||
|
||||
@@ -3,7 +3,24 @@ import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { LitElement, css, html, nothing, svg } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { isSafari } from "../../util/is_safari";
|
||||
import { NODE_SIZE, SPACING } from "./hat-graph-const";
|
||||
import {
|
||||
BUILDING_BLOCK_ICON_SIZE,
|
||||
BUILDING_BLOCK_RADIUS,
|
||||
BUILDING_BLOCK_SIZE,
|
||||
ICON_SIZE,
|
||||
NODE_RADIUS,
|
||||
NODE_SIZE,
|
||||
SPACING,
|
||||
} from "./hat-graph-const";
|
||||
|
||||
/** Matches the 16px live-test indicator used by automation rows. */
|
||||
const BADGE_RADIUS = 8;
|
||||
/** Point on the rounded corner arc, so the badge straddles the node border. */
|
||||
const BADGE_X = NODE_SIZE / 2 - NODE_RADIUS + NODE_RADIUS / Math.SQRT2;
|
||||
const BADGE_Y = -BADGE_X;
|
||||
/** The repeat count sits centered on the bottom edge. */
|
||||
const COUNT_BADGE_Y = NODE_SIZE / 2;
|
||||
const COUNT_BADGE_RADIUS = 9;
|
||||
|
||||
/**
|
||||
* @attribute active
|
||||
@@ -15,7 +32,7 @@ export class HatGraphNode extends LitElement {
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public disabled = false;
|
||||
|
||||
@property({ type: Boolean }) public error = false;
|
||||
@property({ type: Boolean, reflect: true }) public error = false;
|
||||
|
||||
@property({ attribute: "not-enabled", reflect: true, type: Boolean })
|
||||
notEnabled = false;
|
||||
@@ -26,6 +43,10 @@ export class HatGraphNode extends LitElement {
|
||||
@property({ attribute: "graph-start", reflect: true, type: Boolean })
|
||||
graphStart = false;
|
||||
|
||||
/** Renders the node as a filled diamond, like building block rows in the editor. */
|
||||
@property({ attribute: "building-block", reflect: true, type: Boolean })
|
||||
buildingBlock = false;
|
||||
|
||||
@property({ type: Boolean, attribute: "nofocus" }) noFocus = false;
|
||||
|
||||
@property({ reflect: true, type: Number }) badge?: number;
|
||||
@@ -43,6 +64,9 @@ export class HatGraphNode extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
const height = NODE_SIZE + (this.graphStart ? 2 : SPACING + 1);
|
||||
const width = SPACING + NODE_SIZE;
|
||||
const size = this.buildingBlock ? BUILDING_BLOCK_SIZE : NODE_SIZE;
|
||||
const iconSize = this.buildingBlock ? BUILDING_BLOCK_ICON_SIZE : ICON_SIZE;
|
||||
// A rotated building block is wider than its side.
|
||||
return html`
|
||||
<svg
|
||||
class=${isSafari ? "safari" : ""}
|
||||
@@ -69,17 +93,24 @@ export class HatGraphNode extends LitElement {
|
||||
`
|
||||
}
|
||||
<g class="node">
|
||||
<circle cx="0" cy="0" r=${NODE_SIZE / 2} />
|
||||
<rect
|
||||
x=${-size / 2}
|
||||
y=${-size / 2}
|
||||
width=${size}
|
||||
height=${size}
|
||||
rx=${this.buildingBlock ? BUILDING_BLOCK_RADIUS : NODE_RADIUS}
|
||||
transform=${this.buildingBlock ? "rotate(45)" : nothing}
|
||||
/>
|
||||
${
|
||||
this.error
|
||||
? svg`
|
||||
<g class="error">
|
||||
<circle
|
||||
cx="-12"
|
||||
cy=${-NODE_SIZE / 2}
|
||||
r="8"
|
||||
cx=${BADGE_X}
|
||||
cy=${BADGE_Y}
|
||||
r=${BADGE_RADIUS}
|
||||
></circle>
|
||||
<path transform="translate(-18 -21) scale(.5)" class="exclamation" d=${mdiExclamationThick}/>
|
||||
<path transform="translate(${BADGE_X - 6} ${BADGE_Y - 6}) scale(.5)" class="exclamation" d=${mdiExclamationThick}/>
|
||||
</g>
|
||||
`
|
||||
: nothing
|
||||
@@ -89,27 +120,46 @@ export class HatGraphNode extends LitElement {
|
||||
? svg`
|
||||
<g class="number">
|
||||
<circle
|
||||
cx="12"
|
||||
cy=${-NODE_SIZE / 2}
|
||||
r="8"
|
||||
cx="0"
|
||||
cy=${COUNT_BADGE_Y}
|
||||
r=${COUNT_BADGE_RADIUS}
|
||||
></circle>
|
||||
<text
|
||||
x="12"
|
||||
y=${-NODE_SIZE / 2}
|
||||
x="0"
|
||||
y=${COUNT_BADGE_Y}
|
||||
text-anchor="middle"
|
||||
alignment-baseline="middle"
|
||||
dominant-baseline="central"
|
||||
>${this.badge > 9 ? "9+" : this.badge}</text>
|
||||
</g>
|
||||
`
|
||||
: nothing
|
||||
}
|
||||
<g style="pointer-events: none" transform="translate(-12 -12)">
|
||||
<g
|
||||
class="icon-wrapper"
|
||||
style="pointer-events: none"
|
||||
transform="translate(-${iconSize / 2} -${iconSize / 2}) scale(${
|
||||
iconSize / ICON_SIZE
|
||||
})"
|
||||
>
|
||||
${
|
||||
this.iconPath
|
||||
? svg`<path class="icon" d=${this.iconPath}/>`
|
||||
: svg`<foreignObject><span class="icon"><slot name="icon"></slot></span></foreignObject>`
|
||||
}
|
||||
</g>
|
||||
${
|
||||
this.notEnabled
|
||||
? svg`
|
||||
<line
|
||||
class="strike"
|
||||
x1=${-iconSize / 2}
|
||||
y1="0"
|
||||
x2=${iconSize / 2}
|
||||
y2="0"
|
||||
/>
|
||||
`
|
||||
: nothing
|
||||
}
|
||||
</g>
|
||||
</svg>
|
||||
`;
|
||||
@@ -122,6 +172,11 @@ export class HatGraphNode extends LitElement {
|
||||
min-width: calc(var(--hat-graph-node-size) + var(--hat-graph-spacing));
|
||||
height: calc(var(--hat-graph-node-size) + var(--hat-graph-spacing) + 1px);
|
||||
}
|
||||
/* The count badge overlaps the next node's connector. */
|
||||
:host([badge]) {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
:host([graph-start]) {
|
||||
height: calc(var(--hat-graph-node-size) + 2px);
|
||||
}
|
||||
@@ -129,40 +184,81 @@ export class HatGraphNode extends LitElement {
|
||||
--stroke-clr: var(--track-clr);
|
||||
--icon-clr: var(--default-icon-clr);
|
||||
}
|
||||
:host([active]) circle {
|
||||
/* A step that raised is drawn red, but only the node itself: the run did
|
||||
reach it, so the connector above it stays on the tracked path colour. */
|
||||
:host([error]) {
|
||||
--icon-clr: var(--default-icon-clr);
|
||||
}
|
||||
:host([error]) rect {
|
||||
--stroke-clr: var(--error-color);
|
||||
}
|
||||
:host([active]) rect {
|
||||
--stroke-clr: var(--active-clr);
|
||||
--icon-clr: var(--default-icon-clr);
|
||||
stroke-width: 3;
|
||||
}
|
||||
:host(:focus) {
|
||||
outline: none;
|
||||
}
|
||||
:host(:hover) circle {
|
||||
:host(:hover) rect {
|
||||
--stroke-clr: var(--hover-clr);
|
||||
--icon-clr: var(--default-icon-clr);
|
||||
}
|
||||
:host([not-triggered]) circle {
|
||||
:host([not-triggered]) rect {
|
||||
stroke-dasharray: 4 3;
|
||||
}
|
||||
:host([not-enabled]) circle {
|
||||
--stroke-clr: var(--disabled-clr);
|
||||
:host([not-enabled]) {
|
||||
--stroke-clr: var(--ha-color-border-neutral-normal);
|
||||
--icon-clr: var(--ha-color-text-disabled);
|
||||
}
|
||||
:host([not-enabled][active]) circle {
|
||||
/* One step off the surface in whichever direction the theme runs: #e5e5e5
|
||||
on a white node body, #282828 on a near black one. */
|
||||
:host([not-enabled]) rect {
|
||||
fill: var(--secondary-background-color);
|
||||
}
|
||||
/* Not the whole node group: SVG composites group opacity as a unit, which
|
||||
would fade the error and count badges along with the rest. The body is
|
||||
left at full strength so the grey does not wash out. */
|
||||
:host([not-enabled]) .icon-wrapper,
|
||||
:host([not-enabled]) .strike {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.strike {
|
||||
stroke: var(--icon-clr);
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
:host([not-enabled][active]) rect {
|
||||
--stroke-clr: var(--disabled-active-clr);
|
||||
}
|
||||
:host([not-enabled]:hover) circle {
|
||||
:host([not-enabled]:hover) rect {
|
||||
--stroke-clr: var(--disabled-hover-clr);
|
||||
}
|
||||
/* Rotated building blocks and corner badges reach outside the node box. */
|
||||
svg {
|
||||
overflow: visible;
|
||||
}
|
||||
svg:not(.safari) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
circle,
|
||||
rect,
|
||||
path.connector {
|
||||
stroke: var(--stroke-clr);
|
||||
stroke-width: 2;
|
||||
fill: none;
|
||||
}
|
||||
circle {
|
||||
path.connector {
|
||||
stroke: var(--connector-clr, var(--stroke-clr));
|
||||
stroke-width: 1;
|
||||
stroke-dasharray: 4 3;
|
||||
}
|
||||
:host([track]) path.connector {
|
||||
stroke: var(--stroke-clr);
|
||||
stroke-width: 2;
|
||||
stroke-dasharray: none;
|
||||
}
|
||||
rect {
|
||||
fill: var(--background-clr);
|
||||
stroke: var(--circle-clr, var(--stroke-clr));
|
||||
}
|
||||
@@ -180,7 +276,7 @@ export class HatGraphNode extends LitElement {
|
||||
stroke-width: 0;
|
||||
}
|
||||
.number text {
|
||||
font-size: var(--ha-font-size-xs);
|
||||
font-size: var(--ha-font-size-s);
|
||||
fill: var(--text-primary-color);
|
||||
}
|
||||
path.icon {
|
||||
|
||||
@@ -38,12 +38,19 @@ export class HatGraphSpacer extends LitElement {
|
||||
:host([track]) {
|
||||
--stroke-clr: var(--track-clr);
|
||||
}
|
||||
:host([track]) path {
|
||||
stroke: var(--stroke-clr);
|
||||
stroke-width: 2;
|
||||
stroke-dasharray: none;
|
||||
}
|
||||
:host-context([disabled]) {
|
||||
--stroke-clr: var(--disabled-clr);
|
||||
}
|
||||
path {
|
||||
stroke: var(--stroke-clr);
|
||||
stroke-width: 2;
|
||||
stroke: var(--connector-clr, var(--stroke-clr));
|
||||
stroke-width: 1;
|
||||
stroke-dasharray: 4 3;
|
||||
stroke-dashoffset: 4px;
|
||||
fill: none;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -56,8 +56,8 @@ import {
|
||||
ACTION_BUILDING_BLOCKS,
|
||||
ACTION_COMBINED_BLOCKS,
|
||||
ACTION_ICONS,
|
||||
YAML_ONLY_ACTION_TYPES,
|
||||
getAutomationActionType,
|
||||
YAML_ONLY_ACTION_TYPES,
|
||||
} from "../../../../data/action";
|
||||
import type {
|
||||
ActionSidebarConfig,
|
||||
@@ -425,6 +425,16 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
: nothing
|
||||
}
|
||||
</h3>
|
||||
<ha-automation-row-event-chip
|
||||
.show=${this.action.enabled === false && !this._running}
|
||||
slot="event"
|
||||
variant="neutral"
|
||||
class="event-chip"
|
||||
aria-live="polite"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.actions.disabled")}
|
||||
</ha-automation-row-event-chip>
|
||||
|
||||
<ha-automation-row-event-chip
|
||||
.show=${this._running}
|
||||
.variant=${this._runResult?.variant}
|
||||
@@ -732,17 +742,6 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-card outlined>
|
||||
${
|
||||
this.action.enabled === false
|
||||
? html`
|
||||
<div class="disabled-bar">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.disabled"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.optionsInSidebar
|
||||
? html`<ha-automation-row
|
||||
|
||||
@@ -223,6 +223,16 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
: nothing
|
||||
}
|
||||
</ha-automation-condition-summary>
|
||||
<ha-automation-row-event-chip
|
||||
.show=${this.condition.enabled === false && !this._testing}
|
||||
slot="event"
|
||||
variant="neutral"
|
||||
class="event-chip"
|
||||
aria-live="polite"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.actions.disabled")}
|
||||
</ha-automation-row-event-chip>
|
||||
|
||||
<ha-automation-row-event-chip
|
||||
.show=${this._testing}
|
||||
.variant=${this._testingResult ? "success" : "warning"}
|
||||
@@ -506,17 +516,6 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
!this._collapsed,
|
||||
})}
|
||||
>
|
||||
${
|
||||
this.condition.enabled === false
|
||||
? html`
|
||||
<div class="disabled-bar">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.disabled"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.optionsInSidebar
|
||||
? html`<ha-automation-row
|
||||
|
||||
@@ -676,6 +676,7 @@ export class HaAutomationTrace extends LitElement {
|
||||
}
|
||||
|
||||
.graph {
|
||||
background-color: var(--primary-background-color);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -46,18 +46,6 @@ export const rowStyles = css`
|
||||
ha-card {
|
||||
transition: outline 0.2s;
|
||||
}
|
||||
.disabled-bar {
|
||||
background: var(--divider-color, #e0e0e0);
|
||||
text-align: center;
|
||||
border-top-right-radius: var(
|
||||
--ha-card-border-radius,
|
||||
var(--ha-border-radius-lg)
|
||||
);
|
||||
border-top-left-radius: var(
|
||||
--ha-card-border-radius,
|
||||
var(--ha-border-radius-lg)
|
||||
);
|
||||
}
|
||||
.warning ul {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
@query("ha-automation-row")
|
||||
private _automationRowElement?: HaAutomationRow;
|
||||
|
||||
@query("ha-automation-row-event-chip")
|
||||
@query(".triggered-chip")
|
||||
private _eventChipElement?: HaAutomationRowEventChip;
|
||||
|
||||
@storage({
|
||||
@@ -345,10 +345,24 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
: nothing
|
||||
}
|
||||
</h3>
|
||||
<ha-automation-row-event-chip
|
||||
.show=${
|
||||
"enabled" in this.trigger &&
|
||||
this.trigger.enabled === false &&
|
||||
!this._triggered
|
||||
}
|
||||
slot="event"
|
||||
variant="neutral"
|
||||
class="event-chip"
|
||||
aria-live="polite"
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.actions.disabled")}
|
||||
</ha-automation-row-event-chip>
|
||||
|
||||
<ha-automation-row-event-chip
|
||||
.show=${this._triggered}
|
||||
slot="event"
|
||||
class="event-chip"
|
||||
class="event-chip triggered-chip"
|
||||
interactive
|
||||
aria-live="polite"
|
||||
@click=${this._showTriggeredInfo}
|
||||
@@ -622,17 +636,6 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-card outlined class=${this._selected ? "selected" : ""}>
|
||||
${
|
||||
"enabled" in this.trigger && this.trigger.enabled === false
|
||||
? html`
|
||||
<div class="disabled-bar">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.disabled"
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: nothing
|
||||
}
|
||||
${
|
||||
this.optionsInSidebar
|
||||
? html`<ha-automation-row
|
||||
|
||||
@@ -652,6 +652,7 @@ export class HaScriptTrace extends LitElement {
|
||||
}
|
||||
|
||||
.graph {
|
||||
background-color: var(--primary-background-color);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { expect, it } from "vitest";
|
||||
import "../../src/components/trace/hat-graph-branch";
|
||||
|
||||
it("refreshes reused branch tracking and geometry without replacing the slot", async () => {
|
||||
const graph = document.createElement("hat-graph-branch");
|
||||
const branch = document.createElement("div");
|
||||
let height = 40;
|
||||
Object.defineProperties(branch, {
|
||||
clientWidth: { get: () => 50 },
|
||||
clientHeight: { get: () => height },
|
||||
});
|
||||
graph.append(branch);
|
||||
document.body.append(graph);
|
||||
try {
|
||||
await graph.updateComplete;
|
||||
await graph.updateComplete;
|
||||
expect(graph._branches[0]).toMatchObject({
|
||||
height: 40,
|
||||
track: false,
|
||||
trackEnd: false,
|
||||
});
|
||||
|
||||
branch.setAttribute("track", "");
|
||||
branch.setAttribute("unfinished", "");
|
||||
await Promise.resolve();
|
||||
await graph.updateComplete;
|
||||
expect(graph._branches[0]).toMatchObject({ track: true, trackEnd: false });
|
||||
|
||||
branch.removeAttribute("unfinished");
|
||||
height = 80;
|
||||
branch.append(document.createElement("div"));
|
||||
await Promise.resolve();
|
||||
await graph.updateComplete;
|
||||
expect(graph._branches[0]).toMatchObject({
|
||||
height: 80,
|
||||
track: true,
|
||||
trackEnd: true,
|
||||
});
|
||||
|
||||
branch.removeAttribute("track");
|
||||
await Promise.resolve();
|
||||
await graph.updateComplete;
|
||||
expect(graph._branches[0]).toMatchObject({ track: false, trackEnd: false });
|
||||
} finally {
|
||||
graph.remove();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user