mirror of
https://github.com/home-assistant/frontend.git
synced 2026-05-27 19:47:13 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a15bfb4efe | |||
| 7454e856b2 | |||
| fa43ca949d | |||
| ac50ba4edc |
@@ -615,6 +615,7 @@ export interface BaseSidebarConfig {
|
||||
|
||||
export interface TriggerSidebarConfig extends BaseSidebarConfig {
|
||||
save: (value: Trigger) => void;
|
||||
editId: () => void;
|
||||
rename: () => void;
|
||||
disable: () => void;
|
||||
duplicate: () => void;
|
||||
|
||||
@@ -125,20 +125,15 @@ export const getTriggerInfos = (
|
||||
}
|
||||
const map = new Map<string, TriggerInfo>();
|
||||
for (const t of flattenTriggers(triggers)) {
|
||||
if (isTriggerList(t) || !t.id) {
|
||||
if (isTriggerList(t) || !t.id || map.get(t.id)) {
|
||||
continue;
|
||||
}
|
||||
const existing = map.get(t.id);
|
||||
if (existing) {
|
||||
existing.count++;
|
||||
} else {
|
||||
map.set(t.id, {
|
||||
id: t.id,
|
||||
label: describeTrigger(t, hass, entityRegistry),
|
||||
triggerType: t.trigger,
|
||||
count: 1,
|
||||
});
|
||||
}
|
||||
map.set(t.id, {
|
||||
id: t.id,
|
||||
label: describeTrigger(t, hass, entityRegistry),
|
||||
triggerType: t.trigger,
|
||||
count: 1,
|
||||
});
|
||||
}
|
||||
return Array.from(map.values());
|
||||
};
|
||||
|
||||
@@ -62,44 +62,6 @@ export const getTriggerIds = (triggers: Trigger[]): string[] =>
|
||||
.map((trigger) => trigger.id)
|
||||
.filter((id): id is string => !!id);
|
||||
|
||||
export const getNextNumericTriggerId = (triggers: Trigger[]): string => {
|
||||
let max = 0;
|
||||
for (const id of getTriggerIds(triggers)) {
|
||||
const num = Number(id);
|
||||
if (Number.isInteger(num) && num > max) {
|
||||
max = num;
|
||||
}
|
||||
}
|
||||
return String(max + 1);
|
||||
};
|
||||
|
||||
const computeUniqueId = (id: string, existing: Set<string>): string => {
|
||||
if (!existing.has(id)) {
|
||||
return id;
|
||||
}
|
||||
|
||||
// Split into a base and a trailing integer suffix so we can bump the
|
||||
// suffix on collision (e.g. "foo2" -> "foo3"); if there's no trailing
|
||||
// digit we start at 2 ("foo" -> "foo2").
|
||||
const match = id.match(/^(.*?)(\d+)$/);
|
||||
let base: string;
|
||||
let num: number;
|
||||
if (match) {
|
||||
base = match[1];
|
||||
num = Number(match[2]) + 1;
|
||||
} else {
|
||||
base = id;
|
||||
num = 2;
|
||||
}
|
||||
while (existing.has(`${base}${num}`)) {
|
||||
num++;
|
||||
}
|
||||
return `${base}${num}`;
|
||||
};
|
||||
|
||||
export const getUniqueTriggerId = (id: string, triggers: Trigger[]): string =>
|
||||
computeUniqueId(id, new Set(getTriggerIds(triggers)));
|
||||
|
||||
export interface TriggerDescription {
|
||||
target?: TargetSelector["target"];
|
||||
fields: Record<
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { consume } from "@lit/context";
|
||||
import {
|
||||
mdiAlert,
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiArrowDown,
|
||||
mdiArrowUp,
|
||||
@@ -588,9 +587,7 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
private _getTriggerInfos = memoizeOne(getTriggerInfos);
|
||||
|
||||
private _renderTriggerConditionDescription(condition: TriggerCondition) {
|
||||
const ids = ensureArray(condition.id ?? [])
|
||||
.map((id) => (typeof id === "string" ? id : String(id)))
|
||||
.filter((id) => id !== "");
|
||||
const ids = ensureArray(condition.id ?? []).filter((id) => id !== "");
|
||||
const prefix = capitalizeFirstLetter(
|
||||
this.hass
|
||||
.localize(
|
||||
@@ -608,77 +605,44 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const triggers = ensureArray(this._automationConfig?.triggers || []);
|
||||
|
||||
const triggerInfos = this._getTriggerInfos(
|
||||
ensureArray(this._automationConfig?.triggers || []),
|
||||
triggers,
|
||||
this.hass,
|
||||
this._entityReg
|
||||
);
|
||||
const infoById = new Map(triggerInfos.map((info) => [info.id, info]));
|
||||
return html`${prefix}
|
||||
${ids.map((id) => {
|
||||
const info = infoById.get(id);
|
||||
if (!info) {
|
||||
return html`<div class="trigger">
|
||||
<ha-trigger-id-chip id=${`trigger-${id}`} warning .triggerId=${id}>
|
||||
<ha-svg-icon slot="start" .path=${mdiAlert}></ha-svg-icon>
|
||||
</ha-trigger-id-chip>
|
||||
${ids.length < 4
|
||||
? html`<span
|
||||
>${this.hass.localize("state.default.unavailable")}</span
|
||||
>`
|
||||
: nothing}
|
||||
${ids
|
||||
.filter((id) => infoById.get(id))
|
||||
.map((id) => {
|
||||
const info = infoById.get(id)!;
|
||||
|
||||
<ha-tooltip .for=${`trigger-${id}`}>
|
||||
const triggerIcon = html`<ha-trigger-icon
|
||||
.slot=${ids.length < 4 ? "start" : ""}
|
||||
.hass=${this.hass}
|
||||
.trigger=${info.triggerType}
|
||||
></ha-trigger-icon>`;
|
||||
|
||||
return html`
|
||||
<div class="trigger">
|
||||
${ids.length < 4 ? triggerIcon : nothing}
|
||||
<ha-trigger-id-chip id=${`trigger-${id}`} .triggerId=${id}>
|
||||
</ha-trigger-id-chip>
|
||||
${ids.length < 4
|
||||
? html`<span>${info.label}</span>`
|
||||
: html`<ha-tooltip .for=${`trigger-${id}`}></ha-tooltip>`}
|
||||
${ids.length >= 4
|
||||
? html`<div>
|
||||
${this.hass.localize("state.default.unavailable")}
|
||||
</div>`
|
||||
? html`<ha-tooltip .for=${`trigger-${id}`}>
|
||||
${ids.length >= 4
|
||||
? html`<div>${triggerIcon}${info.label}</div>`
|
||||
: nothing}
|
||||
</ha-tooltip>`
|
||||
: nothing}
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.trigger.unavailable_info",
|
||||
{ id: html`<b>${id}</b>` }
|
||||
)}
|
||||
</ha-tooltip>
|
||||
</div>`;
|
||||
}
|
||||
const triggerIcon = html`<ha-trigger-icon
|
||||
.slot=${ids.length < 4 ? "start" : ""}
|
||||
.hass=${this.hass}
|
||||
.trigger=${info.triggerType}
|
||||
></ha-trigger-icon>`;
|
||||
|
||||
const isDuplicateId = info.count > 1;
|
||||
|
||||
return html`
|
||||
<div class="trigger">
|
||||
${ids.length < 4 ? triggerIcon : nothing}
|
||||
<ha-trigger-id-chip
|
||||
id=${`trigger-${id}`}
|
||||
.triggerId=${id}
|
||||
.warning=${isDuplicateId}
|
||||
>
|
||||
${isDuplicateId
|
||||
? html`<ha-svg-icon slot="start" .path=${mdiAlert}></ha-svg-icon>`
|
||||
: nothing}
|
||||
</ha-trigger-id-chip>
|
||||
${ids.length < 4
|
||||
? html`<span>${info.label}</span>`
|
||||
: html`<ha-tooltip .for=${`trigger-${id}`}></ha-tooltip>`}
|
||||
${isDuplicateId || ids.length >= 4
|
||||
? html`<ha-tooltip .for=${`trigger-${id}`}>
|
||||
${ids.length >= 4
|
||||
? html`<div>${triggerIcon}${info.label}</div>`
|
||||
: nothing}
|
||||
${isDuplicateId
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.duplicate_id_warning"
|
||||
)
|
||||
: nothing}
|
||||
</ha-tooltip>`
|
||||
: nothing}
|
||||
</div>
|
||||
`;
|
||||
})}`;
|
||||
</div>
|
||||
`;
|
||||
})}`;
|
||||
}
|
||||
|
||||
private _renderTargets = memoizeOne(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { consume } from "@lit/context";
|
||||
import { mdiAlert } from "@mdi/js";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { ensureArray } from "../../../../../common/array/ensure-array";
|
||||
@@ -63,8 +62,8 @@ export class HaTriggerCondition extends LitElement {
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const selectedIds = ensureArray(this.condition.id || []).filter(
|
||||
(id): id is string => typeof id === "string" && id !== ""
|
||||
const selectedIds: (string | number)[] = ensureArray(
|
||||
this.condition.id || []
|
||||
);
|
||||
|
||||
const triggerInfos = this._triggerInfos(
|
||||
@@ -89,43 +88,11 @@ export class HaTriggerCondition extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderOptions(selectedIds: string[], triggerInfos: TriggerInfo[]) {
|
||||
const unknownTriggerIds = selectedIds.filter(
|
||||
(id) => !triggerInfos.some((info) => info.id === id)
|
||||
);
|
||||
|
||||
const alertIcon = html`<ha-svg-icon
|
||||
slot="start"
|
||||
.path=${mdiAlert}
|
||||
></ha-svg-icon>`;
|
||||
|
||||
private _renderOptions(
|
||||
selectedIds: (string | number)[],
|
||||
triggerInfos: TriggerInfo[]
|
||||
) {
|
||||
return html`
|
||||
${unknownTriggerIds.map(
|
||||
(id) => html`
|
||||
<ha-list-item-option
|
||||
.value=${id}
|
||||
.selected=${true}
|
||||
appearance="checkbox"
|
||||
>
|
||||
<div class="option" slot="headline">
|
||||
<ha-trigger-id-chip
|
||||
id=${`trigger-${id}`}
|
||||
warning
|
||||
.triggerId=${id}
|
||||
>
|
||||
${alertIcon}
|
||||
</ha-trigger-id-chip>
|
||||
${this.hass.localize("state.default.unavailable")}
|
||||
<ha-tooltip .for=${`trigger-${id}`}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.trigger.unavailable_info",
|
||||
{ id: html`<b>${id}</b>` }
|
||||
)}
|
||||
</ha-tooltip>
|
||||
</div>
|
||||
</ha-list-item-option>
|
||||
`
|
||||
)}
|
||||
${triggerInfos.map(
|
||||
(info) => html`
|
||||
<ha-list-item-option
|
||||
@@ -136,18 +103,10 @@ export class HaTriggerCondition extends LitElement {
|
||||
<div class="option" slot="headline">
|
||||
<ha-trigger-id-chip
|
||||
id=${`trigger-${info.id}`}
|
||||
.warning=${info.count > 1}
|
||||
.triggerId=${info.id}
|
||||
>
|
||||
${info.count > 1 ? alertIcon : nothing}
|
||||
</ha-trigger-id-chip>
|
||||
${info.label}${info.count > 1
|
||||
? html`<ha-tooltip .for=${`trigger-${info.id}`}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.trigger.duplicated_info"
|
||||
)}</ha-tooltip
|
||||
>`
|
||||
: nothing}
|
||||
${info.label}
|
||||
</div>
|
||||
</ha-list-item-option>
|
||||
`
|
||||
|
||||
@@ -14,13 +14,15 @@ import {
|
||||
mdiStopCircleOutline,
|
||||
} from "@mdi/js";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { keyed } from "lit/directives/keyed";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { handleStructError } from "../../../../common/structs/handle-errors";
|
||||
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
|
||||
import "../../../../components/ha-dropdown-item";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import "../../../../components/ha-tooltip";
|
||||
import type {
|
||||
LegacyTrigger,
|
||||
Trigger,
|
||||
@@ -35,6 +37,7 @@ import {
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { isMac } from "../../../../util/is_mac";
|
||||
import "../ha-automation-comment";
|
||||
import "../ha-trigger-id-chip";
|
||||
import { overflowStyles, sidebarEditorStyles } from "../styles";
|
||||
import "../trigger/ha-automation-trigger-editor";
|
||||
import type HaAutomationTriggerEditor from "../trigger/ha-automation-trigger-editor";
|
||||
@@ -57,8 +60,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
@property({ type: Number, attribute: "sidebar-key" })
|
||||
public sidebarKey?: number;
|
||||
|
||||
@state() private _requestShowId = false;
|
||||
|
||||
@state() private _warnings?: string[];
|
||||
|
||||
@query(".sidebar-editor")
|
||||
@@ -66,7 +67,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues<this>) {
|
||||
if (changedProperties.has("config")) {
|
||||
this._requestShowId = false;
|
||||
this._warnings = undefined;
|
||||
if (this.config) {
|
||||
this.yamlMode = this.config.yamlMode;
|
||||
@@ -111,11 +111,21 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
@wa-select=${this._handleDropdownSelect}
|
||||
>
|
||||
<span slot="title">${title}</span>
|
||||
<span slot="subtitle"
|
||||
>${subtitle}${rowDisabled
|
||||
? ` (${this.hass.localize("ui.panel.config.automation.editor.actions.disabled")})`
|
||||
: ""}</span
|
||||
>
|
||||
<div slot="subtitle" class="subtitle">
|
||||
${subtitle}
|
||||
${"id" in this.config.config
|
||||
? html`<ha-trigger-id-chip
|
||||
id="trigger-id-chip"
|
||||
.triggerId=${(
|
||||
this.config.config as Exclude<Trigger, TriggerList>
|
||||
).id}
|
||||
>
|
||||
</ha-trigger-id-chip>`
|
||||
: nothing}
|
||||
${rowDisabled
|
||||
? `(${this.hass.localize("ui.panel.config.automation.editor.actions.disabled")})`
|
||||
: nothing}
|
||||
</div>
|
||||
<ha-dropdown-item
|
||||
slot="menu-items"
|
||||
value="rename"
|
||||
@@ -147,18 +157,16 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
</div>
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${!this.yamlMode &&
|
||||
!("id" in this.config.config) &&
|
||||
!this._requestShowId
|
||||
? html`<ha-dropdown-item
|
||||
${type !== "list"
|
||||
? html` <ha-dropdown-item
|
||||
slot="menu-items"
|
||||
value="show_id"
|
||||
value="edit_id"
|
||||
.disabled=${this.disabled || type === "list"}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiIdentifier}></ha-svg-icon>
|
||||
<div class="overflow-label">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.edit_id"
|
||||
`ui.panel.config.automation.editor.triggers.${"id" in this.config.config ? "edit" : "add"}_id`
|
||||
)}
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
@@ -335,7 +343,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
@value-changed=${this._valueChangedSidebar}
|
||||
@yaml-changed=${this._yamlChangedSidebar}
|
||||
.uiSupported=${this.config.uiSupported}
|
||||
.showId=${this._requestShowId}
|
||||
.yamlMode=${this.yamlMode}
|
||||
.disabled=${this.disabled}
|
||||
@ui-mode-not-available=${this._handleUiModeNotAvailable}
|
||||
@@ -386,10 +393,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
fireEvent(this, "toggle-yaml-mode");
|
||||
};
|
||||
|
||||
private _showTriggerId = () => {
|
||||
this._requestShowId = true;
|
||||
};
|
||||
|
||||
private _handleDropdownSelect(ev: HaDropdownSelectEvent) {
|
||||
const action = ev.detail?.item?.value;
|
||||
|
||||
@@ -404,8 +407,8 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
case "edit_comment":
|
||||
this.config.editComment();
|
||||
break;
|
||||
case "show_id":
|
||||
this._showTriggerId();
|
||||
case "edit_id":
|
||||
this.config.editId();
|
||||
break;
|
||||
case "duplicate":
|
||||
this.config.duplicate();
|
||||
@@ -431,7 +434,16 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
static styles = [sidebarEditorStyles, overflowStyles];
|
||||
static styles = [
|
||||
sidebarEditorStyles,
|
||||
overflowStyles,
|
||||
css`
|
||||
.subtitle {
|
||||
display: flex;
|
||||
gap: var(--ha-space-1);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
import { consume, type ContextType } from "@lit/context";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
import "../../../../components/ha-alert";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-dialog";
|
||||
import "../../../../components/ha-dialog-footer";
|
||||
import "../../../../components/input/ha-input";
|
||||
import type { HaInput } from "../../../../components/input/ha-input";
|
||||
import { internationalizationContext } from "../../../../data/context";
|
||||
import { DialogMixin } from "../../../../dialogs/dialog-mixin";
|
||||
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
import type { EditTriggerIdDialogParams } from "./show-edit-trigger-id";
|
||||
|
||||
@customElement("ha-automation-edit-trigger-id-dialog")
|
||||
class HaAutomationEditTriggerIdDialog extends DialogMixin<EditTriggerIdDialogParams>(
|
||||
LitElement
|
||||
) {
|
||||
@state() private _newId = "";
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
protected _i18n!: ContextType<typeof internationalizationContext>;
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._setInitialId();
|
||||
}
|
||||
|
||||
private _setInitialId() {
|
||||
if (this.params?.id) {
|
||||
this._newId = this.params.id;
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this.params) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const title = this._i18n.localize(
|
||||
`ui.panel.config.automation.editor.triggers.${
|
||||
this.params.id ? "edit_id" : "add_id"
|
||||
}`
|
||||
);
|
||||
|
||||
return html`
|
||||
<ha-dialog open header-title=${title}>
|
||||
<ha-input
|
||||
autofocus
|
||||
.label=${this._i18n.localize(
|
||||
"ui.panel.config.automation.editor.triggers.id"
|
||||
)}
|
||||
.value=${this._newId}
|
||||
@input=${this._idChanged}
|
||||
@keydown=${this._handleKeyDown}
|
||||
></ha-input>
|
||||
<ha-alert alert-type="info">
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.automation.editor.triggers.id_description"
|
||||
)}
|
||||
</ha-alert>
|
||||
<ha-dialog-footer slot="footer">
|
||||
<ha-button
|
||||
slot="secondaryAction"
|
||||
appearance="plain"
|
||||
@click=${this.closeDialog}
|
||||
>
|
||||
${this._i18n.localize("ui.common.cancel")}
|
||||
</ha-button>
|
||||
<ha-button slot="primaryAction" @click=${this._save}>
|
||||
${this._i18n.localize("ui.common.save")}
|
||||
</ha-button>
|
||||
</ha-dialog-footer>
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private _idChanged(ev: InputEvent) {
|
||||
const target = ev.target as HaInput;
|
||||
this._newId = target.value ?? "";
|
||||
}
|
||||
|
||||
private _handleKeyDown(ev: KeyboardEvent) {
|
||||
if (ev.key === "Enter") {
|
||||
ev.preventDefault();
|
||||
this._save();
|
||||
}
|
||||
}
|
||||
|
||||
private _save(): void {
|
||||
const trimmed = this._newId.trim();
|
||||
this.params!.onUpdate(trimmed || undefined);
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-input {
|
||||
width: 100%;
|
||||
}
|
||||
ha-alert {
|
||||
display: block;
|
||||
margin-top: var(--ha-space-6);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-edit-trigger-id-dialog": HaAutomationEditTriggerIdDialog;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import { dynamicElement } from "../../../../common/dom/dynamic-element-directive
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-yaml-editor";
|
||||
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||
import "../../../../components/input/ha-input";
|
||||
import type { Trigger } from "../../../../data/automation";
|
||||
import { migrateAutomationTrigger } from "../../../../data/automation";
|
||||
import type { TriggerDescription } from "../../../../data/trigger";
|
||||
@@ -31,8 +30,6 @@ export default class HaAutomationTriggerEditor extends LitElement {
|
||||
|
||||
@property({ type: Boolean, attribute: "sidebar" }) public inSidebar = false;
|
||||
|
||||
@property({ type: Boolean, attribute: "show-id" }) public showId = false;
|
||||
|
||||
@property({ attribute: false }) public description?: TriggerDescription;
|
||||
|
||||
@query("ha-yaml-editor") public yamlEditor?: HaYamlEditor;
|
||||
@@ -42,8 +39,6 @@ export default class HaAutomationTriggerEditor extends LitElement {
|
||||
|
||||
const yamlMode = this.yamlMode || !this.uiSupported;
|
||||
|
||||
const showId = "id" in this.trigger || this.showId;
|
||||
|
||||
return html`
|
||||
<div
|
||||
class=${classMap({
|
||||
@@ -77,18 +72,6 @@ export default class HaAutomationTriggerEditor extends LitElement {
|
||||
></ha-yaml-editor>
|
||||
`
|
||||
: html`
|
||||
${showId && !isTriggerList(this.trigger)
|
||||
? html`
|
||||
<ha-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.id"
|
||||
)}
|
||||
.value=${this.trigger.id || ""}
|
||||
.disabled=${this.disabled}
|
||||
@change=${this._idChanged}
|
||||
></ha-input>
|
||||
`
|
||||
: nothing}
|
||||
<div @value-changed=${this._onUiChanged}>
|
||||
${this.description
|
||||
? html`<ha-automation-trigger-platform
|
||||
@@ -108,24 +91,6 @@ export default class HaAutomationTriggerEditor extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _idChanged(ev: CustomEvent) {
|
||||
if (isTriggerList(this.trigger)) return;
|
||||
const newId = (ev.target as any).value;
|
||||
|
||||
if (newId === (this.trigger.id ?? "")) {
|
||||
return;
|
||||
}
|
||||
const value = { ...this.trigger };
|
||||
if (!newId) {
|
||||
delete value.id;
|
||||
} else {
|
||||
value.id = newId;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value,
|
||||
});
|
||||
}
|
||||
|
||||
private _onYamlChange(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
if (!ev.detail.isValid) {
|
||||
@@ -160,9 +125,6 @@ export default class HaAutomationTriggerEditor extends LitElement {
|
||||
border-top: 1px solid var(--divider-color);
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
}
|
||||
ha-input {
|
||||
margin-bottom: var(--ha-space-3);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { consume } from "@lit/context";
|
||||
import {
|
||||
mdiAlert,
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiArrowDown,
|
||||
mdiArrowUp,
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
mdiContentPaste,
|
||||
mdiDelete,
|
||||
mdiDotsVertical,
|
||||
mdiIdentifier,
|
||||
mdiPlayCircleOutline,
|
||||
mdiPlaylistEdit,
|
||||
mdiPlusCircleMultipleOutline,
|
||||
@@ -29,7 +29,6 @@ import { customElement, property, query, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { ensureArray } from "../../../../common/array/ensure-array";
|
||||
import { storage } from "../../../../common/decorators/storage";
|
||||
import { transform } from "../../../../common/decorators/transform";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { preventDefaultStopPropagation } from "../../../../common/dom/prevent_default_stop_propagation";
|
||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||
@@ -54,17 +53,12 @@ import "../../../../components/ha-tooltip";
|
||||
import { TRIGGER_ICONS } from "../../../../components/ha-trigger-icon";
|
||||
import type {
|
||||
AutomationClipboard,
|
||||
AutomationConfig,
|
||||
PlatformTrigger,
|
||||
Trigger,
|
||||
TriggerList,
|
||||
TriggerSidebarConfig,
|
||||
} from "../../../../data/automation";
|
||||
import {
|
||||
automationConfigContext,
|
||||
isTrigger,
|
||||
subscribeTrigger,
|
||||
} from "../../../../data/automation";
|
||||
import { isTrigger, subscribeTrigger } from "../../../../data/automation";
|
||||
import { describeTrigger } from "../../../../data/automation_i18n";
|
||||
import { validateConfig } from "../../../../data/config";
|
||||
import { fullEntitiesContext } from "../../../../data/context";
|
||||
@@ -86,6 +80,7 @@ import { overflowStyles, rowStyles } from "../styles";
|
||||
import "../target/ha-automation-row-targets";
|
||||
import "./ha-automation-trigger-editor";
|
||||
import type HaAutomationTriggerEditor from "./ha-automation-trigger-editor";
|
||||
import { showEditTriggerIdDialog } from "./show-edit-trigger-id";
|
||||
import "./types/ha-automation-trigger-calendar";
|
||||
import "./types/ha-automation-trigger-conversation";
|
||||
import "./types/ha-automation-trigger-device";
|
||||
@@ -187,30 +182,6 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
_entityReg: EntityRegistryEntry[] = [];
|
||||
|
||||
@state()
|
||||
@consume({ context: automationConfigContext, subscribe: true })
|
||||
@transform<AutomationConfig, boolean>({
|
||||
transformer: function (this: HaAutomationTriggerRow, value) {
|
||||
if (
|
||||
!this.trigger ||
|
||||
isTriggerList(this.trigger) ||
|
||||
!(this.trigger as Exclude<Trigger, TriggerList>).id
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const triggerId = (this.trigger as Exclude<Trigger, TriggerList>).id;
|
||||
// count how often this trigger id is used in the automation, if more than once, show warning
|
||||
return (
|
||||
ensureArray(value?.triggers || []).filter(
|
||||
(trigger) =>
|
||||
(trigger as Exclude<Trigger, TriggerList>).id === triggerId
|
||||
).length > 1
|
||||
);
|
||||
},
|
||||
watch: ["trigger"],
|
||||
})
|
||||
private _duplicateTriggerId = false;
|
||||
|
||||
get selected() {
|
||||
return this._selected;
|
||||
}
|
||||
@@ -279,25 +250,11 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
<h3 slot="header">
|
||||
${type !== "list" && (this.trigger as Exclude<Trigger, TriggerList>).id
|
||||
? html`<ha-trigger-id-chip
|
||||
id="trigger-id-chip"
|
||||
.warning=${this._duplicateTriggerId}
|
||||
slot="leading-icon"
|
||||
.triggerId=${(this.trigger as Exclude<Trigger, TriggerList>).id}
|
||||
>
|
||||
${this._duplicateTriggerId
|
||||
? html`<ha-svg-icon
|
||||
slot="start"
|
||||
.path=${mdiAlert}
|
||||
></ha-svg-icon>`
|
||||
: nothing}
|
||||
</ha-trigger-id-chip>
|
||||
${this._duplicateTriggerId
|
||||
? html`<ha-tooltip for="trigger-id-chip">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.duplicate_id_warning"
|
||||
)}
|
||||
</ha-tooltip>`
|
||||
: nothing} `
|
||||
id="trigger-id-chip"
|
||||
slot="leading-icon"
|
||||
.triggerId=${(this.trigger as Exclude<Trigger, TriggerList>).id}
|
||||
>
|
||||
</ha-trigger-id-chip>`
|
||||
: nothing}
|
||||
${describeTrigger(this.trigger, this.hass, this._entityReg)}
|
||||
${target !== undefined || (descriptionHasTarget && !this._isNew)
|
||||
@@ -376,6 +333,17 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${type !== "list"
|
||||
? html`<ha-dropdown-item value="edit_id" .disabled=${this.disabled}>
|
||||
<ha-svg-icon slot="icon" .path=${mdiIdentifier}></ha-svg-icon>
|
||||
<div class="overflow-label">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.triggers.${"id" in this.trigger ? "edit" : "add"}_id`
|
||||
)}
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
<wa-divider></wa-divider>
|
||||
|
||||
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
|
||||
@@ -749,6 +717,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
this.focus();
|
||||
}
|
||||
},
|
||||
editId: this._editTriggerId,
|
||||
rename: () => {
|
||||
this._renameTrigger();
|
||||
},
|
||||
@@ -860,6 +829,34 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _editTriggerId = () => {
|
||||
if (isTriggerList(this.trigger)) {
|
||||
return;
|
||||
}
|
||||
const trigger = this.trigger as Exclude<Trigger, TriggerList>;
|
||||
showEditTriggerIdDialog(this, {
|
||||
id: trigger.id,
|
||||
onUpdate: (newId) => {
|
||||
if (newId === (trigger.id ?? undefined)) {
|
||||
return;
|
||||
}
|
||||
const value: Trigger = { ...trigger };
|
||||
if (newId) {
|
||||
value.id = newId;
|
||||
} else {
|
||||
delete value.id;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value,
|
||||
});
|
||||
|
||||
if (this._selected && this.optionsInSidebar) {
|
||||
this.openSidebar(value); // refresh sidebar
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
private _renameTrigger = async (): Promise<void> => {
|
||||
if (isTriggerList(this.trigger)) return;
|
||||
const alias = await showPromptDialog(this, {
|
||||
@@ -1044,6 +1041,9 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
case "edit_comment":
|
||||
this._editCommentTrigger();
|
||||
break;
|
||||
case "edit_id":
|
||||
this._editTriggerId();
|
||||
break;
|
||||
case "duplicate":
|
||||
this._duplicateTrigger();
|
||||
break;
|
||||
|
||||
@@ -22,12 +22,7 @@ import {
|
||||
} from "../../../../data/automation";
|
||||
import { subscribeLabFeature } from "../../../../data/labs";
|
||||
import type { TriggerDescriptions } from "../../../../data/trigger";
|
||||
import {
|
||||
getNextNumericTriggerId,
|
||||
getUniqueTriggerId,
|
||||
isTriggerList,
|
||||
subscribeTriggers,
|
||||
} from "../../../../data/trigger";
|
||||
import { isTriggerList, subscribeTriggers } from "../../../../data/trigger";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
import { EDITOR_SAVE_FAB_TOAST_BOTTOM_OFFSET } from "../editor-toast";
|
||||
import { AutomationSortableListMixin } from "../ha-automation-sortable-list-mixin";
|
||||
@@ -76,11 +71,6 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
|
||||
protected override pasteItem(ev: CustomEvent) {
|
||||
if (this.root && ev.detail.item) {
|
||||
const pasted = deepClone(ev.detail.item) as Trigger;
|
||||
if (!isTriggerList(pasted)) {
|
||||
pasted.id = pasted.id
|
||||
? getUniqueTriggerId(pasted.id, this.triggers)
|
||||
: getNextNumericTriggerId(this.triggers);
|
||||
}
|
||||
ev.detail.item = pasted;
|
||||
}
|
||||
super.pasteItem(ev);
|
||||
@@ -91,11 +81,6 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
|
||||
const incoming = ensureArray(ev.detail.value) as Trigger[];
|
||||
if (this.root && incoming.length === 1) {
|
||||
const trigger = deepClone(incoming[0]);
|
||||
if (!isTriggerList(trigger)) {
|
||||
trigger.id = trigger.id
|
||||
? getUniqueTriggerId(trigger.id, this.triggers)
|
||||
: getNextNumericTriggerId(this.triggers);
|
||||
}
|
||||
ev.detail.value = trigger;
|
||||
}
|
||||
super.insertAfter(ev);
|
||||
@@ -105,11 +90,6 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
|
||||
if (this.root) {
|
||||
const index = (ev.target as any).index;
|
||||
const duplicated = deepClone(this.triggers[index]);
|
||||
if (!isTriggerList(duplicated)) {
|
||||
duplicated.id = duplicated.id
|
||||
? getUniqueTriggerId(duplicated.id, this.triggers)
|
||||
: getNextNumericTriggerId(this.triggers);
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
// @ts-expect-error Requires library bump to ES2023
|
||||
value: this.triggers.toSpliced(index + 1, 0, duplicated),
|
||||
@@ -267,11 +247,6 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
|
||||
let triggers: Trigger[];
|
||||
if (value === PASTE_VALUE) {
|
||||
const pasted = deepClone(this._clipboard!.trigger!);
|
||||
if (this.root && !isTriggerList(pasted)) {
|
||||
pasted.id = pasted.id
|
||||
? getUniqueTriggerId(pasted.id, this.triggers)
|
||||
: getNextNumericTriggerId(this.triggers);
|
||||
}
|
||||
triggers = this.triggers.concat(pasted);
|
||||
} else {
|
||||
let newTrigger: Trigger;
|
||||
@@ -292,9 +267,6 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
|
||||
...(target?.entity_id ? { entity_id: target.entity_id } : {}),
|
||||
};
|
||||
}
|
||||
if (this.root && !isTriggerList(newTrigger)) {
|
||||
newTrigger.id = getNextNumericTriggerId(this.triggers);
|
||||
}
|
||||
triggers = this.triggers.concat(newTrigger);
|
||||
}
|
||||
this.focusLastItemOnChange = true;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { LitElement } from "lit";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
|
||||
export const loadEditTriggerIdDialog = () =>
|
||||
import("./ha-automation-edit-trigger-id-dialog");
|
||||
|
||||
export interface EditTriggerIdDialogParams {
|
||||
id?: string;
|
||||
onUpdate: (newId: string | undefined) => void;
|
||||
}
|
||||
|
||||
export const showEditTriggerIdDialog = (
|
||||
element: LitElement,
|
||||
dialogParams: EditTriggerIdDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
parentElement: element,
|
||||
dialogTag: "ha-automation-edit-trigger-id-dialog",
|
||||
dialogImport: loadEditTriggerIdDialog,
|
||||
dialogParams,
|
||||
});
|
||||
};
|
||||
@@ -5164,9 +5164,10 @@
|
||||
},
|
||||
"id": "Trigger ID",
|
||||
"optional": "Optional",
|
||||
"edit_id": "Edit ID",
|
||||
"add_id": "Add trigger ID",
|
||||
"edit_id": "Edit trigger ID",
|
||||
"id_description": "Use trigger IDs in a Triggered by condition to run different actions depending on which trigger started the automation.",
|
||||
"duplicate": "[%key:ui::common::duplicate%]",
|
||||
"duplicate_id_warning": "This trigger ID is used multiple times in this automation. Trigger IDs should be unique.",
|
||||
"re_order": "Re-order",
|
||||
"rename": "Rename",
|
||||
"cut": "Cut",
|
||||
@@ -5592,8 +5593,6 @@
|
||||
"trigger": {
|
||||
"label": "Triggered by",
|
||||
"no_triggers": "There are no triggers with ID's set in this automation. Edit a trigger and give it a Trigger ID name.",
|
||||
"duplicated_info": "This ID is used by multiple triggers. Trigger IDs should be unique.",
|
||||
"unavailable_info": "No trigger has the ID {id}. Set this ID on a trigger to use it.",
|
||||
"id": "Trigger",
|
||||
"description": {
|
||||
"picker": "Tests if the automation has been triggered by a specific trigger.",
|
||||
|
||||
Reference in New Issue
Block a user