mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-26 02:36:37 +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 {
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
LitElement,
|
||||||
|
html,
|
||||||
import "../ha-label-badge";
|
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 computeStateDomain from "../../common/entity/compute_state_domain";
|
||||||
import computeStateName from "../../common/entity/compute_state_name";
|
import computeStateName from "../../common/entity/compute_state_name";
|
||||||
import domainIcon from "../../common/entity/domain_icon";
|
import domainIcon from "../../common/entity/domain_icon";
|
||||||
import stateIcon from "../../common/entity/state_icon";
|
import stateIcon from "../../common/entity/state_icon";
|
||||||
import timerTimeRemaining from "../../common/entity/timer_time_remaining";
|
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 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 "../ha-label-badge";
|
||||||
import LocalizeMixin from "../../mixins/localize-mixin";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @appliesMixin LocalizeMixin
|
* @appliesMixin LocalizeMixin
|
||||||
* @appliesMixin EventsMixin
|
* @appliesMixin EventsMixin
|
||||||
*/
|
*/
|
||||||
class HaStateLabelBadge extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) {
|
||||||
static get template() {
|
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`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
:host {
|
:host {
|
||||||
@ -61,175 +242,13 @@ class HaStateLabelBadge extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
</style>
|
</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() {
|
declare global {
|
||||||
return {
|
interface HTMLElementTagNameMap {
|
||||||
hass: Object,
|
"ha-state-label-badge": HaStateLabelBadge;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
import IntlMessageFormat from "intl-messageformat/src/main";
|
import IntlMessageFormat from "intl-messageformat/src/main";
|
||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapted from Polymer app-localize-behavior.
|
* Adapted from Polymer app-localize-behavior.
|
||||||
@ -32,6 +33,7 @@ export interface FormatsType {
|
|||||||
export type LocalizeFunc = (key: string, ...args: any[]) => string;
|
export type LocalizeFunc = (key: string, ...args: any[]) => string;
|
||||||
|
|
||||||
export interface LocalizeMixin {
|
export interface LocalizeMixin {
|
||||||
|
hass?: HomeAssistant;
|
||||||
localize: LocalizeFunc;
|
localize: LocalizeFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ declare global {
|
|||||||
|
|
||||||
export class HuiThemeSelectionEditor extends hassLocalizeLitMixin(LitElement) {
|
export class HuiThemeSelectionEditor extends hassLocalizeLitMixin(LitElement) {
|
||||||
public value?: string;
|
public value?: string;
|
||||||
protected hass?: HomeAssistant;
|
public hass?: HomeAssistant;
|
||||||
|
|
||||||
static get properties(): PropertyDeclarations {
|
static get properties(): PropertyDeclarations {
|
||||||
return {
|
return {
|
||||||
|
@ -14,7 +14,7 @@ import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
|||||||
import { SaveDialogParams } from "./show-save-config-dialog";
|
import { SaveDialogParams } from "./show-save-config-dialog";
|
||||||
|
|
||||||
export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) {
|
export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) {
|
||||||
protected hass?: HomeAssistant;
|
public hass?: HomeAssistant;
|
||||||
private _params?: SaveDialogParams;
|
private _params?: SaveDialogParams;
|
||||||
private _saving: boolean;
|
private _saving: boolean;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ import { deleteView, addView, replaceView } from "../config-util";
|
|||||||
export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||||
public lovelace?: Lovelace;
|
public lovelace?: Lovelace;
|
||||||
public viewIndex?: number;
|
public viewIndex?: number;
|
||||||
protected hass?: HomeAssistant;
|
public hass?: HomeAssistant;
|
||||||
private _config?: LovelaceViewConfig;
|
private _config?: LovelaceViewConfig;
|
||||||
private _badges?: EntityConfig[];
|
private _badges?: EntityConfig[];
|
||||||
private _cards?: LovelaceCardConfig[];
|
private _cards?: LovelaceCardConfig[];
|
||||||
|
@ -5,9 +5,11 @@ import {
|
|||||||
PropertyDeclarations,
|
PropertyDeclarations,
|
||||||
} from "@polymer/lit-element";
|
} from "@polymer/lit-element";
|
||||||
import { TemplateResult } from "lit-html";
|
import { TemplateResult } from "lit-html";
|
||||||
import { PolymerElement } from "@polymer/polymer";
|
|
||||||
|
|
||||||
import "../../components/entity/ha-state-label-badge";
|
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";
|
import applyThemesOnElement from "../../common/dom/apply_themes_on_element";
|
||||||
|
|
||||||
@ -28,7 +30,7 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) {
|
|||||||
public columns?: number;
|
public columns?: number;
|
||||||
public index?: number;
|
public index?: number;
|
||||||
private _cards: LovelaceCard[];
|
private _cards: LovelaceCard[];
|
||||||
private _badges: Array<{ element: PolymerElement; entityId: string }>;
|
private _badges: Array<{ element: HaStateLabelBadge; entityId: string }>;
|
||||||
|
|
||||||
static get properties(): PropertyDeclarations {
|
static get properties(): PropertyDeclarations {
|
||||||
return {
|
return {
|
||||||
@ -158,10 +160,8 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) {
|
|||||||
} else if (changedProperties.has("hass")) {
|
} else if (changedProperties.has("hass")) {
|
||||||
this._badges.forEach((badge) => {
|
this._badges.forEach((badge) => {
|
||||||
const { element, entityId } = badge;
|
const { element, entityId } = badge;
|
||||||
element.setProperties({
|
element.hass = this.hass!;
|
||||||
hass: this.hass,
|
element.state = this.hass!.states[entityId];
|
||||||
state: this.hass!.states[entityId],
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,17 +196,9 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) {
|
|||||||
|
|
||||||
const elements: HUIView["_badges"] = [];
|
const elements: HUIView["_badges"] = [];
|
||||||
for (const entityId of config.badges) {
|
for (const entityId of config.badges) {
|
||||||
if (!(entityId in this.hass!.states)) {
|
const element = document.createElement("ha-state-label-badge");
|
||||||
continue;
|
element.hass = this.hass;
|
||||||
}
|
element.state = this.hass!.states[entityId];
|
||||||
|
|
||||||
const element = document.createElement(
|
|
||||||
"ha-state-label-badge"
|
|
||||||
) as PolymerElement;
|
|
||||||
element.setProperties({
|
|
||||||
hass: this.hass,
|
|
||||||
state: this.hass!.states[entityId],
|
|
||||||
});
|
|
||||||
elements.push({ element, entityId });
|
elements.push({ element, entityId });
|
||||||
root.appendChild(element);
|
root.appendChild(element);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user