diff --git a/gallery/src/pages/automation/editor-action.ts b/gallery/src/pages/automation/editor-action.ts index 4551593c44..376f547d72 100644 --- a/gallery/src/pages/automation/editor-action.ts +++ b/gallery/src/pages/automation/editor-action.ts @@ -1,5 +1,5 @@ /* eslint-disable lit/no-template-arrow */ -import { LitElement, TemplateResult, html } from "lit"; +import { LitElement, TemplateResult, html, css } from "lit"; import { customElement, state } from "lit/decorators"; import { provideHass } from "../../../../src/fake_data/provide_hass"; import type { HomeAssistant } from "../../../../src/types"; @@ -47,6 +47,8 @@ const SCHEMAS: { name: string; actions: Action[] }[] = [ class DemoHaAutomationEditorAction extends LitElement { @state() private hass!: HomeAssistant; + @state() private _disabled = false; + private data: any = SCHEMAS.map((info) => info.actions); constructor() { @@ -67,6 +69,15 @@ class DemoHaAutomationEditorAction extends LitElement { this.requestUpdate(); }; return html` +
+ + + +
${SCHEMAS.map( (info, sampleIdx) => html` ` @@ -90,6 +102,20 @@ class DemoHaAutomationEditorAction extends LitElement { )} `; } + + private _handleOptionChange(ev) { + this[`_${ev.target.name}`] = ev.target.checked; + } + + static styles = css` + .options { + max-width: 800px; + margin: 16px auto; + } + .options ha-formfield { + margin-right: 16px; + } + `; } declare global { diff --git a/gallery/src/pages/automation/editor-condition.ts b/gallery/src/pages/automation/editor-condition.ts index 8f8ee17604..7504d9dc46 100644 --- a/gallery/src/pages/automation/editor-condition.ts +++ b/gallery/src/pages/automation/editor-condition.ts @@ -1,5 +1,5 @@ /* eslint-disable lit/no-template-arrow */ -import { LitElement, TemplateResult, html } from "lit"; +import { LitElement, TemplateResult, html, css } from "lit"; import { customElement, state } from "lit/decorators"; import { provideHass } from "../../../../src/fake_data/provide_hass"; import type { HomeAssistant } from "../../../../src/types"; @@ -83,6 +83,8 @@ const SCHEMAS: { name: string; conditions: ConditionWithShorthand[] }[] = [ class DemoHaAutomationEditorCondition extends LitElement { @state() private hass!: HomeAssistant; + @state() private _disabled = false; + private data: any = SCHEMAS.map((info) => info.conditions); constructor() { @@ -103,6 +105,15 @@ class DemoHaAutomationEditorCondition extends LitElement { this.requestUpdate(); }; return html` +
+ + + +
${SCHEMAS.map( (info, sampleIdx) => html` ` @@ -126,6 +138,20 @@ class DemoHaAutomationEditorCondition extends LitElement { )} `; } + + private _handleOptionChange(ev) { + this[`_${ev.target.name}`] = ev.target.checked; + } + + static styles = css` + .options { + max-width: 800px; + margin: 16px auto; + } + .options ha-formfield { + margin-right: 16px; + } + `; } declare global { diff --git a/gallery/src/pages/automation/editor-trigger.ts b/gallery/src/pages/automation/editor-trigger.ts index af6d3bd6bb..bff2947bb3 100644 --- a/gallery/src/pages/automation/editor-trigger.ts +++ b/gallery/src/pages/automation/editor-trigger.ts @@ -1,5 +1,5 @@ /* eslint-disable lit/no-template-arrow */ -import { LitElement, TemplateResult, html } from "lit"; +import { LitElement, TemplateResult, html, css } from "lit"; import { customElement, state } from "lit/decorators"; import { provideHass } from "../../../../src/fake_data/provide_hass"; import type { HomeAssistant } from "../../../../src/types"; @@ -107,6 +107,8 @@ const SCHEMAS: { name: string; triggers: Trigger[] }[] = [ class DemoHaAutomationEditorTrigger extends LitElement { @state() private hass!: HomeAssistant; + @state() private _disabled = false; + private data: any = SCHEMAS.map((info) => info.triggers); constructor() { @@ -127,6 +129,15 @@ class DemoHaAutomationEditorTrigger extends LitElement { this.requestUpdate(); }; return html` +
+ + + +
${SCHEMAS.map( (info, sampleIdx) => html` ` @@ -150,6 +162,20 @@ class DemoHaAutomationEditorTrigger extends LitElement { )} `; } + + private _handleOptionChange(ev) { + this[`_${ev.target.name}`] = ev.target.checked; + } + + static styles = css` + .options { + max-width: 800px; + margin: 16px auto; + } + .options ha-formfield { + margin-right: 16px; + } + `; } declare global { diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index 21b10c53dc..ef3c6ee593 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -312,6 +312,7 @@ export class HaEntityPicker extends LitElement { .filteredItems=${this._states} .renderer=${rowRenderer} .required=${this.required} + .disabled=${this.disabled} @opened-changed=${this._openedChanged} @value-changed=${this._valueChanged} @filter-changed=${this._filterChanged} diff --git a/src/components/ha-service-control.ts b/src/components/ha-service-control.ts index a282f9b5f5..5a3a223618 100644 --- a/src/components/ha-service-control.ts +++ b/src/components/ha-service-control.ts @@ -55,12 +55,14 @@ export class HaServiceControl extends LitElement { data?: Record; }; - @state() private _value!: this["value"]; + @property({ type: Boolean }) public disabled = false; @property({ reflect: true, type: Boolean }) public narrow!: boolean; @property({ type: Boolean }) public showAdvanced?: boolean; + @state() private _value!: this["value"]; + @state() private _checkedKeys = new Set(); @state() private _manifest?: IntegrationManifest; @@ -227,6 +229,7 @@ export class HaServiceControl extends LitElement { return html`
@@ -273,6 +276,7 @@ export class HaServiceControl extends LitElement { .selector=${serviceData.target ? { target: serviceData.target } : { target: {} }} + .disabled=${this.disabled} @value-changed=${this._targetChanged} .value=${this._value?.target} >` @@ -311,16 +317,18 @@ export class HaServiceControl extends LitElement { .checked=${this._checkedKeys.has(dataField.key) || (this._value?.data && this._value.data[dataField.key] !== undefined)} + .disabled=${this.disabled} @change=${this._checkboxChanged} slot="prefix" >`} ${dataField.name || dataField.key} ${dataField?.description} = ( class HaServicePicker extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; + @property({ type: Boolean }) public disabled = false; + @property() public value?: string; @state() private _filter?: string; @@ -35,6 +37,7 @@ class HaServicePicker extends LitElement { this._filter )} .value=${this.value} + .disabled=${this.disabled} .renderer=${rowRenderer} item-value-path="service" item-label-path="name" diff --git a/src/data/automation.ts b/src/data/automation.ts index d8ee247032..1afa5a5184 100644 --- a/src/data/automation.ts +++ b/src/data/automation.ts @@ -311,9 +311,18 @@ export const deleteAutomation = (hass: HomeAssistant, id: string) => let inititialAutomationEditorData: Partial | undefined; -export const getAutomationConfig = (hass: HomeAssistant, id: string) => +export const fetchAutomationFileConfig = (hass: HomeAssistant, id: string) => hass.callApi("GET", `config/automation/config/${id}`); +export const getAutomationStateConfig = ( + hass: HomeAssistant, + entity_id: string +) => + hass.callWS<{ config: AutomationConfig }>({ + type: "automation/config", + entity_id, + }); + export const saveAutomationConfig = ( hass: HomeAssistant, id: string, diff --git a/src/panels/config/automation/action/ha-automation-action-row.ts b/src/panels/config/automation/action/ha-automation-action-row.ts index 0d89543050..5fa84a8dea 100644 --- a/src/panels/config/automation/action/ha-automation-action-row.ts +++ b/src/panels/config/automation/action/ha-automation-action-row.ts @@ -100,6 +100,8 @@ export default class HaAutomationActionRow extends LitElement { @property({ type: Boolean }) public narrow = false; + @property({ type: Boolean }) public disabled = false; + @property({ type: Boolean }) public hideMenu = false; @property({ type: Boolean }) public reOrderMode = false; @@ -179,7 +181,7 @@ export default class HaAutomationActionRow extends LitElement { - + ${this.hass.localize( "ui.panel.config.automation.editor.actions.rename" )} @@ -188,7 +190,7 @@ export default class HaAutomationActionRow extends LitElement { .path=${mdiRenameBox} > - + ${this.hass.localize( "ui.panel.config.automation.editor.actions.duplicate" )} @@ -234,7 +236,7 @@ export default class HaAutomationActionRow extends LitElement {
  • - + ${this.action.enabled === false ? this.hass.localize( "ui.panel.config.automation.editor.actions.enable" @@ -249,7 +251,11 @@ export default class HaAutomationActionRow extends LitElement { : mdiStopCircleOutline} > - + ${this.hass.localize( "ui.panel.config.automation.editor.actions.delete" )} @@ -302,6 +308,7 @@ export default class HaAutomationActionRow extends LitElement { ` @@ -312,6 +319,7 @@ export default class HaAutomationActionRow extends LitElement { action: this.action, narrow: this.narrow, reOrderMode: this.reOrderMode, + disabled: this.disabled, })}
    `} diff --git a/src/panels/config/automation/action/ha-automation-action.ts b/src/panels/config/automation/action/ha-automation-action.ts index dd7b802aa1..3462abd6bc 100644 --- a/src/panels/config/automation/action/ha-automation-action.ts +++ b/src/panels/config/automation/action/ha-automation-action.ts @@ -44,6 +44,8 @@ export default class HaAutomationAction extends LitElement { @property({ type: Boolean }) public narrow = false; + @property({ type: Boolean }) public disabled = false; + @property() public actions!: Action[]; @property({ type: Boolean }) public reOrderMode = false; @@ -65,6 +67,7 @@ export default class HaAutomationAction extends LitElement { .index=${idx} .action=${action} .narrow=${this.narrow} + .disabled=${this.disabled} .hideMenu=${this.reOrderMode} .reOrderMode=${this.reOrderMode} @duplicate=${this._duplicateAction} @@ -102,10 +105,15 @@ export default class HaAutomationAction extends LitElement { ` )} - + html` @@ -92,12 +98,17 @@ export class HaChooseAction extends LitElement implements ActionElement { ` - : html` diff --git a/src/panels/config/automation/condition/ha-automation-condition-row.ts b/src/panels/config/automation/condition/ha-automation-condition-row.ts index 386e158d01..9fe75cd479 100644 --- a/src/panels/config/automation/condition/ha-automation-condition-row.ts +++ b/src/panels/config/automation/condition/ha-automation-condition-row.ts @@ -74,6 +74,8 @@ export default class HaAutomationConditionRow extends LitElement { @property({ type: Boolean }) public reOrderMode = false; + @property({ type: Boolean }) public disabled = false; + @state() private _yamlMode = false; @state() private _warnings?: string[]; @@ -131,7 +133,7 @@ export default class HaAutomationConditionRow extends LitElement { )} - + ${this.hass.localize( "ui.panel.config.automation.editor.conditions.rename" )} @@ -140,7 +142,7 @@ export default class HaAutomationConditionRow extends LitElement { .path=${mdiRenameBox} > - + ${this.hass.localize( "ui.panel.config.automation.editor.actions.duplicate" )} @@ -180,7 +182,7 @@ export default class HaAutomationConditionRow extends LitElement {
  • - + ${this.condition.enabled === false ? this.hass.localize( "ui.panel.config.automation.editor.actions.enable" @@ -195,7 +197,11 @@ export default class HaAutomationConditionRow extends LitElement { : mdiStopCircleOutline} > - + ${this.hass.localize( "ui.panel.config.automation.editor.actions.delete" )} @@ -238,6 +244,7 @@ export default class HaAutomationConditionRow extends LitElement { @ui-mode-not-available=${this._handleUiModeNotAvailable} @value-changed=${this._handleChangeEvent} .yamlMode=${this._yamlMode} + .disabled=${this.disabled} .hass=${this.hass} .condition=${this.condition} .reOrderMode=${this.reOrderMode} diff --git a/src/panels/config/automation/condition/ha-automation-condition.ts b/src/panels/config/automation/condition/ha-automation-condition.ts index 8815d15cb1..e6ac6e7a89 100644 --- a/src/panels/config/automation/condition/ha-automation-condition.ts +++ b/src/panels/config/automation/condition/ha-automation-condition.ts @@ -42,6 +42,8 @@ export default class HaAutomationCondition extends LitElement { @property() public conditions!: Condition[]; + @property({ type: Boolean }) public disabled = false; + @property({ type: Boolean }) public reOrderMode = false; private _focusLastConditionOnChange = false; @@ -111,6 +113,7 @@ export default class HaAutomationCondition extends LitElement { .condition=${cond} .hideMenu=${this.reOrderMode} .reOrderMode=${this.reOrderMode} + .disabled=${this.disabled} @duplicate=${this._duplicateCondition} @move-condition=${this._move} @value-changed=${this._conditionChanged} @@ -147,10 +150,15 @@ export default class HaAutomationCondition extends LitElement { ` )} - + @@ -62,7 +65,8 @@ export class HaDeviceCondition extends LitElement { .deviceId=${deviceId} @value-changed=${this._deviceConditionPicked} .hass=${this.hass} - label=${this.hass.localize( + .disabled=${this.disabled} + .label=${this.hass.localize( "ui.panel.config.automation.editor.conditions.type.device.condition" )} > @@ -72,6 +76,7 @@ export class HaDeviceCondition extends LitElement { .hass=${this.hass} .data=${this._extraFieldsData(this.condition, this._capabilities)} .schema=${this._capabilities.extra_fields} + .disabled=${this.disabled} .computeLabel=${this._extraFieldsComputeLabelCallback( this.hass.localize )} diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts b/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts index 0838feffc3..08de5eb584 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts @@ -12,6 +12,8 @@ export class HaLogicalCondition extends LitElement implements ConditionElement { @property({ attribute: false }) public condition!: LogicalCondition; + @property({ type: Boolean }) public disabled = false; + @property({ type: Boolean }) public reOrderMode = false; public static get defaultConfig() { @@ -26,6 +28,7 @@ export class HaLogicalCondition extends LitElement implements ConditionElement { .conditions=${this.condition.conditions || []} @value-changed=${this._valueChanged} .hass=${this.hass} + .disabled=${this.disabled} .reOrderMode=${this.reOrderMode} > `; diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts b/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts index 9a8d3f0a32..9c7647f6b6 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts @@ -13,6 +13,8 @@ export default class HaNumericStateCondition extends LitElement { @property({ attribute: false }) public condition!: NumericStateCondition; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return { entity_id: "", @@ -132,6 +134,7 @@ export default class HaNumericStateCondition extends LitElement { .hass=${this.hass} .data=${this.condition} .schema=${schema} + .disabled=${this.disabled} @value-changed=${this._valueChanged} .computeLabel=${this._computeLabelCallback} > diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-state.ts b/src/panels/config/automation/condition/types/ha-automation-condition-state.ts index 10b7bda06c..2ffd0b68f4 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-state.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-state.ts @@ -26,6 +26,8 @@ export class HaStateCondition extends LitElement implements ConditionElement { @property({ attribute: false }) public condition!: StateCondition; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return { entity_id: "", state: "" }; } @@ -100,6 +102,7 @@ export class HaStateCondition extends LitElement implements ConditionElement { .hass=${this.hass} .data=${data} .schema=${schema} + .disabled=${this.disabled} @value-changed=${this._valueChanged} .computeLabel=${this._computeLabelCallback} > diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts b/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts index 269f9e072b..ff3641fddf 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts @@ -15,6 +15,8 @@ export class HaSunCondition extends LitElement implements ConditionElement { @property({ attribute: false }) public condition!: SunCondition; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return {}; } @@ -72,6 +74,7 @@ export class HaSunCondition extends LitElement implements ConditionElement { .schema=${schema} .data=${this.condition} .hass=${this.hass} + .disabled=${this.disabled} .computeLabel=${this._computeLabelCallback} @value-changed=${this._valueChanged} > diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-template.ts b/src/panels/config/automation/condition/types/ha-automation-condition-template.ts index 2d21860834..43ff58bc53 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-template.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-template.ts @@ -11,6 +11,8 @@ export class HaTemplateCondition extends LitElement { @property({ attribute: false }) public condition!: TemplateCondition; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return { value_template: "" }; } @@ -29,6 +31,7 @@ export class HaTemplateCondition extends LitElement { mode="jinja2" .hass=${this.hass} .value=${value_template} + .readOnly=${this.disabled} autocomplete-entities @value-changed=${this._valueChanged} dir="ltr" diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-time.ts b/src/panels/config/automation/condition/types/ha-automation-condition-time.ts index 9901b4fc22..e2b2301b21 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-time.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-time.ts @@ -21,6 +21,8 @@ export class HaTimeCondition extends LitElement implements ConditionElement { @state() private _inputModeAfter?: boolean; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return {}; } @@ -123,6 +125,7 @@ export class HaTimeCondition extends LitElement implements ConditionElement { .hass=${this.hass} .data=${data} .schema=${schema} + .disabled=${this.disabled} @value-changed=${this._valueChanged} .computeLabel=${this._computeLabelCallback} > diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-trigger.ts b/src/panels/config/automation/condition/types/ha-automation-condition-trigger.ts index cb80c3769b..ef4e22d56f 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-trigger.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-trigger.ts @@ -18,6 +18,8 @@ export class HaTriggerCondition extends LitElement { @property({ attribute: false }) public condition!: TriggerCondition; + @property({ type: Boolean }) public disabled = false; + @state() private _triggers: Trigger[] = []; private _unsub?: UnsubscribeFunc; @@ -55,6 +57,7 @@ export class HaTriggerCondition extends LitElement { "ui.panel.config.automation.editor.conditions.type.trigger.id" )} .value=${id} + .disabled=${this.disabled} @selected=${this._triggerPicked} > ${this._triggers.map( diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts b/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts index def76b97d8..8fc13e5ad6 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts @@ -20,6 +20,8 @@ export class HaZoneCondition extends LitElement { @property({ attribute: false }) public condition!: ZoneCondition; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return { entity_id: "", @@ -37,6 +39,7 @@ export class HaZoneCondition extends LitElement { .value=${entity_id} @value-changed=${this._entityPicked} .hass=${this.hass} + .disabled=${this.disabled} allow-custom-entity .entityFilter=${zoneAndLocationFilter} > @@ -47,6 +50,7 @@ export class HaZoneCondition extends LitElement { .value=${zone} @value-changed=${this._zonePicked} .hass=${this.hass} + .disabled=${this.disabled} allow-custom-entity .includeDomains=${includeDomains} > diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts index e7c7236fd3..fd9b805c71 100644 --- a/src/panels/config/automation/ha-automation-editor.ts +++ b/src/panels/config/automation/ha-automation-editor.ts @@ -43,7 +43,8 @@ import { AutomationConfig, AutomationEntity, deleteAutomation, - getAutomationConfig, + getAutomationStateConfig, + fetchAutomationFileConfig, getAutomationEditorInitData, saveAutomationConfig, showAutomationEditor, @@ -86,6 +87,8 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { @property() public automationId: string | null = null; + @property() public entityId: string | null = null; + @property() public automations!: AutomationEntity[]; @property() public isWide?: boolean; @@ -104,6 +107,8 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { @state() private _mode: "gui" | "yaml" = "gui"; + @state() private _readOnly = false; + @query("ha-yaml-editor", true) private _yamlEditor?: HaYamlEditor; @query("manual-automation-editor") @@ -198,7 +203,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { ${this.hass.localize( "ui.panel.config.automation.editor.change_mode" @@ -214,7 +219,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { ? html` ${this.hass.localize( "ui.panel.config.automation.editor.re_order" @@ -224,11 +229,15 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { : ""} - ${this.hass.localize("ui.panel.config.automation.picker.duplicate")} + ${this.hass.localize( + this._readOnly + ? "ui.panel.config.automation.editor.migrate" + : "ui.panel.config.automation.editor.duplicate" + )} ` : html` @@ -324,11 +335,25 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { .isWide=${this.isWide} .stateObj=${stateObj} .config=${this._config} + .disabled=${Boolean(this._readOnly)} @value-changed=${this._valueChanged} + @duplicate=${this._duplicate} > ` : this._mode === "yaml" ? html` + ${this._readOnly + ? html` + ${this.hass.localize( + "ui.panel.config.automation.editor.read_only" + )} + + ${this.hass.localize( + "ui.panel.config.automation.editor.migrate" + )} + + ` + : ""} ${stateObj?.state === "off" ? html` @@ -346,6 +371,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { @@ -390,7 +416,12 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { this._loadConfig(); } - if (changedProps.has("automationId") && !this.automationId && this.hass) { + if ( + changedProps.has("automationId") && + !this.automationId && + !this.entityId && + this.hass + ) { const initData = getAutomationEditorInitData(); let baseConfig: Partial = { description: "" }; if (!initData || !("use_blueprint" in initData)) { @@ -407,9 +438,19 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { ...initData, } as AutomationConfig; this._entityId = undefined; + this._readOnly = false; this._dirty = true; } + if (changedProps.has("entityId") && this.entityId) { + getAutomationStateConfig(this.hass, this.entityId).then((c) => { + this._config = c.config; + }); + this._entityId = this.entityId; + this._dirty = false; + this._readOnly = true; + } + if ( changedProps.has("automations") && this.automationId && @@ -434,7 +475,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { private async _loadConfig() { try { - const config = await getAutomationConfig( + const config = await fetchAutomationFileConfig( this.hass, this.automationId as string ); @@ -448,8 +489,19 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { } } this._dirty = false; + this._readOnly = false; this._config = config; } catch (err: any) { + const entity = Object.values(this.hass.entities).find( + (ent) => + ent.platform === "automation" && ent.unique_id === this.automationId + ); + if (entity) { + navigate(`/config/automation/show/${entity.entity_id}`, { + replace: true, + }); + return; + } await showAlertDialog(this, { text: err.status_code === 404 @@ -468,6 +520,9 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { private _valueChanged(ev: CustomEvent<{ value: AutomationConfig }>) { ev.stopPropagation(); + if (this._readOnly) { + return; + } this._config = ev.detail.value; this._dirty = true; this._errors = undefined; @@ -563,12 +618,17 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { }; private async _duplicate() { - const result = await this.confirmUnsavedChanged(); + const result = this._readOnly + ? await showConfirmationDialog(this, { + title: "Migrate automation?", + text: "You can migrate this automation, so it can be edited from the UI. After it is migrated and you have saved it, you will have to manually delete your old automation from your configuration. Do you want to migrate this automation?", + }) + : await this.confirmUnsavedChanged(); if (result) { showAutomationEditor({ ...this._config, id: undefined, - alias: undefined, + alias: this._readOnly ? this._config?.alias : undefined, }); } } diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts index 3fe409f34b..3d0327ff74 100644 --- a/src/panels/config/automation/ha-automation-picker.ts +++ b/src/panels/config/automation/ha-automation-picker.ts @@ -34,7 +34,7 @@ import { AutomationEntity, deleteAutomation, duplicateAutomation, - getAutomationConfig, + fetchAutomationFileConfig, triggerAutomationActions, } from "../../../data/automation"; import { @@ -376,7 +376,7 @@ class HaAutomationPicker extends LitElement { private async duplicate(automation) { try { - const config = await getAutomationConfig( + const config = await fetchAutomationFileConfig( this.hass, automation.attributes.id ); @@ -424,6 +424,8 @@ class HaAutomationPicker extends LitElement { if (automation?.attributes.id) { navigate(`/config/automation/edit/${automation.attributes.id}`); + } else { + navigate(`/config/automation/show/${ev.detail.id}`); } } diff --git a/src/panels/config/automation/ha-config-automation.ts b/src/panels/config/automation/ha-config-automation.ts index d1a117e616..1af2b4cadc 100644 --- a/src/panels/config/automation/ha-config-automation.ts +++ b/src/panels/config/automation/ha-config-automation.ts @@ -49,6 +49,9 @@ class HaConfigAutomation extends HassRouterPage { edit: { tag: "ha-automation-editor", }, + show: { + tag: "ha-automation-editor", + }, trace: { tag: "ha-automation-trace", load: () => import("./ha-automation-trace"), @@ -84,13 +87,22 @@ class HaConfigAutomation extends HassRouterPage { this._debouncedUpdateAutomations(pageEl); } } - + if ( + (!changedProps || changedProps.has("route")) && + this._currentPage === "show" + ) { + const automationId = decodeURIComponent(this.routeTail.path.substr(1)); + pageEl.automationId = null; + pageEl.entityId = automationId === "new" ? null : automationId; + return; + } if ( (!changedProps || changedProps.has("route")) && this._currentPage !== "dashboard" ) { const automationId = decodeURIComponent(this.routeTail.path.substr(1)); pageEl.automationId = automationId === "new" ? null : automationId; + pageEl.entityId = null; } } } diff --git a/src/panels/config/automation/manual-automation-editor.ts b/src/panels/config/automation/manual-automation-editor.ts index d13d54ae34..0ef9d6b166 100644 --- a/src/panels/config/automation/manual-automation-editor.ts +++ b/src/panels/config/automation/manual-automation-editor.ts @@ -28,6 +28,8 @@ export class HaManualAutomationEditor extends LitElement { @property({ type: Boolean }) public narrow!: boolean; + @property({ type: Boolean }) public disabled = false; + @property({ attribute: false }) public config!: ManualAutomationConfig; @property({ attribute: false }) public stateObj?: HassEntity; @@ -37,6 +39,14 @@ export class HaManualAutomationEditor extends LitElement { protected render() { return html` + ${this.disabled + ? html` + ${this.hass.localize("ui.panel.config.automation.editor.read_only")} + + ${this.hass.localize("ui.panel.config.automation.editor.migrate")} + + ` + : ""} ${this.stateObj?.state === "off" ? html` @@ -100,6 +110,7 @@ export class HaManualAutomationEditor extends LitElement { @value-changed=${this._triggerChanged} .hass=${this.hass} .reOrderMode=${this.reOrderMode} + .disabled=${this.disabled} >
    @@ -129,6 +140,7 @@ export class HaManualAutomationEditor extends LitElement { @value-changed=${this._conditionChanged} .hass=${this.hass} .reOrderMode=${this.reOrderMode} + .disabled=${this.disabled} >
    @@ -161,6 +173,7 @@ export class HaManualAutomationEditor extends LitElement { .hass=${this.hass} .narrow=${this.narrow} .reOrderMode=${this.reOrderMode} + .disabled=${this.disabled} > `; } @@ -202,6 +215,10 @@ export class HaManualAutomationEditor extends LitElement { }); } + private _duplicate() { + fireEvent(this, "duplicate"); + } + static get styles(): CSSResultGroup { return [ haStyle, diff --git a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts index 8d71152164..d20053d184 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts @@ -89,6 +89,8 @@ export default class HaAutomationTriggerRow extends LitElement { @property({ type: Boolean }) public hideMenu = false; + @property({ type: Boolean }) public disabled = false; + @state() private _warnings?: string[]; @state() private _yamlMode = false; @@ -148,7 +150,7 @@ export default class HaAutomationTriggerRow extends LitElement { .path=${mdiDotsVertical} > - + ${this.hass.localize( "ui.panel.config.automation.editor.triggers.rename" )} @@ -157,7 +159,7 @@ export default class HaAutomationTriggerRow extends LitElement { .path=${mdiRenameBox} > - + ${this.hass.localize( "ui.panel.config.automation.editor.actions.duplicate" )} @@ -167,7 +169,7 @@ export default class HaAutomationTriggerRow extends LitElement { > - + ${this.hass.localize( "ui.panel.config.automation.editor.triggers.edit_id" )} @@ -207,7 +209,7 @@ export default class HaAutomationTriggerRow extends LitElement {
  • - + ${this.trigger.enabled === false ? this.hass.localize( "ui.panel.config.automation.editor.actions.enable" @@ -222,7 +224,11 @@ export default class HaAutomationTriggerRow extends LitElement { : mdiStopCircleOutline} > - + ${this.hass.localize( "ui.panel.config.automation.editor.actions.delete" )} @@ -273,6 +279,7 @@ export default class HaAutomationTriggerRow extends LitElement { ` @@ -292,7 +299,11 @@ export default class HaAutomationTriggerRow extends LitElement {
    ${dynamicElement( `ha-automation-trigger-${this.trigger.platform}`, - { hass: this.hass, trigger: this.trigger } + { + hass: this.hass, + trigger: this.trigger, + disabled: this.disabled, + } )}
    `} diff --git a/src/panels/config/automation/trigger/ha-automation-trigger.ts b/src/panels/config/automation/trigger/ha-automation-trigger.ts index f15b57f07d..38fc5e6de5 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger.ts @@ -45,6 +45,8 @@ export default class HaAutomationTrigger extends LitElement { @property({ type: Boolean }) public reOrderMode = false; + @property({ type: Boolean }) public disabled = false; + private _focusLastTriggerOnChange = false; private _triggerKeys = new WeakMap(); @@ -65,6 +67,7 @@ export default class HaAutomationTrigger extends LitElement { @duplicate=${this._duplicateTrigger} @value-changed=${this._triggerChanged} .hass=${this.hass} + .disabled=${this.disabled} > ${this.reOrderMode ? html` @@ -97,13 +100,14 @@ export default class HaAutomationTrigger extends LitElement { ` )}
    - + diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-calendar.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-calendar.ts index a9a5ae7030..c9cccc4795 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-calendar.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-calendar.ts @@ -17,6 +17,8 @@ export class HaCalendarTrigger extends LitElement implements TriggerElement { @property({ attribute: false }) public trigger!: CalendarTrigger; + @property({ type: Boolean }) public disabled = false; + private _schema = memoizeOne( (localize: LocalizeFunc) => [ @@ -97,6 +99,7 @@ export class HaCalendarTrigger extends LitElement implements TriggerElement { .schema=${schema} .data=${data} .hass=${this.hass} + .disabled=${this.disabled} .computeLabel=${this._computeLabelCallback} @value-changed=${this._valueChanged} > diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts index bf5f1523bb..22207e1f3f 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts @@ -19,6 +19,8 @@ export class HaDeviceTrigger extends LitElement { @property({ type: Object }) public trigger!: DeviceTrigger; + @property({ type: Boolean }) public disabled = false; + @state() private _deviceId?: string; @state() private _capabilities?: DeviceCapabilities; @@ -53,6 +55,7 @@ export class HaDeviceTrigger extends LitElement { .value=${deviceId} @value-changed=${this._devicePicked} .hass=${this.hass} + .disabled=${this.disabled} label=${this.hass.localize( "ui.panel.config.automation.editor.triggers.type.device.label" )} @@ -62,6 +65,7 @@ export class HaDeviceTrigger extends LitElement { .deviceId=${deviceId} @value-changed=${this._deviceTriggerPicked} .hass=${this.hass} + .disabled=${this.disabled} label=${this.hass.localize( "ui.panel.config.automation.editor.triggers.type.device.trigger" )} @@ -72,6 +76,7 @@ export class HaDeviceTrigger extends LitElement { .hass=${this.hass} .data=${this._extraFieldsData(this.trigger, this._capabilities)} .schema=${this._capabilities.extra_fields} + .disabled=${this.disabled} .computeLabel=${this._extraFieldsComputeLabelCallback( this.hass.localize )} diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts index 5c191e76db..3d997e81a4 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts @@ -17,6 +17,8 @@ export class HaEventTrigger extends LitElement implements TriggerElement { @property() public trigger!: EventTrigger; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return { event_type: "" }; } @@ -30,6 +32,7 @@ export class HaEventTrigger extends LitElement implements TriggerElement { )} name="event_type" .value=${event_type} + .disabled=${this.disabled} @change=${this._valueChanged} > @@ -53,6 +57,7 @@ export class HaEventTrigger extends LitElement implements TriggerElement { "ui.panel.config.automation.editor.triggers.type.event.context_user_pick" )} .hass=${this.hass} + .disabled=${this.disabled} .value=${this._wrapUsersInArray(context?.user_id)} @value-changed=${this._usersChanged} > diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts index c2b8020696..849a91b2d8 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts @@ -14,6 +14,8 @@ export class HaGeolocationTrigger extends LitElement { @property({ attribute: false }) public trigger!: GeoLocationTrigger; + @property({ type: Boolean }) public disabled = false; + private _schema = memoizeOne( (localize: LocalizeFunc) => [ @@ -55,6 +57,7 @@ export class HaGeolocationTrigger extends LitElement { .schema=${this._schema(this.hass.localize)} .data=${this.trigger} .hass=${this.hass} + .disabled=${this.disabled} .computeLabel=${this._computeLabelCallback} @value-changed=${this._valueChanged} > diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts index eebd3b0a6c..d0d9629d7e 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts @@ -14,6 +14,8 @@ export class HaHassTrigger extends LitElement { @property({ attribute: false }) public trigger!: HassTrigger; + @property({ type: Boolean }) public disabled = false; + private _schema = memoizeOne( (localize: LocalizeFunc) => [ @@ -51,6 +53,7 @@ export class HaHassTrigger extends LitElement { .schema=${this._schema(this.hass.localize)} .data=${this.trigger} .hass=${this.hass} + .disabled=${this.disabled} .computeLabel=${this._computeLabelCallback} @value-changed=${this._valueChanged} > diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts index 85bd81aa3e..e01df554e9 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts @@ -18,6 +18,8 @@ export class HaMQTTTrigger extends LitElement implements TriggerElement { @property({ attribute: false }) public trigger!: MqttTrigger; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return { topic: "" }; } @@ -28,6 +30,7 @@ export class HaMQTTTrigger extends LitElement implements TriggerElement { .schema=${SCHEMA} .data=${this.trigger} .hass=${this.hass} + .disabled=${this.disabled} .computeLabel=${this._computeLabelCallback} @value-changed=${this._valueChanged} > diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts index f7a8540a8b..ff75075781 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts @@ -15,6 +15,8 @@ export class HaNumericStateTrigger extends LitElement { @property({ attribute: false }) public trigger!: NumericStateTrigger; + @property({ type: Boolean }) public disabled = false; + private _schema = memoizeOne( (entityId) => [ @@ -152,6 +154,7 @@ export class HaNumericStateTrigger extends LitElement { .hass=${this.hass} .data=${data} .schema=${schema} + .disabled=${this.disabled} @value-changed=${this._valueChanged} .computeLabel=${this._computeLabelCallback} > diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts index 8a313b955f..abce03227e 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts @@ -41,6 +41,8 @@ export class HaStateTrigger extends LitElement implements TriggerElement { @property({ attribute: false }) public trigger!: StateTrigger; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return { entity_id: [] }; } @@ -155,6 +157,7 @@ export class HaStateTrigger extends LitElement implements TriggerElement { .schema=${schema} @value-changed=${this._valueChanged} .computeLabel=${this._computeLabelCallback} + .disabled=${this.disabled} > `; } diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts index d50de420ca..3696952110 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts @@ -15,6 +15,8 @@ export class HaSunTrigger extends LitElement implements TriggerElement { @property({ attribute: false }) public trigger!: SunTrigger; + @property({ type: Boolean }) public disabled = false; + private _schema = memoizeOne( (localize: LocalizeFunc) => [ @@ -55,6 +57,7 @@ export class HaSunTrigger extends LitElement implements TriggerElement { .schema=${schema} .data=${this.trigger} .hass=${this.hass} + .disabled=${this.disabled} .computeLabel=${this._computeLabelCallback} @value-changed=${this._valueChanged} > diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-tag.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-tag.ts index 18c702bf16..4d09932c75 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-tag.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-tag.ts @@ -15,6 +15,8 @@ export class HaTagTrigger extends LitElement implements TriggerElement { @property() public trigger!: TagTrigger; + @property({ type: Boolean }) public disabled = false; + @state() private _tags?: Tag[]; public static get defaultConfig() { @@ -35,7 +37,7 @@ export class HaTagTrigger extends LitElement implements TriggerElement { .label=${this.hass.localize( "ui.panel.config.automation.editor.triggers.type.tag.label" )} - .disabled=${this._tags.length === 0} + .disabled=${this.disabled || this._tags.length === 0} .value=${this.trigger.tag_id} @selected=${this._tagChanged} > diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts index 063aece21c..3aa1c02367 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts @@ -11,6 +11,8 @@ export class HaTemplateTrigger extends LitElement { @property({ attribute: false }) public trigger!: TemplateTrigger; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return { value_template: "" }; } @@ -29,6 +31,7 @@ export class HaTemplateTrigger extends LitElement { mode="jinja2" .hass=${this.hass} .value=${value_template} + .readOnly=${this.disabled} autocomplete-entities @value-changed=${this._valueChanged} dir="ltr" diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts index a25b1ee1ca..1375312e3f 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts @@ -15,6 +15,8 @@ export class HaTimeTrigger extends LitElement implements TriggerElement { @property({ attribute: false }) public trigger!: TimeTrigger; + @property({ type: Boolean }) public disabled = false; + @state() private _inputMode?: boolean; public static get defaultConfig() { @@ -89,6 +91,7 @@ export class HaTimeTrigger extends LitElement implements TriggerElement { .hass=${this.hass} .data=${data} .schema=${schema} + .disabled=${this.disabled} @value-changed=${this._valueChanged} .computeLabel=${this._computeLabelCallback} > diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts index da24934ec2..862ce881f6 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts @@ -19,6 +19,8 @@ export class HaTimePatternTrigger extends LitElement implements TriggerElement { @property({ attribute: false }) public trigger!: TimePatternTrigger; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return {}; } @@ -29,6 +31,7 @@ export class HaTimePatternTrigger extends LitElement implements TriggerElement { .hass=${this.hass} .schema=${SCHEMA} .data=${this.trigger} + .disabled=${this.disabled} .computeLabel=${this._computeLabelCallback} @value-changed=${this._valueChanged} > diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts index c612ad3162..d546293fe4 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts @@ -24,6 +24,8 @@ export class HaWebhookTrigger extends LitElement { @property() public trigger!: WebhookTrigger; + @property({ type: Boolean }) public disabled = false; + @state() private _config?: AutomationConfig; private _unsub?: UnsubscribeFunc; @@ -88,6 +90,7 @@ export class HaWebhookTrigger extends LitElement { .helper=${this.hass.localize( "ui.panel.config.automation.editor.triggers.type.webhook.webhook_id_helper" )} + .disabled=${this.disabled} iconTrailing .value=${webhookId || ""} @input=${this._valueChanged} diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts index 7b97d9a5eb..90fac7e280 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts @@ -22,6 +22,8 @@ export class HaZoneTrigger extends LitElement { @property() public trigger!: ZoneTrigger; + @property({ type: Boolean }) public disabled = false; + public static get defaultConfig() { return { entity_id: "", @@ -38,6 +40,7 @@ export class HaZoneTrigger extends LitElement { "ui.panel.config.automation.editor.triggers.type.zone.entity" )} .value=${entity_id} + .disabled=${this.disabled} @value-changed=${this._entityPicked} .hass=${this.hass} allow-custom-entity @@ -48,6 +51,7 @@ export class HaZoneTrigger extends LitElement { "ui.panel.config.automation.editor.triggers.type.zone.zone" )} .value=${zone} + .disabled=${this.disabled} @value-changed=${this._zonePicked} .hass=${this.hass} allow-custom-entity @@ -59,6 +63,7 @@ export class HaZoneTrigger extends LitElement { "ui.panel.config.automation.editor.triggers.type.zone.event" )} diff --git a/src/translations/en.json b/src/translations/en.json index 6def4400c0..be41292a20 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1847,6 +1847,8 @@ "enable": "[%key:ui::common::enable%]", "disable": "[%key:ui::common::disable%]", "disabled": "Automation is disabled", + "read_only": "This automation can not be edited from the UI, because it is not stored in the automations.yaml file, or doesn't have an ID.", + "migrate": "Migrate", "run": "[%key:ui::panel::config::automation::editor::actions::run%]", "rename": "[%key:ui::panel::config::automation::editor::triggers::rename%]", "show_trace": "Traces",