mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add for_each to repeat action UI. Convert repeat to ha-form (#17688)
* Add for_each to repeat action UI. Convert repeat to ha-form * reordermode as a selector option * css styling
This commit is contained in:
parent
fc1782e676
commit
f68823a09e
@ -1,4 +1,4 @@
|
||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { Action } from "../../data/script";
|
||||
import { ActionSelector } from "../../data/selector";
|
||||
@ -19,10 +19,13 @@ export class HaActionSelector extends LitElement {
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
${this.label ? html`<label>${this.label}</label>` : nothing}
|
||||
<ha-automation-action
|
||||
.disabled=${this.disabled}
|
||||
.actions=${this.value || []}
|
||||
.hass=${this.hass}
|
||||
.nested=${this.selector.action?.nested}
|
||||
.reOrderMode=${this.selector.action?.reorder_mode}
|
||||
></ha-automation-action>
|
||||
`;
|
||||
}
|
||||
@ -37,6 +40,11 @@ export class HaActionSelector extends LitElement {
|
||||
opacity: var(--light-disabled-opacity);
|
||||
pointer-events: none;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { Condition } from "../../data/automation";
|
||||
import { ConditionSelector } from "../../data/selector";
|
||||
@ -19,10 +19,13 @@ export class HaConditionSelector extends LitElement {
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
${this.label ? html`<label>${this.label}</label>` : nothing}
|
||||
<ha-automation-condition
|
||||
.disabled=${this.disabled}
|
||||
.conditions=${this.value || []}
|
||||
.hass=${this.hass}
|
||||
.nested=${this.selector.condition?.nested}
|
||||
.reOrderMode=${this.selector.condition?.reorder_mode}
|
||||
></ha-automation-condition>
|
||||
`;
|
||||
}
|
||||
@ -37,6 +40,11 @@ export class HaConditionSelector extends LitElement {
|
||||
opacity: var(--light-disabled-opacity);
|
||||
pointer-events: none;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -54,8 +54,10 @@ export type Selector =
|
||||
| UiColorSelector;
|
||||
|
||||
export interface ActionSelector {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
action: {} | null;
|
||||
action: {
|
||||
reorder_mode?: boolean;
|
||||
nested?: boolean;
|
||||
} | null;
|
||||
}
|
||||
|
||||
export interface AddonSelector {
|
||||
@ -98,8 +100,10 @@ export interface ColorTempSelector {
|
||||
}
|
||||
|
||||
export interface ConditionSelector {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
condition: {} | null;
|
||||
condition: {
|
||||
reorder_mode?: boolean;
|
||||
nested?: boolean;
|
||||
} | null;
|
||||
}
|
||||
|
||||
export interface ConversationAgentSelector {
|
||||
|
@ -1,21 +1,19 @@
|
||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/ha-textfield";
|
||||
import {
|
||||
Action,
|
||||
CountRepeat,
|
||||
RepeatAction,
|
||||
UntilRepeat,
|
||||
WhileRepeat,
|
||||
} from "../../../../../data/script";
|
||||
import { RepeatAction } from "../../../../../data/script";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import type { Condition } from "../../../../lovelace/common/validate-condition";
|
||||
import "../ha-automation-action";
|
||||
import type { ActionElement } from "../ha-automation-action-row";
|
||||
|
||||
const OPTIONS = ["count", "while", "until"] as const;
|
||||
import type { LocalizeFunc } from "../../../../../common/translations/localize";
|
||||
import "../../../../../components/ha-form/ha-form";
|
||||
import type { SchemaUnion } from "../../../../../components/ha-form/types";
|
||||
|
||||
const OPTIONS = ["count", "while", "until", "for_each"] as const;
|
||||
|
||||
const getType = (action) => OPTIONS.find((option) => option in action);
|
||||
|
||||
@ -33,144 +31,115 @@ export class HaRepeatAction extends LitElement implements ActionElement {
|
||||
return { repeat: { count: 2, sequence: [] } };
|
||||
}
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(localize: LocalizeFunc, type: string, reOrderMode: boolean) =>
|
||||
[
|
||||
{
|
||||
name: "type",
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: OPTIONS.map((opt) => ({
|
||||
value: opt,
|
||||
label: localize(
|
||||
`ui.panel.config.automation.editor.actions.type.repeat.type.${opt}.label`
|
||||
),
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
...(type === "count"
|
||||
? ([
|
||||
{
|
||||
name: "count",
|
||||
required: true,
|
||||
selector: { number: { mode: "box", min: 1 } },
|
||||
},
|
||||
] as const)
|
||||
: []),
|
||||
...(type === "until" || type === "while"
|
||||
? ([
|
||||
{
|
||||
name: type,
|
||||
selector: {
|
||||
condition: { nested: true, reorder_mode: reOrderMode },
|
||||
},
|
||||
},
|
||||
] as const)
|
||||
: []),
|
||||
...(type === "for_each"
|
||||
? ([
|
||||
{
|
||||
name: "for_each",
|
||||
required: true,
|
||||
selector: { object: {} },
|
||||
},
|
||||
] as const)
|
||||
: []),
|
||||
{
|
||||
name: "sequence",
|
||||
selector: { action: { nested: true, reorder_mode: reOrderMode } },
|
||||
},
|
||||
] as const
|
||||
);
|
||||
|
||||
protected render() {
|
||||
const action = this.action.repeat;
|
||||
|
||||
const type = getType(action);
|
||||
|
||||
return html`
|
||||
<ha-select
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.repeat.type_select"
|
||||
)}
|
||||
.value=${type}
|
||||
.disabled=${this.disabled}
|
||||
@selected=${this._typeChanged}
|
||||
>
|
||||
${OPTIONS.map(
|
||||
(opt) => html`
|
||||
<mwc-list-item .value=${opt}>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.actions.type.repeat.type.${opt}.label`
|
||||
)}
|
||||
</mwc-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-select>
|
||||
<div>
|
||||
${type === "count"
|
||||
? html`
|
||||
<ha-textfield
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.repeat.type.count.label"
|
||||
)}
|
||||
name="count"
|
||||
.value=${(action as CountRepeat).count || "0"}
|
||||
.disabled=${this.disabled}
|
||||
@change=${this._countChanged}
|
||||
></ha-textfield>
|
||||
`
|
||||
: type === "while"
|
||||
? html` <h3>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.actions.type.repeat.type.while.conditions`
|
||||
)}:
|
||||
</h3>
|
||||
<ha-automation-condition
|
||||
nested
|
||||
.conditions=${(action as WhileRepeat).while || []}
|
||||
.hass=${this.hass}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._conditionChanged}
|
||||
></ha-automation-condition>`
|
||||
: type === "until"
|
||||
? html` <h3>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.actions.type.repeat.type.until.conditions`
|
||||
)}:
|
||||
</h3>
|
||||
<ha-automation-condition
|
||||
nested
|
||||
.conditions=${(action as UntilRepeat).until || []}
|
||||
.hass=${this.hass}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._conditionChanged}
|
||||
></ha-automation-condition>`
|
||||
: ""}
|
||||
</div>
|
||||
<h3>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.repeat.sequence"
|
||||
)}:
|
||||
</h3>
|
||||
<ha-automation-action
|
||||
nested
|
||||
.actions=${action.sequence}
|
||||
.reOrderMode=${this.reOrderMode}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._actionChanged}
|
||||
.hass=${this.hass}
|
||||
></ha-automation-action>
|
||||
`;
|
||||
const schema = this._schema(
|
||||
this.hass.localize,
|
||||
type ?? "count",
|
||||
this.reOrderMode
|
||||
);
|
||||
const data = { ...action, type };
|
||||
return html` <ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${data}
|
||||
.schema=${schema}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._valueChanged}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
></ha-form>`;
|
||||
}
|
||||
|
||||
private _typeChanged(ev) {
|
||||
const type = ev.target.value;
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
ev.stopPropagation();
|
||||
const newVal = ev.detail.value;
|
||||
|
||||
if (!type || type === getType(this.action.repeat)) {
|
||||
return;
|
||||
const newType = newVal.type;
|
||||
delete newVal.type;
|
||||
const oldType = getType(this.action.repeat);
|
||||
|
||||
if (newType !== oldType) {
|
||||
if (newType === "count") {
|
||||
newVal.count = 2;
|
||||
delete newVal.while;
|
||||
delete newVal.until;
|
||||
delete newVal.for_each;
|
||||
}
|
||||
if (newType === "while") {
|
||||
newVal.while = newVal.until ?? [];
|
||||
delete newVal.count;
|
||||
delete newVal.until;
|
||||
delete newVal.for_each;
|
||||
}
|
||||
if (newType === "until") {
|
||||
newVal.until = newVal.while ?? [];
|
||||
delete newVal.count;
|
||||
delete newVal.while;
|
||||
delete newVal.for_each;
|
||||
}
|
||||
if (newType === "for_each") {
|
||||
newVal.for_each = {};
|
||||
delete newVal.count;
|
||||
delete newVal.while;
|
||||
delete newVal.until;
|
||||
}
|
||||
}
|
||||
|
||||
const value = type === "count" ? 2 : [];
|
||||
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
...this.action,
|
||||
repeat: { [type]: value, sequence: this.action.repeat.sequence },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _conditionChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const value = ev.detail.value as Condition[];
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
...this.action,
|
||||
repeat: {
|
||||
...this.action.repeat,
|
||||
[getType(this.action.repeat)!]: value,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _actionChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const value = ev.detail.value as Action[];
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
...this.action,
|
||||
repeat: {
|
||||
...this.action.repeat,
|
||||
sequence: value,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _countChanged(ev: CustomEvent): void {
|
||||
const newVal = (ev.target as any).value;
|
||||
if ((this.action.repeat as CountRepeat).count === newVal) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
...this.action,
|
||||
repeat: {
|
||||
...this.action.repeat,
|
||||
count: newVal,
|
||||
},
|
||||
repeat: { ...newVal },
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -185,6 +154,46 @@ export class HaRepeatAction extends LitElement implements ActionElement {
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
): string => {
|
||||
switch (schema.name) {
|
||||
case "type":
|
||||
return this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.repeat.type_select"
|
||||
);
|
||||
case "count":
|
||||
return this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.repeat.type.count.label"
|
||||
);
|
||||
case "while":
|
||||
return (
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.repeat.type.while.conditions"
|
||||
) + ":"
|
||||
);
|
||||
case "until":
|
||||
return (
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.repeat.type.until.conditions"
|
||||
) + ":"
|
||||
);
|
||||
case "for_each":
|
||||
return (
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.repeat.type.for_each.items"
|
||||
) + ":"
|
||||
);
|
||||
case "sequence":
|
||||
return (
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.repeat.sequence"
|
||||
) + ":"
|
||||
);
|
||||
}
|
||||
return "";
|
||||
};
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -2735,6 +2735,10 @@
|
||||
"until": {
|
||||
"label": "Until",
|
||||
"conditions": "Until conditions"
|
||||
},
|
||||
"for_each": {
|
||||
"label": "For each",
|
||||
"items": "For each item in list"
|
||||
}
|
||||
},
|
||||
"sequence": "Actions",
|
||||
|
Loading…
x
Reference in New Issue
Block a user