diff --git a/src/panels/config/config-entries/ha-config-entries-dashboard.js b/src/panels/config/config-entries/ha-config-entries-dashboard.js
index c89e5f3b7f..276e8eb74e 100644
--- a/src/panels/config/config-entries/ha-config-entries-dashboard.js
+++ b/src/panels/config/config-entries/ha-config-entries-dashboard.js
@@ -30,8 +30,6 @@ class HaConfigManagerDashboard extends LocalizeMixin(
return html`
+ static get styles(): CSSResult {
+ return css`
+ ha-card {
+ --base-unit: 50px;
+ height: calc(var(--base-unit) * 3);
+ position: relative;
+ cursor: pointer;
+ }
+ .container {
+ width: calc(var(--base-unit) * 4);
+ height: calc(var(--base-unit) * 2);
+ position: absolute;
+ top: calc(var(--base-unit) * 1.5);
+ left: 50%;
+ overflow: hidden;
+ text-align: center;
+ transform: translate(-50%, -50%);
+ }
+ .gauge-a {
+ z-index: 1;
+ position: absolute;
+ background-color: var(--primary-background-color);
+ width: calc(var(--base-unit) * 4);
+ height: calc(var(--base-unit) * 2);
+ top: 0%;
+ border-radius: calc(var(--base-unit) * 2.5) calc(var(--base-unit) * 2.5)
+ 0px 0px;
+ }
+ .gauge-b {
+ z-index: 3;
+ position: absolute;
+ background-color: var(--paper-card-background-color);
+ width: calc(var(--base-unit) * 2.5);
+ height: calc(var(--base-unit) * 1.25);
+ top: calc(var(--base-unit) * 0.75);
+ margin-left: calc(var(--base-unit) * 0.75);
+ margin-right: auto;
+ border-radius: calc(var(--base-unit) * 2.5) calc(var(--base-unit) * 2.5)
+ 0px 0px;
+ }
+ .gauge-c {
+ z-index: 2;
+ position: absolute;
+ background-color: var(--label-badge-blue);
+ width: calc(var(--base-unit) * 4);
+ height: calc(var(--base-unit) * 2);
+ top: calc(var(--base-unit) * 2);
+ margin-left: auto;
+ margin-right: auto;
+ border-radius: 0px 0px calc(var(--base-unit) * 2)
+ calc(var(--base-unit) * 2);
+ transform-origin: center top;
+ }
+ .init .gauge-c {
+ transition: all 1.3s ease-in-out;
+ }
+ .gauge-data {
+ z-index: 4;
+ color: var(--primary-text-color);
+ line-height: calc(var(--base-unit) * 0.3);
+ position: absolute;
+ width: calc(var(--base-unit) * 4);
+ height: calc(var(--base-unit) * 2.1);
+ top: calc(var(--base-unit) * 1.2);
+ margin-left: auto;
+ margin-right: auto;
+ }
+ .init .gauge-data {
+ transition: all 1s ease-out;
+ }
+ .gauge-data #percent {
+ font-size: calc(var(--base-unit) * 0.55);
+ }
+ .gauge-data #name {
+ padding-top: calc(var(--base-unit) * 0.15);
+ font-size: calc(var(--base-unit) * 0.3);
+ }
`;
}
}
diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts
index 81e448d056..820ca06f48 100644
--- a/src/panels/lovelace/cards/hui-glance-card.ts
+++ b/src/panels/lovelace/cards/hui-glance-card.ts
@@ -13,6 +13,7 @@ import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace";
import { longPress } from "../common/directives/long-press-directive";
import { EntityConfig } from "../entity-rows/types";
import { processConfigEntities } from "../common/process-config-entities";
+import { handleClick } from "../common/handle-click";
import computeStateDisplay from "../../../common/entity/compute_state_display";
import computeStateName from "../../../common/entity/compute_state_name";
@@ -21,7 +22,7 @@ import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
import "../../../components/entity/state-badge";
import "../../../components/ha-card";
import "../../../components/ha-icon";
-import { handleClick } from "../common/handle-click";
+import "../components/hui-warning";
export interface ConfigEntity extends EntityConfig {
tap_action?: ActionConfig;
@@ -176,10 +177,6 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
state-badge {
margin: 8px 0;
}
- .not-found {
- background-color: yellow;
- text-align: center;
- }
`;
}
@@ -189,10 +186,13 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
-
-
${entityConf.entity}
- Entity Not Available
-
+
${this.hass!.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ entityConf.entity
+ )}
`;
}
diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts
index 785eb339e2..7e30776ef1 100644
--- a/src/panels/lovelace/cards/hui-light-card.ts
+++ b/src/panels/lovelace/cards/hui-light-card.ts
@@ -22,6 +22,7 @@ import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
import "../../../components/ha-card";
import "../../../components/ha-icon";
+import "../components/hui-warning";
const lightConfig = {
radius: 80,
@@ -78,41 +79,45 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[this._config!.entity] as LightEntity;
+ if (!stateObj) {
+ return html`
+
${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
+ `;
+ }
+
return html`
${this.renderStyle()}
- ${!stateObj
- ? html`
-
- Entity not available: ${this._config.entity}
-
- `
- : html`
-
-
-
- `}
+
+
+
`;
}
@@ -272,11 +277,6 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
.show_brightness {
opacity: 1;
}
- .not-found {
- flex: 1;
- background-color: yellow;
- padding: 8px;
- }
.more-info {
position: absolute;
cursor: pointer;
diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.ts b/src/panels/lovelace/cards/hui-picture-entity-card.ts
index b3a20c9523..9fa618a6a0 100644
--- a/src/panels/lovelace/cards/hui-picture-entity-card.ts
+++ b/src/panels/lovelace/cards/hui-picture-entity-card.ts
@@ -8,6 +8,7 @@ import { classMap } from "lit-html/directives/class-map";
import "../../../components/ha-card";
import "../components/hui-image";
+import "../components/hui-warning";
import computeDomain from "../../../common/entity/compute_domain";
import computeStateDisplay from "../../../common/entity/compute_state_display";
@@ -19,10 +20,6 @@ import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace";
import { LovelaceCard } from "../types";
import { handleClick } from "../common/handle-click";
import { UNAVAILABLE } from "../../../data/entity";
-import {
- createErrorCardElement,
- createErrorCardConfig,
-} from "./hui-error-card";
interface Config extends LovelaceCardConfig {
entity: string;
@@ -76,12 +73,13 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
if (!stateObj) {
return html`
- ${createErrorCardElement(
- createErrorCardConfig(
- `Entity not found: ${this._config.entity}`,
- this._config
- )
- )}
+
${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
diff --git a/src/panels/lovelace/cards/hui-sensor-card.ts b/src/panels/lovelace/cards/hui-sensor-card.ts
index 6bc8630dcf..8dbdab4fea 100644
--- a/src/panels/lovelace/cards/hui-sensor-card.ts
+++ b/src/panels/lovelace/cards/hui-sensor-card.ts
@@ -12,6 +12,7 @@ import { LovelaceCard, LovelaceCardEditor } from "../types";
import { LovelaceCardConfig } from "../../../data/lovelace";
import { HomeAssistant } from "../../../types";
import { fireEvent } from "../../../common/dom/fire_event";
+import { fetchRecent } from "../../../data/history";
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
import computeStateName from "../../../common/entity/compute_state_name";
@@ -19,7 +20,7 @@ import stateIcon from "../../../common/entity/state_icon";
import "../../../components/ha-card";
import "../../../components/ha-icon";
-import { fetchRecent } from "../../../data/history";
+import "../components/hui-warning";
const midPoint = (
_Ax: number,
@@ -199,15 +200,27 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[this._config.entity];
+ if (!stateObj) {
+ return html`
+
${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
+ `;
+ }
+
let graph;
if (stateObj && this._config.graph === "line") {
if (!stateObj.attributes.unit_of_measurement) {
- graph = html`
-
- Entity: ${this._config.entity} - Has no Unit of Measurement and
- therefore can not display a line graph.
-
+ return html`
+
Entity: ${this._config.entity} - Has no Unit of Measurement and
+ therefore can not display a line graph.
`;
} else if (!this._history) {
graph = svg`
@@ -233,34 +246,26 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
return html`
${this.renderStyle()}
- ${!stateObj
- ? html`
-
- Entity not available: ${this._config.entity}
-
- `
- : html`
-
-
- ${stateObj.state}
- ${this._config.unit ||
- stateObj.attributes.unit_of_measurement}
-
-
- `}
+
+
+ ${stateObj.state}
+ ${this._config.unit ||
+ stateObj.attributes.unit_of_measurement}
+
+
`;
}
@@ -399,11 +404,6 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
align-self: flex-end;
margin: auto 8px;
}
- .not-found {
- flex: 1;
- background-color: yellow;
- padding: 8px;
- }
`;
}
diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts
index 8ddd773838..21c5d70614 100644
--- a/src/panels/lovelace/cards/hui-thermostat-card.ts
+++ b/src/panels/lovelace/cards/hui-thermostat-card.ts
@@ -10,6 +10,7 @@ import "@polymer/paper-icon-button/paper-icon-button";
import "../../../components/ha-card";
import "../../../components/ha-icon";
+import "../components/hui-warning";
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
import computeStateName from "../../../common/entity/compute_state_name";
@@ -102,16 +103,19 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
return html``;
}
const stateObj = this.hass.states[this._config.entity] as ClimateEntity;
+
if (!stateObj) {
return html`
- ${this.renderStyle()}
-
-
- Entity not available: ${this._config.entity}
-
-
+
${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
+
const mode = modeIcons[stateObj.attributes.operation_mode || ""]
? stateObj.attributes.operation_mode!
: "unknown-mode";
@@ -280,7 +284,10 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
);
} else {
sliderValue = stateObj.attributes.temperature;
- uiValue = "" + stateObj.attributes.temperature;
+ uiValue =
+ stateObj.attributes.temperature !== null
+ ? String(stateObj.attributes.temperature)
+ : "";
}
return [sliderValue, uiValue];
@@ -384,11 +391,6 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
--idle-color: #8a8a8a;
--unknown-color: #bac;
}
- .not-found {
- flex: 1;
- background-color: yellow;
- padding: 8px;
- }
#root {
position: relative;
overflow: hidden;
diff --git a/src/panels/lovelace/components/hui-generic-entity-row.ts b/src/panels/lovelace/components/hui-generic-entity-row.ts
index d9916ffe69..03ecc5ef08 100644
--- a/src/panels/lovelace/components/hui-generic-entity-row.ts
+++ b/src/panels/lovelace/components/hui-generic-entity-row.ts
@@ -1,7 +1,3 @@
-import "../../../components/entity/state-badge";
-import "../../../components/ha-relative-time";
-import "../../../components/ha-icon";
-
import computeStateName from "../../../common/entity/compute_state_name";
import {
LitElement,
@@ -11,10 +7,16 @@ import {
PropertyValues,
property,
} from "lit-element";
+
import { HomeAssistant } from "../../../types";
import { EntitiesCardEntityConfig } from "../cards/hui-entities-card";
import { computeRTL } from "../../../common/util/compute_rtl";
+import "../../../components/entity/state-badge";
+import "../../../components/ha-relative-time";
+import "../../../components/ha-icon";
+import "../components/hui-warning";
+
class HuiGenericEntityRow extends LitElement {
@property() public hass?: HomeAssistant;
@property() public config?: EntitiesCardEntityConfig;
@@ -30,7 +32,13 @@ class HuiGenericEntityRow extends LitElement {
if (!stateObj) {
return html`
-
Entity not available: [[config.entity]]
+
${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this.config.entity
+ )}
`;
}
@@ -107,11 +115,6 @@ class HuiGenericEntityRow extends LitElement {
display: block;
color: var(--secondary-text-color);
}
- .not-found {
- flex: 1;
- background-color: yellow;
- padding: 8px;
- }
state-badge {
flex: 0 0 40px;
}
diff --git a/src/panels/lovelace/components/hui-image.ts b/src/panels/lovelace/components/hui-image.ts
index cdc7b06aa1..04a12f34d8 100644
--- a/src/panels/lovelace/components/hui-image.ts
+++ b/src/panels/lovelace/components/hui-image.ts
@@ -167,15 +167,14 @@ class HuiImage extends LitElement {
if (!this.hass || !this.cameraImage) {
return;
}
- if (this._cameraImageSrc) {
- URL.revokeObjectURL(this._cameraImageSrc);
- this._cameraImageSrc = undefined;
- }
try {
const { content_type: contentType, content } = await fetchThumbnail(
this.hass,
this.cameraImage
);
+ if (this._cameraImageSrc) {
+ URL.revokeObjectURL(this._cameraImageSrc);
+ }
this._cameraImageSrc = URL.createObjectURL(
b64toBlob(content, contentType)
);
diff --git a/src/panels/lovelace/components/hui-warning.ts b/src/panels/lovelace/components/hui-warning.ts
new file mode 100644
index 0000000000..7bbbe1af67
--- /dev/null
+++ b/src/panels/lovelace/components/hui-warning.ts
@@ -0,0 +1,34 @@
+import {
+ html,
+ LitElement,
+ TemplateResult,
+ CSSResult,
+ css,
+ customElement,
+} from "lit-element";
+
+@customElement("hui-warning")
+export class HuiWarning extends LitElement {
+ protected render(): TemplateResult | void {
+ return html`
+
+ `;
+ }
+
+ static get styles(): CSSResult {
+ return css`
+ :host {
+ display: block;
+ color: black;
+ background-color: #fce588;
+ padding: 8px;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hui-warning": HuiWarning;
+ }
+}
diff --git a/src/panels/lovelace/components/notifications/hui-notifications-button.js b/src/panels/lovelace/components/notifications/hui-notifications-button.js
deleted file mode 100644
index 6ecf1ec920..0000000000
--- a/src/panels/lovelace/components/notifications/hui-notifications-button.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import "@material/mwc-button";
-import "@polymer/paper-icon-button/paper-icon-button";
-import "@polymer/app-layout/app-toolbar/app-toolbar";
-
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import EventsMixin from "../../../../mixins/events-mixin";
-
-/*
- * @appliesMixin EventsMixin
- */
-export class HuiNotificationsButton extends EventsMixin(PolymerElement) {
- static get template() {
- return html`
-
-
-
- `;
- }
-
- static get properties() {
- return {
- open: {
- type: Boolean,
- notify: true,
- },
- notifications: {
- type: Array,
- value: [],
- },
- };
- }
-
- _clicked() {
- this.open = true;
- }
-
- _hasNotifications(notifications) {
- return notifications.length > 0;
- }
-}
-customElements.define("hui-notifications-button", HuiNotificationsButton);
diff --git a/src/panels/lovelace/components/notifications/hui-notifications-button.ts b/src/panels/lovelace/components/notifications/hui-notifications-button.ts
new file mode 100644
index 0000000000..c56d2931a1
--- /dev/null
+++ b/src/panels/lovelace/components/notifications/hui-notifications-button.ts
@@ -0,0 +1,80 @@
+import {
+ html,
+ LitElement,
+ TemplateResult,
+ css,
+ CSSResult,
+ property,
+} from "lit-element";
+import "@polymer/paper-icon-button/paper-icon-button";
+import { fireEvent } from "../../../../common/dom/fire_event";
+
+declare global {
+ // tslint:disable-next-line
+ interface HASSDomEvents {
+ "opened-changed": { value: boolean };
+ }
+}
+
+class HuiNotificationsButton extends LitElement {
+ @property() public notifications?: string[];
+ @property() public opened?: boolean;
+
+ protected render(): TemplateResult | void {
+ return html`
+
+ ${this.notifications && this.notifications.length > 0
+ ? html`
+
+ ${this.notifications.length}
+
+ `
+ : ""}
+ `;
+ }
+
+ static get styles(): CSSResult[] {
+ return [
+ css`
+ :host {
+ position: relative;
+ }
+
+ .indicator {
+ position: absolute;
+ top: 0px;
+ right: -3px;
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ background: var(--accent-color);
+ pointer-events: none;
+ z-index: 1;
+ }
+
+ .indicator > div {
+ right: 7px;
+ top: 3px;
+ position: absolute;
+ font-size: 0.55em;
+ }
+ `,
+ ];
+ }
+
+ private _clicked() {
+ this.opened = true;
+ fireEvent(this, "opened-changed", { value: this.opened });
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hui-notifications-button": HuiNotificationsButton;
+ }
+}
+
+customElements.define("hui-notifications-button", HuiNotificationsButton);
diff --git a/src/panels/lovelace/entity-rows/hui-climate-entity-row.ts b/src/panels/lovelace/entity-rows/hui-climate-entity-row.ts
index d452445d78..9487294b76 100644
--- a/src/panels/lovelace/entity-rows/hui-climate-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-climate-entity-row.ts
@@ -1,21 +1,22 @@
-import { html, LitElement, TemplateResult } from "lit-element";
+import {
+ html,
+ LitElement,
+ TemplateResult,
+ property,
+ css,
+ CSSResult,
+} from "lit-element";
import "../../../components/ha-climate-state";
import "../components/hui-generic-entity-row";
+import "../components/hui-warning";
import { HomeAssistant } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
class HuiClimateEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: EntityConfig;
-
- static get properties() {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
public setConfig(config: EntityConfig): void {
if (!config || !config.entity) {
@@ -34,14 +35,17 @@ class HuiClimateEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+
${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
return html`
- ${this.renderStyle()}
- ha-climate-state {
- text-align: right;
- }
-
+ static get styles(): CSSResult {
+ return css`
+ ha-climate-state {
+ text-align: right;
+ }
`;
}
}
diff --git a/src/panels/lovelace/entity-rows/hui-cover-entity-row.ts b/src/panels/lovelace/entity-rows/hui-cover-entity-row.ts
index 2920416d91..148c1614c2 100644
--- a/src/panels/lovelace/entity-rows/hui-cover-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-cover-entity-row.ts
@@ -1,29 +1,24 @@
import {
html,
LitElement,
- PropertyDeclarations,
TemplateResult,
+ property,
+ css,
+ CSSResult,
} from "lit-element";
import "../components/hui-generic-entity-row";
import "../../../components/ha-cover-controls";
import "../../../components/ha-cover-tilt-controls";
-import "./hui-error-entity-row";
+import "../components/hui-warning";
import { isTiltOnly } from "../../../util/cover-model";
import { HomeAssistant } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
class HuiCoverEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: EntityConfig;
-
- static get properties(): PropertyDeclarations {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
public setConfig(config: EntityConfig): void {
if (!config) {
@@ -41,14 +36,17 @@ class HuiCoverEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+ ${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
return html`
- ${this.renderStyle()}
${isTiltOnly(stateObj)
? html`
@@ -67,14 +65,12 @@ class HuiCoverEntityRow extends LitElement implements EntityRow {
`;
}
- private renderStyle(): TemplateResult {
- return html`
-
+ static get styles(): CSSResult {
+ return css`
+ ha-cover-controls,
+ ha-cover-tilt-controls {
+ margin-right: -0.57em;
+ }
`;
}
}
diff --git a/src/panels/lovelace/entity-rows/hui-error-entity-row.ts b/src/panels/lovelace/entity-rows/hui-error-entity-row.ts
deleted file mode 100644
index fc0265eddb..0000000000
--- a/src/panels/lovelace/entity-rows/hui-error-entity-row.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { html, LitElement, TemplateResult } from "lit-element";
-
-class HuiErrorEntityRow extends LitElement {
- public entity?: string;
- public error?: string;
-
- static get properties() {
- return {
- error: {},
- entity: {},
- };
- }
-
- protected render(): TemplateResult | void {
- return html`
- ${this.renderStyle()} ${this.error || "Entity not available"}:
- ${this.entity || ""}
- `;
- }
-
- private renderStyle(): TemplateResult {
- return html`
-
- `;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "hui-error-entity-row": HuiErrorEntityRow;
- }
-}
-
-customElements.define("hui-error-entity-row", HuiErrorEntityRow);
diff --git a/src/panels/lovelace/entity-rows/hui-group-entity-row.ts b/src/panels/lovelace/entity-rows/hui-group-entity-row.ts
index e8afa8acc6..e422037ca6 100644
--- a/src/panels/lovelace/entity-rows/hui-group-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-group-entity-row.ts
@@ -1,13 +1,8 @@
-import {
- html,
- LitElement,
- PropertyDeclarations,
- TemplateResult,
-} from "lit-element";
+import { html, LitElement, TemplateResult, property } from "lit-element";
import "../components/hui-generic-entity-row";
import "../../../components/entity/ha-entity-toggle";
-import "./hui-error-entity-row";
+import "../components/hui-warning";
import computeStateDisplay from "../../../common/entity/compute_state_display";
import { DOMAINS_TOGGLE } from "../../../common/const";
@@ -15,15 +10,8 @@ import { HomeAssistant } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
class HuiGroupEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: EntityConfig;
-
- static get properties(): PropertyDeclarations {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
public setConfig(config: EntityConfig): void {
if (!config) {
@@ -41,9 +29,13 @@ class HuiGroupEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+ ${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
diff --git a/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts b/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts
index 2ee0010b2b..77c056524c 100644
--- a/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts
@@ -1,8 +1,10 @@
import {
html,
LitElement,
- PropertyDeclarations,
TemplateResult,
+ property,
+ css,
+ CSSResult,
} from "lit-element";
import { repeat } from "lit-html/directives/repeat";
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
@@ -10,7 +12,7 @@ import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import "../../../components/entity/state-badge";
-import "./hui-error-entity-row";
+import "../components/hui-warning";
import computeStateName from "../../../common/entity/compute_state_name";
import { HomeAssistant } from "../../../types";
@@ -18,15 +20,8 @@ import { EntityRow, EntityConfig } from "./types";
import { setOption } from "../../../data/input-select";
class HuiInputSelectEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: EntityConfig;
-
- static get properties(): PropertyDeclarations {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
public setConfig(config: EntityConfig): void {
if (!config || !config.entity) {
@@ -45,14 +40,17 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+ ${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
return html`
- ${this.renderStyle()}
- :host {
- display: flex;
- align-items: center;
- }
- paper-dropdown-menu {
- margin-left: 16px;
- flex: 1;
- }
-
+ static get styles(): CSSResult {
+ return css`
+ :host {
+ display: flex;
+ align-items: center;
+ }
+ paper-dropdown-menu {
+ margin-left: 16px;
+ flex: 1;
+ }
`;
}
diff --git a/src/panels/lovelace/entity-rows/hui-input-text-entity-row.ts b/src/panels/lovelace/entity-rows/hui-input-text-entity-row.ts
index 9aae5b482d..1456bb9492 100644
--- a/src/panels/lovelace/entity-rows/hui-input-text-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-input-text-entity-row.ts
@@ -1,28 +1,16 @@
-import {
- html,
- LitElement,
- PropertyDeclarations,
- TemplateResult,
-} from "lit-element";
+import { html, LitElement, TemplateResult, property } from "lit-element";
import { PaperInputElement } from "@polymer/paper-input/paper-input";
import "../components/hui-generic-entity-row";
-import "./hui-error-entity-row";
+import "../components/hui-warning";
import { HomeAssistant } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
import { setValue } from "../../../data/input_text";
class HuiInputTextEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: EntityConfig;
-
- static get properties(): PropertyDeclarations {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
public setConfig(config: EntityConfig): void {
if (!config) {
@@ -40,9 +28,13 @@ class HuiInputTextEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+ ${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
diff --git a/src/panels/lovelace/entity-rows/hui-lock-entity-row.ts b/src/panels/lovelace/entity-rows/hui-lock-entity-row.ts
index 420185b4d8..15c0acbf5c 100644
--- a/src/panels/lovelace/entity-rows/hui-lock-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-lock-entity-row.ts
@@ -1,26 +1,21 @@
import {
html,
LitElement,
- PropertyDeclarations,
TemplateResult,
+ property,
+ css,
+ CSSResult,
} from "lit-element";
import "../components/hui-generic-entity-row";
-import "./hui-error-entity-row";
+import "../components/hui-warning";
import { HomeAssistant } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
class HuiLockEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: EntityConfig;
-
- static get properties(): PropertyDeclarations {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
public setConfig(config: EntityConfig): void {
if (!config) {
@@ -38,14 +33,17 @@ class HuiLockEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+ ${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
return html`
- ${this.renderStyle()}
${stateObj.state === "locked"
@@ -56,15 +54,11 @@ class HuiLockEntityRow extends LitElement implements EntityRow {
`;
}
- protected renderStyle(): TemplateResult {
- return html`
-
+ static get styles(): CSSResult {
+ return css`
+ mwc-button {
+ margin-right: -0.57em;
+ }
`;
}
diff --git a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts
index 12e419828e..3defa48446 100644
--- a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts
@@ -1,7 +1,15 @@
-import { html, LitElement, TemplateResult } from "lit-element";
+import {
+ html,
+ LitElement,
+ TemplateResult,
+ css,
+ CSSResult,
+ property,
+} from "lit-element";
import "@polymer/paper-icon-button/paper-icon-button";
import "../components/hui-generic-entity-row";
+import "../components/hui-warning";
import { EntityRow, EntityConfig } from "./types";
import { HomeAssistant } from "../../../types";
@@ -15,15 +23,8 @@ import {
} from "../../../data/media-player";
class HuiMediaPlayerEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: EntityConfig;
-
- static get properties() {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
public setConfig(config: EntityConfig): void {
if (!config || !config.entity) {
@@ -42,14 +43,17 @@ class HuiMediaPlayerEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+ ${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
return html`
- ${this.renderStyle()}
- .controls {
- white-space: nowrap;
- }
-
+ static get styles(): CSSResult {
+ return css`
+ .controls {
+ white-space: nowrap;
+ }
`;
}
diff --git a/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts b/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts
index 045dba7df9..4a11a1f6a3 100644
--- a/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts
@@ -1,27 +1,22 @@
import {
html,
LitElement,
- PropertyDeclarations,
TemplateResult,
+ CSSResult,
+ css,
+ property,
} from "lit-element";
import "../components/hui-generic-entity-row";
import "../../../components/entity/ha-entity-toggle";
-import "./hui-error-entity-row";
+import "../components/hui-warning";
import { HomeAssistant } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
class HuiSceneEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: EntityConfig;
-
- static get properties(): PropertyDeclarations {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
public setConfig(config: EntityConfig): void {
if (!config) {
@@ -39,14 +34,17 @@ class HuiSceneEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+ ${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
return html`
- ${this.renderStyle()}
${stateObj.attributes.can_cancel
? html`
@@ -64,15 +62,11 @@ class HuiSceneEntityRow extends LitElement implements EntityRow {
`;
}
- protected renderStyle(): TemplateResult {
- return html`
-
+ static get styles(): CSSResult {
+ return css`
+ mwc-button {
+ margin-right: -0.57em;
+ }
`;
}
diff --git a/src/panels/lovelace/entity-rows/hui-script-entity-row.ts b/src/panels/lovelace/entity-rows/hui-script-entity-row.ts
index 3a31251d14..b0465abf11 100644
--- a/src/panels/lovelace/entity-rows/hui-script-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-script-entity-row.ts
@@ -1,27 +1,22 @@
import {
html,
LitElement,
- PropertyDeclarations,
TemplateResult,
+ property,
+ CSSResult,
+ css,
} from "lit-element";
import "../components/hui-generic-entity-row";
import "../../../components/entity/ha-entity-toggle";
-import "./hui-error-entity-row";
+import "../components/hui-warning";
import { HomeAssistant } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
class HuiScriptEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: EntityConfig;
-
- static get properties(): PropertyDeclarations {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
public setConfig(config: EntityConfig): void {
if (!config) {
@@ -39,14 +34,17 @@ class HuiScriptEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+ ${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
return html`
- ${this.renderStyle()}
${stateObj.attributes.can_cancel
? html`
@@ -64,15 +62,11 @@ class HuiScriptEntityRow extends LitElement implements EntityRow {
`;
}
- protected renderStyle(): TemplateResult {
- return html`
-
+ static get styles(): CSSResult {
+ return css`
+ mwc-button {
+ margin-right: -0.57em;
+ }
`;
}
diff --git a/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts b/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts
index ac4a261a55..4c65f99cf0 100644
--- a/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts
@@ -1,13 +1,15 @@
import {
html,
LitElement,
- PropertyDeclarations,
TemplateResult,
+ property,
+ CSSResult,
+ css,
} from "lit-element";
import "../components/hui-generic-entity-row";
import "../components/hui-timestamp-display";
-import "./hui-error-entity-row";
+import "../components/hui-warning";
import { HomeAssistant } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
@@ -19,15 +21,8 @@ interface SensorEntityConfig extends EntityConfig {
}
class HuiSensorEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: SensorEntityConfig;
-
- static get properties(): PropertyDeclarations {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: SensorEntityConfig;
public setConfig(config: SensorEntityConfig): void {
if (!config) {
@@ -45,14 +40,17 @@ class HuiSensorEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+ ${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
return html`
- ${this.renderStyle()}
${stateObj.attributes.device_class === "timestamp"
@@ -73,13 +71,11 @@ class HuiSensorEntityRow extends LitElement implements EntityRow {
`;
}
- private renderStyle(): TemplateResult {
- return html`
-
+ static get styles(): CSSResult {
+ return css`
+ div {
+ text-align: right;
+ }
`;
}
}
diff --git a/src/panels/lovelace/entity-rows/hui-text-entity-row.ts b/src/panels/lovelace/entity-rows/hui-text-entity-row.ts
index e30bdf27e5..5fd9f2f442 100644
--- a/src/panels/lovelace/entity-rows/hui-text-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-text-entity-row.ts
@@ -1,27 +1,22 @@
import {
html,
LitElement,
- PropertyDeclarations,
TemplateResult,
+ property,
+ CSSResult,
+ css,
} from "lit-element";
import "../components/hui-generic-entity-row";
-import "./hui-error-entity-row";
+import "../components/hui-warning";
import computeStateDisplay from "../../../common/entity/compute_state_display";
import { HomeAssistant } from "../../../types";
import { EntityRow, EntityConfig } from "./types";
class HuiTextEntityRow extends LitElement implements EntityRow {
- public hass?: HomeAssistant;
- private _config?: EntityConfig;
-
- static get properties(): PropertyDeclarations {
- return {
- hass: {},
- _config: {},
- };
- }
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
public setConfig(config: EntityConfig): void {
if (!config) {
@@ -39,14 +34,17 @@ class HuiTextEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+
${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
return html`
- ${this.renderStyle()}
${computeStateDisplay(
@@ -59,13 +57,11 @@ class HuiTextEntityRow extends LitElement implements EntityRow {
`;
}
- private renderStyle(): TemplateResult {
- return html`
-
+ static get styles(): CSSResult {
+ return css`
+ div {
+ text-align: right;
+ }
`;
}
}
diff --git a/src/panels/lovelace/entity-rows/hui-timer-entity-row.js b/src/panels/lovelace/entity-rows/hui-timer-entity-row.js
deleted file mode 100644
index fbcfd143d5..0000000000
--- a/src/panels/lovelace/entity-rows/hui-timer-entity-row.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "../components/hui-generic-entity-row";
-
-import timerTimeRemaining from "../../../common/entity/timer_time_remaining";
-import secondsToDuration from "../../../common/datetime/seconds_to_duration";
-
-class HuiTimerEntityRow extends PolymerElement {
- static get template() {
- return html`
-
- ${this.timerControlTemplate}
-
- `;
- }
-
- static get timerControlTemplate() {
- return html`
-
[[_computeDisplay(_stateObj, _timeRemaining)]]
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- _config: Object,
- _stateObj: {
- type: Object,
- computed: "_computeStateObj(hass.states, _config.entity)",
- observer: "_stateObjChanged",
- },
- _timeRemaining: Number,
- };
- }
-
- disconnectedCallback() {
- super.disconnectedCallback();
- this._clearInterval();
- }
-
- _stateObjChanged(stateObj) {
- if (stateObj) {
- this._startInterval(stateObj);
- } else {
- this._clearInterval();
- }
- }
-
- _clearInterval() {
- if (this._updateRemaining) {
- clearInterval(this._updateRemaining);
- this._updateRemaining = null;
- }
- }
-
- _startInterval(stateObj) {
- this._clearInterval();
- this._calculateRemaining(stateObj);
-
- if (stateObj.state === "active") {
- this._updateRemaining = setInterval(
- () => this._calculateRemaining(this._stateObj),
- 1000
- );
- }
- }
-
- _calculateRemaining(stateObj) {
- this._timeRemaining = timerTimeRemaining(stateObj);
- }
-
- _computeDisplay(stateObj, time) {
- if (!stateObj) return null;
-
- if (stateObj.state === "idle" || time === 0) return stateObj.state;
-
- let display = secondsToDuration(time);
-
- if (stateObj.state === "paused") {
- display += " (paused)";
- }
-
- return display;
- }
-
- _computeStateObj(states, entityId) {
- return states && entityId in states ? states[entityId] : null;
- }
-
- setConfig(config) {
- if (!config || !config.entity) {
- throw new Error("Entity not configured.");
- }
- this._config = config;
- }
-}
-customElements.define("hui-timer-entity-row", HuiTimerEntityRow);
diff --git a/src/panels/lovelace/entity-rows/hui-timer-entity-row.ts b/src/panels/lovelace/entity-rows/hui-timer-entity-row.ts
new file mode 100644
index 0000000000..7e7383961d
--- /dev/null
+++ b/src/panels/lovelace/entity-rows/hui-timer-entity-row.ts
@@ -0,0 +1,128 @@
+import {
+ html,
+ LitElement,
+ TemplateResult,
+ property,
+ PropertyValues,
+} from "lit-element";
+
+import "../components/hui-generic-entity-row";
+import "../components/hui-warning";
+
+import timerTimeRemaining from "../../../common/entity/timer_time_remaining";
+import secondsToDuration from "../../../common/datetime/seconds_to_duration";
+import { HomeAssistant } from "../../../types";
+import { EntityConfig } from "./types";
+import { HassEntity } from "home-assistant-js-websocket";
+
+class HuiTimerEntityRow extends LitElement {
+ @property() public hass?: HomeAssistant;
+ @property() private _config?: EntityConfig;
+ @property() private _timeRemaining?: number;
+ private _interval?: number;
+
+ public setConfig(config: EntityConfig): void {
+ if (!config) {
+ throw new Error("Configuration error");
+ }
+ this._config = config;
+ }
+
+ public disconnectedCallback(): void {
+ super.disconnectedCallback();
+ this._clearInterval();
+ }
+
+ protected render(): TemplateResult | void {
+ if (!this._config || !this.hass) {
+ return html``;
+ }
+
+ const stateObj = this.hass.states[this._config.entity];
+
+ if (!stateObj) {
+ return html`
+
${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
+ `;
+ }
+
+ return html`
+
+ ${this._computeDisplay(stateObj)}
+
+ `;
+ }
+
+ protected updated(changedProps: PropertyValues) {
+ super.updated(changedProps);
+
+ if (changedProps.has("hass")) {
+ const stateObj = this.hass!.states[this._config!.entity];
+ const oldHass = changedProps.get("hass") as this["hass"];
+ const oldStateObj = oldHass
+ ? oldHass.states[this._config!.entity]
+ : undefined;
+
+ if (oldStateObj !== stateObj) {
+ this._startInterval(stateObj);
+ } else if (!stateObj) {
+ this._clearInterval();
+ }
+ }
+ }
+
+ private _clearInterval(): void {
+ if (this._interval) {
+ window.clearInterval(this._interval);
+ this._interval = undefined;
+ }
+ }
+
+ private _startInterval(stateObj: HassEntity): void {
+ this._clearInterval();
+ this._calculateRemaining(stateObj);
+
+ if (stateObj.state === "active") {
+ this._interval = window.setInterval(
+ () => this._calculateRemaining(stateObj),
+ 1000
+ );
+ }
+ }
+
+ private _calculateRemaining(stateObj: HassEntity): void {
+ this._timeRemaining = timerTimeRemaining(stateObj);
+ }
+
+ private _computeDisplay(stateObj: HassEntity): string | null {
+ if (!stateObj) {
+ return null;
+ }
+
+ if (stateObj.state === "idle" || this._timeRemaining === 0) {
+ return this.hass!.localize("state.timer." + stateObj.state);
+ }
+
+ let display = secondsToDuration(this._timeRemaining || 0);
+
+ if (stateObj.state === "paused") {
+ display += ` (${this.hass!.localize("state.timer.paused")})`;
+ }
+
+ return display;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hui-timer-entity-row": HuiTimerEntityRow;
+ }
+}
+
+customElements.define("hui-timer-entity-row", HuiTimerEntityRow);
diff --git a/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts b/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts
index f5a7848835..e91a47e460 100644
--- a/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts
@@ -7,7 +7,7 @@ import {
import "../components/hui-generic-entity-row";
import "../../../components/entity/ha-entity-toggle";
-import "./hui-error-entity-row";
+import "../components/hui-warning";
import computeStateDisplay from "../../../common/entity/compute_state_display";
import { HomeAssistant } from "../../../types";
@@ -40,9 +40,13 @@ class HuiToggleEntityRow extends LitElement implements EntityRow {
if (!stateObj) {
return html`
-
+
${this.hass.localize(
+ "ui.panel.lovelace.warning.entity_not_found",
+ "entity",
+ this._config.entity
+ )}
`;
}
diff --git a/src/panels/lovelace/ha-panel-lovelace.ts b/src/panels/lovelace/ha-panel-lovelace.ts
index ff7b39ab10..1b9d3edbd0 100644
--- a/src/panels/lovelace/ha-panel-lovelace.ts
+++ b/src/panels/lovelace/ha-panel-lovelace.ts
@@ -73,12 +73,6 @@ class LovelacePanel extends LitElement {
if (state === "error") {
return html`
-
${this.config.title || "Home Assistant"}
diff --git a/src/panels/profile/ha-mfa-modules-card.js b/src/panels/profile/ha-mfa-modules-card.js
index bae240bbf5..f791f200ef 100644
--- a/src/panels/profile/ha-mfa-modules-card.js
+++ b/src/panels/profile/ha-mfa-modules-card.js
@@ -37,8 +37,6 @@ class HaMfaModulesCard extends EventsMixin(LocalizeMixin(PolymerElement)) {
margin: 16px auto;
}
mwc-button {
- color: var(--primary-color);
- font-weight: 500;
margin-right: -0.57em;
}
diff --git a/src/state-summary/state-card-configurator.js b/src/state-summary/state-card-configurator.js
index daacf85736..5cc66cf4f5 100644
--- a/src/state-summary/state-card-configurator.js
+++ b/src/state-summary/state-card-configurator.js
@@ -16,8 +16,6 @@ class StateCardConfigurator extends LocalizeMixin(PolymerElement) {