Compare commits

..

3 Commits

Author SHA1 Message Date
Wendelin 50a47d7092 Review 2026-05-19 14:31:35 +02:00
Wendelin be4d0fd830 Update src/components/automation/ha-automation-row-live-test.ts
Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2026-05-19 14:29:41 +02:00
Wendelin 2dd71a5d37 Remove live condition test hover 2026-05-19 13:23:30 +02:00
93 changed files with 485 additions and 1026 deletions
+1
View File
@@ -1,2 +1,3 @@
[build.environment]
YARN_VERSION = "1.22.11"
NODE_OPTIONS = "--max_old_space_size=6144"
+3 -3
View File
@@ -74,8 +74,8 @@
"@replit/codemirror-indentation-markers": "6.5.3",
"@swc/helpers": "0.5.21",
"@thomasloven/round-slider": "0.6.0",
"@tsparticles/engine": "4.0.2",
"@tsparticles/preset-links": "4.0.2",
"@tsparticles/engine": "4.0.1",
"@tsparticles/preset-links": "4.0.1",
"@vibrant/color": "4.0.4",
"@webcomponents/scoped-custom-element-registry": "0.0.10",
"@webcomponents/webcomponentsjs": "2.8.0",
@@ -187,7 +187,7 @@
"jsdom": "29.1.1",
"jszip": "3.10.1",
"license-checker-rseidelsohn": "4.4.2",
"lint-staged": "17.0.5",
"lint-staged": "17.0.4",
"lit-analyzer": "2.0.3",
"lodash.merge": "4.6.2",
"lodash.template": "4.18.1",
-39
View File
@@ -18,46 +18,7 @@
"enabled": true,
"schedule": ["on the 19th day of the month before 4am"]
},
"customDatasources": {
"ha-core-python": {
"defaultRegistryUrlTemplate": "https://raw.githubusercontent.com/home-assistant/core/dev/.python-version",
"format": "plain"
}
},
"customManagers": [
{
"description": "Keep PYTHON_VERSION in sync with home-assistant/core (patch + minor)",
"customType": "regex",
"managerFilePatterns": ["/^\\.github/workflows/[^/]+\\.ya?ml$/"],
"matchStrings": ["PYTHON_VERSION: \"(?<currentValue>[^\"]+)\""],
"depNameTemplate": "python",
"datasourceTemplate": "custom.ha-core-python",
"versioningTemplate": "python"
},
{
"description": "Keep devcontainer image and requires-python in sync with home-assistant/core (minor only)",
"customType": "regex",
"managerFilePatterns": [
"/^\\.devcontainer/Dockerfile$/",
"/^pyproject\\.toml$/"
],
"matchStrings": [
"devcontainers/python:(?<currentValue>[\\d.]+)",
"requires-python = \">=(?<currentValue>[^\"]+)\""
],
"depNameTemplate": "python",
"datasourceTemplate": "custom.ha-core-python",
"versioningTemplate": "python",
"extractVersionTemplate": "^(?<version>\\d+\\.\\d+)"
}
],
"packageRules": [
{
"description": "Group all Python version updates from home-assistant/core",
"matchDepNames": ["python"],
"matchDatasources": ["custom.ha-core-python"],
"groupName": "Python version"
},
{
"description": "MDC packages are pinned to the same version as MWC",
"extends": ["monorepo:material-components-web"],
+1 -1
View File
@@ -3,7 +3,7 @@
* @param arr - The array to get combinations of
* @returns A multidimensional array of all possible combinations
*/
export function getAllCombinations<T>(arr: readonly T[]): T[][] {
export function getAllCombinations<T>(arr: T[]) {
return arr.reduce<T[][]>(
(combinations, element) =>
combinations.concat(
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import { isUnavailableState } from "../../data/entity/entity";
import type { HomeAssistant } from "../../types";
interface EntityUnitStubConfig {
@@ -21,24 +21,32 @@ export const computeEntityUnitDisplay = (
stateObj: HassEntity | undefined,
config: EntityUnitStubConfig
): string => {
let unit;
if (
!stateObj ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN ||
(!config.attribute && stateObj.attributes.device_class === "duration")
stateObj &&
!isUnavailableState(stateObj.state) &&
(config.attribute || stateObj.attributes.device_class !== "duration")
) {
return "";
// check for an explicitly defined unit in config
unit = config.unit;
if (!unit) {
if (!config.attribute) {
// use entity's unit_of_measurement
const stateParts = hass.formatEntityStateToParts(stateObj);
unit = stateParts.find((part) => part.type === "unit")?.value;
} else {
// use attribute's unit if available
const attrParts = hass.formatEntityAttributeValueToParts(
stateObj,
config.attribute
);
unit = attrParts.find((part) => part.type === "unit")?.value;
}
}
return unit ?? "";
}
// check for an explicitly defined unit in config
if (config.unit) {
return config.unit;
}
// otherwise derive from the entity's state or attribute
const parts = config.attribute
? hass.formatEntityAttributeValueToParts(stateObj, config.attribute)
: hass.formatEntityStateToParts(stateObj);
return parts.find((part) => part.type === "unit")?.value ?? "";
return "";
};
+2 -2
View File
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import { UNAVAILABLE_STATES } from "../../data/entity/entity";
import type { HomeAssistant } from "../../types";
import { stringCompare } from "../string/compare";
import { computeDomain } from "./compute_domain";
@@ -253,7 +253,7 @@ export const getStatesDomain = (
if (!attribute) {
// All entities can have unavailable states
result.push(UNAVAILABLE, UNKNOWN);
result.push(...UNAVAILABLE_STATES);
}
if (!attribute && domain in FIXED_DOMAIN_STATES) {
+5 -11
View File
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../data/entity/entity";
import type { HomeAssistant } from "../../types";
import { computeStateDomain } from "./compute_state_domain";
@@ -8,18 +8,12 @@ export const computeGroupEntitiesState = (states: HassEntity[]): string => {
return UNAVAILABLE;
}
const allUnavailable = states.every(
(stateObj) => stateObj.state === UNAVAILABLE
const validState = states.some(
(stateObj) => !isUnavailableState(stateObj.state)
);
if (allUnavailable) {
return UNAVAILABLE;
}
const hasValidState = states.some(
(stateObj) => stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN
);
if (!hasValidState) {
return UNKNOWN;
if (!validState) {
return UNAVAILABLE;
}
// Use the first state to determine the domain
+2 -2
View File
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { OFF, UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import { isUnavailableState, OFF, UNAVAILABLE } from "../../data/entity/entity";
import { computeDomain } from "./compute_domain";
export function stateActive(stateObj: HassEntity, state?: string): boolean {
@@ -19,7 +19,7 @@ export function stateActive(stateObj: HassEntity, state?: string): boolean {
return compareState !== UNAVAILABLE;
}
if (compareState === UNAVAILABLE || compareState === UNKNOWN) {
if (isUnavailableState(compareState)) {
return false;
}
@@ -1,6 +1,5 @@
import { LitElement, css, html, nothing } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, property } from "lit/decorators";
import "../ha-tooltip";
export type LiveTestState = "pass" | "fail" | "invalid" | "unknown";
@@ -9,11 +8,10 @@ export type LiveTestState = "pass" | "fail" | "invalid" | "unknown";
*
* @summary
* Small status indicator dot used in automation/condition rows to surface the
* live evaluation result. Renders an optional tooltip with details on hover.
* live evaluation result.
*
* @attr {"pass"|"fail"|"invalid"|"unknown"} state - The current live-test state. Defaults to `unknown`.
* @attr {string} label - Accessible label announced by assistive technology.
* @attr {string} message - Optional tooltip body shown on hover/focus.
*/
@customElement("ha-automation-row-live-test")
export class HaAutomationRowLiveTest extends LitElement {
@@ -21,8 +19,6 @@ export class HaAutomationRowLiveTest extends LitElement {
@property() public label = "";
@property() public message?: string;
protected render() {
return html`
<div
@@ -31,9 +27,6 @@ export class HaAutomationRowLiveTest extends LitElement {
tabindex="0"
aria-label=${this.label}
></div>
${this.message
? html`<ha-tooltip for="indicator">${this.message}</ha-tooltip>`
: nothing}
`;
}
@@ -56,31 +49,15 @@ export class HaAutomationRowLiveTest extends LitElement {
background-color: var(--ha-color-fill-success-loud-resting);
border-color: var(--ha-color-fill-success-loud-resting);
}
:host([state="pass"]) #indicator:hover {
background-color: var(--ha-color-fill-success-loud-hover);
border-color: var(--ha-color-fill-success-loud-hover);
}
:host([state="fail"]) #indicator {
border-color: var(--ha-color-fill-warning-loud-resting);
}
:host([state="fail"]) #indicator:hover {
background-color: var(--ha-color-fill-warning-loud-hover);
border-color: var(--ha-color-fill-warning-loud-hover);
}
:host([state="invalid"]) #indicator {
border-color: var(--ha-color-fill-danger-loud-resting);
}
:host([state="invalid"]) #indicator:hover {
background-color: var(--ha-color-fill-danger-loud-hover);
border-color: var(--ha-color-fill-danger-loud-hover);
}
:host([state="unknown"]) #indicator {
border-color: var(--ha-color-fill-neutral-loud-resting);
}
:host([state="unknown"]) #indicator:hover {
background-color: var(--ha-color-fill-neutral-loud-hover);
border-color: var(--ha-color-fill-neutral-loud-hover);
}
`;
}
+6 -3
View File
@@ -6,7 +6,11 @@ import { customElement, property, state } from "lit/decorators";
import { STATES_OFF } from "../../common/const";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { computeStateName } from "../../common/entity/compute_state_name";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import {
UNAVAILABLE,
UNKNOWN,
isUnavailableState,
} from "../../data/entity/entity";
import { forwardHaptic } from "../../data/haptics";
import type { HomeAssistant } from "../../types";
import "../ha-formfield";
@@ -16,8 +20,7 @@ import "../ha-switch";
const isOn = (stateObj?: HassEntity) =>
stateObj !== undefined &&
!STATES_OFF.includes(stateObj.state) &&
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN;
!isUnavailableState(stateObj.state);
/**
* @element ha-entity-toggle
@@ -9,7 +9,7 @@ import secondsToDuration from "../../common/datetime/seconds_to_duration";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { computeStateName } from "../../common/entity/compute_state_name";
import { FIXED_DOMAIN_STATES } from "../../common/entity/get_states";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../data/entity/entity";
import type { EntityRegistryDisplayEntry } from "../../data/entity/entity_registry";
import { timerTimeRemaining } from "../../data/timer";
import type { HomeAssistant } from "../../types";
@@ -170,8 +170,7 @@ export class HaStateLabelBadge extends LitElement {
}
// eslint-disable-next-line: disable=no-fallthrough
default:
return entityState.state === UNAVAILABLE ||
entityState.state === UNKNOWN
return isUnavailableState(entityState.state)
? "—"
: this.hass!.formatEntityStateToParts(entityState).find(
(part) => part.type === "value"
@@ -210,7 +209,7 @@ export class HaStateLabelBadge extends LitElement {
_timerTimeRemaining = 0
) {
// For unavailable states or certain domains, use a special translation that is truncated to fit within the badge label
if (entityState.state === UNAVAILABLE || entityState.state === UNKNOWN) {
if (isUnavailableState(entityState.state)) {
return this.hass!.localize(`state_badge.default.${entityState.state}`);
}
const domainStateKey = getTruncatedKey(domain, entityState.state);
+3 -3
View File
@@ -29,7 +29,7 @@ export interface AreaControlPickerItem extends PickerComboBoxItem {
deviceClass?: string;
}
const AREA_CONTROL_DOMAINS = [
const AREA_CONTROL_DOMAINS: readonly AreaControlDomain[] = [
"light",
"fan",
"switch",
@@ -43,7 +43,7 @@ const AREA_CONTROL_DOMAINS = [
"cover-door",
"cover-window",
"cover-damper",
] as const satisfies readonly AreaControlDomain[];
] as const;
@customElement("ha-area-controls-picker")
export class HaAreaControlsPicker extends LitElement {
@@ -130,7 +130,7 @@ export class HaAreaControlsPicker extends LitElement {
(excludeValues !== undefined && excludeValues.includes(id));
const controlEntities = getAreaControlEntities(
AREA_CONTROL_DOMAINS,
AREA_CONTROL_DOMAINS as unknown as AreaControlDomain[],
areaId,
excludeEntities,
this.hass
+4 -9
View File
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import type { ClimateEntity } from "../data/climate";
import { CLIMATE_PRESET_NONE } from "../data/climate";
import { OFF, UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import { isUnavailableState, OFF } from "../data/entity/entity";
import type { HomeAssistant } from "../types";
@customElement("ha-climate-state")
@@ -14,11 +14,9 @@ class HaClimateState extends LitElement {
protected render(): TemplateResult {
const currentStatus = this._computeCurrentStatus();
const noValue =
this.stateObj.state === UNAVAILABLE || this.stateObj.state === UNKNOWN;
return html`<div class="target">
${!noValue
${!isUnavailableState(this.stateObj.state)
? html`<span class="state-label">
${this._localizeState()}
${this.stateObj.attributes.preset_mode &&
@@ -34,7 +32,7 @@ class HaClimateState extends LitElement {
: this._localizeState()}
</div>
${currentStatus && !noValue
${currentStatus && !isUnavailableState(this.stateObj.state)
? html`
<div class="current">
${this.hass.localize("ui.card.climate.currently")}:
@@ -121,10 +119,7 @@ class HaClimateState extends LitElement {
}
private _localizeState(): string {
if (
this.stateObj.state === UNAVAILABLE ||
this.stateObj.state === UNKNOWN
) {
if (isUnavailableState(this.stateObj.state)) {
return this.hass.localize(`state.default.${this.stateObj.state}`);
}
+4 -9
View File
@@ -1,7 +1,7 @@
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { OFF, UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import { isUnavailableState, OFF } from "../data/entity/entity";
import type { HumidifierEntity } from "../data/humidifier";
import type { HomeAssistant } from "../types";
@@ -13,11 +13,9 @@ class HaHumidifierState extends LitElement {
protected render(): TemplateResult {
const currentStatus = this._computeCurrentStatus();
const noValue =
this.stateObj.state === UNAVAILABLE || this.stateObj.state === UNKNOWN;
return html`<div class="target">
${!noValue
${!isUnavailableState(this.stateObj.state)
? html`<span class="state-label">
${this._localizeState()}
${this.stateObj.attributes.mode
@@ -32,7 +30,7 @@ class HaHumidifierState extends LitElement {
: this._localizeState()}
</div>
${currentStatus && !noValue
${currentStatus && !isUnavailableState(this.stateObj.state)
? html`<div class="current">
${this.hass.localize("ui.card.humidifier.currently")}:
<div class="unit">${currentStatus}</div>
@@ -71,10 +69,7 @@ class HaHumidifierState extends LitElement {
}
private _localizeState(): string {
if (
this.stateObj.state === UNAVAILABLE ||
this.stateObj.state === UNKNOWN
) {
if (isUnavailableState(this.stateObj.state)) {
return this.hass.localize(`state.default.${this.stateObj.state}`);
}
@@ -2,7 +2,7 @@ import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import memoizeOne from "memoize-one";
import { fireEvent, type HASSDomEvent } from "../../common/dom/fire_event";
import { fireEvent } from "../../common/dom/fire_event";
import type { ColorTempSelector } from "../../data/selector";
import type { HomeAssistant } from "../../types";
import "../ha-labeled-slider";
@@ -94,10 +94,10 @@ export class HaColorTempSelector extends LitElement {
}
);
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
private _valueChanged(ev: CustomEvent) {
ev.stopPropagation();
fireEvent(this, "value-changed", {
value: Number(ev.detail.value),
value: Number((ev.detail as any).value),
});
}
}
@@ -17,7 +17,7 @@ import { until } from "lit/directives/until";
import { fireEvent } from "../../common/dom/fire_event";
import { slugify } from "../../common/string/slugify";
import { debounce } from "../../common/util/debounce";
import { UNAVAILABLE } from "../../data/entity/entity";
import { isUnavailableState } from "../../data/entity/entity";
import type {
MediaPickedEvent,
MediaPlayerBrowseAction,
@@ -290,7 +290,7 @@ export class HaMediaPlayerBrowse extends LitElement {
} else if (
err.code === "entity_not_found" &&
this.entityId &&
this.hass.states[this.entityId]?.state === UNAVAILABLE
isUnavailableState(this.hass.states[this.entityId]?.state)
) {
this._setError({
message: this.hass.localize(
+1 -1
View File
@@ -62,7 +62,7 @@ export const AREA_CONTROLS_BUTTONS: Record<
};
export const getAreaControlEntities = (
controls: readonly AreaControlDomain[],
controls: AreaControlDomain[],
areaId: string,
excludeEntities: string[] | undefined,
hass: HomeAssistant
+2 -2
View File
@@ -6,7 +6,7 @@ import { getColorByIndex } from "../common/color/colors";
import { computeDomain } from "../common/entity/compute_domain";
import { computeStateName } from "../common/entity/compute_state_name";
import type { HomeAssistant } from "../types";
import { UNAVAILABLE } from "./entity/entity";
import { isUnavailableState } from "./entity/entity";
import type { EntityRegistryEntry } from "./entity/entity_registry";
export interface Calendar {
@@ -120,7 +120,7 @@ export const getCalendars = (
.filter(
(eid) =>
computeDomain(eid) === "calendar" &&
hass.states[eid].state !== UNAVAILABLE &&
!isUnavailableState(hass.states[eid].state) &&
hass.entities[eid]?.hidden !== true
)
.sort()
+2
View File
@@ -6,8 +6,10 @@ export const UNKNOWN = "unknown";
export const ON = "on";
export const OFF = "off";
export const UNAVAILABLE_STATES = [UNAVAILABLE, UNKNOWN] as const;
export const OFF_STATES = [UNAVAILABLE, UNKNOWN, OFF] as const;
export const isUnavailableState = arrayLiteralIncludes(UNAVAILABLE_STATES);
export const isOffState = arrayLiteralIncludes(OFF_STATES);
export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
+2 -2
View File
@@ -2,7 +2,7 @@ import { computeDomain } from "../common/entity/compute_domain";
import { computeStateName } from "../common/entity/compute_state_name";
import { stringCompare } from "../common/string/compare";
import type { HomeAssistant, ServiceCallResponse } from "../types";
import { UNAVAILABLE } from "./entity/entity";
import { isUnavailableState } from "./entity/entity";
export interface TodoList {
entity_id: string;
@@ -49,7 +49,7 @@ export const getTodoLists = (
.filter(
(entityId) =>
computeDomain(entityId) === "todo" &&
hass.states[entityId].state !== UNAVAILABLE &&
!isUnavailableState(hass.states[entityId].state) &&
(includeHidden || hass.entities[entityId]?.hidden !== true)
)
.map((entityId) => ({
@@ -18,7 +18,7 @@ import "../../../components/ha-slider";
import "../../../components/ha-time-input";
import "../../../components/input/ha-input";
import { isTiltOnly } from "../../../data/cover";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import type { ImageEntity } from "../../../data/image";
import { computeImageUrl } from "../../../data/image";
import "../../../panels/lovelace/components/hui-timestamp-display";
@@ -108,13 +108,14 @@ class EntityPreviewRow extends LitElement {
private _renderEntityState(stateObj: HassEntity): TemplateResult | string {
const domain = stateObj.entity_id.split(".", 1)[0];
const disabled = stateObj.state === UNAVAILABLE;
const noValue =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
if (domain === "button") {
return html`
<ha-button appearance="plain" size="small" .disabled=${disabled}>
<ha-button
appearance="plain"
size="small"
.disabled=${isUnavailableState(stateObj.state)}
>
${this.hass.localize("ui.card.button.press")}
</ha-button>
`;
@@ -150,15 +151,19 @@ class EntityPreviewRow extends LitElement {
return html`
<ha-date-input
.locale=${this.hass.locale}
.disabled=${disabled}
.value=${noValue ? undefined : stateObj.state}
.disabled=${isUnavailableState(stateObj.state)}
.value=${isUnavailableState(stateObj.state)
? undefined
: stateObj.state}
>
</ha-date-input>
`;
}
if (domain === "datetime") {
const dateObj = noValue ? undefined : new Date(stateObj.state);
const dateObj = isUnavailableState(stateObj.state)
? undefined
: new Date(stateObj.state);
const time = dateObj ? format(dateObj, "HH:mm:ss") : undefined;
const date = dateObj ? format(dateObj, "yyyy-MM-dd") : undefined;
return html`
@@ -167,12 +172,12 @@ class EntityPreviewRow extends LitElement {
.label=${computeStateName(stateObj)}
.locale=${this.hass.locale}
.value=${date}
.disabled=${disabled}
.disabled=${isUnavailableState(stateObj.state)}
>
</ha-date-input>
<ha-time-input
.value=${time}
.disabled=${disabled}
.disabled=${isUnavailableState(stateObj.state)}
.locale=${this.hass.locale}
></ha-time-input>
</div>
@@ -182,7 +187,7 @@ class EntityPreviewRow extends LitElement {
if (domain === "event") {
return html`
<div class="when">
${noValue
${isUnavailableState(stateObj.state)
? this.hass.formatEntityState(stateObj)
: html`<hui-timestamp-display
.hass=${this.hass}
@@ -191,7 +196,7 @@ class EntityPreviewRow extends LitElement {
></hui-timestamp-display>`}
</div>
<div class="what">
${noValue
${isUnavailableState(stateObj.state)
? nothing
: this.hass.formatEntityAttributeValue(stateObj, "event_type")}
</div>
@@ -201,7 +206,9 @@ class EntityPreviewRow extends LitElement {
const toggleDomains = ["fan", "light", "remote", "siren", "switch"];
if (toggleDomains.includes(domain)) {
const showToggle =
stateObj.state === "on" || stateObj.state === "off" || noValue;
stateObj.state === "on" ||
stateObj.state === "off" ||
isUnavailableState(stateObj.state);
return html`
${showToggle
? html`
@@ -234,7 +241,7 @@ class EntityPreviewRow extends LitElement {
if (domain === "lock") {
return html`
<ha-button
.disabled=${disabled}
.disabled=${isUnavailableState(stateObj.state)}
class="text-content"
appearance="plain"
size="small"
@@ -259,7 +266,7 @@ class EntityPreviewRow extends LitElement {
<div class="numberflex">
<ha-slider
labeled
.disabled=${disabled}
.disabled=${stateObj.state === UNAVAILABLE}
.step=${Number(stateObj.attributes.step)}
.min=${Number(stateObj.attributes.min)}
.max=${Number(stateObj.attributes.max)}
@@ -273,7 +280,7 @@ class EntityPreviewRow extends LitElement {
: html`<div class="numberflex numberstate">
<ha-input
auto-validate
.disabled=${disabled}
.disabled=${stateObj.state === UNAVAILABLE}
pattern="[0-9]+([\\.][0-9]+)?"
.step=${Number(stateObj.attributes.step)}
.min=${Number(stateObj.attributes.min)}
@@ -296,7 +303,7 @@ class EntityPreviewRow extends LitElement {
<ha-select
.label=${computeStateName(stateObj)}
.value=${stateObj.state}
.disabled=${disabled}
.disabled=${stateObj.state === UNAVAILABLE}
.options=${stateObj.attributes.options?.map((option) => ({
value: option,
label: this.hass!.formatEntityState(stateObj, option),
@@ -310,7 +317,7 @@ class EntityPreviewRow extends LitElement {
const showSensor =
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
stateObj.attributes.device_class
) && !noValue;
) && !isUnavailableState(stateObj.state);
return html`
${showSensor
? html`
@@ -332,7 +339,7 @@ class EntityPreviewRow extends LitElement {
return html`
<ha-input
.label=${computeStateName(stateObj)}
.disabled=${disabled}
.disabled=${isUnavailableState(stateObj.state)}
.value=${stateObj.state}
.minlength=${stateObj.attributes.min}
.maxlength=${stateObj.attributes.max}
@@ -347,9 +354,11 @@ class EntityPreviewRow extends LitElement {
if (domain === "time") {
return html`
<ha-time-input
.value=${noValue ? undefined : stateObj.state}
.value=${isUnavailableState(stateObj.state)
? undefined
: stateObj.state}
.locale=${this.hass.locale}
.disabled=${disabled}
.disabled=${isUnavailableState(stateObj.state)}
></ha-time-input>
`;
}
@@ -357,7 +366,7 @@ class EntityPreviewRow extends LitElement {
if (domain === "weather") {
return html`
<div>
${noValue ||
${isUnavailableState(stateObj.state) ||
stateObj.attributes.temperature === undefined ||
stateObj.attributes.temperature === null
? this.hass.formatEntityState(stateObj)
-116
View File
@@ -1,116 +0,0 @@
import { navigate } from "../../common/navigate";
import type { LocalizeFunc } from "../../common/translations/localize";
import { createSearchParam } from "../../common/url/search-params";
import {
ADD_AUTOMATION_ELEMENT_QUERY_PARAM,
ADD_AUTOMATION_ELEMENT_TARGET_PARAM,
} from "../../panels/config/automation/show-add-automation-element-dialog";
import type { HomeAssistant, TranslationDict } from "../../types";
type DefaultActionKey =
TranslationDict["ui"]["dialogs"]["more_info_control"]["add_to"]["actions"] extends infer Actions
? keyof Actions
: never;
interface BaseEntityAddToAction {
/** Whether the action is enabled and can be selected. */
enabled: boolean;
/** Translated name of the action */
name: string;
/** Optional translated description of the action */
description?: string;
/** MDI icon name (e.g., "mdi:car") */
icon: string;
}
export interface DefaultEntityAddToAction extends BaseEntityAddToAction {
/** Type of action handled in the frontend */
type: "default";
/** Stable key used to resolve the action handler */
key: DefaultActionKey;
}
export interface ExternalEntityAddToAction extends BaseEntityAddToAction {
/** Type of action. External is handled by external apps instead of in the frontend */
type: "external";
/** Opaque payload for external action handling */
payload?: string;
}
export type EntityAddToAction =
| DefaultEntityAddToAction
| ExternalEntityAddToAction;
export type EntityAddToActions = EntityAddToAction[];
interface ActionDefinition {
translation_key: DefaultActionKey;
icon: string;
}
export const DEFAULT_ACTION_DEFS: ActionDefinition[] = [
{
translation_key: "automation_trigger",
icon: "mdi:robot-outline",
},
{
translation_key: "automation_condition",
icon: "mdi:playlist-check",
},
{
translation_key: "automation_action",
icon: "mdi:play-circle-outline",
},
{
translation_key: "script_action",
icon: "mdi:script-text-outline",
},
];
export const getDefaultAddToActions = (
states: HomeAssistant["states"],
localize: LocalizeFunc,
formatEntityName: HomeAssistant["formatEntityName"],
entityId: string
): EntityAddToActions =>
DEFAULT_ACTION_DEFS.map(
(def: ActionDefinition): EntityAddToAction => ({
type: "default",
key: def.translation_key,
enabled: true,
name: localize(
`ui.dialogs.more_info_control.add_to.actions.${def.translation_key}`,
{
entity:
states[entityId] !== undefined
? formatEntityName(states[entityId], undefined)
: entityId,
}
),
icon: def.icon,
})
);
export function defaultActionHandler(
key: (typeof DEFAULT_ACTION_DEFS)[number]["translation_key"],
entityId: string
): Promise<boolean> {
const params = (addElement: string) =>
`?${createSearchParam({
[ADD_AUTOMATION_ELEMENT_QUERY_PARAM]: addElement,
[ADD_AUTOMATION_ELEMENT_TARGET_PARAM]: entityId,
})}`;
switch (key) {
case "automation_trigger":
return navigate(`/config/automation/edit/new${params("trigger")}`);
case "automation_condition":
return navigate(`/config/automation/edit/new${params("condition")}`);
case "automation_action":
return navigate(`/config/automation/edit/new${params("action")}`);
case "script_action":
return navigate(`/config/script/edit/new${params("action")}`);
default:
return Promise.reject(new Error(`Unknown action key ${key}`));
}
}
@@ -3,7 +3,7 @@ import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-absolute-time";
import "../../../components/ha-relative-time";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { LightEntity } from "../../../data/light";
import { SENSOR_DEVICE_CLASS_TIMESTAMP } from "../../../data/sensor";
import "../../../panels/lovelace/components/hui-timestamp-display";
@@ -24,8 +24,7 @@ export class HaMoreInfoStateHeader extends LitElement {
private _localizeState(): TemplateResult | string {
if (
this.stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP &&
this.stateObj.state !== UNAVAILABLE &&
this.stateObj.state !== UNKNOWN
!isUnavailableState(this.stateObj.state)
) {
return html`
<hui-timestamp-display
@@ -4,7 +4,7 @@ import { customElement, property } from "lit/decorators";
import "../../../components/ha-button";
import "../../../components/ha-relative-time";
import { triggerAutomationActions } from "../../../data/automation";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { HomeAssistant } from "../../../types";
@customElement("more-info-automation")
@@ -34,7 +34,7 @@ class MoreInfoAutomation extends LitElement {
appearance="plain"
size="small"
@click=${this._runActions}
.disabled=${this.stateObj!.state === UNAVAILABLE}
.disabled=${isUnavailableState(this.stateObj!.state)}
>
${this.hass.localize("ui.card.automation.trigger")}
</ha-button>
@@ -2,7 +2,7 @@ import type { HassEntity } from "home-assistant-js-websocket";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../components/ha-button";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { HomeAssistant } from "../../../types";
@customElement("more-info-counter")
@@ -16,7 +16,7 @@ class MoreInfoCounter extends LitElement {
return nothing;
}
const disabled = this.stateObj.state === UNAVAILABLE;
const disabled = isUnavailableState(this.stateObj.state);
return html`
<div class="actions">
@@ -4,7 +4,7 @@ import { customElement, property } from "lit/decorators";
import "../../../components/ha-date-input";
import "../../../components/ha-time-input";
import { setDateValue } from "../../../data/date";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
@customElement("more-info-date")
@@ -21,9 +21,10 @@ class MoreInfoDate extends LitElement {
return html`
<ha-date-input
.locale=${this.hass.locale}
.value=${this.stateObj.state === UNKNOWN
.value=${isUnavailableState(this.stateObj.state)
? undefined
: this.stateObj.state}
.disabled=${this.stateObj.state === UNAVAILABLE}
@value-changed=${this._dateChanged}
>
</ha-date-input>
@@ -5,7 +5,7 @@ import { customElement, property } from "lit/decorators";
import "../../../components/ha-date-input";
import "../../../components/ha-time-input";
import { setDateTimeValue } from "../../../data/datetime";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
@customElement("more-info-datetime")
@@ -19,22 +19,23 @@ class MoreInfoDatetime extends LitElement {
return nothing;
}
const dateObj =
this.stateObj.state === UNKNOWN
? undefined
: new Date(this.stateObj.state);
const dateObj = isUnavailableState(this.stateObj.state)
? undefined
: new Date(this.stateObj.state);
const time = dateObj ? format(dateObj, "HH:mm:ss") : undefined;
const date = dateObj ? format(dateObj, "yyyy-MM-dd") : undefined;
return html`<ha-date-input
.locale=${this.hass.locale}
.value=${date}
.disabled=${this.stateObj.state === UNAVAILABLE}
@value-changed=${this._dateChanged}
>
</ha-date-input>
<ha-time-input
.value=${time}
.locale=${this.hass.locale}
.disabled=${this.stateObj.state === UNAVAILABLE}
@value-changed=${this._timeChanged}
@click=${this._stopEventPropagation}
></ha-time-input>`;
@@ -11,7 +11,7 @@ import "../../../components/ha-control-button-group";
import "../../../components/ha-markdown";
import "../../../components/ha-relative-time";
import "../../../components/ha-service-control";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { ExtEntityRegistryEntry } from "../../../data/entity/entity_registry";
import type { ScriptEntity } from "../../../data/script";
import {
@@ -141,7 +141,7 @@ class MoreInfoScript extends LitElement {
<ha-control-button
class="run-button"
@click=${this._runScript}
.disabled=${stateObj.state === UNAVAILABLE || !this._canRun()}
.disabled=${isUnavailableState(stateObj.state) || !this._canRun()}
>
<ha-svg-icon .path=${mdiPlay}></ha-svg-icon>
${this.hass!.localize("ui.card.script.run")}
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../components/ha-date-input";
import "../../../components/ha-time-input";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { setTimeValue } from "../../../data/time";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
@@ -20,10 +20,11 @@ class MoreInfoTime extends LitElement {
return html`
<ha-time-input
.value=${this.stateObj.state === UNKNOWN
.value=${isUnavailableState(this.stateObj.state)
? undefined
: this.stateObj.state}
.locale=${this.hass.locale}
.disabled=${this.stateObj.state === UNAVAILABLE}
@value-changed=${this._timeChanged}
@click=${this._stopEventPropagation}
></ha-time-input>
@@ -15,7 +15,7 @@ import "../../../components/item/ha-row-item";
import "../../../components/progress/ha-progress-bar";
import type { BackupConfig } from "../../../data/backup";
import { fetchBackupConfig } from "../../../data/backup";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { EntitySources } from "../../../data/entity/entity_sources";
import { fetchEntitySourcesWithCache } from "../../../data/entity/entity_sources";
import { getSupervisorUpdateConfig } from "../../../data/supervisor/update";
@@ -176,8 +176,7 @@ class MoreInfoUpdate extends LitElement {
if (
!this.hass ||
!this.stateObj ||
this.stateObj.state === UNAVAILABLE ||
this.stateObj.state === UNKNOWN
isUnavailableState(this.stateObj.state)
) {
return nothing;
}
+55 -123
View File
@@ -5,18 +5,14 @@ import "../../components/ha-icon";
import "../../components/ha-spinner";
import "../../components/item/ha-list-item-button";
import "../../components/list/ha-list-base";
import type { HaListItemButton } from "../../components/item/ha-list-item-button";
import type {
ExternalEntityAddToAction,
ExternalEntityAddToActions,
} from "../../external_app/external_messaging";
import { showToast } from "../../util/toast";
import type { HASSDomCurrentTargetEvent } from "../../common/dom/fire_event";
import { fireEvent } from "../../common/dom/fire_event";
import type { HomeAssistant } from "../../types";
import {
type EntityAddToAction,
type EntityAddToActions,
defaultActionHandler,
getDefaultAddToActions,
} from "./add-to";
@customElement("ha-more-info-add-to")
export class HaMoreInfoAddTo extends LitElement {
@@ -24,112 +20,54 @@ export class HaMoreInfoAddTo extends LitElement {
@property({ attribute: false }) public entityId!: string;
@state() private _defaultActions: EntityAddToActions = [];
@state() private _externalActions: EntityAddToActions = [];
@state() private _externalActions?: ExternalEntityAddToActions = {
actions: [],
};
@state() private _loading = true;
private async _loadActions() {
this._defaultActions = getDefaultAddToActions(
this.hass.states,
this.hass.localize,
this.hass.formatEntityName,
this.entityId
);
this._externalActions = [];
private async _loadExternalActions() {
if (this.hass.auth.external?.config.hasEntityAddTo) {
try {
const response =
await this.hass.auth.external?.sendMessage<"entity/add_to/get_actions">(
{
type: "entity/add_to/get_actions",
payload: { entity_id: this.entityId },
}
);
if (response?.actions) {
this._externalActions = response.actions.map((action) => ({
type: "external",
enabled: action.enabled,
name: action.name,
description: action.details,
icon: action.mdi_icon,
payload: action.app_payload,
}));
}
} catch (err: unknown) {
// eslint-disable-next-line no-console
console.warn("Failed to fetch add to actions", err);
}
this._externalActions =
await this.hass.auth.external?.sendMessage<"entity/add_to/get_actions">(
{
type: "entity/add_to/get_actions",
payload: { entity_id: this.entityId },
}
);
}
}
private async _actionSelected(
ev: HASSDomCurrentTargetEvent<
HaListItemButton & {
action: EntityAddToAction;
}
>
) {
const action = ev.currentTarget.action;
private async _actionSelected(ev: CustomEvent) {
const action = (ev.currentTarget as any)
.action as ExternalEntityAddToAction;
if (!action.enabled) {
return;
}
if (action.type === "external") {
try {
if (!action.payload) {
throw new Error("Missing external action payload");
}
this.hass.auth.external!.fireMessage({
type: "entity/add_to",
payload: {
entity_id: this.entityId,
app_payload: action.payload,
},
});
fireEvent(this, "add-to-action-selected");
} catch (err: unknown) {
showToast(this, {
message: this.hass.localize(
"ui.dialogs.more_info_control.add_to.action_failed",
{
error: err instanceof Error ? err.message : String(err),
}
),
});
}
return;
try {
await this.hass.auth.external!.fireMessage({
type: "entity/add_to",
payload: {
entity_id: this.entityId,
app_payload: action.app_payload,
},
});
fireEvent(this, "add-to-action-selected");
} catch (err: any) {
showToast(this, {
message: this.hass.localize(
"ui.dialogs.more_info_control.add_to.action_failed",
{
error: err.message || err,
}
),
});
}
if (action.type !== "default") {
return;
}
defaultActionHandler(action.key, this.entityId);
}
private _renderActionItems(actions: EntityAddToActions) {
return actions.map(
(action) => html`
<ha-list-item-button
.disabled=${!action.enabled}
.action=${action}
@click=${this._actionSelected}
>
<ha-icon slot="start" .icon=${action.icon}></ha-icon>
<span slot="headline">${action.name}</span>
${action.description
? html`<span slot="supporting-text">${action.description}</span>`
: nothing}
</ha-list-item-button>
`
);
}
protected async firstUpdated() {
await this._loadActions();
await this._loadExternalActions();
this._loading = false;
}
@@ -142,7 +80,7 @@ export class HaMoreInfoAddTo extends LitElement {
`;
}
if (!this._defaultActions.length && !this._externalActions.length) {
if (!this._externalActions?.actions.length) {
return html`
<ha-alert alert-type="info">
${this.hass.localize(
@@ -154,27 +92,30 @@ export class HaMoreInfoAddTo extends LitElement {
return html`
<ha-list-base>
${this._renderActionItems(this._defaultActions)}
</ha-list-base>
${this._externalActions.length
? html`
<h2 class="section-title">
${this.hass.localize(
"ui.dialogs.more_info_control.add_to.app_actions"
)}
</h2>
<ha-list-base>
${this._renderActionItems(this._externalActions)}
</ha-list-base>
${this._externalActions?.actions.map(
(action) => html`
<ha-list-item-button
.disabled=${!action.enabled}
.action=${action}
@click=${this._actionSelected}
>
<ha-icon slot="start" .icon=${action.mdi_icon}></ha-icon>
<span slot="headline">${action.name}</span>
${action.details
? html`<span slot="supporting-text">${action.details}</span>`
: nothing}
</ha-list-item-button>
`
: nothing}
)}
</ha-list-base>
`;
}
static styles = css`
:host {
display: block;
padding: var(--ha-space-3) 0 var(--ha-space-4);
padding: var(--ha-space-2) var(--ha-space-6) var(--ha-space-6)
var(--ha-space-6);
}
.loading {
@@ -184,15 +125,6 @@ export class HaMoreInfoAddTo extends LitElement {
padding: var(--ha-space-8);
}
.section-title {
padding: 0 var(--ha-space-6);
margin: var(--ha-space-4) 0 var(--ha-space-1);
font-size: var(--ha-font-size-m);
font-weight: var(--ha-font-weight-medium);
line-height: var(--ha-line-height-normal);
color: var(--secondary-text-color);
}
ha-icon {
display: flex;
align-items: center;
+19 -45
View File
@@ -1,4 +1,3 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import {
mdiBackupRestore,
mdiChartBoxOutline,
@@ -18,13 +17,13 @@ import {
} from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { cache } from "lit/directives/cache";
import { classMap } from "lit/directives/class-map";
import { keyed } from "lit/directives/keyed";
import { dynamicElement } from "../../common/dom/dynamic-element-directive";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { dynamicElement } from "../../common/dom/dynamic-element-directive";
import { fireEvent } from "../../common/dom/fire_event";
import { stopPropagation } from "../../common/dom/stop_propagation";
import { computeAreaName } from "../../common/entity/compute_area_name";
@@ -58,12 +57,10 @@ import {
getExtendedEntityRegistryEntry,
updateEntityRegistryEntry,
} from "../../data/entity/entity_registry";
import { subscribeLabFeature } from "../../data/labs";
import type { ItemType } from "../../data/search";
import { SearchableDomains } from "../../data/search";
import { getSensorNumericDeviceClasses } from "../../data/sensor";
import { ScrollableFadeMixin } from "../../mixins/scrollable-fade-mixin";
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
import {
haStyleDialog,
haStyleDialogFixedTop,
@@ -73,12 +70,12 @@ import "../../state-summary/state-card-content";
import type { HomeAssistant } from "../../types";
import { showConfirmationDialog } from "../generic/show-dialog-box";
import {
computeShowHistoryComponent,
computeShowLogBookComponent,
DOMAINS_WITH_MORE_INFO,
EDITABLE_DOMAINS_WITH_ID,
EDITABLE_DOMAINS_WITH_UNIQUE_ID,
type MoreInfoView,
computeShowHistoryComponent,
computeShowLogBookComponent,
} from "./const";
import "./controls/more-info-default";
import type { FavoritesDialogContext } from "./favorites";
@@ -120,9 +117,7 @@ declare global {
const DEFAULT_VIEW: MoreInfoView = "info";
@customElement("ha-more-info-dialog")
export class MoreInfoDialog extends SubscribeMixin(
ScrollableFadeMixin(LitElement)
) {
export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean, reflect: true }) public large = false;
@@ -161,8 +156,6 @@ export class MoreInfoDialog extends SubscribeMixin(
@state() private _sensorNumericDeviceClasses?: string[] = [];
@state() private _newTriggersAndConditions = false;
protected scrollFadeThreshold = 24;
protected get scrollableElement(): HTMLElement | null {
@@ -261,24 +254,7 @@ export class MoreInfoDialog extends SubscribeMixin(
}
private _shouldShowAddEntityTo(): boolean {
// When labs feature is promoted, this whole check can be removed.
return (
this._newTriggersAndConditions ||
!!this.hass.auth.external?.config.hasEntityAddTo
);
}
protected hassSubscribe() {
return [
subscribeLabFeature(
this.hass.connection,
"automation",
"new_triggers_conditions",
(feature) => {
this._newTriggersAndConditions = feature.enabled;
}
),
];
return !!this.hass.auth.external?.config.hasEntityAddTo;
}
private _getDeviceId(): string | null {
@@ -704,21 +680,6 @@ export class MoreInfoDialog extends SubscribeMixin(
.path=${mdiDotsVertical}
></ha-icon-button>
${this._shouldShowAddEntityTo()
? html`
<ha-dropdown-item value="add_to">
<ha-svg-icon
slot="icon"
.path=${mdiPlusBoxMultipleOutline}
></ha-svg-icon>
${this.hass.localize(
"ui.dialogs.more_info_control.add_entity_to"
)}
</ha-dropdown-item>
<wa-divider></wa-divider>
`
: nothing}
${supportsFavorites
? html`
<ha-dropdown-item value="toggle_edit">
@@ -808,6 +769,19 @@ export class MoreInfoDialog extends SubscribeMixin(
"ui.dialogs.more_info_control.details"
)}
</ha-dropdown-item>
${this._shouldShowAddEntityTo()
? html`
<ha-dropdown-item value="add_to">
<ha-svg-icon
slot="icon"
.path=${mdiPlusBoxMultipleOutline}
></ha-svg-icon>
${this.hass.localize(
"ui.dialogs.more_info_control.add_entity_to"
)}
</ha-dropdown-item>
`
: nothing}
</ha-dropdown>
`
: !__DEMO__ && this._shouldShowAddEntityTo()
@@ -18,7 +18,6 @@ import { getValueFromDynamic, isDynamic } from "../../../../data/automation";
import type { Action } from "../../../../data/script";
import { EDITOR_SAVE_FAB_TOAST_BOTTOM_OFFSET } from "../editor-toast";
import {
getAddAutomationElementTargetFromQuery,
PASTE_VALUE,
showAddAutomationElementDialog,
} from "../show-add-automation-element-dialog";
@@ -42,8 +41,6 @@ export default class HaAutomationAction extends AutomationSortableListMixin<Acti
@queryAll("ha-automation-action-row")
private _actionRowElements?: HaAutomationActionRow[];
private _openedAddDialogFromQuery = false;
protected get items(): Action[] {
return this.actions;
}
@@ -136,32 +133,6 @@ export default class HaAutomationAction extends AutomationSortableListMixin<Acti
protected updated(changedProps: PropertyValues<this>) {
super.updated(changedProps);
if (!this.hass) {
return;
}
const addActionTargetFromQuery = getAddAutomationElementTargetFromQuery(
this.hass.states,
"action"
);
if (changedProps.has("actions") && addActionTargetFromQuery) {
this._openedAddDialogFromQuery = false;
}
if (
!this._openedAddDialogFromQuery &&
this.root &&
!this.disabled &&
this.actions.length === 0 &&
addActionTargetFromQuery
) {
this._openedAddDialogFromQuery = true;
queueMicrotask(() => this._addActionDialog());
} else if (this._openedAddDialogFromQuery && !addActionTargetFromQuery) {
this._openedAddDialogFromQuery = false;
}
if (
changedProps.has("actions") &&
(this.focusLastItemOnChange || this.focusItemIndexOnChange !== undefined)
@@ -33,7 +33,6 @@ import type {
import { computeRTL } from "../../../common/util/compute_rtl";
import { debounce } from "../../../common/util/debounce";
import { deepEqual } from "../../../common/util/deep-equal";
import { constructUrlCurrentPath } from "../../../common/url/construct-url";
import "../../../components/entity/state-badge";
import "../../../components/ha-bottom-sheet";
import "../../../components/ha-button";
@@ -129,12 +128,7 @@ import "./add-automation-element/ha-automation-add-from-target";
import "./add-automation-element/ha-automation-add-items";
import "./add-automation-element/ha-automation-add-search";
import type { AddAutomationElementDialogParams } from "./show-add-automation-element-dialog";
import {
ADD_AUTOMATION_ELEMENT_QUERY_PARAM,
ADD_AUTOMATION_ELEMENT_TARGET_PARAM,
getAddAutomationElementTargetFromQuery,
PASTE_VALUE,
} from "./show-add-automation-element-dialog";
import { PASTE_VALUE } from "./show-add-automation-element-dialog";
import { getTargetText } from "./target/get_target_text";
const TYPES = {
@@ -236,8 +230,6 @@ class DialogAddAutomationElement
@state() private _newTriggersAndConditions = false;
@state() private _openedFromQuery = false;
@state() private _conditionDescriptions: ConditionDescriptions = {};
@state()
@@ -303,27 +295,10 @@ class DialogAddAutomationElement
}
}
public showDialog(params: AddAutomationElementDialogParams): void {
public showDialog(params): void {
this._params = params;
this._resetVariables();
const queryEntityId = getAddAutomationElementTargetFromQuery(
this.hass.states,
params.type
);
this._openedFromQuery = !!queryEntityId;
if (queryEntityId) {
const searchParams = new URLSearchParams(mainWindow.location.search);
searchParams.delete(ADD_AUTOMATION_ELEMENT_QUERY_PARAM);
searchParams.delete(ADD_AUTOMATION_ELEMENT_TARGET_PARAM);
mainWindow.history.replaceState(
mainWindow.history.state,
"",
constructUrlCurrentPath(searchParams.toString())
);
}
this.addKeyboardShortcuts();
this._loadConfigEntries();
@@ -339,26 +314,16 @@ class DialogAddAutomationElement
(feature) => {
this._newTriggersAndConditions = feature.enabled;
this._tab = this._newTriggersAndConditions ? "targets" : "groups";
if (
queryEntityId &&
this._newTriggersAndConditions &&
!this._selectedTarget
) {
this._selectedTarget = { entity_id: queryEntityId };
this._getItemsByTarget();
}
}
);
if (!queryEntityId) {
// add initial dialog view state to history
mainWindow.history.pushState(
{
dialogData: {},
},
""
);
}
// add initial dialog view state to history
mainWindow.history.pushState(
{
dialogData: {},
},
""
);
if (this._params?.type === "action") {
this.hass.loadBackendTranslation("services");
@@ -378,16 +343,6 @@ class DialogAddAutomationElement
// prevent view mode switch when resizing window
this._bottomSheetMode = this._narrow;
if (
queryEntityId &&
this._newTriggersAndConditions &&
!this._selectedTarget
) {
this._selectedTarget = { entity_id: queryEntityId };
this._tab = "targets";
this._getItemsByTarget();
}
}
public closeDialog(historyState?: any) {
@@ -452,7 +407,6 @@ class DialogAddAutomationElement
this._narrow = false;
this._targetItems = undefined;
this._loadItemsError = false;
this._openedFromQuery = false;
}
private _updateNarrow = () => {
@@ -937,9 +891,7 @@ class DialogAddAutomationElement
></ha-icon-button>
`
: nothing}
${this._narrow &&
(this._selectedGroup || this._selectedTarget) &&
!this._openedFromQuery
${this._narrow && (this._selectedGroup || this._selectedTarget)
? html`<ha-icon-button-prev
slot="navigationIcon"
@click=${this._back}
@@ -40,6 +40,7 @@ import "../../../../components/automation/ha-automation-row";
import type { HaAutomationRow } from "../../../../components/automation/ha-automation-row";
import "../../../../components/automation/ha-automation-row-event-chip";
import "../../../../components/automation/ha-automation-row-live-test";
import type { LiveTestState } from "../../../../components/automation/ha-automation-row-live-test";
import "../../../../components/ha-card";
import "../../../../components/ha-condition-icon";
import "../../../../components/ha-dropdown";
@@ -149,10 +150,7 @@ export default class HaAutomationConditionRow extends LitElement {
@state() private _selected = false;
@state() private _liveTestResult: {
state: "pass" | "fail" | "invalid" | "unknown";
message?: string;
} = { state: "unknown" };
@state() private _liveTestResult: LiveTestState = "unknown";
@state()
@consume({ context: fullEntitiesContext, subscribe: true })
@@ -500,11 +498,10 @@ export default class HaAutomationConditionRow extends LitElement {
>${this._renderRow()}
<ha-automation-row-live-test
slot="icons"
.state=${this._liveTestResult.state}
.state=${this._liveTestResult}
.label=${this.hass.localize(
`ui.panel.config.automation.editor.conditions.live_test_state.${this._liveTestResult.state}`
`ui.panel.config.automation.editor.conditions.live_test_state.${this._liveTestResult}`
)}
.message=${this._liveTestResult.message}
></ha-automation-row-live-test
></ha-automation-row>`
: html`
@@ -591,12 +588,7 @@ export default class HaAutomationConditionRow extends LitElement {
}
private _resetSubscription() {
this._liveTestResult = {
state: "unknown",
message: this.hass.localize(
"ui.panel.config.automation.editor.conditions.live_test_state.unknown"
),
};
this._liveTestResult = "unknown";
if (this._conditionUnsub) {
this._conditionUnsub.then((unsub) => unsub());
this._conditionUnsub = undefined;
@@ -621,12 +613,7 @@ export default class HaAutomationConditionRow extends LitElement {
if (result.error) {
this._handleLiveTestError(result.error);
} else {
this._liveTestResult = {
state: result.result ? "pass" : "fail",
message: this.hass.localize(
`ui.panel.config.automation.editor.conditions.testing_${result.result ? "pass" : "error"}`
),
};
this._liveTestResult = result.result ? "pass" : "fail";
}
},
this.condition
@@ -643,10 +630,7 @@ export default class HaAutomationConditionRow extends LitElement {
private _handleLiveTestError(error: any) {
const invalid =
typeof error !== "string" && error.code === "invalid_format";
this._liveTestResult = {
state: invalid ? "invalid" : "unknown",
message: typeof error === "string" ? error : error.message,
};
this._liveTestResult = invalid ? "invalid" : "unknown";
}
private _onValueChange(event: CustomEvent) {
@@ -27,7 +27,6 @@ import { subscribeLabFeature } from "../../../../data/labs";
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
import { EDITOR_SAVE_FAB_TOAST_BOTTOM_OFFSET } from "../editor-toast";
import {
getAddAutomationElementTargetFromQuery,
PASTE_VALUE,
showAddAutomationElementDialog,
} from "../show-add-automation-element-dialog";
@@ -58,8 +57,6 @@ export default class HaAutomationCondition extends AutomationSortableListMixin<C
private _unsub?: Promise<UnsubscribeFunc>;
private _openedAddDialogFromQuery = false;
protected get items(): Condition[] {
return this.conditions;
}
@@ -121,32 +118,6 @@ export default class HaAutomationCondition extends AutomationSortableListMixin<C
}
protected updated(changedProperties: PropertyValues<this>) {
if (!this.hass) {
return;
}
const addConditionTargetFromQuery = getAddAutomationElementTargetFromQuery(
this.hass.states,
"condition"
);
if (changedProperties.has("conditions") && addConditionTargetFromQuery) {
this._openedAddDialogFromQuery = false;
}
if (
!this._openedAddDialogFromQuery &&
this.root &&
!this.disabled &&
this.conditions.length === 0 &&
addConditionTargetFromQuery
) {
this._openedAddDialogFromQuery = true;
queueMicrotask(() => this._addConditionDialog());
} else if (this._openedAddDialogFromQuery && !addConditionTargetFromQuery) {
this._openedAddDialogFromQuery = false;
}
if (!changedProperties.has("conditions")) {
return;
}
@@ -77,7 +77,6 @@ import { showAssignCategoryDialog } from "../category/show-dialog-assign-categor
import { showAutomationModeDialog } from "./automation-mode-dialog/show-dialog-automation-mode";
import { showAutomationSaveDialog } from "./automation-save-dialog/show-dialog-automation-save";
import { showAutomationSaveTimeoutDialog } from "./automation-save-timeout-dialog/show-dialog-automation-save-timeout";
import { ADD_AUTOMATION_ELEMENT_QUERY_PARAM } from "./show-add-automation-element-dialog";
import "./blueprint-automation-editor";
import type { EditorDomainHooks } from "./ha-automation-script-editor-mixin";
import {
@@ -573,21 +572,11 @@ export class HaAutomationEditor extends AutomationScriptEditorMixin<AutomationCo
protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);
if (!this.hass) {
return;
}
const shouldResetNewAutomationConfigFromQuery =
changedProps.has("route") &&
this.route?.path === "/new" &&
new URLSearchParams(window.location.search).has(
ADD_AUTOMATION_ELEMENT_QUERY_PARAM
);
const oldAutomationId = changedProps.get("automationId");
if (
changedProps.has("automationId") &&
this.automationId &&
this.hass &&
// Only refresh config if we picked a new automation. If same ID, don't fetch it.
oldAutomationId !== this.automationId
) {
@@ -596,10 +585,10 @@ export class HaAutomationEditor extends AutomationScriptEditorMixin<AutomationCo
}
if (
(changedProps.has("automationId") ||
shouldResetNewAutomationConfigFromQuery) &&
changedProps.has("automationId") &&
!this.automationId &&
!this.entityId
!this.entityId &&
this.hass
) {
const initData = getAutomationEditorInitData();
this.dirty = !!initData;
@@ -1,12 +1,8 @@
import type { HassServiceTarget } from "home-assistant-js-websocket";
import { fireEvent } from "../../../common/dom/fire_event";
import type { HomeAssistant } from "../../../types";
export const PASTE_VALUE = "__paste__";
export const ADD_AUTOMATION_ELEMENT_QUERY_PARAM = "add_automation_element";
export const ADD_AUTOMATION_ELEMENT_TARGET_PARAM = "target_entity_id";
export interface AddAutomationElementDialogParams {
type: "trigger" | "condition" | "action";
add: (key: string, target?: HassServiceTarget) => void;
@@ -15,30 +11,13 @@ export interface AddAutomationElementDialogParams {
}
const loadDialog = () => import("./add-automation-element-dialog");
export const getAddAutomationElementTargetFromQuery = (
states: HomeAssistant["states"],
type: AddAutomationElementDialogParams["type"]
): string | undefined => {
const params = new URLSearchParams(window.location.search);
const entityId = params.get(ADD_AUTOMATION_ELEMENT_TARGET_PARAM);
return params.get(ADD_AUTOMATION_ELEMENT_QUERY_PARAM) === type &&
entityId &&
states[entityId]
? entityId
: undefined;
};
export const showAddAutomationElementDialog = (
element: HTMLElement,
dialogParams: AddAutomationElementDialogParams
): void => {
const params = new URLSearchParams(window.location.search);
fireEvent(element, "show-dialog", {
dialogTag: "add-automation-element-dialog",
dialogImport: loadDialog,
dialogParams,
addHistory:
params.get(ADD_AUTOMATION_ELEMENT_QUERY_PARAM) !== dialogParams.type,
});
};
@@ -25,7 +25,6 @@ import { isTriggerList, subscribeTriggers } from "../../../../data/trigger";
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
import { EDITOR_SAVE_FAB_TOAST_BOTTOM_OFFSET } from "../editor-toast";
import {
getAddAutomationElementTargetFromQuery,
PASTE_VALUE,
showAddAutomationElementDialog,
} from "../show-add-automation-element-dialog";
@@ -53,8 +52,6 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
private _unsub?: Promise<UnsubscribeFunc>;
private _openedAddDialogFromQuery = false;
protected get items(): Trigger[] {
return this.triggers;
}
@@ -238,32 +235,6 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
protected updated(changedProps: PropertyValues<this>) {
super.updated(changedProps);
if (!this.hass) {
return;
}
const addTriggerTargetFromQuery = getAddAutomationElementTargetFromQuery(
this.hass.states,
"trigger"
);
if (changedProps.has("triggers") && addTriggerTargetFromQuery) {
this._openedAddDialogFromQuery = false;
}
if (
!this._openedAddDialogFromQuery &&
this.root &&
!this.disabled &&
this.triggers.length === 0 &&
addTriggerTargetFromQuery
) {
this._openedAddDialogFromQuery = true;
queueMicrotask(() => this._addTriggerDialog());
} else if (this._openedAddDialogFromQuery && !addTriggerTargetFromQuery) {
this._openedAddDialogFromQuery = false;
}
if (
changedProps.has("triggers") &&
(this.focusLastItemOnChange || this.focusItemIndexOnChange !== undefined)
@@ -7,7 +7,7 @@ import type { DataTableColumnData } from "../../../components/data-table/ha-data
import { slugify } from "../../../common/string/slugify";
import { relativeTime } from "../../../common/datetime/relative_time";
import { formatShortDateTimeWithConditionalYear } from "../../../common/datetime/format_date_time";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import "../../../components/ha-tooltip";
import "../../../components/ha-svg-icon";
@@ -146,11 +146,7 @@ export const renderRelativeTimeColumn = (
localize: LocalizeFunc,
hass: HomeAssistant
) => {
if (
!valueRelativeTime ||
valueRelativeTime === UNAVAILABLE ||
valueRelativeTime === UNKNOWN
) {
if (!valueRelativeTime || isUnavailableState(valueRelativeTime)) {
return localize("ui.components.relative_time.never");
}
const date = new Date(valueRelativeTime);
@@ -5,7 +5,6 @@ import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import memoizeOne from "memoize-one";
import { computeDomain } from "../../../common/entity/compute_domain";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { stateColorCss } from "../../../common/entity/state_color";
import "../../../components/ha-control-button";
import "../../../components/ha-control-button-group";
@@ -102,11 +101,9 @@ class HuiAlarmModeCardFeature
return supportedModes.find((mode) => mode === stateObj.state);
});
private async _valueChanged(
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
) {
private async _valueChanged(ev: CustomEvent) {
if (!this._stateObj) return;
const mode = ev.detail.value as AlarmMode;
const mode = (ev.detail as any).value as AlarmMode;
if (mode === this._stateObj.state) return;
@@ -2,7 +2,6 @@ import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { computeCssColor } from "../../../common/color/compute-color";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
import { computeDomain } from "../../../common/entity/compute_domain";
import { stateActive } from "../../../common/entity/state_active";
@@ -116,9 +115,9 @@ class HuiCoverPositionCardFeature
`;
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this.hass!.callService("cover", "set_cover_position", {
entity_id: this._stateObj!.entity_id,
@@ -2,7 +2,6 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { computeCssColor } from "../../../common/color/compute-color";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
import { computeDomain } from "../../../common/entity/compute_domain";
import { stateColorCss } from "../../../common/entity/state_color";
@@ -119,9 +118,9 @@ class HuiCoverTiltPositionCardFeature
`;
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this.hass!.callService("cover", "set_cover_tilt_position", {
entity_id: this._stateObj!.entity_id,
@@ -4,7 +4,6 @@ import { LitElement, html } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { computeDomain } from "../../../common/entity/compute_domain";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { stateColorCss } from "../../../common/entity/state_color";
import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-control-select";
@@ -80,10 +79,8 @@ class HuiFanOscillateCardFeature
}
}
private async _valueChanged(
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
) {
const shouldOscillate = ev.detail.value === "yes";
private async _valueChanged(ev: CustomEvent) {
const shouldOscillate = (ev.detail as any).value === "yes";
if (shouldOscillate === this._stateObj!.attributes.oscillating) return;
@@ -1,7 +1,6 @@
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { computeDomain } from "../../../common/entity/compute_domain";
import { stateActive } from "../../../common/entity/state_active";
import { supportsFeature } from "../../../common/entity/supports-feature";
@@ -145,8 +144,8 @@ class HuiFanSpeedCardFeature extends LitElement implements LovelaceCardFeature {
`;
}
private _speedValueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const speed = ev.detail.value as FanSpeed;
private _speedValueChanged(ev: CustomEvent) {
const speed = (ev.detail as any).value as FanSpeed;
const percentage = fanSpeedToPercentage(this._stateObj!, speed);
@@ -156,9 +155,9 @@ class HuiFanSpeedCardFeature extends LitElement implements LovelaceCardFeature {
});
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this.hass!.callService("fan", "set_percentage", {
entity_id: this._stateObj!.entity_id,
@@ -4,7 +4,6 @@ import { LitElement, html } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { computeDomain } from "../../../common/entity/compute_domain";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { stateColorCss } from "../../../common/entity/state_color";
import "../../../components/ha-control-select";
import type { ControlSelectOption } from "../../../components/ha-control-select";
@@ -82,10 +81,8 @@ class HuiHumidifierToggleCardFeature
}
}
private async _valueChanged(
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
) {
const newState = ev.detail.value as HumidifierState;
private async _valueChanged(ev: CustomEvent) {
const newState = (ev.detail as any).value as HumidifierState;
if (newState === this._stateObj!.state) return;
@@ -26,7 +26,7 @@ import { stateActive } from "../../../common/entity/state_active";
import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-control-button";
import "../../../components/ha-control-button-group";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type {
ControlButton,
MediaPlayerEntity,
@@ -233,7 +233,7 @@ class HuiMediaPlayerPlaybackCardFeature
case "turn_on":
if (
(!active || assumedState) &&
stateObj.state !== UNAVAILABLE &&
!isUnavailableState(stateObj.state) &&
supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_ON)
) {
buttons.push({
@@ -4,7 +4,7 @@ import { computeDomain } from "../../../common/entity/compute_domain";
import { supportsFeature } from "../../../common/entity/supports-feature";
import { clamp } from "../../../common/number/clamp";
import "../../../components/ha-control-number-buttons";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import {
MediaPlayerEntityFeature,
type MediaPlayerEntity,
@@ -89,7 +89,7 @@ class HuiMediaPlayerVolumeButtonsCardFeature
}
const stateObj = this._stateObj;
const disabled = stateObj.state === UNAVAILABLE;
const disabled = isUnavailableState(stateObj.state);
const position =
stateObj.attributes.volume_level != null
@@ -4,7 +4,7 @@ import { computeDomain } from "../../../common/entity/compute_domain";
import { stateActive } from "../../../common/entity/state_active";
import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-control-slider";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import {
MediaPlayerEntityFeature,
type MediaPlayerEntity,
@@ -88,7 +88,7 @@ class HuiMediaPlayerVolumeSliderCardFeature
}
const stateObj = this._stateObj;
const disabled = stateObj.state === UNAVAILABLE;
const disabled = isUnavailableState(stateObj.state);
const position =
stateObj.attributes.volume_level != null
@@ -2,7 +2,6 @@ import type { PropertyValues } from "lit";
import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { computeDomain } from "../../../common/entity/compute_domain";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import "../../../components/ha-control-slider";
import { UNAVAILABLE } from "../../../data/entity/entity";
import type { HumidifierEntity } from "../../../data/humidifier";
@@ -85,9 +84,9 @@ class HuiTargetHumidityCardFeature
return this._stateObj!.attributes.max_humidity ?? 100;
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this._targetHumidity = value;
this._callService();
}
@@ -3,7 +3,6 @@ import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { UNIT_F } from "../../../common/const";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import { stateColorCss } from "../../../common/entity/state_color";
@@ -122,13 +121,10 @@ class HuiTargetTemperatureCardFeature
return this._stateObj!.attributes.max_temp;
}
private async _valueChanged(
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
const target =
(ev.currentTarget as HTMLElement & { target?: Target }).target ?? "value";
private async _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
const target = (ev.currentTarget as any).target ?? "value";
this._targetTemperature = {
...this._targetTemperature,
@@ -2,7 +2,6 @@ import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { computeCssColor } from "../../../common/color/compute-color";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { computeAttributeNameDisplay } from "../../../common/entity/compute_attribute_display";
import { computeDomain } from "../../../common/entity/compute_domain";
import { stateActive } from "../../../common/entity/state_active";
@@ -120,9 +119,9 @@ class HuiValvePositionCardFeature
`;
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this.hass!.callService("valve", "set_valve_position", {
entity_id: this._stateObj!.entity_id,
+4 -9
View File
@@ -32,7 +32,7 @@ import "../../../components/tile/ha-tile-badge";
import "../../../components/tile/ha-tile-container";
import "../../../components/tile/ha-tile-icon";
import "../../../components/tile/ha-tile-info";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import "../card-features/hui-card-features";
@@ -419,9 +419,7 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[area.temperature_entity_id] as
| HassEntity
| undefined;
return !stateObj ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN
return !stateObj || isUnavailableState(stateObj.state)
? ""
: this.hass.formatEntityState(stateObj);
}
@@ -429,9 +427,7 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[area.humidity_entity_id] as
| HassEntity
| undefined;
return !stateObj ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN
return !stateObj || isUnavailableState(stateObj.state)
? ""
: this.hass.formatEntityState(stateObj);
}
@@ -448,8 +444,7 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[entityId];
if (
stateObj &&
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN &&
!isUnavailableState(stateObj.state) &&
isNumericState(stateObj) &&
!isNaN(Number(stateObj.state))
) {
+2 -3
View File
@@ -9,7 +9,7 @@ import "../../../components/entity/state-badge";
import "../../../components/ha-card";
import "../../../components/ha-icon";
import "../../../components/ha-relative-time";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type {
CallServiceActionConfig,
@@ -293,8 +293,7 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
stateObj.attributes.device_class
) &&
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN
!isUnavailableState(stateObj.state)
? html`
<hui-timestamp-display
.hass=${this.hass}
+4 -4
View File
@@ -11,7 +11,7 @@ import { stateColorBrightness } from "../../../common/entity/state_color";
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
import "../../../components/ha-state-icon";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { UNAVAILABLE, isUnavailableState } from "../../../data/entity/entity";
import type { LightEntity } from "../../../data/light";
import { lightSupportsBrightness } from "../../../data/light";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
@@ -113,7 +113,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
min="1"
max="100"
.value=${brightness}
.disabled=${stateObj.state === UNAVAILABLE}
.disabled=${isUnavailableState(stateObj.state)}
@value-changing=${this._dragEvent}
@value-changed=${this._setBrightness}
style=${styleMap({
@@ -128,7 +128,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
"state-on": stateObj.state === "on",
"state-unavailable": stateObj.state === UNAVAILABLE,
})}"
.disabled=${stateObj.state === UNAVAILABLE}
.disabled=${isUnavailableState(stateObj.state)}
style=${styleMap({
filter: this._computeBrightness(stateObj),
color: this._computeColor(stateObj),
@@ -149,7 +149,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
</div>
<div id="info" .title=${name}>
${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
${isUnavailableState(stateObj.state)
? html` <div>${this.hass.formatEntityState(stateObj)}</div> `
: html` <div class="brightness">%</div> `}
${name}
@@ -21,7 +21,7 @@ import type { HaSlider } from "../../../components/ha-slider";
import "../../../components/ha-state-icon";
import { showJoinMediaPlayersDialog } from "../../../components/media-player/show-join-media-players-dialog";
import { showMediaBrowserDialog } from "../../../components/media-player/show-media-browser-dialog";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type {
MediaPickedEvent,
MediaPlayerEntity,
@@ -173,12 +173,9 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
const entityState = stateObj.state;
const isOffState =
!stateActive(stateObj) &&
entityState !== UNAVAILABLE &&
entityState !== UNKNOWN;
!stateActive(stateObj) && !isUnavailableState(entityState);
const isUnavailable =
entityState === UNAVAILABLE ||
entityState === UNKNOWN ||
isUnavailableState(entityState) ||
(isOffState &&
!supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_ON));
const hasNoImage = !this._image;
@@ -45,7 +45,7 @@ import "../../../components/ha-sortable";
import "../../../components/ha-svg-icon";
import "../../../components/input/ha-input";
import type { HaInput } from "../../../components/input/ha-input";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { TodoItem } from "../../../data/todo";
import {
TodoItemStatus,
@@ -383,8 +383,7 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
`;
}
const unavailable =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
const unavailable = isUnavailableState(stateObj.state);
// Discard memoization when we rollover to a new day, so filters can be recalculated
const memoTime = this._config.due_date_period
@@ -13,7 +13,7 @@ import { stringCompare } from "../../../../common/string/compare";
import "../../../../components/ha-spinner";
import "../../../../components/input/ha-input-search";
import type { HaInputSearch } from "../../../../components/input/ha-input-search";
import { UNAVAILABLE, UNKNOWN } from "../../../../data/entity/entity";
import { isUnavailableState } from "../../../../data/entity/entity";
import type { LovelaceBadgeConfig } from "../../../../data/lovelace/config/badge";
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
import type { CustomBadgeEntry } from "../../../../data/lovelace_custom_cards";
@@ -235,14 +235,12 @@ export class HuiBadgePicker extends LitElement {
this._usedEntities = [...usedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
!isUnavailableState(this.hass!.states[eid].state)
);
this._unusedEntities = [...unusedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
!isUnavailableState(this.hass!.states[eid].state)
);
this._loadBages();
@@ -13,7 +13,7 @@ import "../../../../components/ha-expansion-panel";
import "../../../../components/ha-spinner";
import "../../../../components/input/ha-input-search";
import type { HaInputSearch } from "../../../../components/input/ha-input-search";
import { UNAVAILABLE, UNKNOWN } from "../../../../data/entity/entity";
import { isUnavailableState } from "../../../../data/entity/entity";
import type { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
import type { LovelaceConfig } from "../../../../data/lovelace/config/types";
import type { CustomCardEntry } from "../../../../data/lovelace_custom_cards";
@@ -270,14 +270,12 @@ export class HuiCardPicker extends LitElement {
this._usedEntities = [...usedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
!isUnavailableState(this.hass!.states[eid].state)
);
this._unusedEntities = [...unusedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
!isUnavailableState(this.hass!.states[eid].state)
);
this._loadCards();
@@ -21,6 +21,7 @@ import { stopPropagation } from "../../../../common/dom/stop_propagation";
import { handleStructError } from "../../../../common/structs/handle-errors";
import "../../../../components/automation/ha-automation-row-event-chip";
import "../../../../components/automation/ha-automation-row-live-test";
import type { LiveTestState } from "../../../../components/automation/ha-automation-row-live-test";
import "../../../../components/ha-alert";
import "../../../../components/ha-card";
import "../../../../components/ha-dropdown";
@@ -105,10 +106,7 @@ export class HaCardConditionEditor extends LitElement {
@state() private _testingResult?: boolean;
@state() private _liveTestResult: {
state: "pass" | "fail" | "invalid" | "unknown";
message?: string;
} = { state: "unknown" };
@state() private _liveTestResult: LiveTestState = "unknown";
private _listeners = new ConditionListenersController(this);
@@ -177,7 +175,7 @@ export class HaCardConditionEditor extends LitElement {
private _evaluateLiveTest() {
if (!this.condition || !this._condition) {
this._liveTestResult = { state: "unknown" };
this._liveTestResult = "unknown";
return;
}
@@ -185,22 +183,12 @@ export class HaCardConditionEditor extends LitElement {
isNoEntityCondition(this._condition.condition, this._noEntity) ||
containsNoEntityCondition(this._condition, this._noEntity)
) {
this._liveTestResult = {
state: "unknown",
message: this.hass.localize(
"ui.panel.lovelace.editor.condition-editor.live_test_state.unknown"
),
};
this._liveTestResult = "unknown";
return;
}
if (!validateConditionalConfig([this.condition])) {
this._liveTestResult = {
state: "invalid",
message: this.hass.localize(
"ui.panel.lovelace.editor.condition-editor.live_test_state.invalid"
),
};
this._liveTestResult = "invalid";
return;
}
@@ -209,12 +197,7 @@ export class HaCardConditionEditor extends LitElement {
? { entity_id: this._entityContext.entityId }
: {};
const pass = checkConditionsMet([this.condition], this.hass, testContext);
this._liveTestResult = {
state: pass ? "pass" : "fail",
message: this.hass.localize(
`ui.panel.lovelace.editor.condition-editor.live_test_state.${pass ? "pass" : "fail"}`
),
};
this._liveTestResult = pass ? "pass" : "fail";
}
protected render() {
@@ -259,11 +242,10 @@ export class HaCardConditionEditor extends LitElement {
: html`
<ha-automation-row-live-test
slot="icons"
.state=${this._liveTestResult.state}
.state=${this._liveTestResult}
.label=${this.hass.localize(
`ui.panel.lovelace.editor.condition-editor.live_test_state.${this._liveTestResult.state}`
`ui.panel.lovelace.editor.condition-editor.live_test_state.${this._liveTestResult}`
)}
.message=${this._liveTestResult.message}
></ha-automation-row-live-test>
`}
<ha-dropdown
@@ -73,11 +73,11 @@ function computeBreakpointsKey(breakpoints) {
}
// Compute all possible media queries from each breakpoints combination (2 ^ breakpoints = 16)
const queries = getAllCombinations<Breakpoint>(BREAKPOINTS)
const queries = getAllCombinations(BREAKPOINTS as unknown as Breakpoint[])
.filter((arr) => arr.length !== 0)
.map(
(breakpoints) =>
[breakpoints, computeBreakpointsSize(breakpoints)] satisfies [
[breakpoints, computeBreakpointsSize(breakpoints)] as [
Breakpoint[],
string,
]
@@ -69,7 +69,7 @@ export class HuiAreaControlsCardFeatureEditor
return [];
}
const controlEntities = getAreaControlEntities(
AREA_CONTROL_DOMAINS,
AREA_CONTROL_DOMAINS as unknown as AreaControlDomain[],
areaId,
excludeEntities,
this.hass!
@@ -5,7 +5,7 @@ import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { computeStateName } from "../../../common/entity/compute_state_name";
import "../../../components/entity/ha-state-label-badge";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
@@ -36,7 +36,7 @@ export class HuiStateBadgeElement
const includeDomains = ["light", "switch", "sensor"];
const maxEntities = 1;
const entityFilter = (stateObj: HassEntity): boolean =>
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
!isUnavailableState(stateObj.state);
const foundEntities = findEntities(
hass,
maxEntities,
@@ -4,7 +4,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import "../../../components/entity/state-badge";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { computeTooltip } from "../common/compute-tooltip";
@@ -33,7 +33,7 @@ export class HuiStateIconElement extends LitElement implements LovelaceElement {
const includeDomains = ["light", "switch", "sensor"];
const maxEntities = 1;
const entityFilter = (stateObj: HassEntity): boolean =>
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
!isUnavailableState(stateObj.state);
const foundEntities = findEntities(
hass,
maxEntities,
@@ -3,7 +3,7 @@ import type { PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { computeTooltip } from "../common/compute-tooltip";
@@ -32,7 +32,7 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement {
const includeDomains = ["light", "switch", "sensor"];
const maxEntities = 1;
const entityFilter = (stateObj: HassEntity): boolean =>
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
!isUnavailableState(stateObj.state);
const foundEntities = findEntities(
hass,
maxEntities,
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-date-input";
import { setDateValue } from "../../../data/date";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -49,7 +49,7 @@ class HuiDateEntityRow extends LitElement implements LovelaceRow {
<ha-date-input
.locale=${this.hass.locale}
.disabled=${unavailable}
.value=${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
.value=${isUnavailableState(stateObj.state)
? undefined
: stateObj.state}
@value-changed=${this._dateChanged}
@@ -5,7 +5,7 @@ import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-date-input";
import "../../../components/ha-time-input";
import { setDateTimeValue } from "../../../data/datetime";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -46,10 +46,9 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
const unavailable = stateObj.state === UNAVAILABLE;
const dateObj =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
? undefined
: new Date(stateObj.state);
const dateObj = isUnavailableState(stateObj.state)
? undefined
: new Date(stateObj.state);
const time = dateObj ? format(dateObj, "HH:mm:ss") : undefined;
const date = dateObj ? format(dateObj, "yyyy-MM-dd") : undefined;
@@ -1,7 +1,7 @@
import type { PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import type { EntitiesCardEntityConfig } from "../cards/types";
@@ -51,9 +51,6 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
`;
}
const noValue =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
return html`
<hui-generic-entity-row
.hass=${this.hass}
@@ -68,7 +65,7 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
})}
>
<div class="when">
${noValue
${isUnavailableState(stateObj.state)
? this.hass.formatEntityState(stateObj)
: html`<hui-timestamp-display
.hass=${this.hass}
@@ -78,7 +75,7 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
></hui-timestamp-display>`}
</div>
<div class="what">
${noValue
${isUnavailableState(stateObj.state)
? nothing
: this.hass.formatEntityAttributeValue(stateObj, "event_type")}
</div>
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/input/ha-input";
import type { HaInput } from "../../../components/input/ha-input";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { setValue } from "../../../data/input_text";
import type { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
@@ -74,7 +74,7 @@ class HuiInputTextEntityRow extends LitElement implements LovelaceRow {
const newValue = target.value ?? "";
// Filter out invalid text states
if (newValue && (newValue === UNAVAILABLE || newValue === UNKNOWN)) {
if (newValue && isUnavailableState(newValue)) {
target.value = stateObj.state;
return;
}
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-button";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import { callProtectedLockService } from "../../../data/lock";
import type { HomeAssistant } from "../../../types";
import { confirmAction } from "../common/confirm-action";
@@ -49,7 +49,7 @@ class HuiLockEntityRow extends LitElement implements LovelaceRow {
appearance="plain"
size="small"
@click=${this._callService}
.disabled=${stateObj.state === UNAVAILABLE}
.disabled=${isUnavailableState(stateObj.state)}
class="text-content"
>
${stateObj.state === "locked"
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-button";
import { UNAVAILABLE } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { ScriptEntity } from "../../../data/script";
import { canRun, hasScriptFields } from "../../../data/script";
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
@@ -68,7 +68,8 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
appearance="plain"
size="small"
@click=${this._runScript}
.disabled=${stateObj.state === UNAVAILABLE || !canRun(stateObj)}
.disabled=${isUnavailableState(stateObj.state) ||
!canRun(stateObj)}
>
${this._config.action_name ||
this.hass!.localize("ui.card.script.run")}
@@ -1,7 +1,7 @@
import type { PropertyValues } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import {
SENSOR_DEVICE_CLASS_UPTIME,
SENSOR_TIMESTAMP_DEVICE_CLASSES,
@@ -55,9 +55,7 @@ class HuiSensorEntityRow extends LitElement implements LovelaceRow {
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
${SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
stateObj.attributes.device_class
) &&
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN
) && !isUnavailableState(stateObj.state)
? html`
<hui-timestamp-display
.hass=${this.hass}
@@ -3,7 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/input/ha-input";
import type { HaInput } from "../../../components/input/ha-input";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import type { TextEntity } from "../../../data/text";
import { setValue } from "../../../data/text";
import type { HomeAssistant } from "../../../types";
@@ -76,7 +76,7 @@ class HuiTextEntityRow extends LitElement implements LovelaceRow {
const newValue = target.value ?? "";
// Filter out invalid text states
if (newValue && (newValue === UNAVAILABLE || newValue === UNKNOWN)) {
if (newValue && isUnavailableState(newValue)) {
target.value = stateObj.state;
return;
}
@@ -3,7 +3,7 @@ import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-date-input";
import "../../../components/ha-time-input";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { setTimeValue } from "../../../data/time";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
@@ -48,7 +48,7 @@ class HuiTimeEntityRow extends LitElement implements LovelaceRow {
return html`
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
<ha-time-input
.value=${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
.value=${isUnavailableState(stateObj.state)
? undefined
: stateObj.state}
.locale=${this.hass.locale}
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/entity/ha-entity-toggle";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -44,8 +44,7 @@ class HuiToggleEntityRow extends LitElement implements LovelaceRow {
const showToggle =
stateObj.state === "on" ||
stateObj.state === "off" ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN;
isUnavailableState(stateObj.state);
return html`
<hui-generic-entity-row
@@ -2,7 +2,7 @@ import type { PropertyValues } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/entity/ha-entity-toggle";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -44,8 +44,7 @@ class HuiValveEntityRow extends LitElement implements LovelaceRow {
const showToggle =
stateObj.state === "open" ||
stateObj.state === "closed" ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN;
isUnavailableState(stateObj.state);
return html`
<hui-generic-entity-row
@@ -3,7 +3,7 @@ import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { ifDefined } from "lit/directives/if-defined";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { isUnavailableState } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { ForecastEvent, WeatherEntity } from "../../../data/weather";
import {
@@ -193,8 +193,7 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
})}
>
<div>
${stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN ||
${isUnavailableState(stateObj.state) ||
stateObj.attributes.temperature === undefined ||
stateObj.attributes.temperature === null
? this.hass.formatEntityState(stateObj)
@@ -3,7 +3,6 @@ import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import memoizeOne from "memoize-one";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { stateColorCss } from "../../common/entity/state_color";
import { supportsFeature } from "../../common/entity/supports-feature";
import "../../components/ha-control-select";
@@ -56,10 +55,8 @@ export class HaStateControlAlarmControlPanelModes extends LitElement {
);
}
private async _valueChanged(
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
) {
const mode = ev.detail.value as AlarmMode;
private async _valueChanged(ev: CustomEvent) {
const mode = (ev.detail as any).value as AlarmMode;
if (mode === this.stateObj!.state) return;
@@ -3,7 +3,6 @@ import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, html } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { stateActive } from "../../common/entity/state_active";
import { domainStateColorProperties } from "../../common/entity/state_color";
import { supportsFeature } from "../../common/entity/supports-feature";
@@ -58,16 +57,16 @@ export class HaStateControlClimateHumidity extends LitElement {
return this.stateObj.attributes.max_humidity ?? 100;
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this._targetHumidity = value;
this._callService();
}
private _valueChanging(ev: HASSDomEvent<HASSDomEvents["value-changing"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanging(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this._targetHumidity = value;
}
@@ -5,7 +5,6 @@ import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { UNIT_F } from "../../common/const";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { stateActive } from "../../common/entity/state_active";
import { stateColorCss } from "../../common/entity/state_color";
import { supportsFeature } from "../../common/entity/supports-feature";
@@ -89,9 +88,9 @@ export class HaStateControlClimateTemperature extends LitElement {
return this.stateObj.attributes.max_temp;
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
const target = ev.type.replace("-changed", "");
this._targetTemperature = {
...this._targetTemperature,
@@ -101,9 +100,9 @@ export class HaStateControlClimateTemperature extends LitElement {
this._callService(target);
}
private _valueChanging(ev: HASSDomEvent<HASSDomEvents["value-changing"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanging(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
const target = ev.type.replace("-changing", "");
this._targetTemperature = {
...this._targetTemperature,
@@ -3,7 +3,6 @@ import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { computeAttributeNameDisplay } from "../../common/entity/compute_attribute_display";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { stateColorCss } from "../../common/entity/state_color";
import "../../components/ha-control-slider";
import type { CoverEntity } from "../../data/cover";
@@ -27,9 +26,9 @@ export class HaStateControlCoverPosition extends LitElement {
}
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this.hass.callService("cover", "set_cover_position", {
entity_id: this.stateObj!.entity_id,
@@ -3,7 +3,6 @@ import { css, html, LitElement, unsafeCSS } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { computeAttributeNameDisplay } from "../../common/entity/compute_attribute_display";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { stateColorCss } from "../../common/entity/state_color";
import "../../components/ha-control-slider";
import type { CoverEntity } from "../../data/cover";
@@ -57,9 +56,9 @@ export class HaStateControlInfoCoverTiltPosition extends LitElement {
}
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this.hass.callService("cover", "set_cover_tilt_position", {
entity_id: this.stateObj!.entity_id,
@@ -3,7 +3,6 @@ import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { computeAttributeNameDisplay } from "../../common/entity/compute_attribute_display";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { stateActive } from "../../common/entity/state_active";
import { stateColorCss } from "../../common/entity/state_color";
import "../../components/ha-control-select";
@@ -42,8 +41,8 @@ export class HaStateControlFanSpeed extends LitElement {
}
}
private _speedValueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const speed = ev.detail.value as FanSpeed;
private _speedValueChanged(ev: CustomEvent) {
const speed = (ev.detail as any).value as FanSpeed;
this.speedValue = speed;
@@ -55,9 +54,9 @@ export class HaStateControlFanSpeed extends LitElement {
});
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this.sliderValue = value;
@@ -3,7 +3,6 @@ import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { stateActive } from "../../common/entity/state_active";
import { stateColorCss } from "../../common/entity/state_color";
import { clamp } from "../../common/number/clamp";
@@ -63,16 +62,16 @@ export class HaStateControlHumidifierHumidity extends LitElement {
return this.stateObj.attributes.max_humidity ?? 100;
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this._targetHumidity = value;
this._callService();
}
private _valueChanging(ev: HASSDomEvent<HASSDomEvents["value-changing"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanging(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this._targetHumidity = value;
}
@@ -3,7 +3,6 @@ import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { hsv2rgb, rgb2hex, rgb2hsv } from "../../common/color/convert-color";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { stateActive } from "../../common/entity/state_active";
import { stateColorCss } from "../../common/entity/state_color";
import "../../components/ha-control-slider";
@@ -31,9 +30,9 @@ export class HaStateControlLightBrightness extends LitElement {
}
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this.hass.callService("light", "turn_on", {
entity_id: this.stateObj!.entity_id,
@@ -3,7 +3,6 @@ import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { computeAttributeNameDisplay } from "../../common/entity/compute_attribute_display";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { stateColorCss } from "../../common/entity/state_color";
import "../../components/ha-control-slider";
import type { CoverEntity } from "../../data/cover";
@@ -27,9 +26,9 @@ export class HaStateControlValvePosition extends LitElement {
}
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this.hass.callService("valve", "set_valve_position", {
entity_id: this.stateObj!.entity_id,
@@ -4,7 +4,6 @@ import { LitElement, html } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { UNIT_F } from "../../common/const";
import type { HASSDomEvent } from "../../common/dom/fire_event";
import { stateActive } from "../../common/entity/state_active";
import { stateColorCss } from "../../common/entity/state_color";
import { supportsFeature } from "../../common/entity/supports-feature";
@@ -61,16 +60,16 @@ export class HaStateControlWaterHeaterTemperature extends LitElement {
return this.stateObj.attributes.max_temp;
}
private _valueChanged(ev: HASSDomEvent<HASSDomEvents["value-changed"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this._targetTemperature = value;
this._callService();
}
private _valueChanging(ev: HASSDomEvent<HASSDomEvents["value-changing"]>) {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _valueChanging(ev: CustomEvent) {
const value = (ev.detail as any).value;
if (isNaN(value)) return;
this._targetTemperature = value;
}
+3 -5
View File
@@ -7,7 +7,7 @@ import { ensureArray } from "../common/array/ensure-array";
import { computeStateDomain } from "../common/entity/compute_state_domain";
import { STRINGS_SEPARATOR_DOT } from "../common/const";
import "../components/ha-relative-time";
import { UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import { isUnavailableState } from "../data/entity/entity";
import {
SENSOR_TIMESTAMP_DEVICE_CLASSES,
SENSOR_DEVICE_CLASS_UPTIME,
@@ -89,9 +89,7 @@ class StateDisplay extends LitElement {
const domain = computeStateDomain(stateObj);
if (content === "state") {
const noValue =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
if (this.dashUnavailable && noValue) {
if (this.dashUnavailable && isUnavailableState(stateObj.state)) {
return "—";
}
if (
@@ -99,7 +97,7 @@ class StateDisplay extends LitElement {
this.stateObj.attributes.device_class
) ||
TIMESTAMP_STATE_DOMAINS.includes(domain)) &&
!noValue
!isUnavailableState(stateObj.state)
) {
return html`
<hui-timestamp-display
+2 -3
View File
@@ -5,7 +5,7 @@ import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { computeDomain } from "../common/entity/compute_domain";
import "../components/entity/state-info";
import { UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import { isUnavailableState } from "../data/entity/entity";
import {
SENSOR_TIMESTAMP_DEVICE_CLASSES,
SENSOR_DEVICE_CLASS_UPTIME,
@@ -44,8 +44,7 @@ class StateCardDisplay extends LitElement {
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
this.stateObj.attributes.device_class
) &&
this.stateObj.state !== UNAVAILABLE &&
this.stateObj.state !== UNKNOWN
!isUnavailableState(this.stateObj.state)
? html`<hui-timestamp-display
.hass=${this.hass}
.ts=${new Date(this.stateObj.state)}
+3 -2
View File
@@ -5,7 +5,7 @@ import { customElement, property } from "lit/decorators";
import "../components/entity/ha-entity-toggle";
import "../components/entity/state-info";
import "../components/ha-button";
import { UNAVAILABLE } from "../data/entity/entity";
import { isUnavailableState } from "../data/entity/entity";
import type { ScriptEntity } from "../data/script";
import { canRun, hasScriptFields } from "../data/script";
import { showMoreInfoDialog } from "../dialogs/more-info/show-ha-more-info-dialog";
@@ -48,7 +48,8 @@ class StateCardScript extends LitElement {
appearance="plain"
size="small"
@click=${this._runScript}
.disabled=${stateObj.state === UNAVAILABLE || !canRun(stateObj)}
.disabled=${isUnavailableState(stateObj.state) ||
!canRun(stateObj)}
>
${this.hass!.localize("ui.card.script.run")}
</ha-button>`
+2 -2
View File
@@ -6,7 +6,7 @@ import { computeStateName } from "../common/entity/compute_state_name";
import "../components/entity/state-badge";
import "../components/input/ha-input";
import type { HaInput } from "../components/input/ha-input";
import { UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import { isUnavailableState, UNAVAILABLE } from "../data/entity/entity";
import type { TextEntity } from "../data/text";
import { setValue } from "../data/text";
import type { HomeAssistant } from "../types";
@@ -40,7 +40,7 @@ class StateCardText extends LitElement {
const value = (ev.target as HaInput).value ?? "";
// Filter out invalid text states
if (value && (value === UNAVAILABLE || value === UNKNOWN)) {
if (value && isUnavailableState(value)) {
(ev.target as HaInput).value = this.stateObj.state;
return;
}
-7
View File
@@ -1694,13 +1694,6 @@
"last_triggered": "Last triggered"
},
"add_to": {
"actions": {
"automation_trigger": "Create new automation using {entity} as a trigger",
"automation_condition": "Create new automation using {entity} as a condition",
"automation_action": "Create new automation using {entity} in an action",
"script_action": "Create new script using {entity} in an action"
},
"app_actions": "App actions",
"no_actions": "No actions available",
"action_failed": "Failed to perform the action {error}"
},
+110 -120
View File
@@ -4125,151 +4125,141 @@ __metadata:
languageName: node
linkType: hard
"@tsparticles/basic@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/basic@npm:4.0.2"
"@tsparticles/basic@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/basic@npm:4.0.1"
dependencies:
"@tsparticles/engine": "npm:4.0.2"
"@tsparticles/plugin-hex-color": "npm:4.0.2"
"@tsparticles/plugin-hsl-color": "npm:4.0.2"
"@tsparticles/plugin-move": "npm:4.0.2"
"@tsparticles/plugin-rgb-color": "npm:4.0.2"
"@tsparticles/shape-circle": "npm:4.0.2"
"@tsparticles/updater-opacity": "npm:4.0.2"
"@tsparticles/updater-out-modes": "npm:4.0.2"
"@tsparticles/updater-paint": "npm:4.0.2"
"@tsparticles/updater-size": "npm:4.0.2"
checksum: 10/298979c82cc3a29f9b7a79c5f9521f2a46d51faf4b3374e0608c5f192c273432f13d29c6651329ad895497f23934d34bc8880fa156926dd29068ab634836d89f
"@tsparticles/engine": "npm:4.0.1"
"@tsparticles/plugin-hex-color": "npm:4.0.1"
"@tsparticles/plugin-hsl-color": "npm:4.0.1"
"@tsparticles/plugin-move": "npm:4.0.1"
"@tsparticles/plugin-rgb-color": "npm:4.0.1"
"@tsparticles/shape-circle": "npm:4.0.1"
"@tsparticles/updater-opacity": "npm:4.0.1"
"@tsparticles/updater-out-modes": "npm:4.0.1"
"@tsparticles/updater-paint": "npm:4.0.1"
"@tsparticles/updater-size": "npm:4.0.1"
checksum: 10/693774cc82938763017a5797593ebd372e449150c907be35f59682a344d4764039b0495b5e09dbbf8907ce57a36c8593ac94c05421d80e20d9b7b4576884c92c
languageName: node
linkType: hard
"@tsparticles/canvas-utils@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/canvas-utils@npm:4.0.2"
"@tsparticles/engine@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/engine@npm:4.0.1"
checksum: 10/727d044de30145a7f4244c266b74ee40ee7a6ac9e0ab637b99908effd73cd929a6db16255db5d4b04d24538ba4556945a09bc685d49a24f3b9201ab453ccd6a6
languageName: node
linkType: hard
"@tsparticles/interaction-particles-links@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/interaction-particles-links@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/f4b16aafa66885e3bc79acd026e331376338581946ccf294563010887e10b67ff43526deeead8e1a79f4cd54100a27e3ed4b5618be7153687f36c587fcd48c36
"@tsparticles/canvas-utils": 4.0.1
"@tsparticles/engine": 4.0.1
"@tsparticles/plugin-interactivity": 4.0.1
checksum: 10/74097c18f958eabf753b2d3bb299a7bfcca8468e195d0791122ef7a88ec6424e4f1726960eaa877459be72d414d5312740240f93a8e3ada8dc88d887369d9b09
languageName: node
linkType: hard
"@tsparticles/engine@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/engine@npm:4.0.2"
checksum: 10/b0d9a2939492352c4ed4ae1872859e2ee682bd949a8e4de1286035d3f9adb25e3fbfe5cab72c4b29c0d44a69a19347879c7bf3055580076bb5b29a435a20024c
"@tsparticles/plugin-hex-color@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/plugin-hex-color@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.1
checksum: 10/e2e9970322049f6df59a315b2bbfd86ee3dc447a844e119f4c38e5224ba359e597edc610da7946f8dfe628184bc5935542f6bf6b043ab94623427281b2eb7f72
languageName: node
linkType: hard
"@tsparticles/interaction-particles-links@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/interaction-particles-links@npm:4.0.2"
"@tsparticles/plugin-hsl-color@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/plugin-hsl-color@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.1
checksum: 10/f14168d72d112011c237605f1bb7384c874b72101ec9ae75ff521f25e2f71f29d5678af8d3b63bec94db439faeffbb4ecfd3aece01904ab0b14aa4c0e455fcac
languageName: node
linkType: hard
"@tsparticles/plugin-interactivity@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/plugin-interactivity@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.1
checksum: 10/85963f34314faf0db1aa75267c48f13da43ef388c3fc090d2cec347d9b31a7e1a89adf1fca390509b474cfd3cdae3d04b91c15e248461de2b489d56239285410
languageName: node
linkType: hard
"@tsparticles/plugin-move@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/plugin-move@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.1
checksum: 10/9b50ca6467b19cc89b12dfbdfed08fde52780e458ec2166c9d3bd6daac4bd48d1762bef674b5a3bc5be190caa99d644201792992dce35015a2100b9019b64b1c
languageName: node
linkType: hard
"@tsparticles/plugin-rgb-color@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/plugin-rgb-color@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.1
checksum: 10/f435e46d564fb22177b9516ff1a01912b2cc6cdc2b8217316d7c6ff6097acf4ee0cd60e6660e26c0da2321f1a57e469e1ec344045fb4f95f69818e63b7c4c56f
languageName: node
linkType: hard
"@tsparticles/preset-links@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/preset-links@npm:4.0.1"
dependencies:
"@tsparticles/canvas-utils": "npm:4.0.2"
peerDependencies:
"@tsparticles/engine": 4.0.2
"@tsparticles/plugin-interactivity": 4.0.2
checksum: 10/8c7f6086764f0ed65e8bec764b9c0c00653c77cdb9baafd6c7241832cbea7f30834c7c14da80c1566e85ecc74456a98990f0d5836dfd65768f14cdfe237aa17c
"@tsparticles/basic": "npm:4.0.1"
"@tsparticles/engine": "npm:4.0.1"
"@tsparticles/interaction-particles-links": "npm:4.0.1"
"@tsparticles/plugin-interactivity": "npm:4.0.1"
checksum: 10/ef046ef9f384d2af62d5b237cf2f5f4d0373b49bb6ca1c3fdd20b8b58a2a2ebf2af58a2af2ed4b6ba4d8bdf81e7280f6332b46d17b95dd95bf104063e8ee6478
languageName: node
linkType: hard
"@tsparticles/plugin-hex-color@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/plugin-hex-color@npm:4.0.2"
"@tsparticles/shape-circle@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/shape-circle@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/bc46c9c202ea1c617366175f2bc9c863b0b276f6404f33826049263631ca6cbfa0b78412c30e6ea78675624948dc1e6ee7720ab14dcdf71dbd6e29cb4363b09a
"@tsparticles/engine": 4.0.1
checksum: 10/f602034fd7dcc635b68b4065600f0a23dbecf3893354a7247132d2874657ac0ea2407292f7c75bad20b2db7f13ec14cb8e8e3ff3f9dce90727f5b1e8e81e59d7
languageName: node
linkType: hard
"@tsparticles/plugin-hsl-color@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/plugin-hsl-color@npm:4.0.2"
"@tsparticles/updater-opacity@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/updater-opacity@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/194bc7c997889e25d8fc80e9ddcb6047de9e19cf6c1b0df0c71e79b1b246c3d5c69688a6525fb631ce62bdd121f76dc8f97ebadf91dd89e6f9c59e7ca6b85029
"@tsparticles/engine": 4.0.1
checksum: 10/6d769e3fb36a33d553e4b32c35f8450bb72e6e995bfeb6ad493c17079201ee1b9c6a611aabd44b85a6e3990e2481a71d00a2710fdee72895c4c25a473c9db299
languageName: node
linkType: hard
"@tsparticles/plugin-interactivity@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/plugin-interactivity@npm:4.0.2"
"@tsparticles/updater-out-modes@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/updater-out-modes@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/72a2303b15de64d319c493dfd79533d352cda11d43c69d74e67227e02a20f5326a5b4739717e962807aad573b25a0735b015d82e4cd01f33ed21817caeeb4d6c
"@tsparticles/engine": 4.0.1
checksum: 10/0eb2e1e2a4480bc490ae82cf853a3dad26419b3812acf0d20b65868d6e633f2faf453f332f7d6a85779ae59dad1cbb2c94426f7ce43dccea9173ef8032911726
languageName: node
linkType: hard
"@tsparticles/plugin-move@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/plugin-move@npm:4.0.2"
"@tsparticles/updater-paint@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/updater-paint@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/eb3f2dfec34c8486e3a3dd598c6c77bd58fd84cab4705565df470219cd350d23bd1bfa508f235bca389850c457455f2438496e228c0908c88aeabb840e6eae41
"@tsparticles/engine": 4.0.1
checksum: 10/add5a658e70aa19ea0220ba73249408f845800bb015cbbdb365d99d0be1a732559dba869090166c3ef45ca93a55f982aafb39e20c66d63e55bfca61e78dd2f51
languageName: node
linkType: hard
"@tsparticles/plugin-rgb-color@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/plugin-rgb-color@npm:4.0.2"
"@tsparticles/updater-size@npm:4.0.1":
version: 4.0.1
resolution: "@tsparticles/updater-size@npm:4.0.1"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/05ef1a16e3fd01859987943d5c1362d60f14ef98e9b076e9f61b18a74982bbbe63e73f9c8c5df50f1dd306e9af41d16593712648615c50f89386e76c2bac6451
languageName: node
linkType: hard
"@tsparticles/preset-links@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/preset-links@npm:4.0.2"
dependencies:
"@tsparticles/basic": "npm:4.0.2"
"@tsparticles/engine": "npm:4.0.2"
"@tsparticles/interaction-particles-links": "npm:4.0.2"
"@tsparticles/plugin-interactivity": "npm:4.0.2"
checksum: 10/3656f49a731949695c596fd4c39cab24b4c839c3773468967c33d0be48ba766188c921eeb883349c6f292967a73dccb40e8f323388321c64539ba7b966a62d90
languageName: node
linkType: hard
"@tsparticles/shape-circle@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/shape-circle@npm:4.0.2"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/a083f2819a4d0d5069efef4bc7e62660691a2a6d2dd0e1e0ec8213c536873d98e6aa51afcd7d78405302dfe2d316e9300d5beb3b11fb6102173ec09fc727f4bb
languageName: node
linkType: hard
"@tsparticles/updater-opacity@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/updater-opacity@npm:4.0.2"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/a144095e6a8496969cc329c34b717b204813f2e71f00691ac8f5be13551e5fa796a1269f5c9f1688e4f3df6057f485e140d1d7a10bd5d8e502736e78d3094463
languageName: node
linkType: hard
"@tsparticles/updater-out-modes@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/updater-out-modes@npm:4.0.2"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/95e83a66441d83b1f4a3d9c367b5b8d24c8ad6f9b0e5517c30b9f80d02f007e6d28875489bfdcface93d19b0325cbb0d23c69c5d3f3cba213a34623b9d195e32
languageName: node
linkType: hard
"@tsparticles/updater-paint@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/updater-paint@npm:4.0.2"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/3a829e61adebd375474065f7d3486c2768d977f5bfadf642b9c056874aa488f842409a49873c454e699d3fd0bf4c633f236a40baa83005bb0e63622155bf7be5
languageName: node
linkType: hard
"@tsparticles/updater-size@npm:4.0.2":
version: 4.0.2
resolution: "@tsparticles/updater-size@npm:4.0.2"
peerDependencies:
"@tsparticles/engine": 4.0.2
checksum: 10/dcce6579bb06319c8c520640e9ffc572ac38bbd4aa7d1a8077e54468cb5011e6c4fef9fc54c044a0ab3bdbdc916616feb1f4960ad0c9b19270bf420ea1f7ae8e
"@tsparticles/engine": 4.0.1
checksum: 10/87a118066f97a21af99db8ecbba7de44e6ff758a5cded33cd2ac68ce0cdca0f9be4ddacdb185af46ac25f00e6e52fe0777530c10a168360385bb8ee93152f35c
languageName: node
linkType: hard
@@ -8602,8 +8592,8 @@ __metadata:
"@rspack/dev-server": "npm:2.0.1"
"@swc/helpers": "npm:0.5.21"
"@thomasloven/round-slider": "npm:0.6.0"
"@tsparticles/engine": "npm:4.0.2"
"@tsparticles/preset-links": "npm:4.0.2"
"@tsparticles/engine": "npm:4.0.1"
"@tsparticles/preset-links": "npm:4.0.1"
"@types/babel__plugin-transform-runtime": "npm:7.9.5"
"@types/chromecast-caf-receiver": "npm:6.0.26"
"@types/chromecast-caf-sender": "npm:1.0.11"
@@ -8675,7 +8665,7 @@ __metadata:
leaflet-draw: "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch"
leaflet.markercluster: "npm:1.5.3"
license-checker-rseidelsohn: "npm:4.4.2"
lint-staged: "npm:17.0.5"
lint-staged: "npm:17.0.4"
lit: "npm:3.3.3"
lit-analyzer: "npm:2.0.3"
lit-html: "npm:3.3.3"
@@ -10082,9 +10072,9 @@ __metadata:
languageName: node
linkType: hard
"lint-staged@npm:17.0.5":
version: 17.0.5
resolution: "lint-staged@npm:17.0.5"
"lint-staged@npm:17.0.4":
version: 17.0.4
resolution: "lint-staged@npm:17.0.4"
dependencies:
listr2: "npm:^10.2.1"
picomatch: "npm:^4.0.4"
@@ -10096,7 +10086,7 @@ __metadata:
optional: true
bin:
lint-staged: bin/lint-staged.js
checksum: 10/a0bea43689d68ec0bf6a56943884dbdb96b6b49e2677bf80654d802678b2edf9fc65338ca8ef3fc310f245933ea2a809db1ac94431dc445c57a4d49620d9d4da
checksum: 10/a9b1bf30450523ea301e6d95782963f3b94fc7dd012647a523fa494f072aa046f2e60d854885bb9f909bf69b6bf2e02d70ddc42553a8ead9307532688005f64c
languageName: node
linkType: hard