Updating Entities Card to TS+lit

This commit is contained in:
Zack Arnett 2018-10-17 09:55:30 -04:00
parent 1feb9f6a27
commit 18be134ad8
4 changed files with 196 additions and 152 deletions

View File

@ -1,150 +0,0 @@
import "@polymer/iron-flex-layout/iron-flex-layout-classes.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import "../../../components/ha-card.js";
import "../components/hui-entities-toggle.js";
import createRowElement from "../common/create-row-element.js";
import computeDomain from "../../../common/entity/compute_domain.js";
import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const.js";
import EventsMixin from "../../../mixins/events-mixin.js";
/*
* @appliesMixin EventsMixin
*/
class HuiEntitiesCard extends EventsMixin(PolymerElement) {
static get template() {
return html`
<style>
ha-card {
padding: 16px;
}
#states {
margin: -4px 0;
}
#states > div {
margin: 4px 0;
}
#states > div > * {
overflow: hidden;
}
.header {
@apply --paper-font-headline;
/* overwriting line-height +8 because entity-toggle can be 40px height,
compensating this with reduced padding */
line-height: 40px;
color: var(--primary-text-color);
padding: 4px 0 12px;
display: flex;
justify-content: space-between;
}
.header .name {
@apply --paper-font-common-nowrap;
}
.state-card-dialog {
cursor: pointer;
}
</style>
<ha-card>
<template is='dom-if' if='[[_showHeader(_config)]]'>
<div class='header'>
<div class="name">[[_config.title]]</div>
<template is="dom-if" if="[[_showHeaderToggle(_config.show_header_toggle)]]">
<hui-entities-toggle hass="[[hass]]" entities="[[_filterEntities(_config.entities)]]"></hui-entities-toggle>
</template>
</div>
</template>
<div id="states"></div>
</ha-card>
`;
}
static get properties() {
return {
hass: {
type: Object,
observer: "_hassChanged",
},
_config: Object,
};
}
constructor() {
super();
this._elements = [];
}
ready() {
super.ready();
if (this._config) this._buildConfig();
}
getCardSize() {
// +1 for the header
return 1 + (this._config ? this._config.entities.length : 0);
}
_showHeaderToggle(show) {
// If show is undefined, we treat it as true
return show !== false;
}
_showHeader(config) {
// Show header if either title or toggle configured to show in it
return config.title || config.show_header_toggle;
}
setConfig(config) {
this._config = config;
this._rows = config.entities.map(
(item) => (typeof item === "string" ? { entity: item } : item)
);
if (this.$) this._buildConfig();
}
_buildConfig() {
const root = this.$.states;
while (root.lastChild) {
root.removeChild(root.lastChild);
}
this._elements = [];
for (const row of this._rows) {
const entityId = row.entity;
const element = createRowElement(row);
if (
entityId &&
!DOMAINS_HIDE_MORE_INFO.includes(computeDomain(entityId))
) {
element.classList.add("state-card-dialog");
element.addEventListener("click", () =>
this.fire("hass-more-info", { entityId })
);
}
element.hass = this.hass;
this._elements.push(element);
const container = document.createElement("div");
container.appendChild(element);
root.appendChild(container);
}
}
_hassChanged(hass) {
this._elements.forEach((element) => {
element.hass = hass;
});
}
_filterEntities(items) {
return items
.filter((item) => typeof item === "string" || item.entity)
.map((item) => (typeof item === "string" ? item : item.entity));
}
}
customElements.define("hui-entities-card", HuiEntitiesCard);

View File

@ -0,0 +1,194 @@
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
import { repeat } from "lit-html/directives/repeat";
import "../../../components/ha-card.js";
import "../components/hui-entities-toggle.js";
import { fireEvent } from "../../../common/dom/fire_event.js";
import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const.js";
import { HassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
import { LovelaceCard, LovelaceConfig } from "../types.js";
import { HomeAssistant } from "../../../types.js";
import createRowElement from "../common/create-row-element.js";
import computeDomain from "../../../common/entity/compute_domain.js";
import processConfigEntities from "../common/process-config-entities";
interface EntityConfig {
name?: string;
icon?: string;
entity: string;
type?: string;
secondary_info: "entity-id" | "last-changed";
action_name?: string;
service?: string;
service_data?: object;
url?: string;
}
interface Config extends LovelaceConfig {
show_header_toggle?: boolean;
title?: string;
entities: EntityConfig[];
}
class HuiEntitiesCard extends HassLocalizeLitMixin(LitElement)
implements LovelaceCard {
protected hass?: HomeAssistant;
protected config?: Config;
protected configEntities?: EntityConfig[];
static get properties(): PropertyDeclarations {
return {
hass: {},
config: {},
};
}
public getCardSize() {
// +1 for the header
return 1 + (this.config ? this.config.entities.length : 0);
}
public setConfig(config: Config) {
this.config = { show_header_toggle: true, ...config };
const entities = processConfigEntities(config.entities);
for (const entity of entities) {
if (
entity.type === "call-service" &&
!entity.service &&
!entity.name &&
!entity.icon &&
!entity.service_data &&
!entity.action_name
) {
throw new Error("Missing required property when type is call-service");
} else if (
entity.type === "weblink" &&
!entity.name &&
!entity.icon &&
!entity.url
) {
throw new Error("Missing required property when type is weblink");
}
}
this.configEntities = entities;
if (this.hass) {
this.requestUpdate();
}
}
protected render() {
if (!this.config || !this.hass) {
return html``;
}
const { show_header_toggle, title } = this.config;
const states = this.hass.states;
const stateEntities = this.configEntities!.filter(
(conf) => conf.entity in states
);
const rowEntities = this.configEntities!.filter(
(item) => typeof item === "string" || item.entity
).map((item) => (typeof item === "string" ? item : item.entity));
return html`
${this.renderStyle()}
<ha-card>
${
!title && !show_header_toggle
? html``
: html`
<div class='header'>
${!title ? html`` : html`<div class="name">${title}</div>`}
${
!show_header_toggle
? html``
: html`
<hui-entities-toggle
.hass="${this.hass}"
.entities="${rowEntities}"
>
</hui-entities-toggle>`
}
</div>`
}
<div id="states">
${repeat<EntityConfig>(
stateEntities,
(entityConf) => entityConf.entity,
(entityConf) => this.renderEntity(entityConf)
)}
</div>
</ha-card>
`;
}
private renderStyle() {
return html`
<style>
ha-card {
padding: 16px;
}
#states {
margin: -4px 0;
}
#states > div {
margin: 4px 0;
}
#states > div > * {
overflow: hidden;
}
.header {
@apply --paper-font-headline;
/* overwriting line-height +8 because entity-toggle can be 40px height,
compensating this with reduced padding */
line-height: 40px;
color: var(--primary-text-color);
padding: 4px 0 12px;
display: flex;
justify-content: space-between;
}
.header .name {
@apply --paper-font-common-nowrap;
}
.state-card-dialog {
cursor: pointer;
}
</style>
`;
}
private renderEntity(entityConf) {
const element = createRowElement(entityConf);
element.hass = this.hass;
element.entityConf = entityConf;
if (!DOMAINS_HIDE_MORE_INFO.includes(computeDomain(entityConf.entity))) {
element.classList.add("state-card-dialog");
element.onclick = this.handleClick;
}
return html`
<div>
${element}
</div>
`;
}
private handleClick(ev: MouseEvent) {
const config = (ev.currentTarget as any).entityConf as EntityConfig;
const entityId = config.entity;
fireEvent(this, "hass-more-info", { entityId });
}
}
declare global {
interface HTMLElementTagNameMap {
"hui-entities-card": HuiEntitiesCard;
}
}
customElements.define("hui-entities-card", HuiEntitiesCard);

View File

@ -2,7 +2,7 @@ import { fireEvent } from "../../../common/dom/fire_event.js";
import "../cards/hui-alarm-panel-card.js";
import "../cards/hui-conditional-card.ts";
import "../cards/hui-entities-card.js";
import "../cards/hui-entities-card.ts";
import "../cards/hui-entity-button-card.ts";
import "../cards/hui-entity-filter-card.js";
import "../cards/hui-error-card.js";

View File

@ -4,7 +4,7 @@ import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import computeUnusedEntities from "./common/compute-unused-entities.js";
import createCardElement from "./common/create-card-element.js";
import "./cards/hui-entities-card.js";
import "./cards/hui-entities-card.ts";
class HuiUnusedEntities extends PolymerElement {
static get template() {