1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-04-02 08:33:31 +01:00

Move loadConfig to common mixin (#30171)

This commit is contained in:
karwosts
2026-03-16 08:34:41 -07:00
committed by GitHub
parent 619c75ac8b
commit e2e5feb8d5
6 changed files with 102 additions and 123 deletions

View File

@@ -1,5 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import { consume } from "@lit/context";
import {
mdiAppleKeyboardCommand,
mdiCog,
@@ -24,7 +23,7 @@ import {
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { customElement, property, query } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { UndoRedoController } from "../../../common/controllers/undo-redo-controller";
import { fireEvent } from "../../../common/dom/fire_event";
@@ -57,7 +56,6 @@ import {
} from "../../../data/automation";
import { substituteBlueprint } from "../../../data/blueprint";
import { validateConfig } from "../../../data/config";
import { fullEntitiesContext } from "../../../data/context";
import { UNAVAILABLE } from "../../../data/entity/entity";
import {
type EntityRegistryEntry,
@@ -80,6 +78,7 @@ import { showAutomationModeDialog } from "./automation-mode-dialog/show-dialog-a
import { showAutomationSaveDialog } from "./automation-save-dialog/show-dialog-automation-save";
import { showAutomationSaveTimeoutDialog } from "./automation-save-timeout-dialog/show-dialog-automation-save-timeout";
import "./blueprint-automation-editor";
import type { EditorDomainHooks } from "./ha-automation-script-editor-mixin";
import {
AutomationScriptEditorMixin,
automationScriptEditorStyles,
@@ -117,10 +116,6 @@ export class HaAutomationEditor extends AutomationScriptEditorMixin<AutomationCo
@property({ attribute: false }) public automations!: AutomationEntity[];
@state()
@consume({ context: fullEntitiesContext, subscribe: true })
_entityRegistry!: EntityRegistryEntry[];
@query("manual-automation-editor")
private _manualEditor?: HaManualAutomationEditor;
@@ -133,6 +128,13 @@ export class HaAutomationEditor extends AutomationScriptEditorMixin<AutomationCo
private _newAutomationId?: string;
protected domainHooks: EditorDomainHooks<AutomationConfig> = {
domain: "automation",
fetchFileConfig: fetchAutomationFileConfig,
normalizeConfig: normalizeAutomationConfig,
checkValidation: () => this._checkValidation(),
};
private _undoRedoController = new UndoRedoController<AutomationConfig>(this, {
apply: (config) => this._applyUndoRedo(config),
currentConfig: () => this.config!,
@@ -144,9 +146,9 @@ export class HaAutomationEditor extends AutomationScriptEditorMixin<AutomationCo
if (
this.entityRegCreated &&
this._newAutomationId &&
changedProps.has("_entityRegistry")
changedProps.has("entityRegistry")
) {
const automation = this._entityRegistry.find(
const automation = this.entityRegistry.find(
(entity: EntityRegistryEntry) =>
entity.platform === "automation" &&
entity.unique_id === this._newAutomationId
@@ -576,7 +578,7 @@ export class HaAutomationEditor extends AutomationScriptEditorMixin<AutomationCo
oldAutomationId !== this.automationId
) {
this._setEntityId();
this._loadConfig();
this.loadConfig(this.automationId);
}
if (
@@ -663,49 +665,6 @@ export class HaAutomationEditor extends AutomationScriptEditorMixin<AutomationCo
);
}
private async _loadConfig() {
try {
const config = await fetchAutomationFileConfig(
this.hass,
this.automationId as string
);
this.dirty = false;
this.readOnly = false;
this.config = normalizeAutomationConfig(config);
this._checkValidation();
} catch (err: any) {
if (err.status_code !== 404) {
const alertText =
err.body?.message || err.error || err.body || "Unknown error";
await showAlertDialog(this, {
title: this.hass.localize(
"ui.panel.config.automation.editor.load_error_unknown",
{ err_no: err.status_code ?? "unknown" }
),
text: html`<pre>${alertText}</pre>`,
});
goBack("/config");
return;
}
const entity = this._entityRegistry.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: this.hass.localize(
"ui.panel.config.automation.editor.load_error_not_editable"
),
});
goBack("/config");
}
}
private _valueChanged(ev: ValueChangedEvent<AutomationConfig>) {
ev.stopPropagation();

View File

@@ -3,11 +3,14 @@ import type { CSSResult, TemplateResult, LitElement } from "lit";
import { css, html } from "lit";
import { property, state } from "lit/decorators";
import { transform } from "../../../common/decorators/transform";
import { goBack } from "../../../common/navigate";
import { goBack, navigate } from "../../../common/navigate";
import { afterNextRender } from "../../../common/util/render-status";
import { fullEntitiesContext } from "../../../data/context";
import type { EntityRegistryEntry } from "../../../data/entity/entity_registry";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import {
showAlertDialog,
showConfirmationDialog,
} from "../../../dialogs/generic/show-dialog-box";
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
import type { Constructor, HomeAssistant, Route } from "../../../types";
import type { EntityRegistryUpdate } from "./automation-save-dialog/show-dialog-automation-save";
@@ -67,6 +70,13 @@ export const automationScriptEditorStyles: CSSResult = css`
}
`;
export interface EditorDomainHooks<TConfig> {
fetchFileConfig(hass: HomeAssistant, id: string): Promise<TConfig>;
normalizeConfig(raw: TConfig): TConfig;
checkValidation(): Promise<void>;
domain: "automation" | "script";
}
export const AutomationScriptEditorMixin = <TConfig extends BaseEditorConfig>(
superClass: Constructor<LitElement>
) => {
@@ -81,6 +91,10 @@ export const AutomationScriptEditorMixin = <TConfig extends BaseEditorConfig>(
@property({ attribute: false }) public entityId: string | null = null;
@state()
@consume({ context: fullEntitiesContext, subscribe: true })
entityRegistry!: EntityRegistryEntry[];
@state() protected dirty = false;
@state() protected errors?: string;
@@ -115,6 +129,8 @@ export const AutomationScriptEditorMixin = <TConfig extends BaseEditorConfig>(
protected entityRegistryUpdate?: EntityRegistryUpdate;
protected domainHooks!: EditorDomainHooks<TConfig>;
protected entityRegCreated?: (
value: PromiseLike<EntityRegistryEntry> | EntityRegistryEntry
) => void;
@@ -194,6 +210,47 @@ export const AutomationScriptEditorMixin = <TConfig extends BaseEditorConfig>(
protected confirmUnsavedChanged(): Promise<boolean> {
return Promise.resolve(true);
}
protected async loadConfig(id: string) {
const hooks = this.domainHooks;
const domain = hooks.domain;
try {
const config = await hooks.fetchFileConfig(this.hass, id);
this.dirty = false;
this.readOnly = false;
this.config = hooks.normalizeConfig(config);
hooks.checkValidation();
} catch (err: any) {
if (err.status_code !== 404) {
const alertText =
err.body?.message || err.body || err.error || "Unknown error";
await showAlertDialog(this, {
title: this.hass.localize(
`ui.panel.config.${domain}.editor.load_error_unknown`,
{ err_no: err.status_code ?? "unknown" }
),
text: html`<pre>${alertText}</pre>`,
});
goBack("/config");
return;
}
const entity = this.entityRegistry.find(
(ent) => ent.platform === domain && ent.unique_id === id
);
if (entity) {
navigate(`/config/${domain}/show/${entity.entity_id}`, {
replace: true,
});
return;
}
await showAlertDialog(this, {
text: this.hass.localize(
`ui.panel.config.${domain}.editor.load_error_not_editable`
),
});
goBack("/config");
}
}
}
return AutomationScriptEditorClass;
};

View File

@@ -1,13 +1,10 @@
import { consume } from "@lit/context";
import type { HassEntities } from "home-assistant-js-websocket";
import type { PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import { customElement, property } from "lit/decorators";
import memoizeOne from "memoize-one";
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import { debounce } from "../../../common/util/debounce";
import type { CloudStatus } from "../../../data/cloud";
import { fullEntitiesContext } from "../../../data/context";
import type { EntityRegistryEntry } from "../../../data/entity/entity_registry";
import type { ScriptEntity } from "../../../data/script";
import type { RouterOptions } from "../../../layouts/hass-router-page";
import { HassRouterPage } from "../../../layouts/hass-router-page";
@@ -36,10 +33,6 @@ class HaConfigScript extends HassRouterPage {
@property({ attribute: false }) public scripts: ScriptEntity[] = [];
@state()
@consume({ context: fullEntitiesContext, subscribe: true })
_entityReg: EntityRegistryEntry[] = [];
protected routerOptions: RouterOptions = {
defaultPage: "dashboard",
routes: {
@@ -86,7 +79,6 @@ class HaConfigScript extends HassRouterPage {
pageEl.isWide = this.isWide;
pageEl.route = this.routeTail;
pageEl.showAdvanced = this.showAdvanced;
pageEl.entityRegistry = this._entityReg;
pageEl.cloudStatus = this.cloudStatus;
if (this.hass) {

View File

@@ -71,6 +71,7 @@ import { showAutomationSaveDialog } from "../automation/automation-save-dialog/s
import { showAutomationSaveTimeoutDialog } from "../automation/automation-save-timeout-dialog/show-dialog-automation-save-timeout";
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
import "./blueprint-script-editor";
import type { EditorDomainHooks } from "../automation/ha-automation-script-editor-mixin";
import {
AutomationScriptEditorMixin,
automationScriptEditorStyles,
@@ -87,13 +88,18 @@ export class HaScriptEditor extends SubscribeMixin(
) {
@property({ attribute: false }) public scriptId: string | null = null;
@property({ attribute: false }) public entityRegistry!: EntityRegistryEntry[];
@query("manual-script-editor")
private _manualEditor?: HaManualScriptEditor;
private _newScriptId?: string;
protected domainHooks: EditorDomainHooks<ScriptConfig> = {
domain: "script",
fetchFileConfig: fetchScriptFileConfig,
normalizeConfig: normalizeScriptConfig,
checkValidation: () => this._checkValidation(),
};
private _undoRedoController = new UndoRedoController<ScriptConfig>(this, {
apply: (config) => this._applyUndoRedo(config),
currentConfig: () => this.config!,
@@ -480,6 +486,13 @@ export class HaScriptEditor extends SubscribeMixin(
`;
}
private _setEntityId() {
const entity = this.entityRegistry.find(
(ent) => ent.platform === "script" && ent.unique_id === this.scriptId
);
this.currentEntityId = entity?.entity_id;
}
protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);
@@ -492,7 +505,8 @@ export class HaScriptEditor extends SubscribeMixin(
// Only refresh config if we picked a new script. If same ID, don't fetch it.
(!oldScript || oldScript !== this.scriptId)
) {
this._loadConfig();
this._setEntityId();
this.loadConfig(this.scriptId);
}
if (
@@ -500,11 +514,7 @@ export class HaScriptEditor extends SubscribeMixin(
this.scriptId &&
this.entityRegistry
) {
// find entity for when script entity id changed
const entity = this.entityRegistry.find(
(ent) => ent.platform === "script" && ent.unique_id === this.scriptId
);
this.currentEntityId = entity?.entity_id;
this._setEntityId();
}
if (changedProps.has("scriptId") && !this.scriptId && this.hass) {
@@ -562,43 +572,6 @@ export class HaScriptEditor extends SubscribeMixin(
);
}
private async _loadConfig() {
fetchScriptFileConfig(this.hass, this.scriptId!).then(
(config) => {
this.dirty = false;
this.readOnly = false;
this.config = normalizeScriptConfig(config);
const entity = this.entityRegistry.find(
(ent) => ent.platform === "script" && ent.unique_id === this.scriptId
);
this.currentEntityId = entity?.entity_id;
this._checkValidation();
},
(resp) => {
const entity = this.entityRegistry.find(
(ent) => ent.platform === "script" && ent.unique_id === this.scriptId
);
if (entity) {
navigate(`/config/script/show/${entity.entity_id}`, {
replace: true,
});
return;
}
alert(
resp.status_code === 404
? this.hass.localize(
"ui.panel.config.script.editor.load_error_not_editable"
)
: this.hass.localize(
"ui.panel.config.script.editor.load_error_unknown",
{ err_no: resp.status_code || resp.code }
)
);
goBack("/config");
}
);
}
private _valueChanged(ev) {
if (this.config) {
this._undoRedoController.commit(this.config);

View File

@@ -146,8 +146,6 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public cloudStatus?: CloudStatus;
@property({ attribute: false }) public entityRegistry!: EntityRegistryEntry[];
@state() private _searchParms = new URLSearchParams(window.location.search);
@state() private _selected: string[] = [];
@@ -933,7 +931,7 @@ ${rejected
}
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
const entry = this.entityRegistry.find((e) => e.entity_id === ev.detail.id);
const entry = this._entityReg.find((e) => e.entity_id === ev.detail.id);
if (entry) {
navigate(`/config/script/edit/${entry.unique_id}`);
} else {
@@ -950,9 +948,7 @@ ${rejected
}
private _runScript = async (script: any) => {
const entry = this.entityRegistry.find(
(e) => e.entity_id === script.entity_id
);
const entry = this._entityReg.find((e) => e.entity_id === script.entity_id);
if (!entry) {
return;
}
@@ -981,9 +977,7 @@ ${rejected
}
private _showTrace(script: any) {
const entry = this.entityRegistry.find(
(e) => e.entity_id === script.entity_id
);
const entry = this._entityReg.find((e) => e.entity_id === script.entity_id);
if (entry) {
navigate(`/config/script/trace/${entry.unique_id}`);
}
@@ -1009,7 +1003,7 @@ ${rejected
private async _duplicate(script: any) {
try {
const entry = this.entityRegistry.find(
const entry = this._entityReg.find(
(e) => e.entity_id === script.entity_id
);
if (!entry) {
@@ -1058,7 +1052,7 @@ ${rejected
private async _delete(script: any) {
try {
const entry = this.entityRegistry.find(
const entry = this._entityReg.find(
(e) => e.entity_id === script.entity_id
);
if (entry) {

View File

@@ -13,6 +13,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { repeat } from "lit/directives/repeat";
import { consume } from "@lit/context";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time";
import { fireEvent } from "../../../common/dom/fire_event";
@@ -44,6 +45,7 @@ import { haStyle } from "../../../resources/styles";
import type { HomeAssistant, Route } from "../../../types";
import { fileDownload } from "../../../util/file_download";
import type { HaDropdownSelectEvent } from "../../../components/ha-dropdown";
import { fullEntitiesContext } from "../../../data/context";
@customElement("ha-script-trace")
export class HaScriptTrace extends LitElement {
@@ -59,7 +61,9 @@ export class HaScriptTrace extends LitElement {
@property({ attribute: false }) public route!: Route;
@property({ attribute: false }) public entityRegistry!: EntityRegistryEntry[];
@state()
@consume({ context: fullEntitiesContext, subscribe: true })
_entityRegistry!: EntityRegistryEntry[];
@state() private _entityId?: string;
@@ -346,7 +350,7 @@ export class HaScriptTrace extends LitElement {
const params = new URLSearchParams(location.search);
this._loadTraces(params.get("run_id") || undefined);
this._entityId = this.entityRegistry.find(
this._entityId = this._entityRegistry.find(
(entry) => entry.unique_id === this.scriptId
)?.entity_id;
}
@@ -363,7 +367,7 @@ export class HaScriptTrace extends LitElement {
if (this.scriptId) {
this._loadTraces();
this._entityId = this.entityRegistry.find(
this._entityId = this._entityRegistry.find(
(entry) => entry.unique_id === this.scriptId
)?.entity_id;
}