mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-18 07:56:44 +01:00
Support more-info-view query param (#30282)
* Support more-info-view query param * Remove unintended subview logic and add details view * Reset childView
This commit is contained in:
@@ -7,6 +7,22 @@ import { CONTINUOUS_DOMAINS } from "../../data/logbook";
|
|||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import { isNumericEntity } from "../../data/history";
|
import { isNumericEntity } from "../../data/history";
|
||||||
|
|
||||||
|
export const MORE_INFO_VIEWS = [
|
||||||
|
"info",
|
||||||
|
"history",
|
||||||
|
"settings",
|
||||||
|
"related",
|
||||||
|
"add_to",
|
||||||
|
"details",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type MoreInfoView = (typeof MORE_INFO_VIEWS)[number];
|
||||||
|
|
||||||
|
export const isMoreInfoView = (
|
||||||
|
value: string | undefined
|
||||||
|
): value is MoreInfoView =>
|
||||||
|
value !== undefined && (MORE_INFO_VIEWS as readonly string[]).includes(value);
|
||||||
|
|
||||||
export const DOMAINS_NO_INFO = ["camera", "configurator"];
|
export const DOMAINS_NO_INFO = ["camera", "configurator"];
|
||||||
/**
|
/**
|
||||||
* Entity domains that should be editable *if* they have an id present;
|
* Entity domains that should be editable *if* they have an id present;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { customElement, property, query, state } from "lit/decorators";
|
|||||||
import { cache } from "lit/directives/cache";
|
import { cache } from "lit/directives/cache";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { keyed } from "lit/directives/keyed";
|
import { keyed } from "lit/directives/keyed";
|
||||||
import { dynamicElement } from "../../common/dom/dynamic-element-directive";
|
import type { HASSDomEvent } from "../../common/dom/fire_event";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { stopPropagation } from "../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../common/dom/stop_propagation";
|
||||||
import { computeAreaName } from "../../common/entity/compute_area_name";
|
import { computeAreaName } from "../../common/entity/compute_area_name";
|
||||||
@@ -72,6 +72,7 @@ import {
|
|||||||
DOMAINS_WITH_MORE_INFO,
|
DOMAINS_WITH_MORE_INFO,
|
||||||
EDITABLE_DOMAINS_WITH_ID,
|
EDITABLE_DOMAINS_WITH_ID,
|
||||||
EDITABLE_DOMAINS_WITH_UNIQUE_ID,
|
EDITABLE_DOMAINS_WITH_UNIQUE_ID,
|
||||||
|
type MoreInfoView,
|
||||||
computeShowHistoryComponent,
|
computeShowHistoryComponent,
|
||||||
computeShowLogBookComponent,
|
computeShowLogBookComponent,
|
||||||
} from "./const";
|
} from "./const";
|
||||||
@@ -79,6 +80,7 @@ import "./controls/more-info-default";
|
|||||||
import type { FavoritesDialogContext } from "./favorites";
|
import type { FavoritesDialogContext } from "./favorites";
|
||||||
import { getFavoritesDialogHandler } from "./favorites";
|
import { getFavoritesDialogHandler } from "./favorites";
|
||||||
import "./ha-more-info-add-to";
|
import "./ha-more-info-add-to";
|
||||||
|
import "./ha-more-info-details";
|
||||||
import "./ha-more-info-history-and-logbook";
|
import "./ha-more-info-history-and-logbook";
|
||||||
import "./ha-more-info-info";
|
import "./ha-more-info-info";
|
||||||
import "./ha-more-info-settings";
|
import "./ha-more-info-settings";
|
||||||
@@ -86,16 +88,14 @@ import "./more-info-content";
|
|||||||
|
|
||||||
export interface MoreInfoDialogParams {
|
export interface MoreInfoDialogParams {
|
||||||
entityId: string | null;
|
entityId: string | null;
|
||||||
view?: View;
|
view?: MoreInfoView;
|
||||||
/** @deprecated Use `view` instead */
|
/** @deprecated Use `view` instead */
|
||||||
tab?: View;
|
tab?: MoreInfoView;
|
||||||
large?: boolean;
|
large?: boolean;
|
||||||
data?: Record<string, any>;
|
data?: Record<string, any>;
|
||||||
parentElement?: LitElement;
|
parentElement?: LitElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
type View = "info" | "history" | "settings" | "related" | "add_to";
|
|
||||||
|
|
||||||
interface ChildView {
|
interface ChildView {
|
||||||
viewTag: string;
|
viewTag: string;
|
||||||
viewTitle?: string;
|
viewTitle?: string;
|
||||||
@@ -112,7 +112,7 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_VIEW: View = "info";
|
const DEFAULT_VIEW: MoreInfoView = "info";
|
||||||
|
|
||||||
@customElement("ha-more-info-dialog")
|
@customElement("ha-more-info-dialog")
|
||||||
export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
||||||
@@ -134,9 +134,9 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
|
|
||||||
@state() private _data?: Record<string, any>;
|
@state() private _data?: Record<string, any>;
|
||||||
|
|
||||||
@state() private _currView: View = DEFAULT_VIEW;
|
@state() private _currView: MoreInfoView = DEFAULT_VIEW;
|
||||||
|
|
||||||
@state() private _initialView: View = DEFAULT_VIEW;
|
@state() private _initialView: MoreInfoView = DEFAULT_VIEW;
|
||||||
|
|
||||||
@state() private _childView?: ChildView;
|
@state() private _childView?: ChildView;
|
||||||
|
|
||||||
@@ -163,10 +163,15 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const view = params.view || params.tab || DEFAULT_VIEW;
|
||||||
|
|
||||||
this._data = params.data;
|
this._data = params.data;
|
||||||
this._currView = params.view || DEFAULT_VIEW;
|
this._currView = view;
|
||||||
this._initialView = params.view || DEFAULT_VIEW;
|
this._initialView = view;
|
||||||
this._childView = undefined;
|
this._childView = undefined;
|
||||||
|
this._infoEditMode = false;
|
||||||
|
this._detailsYamlMode = false;
|
||||||
|
|
||||||
this.large = params.large ?? false;
|
this.large = params.large ?? false;
|
||||||
this._fill = false;
|
this._fill = false;
|
||||||
this._open = true;
|
this._open = true;
|
||||||
@@ -253,7 +258,7 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
return entity?.device_id ?? null;
|
return entity?.device_id ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setView(view: View) {
|
private _setView(view: MoreInfoView) {
|
||||||
history.replaceState(
|
history.replaceState(
|
||||||
{
|
{
|
||||||
...history.state,
|
...history.state,
|
||||||
@@ -278,6 +283,13 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
this._detailsYamlMode = false;
|
this._detailsYamlMode = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
this._initialView !== DEFAULT_VIEW &&
|
||||||
|
this._currView === this._initialView
|
||||||
|
) {
|
||||||
|
this._resetInitialView();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this._initialView !== this._currView) {
|
if (this._initialView !== this._currView) {
|
||||||
this._setView(this._initialView);
|
this._setView(this._initialView);
|
||||||
return;
|
return;
|
||||||
@@ -404,7 +416,9 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
this._resetInitialView();
|
this._resetInitialView();
|
||||||
break;
|
break;
|
||||||
case "details":
|
case "details":
|
||||||
this._showDetails();
|
this._setView("details");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -449,15 +463,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
this._entry = result.entity_entry;
|
this._entry = result.entity_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _showDetails(): void {
|
|
||||||
import("./ha-more-info-details");
|
|
||||||
this._childView = {
|
|
||||||
viewTag: "ha-more-info-details",
|
|
||||||
viewTitle: this.hass.localize("ui.dialogs.more_info_control.details"),
|
|
||||||
viewParams: { entityId: this._entityId },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _copyFavorites() {
|
private async _copyFavorites() {
|
||||||
const favoritesContext = this._getFavoritesContext();
|
const favoritesContext = this._getFavoritesContext();
|
||||||
|
|
||||||
@@ -509,13 +514,8 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
(deviceId && this.hass.devices[deviceId].entry_type) || "device";
|
(deviceId && this.hass.devices[deviceId].entry_type) || "device";
|
||||||
|
|
||||||
const isDefaultView = this._currView === DEFAULT_VIEW && !this._childView;
|
const isDefaultView = this._currView === DEFAULT_VIEW && !this._childView;
|
||||||
const isSpecificInitialView =
|
|
||||||
this._initialView !== DEFAULT_VIEW && !this._childView;
|
|
||||||
const showCloseIcon =
|
const showCloseIcon =
|
||||||
(isDefaultView &&
|
isDefaultView && this._parentEntityIds.length === 0 && !this._childView;
|
||||||
this._parentEntityIds.length === 0 &&
|
|
||||||
!this._childView) ||
|
|
||||||
(isSpecificInitialView && !this._childView);
|
|
||||||
|
|
||||||
const context = stateObj
|
const context = stateObj
|
||||||
? getEntityContext(
|
? getEntityContext(
|
||||||
@@ -549,7 +549,11 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
const breadcrumb = [areaName, deviceName, entityName].filter(
|
const breadcrumb = [areaName, deviceName, entityName].filter(
|
||||||
(v): v is string => Boolean(v)
|
(v): v is string => Boolean(v)
|
||||||
);
|
);
|
||||||
const title = this._childView?.viewTitle || breadcrumb.pop() || entityId;
|
const defaultTitle = breadcrumb.pop() || entityId;
|
||||||
|
const title =
|
||||||
|
this._currView === "details"
|
||||||
|
? this.hass.localize("ui.dialogs.more_info_control.details")
|
||||||
|
: this._childView?.viewTitle || defaultTitle;
|
||||||
|
|
||||||
const favoritesContext =
|
const favoritesContext =
|
||||||
this._entry && stateObj
|
this._entry && stateObj
|
||||||
@@ -774,26 +778,16 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
`
|
`
|
||||||
: isSpecificInitialView
|
: this._currView === "details"
|
||||||
? html`
|
? html`
|
||||||
<ha-dropdown
|
<ha-icon-button
|
||||||
slot="headerActionItems"
|
slot="headerActionItems"
|
||||||
@closed=${stopPropagation}
|
.label=${this.hass.localize(
|
||||||
@wa-select=${this._handleMenuAction}
|
"ui.dialogs.more_info_control.toggle_yaml_mode"
|
||||||
placement="bottom-end"
|
)}
|
||||||
>
|
.path=${mdiCodeBraces}
|
||||||
<ha-icon-button
|
@click=${this._toggleDetailsYamlMode}
|
||||||
slot="trigger"
|
></ha-icon-button>
|
||||||
.label=${this.hass.localize("ui.common.menu")}
|
|
||||||
.path=${mdiDotsVertical}
|
|
||||||
></ha-icon-button>
|
|
||||||
|
|
||||||
<ha-dropdown-item value="info">
|
|
||||||
<ha-svg-icon slot="icon" .path=${mdiInformationOutline}>
|
|
||||||
</ha-svg-icon>
|
|
||||||
${this.hass.localize("ui.dialogs.more_info_control.info")}
|
|
||||||
</ha-dropdown-item>
|
|
||||||
</ha-dropdown>
|
|
||||||
`
|
`
|
||||||
: this._childView?.viewTag === "ha-more-info-details"
|
: this._childView?.viewTag === "ha-more-info-details"
|
||||||
? html`
|
? html`
|
||||||
@@ -828,12 +822,24 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
this._childView
|
this._childView
|
||||||
? html`
|
? html`
|
||||||
<div class="child-view">
|
<div class="child-view">
|
||||||
${dynamicElement(this._childView.viewTag, {
|
${this._childView.viewTag ===
|
||||||
hass: this.hass,
|
"ha-more-info-view-voice-assistants"
|
||||||
entry: this._entry,
|
? html`
|
||||||
params: this._childView.viewParams,
|
<ha-more-info-view-voice-assistants
|
||||||
yamlMode: this._detailsYamlMode,
|
.hass=${this.hass}
|
||||||
})}
|
.entry=${this._entry!}
|
||||||
|
.params=${this._childView.viewParams}
|
||||||
|
></ha-more-info-view-voice-assistants>
|
||||||
|
`
|
||||||
|
: this._childView.viewTag ===
|
||||||
|
"ha-more-info-view-vacuum-segment-mapping"
|
||||||
|
? html`
|
||||||
|
<ha-more-info-view-vacuum-segment-mapping
|
||||||
|
.hass=${this.hass}
|
||||||
|
.params=${this._childView.viewParams}
|
||||||
|
></ha-more-info-view-vacuum-segment-mapping>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: this._currView === "info"
|
: this._currView === "info"
|
||||||
@@ -879,7 +885,16 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
@add-to-action-selected=${this._goBack}
|
@add-to-action-selected=${this._goBack}
|
||||||
></ha-more-info-add-to>
|
></ha-more-info-add-to>
|
||||||
`
|
`
|
||||||
: nothing
|
: this._currView === "details"
|
||||||
|
? html`
|
||||||
|
<ha-more-info-details
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entry=${this._entry}
|
||||||
|
.params=${{ entityId }}
|
||||||
|
.yamlMode=${this._detailsYamlMode}
|
||||||
|
></ha-more-info-details>
|
||||||
|
`
|
||||||
|
: nothing
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@@ -898,14 +913,11 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
|
|
||||||
protected updated(changedProps: PropertyValues) {
|
protected updated(changedProps: PropertyValues) {
|
||||||
super.updated(changedProps);
|
super.updated(changedProps);
|
||||||
const previousChildView = changedProps.get("_childView") as
|
const previousView = changedProps.get("_currView") as
|
||||||
| ChildView
|
| MoreInfoView
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
if (
|
if (previousView === "details" && this._currView !== "details") {
|
||||||
previousChildView?.viewTag === "ha-more-info-details" &&
|
|
||||||
this._childView?.viewTag !== "ha-more-info-details"
|
|
||||||
) {
|
|
||||||
const dialog =
|
const dialog =
|
||||||
this._dialogElement?.shadowRoot?.querySelector("ha-dialog");
|
this._dialogElement?.shadowRoot?.querySelector("ha-dialog");
|
||||||
if (dialog) {
|
if (dialog) {
|
||||||
@@ -914,7 +926,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changedProps.has("_currView")) {
|
if (changedProps.has("_currView")) {
|
||||||
this._childView = undefined;
|
|
||||||
this._infoEditMode = false;
|
this._infoEditMode = false;
|
||||||
this._detailsYamlMode = false;
|
this._detailsYamlMode = false;
|
||||||
}
|
}
|
||||||
@@ -935,15 +946,25 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
window.addEventListener("show-dialog", this._disableEscapeKeyClose);
|
window.addEventListener("show-dialog", this._disableEscapeKeyClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleMoreInfoEvent(ev) {
|
private _handleMoreInfoEvent(ev: HASSDomEvent<MoreInfoDialogParams>) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
const entityId = ev.detail.entityId;
|
const entityId = ev.detail.entityId;
|
||||||
if (!entityId) {
|
if (!entityId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const view = ev.detail.view || ev.detail.tab || DEFAULT_VIEW;
|
||||||
|
if (entityId === this._entityId) {
|
||||||
|
this._infoEditMode = false;
|
||||||
|
this._detailsYamlMode = false;
|
||||||
|
this._setView(view);
|
||||||
|
return;
|
||||||
|
}
|
||||||
this._parentEntityIds = [...this._parentEntityIds, this._entityId!];
|
this._parentEntityIds = [...this._parentEntityIds, this._entityId!];
|
||||||
this._entityId = entityId;
|
this._entityId = entityId;
|
||||||
this._currView = DEFAULT_VIEW;
|
this._currView = view === "details" ? view : DEFAULT_VIEW;
|
||||||
|
this._initialView = view;
|
||||||
|
this._infoEditMode = false;
|
||||||
|
this._detailsYamlMode = false;
|
||||||
this._childView = undefined;
|
this._childView = undefined;
|
||||||
this._loadEntityRegistryEntry();
|
this._loadEntityRegistryEntry();
|
||||||
}
|
}
|
||||||
@@ -998,12 +1019,6 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.child-view {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-more-info-history-and-logbook {
|
ha-more-info-history-and-logbook {
|
||||||
padding: var(--ha-space-2) var(--ha-space-6) var(--ha-space-6)
|
padding: var(--ha-space-2) var(--ha-space-6) var(--ha-space-6)
|
||||||
var(--ha-space-6);
|
var(--ha-space-6);
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import {
|
|||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
} from "../../dialogs/generic/show-dialog-box";
|
} from "../../dialogs/generic/show-dialog-box";
|
||||||
|
import { isMoreInfoView } from "../../dialogs/more-info/const";
|
||||||
import { showMoreInfoDialog } from "../../dialogs/more-info/show-ha-more-info-dialog";
|
import { showMoreInfoDialog } from "../../dialogs/more-info/show-ha-more-info-dialog";
|
||||||
import { showQuickBar } from "../../dialogs/quick-bar/show-dialog-quick-bar";
|
import { showQuickBar } from "../../dialogs/quick-bar/show-dialog-quick-bar";
|
||||||
import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-ha-voice-command-dialog";
|
import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-ha-voice-command-dialog";
|
||||||
@@ -716,11 +717,18 @@ class HUIRoot extends LitElement {
|
|||||||
this._showVoiceCommandDialog();
|
this._showVoiceCommandDialog();
|
||||||
} else if (searchParams["more-info-entity-id"]) {
|
} else if (searchParams["more-info-entity-id"]) {
|
||||||
const entityId = searchParams["more-info-entity-id"];
|
const entityId = searchParams["more-info-entity-id"];
|
||||||
|
const view = searchParams["more-info-view"];
|
||||||
this._clearParam("more-info-entity-id");
|
this._clearParam("more-info-entity-id");
|
||||||
|
if (view) {
|
||||||
|
this._clearParam("more-info-view");
|
||||||
|
}
|
||||||
// Wait for the next render to ensure the view is fully loaded
|
// Wait for the next render to ensure the view is fully loaded
|
||||||
// because the more info dialog is closed when the url changes
|
// because the more info dialog is closed when the url changes
|
||||||
afterNextRender(() => {
|
afterNextRender(() => {
|
||||||
this._showMoreInfoDialog(entityId);
|
showMoreInfoDialog(this, {
|
||||||
|
entityId,
|
||||||
|
view: isMoreInfoView(view) ? view : undefined,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -975,10 +983,6 @@ class HUIRoot extends LitElement {
|
|||||||
showVoiceCommandDialog(this, this.hass, { pipeline_id: "last_used" });
|
showVoiceCommandDialog(this, this.hass, { pipeline_id: "last_used" });
|
||||||
};
|
};
|
||||||
|
|
||||||
private _showMoreInfoDialog(entityId: string): void {
|
|
||||||
showMoreInfoDialog(this, { entityId });
|
|
||||||
}
|
|
||||||
|
|
||||||
private _enableEditMode = async () => {
|
private _enableEditMode = async () => {
|
||||||
if (this._yamlMode) {
|
if (this._yamlMode) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
|
|||||||
Reference in New Issue
Block a user