This commit is contained in:
Bram Kragten 2025-07-29 09:35:33 +02:00
parent b20d489bdd
commit d74fe9f012
12 changed files with 778 additions and 275 deletions

View File

@ -0,0 +1,138 @@
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import "./ha-svg-icon";
@customElement("ha-automation-row")
export class HaAutomationRow extends LitElement {
@property() header?: string;
@property() secondary?: string;
protected render(): TemplateResult {
return html`
<div class="top">
<div
id="summary"
@click=${this._toggleContainer}
@keydown=${this._toggleContainer}
role="button"
>
<slot name="leading-icon"></slot>
<slot name="header">
<div class="header">
${this.header}
<slot class="secondary" name="secondary">${this.secondary}</slot>
</div>
</slot>
<slot name="icons"></slot>
</div>
</div>
`;
}
private async _toggleContainer(ev): Promise<void> {
if (ev.defaultPrevented) {
return;
}
if (ev.type === "keydown" && ev.key !== "Enter" && ev.key !== " ") {
return;
}
ev.preventDefault();
this.click();
}
static styles = css`
:host {
display: block;
}
.top {
display: flex;
align-items: center;
border-radius: var(--ha-card-border-radius, 12px);
}
.top.expanded {
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
.top.focused {
background: var(--input-fill-color);
}
:host([outlined]) {
box-shadow: none;
border-width: 1px;
border-style: solid;
border-color: var(--outline-color);
border-radius: var(--ha-card-border-radius, 12px);
}
.summary-icon {
transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
direction: var(--direction);
margin-left: 8px;
margin-inline-start: 8px;
margin-inline-end: initial;
}
:host([left-chevron]) .summary-icon,
::slotted([slot="leading-icon"]) {
margin-left: 0;
margin-right: 8px;
margin-inline-start: 0;
margin-inline-end: 8px;
}
#summary {
flex: 1;
display: flex;
padding: var(--expansion-panel-summary-padding, 0 8px);
min-height: 48px;
align-items: center;
cursor: pointer;
overflow: hidden;
font-weight: var(--ha-font-weight-medium);
outline: none;
}
#summary.noCollapse {
cursor: default;
}
.summary-icon.expanded {
transform: rotate(180deg);
}
.header,
::slotted([slot="header"]) {
flex: 1;
overflow-wrap: anywhere;
}
.container {
padding: var(--expansion-panel-content-padding, 0 8px);
overflow: hidden;
transition: height 300ms cubic-bezier(0.4, 0, 0.2, 1);
height: 0px;
}
.container.expanded {
height: auto;
}
.secondary {
display: block;
color: var(--secondary-text-color);
font-size: var(--ha-font-size-s);
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-row": HaAutomationRow;
}
}

View File

@ -55,7 +55,11 @@ class HassSubpage extends LitElement {
<div class="main-title"><slot name="header">${this.header}</slot></div>
<slot name="toolbar-icon"></slot>
</div>
<div class="content ha-scrollbar" @scroll=${this._saveScrollPos}>
<div
class="content ha-scrollbar"
@scroll=${this._saveScrollPos}
@scroll-to=${this._scrollTo}
>
<slot></slot>
</div>
<div id="fab">
@ -69,6 +73,15 @@ class HassSubpage extends LitElement {
this._savedScrollPos = (e.target as HTMLDivElement).scrollTop;
}
private _scrollTo(e: CustomEvent<{ up: number }>): void {
this.renderRoot
.querySelector(".content")!
.scrollTo(
0,
e.detail.up + this.renderRoot.querySelector(".content")?.scrollTop
);
}
private _backTapped(): void {
if (this.backCallback) {
this.backCallback();

View File

@ -203,7 +203,7 @@ export default class HaAutomationActionRow extends LitElement {
</div>
`
: nothing}
<ha-expansion-panel left-chevron>
<ha-automation-row>
${type === "service" && "action" in this.action && this.action.action
? html`
<ha-service-icon
@ -328,16 +328,6 @@ export default class HaAutomationActionRow extends LitElement {
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
.disabled=${!this._uiModeAvailable}
>
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!yamlMode ? "yaml" : "ui"}`
)}
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
@ -430,7 +420,7 @@ export default class HaAutomationActionRow extends LitElement {
</div>
`}
</div>
</ha-expansion-panel>
</ha-automation-row>
</ha-card>
`;
}
@ -676,8 +666,8 @@ export default class HaAutomationActionRow extends LitElement {
}
:host([highlight]) ha-card {
--shadow-default: var(--ha-card-box-shadow, 0 0 0 0 transparent);
--shadow-focus: 0 0 0 1px var(--state-inactive-color);
border-color: var(--state-inactive-color);
--shadow-focus: 0 0 0 1px var(--primary-color);
border-color: var(--primary-color);
box-shadow: var(--shadow-default), var(--shadow-focus);
}
`,

View File

@ -93,6 +93,7 @@ export default class HaAutomationAction extends LitElement {
@move-down=${this._moveDown}
@move-up=${this._moveUp}
@value-changed=${this._actionChanged}
@click=${this._actionClicked}
.hass=${this.hass}
?highlight=${this.highlightedActions?.includes(action)}
>
@ -102,8 +103,74 @@ export default class HaAutomationAction extends LitElement {
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
</div>
`
: nothing} </ha-automation-action-row
>${Object.keys(action)[0] === "choose"
? html`<div
style="padding-left: 24px; border-left: 1px solid var(--primary-color);"
>
<ha-card outlined
><ha-automation-row>
<h3
slot="header"
style=" margin: 0;
font-size: inherit;
font-weight: inherit;"
>
Option 1:
</h3>
</ha-automation-row></ha-card
>
<div
style="padding-left: 24px; border-left: 1px solid var(--primary-color); margin-top: 8px;"
>
<ha-automation-condition></ha-automation-condition>
<ha-button
outlined
style=" padding: 16px 0; padding-top: 8px;"
.disabled=${this.disabled}
.label=${"Condition"}
>
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
</ha-button>
<ha-card style=" padding: 0 16px;
padding-top: 8px;"
>Actions</br>
<ha-button
style=" padding: 16px 0;"
outlined
.disabled=${this.disabled}
.label=${"Action"}
>
<ha-svg-icon
.path=${mdiPlus}
slot="icon"
></ha-svg-icon> </ha-button
></ha-card>
</div>
<ha-button
outlined
style=" padding: 16px 0;"
.disabled=${this.disabled}
.label=${"Option"}
>
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
</ha-button>
<ha-card style=" padding: 0 16px;
padding-top: 8px;"
>Default actions</br>
<ha-button
style=" padding: 16px 0;"
outlined
.disabled=${this.disabled}
.label=${"Action"}
>
<ha-svg-icon
.path=${mdiPlus}
slot="icon"
></ha-svg-icon></ha-button
></ha-card>
</div>`
: nothing}
</ha-automation-action-row>
`
)}
<div class="buttons">
@ -132,6 +199,15 @@ export default class HaAutomationAction extends LitElement {
`;
}
private _actionClicked(ev: MouseEvent) {
fireEvent(this, "element-selected", {
type: "action",
element: (ev.currentTarget as HaAutomationActionRow).action,
index: (ev.currentTarget as HaAutomationActionRow).index,
path: (ev.currentTarget as HaAutomationActionRow).path,
});
}
protected updated(changedProps: PropertyValues) {
super.updated(changedProps);

View File

@ -128,7 +128,7 @@ export default class HaAutomationConditionRow extends LitElement {
`
: ""}
<ha-expansion-panel left-chevron>
<ha-automation-row>
<ha-svg-icon
slot="leading-icon"
class="condition-icon"
@ -225,16 +225,6 @@ export default class HaAutomationConditionRow extends LitElement {
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
.disabled=${this._warnings}
>
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this._yamlMode ? "yaml" : "ui"}`
)}
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
@ -297,16 +287,8 @@ export default class HaAutomationConditionRow extends LitElement {
)}
</ha-alert>`
: ""}
<ha-automation-condition-editor
@ui-mode-not-available=${this._handleUiModeNotAvailable}
@value-changed=${this._handleChangeEvent}
.yamlMode=${this._yamlMode}
.disabled=${this.disabled}
.hass=${this.hass}
.condition=${this.condition}
></ha-automation-condition-editor>
</div>
</ha-expansion-panel>
</ha-automation-row>
<div
class="testing ${classMap({
active: this._testing,
@ -589,8 +571,8 @@ export default class HaAutomationConditionRow extends LitElement {
}
:host([highlight]) ha-card {
--shadow-default: var(--ha-card-box-shadow, 0 0 0 0 transparent);
--shadow-focus: 0 0 0 1px var(--state-inactive-color);
border-color: var(--state-inactive-color);
--shadow-focus: 0 0 0 1px var(--primary-color);
border-color: var(--primary-color);
box-shadow: var(--shadow-default), var(--shadow-focus);
}
`,

View File

@ -142,6 +142,7 @@ export default class HaAutomationCondition extends LitElement {
@move-down=${this._moveDown}
@move-up=${this._moveUp}
@value-changed=${this._conditionChanged}
@click=${this._conditionClicked}
.hass=${this.hass}
?highlight=${this.highlightedConditions?.includes(cond)}
>
@ -181,6 +182,15 @@ export default class HaAutomationCondition extends LitElement {
`;
}
private _conditionClicked(ev: MouseEvent) {
fireEvent(this, "element-selected", {
type: "condition",
element: (ev.currentTarget as HaAutomationConditionRow).condition,
index: (ev.currentTarget as HaAutomationConditionRow).index,
path: (ev.currentTarget as HaAutomationConditionRow).path,
});
}
private _addConditionDialog() {
showAddAutomationElementDialog(this, {
type: "condition",

View File

@ -1092,7 +1092,6 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
flex-direction: column;
padding-bottom: 0;
}
manual-automation-editor,
blueprint-automation-editor,
:not(.yaml-mode) > ha-alert {
margin: 0 auto;
@ -1100,6 +1099,12 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
padding: 28px 20px 0;
display: block;
}
manual-automation-editor {
margin: 0 auto;
max-width: 1540px;
padding: 28px 20px 0;
display: block;
}
ha-yaml-editor {
flex-grow: 1;
--actions-border-radius: 0;

View File

@ -1,5 +1,11 @@
import "@material/mwc-button/mwc-button";
import { mdiHelpCircle } from "@mdi/js";
import {
mdiClose,
mdiDotsVertical,
mdiHelpCircle,
mdiIdentifier,
mdiPlaylistEdit,
} from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { CSSResultGroup, PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
@ -49,6 +55,51 @@ import { constructUrlCurrentPath } from "../../../common/url/construct-url";
import { canOverrideAlphanumericInput } from "../../../common/dom/can-override-input";
import { showToast } from "../../../util/toast";
import { showPasteReplaceDialog } from "./paste-replace-dialog/show-dialog-paste-replace";
import "@shoelace-style/shoelace/dist/components/split-panel/split-panel";
import "@shoelace-style/shoelace/dist/components/drawer/drawer";
import { dynamicElement } from "../../../common/dom/dynamic-element-directive";
import { classMap } from "lit/directives/class-map";
import { getType } from "./action/ha-automation-action-row";
import { storage } from "../../../common/decorators/storage";
import { nextRender } from "../../../common/util/render-status";
import {
DIRECTION_ALL,
DIRECTION_VERTICAL,
Manager,
Pan,
Swipe,
} from "@egjs/hammerjs";
function findNestedItem(
obj: any,
path: ItemPath,
createNonExistingPath?: boolean
): any {
return path.reduce((ac, p, index, array) => {
if (ac === undefined) return undefined;
if (!ac[p] && createNonExistingPath) {
const nextP = array[index + 1];
// Create object or array depending on next path
if (nextP === undefined || typeof nextP === "number") {
ac[p] = [];
} else {
ac[p] = {};
}
}
return ac[p];
}, obj);
}
function updateNestedItem(obj: any, path: ItemPath, newValue): any {
const lastKey = path.pop()!;
const parent = findNestedItem(obj, path);
parent[lastKey] = newValue
? newValue
: Array.isArray(parent[lastKey])
? [...parent[lastKey]]
: [parent[lastKey]];
return obj;
}
const baseConfigStruct = object({
alias: optional(string()),
@ -85,6 +136,14 @@ export class HaManualAutomationEditor extends LitElement {
@state() private _pastedConfig?: ManualAutomationConfig;
@state() private _selectedElement?: any;
@state()
@storage({ key: "automationSidebarPosition" })
private _sidebarWidth = 99999;
@state() private _yamlMode = false;
private _previousConfig?: ManualAutomationConfig;
public connectedCallback() {
@ -114,6 +173,13 @@ export class HaManualAutomationEditor extends LitElement {
}
}
protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);
if (changedProps.has("narrow") && this.narrow && this._selectedElement) {
this.renderRoot.querySelector("sl-drawer").show();
}
}
private _clearParam(param: string) {
window.history.replaceState(
null,
@ -123,7 +189,139 @@ export class HaManualAutomationEditor extends LitElement {
}
protected render() {
const selectedElement = this._selectedElement?.element;
const selectedElementType = this._selectedElement?.type;
const path = this._selectedElement?.path || [];
const type = "";
const supported = true;
const yamlMode = this._yamlMode;
const sidePanel = this._selectedElement
? html`<ha-dialog-header>
<ha-icon-button
slot="navigationIcon"
.label=${this.hass.localize("ui.common.close")}
.path=${mdiClose}
@click=${this._closeSidebar}
></ha-icon-button>
<span slot="title">${`Edit ${selectedElementType}`}</span>
<ha-button-menu slot="actionItems" fixed>
<ha-icon-button
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
${selectedElementType === "trigger"
? html`<ha-md-menu-item
.clickAction=${this._showTriggerId}
.disabled=${this.disabled || type === "list"}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.edit_id"
)}
<ha-svg-icon
slot="start"
.path=${mdiIdentifier}
></ha-svg-icon>
</ha-md-menu-item>`
: nothing}
<ha-md-menu-item
@click=${this._toggleYamlMode}
.disabled=${!supported}
>
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!yamlMode ? "yaml" : "ui"}`
)}
<ha-svg-icon
slot="start"
.path=${mdiPlaylistEdit}
></ha-svg-icon>
</ha-md-menu-item>
</ha-button-menu>
</ha-dialog-header>
<div
class=${classMap({
"card-content": true,
disabled:
"enabled" in this._selectedElement &&
this._selectedElement.enabled === false,
})}
>
${this._yamlMode
? html`<ha-yaml-editor
.hass=${this.hass}
.defaultValue=${selectedElement}
.readOnly=${this.disabled}
@value-changed=${this._onYamlChange}
></ha-yaml-editor>`
: selectedElementType === "trigger"
? html`<div
@ui-mode-not-available=${this._handleUiModeNotAvailable}
@value-changed=${this._onUiChanged}
.path=${path}
>
${dynamicElement(
`ha-automation-trigger-${selectedElement.trigger}`,
{
hass: this.hass,
trigger: selectedElement,
disabled: this.disabled,
}
)}
</div>`
: selectedElementType === "condition"
? html`<ha-automation-condition-editor
@ui-mode-not-available=${this._handleUiModeNotAvailable}
@value-changed=${this._onUiChanged}
.path=${path}
.yamlMode=${this._yamlMode}
.disabled=${this.disabled}
.hass=${this.hass}
.condition=${selectedElement}
></ha-automation-condition-editor>`
: selectedElementType === "action"
? html`<div
@ui-mode-not-available=${this._handleUiModeNotAvailable}
@value-changed=${this._onUiChanged}
.path=${path}
>
${dynamicElement(
`ha-automation-action-${getType(selectedElement)}`,
{
hass: this.hass,
action: selectedElement,
narrow: true,
disabled: this.disabled,
}
)}
</div>`
: nothing}
</div>`
: nothing;
return html`
${this.narrow
? html`<sl-drawer
no-header
placement="bottom"
class="drawer-placement-bottom"
@sl-show=${this._drawerOpen}
@sl-hide=${this._drawerClose}
>
${sidePanel}
</sl-drawer>`
: nothing}
<sl-split-panel
primary="start"
.positionInPixels=${selectedElement && !this.narrow
? this.clientWidth - 40 - this._sidebarWidth || 99999
: 0}
style=${selectedElement && !this.narrow
? "--min: 300px; --max: calc(100% - 300px); --divider-width: 32px;"
: "--min: 100%; --max: 100%;"}
@sl-reposition=${this._splitPanelRepositioned}
>
<div slot="start" style="overflow: auto; height: 100%">
${this.stateObj?.state === "off"
? html`
<ha-alert alert-type="info">
@ -176,11 +374,14 @@ export class HaManualAutomationEditor extends LitElement {
role="region"
aria-labelledby="triggers-heading"
.triggers=${this.config.triggers || []}
.highlightedTriggers=${this._pastedConfig?.triggers || []}
.highlightedTriggers=${this._pastedConfig?.triggers || [
selectedElement,
]}
.path=${["triggers"]}
@value-changed=${this._triggerChanged}
.hass=${this.hass}
.disabled=${this.disabled}
@element-selected=${this._elementSelected}
></ha-automation-trigger>
<div class="header">
@ -218,11 +419,14 @@ export class HaManualAutomationEditor extends LitElement {
role="region"
aria-labelledby="conditions-heading"
.conditions=${this.config.conditions || []}
.highlightedConditions=${this._pastedConfig?.conditions || []}
.highlightedConditions=${this._pastedConfig?.conditions || [
selectedElement,
]}
.path=${["conditions"]}
@value-changed=${this._conditionChanged}
.hass=${this.hass}
.disabled=${this.disabled}
@element-selected=${this._elementSelected}
></ha-automation-condition>
<div class="header">
@ -258,16 +462,138 @@ export class HaManualAutomationEditor extends LitElement {
role="region"
aria-labelledby="actions-heading"
.actions=${this.config.actions || []}
.highlightedActions=${this._pastedConfig?.actions || []}
.highlightedActions=${this._pastedConfig?.actions || [
selectedElement,
]}
.path=${["actions"]}
@value-changed=${this._actionChanged}
.hass=${this.hass}
.narrow=${this.narrow}
.disabled=${this.disabled}
@element-selected=${this._elementSelected}
></ha-automation-action>
</div>
${!this.narrow && selectedElement
? html`<ha-card
slot="end"
style="--ha-card-border-color: var(--primary-color); --ha-card-border-width: 2px;"
>
${sidePanel}
</ha-card>`
: nothing}
</sl-split-panel>
`;
}
private _onUiChanged(ev: CustomEvent): void {
ev.stopPropagation();
const path = ev.currentTarget?.path || [];
const newConfig = updateNestedItem(
{ ...this.config },
path,
ev.detail.value
);
console.log(newConfig);
fireEvent(this, "value-changed", { value: newConfig });
}
private async _toggleYamlMode() {
this._yamlMode = !this._yamlMode;
if (this._yamlMode) {
await this.updateComplete;
// this.renderRoot.querySelector("ha-yaml-editor").positionInPixels = 0;
}
}
private async _elementSelected(ev) {
console.log(ev);
this._selectedElement = ev.detail;
console.log("repo", this._sidebarWidth);
const target = ev.target;
await this.updateComplete;
this.renderRoot.querySelector("sl-split-panel").positionInPixels =
this.clientWidth - 40 - this._sidebarWidth;
if (this.narrow) {
this.renderRoot.querySelector("sl-drawer").show();
console.log(target);
this._targetEl = target;
}
}
private _splitPanelRepositioned(ev: CustomEvent): void {
if (!this._selectedElement) {
return;
}
console.log(ev);
console.log("reposition", ev.target.positionInPixels);
let sidebarWidth = ev.target.clientWidth - ev.target.positionInPixels;
if (this._oldClientWidth && this._oldClientWidth !== this.clientWidth) {
// If the client width has changed, we need to subtract the difference
sidebarWidth = sidebarWidth + (this._oldClientWidth - this.clientWidth);
}
this._oldClientWidth = this.clientWidth;
console.log(sidebarWidth);
console.log(this.clientWidth);
console.log(this.clientWidth - 40 - sidebarWidth);
// if (Math.abs(sidebarWidth - this._sidebarWidth) > 20) {
// this._sidebarWidth = sidebarWidth;
// }
this._sidebarWidth = sidebarWidth;
}
private _closeSidebar() {
if (this.narrow) {
this.renderRoot.querySelector("sl-drawer").hide();
}
this._selectedElement = undefined;
}
private async _drawerOpen() {
// this._oldScrollPosition = window.scrollY;
this.renderRoot.querySelector("div[slot='start']").style.paddingBottom =
"66vh";
await nextRender();
fireEvent(this, "scroll-to", {
up: this._targetEl.getBoundingClientRect().top,
});
this._setupListeners();
}
private _setupListeners() {
const mc = new Manager(this.renderRoot.querySelector("ha-dialog-header"), {
touchAction: "pan-y",
});
mc.add(
new Swipe({
direction: DIRECTION_VERTICAL,
})
);
mc.on("swipeup", (e) => {
console.log("up", e);
this.toggleAttribute("big-drawer", true);
});
mc.on("swipedown", (e) => {
console.log("down", e);
if (this.hasAttribute("big-drawer")) {
this.toggleAttribute("big-drawer", false);
} else {
this.renderRoot.querySelector("sl-drawer").hide();
}
});
this._manager = mc;
}
private _drawerClose() {
this.renderRoot.querySelector("div[slot='start']").style.paddingBottom =
"0";
}
private _triggerChanged(ev: CustomEvent): void {
ev.stopPropagation();
this.resetPastedConfig();
@ -552,6 +878,45 @@ export class HaManualAutomationEditor extends LitElement {
font-weight: var(--ha-font-weight-normal);
line-height: 0;
}
sl-split-panel {
height: calc(100vh - var(--header-height, 64px) - 28px - 20px - 1px);
}
sl-drawer {
--sl-z-index-drawer: 9999;
--size: 66vh;
--sl-panel-background-color: var(--ha-card-background, white);
--sl-overlay-background-color: rgba(0, 0, 0, 0.32);
--sl-shadow-x-large: var(
--ha-card-box-shadow,
0px -1px 4px 1px rgba(0, 0, 0, 0.2),
0px 1px 1px 0px rgba(0, 0, 0, 0.14),
0px 1px 3px 0px rgba(0, 0, 0, 0.12)
);
--sl-panel-border-color: var(--ha-card-border-color, #e0e0e0);
}
:host([big-drawer]) sl-drawer {
--size: 90vh;
}
sl-drawer::part(panel) {
border-radius: 12px 12px 0 0;
border: 1px solid var(--ha-card-border-color, #e0e0e0);
}
sl-drawer .card-content {
padding: 12px;
}
sl-drawer ha-dialog-header {
position: sticky;
top: 0;
background: var(--card-background-color);
z-index: 999;
}
.card-content {
overflow: auto;
height: 100%;
padding-bottom: 16px;
}
`,
];
}

View File

@ -70,6 +70,7 @@ import "./types/ha-automation-trigger-time";
import "./types/ha-automation-trigger-time_pattern";
import "./types/ha-automation-trigger-webhook";
import "./types/ha-automation-trigger-zone";
import "../../../../components/ha-automation-row";
export interface TriggerElement extends LitElement {
trigger: Trigger;
@ -158,7 +159,7 @@ export default class HaAutomationTriggerRow extends LitElement {
`
: nothing}
<ha-expansion-panel left-chevron>
<ha-automation-row>
<ha-svg-icon
slot="leading-icon"
class="trigger-icon"
@ -193,16 +194,6 @@ export default class HaAutomationTriggerRow extends LitElement {
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._showTriggerId}
.disabled=${this.disabled || type === "list"}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.edit_id"
)}
<ha-svg-icon slot="start" .path=${mdiIdentifier}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
@ -256,16 +247,6 @@ export default class HaAutomationTriggerRow extends LitElement {
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
.disabled=${!supported}
>
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!yamlMode ? "yaml" : "ui"}`
)}
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
@ -302,77 +283,7 @@ export default class HaAutomationTriggerRow extends LitElement {
></ha-svg-icon>
</ha-md-menu-item>
</ha-md-button-menu>
<div
class=${classMap({
"card-content": true,
disabled:
"enabled" in this.trigger && this.trigger.enabled === false,
})}
>
${this._warnings
? html`<ha-alert
alert-type="warning"
.title=${this.hass.localize(
"ui.errors.config.editor_not_supported"
)}
>
${this._warnings.length && this._warnings[0] !== undefined
? html` <ul>
${this._warnings.map(
(warning) => html`<li>${warning}</li>`
)}
</ul>`
: ""}
${this.hass.localize(
"ui.errors.config.edit_in_yaml_supported"
)}
</ha-alert>`
: ""}
${yamlMode
? html`
${!supported
? html`
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.unsupported_platform",
{ platform: type }
)}
`
: ""}
<ha-yaml-editor
.hass=${this.hass}
.defaultValue=${this.trigger}
.readOnly=${this.disabled}
@value-changed=${this._onYamlChange}
></ha-yaml-editor>
`
: html`
${showId && !isTriggerList(this.trigger)
? html`
<ha-textfield
.label=${this.hass.localize(
"ui.panel.config.automation.editor.triggers.id"
)}
.value=${this.trigger.id || ""}
.disabled=${this.disabled}
@change=${this._idChanged}
>
</ha-textfield>
`
: ""}
<div
@ui-mode-not-available=${this._handleUiModeNotAvailable}
@value-changed=${this._onUiChanged}
>
${dynamicElement(`ha-automation-trigger-${type}`, {
hass: this.hass,
trigger: this.trigger,
disabled: this.disabled,
})}
</div>
`}
</div>
</ha-expansion-panel>
</ha-automation-row>
<div
class="triggered ${classMap({
@ -740,8 +651,8 @@ export default class HaAutomationTriggerRow extends LitElement {
}
:host([highlight]) ha-card {
--shadow-default: var(--ha-card-box-shadow, 0 0 0 0 transparent);
--shadow-focus: 0 0 0 1px var(--state-inactive-color);
border-color: var(--state-inactive-color);
--shadow-focus: 0 0 0 1px var(--primary-color);
border-color: var(--primary-color);
box-shadow: var(--shadow-default), var(--shadow-focus);
}
`,

View File

@ -34,6 +34,8 @@ export default class HaAutomationTrigger extends LitElement {
@property({ attribute: false }) public highlightedTriggers?: Trigger[];
@property({ type: Array }) public path?: ItemPath;
@property({ type: Boolean }) public disabled = false;
@state() private _showReorder = false;
@ -89,10 +91,12 @@ export default class HaAutomationTrigger extends LitElement {
.first=${idx === 0}
.last=${idx === this.triggers.length - 1}
.trigger=${trg}
.path=${[...(this.path ?? []), idx]}
@duplicate=${this._duplicateTrigger}
@move-down=${this._moveDown}
@move-up=${this._moveUp}
@value-changed=${this._triggerChanged}
@click=${this._triggerClicked}
.hass=${this.hass}
.disabled=${this.disabled}
?highlight=${this.highlightedTriggers?.includes(trg)}
@ -136,6 +140,15 @@ export default class HaAutomationTrigger extends LitElement {
});
}
private _triggerClicked(ev: MouseEvent) {
fireEvent(this, "element-selected", {
type: "trigger",
element: (ev.currentTarget as HaAutomationTriggerRow).trigger,
index: (ev.currentTarget as HaAutomationTriggerRow).index,
path: (ev.currentTarget as HaAutomationTriggerRow).path,
});
}
private _addTrigger = (value: string) => {
let triggers: Trigger[];
if (value === PASTE_VALUE) {

View File

@ -156,7 +156,7 @@ class ZHADeviceCard extends SubscribeMixin(LitElement) {
newName = name.replace(oldDeviceName, newDeviceName);
}
if (newName !== undefined && !newEntityId) {
if (newName === undefined && !newEntityId) {
return undefined;
}

View File

@ -355,8 +355,8 @@ export default class HaScriptFieldRow extends LitElement {
}
:host([highlight]) ha-card {
--shadow-default: var(--ha-card-box-shadow, 0 0 0 0 transparent);
--shadow-focus: 0 0 0 1px var(--state-inactive-color);
border-color: var(--state-inactive-color);
--shadow-focus: 0 0 0 1px var(--primary-color);
border-color: var(--primary-color);
box-shadow: var(--shadow-default), var(--shadow-focus);
}
`,