mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-30 12:46:35 +00:00
WIP
This commit is contained in:
parent
b20d489bdd
commit
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
|
||||
>${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);
|
||||
|
||||
|
@ -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,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;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
`,
|
||||
|
Loading…
x
Reference in New Issue
Block a user