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
39 changes: 21 additions & 18 deletions src/panels/config/devices/device-detail/ha-device-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,24 +123,26 @@ class HaDeviceCard extends EventsMixin(LocalizeMixin(PolymerElement)) {
</template>
</div>

<div class="device-entities">
<template
is="dom-repeat"
items="[[_computeDeviceEntities(hass, device, entities)]]"
as="entity"
>
<paper-icon-item on-click="_openMoreInfo">
<state-badge
state-obj="[[_computeStateObj(entity, hass)]]"
slot="item-icon"
></state-badge>
<paper-item-body>
<div class="name">[[_computeEntityName(entity, hass)]]</div>
<div class="secondary entity-id">[[entity.entity_id]]</div>
</paper-item-body>
</paper-icon-item>
</template>
</div>
<template is="dom-if" if="[[!hideEntities]]">
<div class="device-entities">
<template
is="dom-repeat"
items="[[_computeDeviceEntities(hass, device, entities)]]"
as="entity"
>
<paper-icon-item on-click="_openMoreInfo">
<state-badge
state-obj="[[_computeStateObj(entity, hass)]]"
slot="item-icon"
></state-badge>
<paper-item-body>
<div class="name">[[_computeEntityName(entity, hass)]]</div>
<div class="secondary entity-id">[[entity.entity_id]]</div>
</paper-item-body>
</paper-icon-item>
</template>
</div>
</template>
</ha-card>
`;
}
Expand All @@ -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)",
Expand Down
171 changes: 171 additions & 0 deletions src/panels/config/devices/device-detail/ha-device-entities-card.ts
Original file line number Diff line number Diff line change
@@ -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`
<ha-card>
<paper-item>
<ha-switch
?checked=${this._showDisabled}
@change=${this._showDisabledChanged}
>${this.hass.localize(
"ui.panel.config.entity_registry.picker.show_disabled"
)}
</ha-switch>
</paper-item>
${entities.length
? entities.map((entry: EntityRegistryEntry) => {
if (!this._showDisabled && entry.disabled_by) {
return "";
}
const stateObj = this.hass.states[entry.entity_id];
return html`
<paper-icon-item
.entry=${entry}
class=${classMap({ "disabled-entry": !!entry.disabled_by })}
>
${stateObj
? html`
<state-badge
.stateObj=${stateObj}
slot="item-icon"
></state-badge>
`
: html`
<ha-icon
slot="item-icon"
.icon=${domainIcon(computeDomain(entry.entity_id))}
></ha-icon>
`}
<paper-item-body two-line>
<div class="name">${this._computeEntityName(entry)}</div>
<div class="secondary entity-id">${entry.entity_id}</div>
</paper-item-body>
<div class="buttons">
${stateObj
? html`
<paper-icon-button
@click=${this._openMoreInfo}
icon="hass:open-in-new"
></paper-icon-button>
`
: ""}
<paper-icon-button
@click=${this._openEditEntry}
icon="hass:settings"
></paper-icon-button>
</div>
</paper-icon-item>
`;
})
: html`
<div class="config-entry-row">
<paper-item-body two-line>
<div>
${this.hass.localize(
"ui.panel.config.devices.entities.none"
)}
</div>
</paper-item-body>
</div>
`}
</ha-card>
`;
}

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, {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird that this is necessary. The update/confirm logic should happen in the dialog and we just should receive callbacks.

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);
}
`;
}
}
41 changes: 33 additions & 8 deletions src/panels/config/devices/ha-config-device-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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(
(
Expand Down Expand Up @@ -67,15 +69,30 @@ export class HaConfigDevicePage extends LitElement {
icon="hass:settings"
@click=${this._showSettings}
></paper-icon-button>
<div class="content">
<ha-config-section .isWide=${!this.narrow}>
<span slot="header">Device info</span>
<span slot="introduction">
Here are all the details of your device.
</span>
<ha-device-card
.hass=${this.hass}
.areas=${this.areas}
.devices=${this.devices}
.device=${device}
.entities=${this.entities}
hide-settings
hide-entities
></ha-device-card>

<div class="header">Entities</div>
<ha-device-entities-card
.hass=${this.hass}
.deviceId=${this.deviceId}
.entities=${this.entities}
>
</ha-device-entities-card>

<div class="header">Automations</div>
<ha-device-triggers-card
.hass=${this.hass}
.deviceId=${this.deviceId}
Expand All @@ -88,7 +105,7 @@ export class HaConfigDevicePage extends LitElement {
.hass=${this.hass}
.deviceId=${this.deviceId}
></ha-device-actions-card>
</div>
</ha-config-section>
</hass-subpage>
`;
}
Expand All @@ -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;
}
`;
}
Expand Down
30 changes: 26 additions & 4 deletions src/panels/config/entity_registry/dialog-entity-registry-detail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -164,7 +170,7 @@ class DialogEntityRegistryDetail extends LitElement {
private async _updateEntry(): Promise<void> {
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(),
Expand All @@ -178,11 +184,27 @@ class DialogEntityRegistryDetail extends LitElement {
}

private async _deleteEntry(): Promise<void> {
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;
}
Expand Down
Loading