Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/dialogs/form/dialog-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,13 @@ export class DialogForm
): Promise<void> {
await this._afterFormRender();

if (!this._open || this._params !== expectedParams) {
if (!this.isConnected || !this._open || this._params !== expectedParams) {
return;
}

await this._waitForSelectorElements();

if (!this._open || this._params !== expectedParams) {
if (!this.isConnected || !this._open || this._params !== expectedParams) {
return;
}

Expand All @@ -250,7 +250,12 @@ export class DialogForm
): Promise<void> {
await this._afterFormRender();

if (!this._open || this._params !== expectedParams || !this._dialog) {
if (
!this.isConnected ||
!this._open ||
this._params !== expectedParams ||
!this._dialog
) {
return;
}

Expand Down
26 changes: 22 additions & 4 deletions src/layouts/hass-router-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export interface RouteOptions {
// Function to load the page.
load?: () => Promise<unknown>;
cache?: boolean;
// Recreate the page when the remaining path (the item id) changes.
itemId?: boolean;
waitForReady?: boolean;
}

Expand Down Expand Up @@ -138,10 +140,23 @@ export class HassRouterPage extends ReactiveElement {
}

if (this._currentPage === newPage) {
if (this.lastChild) {
this.updatePageEl(this.lastChild, changedProps);
const oldRoute = changedProps.get("route");
const oldTail = oldRoute ? computeRouteTail(oldRoute).path : undefined;
const newTail = route ? this._computeTail(route).path : undefined;
if (
typeof routeOptions === "object" &&
routeOptions.itemId &&
oldTail !== newTail
) {
// Fall through to the normal create path so `load` / loading screen
// still run. itemId pages are not cached, so this is a new element.
this._currentPage = "";
} else {
if (this.lastChild) {
this.updatePageEl(this.lastChild, changedProps);
}
return;
}
return;
}

if (!routeOptions) {
Expand Down Expand Up @@ -365,7 +380,10 @@ export class HassRouterPage extends ReactiveElement {
this.updatePageEl(panelEl);
this.appendChild(panelEl);

if (routerOptions.cacheAll || routeOptions.cache) {
if (
(routerOptions.cacheAll || routeOptions.cache) &&
!routeOptions.itemId
) {
this._cache[page] = panelEl;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ export const AutomationScriptEditorMixin = <TConfig extends BaseEditorConfig>(
const domain = hooks.domain;
try {
const config = await hooks.fetchFileConfig(this.hass, id);
if (!this.isConnected) {
return;
}
this.readOnly = false;
const report: AutomationMigrationReport = { deprecated: false };
this.config = hooks.normalizeConfig(config, report);
Expand All @@ -294,6 +297,9 @@ export const AutomationScriptEditorMixin = <TConfig extends BaseEditorConfig>(
);
hooks.checkValidation();
} catch (err: any) {
if (!this.isConnected) {
return;
}
if (err.status_code !== 404) {
const alertText =
err.body?.message || err.body || err.error || "Unknown error";
Expand Down
2 changes: 2 additions & 0 deletions src/panels/config/automation/ha-config-automation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ class HaConfigAutomation extends HassRouterPage {
},
edit: {
tag: "ha-automation-editor",
itemId: true,
},
show: {
tag: "ha-automation-editor",
itemId: true,
},
trace: {
tag: "ha-automation-trace",
Expand Down
1 change: 1 addition & 0 deletions src/panels/config/scene/ha-config-scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class HaConfigScene extends HassRouterPage {
},
edit: {
tag: "ha-scene-editor",
itemId: true,
},
},
};
Expand Down
21 changes: 16 additions & 5 deletions src/panels/config/scene/ha-scene-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -911,11 +911,15 @@ export class HaSceneEditor extends DirtyStateProviderMixin<number>()(
}

private async _subscribeEvents() {
this._unsubscribeEvents =
await this.hass!.connection.subscribeEvents<HassEvent>(
(event) => this._stateChanged(event),
"state_changed"
);
const unsubscribe = await this.hass!.connection.subscribeEvents<HassEvent>(
(event) => this._stateChanged(event),
"state_changed"
);
if (!this.isConnected || this._mode !== "live") {
unsubscribe();
return;
}
this._unsubscribeEvents = unsubscribe;
}

private _showMoreInfo(ev: Event) {
Expand All @@ -928,6 +932,9 @@ export class HaSceneEditor extends DirtyStateProviderMixin<number>()(
try {
config = await getSceneConfig(this.hass, this.sceneId!);
} catch (err: any) {
if (!this.isConnected) {
return;
}
await showAlertDialog(this, {
text:
err.status_code === 404
Expand All @@ -943,6 +950,10 @@ export class HaSceneEditor extends DirtyStateProviderMixin<number>()(
return;
}

if (!this.isConnected) {
return;
}

if (!config.entities) {
config.entities = {};
}
Expand Down
2 changes: 2 additions & 0 deletions src/panels/config/script/ha-config-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ class HaConfigScript extends HassRouterPage {
},
edit: {
tag: "ha-script-editor",
itemId: true,
},
show: {
tag: "ha-script-editor",
itemId: true,
},
trace: {
tag: "ha-script-trace",
Expand Down
8 changes: 7 additions & 1 deletion test/dialogs/form/dialog-form.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { deepActiveElement } from "../../../src/common/dom/deep-active-element";
import { nextRender } from "../../../src/common/util/render-status";
import type {
FormDialogData,
FormDialogParams,
Expand Down Expand Up @@ -146,8 +147,13 @@ const submit = (dialog: DialogForm) =>
const cancel = (dialog: DialogForm) =>
(getInternals(dialog)["_cancel"] as () => void)();

afterEach(() => {
afterEach(async () => {
mockForm.delayedTag = undefined;
document.body.querySelectorAll("dialog-form").forEach((el) => {
(el as DialogForm).closeDialog();
});
// Drain the fire-and-forget focus restore before jsdom teardown.
await nextRender();
document.body.replaceChildren();
vi.clearAllMocks();
});
Expand Down
Loading