mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 17:26:42 +00:00
Merge pull request #10506 from home-assistant/dev
This commit is contained in:
commit
6cf3580fb4
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20211028.0",
|
version="20211103.0",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/frontend",
|
url="https://github.com/home-assistant/frontend",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@ -4,7 +4,7 @@ import { FrontendLocaleData } from "../../data/translation";
|
|||||||
import { formatDate } from "../datetime/format_date";
|
import { formatDate } from "../datetime/format_date";
|
||||||
import { formatDateTime } from "../datetime/format_date_time";
|
import { formatDateTime } from "../datetime/format_date_time";
|
||||||
import { formatTime } from "../datetime/format_time";
|
import { formatTime } from "../datetime/format_time";
|
||||||
import { formatNumber } from "../number/format_number";
|
import { formatNumber, isNumericState } from "../number/format_number";
|
||||||
import { LocalizeFunc } from "../translations/localize";
|
import { LocalizeFunc } from "../translations/localize";
|
||||||
import { computeStateDomain } from "./compute_state_domain";
|
import { computeStateDomain } from "./compute_state_domain";
|
||||||
|
|
||||||
@ -20,7 +20,8 @@ export const computeStateDisplay = (
|
|||||||
return localize(`state.default.${compareState}`);
|
return localize(`state.default.${compareState}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stateObj.attributes.unit_of_measurement) {
|
// Entities with a `unit_of_measurement` or `state_class` are numeric values and should use `formatNumber`
|
||||||
|
if (isNumericState(stateObj)) {
|
||||||
if (stateObj.attributes.device_class === "monetary") {
|
if (stateObj.attributes.device_class === "monetary") {
|
||||||
try {
|
try {
|
||||||
return formatNumber(compareState, locale, {
|
return formatNumber(compareState, locale, {
|
||||||
@ -31,8 +32,10 @@ export const computeStateDisplay = (
|
|||||||
// fallback to default
|
// fallback to default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return `${formatNumber(compareState, locale)} ${
|
return `${formatNumber(compareState, locale)}${
|
||||||
stateObj.attributes.unit_of_measurement
|
stateObj.attributes.unit_of_measurement
|
||||||
|
? " " + stateObj.attributes.unit_of_measurement
|
||||||
|
: ""
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { FrontendLocaleData, NumberFormat } from "../../data/translation";
|
import { FrontendLocaleData, NumberFormat } from "../../data/translation";
|
||||||
import { round } from "./round";
|
import { round } from "./round";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the entity is considered numeric based on the attributes it has
|
||||||
|
* @param stateObj The entity state object
|
||||||
|
*/
|
||||||
|
export const isNumericState = (stateObj: HassEntity): boolean =>
|
||||||
|
!!stateObj.attributes.unit_of_measurement ||
|
||||||
|
!!stateObj.attributes.state_class;
|
||||||
|
|
||||||
export const numberFormatToLocale = (
|
export const numberFormatToLocale = (
|
||||||
localeOptions: FrontendLocaleData
|
localeOptions: FrontendLocaleData
|
||||||
): string | string[] | undefined => {
|
): string | string[] | undefined => {
|
||||||
|
@ -14,7 +14,10 @@ import secondsToDuration from "../../common/datetime/seconds_to_duration";
|
|||||||
import { computeStateDisplay } from "../../common/entity/compute_state_display";
|
import { computeStateDisplay } from "../../common/entity/compute_state_display";
|
||||||
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 { formatNumber } from "../../common/number/format_number";
|
import {
|
||||||
|
formatNumber,
|
||||||
|
isNumericState,
|
||||||
|
} from "../../common/number/format_number";
|
||||||
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
||||||
import { timerTimeRemaining } from "../../data/timer";
|
import { timerTimeRemaining } from "../../data/timer";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
@ -145,7 +148,7 @@ export class HaStateLabelBadge extends LitElement {
|
|||||||
return entityState.state === UNKNOWN ||
|
return entityState.state === UNKNOWN ||
|
||||||
entityState.state === UNAVAILABLE
|
entityState.state === UNAVAILABLE
|
||||||
? "-"
|
? "-"
|
||||||
: entityState.attributes.unit_of_measurement
|
: isNumericState(entityState)
|
||||||
? formatNumber(entityState.state, this.hass!.locale)
|
? formatNumber(entityState.state, this.hass!.locale)
|
||||||
: computeStateDisplay(
|
: computeStateDisplay(
|
||||||
this.hass!.localize,
|
this.hass!.localize,
|
||||||
|
@ -38,6 +38,7 @@ export class HaDialog extends Dialog {
|
|||||||
.mdc-dialog {
|
.mdc-dialog {
|
||||||
--mdc-dialog-scroll-divider-color: var(--divider-color);
|
--mdc-dialog-scroll-divider-color: var(--divider-color);
|
||||||
z-index: var(--dialog-z-index, 7);
|
z-index: var(--dialog-z-index, 7);
|
||||||
|
-webkit-backdrop-filter: var(--dialog-backdrop-filter, none);
|
||||||
backdrop-filter: var(--dialog-backdrop-filter, none);
|
backdrop-filter: var(--dialog-backdrop-filter, none);
|
||||||
}
|
}
|
||||||
.mdc-dialog__actions {
|
.mdc-dialog__actions {
|
||||||
|
@ -10,7 +10,8 @@ import { property, state } from "lit/decorators";
|
|||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||||
import "../../../components/ha-camera-stream";
|
import "../../../components/ha-camera-stream";
|
||||||
import { HaCheckbox } from "../../../components/ha-checkbox";
|
import type { HaCheckbox } from "../../../components/ha-checkbox";
|
||||||
|
import "../../../components/ha-checkbox";
|
||||||
import {
|
import {
|
||||||
CameraEntity,
|
CameraEntity,
|
||||||
CameraPreferences,
|
CameraPreferences,
|
||||||
|
@ -209,6 +209,7 @@ class MoreInfoLight extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<hr />
|
<hr />
|
||||||
<ha-paper-dropdown-menu
|
<ha-paper-dropdown-menu
|
||||||
|
dynamic-align
|
||||||
.label=${this.hass.localize("ui.card.light.effect")}
|
.label=${this.hass.localize("ui.card.light.effect")}
|
||||||
>
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
|
@ -152,7 +152,14 @@ export class HaDeviceEntitiesCard extends LitElement {
|
|||||||
.path=${domainIcon(computeDomain(entry.entity_id))}
|
.path=${domainIcon(computeDomain(entry.entity_id))}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
<paper-item-body>
|
<paper-item-body>
|
||||||
<div class="name">${entry.stateName || entry.entity_id}</div>
|
<div class="name">
|
||||||
|
${entry.stateName
|
||||||
|
? stripPrefixFromEntityName(
|
||||||
|
entry.stateName,
|
||||||
|
`${this.deviceName} `.toLowerCase()
|
||||||
|
)
|
||||||
|
: entry.entity_id}
|
||||||
|
</div>
|
||||||
</paper-item-body>
|
</paper-item-body>
|
||||||
</paper-icon-item>
|
</paper-icon-item>
|
||||||
`;
|
`;
|
||||||
|
@ -121,7 +121,13 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
const result = groupBy(entities, (entry) =>
|
const result = groupBy(entities, (entry) =>
|
||||||
entry.entity_category
|
entry.entity_category
|
||||||
? entry.entity_category
|
? entry.entity_category
|
||||||
: ["sensor", "binary_sensor"].includes(computeDomain(entry.entity_id))
|
: [
|
||||||
|
"sensor",
|
||||||
|
"binary_sensor",
|
||||||
|
"camera",
|
||||||
|
"device_tracker",
|
||||||
|
"weather",
|
||||||
|
].includes(computeDomain(entry.entity_id))
|
||||||
? "sensor"
|
? "sensor"
|
||||||
: "control"
|
: "control"
|
||||||
) as Record<
|
) as Record<
|
||||||
|
@ -15,7 +15,10 @@ import { computeStateDisplay } from "../../../common/entity/compute_state_displa
|
|||||||
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 { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
||||||
import { formatNumber } from "../../../common/number/format_number";
|
import {
|
||||||
|
formatNumber,
|
||||||
|
isNumericState,
|
||||||
|
} from "../../../common/number/format_number";
|
||||||
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-icon";
|
import "../../../components/ha-icon";
|
||||||
@ -143,7 +146,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
|||||||
stateObj.attributes[this._config.attribute!]
|
stateObj.attributes[this._config.attribute!]
|
||||||
)
|
)
|
||||||
: this.hass.localize("state.default.unknown")
|
: this.hass.localize("state.default.unknown")
|
||||||
: stateObj.attributes.unit_of_measurement
|
: isNumericState(stateObj)
|
||||||
? formatNumber(stateObj.state, this.hass.locale)
|
? formatNumber(stateObj.state, this.hass.locale)
|
||||||
: computeStateDisplay(
|
: computeStateDisplay(
|
||||||
this.hass.localize,
|
this.hass.localize,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
mdiEmoticonPoop,
|
mdiSprout,
|
||||||
mdiThermometer,
|
mdiThermometer,
|
||||||
mdiWater,
|
mdiWaterPercent,
|
||||||
mdiWhiteBalanceSunny,
|
mdiWhiteBalanceSunny,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
@ -29,10 +29,10 @@ import { LovelaceCard, LovelaceCardEditor } from "../types";
|
|||||||
import { PlantAttributeTarget, PlantStatusCardConfig } from "./types";
|
import { PlantAttributeTarget, PlantStatusCardConfig } from "./types";
|
||||||
|
|
||||||
const SENSOR_ICONS = {
|
const SENSOR_ICONS = {
|
||||||
moisture: mdiWater,
|
moisture: mdiWaterPercent,
|
||||||
temperature: mdiThermometer,
|
temperature: mdiThermometer,
|
||||||
brightness: mdiWhiteBalanceSunny,
|
brightness: mdiWhiteBalanceSunny,
|
||||||
conductivity: mdiEmoticonPoop,
|
conductivity: mdiSprout,
|
||||||
battery: undefined,
|
battery: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,6 +96,20 @@ describe("computeStateDisplay", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Localizes and formats numeric sensor value with state_class", () => {
|
||||||
|
const stateObj: any = {
|
||||||
|
entity_id: "sensor.test",
|
||||||
|
state: "1234.5",
|
||||||
|
attributes: {
|
||||||
|
state_class: "measurement",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert.strictEqual(
|
||||||
|
computeStateDisplay(localize, stateObj, localeData),
|
||||||
|
"1,234.5 m"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("Localizes unknown sensor value with units", () => {
|
it("Localizes unknown sensor value with units", () => {
|
||||||
const altLocalize = (message, ...args) => {
|
const altLocalize = (message, ...args) => {
|
||||||
if (message === "state.sensor.unknown") {
|
if (message === "state.sensor.unknown") {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user