diff --git a/src/panels/config/devices/device-detail/ha-device-card.js b/src/panels/config/devices/device-detail/ha-device-card.js index 2bad52c16b..4ef8dfad9c 100644 --- a/src/panels/config/devices/device-detail/ha-device-card.js +++ b/src/panels/config/devices/device-detail/ha-device-card.js @@ -123,24 +123,26 @@ class HaDeviceCard extends EventsMixin(LocalizeMixin(PolymerElement)) { -
- -
+ `; } @@ -157,6 +159,7 @@ class HaDeviceCard extends EventsMixin(LocalizeMixin(PolymerElement)) { reflectToAttribute: true, }, hideSettings: { type: Boolean, value: false }, + hideEntities: { type: Boolean, value: false }, _childDevices: { type: Array, computed: "_computeChildDevices(device, devices)", 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 new file mode 100644 index 0000000000..03129e5a1c --- /dev/null +++ b/src/panels/config/devices/device-detail/ha-device-entities-card.ts @@ -0,0 +1,171 @@ +import { + LitElement, + TemplateResult, + html, + property, + customElement, + css, + CSSResult, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; + +import { HomeAssistant } from "../../../../types"; +import memoizeOne from "memoize-one"; + +import { compare } from "../../../../common/string/compare"; +import "../../../../components/entity/state-badge"; + +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-item/paper-icon-item"; +import "@polymer/paper-item/paper-item-body"; + +import "../../../../components/ha-card"; +import "../../../../components/ha-icon"; +import "../../../../components/ha-switch"; +import { computeStateName } from "../../../../common/entity/compute_state_name"; +import { EntityRegistryEntry } from "../../../../data/entity_registry"; +import { showEntityRegistryDetailDialog } from "../../entity_registry/show-dialog-entity-registry-detail"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { computeDomain } from "../../../../common/entity/compute_domain"; +import { domainIcon } from "../../../../common/entity/domain_icon"; +// tslint:disable-next-line +import { HaSwitch } from "../../../../components/ha-switch"; + +@customElement("ha-device-entities-card") +export class HaDeviceEntitiesCard extends LitElement { + @property() public hass!: HomeAssistant; + @property() public deviceId!: string; + @property() public entities!: EntityRegistryEntry[]; + @property() public narrow!: boolean; + @property() private _showDisabled = false; + + private _entities = memoizeOne( + ( + deviceId: string, + entities: EntityRegistryEntry[] + ): EntityRegistryEntry[] => + entities + .filter((entity) => entity.device_id === deviceId) + .sort((ent1, ent2) => + compare( + this._computeEntityName(ent1) || `zzz${ent1.entity_id}`, + this._computeEntityName(ent2) || `zzz${ent2.entity_id}` + ) + ) + ); + + protected render(): TemplateResult { + const entities = this._entities(this.deviceId, this.entities); + return html` + + + ${this.hass.localize( + "ui.panel.config.entity_registry.picker.show_disabled" + )} + + + ${entities.length + ? entities.map((entry: EntityRegistryEntry) => { + if (!this._showDisabled && entry.disabled_by) { + return ""; + } + const stateObj = this.hass.states[entry.entity_id]; + return html` + + ${stateObj + ? html` + + ` + : html` + + `} + +
${this._computeEntityName(entry)}
+
${entry.entity_id}
+
+
+ ${stateObj + ? html` + + ` + : ""} + +
+
+ `; + }) + : html` +
+ +
+ ${this.hass.localize( + "ui.panel.config.devices.entities.none" + )} +
+
+
+ `} +
+ `; + } + + private _showDisabledChanged(ev: Event) { + this._showDisabled = (ev.target as HaSwitch).checked; + } + + private _openEditEntry(ev: MouseEvent): void { + const entry = (ev.currentTarget! as any).closest("paper-icon-item").entry; + showEntityRegistryDetailDialog(this, { + entry, + }); + } + + private _openMoreInfo(ev: MouseEvent) { + const entry = (ev.currentTarget! as any).closest("paper-icon-item").entry; + fireEvent(this, "hass-more-info", { entityId: entry.entity_id }); + } + + private _computeEntityName(entity) { + if (entity.name) { + return entity.name; + } + const state = this.hass.states[entity.entity_id]; + return state ? computeStateName(state) : null; + } + + static get styles(): CSSResult { + return css` + ha-icon { + width: 40px; + } + .entity-id { + color: var(--secondary-text-color); + } + .buttons { + text-align: right; + margin: 0 0 0 8px; + } + .disabled-entry { + color: var(--secondary-text-color); + } + `; + } +} diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index e477d4b049..c47cf2610d 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -11,11 +11,12 @@ import memoizeOne from "memoize-one"; import "../../../layouts/hass-subpage"; import "../../../layouts/hass-error-screen"; +import "../ha-config-section"; -import "./device-detail/ha-device-card"; import "./device-detail/ha-device-triggers-card"; import "./device-detail/ha-device-conditions-card"; import "./device-detail/ha-device-actions-card"; +import "./device-detail/ha-device-entities-card"; import { HomeAssistant } from "../../../types"; import { ConfigEntry } from "../../../data/config_entries"; import { EntityRegistryEntry } from "../../../data/entity_registry"; @@ -37,6 +38,7 @@ export class HaConfigDevicePage extends LitElement { @property() public entities!: EntityRegistryEntry[]; @property() public areas!: AreaRegistryEntry[]; @property() public deviceId!: string; + @property() public narrow!: boolean; private _device = memoizeOne( ( @@ -67,7 +69,11 @@ export class HaConfigDevicePage extends LitElement { icon="hass:settings" @click=${this._showSettings} > -
+ + Device info + + Here are all the details of your device. + + +
Entities
+ + + +
Automations
-
+ `; } @@ -104,12 +121,20 @@ export class HaConfigDevicePage extends LitElement { static get styles(): CSSResult { return css` - .content { - padding: 16px; + .header { + font-family: var(--paper-font-display1_-_font-family); + -webkit-font-smoothing: var( + --paper-font-display1_-_-webkit-font-smoothing + ); + font-size: var(--paper-font-display1_-_font-size); + font-weight: var(--paper-font-display1_-_font-weight); + letter-spacing: var(--paper-font-display1_-_letter-spacing); + line-height: var(--paper-font-display1_-_line-height); + opacity: var(--dark-primary-opacity); } - .content > * { - display: block; - margin-bottom: 16px; + + ha-config-section *:last-child { + padding-bottom: 24px; } `; } diff --git a/src/panels/config/entity_registry/dialog-entity-registry-detail.ts b/src/panels/config/entity_registry/dialog-entity-registry-detail.ts index 30da701f41..e65ea47d7c 100644 --- a/src/panels/config/entity_registry/dialog-entity-registry-detail.ts +++ b/src/panels/config/entity_registry/dialog-entity-registry-detail.ts @@ -22,10 +22,15 @@ import { HaSwitch } from "../../../components/ha-switch"; import { computeDomain } from "../../../common/entity/compute_domain"; import { computeStateName } from "../../../common/entity/compute_state_name"; +import { + updateEntityRegistryEntry, + removeEntityRegistryEntry, +} from "../../../data/entity_registry"; class DialogEntityRegistryDetail extends LitElement { @property() public hass!: HomeAssistant; @property() private _name!: string; + @property() private _platform!: string; @property() private _entityId!: string; @property() private _disabledBy!: string | null; @property() private _error?: string; @@ -38,6 +43,7 @@ class DialogEntityRegistryDetail extends LitElement { this._params = params; this._error = undefined; this._name = this._params.entry.name || ""; + this._platform = this._params.entry.platform; this._entityId = this._params.entry.entity_id; this._disabledBy = this._params.entry.disabled_by; await this.updateComplete; @@ -164,7 +170,7 @@ class DialogEntityRegistryDetail extends LitElement { private async _updateEntry(): Promise { this._submitting = true; try { - await this._params!.updateEntry({ + await updateEntityRegistryEntry(this.hass!, this._entityId, { name: this._name.trim() || null, disabled_by: this._disabledBy, new_entity_id: this._entityId.trim(), @@ -178,11 +184,27 @@ class DialogEntityRegistryDetail extends LitElement { } private async _deleteEntry(): Promise { + if ( + !confirm( + `${this.hass.localize( + "ui.panel.config.entity_registry.editor.confirm_delete" + )} + +${this.hass.localize( + "ui.panel.config.entity_registry.editor.confirm_delete2", + "platform", + this._platform +)}` + ) + ) { + return; + } + this._submitting = true; + try { - if (await this._params!.removeEntry()) { - this._params = undefined; - } + await removeEntityRegistryEntry(this.hass!, this._entityId); + this._params = undefined; } finally { this._submitting = false; } diff --git a/src/panels/config/entity_registry/ha-config-entity-registry.ts b/src/panels/config/entity_registry/ha-config-entity-registry.ts index d7d496dc89..96990ff9db 100644 --- a/src/panels/config/entity_registry/ha-config-entity-registry.ts +++ b/src/panels/config/entity_registry/ha-config-entity-registry.ts @@ -13,8 +13,6 @@ import { HomeAssistant } from "../../../types"; import { EntityRegistryEntry, computeEntityRegistryName, - updateEntityRegistryEntry, - removeEntityRegistryEntry, subscribeEntityRegistry, } from "../../../data/entity_registry"; import "../../../layouts/hass-subpage"; @@ -143,35 +141,6 @@ class HaConfigEntityRegistry extends LitElement { const entry = (ev.currentTarget! as any).entry; showEntityRegistryDetailDialog(this, { entry, - updateEntry: async (updates) => { - const updated = await updateEntityRegistryEntry( - this.hass!, - entry.entity_id, - updates - ); - this._entities = this._entities!.map((ent) => - ent === entry ? updated : ent - ); - }, - removeEntry: async () => { - if ( - !confirm(`Are you sure you want to delete this entry? - -Deleting an entry will not remove the entity from Home Assistant. To do this, you will need to remove the integration "${ - entry.platform - }" from Home Assistant.`) - ) { - return false; - } - - try { - await removeEntityRegistryEntry(this.hass!, entry.entity_id); - this._entities = this._entities!.filter((ent) => ent !== entry); - return true; - } catch (err) { - return false; - } - }, }); } diff --git a/src/panels/config/entity_registry/show-dialog-entity-registry-detail.ts b/src/panels/config/entity_registry/show-dialog-entity-registry-detail.ts index 372c5f2efc..8985f4cffa 100644 --- a/src/panels/config/entity_registry/show-dialog-entity-registry-detail.ts +++ b/src/panels/config/entity_registry/show-dialog-entity-registry-detail.ts @@ -1,15 +1,8 @@ import { fireEvent } from "../../../common/dom/fire_event"; -import { - EntityRegistryEntry, - EntityRegistryEntryUpdateParams, -} from "../../../data/entity_registry"; +import { EntityRegistryEntry } from "../../../data/entity_registry"; export interface EntityRegistryDetailDialogParams { entry: EntityRegistryEntry; - updateEntry: ( - updates: Partial - ) => Promise; - removeEntry: () => Promise; } export const loadEntityRegistryDetailDialog = () => diff --git a/src/translations/en.json b/src/translations/en.json index bc60381a98..6010e2bf79 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -930,6 +930,8 @@ "enabled_cause": "Disabled by {cause}.", "enabled_description": "Disabled entities will not be added to Home Assistant.", "delete": "DELETE", + "confirm_delete": "Are you sure you want to delete this entry?", + "confirm_delete2": "Deleting an entry will not remove the entity from Home Assistant. To do this, you will need to remove the integration '{platform}' from Home Assistant.", "update": "UPDATE" } },