mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Convert HA-STATE-LABEL-BADGE to lit (#2268)
This commit is contained in:
parent
bd46e3b8e0
commit
99395360c7
@ -1,25 +1,206 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
|
||||
import "../ha-label-badge";
|
||||
import {
|
||||
LitElement,
|
||||
html,
|
||||
PropertyValues,
|
||||
PropertyDeclarations,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
|
||||
import computeStateDomain from "../../common/entity/compute_state_domain";
|
||||
import computeStateName from "../../common/entity/compute_state_name";
|
||||
import domainIcon from "../../common/entity/domain_icon";
|
||||
import stateIcon from "../../common/entity/state_icon";
|
||||
import timerTimeRemaining from "../../common/entity/timer_time_remaining";
|
||||
import attributeClassNames from "../../common/entity/attribute_class_names";
|
||||
import secondsToDuration from "../../common/datetime/seconds_to_duration";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin";
|
||||
|
||||
import EventsMixin from "../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../mixins/localize-mixin";
|
||||
import "../ha-label-badge";
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
* @appliesMixin EventsMixin
|
||||
*/
|
||||
class HaStateLabelBadge extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) {
|
||||
public state?: HassEntity;
|
||||
private _connected?: boolean;
|
||||
private _updateRemaining?: number;
|
||||
private _timerTimeRemaining?: number;
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this._connected = true;
|
||||
this.startInterval(this.state);
|
||||
}
|
||||
|
||||
public disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._connected = false;
|
||||
this.clearInterval();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const state = this.state;
|
||||
|
||||
if (!state) {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<ha-label-badge label="not found"></ha-label-badge>
|
||||
`;
|
||||
}
|
||||
|
||||
const domain = computeStateDomain(state);
|
||||
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<ha-label-badge
|
||||
class="${
|
||||
classMap({
|
||||
[domain]: true,
|
||||
"has-unit_of_measurement":
|
||||
"unit_of_measurement" in state.attributes,
|
||||
})
|
||||
}"
|
||||
.value="${this._computeValue(domain, state)}"
|
||||
.icon="${this._computeIcon(domain, state)}"
|
||||
.image="${state.attributes.entity_picture}"
|
||||
.label="${this._computeLabel(domain, state, this._timerTimeRemaining)}"
|
||||
.description="${computeStateName(state)}"
|
||||
></ha-label-badge>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
state: {},
|
||||
_timerTimeRemaining: {},
|
||||
};
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties: PropertyValues): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
this.addEventListener("click", (ev) => {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "hass-more-info", { entityId: this.state!.entity_id });
|
||||
});
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
super.updated(changedProperties);
|
||||
|
||||
if (this._connected && changedProperties.has("state")) {
|
||||
this.startInterval(this.state);
|
||||
}
|
||||
}
|
||||
|
||||
private _computeValue(domain: string, state: HassEntity) {
|
||||
switch (domain) {
|
||||
case "binary_sensor":
|
||||
case "device_tracker":
|
||||
case "updater":
|
||||
case "sun":
|
||||
case "alarm_control_panel":
|
||||
case "timer":
|
||||
return null;
|
||||
case "sensor":
|
||||
default:
|
||||
return state.state === "unknown"
|
||||
? "-"
|
||||
: this.localize(`component.${domain}.state.${state.state}`) ||
|
||||
state.state;
|
||||
}
|
||||
}
|
||||
|
||||
private _computeIcon(domain: string, state: HassEntity) {
|
||||
if (state.state === "unavailable") {
|
||||
return null;
|
||||
}
|
||||
switch (domain) {
|
||||
case "alarm_control_panel":
|
||||
if (state.state === "pending") {
|
||||
return "hass:clock-fast";
|
||||
}
|
||||
if (state.state === "armed_away") {
|
||||
return "hass:nature";
|
||||
}
|
||||
if (state.state === "armed_home") {
|
||||
return "hass:home-variant";
|
||||
}
|
||||
if (state.state === "armed_night") {
|
||||
return "hass:weather-night";
|
||||
}
|
||||
if (state.state === "armed_custom_bypass") {
|
||||
return "hass:security-home";
|
||||
}
|
||||
if (state.state === "triggered") {
|
||||
return "hass:alert-circle";
|
||||
}
|
||||
// state == 'disarmed'
|
||||
return domainIcon(domain, state.state);
|
||||
case "binary_sensor":
|
||||
case "device_tracker":
|
||||
case "updater":
|
||||
return stateIcon(state);
|
||||
case "sun":
|
||||
return state.state === "above_horizon"
|
||||
? domainIcon(domain)
|
||||
: "hass:brightness-3";
|
||||
case "timer":
|
||||
return state.state === "active" ? "hass:timer" : "hass:timer-off";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private _computeLabel(domain, state, _timerTimeRemaining) {
|
||||
if (
|
||||
state.state === "unavailable" ||
|
||||
["device_tracker", "alarm_control_panel"].includes(domain)
|
||||
) {
|
||||
// Localize the state with a special state_badge namespace, which has variations of
|
||||
// the state translations that are truncated to fit within the badge label. Translations
|
||||
// are only added for device_tracker and alarm_control_panel.
|
||||
return (
|
||||
this.localize(`state_badge.${domain}.${state.state}`) ||
|
||||
this.localize(`state_badge.default.${state.state}`) ||
|
||||
state.state
|
||||
);
|
||||
}
|
||||
if (domain === "timer") {
|
||||
return secondsToDuration(_timerTimeRemaining);
|
||||
}
|
||||
return state.attributes.unit_of_measurement || null;
|
||||
}
|
||||
|
||||
private clearInterval() {
|
||||
if (this._updateRemaining) {
|
||||
clearInterval(this._updateRemaining);
|
||||
this._updateRemaining = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private startInterval(stateObj) {
|
||||
this.clearInterval();
|
||||
if (computeStateDomain(stateObj) === "timer") {
|
||||
this.calculateTimerRemaining(stateObj);
|
||||
|
||||
if (stateObj.state === "active") {
|
||||
this._updateRemaining = window.setInterval(
|
||||
() => this.calculateTimerRemaining(this.state),
|
||||
1000
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private calculateTimerRemaining(stateObj) {
|
||||
this._timerTimeRemaining = timerTimeRemaining(stateObj);
|
||||
}
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
@ -61,175 +242,13 @@ class HaStateLabelBadge extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
);
|
||||
}
|
||||
</style>
|
||||
|
||||
<ha-label-badge
|
||||
class$="[[computeClassNames(state)]]"
|
||||
value="[[computeValue(localize, state)]]"
|
||||
icon="[[computeIcon(state)]]"
|
||||
image="[[computeImage(state)]]"
|
||||
label="[[computeLabel(localize, state, _timerTimeRemaining)]]"
|
||||
description="[[computeDescription(state)]]"
|
||||
></ha-label-badge>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
state: {
|
||||
type: Object,
|
||||
observer: "stateChanged",
|
||||
},
|
||||
_timerTimeRemaining: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.startInterval(this.state);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this.clearInterval();
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.addEventListener("click", (ev) => this.badgeTap(ev));
|
||||
}
|
||||
|
||||
badgeTap(ev) {
|
||||
ev.stopPropagation();
|
||||
this.fire("hass-more-info", { entityId: this.state.entity_id });
|
||||
}
|
||||
|
||||
computeClassNames(state) {
|
||||
const classes = [computeStateDomain(state)];
|
||||
classes.push(attributeClassNames(state, ["unit_of_measurement"]));
|
||||
return classes.join(" ");
|
||||
}
|
||||
|
||||
computeValue(localize, state) {
|
||||
const domain = computeStateDomain(state);
|
||||
switch (domain) {
|
||||
case "binary_sensor":
|
||||
case "device_tracker":
|
||||
case "updater":
|
||||
case "sun":
|
||||
case "alarm_control_panel":
|
||||
case "timer":
|
||||
return null;
|
||||
case "sensor":
|
||||
default:
|
||||
return state.state === "unknown"
|
||||
? "-"
|
||||
: localize(`component.${domain}.state.${state.state}`) || state.state;
|
||||
}
|
||||
}
|
||||
|
||||
computeIcon(state) {
|
||||
if (state.state === "unavailable") {
|
||||
return null;
|
||||
}
|
||||
const domain = computeStateDomain(state);
|
||||
switch (domain) {
|
||||
case "alarm_control_panel":
|
||||
if (state.state === "pending") {
|
||||
return "hass:clock-fast";
|
||||
}
|
||||
if (state.state === "armed_away") {
|
||||
return "hass:nature";
|
||||
}
|
||||
if (state.state === "armed_home") {
|
||||
return "hass:home-variant";
|
||||
}
|
||||
if (state.state === "armed_night") {
|
||||
return "hass:weather-night";
|
||||
}
|
||||
if (state.state === "armed_custom_bypass") {
|
||||
return "hass:security-home";
|
||||
}
|
||||
if (state.state === "triggered") {
|
||||
return "hass:alert-circle";
|
||||
}
|
||||
// state == 'disarmed'
|
||||
return domainIcon(domain, state.state);
|
||||
case "binary_sensor":
|
||||
case "device_tracker":
|
||||
case "updater":
|
||||
return stateIcon(state);
|
||||
case "sun":
|
||||
return state.state === "above_horizon"
|
||||
? domainIcon(domain)
|
||||
: "hass:brightness-3";
|
||||
case "timer":
|
||||
return state.state === "active" ? "hass:timer" : "hass:timer-off";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
computeImage(state) {
|
||||
return state.attributes.entity_picture || null;
|
||||
}
|
||||
|
||||
computeLabel(localize, state, _timerTimeRemaining) {
|
||||
const domain = computeStateDomain(state);
|
||||
if (
|
||||
state.state === "unavailable" ||
|
||||
["device_tracker", "alarm_control_panel"].includes(domain)
|
||||
) {
|
||||
// Localize the state with a special state_badge namespace, which has variations of
|
||||
// the state translations that are truncated to fit within the badge label. Translations
|
||||
// are only added for device_tracker and alarm_control_panel.
|
||||
return (
|
||||
localize(`state_badge.${domain}.${state.state}`) ||
|
||||
localize(`state_badge.default.${state.state}`) ||
|
||||
state.state
|
||||
);
|
||||
}
|
||||
if (domain === "timer") {
|
||||
return secondsToDuration(_timerTimeRemaining);
|
||||
}
|
||||
return state.attributes.unit_of_measurement || null;
|
||||
}
|
||||
|
||||
computeDescription(state) {
|
||||
return computeStateName(state);
|
||||
}
|
||||
|
||||
stateChanged(stateObj) {
|
||||
this.updateStyles();
|
||||
this.startInterval(stateObj);
|
||||
}
|
||||
|
||||
clearInterval() {
|
||||
if (this._updateRemaining) {
|
||||
clearInterval(this._updateRemaining);
|
||||
this._updateRemaining = null;
|
||||
}
|
||||
}
|
||||
|
||||
startInterval(stateObj) {
|
||||
this.clearInterval();
|
||||
if (computeStateDomain(stateObj) === "timer") {
|
||||
this.calculateTimerRemaining(stateObj);
|
||||
|
||||
if (stateObj.state === "active") {
|
||||
this._updateRemaining = setInterval(
|
||||
() => this.calculateTimerRemaining(this.state),
|
||||
1000
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
calculateTimerRemaining(stateObj) {
|
||||
this._timerTimeRemaining = timerTimeRemaining(stateObj);
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-state-label-badge": HaStateLabelBadge;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import IntlMessageFormat from "intl-messageformat/src/main";
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
/**
|
||||
* Adapted from Polymer app-localize-behavior.
|
||||
@ -32,6 +33,7 @@ export interface FormatsType {
|
||||
export type LocalizeFunc = (key: string, ...args: any[]) => string;
|
||||
|
||||
export interface LocalizeMixin {
|
||||
hass?: HomeAssistant;
|
||||
localize: LocalizeFunc;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ declare global {
|
||||
|
||||
export class HuiThemeSelectionEditor extends hassLocalizeLitMixin(LitElement) {
|
||||
public value?: string;
|
||||
protected hass?: HomeAssistant;
|
||||
public hass?: HomeAssistant;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
|
@ -14,7 +14,7 @@ import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { SaveDialogParams } from "./show-save-config-dialog";
|
||||
|
||||
export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) {
|
||||
protected hass?: HomeAssistant;
|
||||
public hass?: HomeAssistant;
|
||||
private _params?: SaveDialogParams;
|
||||
private _saving: boolean;
|
||||
|
||||
|
@ -30,7 +30,7 @@ import { deleteView, addView, replaceView } from "../config-util";
|
||||
export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
public lovelace?: Lovelace;
|
||||
public viewIndex?: number;
|
||||
protected hass?: HomeAssistant;
|
||||
public hass?: HomeAssistant;
|
||||
private _config?: LovelaceViewConfig;
|
||||
private _badges?: EntityConfig[];
|
||||
private _cards?: LovelaceCardConfig[];
|
||||
|
@ -5,9 +5,11 @@ import {
|
||||
PropertyDeclarations,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { PolymerElement } from "@polymer/polymer";
|
||||
|
||||
import "../../components/entity/ha-state-label-badge";
|
||||
// This one is for types
|
||||
// tslint:disable-next-line
|
||||
import { HaStateLabelBadge } from "../../components/entity/ha-state-label-badge";
|
||||
|
||||
import applyThemesOnElement from "../../common/dom/apply_themes_on_element";
|
||||
|
||||
@ -28,7 +30,7 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) {
|
||||
public columns?: number;
|
||||
public index?: number;
|
||||
private _cards: LovelaceCard[];
|
||||
private _badges: Array<{ element: PolymerElement; entityId: string }>;
|
||||
private _badges: Array<{ element: HaStateLabelBadge; entityId: string }>;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
@ -158,10 +160,8 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) {
|
||||
} else if (changedProperties.has("hass")) {
|
||||
this._badges.forEach((badge) => {
|
||||
const { element, entityId } = badge;
|
||||
element.setProperties({
|
||||
hass: this.hass,
|
||||
state: this.hass!.states[entityId],
|
||||
});
|
||||
element.hass = this.hass!;
|
||||
element.state = this.hass!.states[entityId];
|
||||
});
|
||||
}
|
||||
|
||||
@ -196,17 +196,9 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) {
|
||||
|
||||
const elements: HUIView["_badges"] = [];
|
||||
for (const entityId of config.badges) {
|
||||
if (!(entityId in this.hass!.states)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const element = document.createElement(
|
||||
"ha-state-label-badge"
|
||||
) as PolymerElement;
|
||||
element.setProperties({
|
||||
hass: this.hass,
|
||||
state: this.hass!.states[entityId],
|
||||
});
|
||||
const element = document.createElement("ha-state-label-badge");
|
||||
element.hass = this.hass;
|
||||
element.state = this.hass!.states[entityId];
|
||||
elements.push({ element, entityId });
|
||||
root.appendChild(element);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user