mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Migrate base automation config to plurals (#22053)
* Migrate base automation config to plurals * revert * Update hat-script-graph.ts * Make traces work with both new and old config * Adjust validateConfig
This commit is contained in:
parent
1bbf45d35e
commit
cbce6f633f
@ -217,20 +217,20 @@ export const basicTrace: DemoTrace = {
|
||||
id: "1615419646544",
|
||||
alias: "Ensure Party mode",
|
||||
description: "",
|
||||
trigger: [
|
||||
triggers: [
|
||||
{
|
||||
platform: "state",
|
||||
entity_id: "input_boolean.toggle_1",
|
||||
},
|
||||
],
|
||||
condition: [
|
||||
conditions: [
|
||||
{
|
||||
condition: "template",
|
||||
alias: "Test if Paulus is home",
|
||||
value_template: "{{ true }}",
|
||||
},
|
||||
],
|
||||
action: [
|
||||
actions: [
|
||||
{
|
||||
action: "input_boolean.toggle",
|
||||
target: {
|
||||
|
@ -31,8 +31,8 @@ export const mockDemoTrace = (
|
||||
],
|
||||
},
|
||||
config: {
|
||||
trigger: [],
|
||||
action: [],
|
||||
triggers: [],
|
||||
actions: [],
|
||||
},
|
||||
context: {
|
||||
id: "abcd",
|
||||
|
@ -133,7 +133,7 @@ export const motionLightTrace: DemoTrace = {
|
||||
config: {
|
||||
mode: "restart",
|
||||
max_exceeded: "silent",
|
||||
trigger: [
|
||||
triggers: [
|
||||
{
|
||||
platform: "state",
|
||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
||||
@ -141,7 +141,7 @@ export const motionLightTrace: DemoTrace = {
|
||||
to: "on",
|
||||
},
|
||||
],
|
||||
action: [
|
||||
actions: [
|
||||
{
|
||||
action: "light.turn_on",
|
||||
target: {
|
||||
|
@ -121,7 +121,7 @@ const ACTIONS = [
|
||||
];
|
||||
|
||||
const initialAction: Action = {
|
||||
service: "light.turn_on",
|
||||
action: "light.turn_on",
|
||||
target: {
|
||||
entity_id: "light.kitchen",
|
||||
},
|
||||
|
@ -569,10 +569,15 @@ export class HatScriptGraph extends LitElement {
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const triggerKey = "triggers" in this.trace.config ? "triggers" : "trigger";
|
||||
const conditionKey =
|
||||
"conditions" in this.trace.config ? "conditions" : "condition";
|
||||
const actionKey = "actions" in this.trace.config ? "actions" : "action";
|
||||
|
||||
const paths = Object.keys(this.trackedNodes);
|
||||
const trigger_nodes =
|
||||
"trigger" in this.trace.config
|
||||
? flattenTriggers(ensureArray(this.trace.config.trigger)).map(
|
||||
triggerKey in this.trace.config
|
||||
? flattenTriggers(ensureArray(this.trace.config[triggerKey])).map(
|
||||
(trigger, i) => this.render_trigger(trigger, i)
|
||||
)
|
||||
: undefined;
|
||||
@ -584,14 +589,14 @@ export class HatScriptGraph extends LitElement {
|
||||
${trigger_nodes}
|
||||
</hat-graph-branch>`
|
||||
: ""}
|
||||
${"condition" in this.trace.config
|
||||
? html`${ensureArray(this.trace.config.condition)?.map(
|
||||
${conditionKey in this.trace.config
|
||||
? html`${ensureArray(this.trace.config[conditionKey])?.map(
|
||||
(condition, i) => this.render_condition(condition, i)
|
||||
)}`
|
||||
: ""}
|
||||
${"action" in this.trace.config
|
||||
? html`${ensureArray(this.trace.config.action).map((action, i) =>
|
||||
this.render_action_node(action, `action/${i}`)
|
||||
${actionKey in this.trace.config
|
||||
? html`${ensureArray(this.trace.config[actionKey]).map(
|
||||
(action, i) => this.render_action_node(action, `action/${i}`)
|
||||
)}`
|
||||
: ""}
|
||||
${"sequence" in this.trace.config
|
||||
|
@ -27,8 +27,14 @@ export interface ManualAutomationConfig {
|
||||
id?: string;
|
||||
alias?: string;
|
||||
description?: string;
|
||||
trigger: Trigger | Trigger[];
|
||||
triggers: Trigger | Trigger[];
|
||||
/** @deprecated Use `triggers` instead */
|
||||
trigger?: Trigger | Trigger[];
|
||||
conditions?: Condition | Condition[];
|
||||
/** @deprecated Use `conditions` instead */
|
||||
condition?: Condition | Condition[];
|
||||
actions: Action | Action[];
|
||||
/** @deprecated Use `actions` instead */
|
||||
action?: Action | Action[];
|
||||
mode?: (typeof MODES)[number];
|
||||
max?: number;
|
||||
@ -362,22 +368,50 @@ export const normalizeAutomationConfig = <
|
||||
>(
|
||||
config: T
|
||||
): T => {
|
||||
config = migrateAutomationConfig(config);
|
||||
|
||||
// Normalize data: ensure triggers, actions and conditions are lists
|
||||
// Happens when people copy paste their automations into the config
|
||||
for (const key of ["trigger", "condition", "action"]) {
|
||||
for (const key of ["triggers", "conditions", "actions"]) {
|
||||
const value = config[key];
|
||||
if (value && !Array.isArray(value)) {
|
||||
config[key] = [value];
|
||||
}
|
||||
}
|
||||
|
||||
if (config.action) {
|
||||
config.action = migrateAutomationAction(config.action);
|
||||
if (config.actions) {
|
||||
config.actions = migrateAutomationAction(config.actions);
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
export const migrateAutomationConfig = <
|
||||
T extends Partial<AutomationConfig> | AutomationConfig,
|
||||
>(
|
||||
config: T
|
||||
) => {
|
||||
if ("trigger" in config) {
|
||||
if (!("triggers" in config)) {
|
||||
config.triggers = config.trigger;
|
||||
}
|
||||
delete config.trigger;
|
||||
}
|
||||
if ("condition" in config) {
|
||||
if (!("conditions" in config)) {
|
||||
config.conditions = config.condition;
|
||||
}
|
||||
delete config.condition;
|
||||
}
|
||||
if ("action" in config) {
|
||||
if (!("actions" in config)) {
|
||||
config.actions = config.action;
|
||||
}
|
||||
delete config.action;
|
||||
}
|
||||
return config;
|
||||
};
|
||||
|
||||
export const flattenTriggers = (
|
||||
triggers: undefined | (Trigger | TriggerList)[]
|
||||
): Trigger[] => {
|
||||
|
@ -10,7 +10,7 @@ interface InvalidConfig {
|
||||
error: string;
|
||||
}
|
||||
|
||||
type ValidKeys = "trigger" | "action" | "condition";
|
||||
type ValidKeys = "triggers" | "actions" | "conditions";
|
||||
|
||||
export const validateConfig = <
|
||||
T extends Partial<{ [key in ValidKeys]: unknown }>,
|
||||
|
@ -404,7 +404,7 @@ export const getActionType = (action: Action): ActionType => {
|
||||
if ("set_conversation_response" in action) {
|
||||
return "set_conversation_response";
|
||||
}
|
||||
if ("action" in action) {
|
||||
if ("action" in action || "service" in action) {
|
||||
if ("metadata" in action) {
|
||||
if (is(action, activateSceneActionStruct)) {
|
||||
return "activate_scene";
|
||||
|
@ -187,10 +187,21 @@ export const getDataFromPath = (
|
||||
const asNumber = Number(raw);
|
||||
|
||||
if (isNaN(asNumber)) {
|
||||
const tempResult = result[raw];
|
||||
let tempResult = result[raw];
|
||||
if (!tempResult && raw === "sequence") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tempResult && raw === "trigger") {
|
||||
tempResult = result.triggers;
|
||||
}
|
||||
if (!tempResult && raw === "condition") {
|
||||
tempResult = result.conditions;
|
||||
}
|
||||
if (!tempResult && raw === "action") {
|
||||
tempResult = result.actions;
|
||||
}
|
||||
|
||||
if (raw === "trigger") {
|
||||
result = flattenTriggers(tempResult);
|
||||
} else {
|
||||
|
@ -510,15 +510,15 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
|
||||
private async _runAction() {
|
||||
const validated = await validateConfig(this.hass, {
|
||||
action: this.action,
|
||||
actions: this.action,
|
||||
});
|
||||
|
||||
if (!validated.action.valid) {
|
||||
if (!validated.actions.valid) {
|
||||
showAlertDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.invalid_action"
|
||||
),
|
||||
text: validated.action.error,
|
||||
text: validated.actions.error,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -431,7 +431,7 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
|
||||
try {
|
||||
const validateResult = await validateConfig(this.hass, {
|
||||
condition,
|
||||
conditions: condition,
|
||||
});
|
||||
|
||||
// Abort if condition changed.
|
||||
@ -440,12 +440,12 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateResult.condition.valid) {
|
||||
if (!validateResult.conditions.valid) {
|
||||
showAlertDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.invalid_condition"
|
||||
),
|
||||
text: validateResult.condition.error,
|
||||
text: validateResult.conditions.error,
|
||||
});
|
||||
this._testing = false;
|
||||
return;
|
||||
|
@ -46,6 +46,7 @@ import {
|
||||
fetchAutomationFileConfig,
|
||||
getAutomationEditorInitData,
|
||||
getAutomationStateConfig,
|
||||
migrateAutomationConfig,
|
||||
normalizeAutomationConfig,
|
||||
saveAutomationConfig,
|
||||
showAutomationEditor,
|
||||
@ -520,9 +521,9 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
return;
|
||||
}
|
||||
const validation = await validateConfig(this.hass, {
|
||||
trigger: this._config.trigger,
|
||||
condition: this._config.condition,
|
||||
action: this._config.action,
|
||||
triggers: this._config.triggers,
|
||||
conditions: this._config.conditions,
|
||||
actions: this._config.actions,
|
||||
});
|
||||
this._validationErrors = (
|
||||
Object.entries(validation) as Entries<typeof validation>
|
||||
@ -530,7 +531,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
value.valid
|
||||
? ""
|
||||
: html`${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.${key}s.name`
|
||||
`ui.panel.config.automation.editor.${key}.name`
|
||||
)}:
|
||||
${value.error}<br />`
|
||||
);
|
||||
@ -637,7 +638,10 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
if (!ev.detail.isValid) {
|
||||
return;
|
||||
}
|
||||
this._config = { id: this._config?.id, ...ev.detail.value };
|
||||
this._config = {
|
||||
id: this._config?.id,
|
||||
...migrateAutomationConfig(ev.detail.value),
|
||||
};
|
||||
this._errors = undefined;
|
||||
this._dirty = true;
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
<ha-automation-trigger
|
||||
role="region"
|
||||
aria-labelledby="triggers-heading"
|
||||
.triggers=${this.config.trigger || []}
|
||||
.triggers=${this.config.triggers || []}
|
||||
.path=${["trigger"]}
|
||||
@value-changed=${this._triggerChanged}
|
||||
@item-moved=${this._itemMoved}
|
||||
@ -119,7 +119,7 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
></ha-icon-button>
|
||||
</a>
|
||||
</div>
|
||||
${!ensureArray(this.config.condition)?.length
|
||||
${!ensureArray(this.config.conditions)?.length
|
||||
? html`<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.description",
|
||||
@ -131,7 +131,7 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
<ha-automation-condition
|
||||
role="region"
|
||||
aria-labelledby="conditions-heading"
|
||||
.conditions=${this.config.condition || []}
|
||||
.conditions=${this.config.conditions || []}
|
||||
.path=${["condition"]}
|
||||
@value-changed=${this._conditionChanged}
|
||||
@item-moved=${this._itemMoved}
|
||||
@ -160,7 +160,7 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
${!ensureArray(this.config.action)?.length
|
||||
${!ensureArray(this.config.actions)?.length
|
||||
? html`<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.description"
|
||||
@ -171,7 +171,7 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
<ha-automation-action
|
||||
role="region"
|
||||
aria-labelledby="actions-heading"
|
||||
.actions=${this.config.action}
|
||||
.actions=${this.config.actions || []}
|
||||
.path=${["action"]}
|
||||
@value-changed=${this._actionChanged}
|
||||
@item-moved=${this._itemMoved}
|
||||
@ -185,7 +185,7 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
private _triggerChanged(ev: CustomEvent): void {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.config!, trigger: ev.detail.value as Trigger[] },
|
||||
value: { ...this.config!, triggers: ev.detail.value as Trigger[] },
|
||||
});
|
||||
}
|
||||
|
||||
@ -194,7 +194,7 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
...this.config!,
|
||||
condition: ev.detail.value as Condition[],
|
||||
conditions: ev.detail.value as Condition[],
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -202,7 +202,7 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
private _actionChanged(ev: CustomEvent): void {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.config!, action: ev.detail.value as Action[] },
|
||||
value: { ...this.config!, actions: ev.detail.value as Action[] },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -436,11 +436,11 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
}
|
||||
|
||||
const validateResult = await validateConfig(this.hass, {
|
||||
trigger,
|
||||
triggers: trigger,
|
||||
});
|
||||
|
||||
// Don't do anything if trigger not valid or if trigger changed.
|
||||
if (!validateResult.trigger.valid || this.trigger !== trigger) {
|
||||
if (!validateResult.triggers.valid || this.trigger !== trigger) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -467,7 +467,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
return;
|
||||
}
|
||||
const validation = await validateConfig(this.hass, {
|
||||
action: this._config.sequence,
|
||||
actions: this._config.sequence,
|
||||
});
|
||||
this._validationErrors = (
|
||||
Object.entries(validation) as Entries<typeof validation>
|
||||
@ -475,7 +475,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
value.valid
|
||||
? ""
|
||||
: html`${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.${key}s.name`
|
||||
`ui.panel.config.automation.editor.${key}.name`
|
||||
)}:
|
||||
${value.error}<br />`
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user