diff --git a/src/common/const.ts b/src/common/const.ts index 68489f95d2..432e85b6b9 100644 --- a/src/common/const.ts +++ b/src/common/const.ts @@ -166,46 +166,6 @@ export const DOMAINS_WITH_CARD = [ "water_heater", ]; -/** Domains with separate more info dialog. */ -export const DOMAINS_WITH_MORE_INFO = [ - "alarm_control_panel", - "automation", - "camera", - "climate", - "configurator", - "counter", - "cover", - "fan", - "group", - "humidifier", - "input_datetime", - "light", - "lock", - "media_player", - "person", - "remote", - "script", - "scene", - "sun", - "timer", - "update", - "vacuum", - "water_heater", - "weather", -]; - -/** Domains that do not show the default more info dialog content (e.g. the attribute section) - * and do not have a separate more info (so not in DOMAINS_WITH_MORE_INFO). */ -export const DOMAINS_HIDE_DEFAULT_MORE_INFO = [ - "input_number", - "input_select", - "input_text", - "number", - "scene", - "update", - "select", -]; - /** Domains that render an input element instead of a text value when displayed in a row. * Those rows should then not show a cursor pointer when hovered (which would normally * be the default) unless the element itself enforces it (e.g. a button). Also those elements @@ -237,9 +197,6 @@ export const DOMAINS_INPUT_ROW = [ "vacuum", ]; -/** Domains that should have the history hidden in the more info dialog. */ -export const DOMAINS_MORE_INFO_NO_HISTORY = ["camera", "configurator"]; - /** States that we consider "off". */ export const STATES_OFF = ["closed", "locked", "off"]; diff --git a/src/components/ha-related-items.ts b/src/components/ha-related-items.ts index 54baf0f25f..89974e6be8 100644 --- a/src/components/ha-related-items.ts +++ b/src/components/ha-related-items.ts @@ -326,6 +326,9 @@ export class HaRelatedItems extends SubscribeMixin(LitElement) { line-height: var(--paper-font-title_-_line-height); opacity: var(--dark-primary-opacity); } + h3:first-child { + margin-top: 0; + } `; } } diff --git a/src/dialogs/more-info/const.ts b/src/dialogs/more-info/const.ts new file mode 100644 index 0000000000..2d9a8d4295 --- /dev/null +++ b/src/dialogs/more-info/const.ts @@ -0,0 +1,89 @@ +import { isComponentLoaded } from "../../common/config/is_component_loaded"; +import { computeDomain } from "../../common/entity/compute_domain"; +import { CONTINUOUS_DOMAINS } from "../../data/logbook"; +import { HomeAssistant } from "../../types"; + +export const DOMAINS_NO_INFO = ["camera", "configurator"]; +/** + * Entity domains that should be editable *if* they have an id present; + * {@see shouldShowEditIcon}. + * */ +export const EDITABLE_DOMAINS_WITH_ID = ["scene", "automation"]; +/** + * Entity Domains that should always be editable; {@see shouldShowEditIcon}. + * */ +export const EDITABLE_DOMAINS = ["script"]; + +/** Domains with separate more info dialog. */ +export const DOMAINS_WITH_MORE_INFO = [ + "alarm_control_panel", + "automation", + "camera", + "climate", + "configurator", + "counter", + "cover", + "fan", + "group", + "humidifier", + "input_datetime", + "light", + "lock", + "media_player", + "person", + "remote", + "script", + "scene", + "sun", + "timer", + "update", + "vacuum", + "water_heater", + "weather", +]; + +/** Domains that do not show the default more info dialog content (e.g. the attribute section) + * and do not have a separate more info (so not in DOMAINS_WITH_MORE_INFO). */ +export const DOMAINS_HIDE_DEFAULT_MORE_INFO = [ + "input_number", + "input_select", + "input_text", + "number", + "scene", + "update", + "select", +]; + +/** Domains that should have the history hidden in the more info dialog. */ +export const DOMAINS_MORE_INFO_NO_HISTORY = ["camera", "configurator"]; + +export const computeShowHistoryComponent = ( + hass: HomeAssistant, + entityId: string +) => + isComponentLoaded(hass, "history") && + !DOMAINS_MORE_INFO_NO_HISTORY.includes(computeDomain(entityId)); + +export const computeShowLogBookComponent = ( + hass: HomeAssistant, + entityId: string +): boolean => { + if (!isComponentLoaded(hass, "logbook")) { + return false; + } + + const stateObj = hass.states[entityId]; + if (!stateObj || stateObj.attributes.unit_of_measurement) { + return false; + } + + const domain = computeDomain(entityId); + if ( + CONTINUOUS_DOMAINS.includes(domain) || + DOMAINS_MORE_INFO_NO_HISTORY.includes(domain) + ) { + return false; + } + + return true; +}; diff --git a/src/dialogs/more-info/ha-more-info-dialog.ts b/src/dialogs/more-info/ha-more-info-dialog.ts index fb7179a782..9df9d29514 100644 --- a/src/dialogs/more-info/ha-more-info-dialog.ts +++ b/src/dialogs/more-info/ha-more-info-dialog.ts @@ -1,15 +1,11 @@ +import type { HassEntity } from "home-assistant-js-websocket"; import "@material/mwc-button"; import "@material/mwc-tab"; import "@material/mwc-tab-bar"; -import { mdiClose, mdiCog, mdiPencil } from "@mdi/js"; -import { css, html, LitElement } from "lit"; +import { mdiClose, mdiPencil } from "@mdi/js"; +import { css, html, LitElement, PropertyValues } from "lit"; import { customElement, property, state } from "lit/decorators"; import { cache } from "lit/directives/cache"; -import { isComponentLoaded } from "../../common/config/is_component_loaded"; -import { - DOMAINS_MORE_INFO_NO_HISTORY, - DOMAINS_WITH_MORE_INFO, -} from "../../common/const"; import { fireEvent } from "../../common/dom/fire_event"; import { computeDomain } from "../../common/entity/compute_domain"; import { computeStateName } from "../../common/entity/compute_state_name"; @@ -17,34 +13,28 @@ import { navigate } from "../../common/navigate"; import "../../components/ha-dialog"; import "../../components/ha-header-bar"; import "../../components/ha-icon-button"; -import { removeEntityRegistryEntry } from "../../data/entity_registry"; -import { CONTINUOUS_DOMAINS } from "../../data/logbook"; -import { showEntityEditorDialog } from "../../panels/config/entities/show-dialog-entity-editor"; +import "../../components/ha-related-items"; import { haStyleDialog } from "../../resources/styles"; import "../../state-summary/state-card-content"; import { HomeAssistant } from "../../types"; -import { showConfirmationDialog } from "../generic/show-dialog-box"; -import { replaceDialog } from "../make-dialog-manager"; +import { + EDITABLE_DOMAINS_WITH_ID, + EDITABLE_DOMAINS, + DOMAINS_MORE_INFO_NO_HISTORY, +} from "./const"; import "./controls/more-info-default"; -import "./ha-more-info-history"; -import "./ha-more-info-logbook"; +import "./ha-more-info-info"; +import "./ha-more-info-settings"; +import "./ha-more-info-history-and-logbook"; import "./more-info-content"; -const DOMAINS_NO_INFO = ["camera", "configurator"]; -/** - * Entity domains that should be editable *if* they have an id present; - * {@see shouldShowEditIcon}. - * */ -const EDITABLE_DOMAINS_WITH_ID = ["scene", "automation"]; -/** - * Entity Domains that should always be editable; {@see shouldShowEditIcon}. - * */ -const EDITABLE_DOMAINS = ["script"]; - export interface MoreInfoDialogParams { entityId: string | null; + tab?: Tab; } +type Tab = "info" | "history" | "settings" | "related"; + @customElement("ha-more-info-dialog") export class MoreInfoDialog extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -53,10 +43,13 @@ export class MoreInfoDialog extends LitElement { @state() private _entityId?: string | null; - @state() private _currTabIndex = 0; + @state() private _currTab: Tab = "info"; public showDialog(params: MoreInfoDialogParams) { this._entityId = params.entityId; + if (params.tab) { + this._currTab = params.tab; + } if (!this._entityId) { this.closeDialog(); return; @@ -66,12 +59,14 @@ export class MoreInfoDialog extends LitElement { public closeDialog() { this._entityId = undefined; - this._currTabIndex = 0; fireEvent(this, "dialog-closed", { dialog: this.localName }); } - protected shouldShowEditIcon(domain, stateObj): boolean { - if (__DEMO__) { + protected shouldShowEditIcon( + domain: string, + stateObj: HassEntity | undefined + ): boolean { + if (__DEMO__ || !stateObj) { return false; } if (EDITABLE_DOMAINS_WITH_ID.includes(domain) && stateObj.attributes.id) { @@ -94,12 +89,9 @@ export class MoreInfoDialog extends LitElement { const entityId = this._entityId; const stateObj = this.hass.states[entityId]; - if (!stateObj) { - return html``; - } - const domain = computeDomain(entityId); - const name = computeStateName(stateObj); + const name = stateObj ? computeStateName(stateObj) : entityId; + const tabs = this._getTabs(entityId, this.hass.user!.is_admin); return html` ${name} - ${this.hass.user!.is_admin - ? html` - - ` - : ""} ${this.shouldShowEditIcon(domain, stateObj) ? html` - ${DOMAINS_WITH_MORE_INFO.includes(domain) && - (this._computeShowHistoryComponent(entityId) || - this._computeShowLogBookComponent(entityId)) + + ${tabs.length > 1 ? html` - - + ${tabs.map( + (tab) => html` + + ` + )} ` : ""}
${cache( - this._currTabIndex === 0 + this._currTab === "info" ? html` - ${DOMAINS_NO_INFO.includes(domain) - ? "" - : html` - - `} - ${DOMAINS_WITH_MORE_INFO.includes(domain) || - !this._computeShowHistoryComponent(entityId) - ? "" - : html``} - ${DOMAINS_WITH_MORE_INFO.includes(domain) || - !this._computeShowLogBookComponent(entityId) - ? "" - : html``} - - ${stateObj.attributes.restored - ? html` -

- ${this.hass.localize( - "ui.dialogs.more_info_control.restored.not_provided" - )} -

-

- ${this.hass.localize( - "ui.dialogs.more_info_control.restored.remove_intro" - )} -

- - ${this.hass.localize( - "ui.dialogs.more_info_control.restored.remove_action" - )} - - ` - : ""} + .entityId=${this._entityId} + > + ` + : this._currTab === "history" + ? html` + + ` + : this._currTab === "settings" + ? html` + ` : html` - - + .itemId=${entityId} + itemType="entity" + > ` )}
@@ -245,63 +189,49 @@ export class MoreInfoDialog extends LitElement { `; } + protected firstUpdated(changedProps: PropertyValues) { + super.firstUpdated(changedProps); + this.addEventListener("close-dialog", () => this.closeDialog()); + } + + protected willUpdate(changedProps: PropertyValues) { + super.willUpdate(changedProps); + if (!this._entityId) { + return; + } + const tabs = this._getTabs(this._entityId, this.hass.user!.is_admin); + if (!tabs.includes(this._currTab)) { + this._currTab = tabs[0]; + } + } + + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + if (changedProps.has("_currTab")) { + this.setAttribute("tab", this._currTab); + } + } + + private _getTabs(entityId: string, isAdmin: boolean): Tab[] { + const domain = computeDomain(entityId); + const tabs: Tab[] = ["info"]; + + if (!DOMAINS_MORE_INFO_NO_HISTORY.includes(domain)) { + tabs.push("history"); + } + + if (isAdmin) { + tabs.push("settings"); + tabs.push("related"); + } + + return tabs; + } + private _enlarge() { this.large = !this.large; } - private _computeShowHistoryComponent(entityId) { - return ( - isComponentLoaded(this.hass, "history") && - !DOMAINS_MORE_INFO_NO_HISTORY.includes(computeDomain(entityId)) - ); - } - - private _computeShowLogBookComponent(entityId): boolean { - if (!isComponentLoaded(this.hass, "logbook")) { - return false; - } - - const stateObj = this.hass.states[entityId]; - if (!stateObj || stateObj.attributes.unit_of_measurement) { - return false; - } - - const domain = computeDomain(entityId); - if ( - CONTINUOUS_DOMAINS.includes(domain) || - DOMAINS_MORE_INFO_NO_HISTORY.includes(domain) - ) { - return false; - } - - return true; - } - - private _removeEntity() { - const entityId = this._entityId!; - showConfirmationDialog(this, { - title: this.hass.localize( - "ui.dialogs.more_info_control.restored.confirm_remove_title" - ), - text: this.hass.localize( - "ui.dialogs.more_info_control.restored.confirm_remove_text" - ), - confirmText: this.hass.localize("ui.common.remove"), - dismissText: this.hass.localize("ui.common.cancel"), - confirm: () => { - removeEntityRegistryEntry(this.hass, entityId); - }, - }); - } - - private _gotoSettings() { - replaceDialog(this); - showEntityEditorDialog(this, { - entity_id: this._entityId!, - }); - this.closeDialog(); - } - private _gotoEdit() { const stateObj = this.hass.states[this._entityId!]; const domain = computeDomain(this._entityId!); @@ -315,12 +245,14 @@ export class MoreInfoDialog extends LitElement { } private _handleTabChanged(ev: CustomEvent): void { - const newTab = ev.detail.index; - if (newTab === this._currTabIndex) { + const newTab = this._getTabs(this._entityId!, this.hass.user!.is_admin)[ + ev.detail.index + ]; + if (newTab === this._currTab) { return; } - this._currTabIndex = ev.detail.index; + this._currTab = newTab; } static get styles() { @@ -354,17 +286,21 @@ export class MoreInfoDialog extends LitElement { var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); } - @media all and (min-width: 451px) and (min-height: 501px) { + :host([tab="settings"]) ha-dialog { + --dialog-content-padding: 0px; + } + + @media all and (min-width: 600px) and (min-height: 501px) { ha-dialog { - --mdc-dialog-max-width: 90vw; + --mdc-dialog-min-width: 560px; + --mdc-dialog-max-width: 560px; + --dialog-surface-position: fixed; + --dialog-surface-top: 40px; + --mdc-dialog-max-height: calc(100% - 72px); } - .content { - width: 352px; - } - - ha-header-bar { - width: 400px; + ha-icon-button[slot="navigationIcon"] { + display: none; } .main-title { @@ -373,18 +309,10 @@ export class MoreInfoDialog extends LitElement { cursor: default; } - ha-dialog[data-domain="camera"] .content, - ha-dialog[data-domain="camera"] ha-header-bar { - width: auto; - } - - :host([large]) .content { - width: calc(90vw - 48px); - } - - :host([large]) ha-dialog[data-domain="camera"] .content, - :host([large]) ha-header-bar { - width: 90vw; + :host([large]) ha-dialog, + ha-dialog[data-domain="camera"] { + --mdc-dialog-min-width: 90vw; + --mdc-dialog-max-width: 90vw; } } diff --git a/src/dialogs/more-info/ha-more-info-history-and-logbook.ts b/src/dialogs/more-info/ha-more-info-history-and-logbook.ts new file mode 100644 index 0000000000..c0ae54602f --- /dev/null +++ b/src/dialogs/more-info/ha-more-info-history-and-logbook.ts @@ -0,0 +1,43 @@ +import { LitElement, html } from "lit"; +import { customElement, property } from "lit/decorators"; +import { HomeAssistant } from "../../types"; +import { + computeShowHistoryComponent, + computeShowLogBookComponent, +} from "./const"; +import "./ha-more-info-history"; +import "./ha-more-info-logbook"; + +@customElement("ha-more-info-history-and-logbook") +export class MoreInfoHistoryAndLogbook extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public entityId!: string; + + protected render() { + return html` + ${computeShowHistoryComponent(this.hass, this.entityId) + ? html` + + ` + : ""} + ${computeShowLogBookComponent(this.hass, this.entityId) + ? html` + + ` + : ""} + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-more-info-history-and-logbook": MoreInfoHistoryAndLogbook; + } +} diff --git a/src/dialogs/more-info/ha-more-info-info.ts b/src/dialogs/more-info/ha-more-info-info.ts new file mode 100644 index 0000000000..0167943d34 --- /dev/null +++ b/src/dialogs/more-info/ha-more-info-info.ts @@ -0,0 +1,80 @@ +import { LitElement, html } from "lit"; +import { customElement, property } from "lit/decorators"; +import { computeDomain } from "../../common/entity/compute_domain"; +import { removeEntityRegistryEntry } from "../../data/entity_registry"; +import type { HomeAssistant } from "../../types"; +import { showConfirmationDialog } from "../generic/show-dialog-box"; +import { DOMAINS_NO_INFO } from "./const"; +import "./ha-more-info-history"; +import "./ha-more-info-logbook"; + +@customElement("ha-more-info-info") +export class MoreInfoInfo extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public entityId!: string; + + protected render() { + const entityId = this.entityId; + const stateObj = this.hass.states[entityId]; + const domain = computeDomain(entityId); + + return html` + ${DOMAINS_NO_INFO.includes(domain) + ? "" + : html` + + `} + + ${stateObj.attributes.restored + ? html` +

+ ${this.hass.localize( + "ui.dialogs.more_info_control.restored.not_provided" + )} +

+

+ ${this.hass.localize( + "ui.dialogs.more_info_control.restored.remove_intro" + )} +

+ + ${this.hass.localize( + "ui.dialogs.more_info_control.restored.remove_action" + )} + + ` + : ""} + `; + } + + private _removeEntity() { + const entityId = this.entityId!; + showConfirmationDialog(this, { + title: this.hass.localize( + "ui.dialogs.more_info_control.restored.confirm_remove_title" + ), + text: this.hass.localize( + "ui.dialogs.more_info_control.restored.confirm_remove_text" + ), + confirmText: this.hass.localize("ui.common.remove"), + dismissText: this.hass.localize("ui.common.cancel"), + confirm: () => { + removeEntityRegistryEntry(this.hass, entityId); + }, + }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-more-info-info": MoreInfoInfo; + } +} diff --git a/src/dialogs/more-info/ha-more-info-settings.ts b/src/dialogs/more-info/ha-more-info-settings.ts new file mode 100644 index 0000000000..7a436aa86f --- /dev/null +++ b/src/dialogs/more-info/ha-more-info-settings.ts @@ -0,0 +1,117 @@ +import "@material/mwc-tab"; +import "@material/mwc-tab-bar"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { dynamicElement } from "../../common/dom/dynamic-element-directive"; +import { + EntityRegistryEntry, + ExtEntityRegistryEntry, + getExtendedEntityRegistryEntry, +} from "../../data/entity_registry"; +import { PLATFORMS_WITH_SETTINGS_TAB } from "../../panels/config/entities/const"; +import type { HomeAssistant } from "../../types"; +import { documentationUrl } from "../../util/documentation-url"; +import "../../panels/config/entities/entity-registry-settings"; + +@customElement("ha-more-info-settings") +export class HaMoreInfoSettings extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) public entityId!: string; + + @state() private _entry?: EntityRegistryEntry | ExtEntityRegistryEntry | null; + + @state() private _settingsElementTag?: string; + + protected render() { + // loading. + if (this._entry === undefined) { + return html``; + } + + // No unique ID + if (this._entry === null) { + return html` +
+ ${this.hass.localize( + "ui.dialogs.entity_registry.no_unique_id", + "entity_id", + this.entityId, + "faq_link", + html`${this.hass.localize("ui.dialogs.entity_registry.faq")}` + )} +
+ `; + } + + if (!this._settingsElementTag) { + return html``; + } + + return html` + ${dynamicElement(this._settingsElementTag, { + hass: this.hass, + entry: this._entry, + entityId: this.entityId, + })} + `; + } + + protected willUpdate(changedProps: PropertyValues) { + super.willUpdate(changedProps); + if (changedProps.has("entityId")) { + this._entry = undefined; + if (this.entityId) { + this._getEntityReg(); + } + } + } + + private async _getEntityReg() { + try { + this._entry = await getExtendedEntityRegistryEntry( + this.hass, + this.entityId + ); + this._loadPlatformSettingTabs(); + } catch { + this._entry = null; + } + } + + private async _loadPlatformSettingTabs(): Promise { + if (!this._entry) { + return; + } + if ( + !Object.keys(PLATFORMS_WITH_SETTINGS_TAB).includes(this._entry.platform) + ) { + this._settingsElementTag = "entity-registry-settings"; + return; + } + const tag = PLATFORMS_WITH_SETTINGS_TAB[this._entry.platform]; + await import(`../../panels/config/entities/editor-tabs/settings/${tag}`); + this._settingsElementTag = tag; + } + + static get styles(): CSSResultGroup { + return [ + css` + .content { + padding: 24px; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-more-info-settings": HaMoreInfoSettings; + } +} diff --git a/src/dialogs/more-info/show-ha-more-info-dialog.ts b/src/dialogs/more-info/show-ha-more-info-dialog.ts new file mode 100644 index 0000000000..b5a4197979 --- /dev/null +++ b/src/dialogs/more-info/show-ha-more-info-dialog.ts @@ -0,0 +1,10 @@ +import { fireEvent } from "../../common/dom/fire_event"; +import type { MoreInfoDialogParams } from "./ha-more-info-dialog"; + +export const showMoreInfoDialog = ( + element: HTMLElement, + params: MoreInfoDialogParams +) => fireEvent(element, "hass-more-info", params); + +export const hideMoreInfoDialog = (element: HTMLElement) => + fireEvent(element, "hass-more-info", { entityId: null }); diff --git a/src/dialogs/more-info/state_more_info_control.ts b/src/dialogs/more-info/state_more_info_control.ts index 3df5e85b4b..d4ebaed326 100644 --- a/src/dialogs/more-info/state_more_info_control.ts +++ b/src/dialogs/more-info/state_more_info_control.ts @@ -1,8 +1,8 @@ import type { HassEntity } from "home-assistant-js-websocket"; import { - DOMAINS_HIDE_DEFAULT_MORE_INFO, DOMAINS_WITH_MORE_INFO, -} from "../../common/const"; + DOMAINS_HIDE_DEFAULT_MORE_INFO, +} from "./const"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; const LAZY_LOADED_MORE_INFO_CONTROL = { diff --git a/src/panels/config/areas/ha-config-area-page.ts b/src/panels/config/areas/ha-config-area-page.ts index ed4573578c..74aec4c709 100644 --- a/src/panels/config/areas/ha-config-area-page.ts +++ b/src/panels/config/areas/ha-config-area-page.ts @@ -42,11 +42,11 @@ import { SceneEntity } from "../../../data/scene"; import { ScriptEntity } from "../../../data/script"; import { findRelated, RelatedResult } from "../../../data/search"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; +import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant, Route } from "../../../types"; import "../../logbook/ha-logbook"; -import { showEntityEditorDialog } from "../entities/show-dialog-entity-editor"; import { configSections } from "../ha-panel-config"; import { loadAreaRegistryDetailDialog, @@ -620,9 +620,8 @@ class HaConfigAreaPage extends SubscribeMixin(LitElement) { private _openEntity(ev) { const entry: EntityRegistryEntry = (ev.currentTarget as any).entity; - showEntityEditorDialog(this, { - entity_id: entry.entity_id, - entry, + showMoreInfoDialog(this, { + entityId: entry.entity_id, }); } diff --git a/src/panels/config/devices/device-detail/ha-device-entities-card.ts b/src/panels/config/devices/device-detail/ha-device-entities-card.ts index 96599b1e5f..e0aeffd445 100644 --- a/src/panels/config/devices/device-detail/ha-device-entities-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-entities-card.ts @@ -21,13 +21,13 @@ import { ExtEntityRegistryEntry, getExtendedEntityRegistryEntry, } from "../../../../data/entity_registry"; +import { showMoreInfoDialog } from "../../../../dialogs/more-info/show-ha-more-info-dialog"; import type { HomeAssistant } from "../../../../types"; import type { HuiErrorCard } from "../../../lovelace/cards/hui-error-card"; import { createRowElement } from "../../../lovelace/create-element/create-row-element"; import { addEntitiesToLovelaceView } from "../../../lovelace/editor/add-entities-to-view"; import type { LovelaceRowConfig } from "../../../lovelace/entity-rows/types"; import { LovelaceRow } from "../../../lovelace/entity-rows/types"; -import { showEntityEditorDialog } from "../../entities/show-dialog-entity-editor"; import { EntityRegistryStateEntry } from "../ha-config-device-page"; @customElement("ha-device-entities-card") @@ -90,7 +90,7 @@ export class HaDeviceEntitiesCard extends LitElement { return html` -
+
${shownEntities.map((entry) => this.hass.states[entry.entity_id] ? this._renderEntity(entry) @@ -221,20 +221,11 @@ export class HaDeviceEntitiesCard extends LitElement { `; } - private _overrideMoreInfo(ev: Event): void { - ev.stopPropagation(); - const entry = (ev.target! as any).entry; - showEntityEditorDialog(this, { - entry, - entity_id: entry.entity_id, - }); - } - private _openEditEntry(ev: Event): void { const entry = (ev.currentTarget! as any).entry; - showEntityEditorDialog(this, { - entry, - entity_id: entry.entity_id, + showMoreInfoDialog(this, { + entityId: entry.entity_id, + tab: "settings", }); } diff --git a/src/panels/config/entities/dialog-entity-editor.ts b/src/panels/config/entities/dialog-entity-editor.ts deleted file mode 100644 index ec234961bb..0000000000 --- a/src/panels/config/entities/dialog-entity-editor.ts +++ /dev/null @@ -1,287 +0,0 @@ -import "@material/mwc-tab"; -import "@material/mwc-tab-bar"; -import { mdiClose, mdiTune } from "@mdi/js"; -import { HassEntity } from "home-assistant-js-websocket"; -import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { cache } from "lit/directives/cache"; -import { dynamicElement } from "../../../common/dom/dynamic-element-directive"; -import { fireEvent } from "../../../common/dom/fire_event"; -import { computeStateName } from "../../../common/entity/compute_state_name"; -import "../../../components/ha-dialog"; -import "../../../components/ha-header-bar"; -import "../../../components/ha-icon-button"; -import "../../../components/ha-related-items"; -import { - EntityRegistryEntry, - ExtEntityRegistryEntry, - getExtendedEntityRegistryEntry, -} from "../../../data/entity_registry"; -import { replaceDialog } from "../../../dialogs/make-dialog-manager"; -import { haStyleDialog } from "../../../resources/styles"; -import type { HomeAssistant } from "../../../types"; -import { documentationUrl } from "../../../util/documentation-url"; -import { PLATFORMS_WITH_SETTINGS_TAB } from "./const"; -import "./entity-registry-settings"; -import type { EntityRegistryDetailDialogParams } from "./show-dialog-entity-editor"; - -interface Tabs { - [key: string]: Tab; -} - -interface Tab { - component: string; - translationKey: Parameters[0]; -} - -@customElement("dialog-entity-editor") -export class DialogEntityEditor extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @state() private _params?: EntityRegistryDetailDialogParams; - - @state() private _entry?: EntityRegistryEntry | ExtEntityRegistryEntry | null; - - @state() private _curTab = "tab-settings"; - - @state() private _extraTabs: Tabs = {}; - - @state() private _settingsElementTag?: string; - - private _curTabIndex = 0; - - public showDialog(params: EntityRegistryDetailDialogParams): void { - this._params = params; - this._entry = undefined; - this._settingsElementTag = undefined; - this._extraTabs = {}; - this._getEntityReg(); - } - - public closeDialog(): void { - this._params = undefined; - fireEvent(this, "dialog-closed", { dialog: this.localName }); - } - - protected render(): TemplateResult { - if (!this._params || this._entry === undefined) { - return html``; - } - const entityId = this._params.entity_id; - const entry = this._entry; - const stateObj: HassEntity | undefined = this.hass.states[entityId]; - - return html` - -
- - - - ${stateObj ? computeStateName(stateObj) : entry?.name || entityId} - - ${stateObj - ? html` - - ` - : ""} - - - - - ${Object.entries(this._extraTabs).map( - ([key, tab]) => html` - - - ` - )} - - - -
-
${cache(this._renderTab())}
-
- `; - } - - private _renderTab() { - switch (this._curTab) { - case "tab-settings": - if (this._entry) { - if (this._settingsElementTag) { - return html` - ${dynamicElement(this._settingsElementTag, { - hass: this.hass, - entry: this._entry, - entityId: this._params!.entity_id, - })} - `; - } - return html``; - } - return html` -
- ${this.hass.localize( - "ui.dialogs.entity_registry.no_unique_id", - "entity_id", - this._params!.entity_id, - "faq_link", - html`${this.hass.localize("ui.dialogs.entity_registry.faq")}` - )} -
- `; - case "tab-related": - return html` - - `; - default: - return html``; - } - } - - private async _getEntityReg() { - try { - this._entry = await getExtendedEntityRegistryEntry( - this.hass, - this._params!.entity_id - ); - this._loadPlatformSettingTabs(); - } catch { - this._entry = null; - } - } - - private _handleTabActivated(ev: CustomEvent): void { - this._curTabIndex = ev.detail.index; - } - - private _handleTabInteracted(ev: CustomEvent): void { - this._curTab = ev.detail.tabId; - } - - private async _loadPlatformSettingTabs(): Promise { - if (!this._entry) { - return; - } - if ( - !Object.keys(PLATFORMS_WITH_SETTINGS_TAB).includes(this._entry.platform) - ) { - this._settingsElementTag = "entity-registry-settings"; - return; - } - const tag = PLATFORMS_WITH_SETTINGS_TAB[this._entry.platform]; - await import(`./editor-tabs/settings/${tag}`); - this._settingsElementTag = tag; - } - - private _openMoreInfo(): void { - replaceDialog(this); - fireEvent(this, "hass-more-info", { - entityId: this._params!.entity_id, - }); - this.closeDialog(); - } - - static get styles(): CSSResultGroup { - return [ - haStyleDialog, - css` - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - flex-shrink: 0; - } - - mwc-tab-bar { - border-bottom: 1px solid - var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); - } - - ha-dialog { - --dialog-content-position: static; - --dialog-content-padding: 0; - --dialog-z-index: 6; - } - - @media all and (min-width: 451px) and (min-height: 501px) { - .wrapper { - min-width: 400px; - } - } - - .content { - display: block; - padding: 20px 24px; - } - - /* overrule the ha-style-dialog max-height on small screens */ - @media all and (max-width: 450px), all and (max-height: 500px) { - ha-header-bar { - --mdc-theme-primary: var(--app-header-background-color); - --mdc-theme-on-primary: var(--app-header-text-color, white); - } - } - - mwc-button.warning { - --mdc-theme-primary: var(--error-color); - } - - :host([rtl]) app-toolbar { - direction: rtl; - text-align: right; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-entity-editor": DialogEntityEditor; - } -} diff --git a/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts b/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts index da462f9ca9..0ad83b15df 100644 --- a/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts +++ b/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts @@ -182,18 +182,12 @@ export class EntityRegistrySettingsHelper extends LitElement { } .form { padding: 20px 24px; - margin-bottom: 53px; } .buttons { - position: absolute; - bottom: 0; - width: 100%; box-sizing: border-box; - border-top: 1px solid - var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); display: flex; justify-content: space-between; - padding: 8px; + padding: 0 24px 24px 24px; background-color: var(--mdc-theme-surface, #fff); } .error { diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts index c3ae97d0e3..a2b1d57f96 100644 --- a/src/panels/config/entities/entity-registry-settings.ts +++ b/src/panels/config/entities/entity-registry-settings.ts @@ -66,11 +66,11 @@ import { showAlertDialog, showConfirmationDialog, } from "../../../dialogs/generic/show-dialog-box"; +import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { haStyle } from "../../../resources/styles"; import type { HomeAssistant } from "../../../types"; import { showDeviceRegistryDetailDialog } from "../devices/device-registry-detail/show-dialog-device-registry-detail"; -import { showEntityEditorDialog } from "./show-dialog-entity-editor"; const OVERRIDE_DEVICE_CLASSES = { cover: [ @@ -977,8 +977,9 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { if (!entity) { return; } - showEntityEditorDialog(parent, { - entity_id: entity.entity_id, + showMoreInfoDialog(parent, { + entityId: entity.entity_id, + tab: "settings", }); }); }, "entity_registry_updated"); @@ -1046,17 +1047,11 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { .container { padding: 20px 24px; } - .form { - margin-bottom: 53px; - } .buttons { - position: absolute; - bottom: 0; - width: 100%; box-sizing: border-box; display: flex; padding: 0 24px 24px 24px; - justify-content: flex-end; + justify-content: space-between; padding-bottom: max(env(safe-area-inset-bottom), 24px); background-color: var(--mdc-theme-surface, #fff); } diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index 154f2cb424..5a610d8169 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -55,6 +55,10 @@ import { showAlertDialog, showConfirmationDialog, } from "../../../dialogs/generic/show-dialog-box"; +import { + hideMoreInfoDialog, + showMoreInfoDialog, +} from "../../../dialogs/more-info/show-ha-more-info-dialog"; import "../../../layouts/hass-loading-screen"; import "../../../layouts/hass-tabs-subpage-data-table"; import type { HaTabsSubpageDataTable } from "../../../layouts/hass-tabs-subpage-data-table"; @@ -63,11 +67,6 @@ import { haStyle } from "../../../resources/styles"; import type { HomeAssistant, Route } from "../../../types"; import { configSections } from "../ha-panel-config"; import "../integrations/ha-integration-overflow-menu"; -import { DialogEntityEditor } from "./dialog-entity-editor"; -import { - loadEntityEditorDialog, - showEntityEditorDialog, -} from "./show-dialog-entity-editor"; export interface StateEntity extends EntityRegistryEntry { readonly?: boolean; @@ -121,8 +120,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { @query("hass-tabs-subpage-data-table", true) private _dataTable!: HaTabsSubpageDataTable; - private getDialog?: () => DialogEntityEditor | undefined; - private _activeFilters = memoize( ( filters: URLSearchParams, @@ -454,14 +451,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { public disconnectedCallback() { super.disconnectedCallback(); - if (!this.getDialog) { - return; - } - const dialog = this.getDialog(); - if (!dialog) { - return; - } - dialog.closeDialog(); + hideMoreInfoDialog(this); } protected render(): TemplateResult { @@ -695,11 +685,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { `; } - protected firstUpdated(changedProps): void { - super.firstUpdated(changedProps); - loadEntityEditorDialog(); - } - public willUpdate(changedProps): void { super.willUpdate(changedProps); const oldHass = changedProps.get("hass"); @@ -923,12 +908,9 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { private _openEditEntry(ev: CustomEvent): void { const entityId = (ev.detail as RowClickedEvent).id; - const entry = this._entities!.find( - (entity) => entity.entity_id === entityId - ); - this.getDialog = showEntityEditorDialog(this, { - entry, - entity_id: entityId, + showMoreInfoDialog(this, { + entityId, + tab: "settings", }); } diff --git a/src/panels/config/entities/show-dialog-entity-editor.ts b/src/panels/config/entities/show-dialog-entity-editor.ts deleted file mode 100644 index 46df6fbe7d..0000000000 --- a/src/panels/config/entities/show-dialog-entity-editor.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { fireEvent } from "../../../common/dom/fire_event"; -import { EntityRegistryEntry } from "../../../data/entity_registry"; -import type { DialogEntityEditor } from "./dialog-entity-editor"; - -export interface EntityRegistryDetailDialogParams { - entry?: EntityRegistryEntry; - entity_id: string; - tab?: string; -} - -export const loadEntityEditorDialog = () => import("./dialog-entity-editor"); - -const getDialog = () => - document - .querySelector("home-assistant")! - .shadowRoot!.querySelector("dialog-entity-editor") as - | DialogEntityEditor - | undefined; - -export const showEntityEditorDialog = ( - element: HTMLElement, - entityDetailParams: EntityRegistryDetailDialogParams -): (() => DialogEntityEditor | undefined) => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-entity-editor", - dialogImport: loadEntityEditorDialog, - dialogParams: entityDetailParams, - }); - return getDialog; -}; diff --git a/src/panels/config/helpers/ha-config-helpers.ts b/src/panels/config/helpers/ha-config-helpers.ts index 2cd3d23499..31c2ae5175 100644 --- a/src/panels/config/helpers/ha-config-helpers.ts +++ b/src/panels/config/helpers/ha-config-helpers.ts @@ -29,11 +29,11 @@ import { showAlertDialog, showConfirmationDialog, } from "../../../dialogs/generic/show-dialog-box"; +import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog"; import "../../../layouts/hass-loading-screen"; import "../../../layouts/hass-tabs-subpage-data-table"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { HomeAssistant, Route } from "../../../types"; -import { showEntityEditorDialog } from "../entities/show-dialog-entity-editor"; import { configSections } from "../ha-panel-config"; import "../integrations/ha-integration-overflow-menu"; import { HELPER_DOMAINS } from "./const"; @@ -357,8 +357,9 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) { private async _openEditDialog(ev: CustomEvent): Promise { const entityId = (ev.detail as RowClickedEvent).id; - showEntityEditorDialog(this, { - entity_id: entityId, + showMoreInfoDialog(this, { + entityId, + tab: "settings", }); } diff --git a/src/state/more-info-mixin.ts b/src/state/more-info-mixin.ts index e05c76ed72..509c1a4b7a 100644 --- a/src/state/more-info-mixin.ts +++ b/src/state/more-info-mixin.ts @@ -29,6 +29,7 @@ export default >(superClass: T) => "ha-more-info-dialog", { entityId: ev.detail.entityId, + tab: ev.detail.tab, }, () => import("../dialogs/more-info/ha-more-info-dialog") ); diff --git a/src/translations/en.json b/src/translations/en.json index 0414bfa152..a5a31809f8 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -738,9 +738,11 @@ }, "more_info_control": { "dismiss": "Dismiss dialog", - "settings": "Entity settings", + "settings": "Settings", "edit": "Edit entity", "details": "Details", + "info": "Info", + "related": "Related", "history": "History", "logbook": "Logbook", "last_changed": "Last changed",