Handle errrors/wrong values on paste (#25245)

This commit is contained in:
Bram Kragten 2025-04-30 18:45:35 +03:00 committed by Paul Bottein
parent 46cc254f77
commit efd7b380a9
No known key found for this signature in database
4 changed files with 181 additions and 145 deletions

View File

@ -24,6 +24,10 @@ export class HaToast extends Snackbar {
max-width: 650px;
}
.mdc-snackbar__actions {
color: rgba(255, 255, 255, 0.87);
}
/* Revert the default styles set by mwc-snackbar */
@media (max-width: 480px), (max-width: 344px) {
.mdc-snackbar__surface {

View File

@ -314,104 +314,119 @@ export class HaManualAutomationEditor extends LitElement {
return;
}
const loaded: any = load(paste);
if (loaded) {
let config = loaded;
let loaded: any;
try {
loaded = load(paste);
} catch (_err: any) {
showToast(this, {
message: this.hass.localize(
"ui.panel.config.automation.editor.paste_invalid_yaml"
),
duration: 4000,
dismissable: true,
});
return;
}
if ("automation" in config) {
config = config.automation;
if (Array.isArray(config)) {
config = config[0];
}
}
if (!loaded || typeof loaded !== "object") {
return;
}
let config = loaded;
if ("automation" in config) {
config = config.automation;
if (Array.isArray(config)) {
if (config.length === 1) {
config = config[0];
} else {
const newConfig: AutomationConfig = {
triggers: [],
conditions: [],
actions: [],
};
let found = false;
config.forEach((cfg: any) => {
if (isTrigger(cfg)) {
found = true;
(newConfig.triggers as Trigger[]).push(cfg);
}
if (isCondition(cfg)) {
found = true;
(newConfig.conditions as Condition[]).push(cfg);
}
if (getActionType(cfg) !== "unknown") {
found = true;
(newConfig.actions as Action[]).push(cfg);
}
});
if (found) {
config = newConfig;
config = config[0];
}
}
if (Array.isArray(config)) {
if (config.length === 1) {
config = config[0];
} else {
const newConfig: AutomationConfig = {
triggers: [],
conditions: [],
actions: [],
};
let found = false;
config.forEach((cfg: any) => {
if (isTrigger(cfg)) {
found = true;
(newConfig.triggers as Trigger[]).push(cfg);
}
if (isCondition(cfg)) {
found = true;
(newConfig.conditions as Condition[]).push(cfg);
}
if (getActionType(cfg) !== "unknown") {
found = true;
(newConfig.actions as Action[]).push(cfg);
}
}
}
if (isTrigger(config)) {
config = { triggers: [config] };
}
if (isCondition(config)) {
config = { conditions: [config] };
}
if (getActionType(config) !== "unknown") {
config = { actions: [config] };
}
let normalized: AutomationConfig;
try {
normalized = normalizeAutomationConfig(config);
} catch (_err: any) {
return;
}
try {
assert(normalized, automationConfigStruct);
} catch (_err: any) {
showToast(this, {
message: this.hass.localize(
"ui.panel.config.automation.editor.paste_invalid_config"
),
duration: 4000,
dismissable: true,
});
return;
}
if (normalized) {
ev.preventDefault();
if (this.dirty) {
const result = await new Promise<boolean>((resolve) => {
showPasteReplaceDialog(this, {
domain: "automation",
pastedConfig: normalized,
onClose: () => resolve(false),
onAppend: () => {
this._appendToExistingConfig(normalized);
resolve(false);
},
onReplace: () => resolve(true),
});
});
if (!result) {
return;
}
if (found) {
config = newConfig;
}
// replace the config completely
this._replaceExistingConfig(normalized);
}
}
if (isTrigger(config)) {
config = { triggers: [config] };
}
if (isCondition(config)) {
config = { conditions: [config] };
}
if (getActionType(config) !== "unknown") {
config = { actions: [config] };
}
let normalized: AutomationConfig;
try {
normalized = normalizeAutomationConfig(config);
} catch (_err: any) {
return;
}
try {
assert(normalized, automationConfigStruct);
} catch (_err: any) {
showToast(this, {
message: this.hass.localize(
"ui.panel.config.automation.editor.paste_invalid_config"
),
duration: 4000,
dismissable: true,
});
return;
}
if (normalized) {
ev.preventDefault();
if (this.dirty) {
const result = await new Promise<boolean>((resolve) => {
showPasteReplaceDialog(this, {
domain: "automation",
pastedConfig: normalized,
onClose: () => resolve(false),
onAppend: () => {
this._appendToExistingConfig(normalized);
resolve(false);
},
onReplace: () => resolve(true),
});
});
if (!result) {
return;
}
}
// replace the config completely
this._replaceExistingConfig(normalized);
}
};
private _appendToExistingConfig(config: ManualAutomationConfig) {

View File

@ -238,75 +238,90 @@ export class HaManualScriptEditor extends LitElement {
return;
}
const loaded: any = load(paste);
if (loaded) {
let config = loaded;
let loaded: any;
try {
loaded = load(paste);
} catch (_err: any) {
showToast(this, {
message: this.hass.localize(
"ui.panel.config.script.editor.paste_invalid_config"
),
duration: 4000,
dismissable: true,
});
return;
}
if ("script" in config) {
config = config.script;
if (Object.keys(config).length) {
config = config[Object.keys(config)[0]];
}
if (!loaded || typeof loaded !== "object") {
return;
}
let config = loaded;
if ("script" in config) {
config = config.script;
if (Object.keys(config).length) {
config = config[Object.keys(config)[0]];
}
}
if (Array.isArray(config)) {
if (config.length === 1) {
config = config[0];
} else {
config = { sequence: config };
}
if (Array.isArray(config)) {
if (config.length === 1) {
config = config[0];
} else {
config = { sequence: config };
}
}
if (!["sequence", "unknown"].includes(getActionType(config))) {
config = { sequence: [config] };
}
if (!["sequence", "unknown"].includes(getActionType(config))) {
config = { sequence: [config] };
}
let normalized: ScriptConfig | undefined;
let normalized: ScriptConfig | undefined;
try {
normalized = normalizeScriptConfig(config);
} catch (_err: any) {
return;
}
try {
normalized = normalizeScriptConfig(config);
} catch (_err: any) {
return;
}
try {
assert(normalized, scriptConfigStruct);
} catch (_err: any) {
showToast(this, {
message: this.hass.localize(
"ui.panel.config.script.editor.paste_invalid_config"
),
duration: 4000,
dismissable: true,
});
return;
}
try {
assert(normalized, scriptConfigStruct);
} catch (_err: any) {
showToast(this, {
message: this.hass.localize(
"ui.panel.config.script.editor.paste_invalid_config"
),
duration: 4000,
dismissable: true,
});
return;
}
if (normalized) {
ev.preventDefault();
if (normalized) {
ev.preventDefault();
if (this.dirty) {
const result = await new Promise<boolean>((resolve) => {
showPasteReplaceDialog(this, {
domain: "script",
pastedConfig: normalized,
onClose: () => resolve(false),
onAppend: () => {
this._appendToExistingConfig(normalized);
resolve(false);
},
onReplace: () => resolve(true),
});
if (this.dirty) {
const result = await new Promise<boolean>((resolve) => {
showPasteReplaceDialog(this, {
domain: "script",
pastedConfig: normalized,
onClose: () => resolve(false),
onAppend: () => {
this._appendToExistingConfig(normalized);
resolve(false);
},
onReplace: () => resolve(true),
});
});
if (!result) {
return;
}
if (!result) {
return;
}
// replace the config completely
this._replaceExistingConfig(normalized);
}
// replace the config completely
this._replaceExistingConfig(normalized);
}
};

View File

@ -4356,6 +4356,7 @@
"text": "How do you want to paste your automation?"
},
"paste_toast_message": "Pasted automation from clipboard",
"paste_invalid_yaml": "Pasted value is not valid YAML",
"paste_invalid_config": "Pasted automation is not editable in the visual editor"
},
"trace": {
@ -4595,6 +4596,7 @@
"text": "How do you want to paste your script?"
},
"paste_toast_message": "Pasted script from clipboard",
"paste_invalid_yaml": "Pasted value is not valid YAML",
"paste_invalid_config": "Pasted script is not editable in the visual editor"
},
"trace": {