mirror of
				https://github.com/home-assistant/frontend.git
				synced 2025-11-04 00:19:47 +00:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			20251001.2
			...
			automation
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d74fe9f012 | 
							
								
								
									
										138
									
								
								src/components/ha-automation-row.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/components/ha-automation-row.ts
									
									
									
									
									
										Normal 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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
      `,
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
                  : 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}
 | 
			
		||||
            `
 | 
			
		||||
          )}
 | 
			
		||||
          <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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
      `,
 | 
			
		||||
 
 | 
			
		||||
@@ -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",
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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,151 +189,411 @@ export class HaManualAutomationEditor extends LitElement {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected render() {
 | 
			
		||||
    return html`
 | 
			
		||||
      ${this.stateObj?.state === "off"
 | 
			
		||||
        ? html`
 | 
			
		||||
            <ha-alert alert-type="info">
 | 
			
		||||
              ${this.hass.localize(
 | 
			
		||||
                "ui.panel.config.automation.editor.disabled"
 | 
			
		||||
              )}
 | 
			
		||||
              <mwc-button slot="action" @click=${this._enable}>
 | 
			
		||||
                ${this.hass.localize(
 | 
			
		||||
                  "ui.panel.config.automation.editor.enable"
 | 
			
		||||
                )}
 | 
			
		||||
              </mwc-button>
 | 
			
		||||
            </ha-alert>
 | 
			
		||||
          `
 | 
			
		||||
        : nothing}
 | 
			
		||||
      ${this.config.description
 | 
			
		||||
        ? html`<ha-markdown
 | 
			
		||||
            class="description"
 | 
			
		||||
            breaks
 | 
			
		||||
            .content=${this.config.description}
 | 
			
		||||
          ></ha-markdown>`
 | 
			
		||||
        : nothing}
 | 
			
		||||
      <div class="header">
 | 
			
		||||
        <h2 id="triggers-heading" class="name">
 | 
			
		||||
          ${this.hass.localize(
 | 
			
		||||
            "ui.panel.config.automation.editor.triggers.header"
 | 
			
		||||
          )}
 | 
			
		||||
        </h2>
 | 
			
		||||
        <a
 | 
			
		||||
          href=${documentationUrl(this.hass, "/docs/automation/trigger/")}
 | 
			
		||||
          target="_blank"
 | 
			
		||||
          rel="noreferrer"
 | 
			
		||||
        >
 | 
			
		||||
          <ha-icon-button
 | 
			
		||||
            .path=${mdiHelpCircle}
 | 
			
		||||
            .label=${this.hass.localize(
 | 
			
		||||
              "ui.panel.config.automation.editor.triggers.learn_more"
 | 
			
		||||
            )}
 | 
			
		||||
          ></ha-icon-button>
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
      ${!ensureArray(this.config.triggers)?.length
 | 
			
		||||
        ? html`<p>
 | 
			
		||||
            ${this.hass.localize(
 | 
			
		||||
              "ui.panel.config.automation.editor.triggers.description"
 | 
			
		||||
            )}
 | 
			
		||||
          </p>`
 | 
			
		||||
        : nothing}
 | 
			
		||||
    const selectedElement = this._selectedElement?.element;
 | 
			
		||||
    const selectedElementType = this._selectedElement?.type;
 | 
			
		||||
    const path = this._selectedElement?.path || [];
 | 
			
		||||
 | 
			
		||||
      <ha-automation-trigger
 | 
			
		||||
        role="region"
 | 
			
		||||
        aria-labelledby="triggers-heading"
 | 
			
		||||
        .triggers=${this.config.triggers || []}
 | 
			
		||||
        .highlightedTriggers=${this._pastedConfig?.triggers || []}
 | 
			
		||||
        .path=${["triggers"]}
 | 
			
		||||
        @value-changed=${this._triggerChanged}
 | 
			
		||||
        .hass=${this.hass}
 | 
			
		||||
        .disabled=${this.disabled}
 | 
			
		||||
      ></ha-automation-trigger>
 | 
			
		||||
    const type = "";
 | 
			
		||||
    const supported = true;
 | 
			
		||||
    const yamlMode = this._yamlMode;
 | 
			
		||||
 | 
			
		||||
      <div class="header">
 | 
			
		||||
        <h2 id="conditions-heading" class="name">
 | 
			
		||||
          ${this.hass.localize(
 | 
			
		||||
            "ui.panel.config.automation.editor.conditions.header"
 | 
			
		||||
          )}
 | 
			
		||||
          <span class="small"
 | 
			
		||||
            >(${this.hass.localize("ui.common.optional")})</span
 | 
			
		||||
          >
 | 
			
		||||
        </h2>
 | 
			
		||||
        <a
 | 
			
		||||
          href=${documentationUrl(this.hass, "/docs/automation/condition/")}
 | 
			
		||||
          target="_blank"
 | 
			
		||||
          rel="noreferrer"
 | 
			
		||||
        >
 | 
			
		||||
          <ha-icon-button
 | 
			
		||||
            .path=${mdiHelpCircle}
 | 
			
		||||
            .label=${this.hass.localize(
 | 
			
		||||
              "ui.panel.config.automation.editor.conditions.learn_more"
 | 
			
		||||
            )}
 | 
			
		||||
          ></ha-icon-button>
 | 
			
		||||
        </a>
 | 
			
		||||
      </div>
 | 
			
		||||
      ${!ensureArray(this.config.conditions)?.length
 | 
			
		||||
        ? html`<p>
 | 
			
		||||
            ${this.hass.localize(
 | 
			
		||||
              "ui.panel.config.automation.editor.conditions.description",
 | 
			
		||||
              { user: this.hass.user?.name || "Alice" }
 | 
			
		||||
            )}
 | 
			
		||||
          </p>`
 | 
			
		||||
        : nothing}
 | 
			
		||||
 | 
			
		||||
      <ha-automation-condition
 | 
			
		||||
        role="region"
 | 
			
		||||
        aria-labelledby="conditions-heading"
 | 
			
		||||
        .conditions=${this.config.conditions || []}
 | 
			
		||||
        .highlightedConditions=${this._pastedConfig?.conditions || []}
 | 
			
		||||
        .path=${["conditions"]}
 | 
			
		||||
        @value-changed=${this._conditionChanged}
 | 
			
		||||
        .hass=${this.hass}
 | 
			
		||||
        .disabled=${this.disabled}
 | 
			
		||||
      ></ha-automation-condition>
 | 
			
		||||
 | 
			
		||||
      <div class="header">
 | 
			
		||||
        <h2 id="actions-heading" class="name">
 | 
			
		||||
          ${this.hass.localize(
 | 
			
		||||
            "ui.panel.config.automation.editor.actions.header"
 | 
			
		||||
          )}
 | 
			
		||||
        </h2>
 | 
			
		||||
        <div>
 | 
			
		||||
          <a
 | 
			
		||||
            href=${documentationUrl(this.hass, "/docs/automation/action/")}
 | 
			
		||||
            target="_blank"
 | 
			
		||||
            rel="noreferrer"
 | 
			
		||||
          >
 | 
			
		||||
    const sidePanel = this._selectedElement
 | 
			
		||||
      ? html`<ha-dialog-header>
 | 
			
		||||
            <ha-icon-button
 | 
			
		||||
              .path=${mdiHelpCircle}
 | 
			
		||||
              .label=${this.hass.localize(
 | 
			
		||||
                "ui.panel.config.automation.editor.actions.learn_more"
 | 
			
		||||
              )}
 | 
			
		||||
              slot="navigationIcon"
 | 
			
		||||
              .label=${this.hass.localize("ui.common.close")}
 | 
			
		||||
              .path=${mdiClose}
 | 
			
		||||
              @click=${this._closeSidebar}
 | 
			
		||||
            ></ha-icon-button>
 | 
			
		||||
          </a>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      ${!ensureArray(this.config.actions)?.length
 | 
			
		||||
        ? html`<p>
 | 
			
		||||
            ${this.hass.localize(
 | 
			
		||||
              "ui.panel.config.automation.editor.actions.description"
 | 
			
		||||
            )}
 | 
			
		||||
          </p>`
 | 
			
		||||
        : nothing}
 | 
			
		||||
            <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;
 | 
			
		||||
 | 
			
		||||
      <ha-automation-action
 | 
			
		||||
        role="region"
 | 
			
		||||
        aria-labelledby="actions-heading"
 | 
			
		||||
        .actions=${this.config.actions || []}
 | 
			
		||||
        .highlightedActions=${this._pastedConfig?.actions || []}
 | 
			
		||||
        .path=${["actions"]}
 | 
			
		||||
        @value-changed=${this._actionChanged}
 | 
			
		||||
        .hass=${this.hass}
 | 
			
		||||
        .narrow=${this.narrow}
 | 
			
		||||
        .disabled=${this.disabled}
 | 
			
		||||
      ></ha-automation-action>
 | 
			
		||||
    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">
 | 
			
		||||
                  ${this.hass.localize(
 | 
			
		||||
                    "ui.panel.config.automation.editor.disabled"
 | 
			
		||||
                  )}
 | 
			
		||||
                  <mwc-button slot="action" @click=${this._enable}>
 | 
			
		||||
                    ${this.hass.localize(
 | 
			
		||||
                      "ui.panel.config.automation.editor.enable"
 | 
			
		||||
                    )}
 | 
			
		||||
                  </mwc-button>
 | 
			
		||||
                </ha-alert>
 | 
			
		||||
              `
 | 
			
		||||
            : nothing}
 | 
			
		||||
          ${this.config.description
 | 
			
		||||
            ? html`<ha-markdown
 | 
			
		||||
                class="description"
 | 
			
		||||
                breaks
 | 
			
		||||
                .content=${this.config.description}
 | 
			
		||||
              ></ha-markdown>`
 | 
			
		||||
            : nothing}
 | 
			
		||||
          <div class="header">
 | 
			
		||||
            <h2 id="triggers-heading" class="name">
 | 
			
		||||
              ${this.hass.localize(
 | 
			
		||||
                "ui.panel.config.automation.editor.triggers.header"
 | 
			
		||||
              )}
 | 
			
		||||
            </h2>
 | 
			
		||||
            <a
 | 
			
		||||
              href=${documentationUrl(this.hass, "/docs/automation/trigger/")}
 | 
			
		||||
              target="_blank"
 | 
			
		||||
              rel="noreferrer"
 | 
			
		||||
            >
 | 
			
		||||
              <ha-icon-button
 | 
			
		||||
                .path=${mdiHelpCircle}
 | 
			
		||||
                .label=${this.hass.localize(
 | 
			
		||||
                  "ui.panel.config.automation.editor.triggers.learn_more"
 | 
			
		||||
                )}
 | 
			
		||||
              ></ha-icon-button>
 | 
			
		||||
            </a>
 | 
			
		||||
          </div>
 | 
			
		||||
          ${!ensureArray(this.config.triggers)?.length
 | 
			
		||||
            ? html`<p>
 | 
			
		||||
                ${this.hass.localize(
 | 
			
		||||
                  "ui.panel.config.automation.editor.triggers.description"
 | 
			
		||||
                )}
 | 
			
		||||
              </p>`
 | 
			
		||||
            : nothing}
 | 
			
		||||
 | 
			
		||||
          <ha-automation-trigger
 | 
			
		||||
            role="region"
 | 
			
		||||
            aria-labelledby="triggers-heading"
 | 
			
		||||
            .triggers=${this.config.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">
 | 
			
		||||
            <h2 id="conditions-heading" class="name">
 | 
			
		||||
              ${this.hass.localize(
 | 
			
		||||
                "ui.panel.config.automation.editor.conditions.header"
 | 
			
		||||
              )}
 | 
			
		||||
              <span class="small"
 | 
			
		||||
                >(${this.hass.localize("ui.common.optional")})</span
 | 
			
		||||
              >
 | 
			
		||||
            </h2>
 | 
			
		||||
            <a
 | 
			
		||||
              href=${documentationUrl(this.hass, "/docs/automation/condition/")}
 | 
			
		||||
              target="_blank"
 | 
			
		||||
              rel="noreferrer"
 | 
			
		||||
            >
 | 
			
		||||
              <ha-icon-button
 | 
			
		||||
                .path=${mdiHelpCircle}
 | 
			
		||||
                .label=${this.hass.localize(
 | 
			
		||||
                  "ui.panel.config.automation.editor.conditions.learn_more"
 | 
			
		||||
                )}
 | 
			
		||||
              ></ha-icon-button>
 | 
			
		||||
            </a>
 | 
			
		||||
          </div>
 | 
			
		||||
          ${!ensureArray(this.config.conditions)?.length
 | 
			
		||||
            ? html`<p>
 | 
			
		||||
                ${this.hass.localize(
 | 
			
		||||
                  "ui.panel.config.automation.editor.conditions.description",
 | 
			
		||||
                  { user: this.hass.user?.name || "Alice" }
 | 
			
		||||
                )}
 | 
			
		||||
              </p>`
 | 
			
		||||
            : nothing}
 | 
			
		||||
 | 
			
		||||
          <ha-automation-condition
 | 
			
		||||
            role="region"
 | 
			
		||||
            aria-labelledby="conditions-heading"
 | 
			
		||||
            .conditions=${this.config.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">
 | 
			
		||||
            <h2 id="actions-heading" class="name">
 | 
			
		||||
              ${this.hass.localize(
 | 
			
		||||
                "ui.panel.config.automation.editor.actions.header"
 | 
			
		||||
              )}
 | 
			
		||||
            </h2>
 | 
			
		||||
            <div>
 | 
			
		||||
              <a
 | 
			
		||||
                href=${documentationUrl(this.hass, "/docs/automation/action/")}
 | 
			
		||||
                target="_blank"
 | 
			
		||||
                rel="noreferrer"
 | 
			
		||||
              >
 | 
			
		||||
                <ha-icon-button
 | 
			
		||||
                  .path=${mdiHelpCircle}
 | 
			
		||||
                  .label=${this.hass.localize(
 | 
			
		||||
                    "ui.panel.config.automation.editor.actions.learn_more"
 | 
			
		||||
                  )}
 | 
			
		||||
                ></ha-icon-button>
 | 
			
		||||
              </a>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          ${!ensureArray(this.config.actions)?.length
 | 
			
		||||
            ? html`<p>
 | 
			
		||||
                ${this.hass.localize(
 | 
			
		||||
                  "ui.panel.config.automation.editor.actions.description"
 | 
			
		||||
                )}
 | 
			
		||||
              </p>`
 | 
			
		||||
            : nothing}
 | 
			
		||||
 | 
			
		||||
          <ha-automation-action
 | 
			
		||||
            role="region"
 | 
			
		||||
            aria-labelledby="actions-heading"
 | 
			
		||||
            .actions=${this.config.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;
 | 
			
		||||
        }
 | 
			
		||||
      `,
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
      `,
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -156,7 +156,7 @@ class ZHADeviceCard extends SubscribeMixin(LitElement) {
 | 
			
		||||
        newName = name.replace(oldDeviceName, newDeviceName);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (newName !== undefined && !newEntityId) {
 | 
			
		||||
      if (newName === undefined && !newEntityId) {
 | 
			
		||||
        return undefined;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
      `,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user