Compare commits

...
Author SHA1 Message Date
Maarten Lakerveld da9adc26e5 Drop a queued more-info restore when the URL's view moved on
Two deep links for the same entity with different views queued in one
frame let the older restore open the dialog and write its view back to
the URL. The queued restore now also bails when the URL's view differs
from the one it captured, so the newest deep link wins.
2026-11-05 16:21:38 +01:00
Maarten Lakerveld 9b9a9d86e8 Only skip the more-info restore for the entity already shown
The restore skipped whenever a more-info dialog was open. A deep link
that arrived while the previous dialog was still closing after
navigate's wait was dropped, and when two deep links queued up the
older one won and the newer was never opened.

The dialog manager now exposes the params a dialog was shown with. The
restore skips only when the open dialog already shows the URL's entity,
and a queued restore bails when the URL moved on to another entity.
2026-11-05 16:06:34 +01:00
Maarten Lakerveld 26c71b2712 Keep dialogs on the remaining default-route redirects
The energy panel, the energy config tabs and the media browser fill in
their default route with a replace, which closed a dialog restored from
the URL and dropped the query the restore needs. They now pass
keepDialogs and keep the query, like the router and dashboard redirects.

The more-info restore runs on every location change, so those redirects
re-showed the dialog that was already open. That hoisted it above any
dialog opened on top of it and reset its view. Skip the restore while
the more-info dialog is open.
2026-11-05 16:06:27 +01:00
5 changed files with 29 additions and 3 deletions

No files matched your search

+5
View File
@@ -85,6 +85,11 @@ const _removeOpenDialogTag = (dialogTag: string) => {
export const getTopOpenDialogTag = (): string | undefined =>
OPEN_DIALOG_TAGS[OPEN_DIALOG_TAGS.length - 1];
/** The params the dialog with this tag was shown with, while it is open. */
export const getOpenDialogParams = <T>(dialogTag: string): T | undefined =>
OPEN_DIALOG_STACK.find((dialog) => dialog.dialogTag === dialogTag)
?.dialogParams as T | undefined;
/** The URL of the last dialog's entry, when the dialog went back to close. */
let closedDialogUrl: { pathname: string; search: string } | undefined;
+12
View File
@@ -15,6 +15,8 @@ import type { WindowWithPreloads } from "../data/preloads";
import type { RecorderInfo } from "../data/recorder";
import { getRecorderInfo } from "../data/recorder";
import { showHttpPendingConfigDialog } from "../dialogs/http-pending-config/show-dialog-http-pending-config";
import { getOpenDialogParams } from "../dialogs/make-dialog-manager";
import type { MoreInfoDialogParams } from "../dialogs/more-info/ha-more-info-dialog";
import { showMoreInfoDialog } from "../dialogs/more-info/show-ha-more-info-dialog";
import "../resources/custom-card-support";
import { HassElement } from "../state/hass-element";
@@ -327,6 +329,16 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
// Wait for the next render to ensure the view is fully loaded
// because the more info dialog is closed when the url changes
afterNextRender(() => {
const current = decodeMoreInfoUrl(window.location.search);
if (current.entityId !== entityId || current.view !== view) {
return;
}
if (
getOpenDialogParams<MoreInfoDialogParams>("ha-more-info-dialog")
?.entityId === entityId
) {
return;
}
showMoreInfoDialog(this, {
entityId,
view,
+4 -1
View File
@@ -97,7 +97,10 @@ class HaConfigEnergy extends LitElement {
if (changedProperties.has("route")) {
const tab = this.route.path.substring(1);
if (!tab || !TABS.some((t) => t.path.endsWith(`/${tab}`))) {
navigate(`${this.route.prefix}/electricity`, { replace: true });
navigate(`${this.route.prefix}/electricity${location.search}`, {
replace: true,
keepDialogs: true,
});
}
}
}
+4 -1
View File
@@ -93,7 +93,10 @@ class PanelEnergy extends LitElement {
const validPaths = views.map((view) => view.path);
const viewPath: string | undefined = this.route!.path.split("/")[1];
if (!viewPath || !validPaths.includes(viewPath)) {
navigate(`${this.route!.prefix}/${validPaths[0]}`, { replace: true });
navigate(`${this.route!.prefix}/${validPaths[0]}${location.search}`, {
replace: true,
keepDialogs: true,
});
} else {
// Force hui-root to re-process the route by creating a new route object
this.route = { ...this.route! };
@@ -191,7 +191,10 @@ class PanelMediaBrowser extends LitElement {
}
if (this.route.path === "") {
navigate(`/media-browser/${this._entityId}`, { replace: true });
navigate(`/media-browser/${this._entityId}${location.search}`, {
replace: true,
keepDialogs: true,
});
return;
}