Compare commits

..

2 Commits

Author SHA1 Message Date
Paul Bottein 2aa1c99117 Distinguish unknown from unavailable entity state 2026-05-18 12:52:38 +02:00
Paulus Schoutsen defad3beca Treat media player unknown state like off instead of unavailable (#52080)
* Show both power buttons for assumed-state media players when unknown

Media players with assumed state report an unknown state when their
actual power state can't be determined. In that case the entity row and
more info should still expose both turn on and turn off controls so the
user can operate the device.

https://claude.ai/code/session_01JyZojNPCCY65HmRVQaASkG

* Treat media player unknown state like off instead of unavailable

The media player controls lumped the "unknown" state in with
"unavailable" and hid all controls. An unknown state is closer to "off":
the device exists but its power state isn't reported, which is common
for assumed-state players. Only "unavailable" should hide the controls,
so an unknown-state player now shows the turn on button (and both power
buttons when it has an assumed state) in the entity row and more info.

https://claude.ai/code/session_01JyZojNPCCY65HmRVQaASkG

* Adjust comments and variable placement for media player state check

https://claude.ai/code/session_01JyZojNPCCY65HmRVQaASkG

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-18 09:58:01 +03:00
87 changed files with 251 additions and 871 deletions
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { isUnavailableState } from "../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import type { HomeAssistant } from "../../types";
interface EntityUnitStubConfig {
@@ -21,32 +21,24 @@ export const computeEntityUnitDisplay = (
stateObj: HassEntity | undefined,
config: EntityUnitStubConfig
): string => {
let unit;
if (
stateObj &&
!isUnavailableState(stateObj.state) &&
(config.attribute || stateObj.attributes.device_class !== "duration")
!stateObj ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN ||
(!config.attribute && stateObj.attributes.device_class === "duration")
) {
// 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 ?? "";
return "";
}
return "";
// 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 ?? "";
};
+2 -2
View File
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE_STATES } from "../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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_STATES);
result.push(UNAVAILABLE, UNKNOWN);
}
if (!attribute && domain in FIXED_DOMAIN_STATES) {
+11 -5
View File
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { isUnavailableState, UNAVAILABLE } from "../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import type { HomeAssistant } from "../../types";
import { computeStateDomain } from "./compute_state_domain";
@@ -8,14 +8,20 @@ export const computeGroupEntitiesState = (states: HassEntity[]): string => {
return UNAVAILABLE;
}
const validState = states.some(
(stateObj) => !isUnavailableState(stateObj.state)
const allUnavailable = states.every(
(stateObj) => stateObj.state === UNAVAILABLE
);
if (!validState) {
if (allUnavailable) {
return UNAVAILABLE;
}
const hasValidState = states.some(
(stateObj) => stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN
);
if (!hasValidState) {
return UNKNOWN;
}
// Use the first state to determine the domain
// This assumes all states in the group have the same domain
const domain = computeStateDomain(states[0]);
+2 -2
View File
@@ -1,5 +1,5 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { isUnavailableState, OFF, UNAVAILABLE } from "../../data/entity/entity";
import { OFF, UNAVAILABLE, UNKNOWN } 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 (isUnavailableState(compareState)) {
if (compareState === UNAVAILABLE || compareState === UNKNOWN) {
return false;
}
+3 -6
View File
@@ -6,11 +6,7 @@ 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,
isUnavailableState,
} from "../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import { forwardHaptic } from "../../data/haptics";
import type { HomeAssistant } from "../../types";
import "../ha-formfield";
@@ -20,7 +16,8 @@ import "../ha-switch";
const isOn = (stateObj?: HassEntity) =>
stateObj !== undefined &&
!STATES_OFF.includes(stateObj.state) &&
!isUnavailableState(stateObj.state);
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN;
/**
* @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 { isUnavailableState, UNAVAILABLE } from "../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import type { EntityRegistryDisplayEntry } from "../../data/entity/entity_registry";
import { timerTimeRemaining } from "../../data/timer";
import type { HomeAssistant } from "../../types";
@@ -170,7 +170,8 @@ export class HaStateLabelBadge extends LitElement {
}
// eslint-disable-next-line: disable=no-fallthrough
default:
return isUnavailableState(entityState.state)
return entityState.state === UNAVAILABLE ||
entityState.state === UNKNOWN
? "—"
: this.hass!.formatEntityStateToParts(entityState).find(
(part) => part.type === "value"
@@ -209,7 +210,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 (isUnavailableState(entityState.state)) {
if (entityState.state === UNAVAILABLE || entityState.state === UNKNOWN) {
return this.hass!.localize(`state_badge.default.${entityState.state}`);
}
const domainStateKey = getTruncatedKey(domain, entityState.state);
+9 -4
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 { isUnavailableState, OFF } from "../data/entity/entity";
import { OFF, UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import type { HomeAssistant } from "../types";
@customElement("ha-climate-state")
@@ -14,9 +14,11 @@ 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">
${!isUnavailableState(this.stateObj.state)
${!noValue
? html`<span class="state-label">
${this._localizeState()}
${this.stateObj.attributes.preset_mode &&
@@ -32,7 +34,7 @@ class HaClimateState extends LitElement {
: this._localizeState()}
</div>
${currentStatus && !isUnavailableState(this.stateObj.state)
${currentStatus && !noValue
? html`
<div class="current">
${this.hass.localize("ui.card.climate.currently")}:
@@ -119,7 +121,10 @@ class HaClimateState extends LitElement {
}
private _localizeState(): string {
if (isUnavailableState(this.stateObj.state)) {
if (
this.stateObj.state === UNAVAILABLE ||
this.stateObj.state === UNKNOWN
) {
return this.hass.localize(`state.default.${this.stateObj.state}`);
}
+9 -4
View File
@@ -1,7 +1,7 @@
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { isUnavailableState, OFF } from "../data/entity/entity";
import { OFF, UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import type { HumidifierEntity } from "../data/humidifier";
import type { HomeAssistant } from "../types";
@@ -13,9 +13,11 @@ 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">
${!isUnavailableState(this.stateObj.state)
${!noValue
? html`<span class="state-label">
${this._localizeState()}
${this.stateObj.attributes.mode
@@ -30,7 +32,7 @@ class HaHumidifierState extends LitElement {
: this._localizeState()}
</div>
${currentStatus && !isUnavailableState(this.stateObj.state)
${currentStatus && !noValue
? html`<div class="current">
${this.hass.localize("ui.card.humidifier.currently")}:
<div class="unit">${currentStatus}</div>
@@ -69,7 +71,10 @@ class HaHumidifierState extends LitElement {
}
private _localizeState(): string {
if (isUnavailableState(this.stateObj.state)) {
if (
this.stateObj.state === UNAVAILABLE ||
this.stateObj.state === UNKNOWN
) {
return this.hass.localize(`state.default.${this.stateObj.state}`);
}
-1
View File
@@ -30,7 +30,6 @@ export class HaSettingsRow extends LitElement {
<slot name="prefix"></slot>
<div
class="body"
part="heading"
?two-line=${!this.threeLine && hasDescription}
?three-line=${this.threeLine}
>
+1 -16
View File
@@ -1,13 +1,12 @@
import "@home-assistant/webawesome/dist/components/textarea/textarea";
import type WaTextarea from "@home-assistant/webawesome/dist/components/textarea/textarea";
import { HasSlotController } from "@home-assistant/webawesome/dist/internal/slot";
import type { PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { ifDefined } from "lit/directives/if-defined";
import { stopPropagation } from "../common/dom/stop_propagation";
import { WaInputMixin, waInputStyles } from "./input/wa-input-mixin";
import { stopPropagation } from "../common/dom/stop_propagation";
/**
* Home Assistant textarea component
@@ -85,20 +84,6 @@ export class HaTextArea extends WaInputMixin(LitElement) {
this.removeEventListener("keydown", stopPropagation);
}
protected override async firstUpdated(
changedProperties: PropertyValues<this>
): Promise<void> {
super.firstUpdated(changedProperties);
if (this.autofocus) {
await this._textarea?.updateComplete;
this._textarea?.focus();
}
}
public override focus(options?: FocusOptions): void {
this._textarea?.focus(options);
}
protected render() {
const hasLabelSlot = this.label
? false
@@ -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 { isUnavailableState } from "../../data/entity/entity";
import { UNAVAILABLE } 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 &&
isUnavailableState(this.hass.states[this.entityId]?.state)
this.hass.states[this.entityId]?.state === UNAVAILABLE
) {
this._setError({
message: this.hass.localize(
-4
View File
@@ -95,7 +95,6 @@ export interface TriggerList {
export interface BaseTrigger {
alias?: string;
comment?: string;
/** @deprecated Use `trigger` instead */
platform?: string;
trigger: string;
@@ -241,7 +240,6 @@ export type Trigger = LegacyTrigger | TriggerList | PlatformTrigger;
interface BaseCondition {
condition: string;
alias?: string;
comment?: string;
enabled?: boolean;
options?: Record<string, unknown>;
}
@@ -609,7 +607,6 @@ export interface AutomationClipboard {
export interface BaseSidebarConfig {
delete: () => void;
close: (focus?: boolean) => void;
editComment: () => void;
}
export interface TriggerSidebarConfig extends BaseSidebarConfig {
@@ -671,7 +668,6 @@ export interface OptionSidebarConfig extends BaseSidebarConfig {
rename: () => void;
duplicate: () => void;
defaultOption?: boolean;
comment?: string;
}
export interface ScriptFieldSidebarConfig extends BaseSidebarConfig {
+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 { isUnavailableState } from "./entity/entity";
import { UNAVAILABLE } 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" &&
!isUnavailableState(hass.states[eid].state) &&
hass.states[eid].state !== UNAVAILABLE &&
hass.entities[eid]?.hidden !== true
)
.sort()
-1
View File
@@ -12,7 +12,6 @@ import {
export interface DeviceAutomation {
alias?: string;
comment?: string;
device_id: string;
domain: string;
entity_id?: string;
-2
View File
@@ -6,10 +6,8 @@ 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;
+3 -2
View File
@@ -38,7 +38,7 @@ import { stateActive } from "../common/entity/state_active";
import { supportsFeature } from "../common/entity/supports-feature";
import type { MediaPlayerItemId } from "../components/media-player/ha-media-player-browse";
import type { HomeAssistant, TranslationDict } from "../types";
import { isUnavailableState } from "./entity/entity";
import { UNAVAILABLE } from "./entity/entity";
import { isTTSMediaSource } from "./tts";
interface MediaPlayerEntityAttributes extends HassEntityAttributeBase {
@@ -284,7 +284,8 @@ export const computeMediaControls = (
const state = stateObj.state;
if (isUnavailableState(state)) {
// We only filter out `unavailable`, not `unknown`
if (state === UNAVAILABLE) {
return undefined;
}
-3
View File
@@ -36,7 +36,6 @@ export const isMaxMode = arrayLiteralIncludes(MODES_MAX);
export const baseActionStruct = object({
alias: optional(string()),
comment: optional(string()),
continue_on_error: optional(boolean()),
enabled: optional(boolean()),
});
@@ -106,7 +105,6 @@ export interface Field {
interface BaseAction {
alias?: string;
comment?: string;
continue_on_error?: boolean;
enabled?: boolean;
}
@@ -197,7 +195,6 @@ export interface ForEachRepeat extends BaseRepeat {
export interface Option {
alias?: string;
comment?: string;
conditions: string | Condition[];
sequence: Action | Action[];
}
+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 { isUnavailableState } from "./entity/entity";
import { UNAVAILABLE } from "./entity/entity";
export interface TodoList {
entity_id: string;
@@ -49,7 +49,7 @@ export const getTodoLists = (
.filter(
(entityId) =>
computeDomain(entityId) === "todo" &&
!isUnavailableState(hass.states[entityId].state) &&
hass.states[entityId].state !== UNAVAILABLE &&
(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 { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ImageEntity } from "../../../data/image";
import { computeImageUrl } from "../../../data/image";
import "../../../panels/lovelace/components/hui-timestamp-display";
@@ -108,14 +108,13 @@ 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=${isUnavailableState(stateObj.state)}
>
<ha-button appearance="plain" size="small" .disabled=${disabled}>
${this.hass.localize("ui.card.button.press")}
</ha-button>
`;
@@ -151,19 +150,15 @@ class EntityPreviewRow extends LitElement {
return html`
<ha-date-input
.locale=${this.hass.locale}
.disabled=${isUnavailableState(stateObj.state)}
.value=${isUnavailableState(stateObj.state)
? undefined
: stateObj.state}
.disabled=${disabled}
.value=${noValue ? undefined : stateObj.state}
>
</ha-date-input>
`;
}
if (domain === "datetime") {
const dateObj = isUnavailableState(stateObj.state)
? undefined
: new Date(stateObj.state);
const dateObj = noValue ? 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`
@@ -172,12 +167,12 @@ class EntityPreviewRow extends LitElement {
.label=${computeStateName(stateObj)}
.locale=${this.hass.locale}
.value=${date}
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${disabled}
>
</ha-date-input>
<ha-time-input
.value=${time}
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${disabled}
.locale=${this.hass.locale}
></ha-time-input>
</div>
@@ -187,7 +182,7 @@ class EntityPreviewRow extends LitElement {
if (domain === "event") {
return html`
<div class="when">
${isUnavailableState(stateObj.state)
${noValue
? this.hass.formatEntityState(stateObj)
: html`<hui-timestamp-display
.hass=${this.hass}
@@ -196,7 +191,7 @@ class EntityPreviewRow extends LitElement {
></hui-timestamp-display>`}
</div>
<div class="what">
${isUnavailableState(stateObj.state)
${noValue
? nothing
: this.hass.formatEntityAttributeValue(stateObj, "event_type")}
</div>
@@ -206,9 +201,7 @@ class EntityPreviewRow extends LitElement {
const toggleDomains = ["fan", "light", "remote", "siren", "switch"];
if (toggleDomains.includes(domain)) {
const showToggle =
stateObj.state === "on" ||
stateObj.state === "off" ||
isUnavailableState(stateObj.state);
stateObj.state === "on" || stateObj.state === "off" || noValue;
return html`
${showToggle
? html`
@@ -241,7 +234,7 @@ class EntityPreviewRow extends LitElement {
if (domain === "lock") {
return html`
<ha-button
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${disabled}
class="text-content"
appearance="plain"
size="small"
@@ -266,7 +259,7 @@ class EntityPreviewRow extends LitElement {
<div class="numberflex">
<ha-slider
labeled
.disabled=${stateObj.state === UNAVAILABLE}
.disabled=${disabled}
.step=${Number(stateObj.attributes.step)}
.min=${Number(stateObj.attributes.min)}
.max=${Number(stateObj.attributes.max)}
@@ -280,7 +273,7 @@ class EntityPreviewRow extends LitElement {
: html`<div class="numberflex numberstate">
<ha-input
auto-validate
.disabled=${stateObj.state === UNAVAILABLE}
.disabled=${disabled}
pattern="[0-9]+([\\.][0-9]+)?"
.step=${Number(stateObj.attributes.step)}
.min=${Number(stateObj.attributes.min)}
@@ -303,7 +296,7 @@ class EntityPreviewRow extends LitElement {
<ha-select
.label=${computeStateName(stateObj)}
.value=${stateObj.state}
.disabled=${stateObj.state === UNAVAILABLE}
.disabled=${disabled}
.options=${stateObj.attributes.options?.map((option) => ({
value: option,
label: this.hass!.formatEntityState(stateObj, option),
@@ -317,7 +310,7 @@ class EntityPreviewRow extends LitElement {
const showSensor =
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
stateObj.attributes.device_class
) && !isUnavailableState(stateObj.state);
) && !noValue;
return html`
${showSensor
? html`
@@ -339,7 +332,7 @@ class EntityPreviewRow extends LitElement {
return html`
<ha-input
.label=${computeStateName(stateObj)}
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${disabled}
.value=${stateObj.state}
.minlength=${stateObj.attributes.min}
.maxlength=${stateObj.attributes.max}
@@ -354,11 +347,9 @@ class EntityPreviewRow extends LitElement {
if (domain === "time") {
return html`
<ha-time-input
.value=${isUnavailableState(stateObj.state)
? undefined
: stateObj.state}
.value=${noValue ? undefined : stateObj.state}
.locale=${this.hass.locale}
.disabled=${isUnavailableState(stateObj.state)}
.disabled=${disabled}
></ha-time-input>
`;
}
@@ -366,7 +357,7 @@ class EntityPreviewRow extends LitElement {
if (domain === "weather") {
return html`
<div>
${isUnavailableState(stateObj.state) ||
${noValue ||
stateObj.attributes.temperature === undefined ||
stateObj.attributes.temperature === null
? this.hass.formatEntityState(stateObj)
+3 -16
View File
@@ -9,7 +9,6 @@ import "../../components/ha-dialog";
import "../../components/ha-dialog-footer";
import "../../components/ha-dialog-header";
import "../../components/ha-svg-icon";
import "../../components/ha-textarea";
import "../../components/input/ha-input";
import type { HaInput } from "../../components/input/ha-input";
import type { HomeAssistant } from "../../types";
@@ -29,7 +28,7 @@ class DialogBox extends LitElement {
@state() private _validInput = true;
@query("ha-input, ha-textarea") private _textField?: HaInput;
@query("ha-input") private _textField?: HaInput;
private _closePromise?: Promise<void>;
@@ -110,7 +109,7 @@ class DialogBox extends LitElement {
</ha-dialog-header>
<div id="dialog-box-description">
${this._params.text ? html` <p>${this._params.text}</p> ` : ""}
${this._params.prompt && !this._params.multiline
${this._params.prompt
? html`
<ha-input
autofocus
@@ -132,19 +131,7 @@ class DialogBox extends LitElement {
: nothing}
</ha-input>
`
: this._params.prompt && this._params.multiline
? html`
<ha-textarea
resize="auto"
autofocus
.value=${this._params.defaultValue}
.placeholder=${this._params.placeholder}
.label=${this._params.inputLabel}
.disabled=${this._loading}
@input=${this._validateInput}
></ha-textarea>
`
: nothing}
: nothing}
</div>
<ha-dialog-footer slot="footer">
${confirmPrompt
-1
View File
@@ -33,7 +33,6 @@ export interface PromptDialogParams extends BaseDialogBoxParams {
inputMin?: number | string;
inputMax?: number | string;
action?: (value?: string) => Promise<void>;
multiline?: boolean;
}
export interface DialogBoxParams
@@ -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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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,7 +24,8 @@ export class HaMoreInfoStateHeader extends LitElement {
private _localizeState(): TemplateResult | string {
if (
this.stateObj.attributes.device_class === SENSOR_DEVICE_CLASS_TIMESTAMP &&
!isUnavailableState(this.stateObj.state)
this.stateObj.state !== UNAVAILABLE &&
this.stateObj.state !== UNKNOWN
) {
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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } 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=${isUnavailableState(this.stateObj!.state)}
.disabled=${this.stateObj!.state === UNAVAILABLE}
>
${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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } 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 = isUnavailableState(this.stateObj.state);
const disabled = this.stateObj.state === UNAVAILABLE;
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 { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
@customElement("more-info-date")
@@ -21,10 +21,9 @@ class MoreInfoDate extends LitElement {
return html`
<ha-date-input
.locale=${this.hass.locale}
.value=${isUnavailableState(this.stateObj.state)
.value=${this.stateObj.state === UNKNOWN
? 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 { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
@customElement("more-info-datetime")
@@ -19,23 +19,22 @@ class MoreInfoDatetime extends LitElement {
return nothing;
}
const dateObj = isUnavailableState(this.stateObj.state)
? undefined
: new Date(this.stateObj.state);
const dateObj =
this.stateObj.state === UNKNOWN
? 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>`;
@@ -37,7 +37,7 @@ import "../../../components/ha-svg-icon";
import "../../../components/ha-tooltip";
import { showJoinMediaPlayersDialog } from "../../../components/media-player/show-join-media-players-dialog";
import { showMediaBrowserDialog } from "../../../components/media-player/show-media-browser-dialog";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import type {
MediaPickedEvent,
MediaPlayerEntity,
@@ -275,7 +275,8 @@ class MoreInfoMediaPlayer extends LitElement {
protected _renderGrouping() {
if (
!this.stateObj ||
isUnavailableState(this.stateObj.state) ||
// Compare against `unavailable` so we allow `unknown`
this.stateObj.state === UNAVAILABLE ||
!supportsFeature(this.stateObj, MediaPlayerEntityFeature.GROUPING)
) {
return nothing;
@@ -315,7 +316,7 @@ class MoreInfoMediaPlayer extends LitElement {
return nothing;
}
if (isUnavailableState(this.stateObj.state)) {
if (this.stateObj.state === UNAVAILABLE) {
return this._renderEmptyCover(this.hass.formatEntityState(this.stateObj));
}
@@ -461,7 +462,7 @@ class MoreInfoMediaPlayer extends LitElement {
: nothing}
${this._renderVolumeControl()}
<div class="controls-row">
${!isUnavailableState(stateObj.state) &&
${stateObj.state !== UNAVAILABLE &&
supportsFeature(stateObj, MediaPlayerEntityFeature.BROWSE_MEDIA)
? this._renderControlButton(
"browse_media",
@@ -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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } 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=${isUnavailableState(stateObj.state) || !this._canRun()}
.disabled=${stateObj.state === UNAVAILABLE || !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 { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import { setTimeValue } from "../../../data/time";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
@@ -20,11 +20,10 @@ class MoreInfoTime extends LitElement {
return html`
<ha-time-input
.value=${isUnavailableState(this.stateObj.state)
.value=${this.stateObj.state === UNKNOWN
? 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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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,7 +176,8 @@ class MoreInfoUpdate extends LitElement {
if (
!this.hass ||
!this.stateObj ||
isUnavailableState(this.stateObj.state)
this.stateObj.state === UNAVAILABLE ||
this.stateObj.state === UNKNOWN
) {
return nothing;
}
@@ -107,7 +107,6 @@ export default class HaAutomationActionEditor extends LitElement {
ev.stopPropagation();
const value = {
...(this.action.alias ? { alias: this.action.alias } : {}),
...(this.action.comment ? { comment: this.action.comment } : {}),
...ev.detail.value,
};
fireEvent(this, "value-changed", { value });
@@ -8,8 +8,6 @@ import {
mdiArrowUp,
mdiCheckboxBlankOutline,
mdiCheckboxOutline,
mdiCommentEditOutline,
mdiCommentTextOutline,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
@@ -348,24 +346,6 @@ export default class HaAutomationActionRow extends LitElement {
)}
</ha-tooltip>`
: nothing}
${this.action.comment?.trim()
? html`
<ha-svg-icon
id="comment-icon"
.path=${mdiCommentTextOutline}
.label=${this.hass.localize(
"ui.panel.config.automation.editor.comment.label"
)}
class="comment-indicator"
></ha-svg-icon>
<ha-tooltip for="comment-icon"
>${this.action.comment.substring(0, 250)}${this.action.comment
.length > 250
? "..."
: nothing}</ha-tooltip
>
`
: nothing}
</h3>
<ha-automation-row-event-chip
.show=${this._running}
@@ -409,14 +389,6 @@ export default class HaAutomationActionRow extends LitElement {
)
)}
</ha-dropdown-item>
<ha-dropdown-item value="edit_comment">
<ha-svg-icon slot="icon" .path=${mdiCommentEditOutline}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.action.comment ? "edit" : "add"}`
)
)}
</ha-dropdown-item>
<wa-divider></wa-divider>
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
<ha-svg-icon
@@ -943,38 +915,6 @@ export default class HaAutomationActionRow extends LitElement {
}
};
private _editCommentAction = async (): Promise<void> => {
const comment = await showPromptDialog(this, {
title: this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.action.comment ? "edit" : "add"}`
),
inputLabel: this.hass.localize(
"ui.panel.config.automation.editor.comment.label"
),
inputType: "string",
defaultValue: this.action.comment,
confirmText: this.hass.localize("ui.common.submit"),
multiline: true,
});
if (comment !== null) {
const value = { ...this.action };
if (comment === "") {
delete value.comment;
} else {
value.comment = comment;
}
fireEvent(this, "value-changed", {
value,
});
if (this._selected && this.optionsInSidebar) {
this.openSidebar(value); // refresh sidebar
} else if (this._yamlMode) {
this._actionEditor?.yamlEditor?.setValue(value);
}
}
};
private _duplicateAction = () => {
fireEvent(this, "duplicate");
};
@@ -1091,7 +1031,6 @@ export default class HaAutomationActionRow extends LitElement {
rename: () => {
this._renameAction();
},
editComment: this._editCommentAction,
toggleYamlMode: () => {
this._toggleYamlMode();
this.openSidebar();
@@ -1187,9 +1126,6 @@ export default class HaAutomationActionRow extends LitElement {
case "rename":
this._renameAction();
break;
case "edit_comment":
this._editCommentAction();
break;
case "duplicate":
this._duplicateAction();
break;
@@ -186,10 +186,6 @@ export class HaDeviceAction extends LitElement {
}
static styles = css`
:host {
display: block;
margin-bottom: var(--ha-space-3);
}
ha-device-picker {
display: block;
margin-bottom: 24px;
@@ -123,7 +123,6 @@ export default class HaAutomationConditionEditor extends LitElement {
ev.stopPropagation();
const value = {
...(this.condition.alias ? { alias: this.condition.alias } : {}),
...(this.condition.comment ? { comment: this.condition.comment } : {}),
...ev.detail.value,
};
fireEvent(this, "value-changed", { value });
@@ -4,8 +4,6 @@ import {
mdiAppleKeyboardCommand,
mdiArrowDown,
mdiArrowUp,
mdiCommentEditOutline,
mdiCommentTextOutline,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
@@ -219,24 +217,6 @@ export default class HaAutomationConditionRow extends LitElement {
conditionTargetSpec
)
: nothing}
${this.condition.comment?.trim()
? html`
<ha-svg-icon
id="comment-icon"
.path=${mdiCommentTextOutline}
.label=${this.hass.localize(
"ui.panel.config.automation.editor.comment.label"
)}
class="comment-indicator"
></ha-svg-icon>
<ha-tooltip for="comment-icon"
>${this.condition.comment.substring(0, 250)}${this.condition
.comment.length > 250
? "..."
: nothing}</ha-tooltip
>
`
: nothing}
</h3>
<ha-automation-row-event-chip
.show=${this._testing}
@@ -284,14 +264,6 @@ export default class HaAutomationConditionRow extends LitElement {
)
)}
</ha-dropdown-item>
<ha-dropdown-item value="edit_comment">
<ha-svg-icon slot="icon" .path=${mdiCommentEditOutline}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.condition.comment ? "edit" : "add"}`
)
)}
</ha-dropdown-item>
<wa-divider></wa-divider>
@@ -849,38 +821,6 @@ export default class HaAutomationConditionRow extends LitElement {
}
};
private _editCommentCondition = async (): Promise<void> => {
const comment = await showPromptDialog(this, {
title: this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.condition.comment ? "edit" : "add"}`
),
inputLabel: this.hass.localize(
"ui.panel.config.automation.editor.comment.label"
),
inputType: "string",
defaultValue: this.condition.comment,
confirmText: this.hass.localize("ui.common.submit"),
multiline: true,
});
if (comment !== null) {
const value = { ...this.condition };
if (comment === "") {
delete value.comment;
} else {
value.comment = comment;
}
fireEvent(this, "value-changed", {
value,
});
if (this._selected && this.optionsInSidebar) {
this.openSidebar(value); // refresh sidebar
} else if (this._yamlMode) {
this.conditionEditor?.yamlEditor?.setValue(value);
}
}
};
private _duplicateCondition = () => {
fireEvent(this, "duplicate");
};
@@ -1022,7 +962,6 @@ export default class HaAutomationConditionRow extends LitElement {
rename: () => {
this._renameCondition();
},
editComment: this._editCommentCondition,
toggleYamlMode: () => {
this._toggleYamlMode();
this.openSidebar();
@@ -1094,9 +1033,6 @@ export default class HaAutomationConditionRow extends LitElement {
case "rename":
this._renameCondition();
break;
case "edit_comment":
this._editCommentCondition();
break;
case "duplicate":
this._duplicateCondition();
break;
@@ -188,10 +188,6 @@ export class HaDeviceCondition extends LitElement {
}
static styles = css`
:host {
display: block;
margin-bottom: var(--ha-space-3);
}
ha-device-picker {
display: block;
margin-bottom: 24px;
@@ -1,5 +1,5 @@
import type { PropertyValues } from "lit";
import { css, html, LitElement } from "lit";
import { html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import {
@@ -22,7 +22,6 @@ import type { HomeAssistant } from "../../../../../types";
const numericStateConditionStruct = object({
alias: optional(string()),
comment: optional(string()),
condition: literal("numeric_state"),
entity_id: optional(string()),
attribute: optional(string()),
@@ -256,13 +255,6 @@ export default class HaNumericStateCondition extends LitElement {
);
}
};
static styles = css`
:host {
display: block;
margin-bottom: var(--ha-space-3);
}
`;
}
declare global {
@@ -1,8 +1,7 @@
import type { PropertyValues } from "lit";
import { css, html, LitElement } from "lit";
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import {
array,
assert,
boolean,
literal,
@@ -11,9 +10,10 @@ import {
optional,
string,
union,
array,
} from "superstruct";
import { ensureArray } from "../../../../../common/array/ensure-array";
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
import { ensureArray } from "../../../../../common/array/ensure-array";
import { fireEvent } from "../../../../../common/dom/fire_event";
import "../../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../../components/ha-form/types";
@@ -25,7 +25,6 @@ import type { ConditionElement } from "../ha-automation-condition-row";
const stateConditionStruct = object({
alias: optional(string()),
comment: optional(string()),
condition: literal("state"),
entity_id: optional(string()),
attribute: optional(string()),
@@ -143,13 +142,6 @@ export class HaStateCondition extends LitElement implements ConditionElement {
);
}
};
static styles = css`
:host {
display: block;
margin-bottom: var(--ha-space-3);
}
`;
}
declare global {
@@ -1,79 +0,0 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import { consume, type ContextType } from "@lit/context";
import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/ha-button";
import "../../../components/ha-settings-row";
import { internationalizationContext } from "../../../data/context";
@customElement("ha-automation-comment")
export class HaAutomationComment extends LitElement {
@property() public comment!: string;
@state()
@consume({ context: internationalizationContext, subscribe: true })
private _i18n!: ContextType<typeof internationalizationContext>;
protected render() {
return html`
<ha-settings-row narrow>
<div class="heading" slot="heading">
<span class="title" id="comment-label">
${this._i18n.localize(
"ui.panel.config.automation.editor.comment.label"
)}
</span>
<ha-button
@click=${this._handleClick}
size="small"
appearance="plain"
>
${this._i18n.localize("ui.common.edit")}
</ha-button>
</div>
<p aria-labelledby="comment-label">${this.comment}</p>
</ha-settings-row>
`;
}
private _handleClick() {
fireEvent(this, "edit-comment");
}
static styles = css`
ha-settings-row {
margin-inline: calc(-1 * var(--ha-space-4));
}
ha-settings-row::part(heading) {
padding-inline-end: 0;
overflow: visible;
}
.heading {
display: flex;
justify-content: space-between;
align-items: center;
}
p {
margin: var(--ha-space-2) 0 0;
border: var(--ha-border-width-sm) solid
var(--ha-color-border-neutral-quiet);
padding: var(--ha-space-1) var(--ha-space-3);
border-radius: var(--ha-border-radius-lg);
background-color: var(--ha-color-fill-neutral-quiet-resting);
}
ha-button {
margin-inline-end: calc(-1 * var(--ha-space-3));
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-comment": HaAutomationComment;
}
interface HASSDomEvents {
"edit-comment": undefined;
}
}
@@ -3,8 +3,6 @@ import {
mdiAppleKeyboardCommand,
mdiArrowDown,
mdiArrowUp,
mdiCommentEditOutline,
mdiCommentTextOutline,
mdiDelete,
mdiDotsVertical,
mdiPlusCircleMultipleOutline,
@@ -39,11 +37,11 @@ import type { Action, Option } from "../../../../data/script";
import { showPromptDialog } from "../../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import { showEditorToast } from "../editor-toast";
import "../action/ha-automation-action";
import type HaAutomationAction from "../action/ha-automation-action";
import "../condition/ha-automation-condition";
import type HaAutomationCondition from "../condition/ha-automation-condition";
import { showEditorToast } from "../editor-toast";
import {
editorStyles,
indentStyle,
@@ -152,24 +150,6 @@ export default class HaAutomationOptionRow extends LitElement {
: this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.default"
)}
${this.option?.comment?.trim()
? html`
<ha-svg-icon
id="comment-icon"
.path=${mdiCommentTextOutline}
.label=${this.hass.localize(
"ui.panel.config.automation.editor.comment.label"
)}
class="comment-indicator"
></ha-svg-icon>
<ha-tooltip for="comment-icon"
>${this.option.comment.substring(0, 250)}${this.option.comment
.length > 250
? "..."
: nothing}</ha-tooltip
>
`
: nothing}
</h3>
<slot name="icons" slot="icons"></slot>
@@ -197,17 +177,6 @@ export default class HaAutomationOptionRow extends LitElement {
)
)}
</ha-dropdown-item>
<ha-dropdown-item value="edit_comment">
<ha-svg-icon
slot="icon"
.path=${mdiCommentEditOutline}
></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.option?.comment ? "edit" : "add"}`
)
)}
</ha-dropdown-item>
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
<ha-svg-icon
@@ -392,9 +361,6 @@ export default class HaAutomationOptionRow extends LitElement {
case "rename":
this._renameOption();
break;
case "edit_comment":
this._editCommentOption();
break;
case "delete":
this._removeOption();
break;
@@ -458,39 +424,6 @@ export default class HaAutomationOptionRow extends LitElement {
}
};
private _editCommentOption = async (): Promise<void> => {
if (!this.option) {
return;
}
const comment = await showPromptDialog(this, {
title: this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.option.comment ? "edit" : "add"}`
),
inputLabel: this.hass.localize(
"ui.panel.config.automation.editor.comment.label"
),
inputType: "string",
defaultValue: this.option.comment,
confirmText: this.hass.localize("ui.common.submit"),
multiline: true,
});
if (comment !== null) {
const value: Option = { ...this.option };
if (comment === "") {
delete value.comment;
} else {
value.comment = comment;
}
fireEvent(this, "value-changed", {
value,
});
if (this._selected) {
this.openSidebar(value); // refresh sidebar
}
}
};
private _conditionChanged(ev: CustomEvent) {
ev.stopPropagation();
const conditions = ev.detail.value as Condition[];
@@ -522,8 +455,7 @@ export default class HaAutomationOptionRow extends LitElement {
this.openSidebar();
}
public openSidebar(option?: Option): void {
const sidebarOption = option ?? this.option;
public openSidebar(): void {
fireEvent(this, "open-sidebar", {
close: (focus?: boolean) => {
this._selected = false;
@@ -535,11 +467,9 @@ export default class HaAutomationOptionRow extends LitElement {
rename: () => {
this._renameOption();
},
editComment: this._editCommentOption,
delete: this._removeOption,
duplicate: this._duplicateOption,
defaultOption: !!this.defaultActions,
comment: sidebarOption?.comment,
} satisfies OptionSidebarConfig);
this._selected = true;
this._collapsed = false;
@@ -3,7 +3,6 @@ import {
mdiAppleKeyboardCommand,
mdiCheckboxBlankOutline,
mdiCheckboxOutline,
mdiCommentEditOutline,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
@@ -27,8 +26,8 @@ import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
import "../../../../components/ha-dropdown-item";
import { ACTION_BUILDING_BLOCKS } from "../../../../data/action";
import type { ActionSidebarConfig } from "../../../../data/automation";
import type { DomainManifestLookup } from "../../../../data/integration";
import { domainToName } from "../../../../data/integration";
import type { DomainManifestLookup } from "../../../../data/integration";
import type {
NonConditionAction,
RepeatAction,
@@ -39,7 +38,6 @@ import { isMac } from "../../../../util/is_mac";
import type HaAutomationConditionEditor from "../action/ha-automation-action-editor";
import { getAutomationActionType } from "../action/ha-automation-action-row";
import { getRepeatType } from "../action/types/ha-automation-action-repeat";
import "../ha-automation-comment";
import { overflowStyles, sidebarEditorStyles } from "../styles";
import "./ha-automation-sidebar-card";
@@ -177,15 +175,6 @@ export default class HaAutomationSidebarAction extends LitElement {
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-dropdown-item>
<ha-dropdown-item slot="menu-items" value="edit_comment">
<ha-svg-icon slot="icon" .path=${mdiCommentEditOutline}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.config.config.action.comment ? "edit" : "add"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-dropdown-item>
<wa-divider slot="menu-items"></wa-divider>
<ha-dropdown-item
@@ -388,12 +377,6 @@ export default class HaAutomationSidebarAction extends LitElement {
@ui-mode-not-available=${this._handleUiModeNotAvailable}
></ha-automation-action-editor>`
)}
${this.config.config.action.comment?.trim() && !this.yamlMode
? html`<ha-automation-comment
@edit-comment=${this.config.editComment}
.comment=${this.config.config.action.comment}
></ha-automation-comment>`
: nothing}
</ha-automation-sidebar-card>`;
}
@@ -442,9 +425,6 @@ export default class HaAutomationSidebarAction extends LitElement {
case "rename":
this.config.rename();
break;
case "edit_comment":
this.config.editComment();
break;
case "run":
this.config.run();
break;
@@ -1,7 +1,6 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import {
mdiAppleKeyboardCommand,
mdiCommentEditOutline,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
@@ -35,7 +34,6 @@ import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import "../condition/ha-automation-condition-editor";
import type HaAutomationConditionEditor from "../condition/ha-automation-condition-editor";
import "../ha-automation-comment";
import { overflowStyles, sidebarEditorStyles } from "../styles";
import "./ha-automation-sidebar-card";
@@ -151,19 +149,6 @@ export default class HaAutomationSidebarCondition extends LitElement {
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
value="edit_comment"
.disabled=${this.disabled}
>
<ha-svg-icon slot="icon" .path=${mdiCommentEditOutline}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.config.config.comment ? "edit" : "add"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-dropdown-item>
<wa-divider slot="menu-items"></wa-divider>
@@ -347,12 +332,6 @@ export default class HaAutomationSidebarCondition extends LitElement {
sidebar
></ha-automation-condition-editor>`
)}
${this.config.config.comment?.trim() && !this.yamlMode
? html`<ha-automation-comment
@edit-comment=${this.config.editComment}
.comment=${this.config.config.comment}
></ha-automation-comment>`
: nothing}
<div class="testing-wrapper">
<div
class="testing ${classMap({
@@ -417,9 +396,6 @@ export default class HaAutomationSidebarCondition extends LitElement {
case "rename":
this.config.rename();
break;
case "edit_comment":
this.config.editComment();
break;
case "test":
this.config.test();
break;
@@ -1,7 +1,6 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import {
mdiAppleKeyboardCommand,
mdiCommentEditOutline,
mdiDelete,
mdiPlusCircleMultipleOutline,
mdiRenameBox,
@@ -15,7 +14,6 @@ import type { OptionSidebarConfig } from "../../../../data/automation";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import type HaAutomationConditionEditor from "../action/ha-automation-action-editor";
import "../ha-automation-comment";
import { overflowStyles, sidebarEditorStyles } from "../styles";
import "./ha-automation-sidebar-card";
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
@@ -74,22 +72,6 @@ export default class HaAutomationSidebarOption extends LitElement {
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
value="edit_comment"
.disabled=${!!disabled}
>
<ha-svg-icon
slot="icon"
.path=${mdiCommentEditOutline}
></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.config.comment ? "edit" : "add"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
@@ -144,12 +126,6 @@ export default class HaAutomationSidebarOption extends LitElement {
`}
<div class="description">${description}</div>
${!this.config.defaultOption && this.config.comment?.trim()
? html`<ha-automation-comment
@edit-comment=${this.config.editComment}
.comment=${this.config.comment}
></ha-automation-comment>`
: nothing}
</ha-automation-sidebar-card>`;
}
@@ -164,9 +140,6 @@ export default class HaAutomationSidebarOption extends LitElement {
case "rename":
this.config.rename();
break;
case "edit_comment":
this.config.editComment();
break;
case "duplicate":
this.config.duplicate();
break;
@@ -1,24 +1,18 @@
import {
mdiAppleKeyboardCommand,
mdiCommentEditOutline,
mdiDelete,
mdiPlaylistEdit,
} from "@mdi/js";
import { mdiAppleKeyboardCommand, mdiDelete, mdiPlaylistEdit } from "@mdi/js";
import type { PropertyValues } from "lit";
import { html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
import "../../../../components/ha-dropdown-item";
import type { ScriptFieldSidebarConfig } from "../../../../data/automation";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import "../../script/ha-script-field-editor";
import type HaAutomationConditionEditor from "../action/ha-automation-action-editor";
import "../ha-automation-comment";
import { overflowStyles, sidebarEditorStyles } from "../styles";
import "./ha-automation-sidebar-card";
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
@customElement("ha-automation-sidebar-script-field")
export default class HaAutomationSidebarScriptField extends LitElement {
@@ -68,15 +62,6 @@ export default class HaAutomationSidebarScriptField extends LitElement {
@wa-select=${this._handleDropdownSelect}
>
<span slot="title">${title}</span>
<ha-dropdown-item slot="menu-items" value="edit_comment">
<ha-svg-icon slot="icon" .path=${mdiCommentEditOutline}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.config.config.field.description ? "edit" : "add"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
value="toggle_yaml_mode"
@@ -136,12 +121,6 @@ export default class HaAutomationSidebarScriptField extends LitElement {
@yaml-changed=${this._yamlChangedSidebar}
></ha-script-field-editor>`
)}
${this.config.config.field.description?.trim() && !this.yamlMode
? html`<ha-automation-comment
@edit-comment=${this.config.editComment}
.comment=${this.config.config.field.description}
></ha-automation-comment>`
: nothing}
</ha-automation-sidebar-card>`;
}
@@ -189,9 +168,6 @@ export default class HaAutomationSidebarScriptField extends LitElement {
case "toggle_yaml_mode":
this._toggleYamlMode();
break;
case "edit_comment":
this.config.editComment();
break;
case "delete":
this.config.delete();
break;
@@ -1,7 +1,6 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import {
mdiAppleKeyboardCommand,
mdiCommentEditOutline,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
@@ -19,12 +18,9 @@ import { customElement, property, query, state } from "lit/decorators";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import { handleStructError } from "../../../../common/structs/handle-errors";
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
import "../../../../components/ha-dropdown-item";
import type {
LegacyTrigger,
Trigger,
TriggerList,
TriggerSidebarConfig,
} from "../../../../data/automation";
import {
@@ -34,11 +30,11 @@ import {
} from "../../../../data/trigger";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import "../ha-automation-comment";
import { overflowStyles, sidebarEditorStyles } from "../styles";
import "../trigger/ha-automation-trigger-editor";
import type HaAutomationTriggerEditor from "../trigger/ha-automation-trigger-editor";
import "./ha-automation-sidebar-card";
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
@customElement("ha-automation-sidebar-trigger")
export default class HaAutomationSidebarTrigger extends LitElement {
@@ -129,24 +125,7 @@ export default class HaAutomationSidebarTrigger extends LitElement {
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-dropdown-item>
${type !== "list"
? html`<ha-dropdown-item
slot="menu-items"
value="edit_comment"
.disabled=${this.disabled}
>
<ha-svg-icon
slot="icon"
.path=${mdiCommentEditOutline}
></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.comment.${(this.config.config as Exclude<Trigger, TriggerList>).comment ? "edit" : "add"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-dropdown-item>`
: nothing}
${!this.yamlMode &&
!("id" in this.config.config) &&
!this._requestShowId
@@ -342,14 +321,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
sidebar
></ha-automation-trigger-editor>`
)}
${!isTriggerList(this.config.config) &&
this.config.config.comment?.trim() &&
!this.yamlMode
? html`<ha-automation-comment
@edit-comment=${this.config.editComment}
.comment=${this.config.config.comment}
></ha-automation-comment>`
: nothing}
</ha-automation-sidebar-card>
`;
}
@@ -401,9 +372,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
case "rename":
this.config.rename();
break;
case "edit_comment":
this.config.editComment();
break;
case "show_id":
this._showTriggerId();
break;
-1
View File
@@ -4,7 +4,6 @@ export const baseTriggerStruct = object({
trigger: string(),
id: optional(string()),
enabled: optional(boolean()),
comment: optional(string()),
});
export const forDictStruct = object({
-8
View File
@@ -52,14 +52,6 @@ export const rowStyles = css`
ha-automation-row-event-chip.event-chip {
position: absolute;
}
.comment-indicator {
color: var(--ha-color-on-neutral-normal);
}
.comment-indicator + ha-tooltip::part(body) {
cursor: default;
max-width: 300px;
}
`;
export const editorStyles = css`
@@ -141,7 +141,6 @@ export default class HaAutomationTriggerEditor extends LitElement {
ev.stopPropagation();
const value = {
...(this.trigger.alias ? { alias: this.trigger.alias } : {}),
...(this.trigger.comment ? { comment: this.trigger.comment } : {}),
...ev.detail.value,
};
fireEvent(this, "value-changed", { value });
@@ -4,8 +4,6 @@ import {
mdiAppleKeyboardCommand,
mdiArrowDown,
mdiArrowUp,
mdiCommentEditOutline,
mdiCommentTextOutline,
mdiContentCopy,
mdiContentCut,
mdiContentPaste,
@@ -244,28 +242,6 @@ export default class HaAutomationTriggerRow extends LitElement {
triggerTargetSpec
)
: nothing}
${type !== "list" &&
(this.trigger as Exclude<Trigger, TriggerList>).comment?.trim()
? html`
<ha-svg-icon
id="comment-icon"
.path=${mdiCommentTextOutline}
.label=${this.hass.localize(
"ui.panel.config.automation.editor.comment.label"
)}
class="comment-indicator"
></ha-svg-icon>
<ha-tooltip for="comment-icon"
>${(
this.trigger as Exclude<Trigger, TriggerList>
).comment!.substring(0, 250)}${(
this.trigger as Exclude<Trigger, TriggerList>
).comment!.length > 250
? "..."
: nothing}</ha-tooltip
>
`
: nothing}
</h3>
<ha-automation-row-event-chip
.show=${this._triggered}
@@ -306,19 +282,7 @@ export default class HaAutomationTriggerRow extends LitElement {
)
)}
</ha-dropdown-item>
${type !== "list"
? html`<ha-dropdown-item value="edit_comment">
<ha-svg-icon
slot="icon"
.path=${mdiCommentEditOutline}
></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.comment.${(this.trigger as Exclude<Trigger, TriggerList>).comment ? "edit" : "add"}`
)
)}
</ha-dropdown-item>`
: nothing}
<wa-divider></wa-divider>
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
@@ -695,7 +659,6 @@ export default class HaAutomationTriggerRow extends LitElement {
rename: () => {
this._renameTrigger();
},
editComment: this._editCommentTrigger,
toggleYamlMode: () => {
this._toggleYamlMode();
this.openSidebar();
@@ -839,40 +802,6 @@ export default class HaAutomationTriggerRow extends LitElement {
}
};
private _editCommentTrigger = async (): Promise<void> => {
if (isTriggerList(this.trigger)) return;
const trigger = this.trigger;
const comment = await showPromptDialog(this, {
title: this.hass.localize(
`ui.panel.config.automation.editor.comment.${trigger.comment ? "edit" : "add"}`
),
inputLabel: this.hass.localize(
"ui.panel.config.automation.editor.comment.label"
),
inputType: "string",
defaultValue: trigger.comment,
confirmText: this.hass.localize("ui.common.submit"),
multiline: true,
});
if (comment !== null) {
const value = { ...trigger };
if (comment === "") {
delete value.comment;
} else {
value.comment = comment;
}
fireEvent(this, "value-changed", {
value,
});
if (this._selected && this.optionsInSidebar) {
this.openSidebar(value); // refresh sidebar
} else if (this._yamlMode) {
this.triggerEditor?.yamlEditor?.setValue(value);
}
}
};
private _duplicateTrigger = () => {
fireEvent(this, "duplicate");
};
@@ -984,9 +913,6 @@ export default class HaAutomationTriggerRow extends LitElement {
case "rename":
this._renameTrigger();
break;
case "edit_comment":
this._editCommentTrigger();
break;
case "duplicate":
this._duplicateTrigger();
break;
@@ -212,10 +212,6 @@ export class HaDeviceTrigger extends LitElement {
}
static styles = css`
:host {
display: block;
margin-bottom: var(--ha-space-3);
}
ha-device-picker {
display: block;
margin-bottom: 24px;
@@ -1,8 +1,7 @@
import type { PropertyValues } from "lit";
import { css, html, LitElement } from "lit";
import { html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { ensureArray } from "../../../../../common/array/ensure-array";
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { hasTemplate } from "../../../../../common/string/has-template";
@@ -11,6 +10,7 @@ import "../../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../../components/ha-form/types";
import type { NumericStateTrigger } from "../../../../../data/automation";
import type { HomeAssistant } from "../../../../../types";
import { ensureArray } from "../../../../../common/array/ensure-array";
@customElement("ha-automation-trigger-numeric_state")
export class HaNumericStateTrigger extends LitElement {
@@ -333,13 +333,6 @@ export class HaNumericStateTrigger extends LitElement {
);
}
};
static styles = css`
:host {
display: block;
margin-bottom: var(--ha-space-3);
}
`;
}
declare global {
@@ -29,7 +29,6 @@ const DEFAULT_KEYS: (keyof PlatformTrigger)[] = [
"trigger",
"target",
"alias",
"comment",
"id",
"variables",
"enabled",
@@ -1,7 +1,6 @@
import type { PropertyValues } from "lit";
import { css, html, LitElement } from "lit";
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import memoizeOne from "memoize-one";
import {
array,
assert,
@@ -14,21 +13,22 @@ import {
string,
union,
} from "superstruct";
import memoizeOne from "memoize-one";
import type { LocalizeFunc } from "../../../../../common/translations/localize";
import { ensureArray } from "../../../../../common/array/ensure-array";
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { hasTemplate } from "../../../../../common/string/has-template";
import type { LocalizeFunc } from "../../../../../common/translations/localize";
import type { StateTrigger } from "../../../../../data/automation";
import { ANY_STATE_VALUE } from "../../../../../components/entity/const";
import type { HomeAssistant } from "../../../../../types";
import { baseTriggerStruct, forDictStruct } from "../../structs";
import type { TriggerElement } from "../ha-automation-trigger-row";
import "../../../../../components/ha-form/ha-form";
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
import type {
HaFormSchema,
SchemaUnion,
} from "../../../../../components/ha-form/types";
import type { StateTrigger } from "../../../../../data/automation";
import type { HomeAssistant } from "../../../../../types";
import { baseTriggerStruct, forDictStruct } from "../../structs";
import type { TriggerElement } from "../ha-automation-trigger-row";
const stateTriggerStruct = assign(
baseTriggerStruct,
@@ -303,13 +303,6 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
? "ui.components.entity.entity-picker.entity"
: `ui.panel.config.automation.editor.triggers.type.state.${schema.name}`
);
static styles = css`
:host {
display: block;
margin-bottom: var(--ha-space-3);
}
`;
}
declare global {
@@ -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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import "../../../components/ha-tooltip";
import "../../../components/ha-svg-icon";
@@ -146,7 +146,11 @@ export const renderRelativeTimeColumn = (
localize: LocalizeFunc,
hass: HomeAssistant
) => {
if (!valueRelativeTime || isUnavailableState(valueRelativeTime)) {
if (
!valueRelativeTime ||
valueRelativeTime === UNAVAILABLE ||
valueRelativeTime === UNKNOWN
) {
return localize("ui.components.relative_time.never");
}
const date = new Date(valueRelativeTime);
@@ -42,6 +42,10 @@ export default class HaScriptFieldEditor extends LitElement {
name: "key",
selector: { text: {} },
},
{
name: "description",
selector: { text: {} },
},
{
name: "required",
selector: { boolean: {} },
@@ -1,7 +1,5 @@
import {
mdiAppleKeyboardCommand,
mdiCommentEditOutline,
mdiCommentTextOutline,
mdiDelete,
mdiDotsVertical,
mdiPlaylistEdit,
@@ -23,7 +21,6 @@ import "../../../components/ha-dropdown-item";
import type { ScriptFieldSidebarConfig } from "../../../data/automation";
import type { Field } from "../../../data/script";
import { SELECTOR_SELECTOR_BUILDING_BLOCKS } from "../../../data/selector/selector_selector";
import { showPromptDialog } from "../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../types";
import { isMac } from "../../../util/is_mac";
import { showEditorToast } from "../automation/editor-toast";
@@ -93,16 +90,6 @@ export default class HaScriptFieldRow extends LitElement {
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-dropdown-item value="edit_comment">
<ha-svg-icon
slot="icon"
.path=${mdiCommentEditOutline}
></ha-svg-icon>
${this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.field.description ? "edit" : "add"}`
)}
</ha-dropdown-item>
<ha-dropdown-item value="toggle_yaml_mode">
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
<div class="overflow-label">
@@ -145,27 +132,7 @@ export default class HaScriptFieldRow extends LitElement {
</ha-dropdown-item>
</ha-dropdown>
<h3 slot="header">
${this.field.name ?? this.key}
${this.field.description?.trim()
? html`
<ha-svg-icon
id="comment-icon"
.path=${mdiCommentTextOutline}
.label=${this.hass.localize(
"ui.panel.config.automation.editor.comment.label"
)}
class="comment-indicator"
></ha-svg-icon>
<ha-tooltip for="comment-icon"
>${this.field.description.substring(0, 250)}${this.field
.description.length > 250
? "..."
: nothing}</ha-tooltip
>
`
: nothing}
</h3>
<h3 slot="header">${this.field.name ?? this.key}</h3>
<slot name="icons" slot="icons"></slot>
</ha-automation-row>
@@ -357,46 +324,11 @@ export default class HaScriptFieldRow extends LitElement {
});
}
private _editComment = async (): Promise<void> => {
const comment = await showPromptDialog(this, {
title: this.hass.localize(
`ui.panel.config.automation.editor.comment.${this.field.description ? "edit" : "add"}`
),
inputLabel: this.hass.localize(
"ui.panel.config.automation.editor.comment.label"
),
inputType: "string",
defaultValue: this.field.description,
confirmText: this.hass.localize("ui.common.submit"),
multiline: true,
});
if (comment !== null) {
const value = { ...this.field };
if (comment === "") {
delete value.description;
} else {
value.description = comment;
}
fireEvent(this, "value-changed", {
value,
});
if (this._selected) {
this.openSidebar(false, value); // refresh sidebar
}
}
};
public openSidebar(
selectorEditor = false,
fieldValue?: HaScriptFieldRow["field"]
): void {
public openSidebar(selectorEditor = false): void {
if (!selectorEditor) {
this._selected = true;
}
const field = fieldValue ?? this.field;
fireEvent(this, "open-sidebar", {
save: (value) => {
fireEvent(this, "value-changed", { value });
@@ -421,13 +353,12 @@ export default class HaScriptFieldRow extends LitElement {
},
delete: this._onDelete,
config: {
field,
field: this.field,
selector: selectorEditor,
key: this.key,
excludeKeys: this.excludeKeys,
},
yamlMode: this._yamlMode,
editComment: this._editComment,
} satisfies ScriptFieldSidebarConfig);
if (this.narrow) {
@@ -488,9 +419,6 @@ export default class HaScriptFieldRow extends LitElement {
case "delete":
this._onDelete();
break;
case "edit_comment":
this._editComment();
break;
}
}
@@ -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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import type {
ControlButton,
MediaPlayerEntity,
@@ -233,7 +233,7 @@ class HuiMediaPlayerPlaybackCardFeature
case "turn_on":
if (
(!active || assumedState) &&
!isUnavailableState(stateObj.state) &&
stateObj.state !== UNAVAILABLE &&
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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import {
MediaPlayerEntityFeature,
type MediaPlayerEntity,
@@ -89,7 +89,7 @@ class HuiMediaPlayerVolumeButtonsCardFeature
}
const stateObj = this._stateObj;
const disabled = isUnavailableState(stateObj.state);
const disabled = stateObj.state === UNAVAILABLE;
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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import {
MediaPlayerEntityFeature,
type MediaPlayerEntity,
@@ -88,7 +88,7 @@ class HuiMediaPlayerVolumeSliderCardFeature
}
const stateObj = this._stateObj;
const disabled = isUnavailableState(stateObj.state);
const disabled = stateObj.state === UNAVAILABLE;
const position =
stateObj.attributes.volume_level != null
+9 -4
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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import "../card-features/hui-card-features";
@@ -419,7 +419,9 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[area.temperature_entity_id] as
| HassEntity
| undefined;
return !stateObj || isUnavailableState(stateObj.state)
return !stateObj ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN
? ""
: this.hass.formatEntityState(stateObj);
}
@@ -427,7 +429,9 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[area.humidity_entity_id] as
| HassEntity
| undefined;
return !stateObj || isUnavailableState(stateObj.state)
return !stateObj ||
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN
? ""
: this.hass.formatEntityState(stateObj);
}
@@ -444,7 +448,8 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
const stateObj = this.hass.states[entityId];
if (
stateObj &&
!isUnavailableState(stateObj.state) &&
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN &&
isNumericState(stateObj) &&
!isNaN(Number(stateObj.state))
) {
+3 -2
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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type {
CallServiceActionConfig,
@@ -293,7 +293,8 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
stateObj.attributes.device_class
) &&
!isUnavailableState(stateObj.state)
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN
? 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, isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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=${isUnavailableState(stateObj.state)}
.disabled=${stateObj.state === UNAVAILABLE}
@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=${isUnavailableState(stateObj.state)}
.disabled=${stateObj.state === UNAVAILABLE}
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}>
${isUnavailableState(stateObj.state)
${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
? 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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type {
MediaPickedEvent,
MediaPlayerEntity,
@@ -173,9 +173,12 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
const entityState = stateObj.state;
const isOffState =
!stateActive(stateObj) && !isUnavailableState(entityState);
!stateActive(stateObj) &&
entityState !== UNAVAILABLE &&
entityState !== UNKNOWN;
const isUnavailable =
isUnavailableState(entityState) ||
entityState === UNAVAILABLE ||
entityState === UNKNOWN ||
(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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { TodoItem } from "../../../data/todo";
import {
TodoItemStatus,
@@ -383,7 +383,8 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
`;
}
const unavailable = isUnavailableState(stateObj.state);
const unavailable =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
// 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 { isUnavailableState } from "../../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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,12 +235,14 @@ export class HuiBadgePicker extends LitElement {
this._usedEntities = [...usedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
!isUnavailableState(this.hass!.states[eid].state)
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
);
this._unusedEntities = [...unusedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
!isUnavailableState(this.hass!.states[eid].state)
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
);
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 { isUnavailableState } from "../../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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,12 +270,14 @@ export class HuiCardPicker extends LitElement {
this._usedEntities = [...usedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
!isUnavailableState(this.hass!.states[eid].state)
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
);
this._unusedEntities = [...unusedEntities].filter(
(eid) =>
this.hass!.states[eid] &&
!isUnavailableState(this.hass!.states[eid].state)
this.hass!.states[eid].state !== UNAVAILABLE &&
this.hass!.states[eid].state !== UNKNOWN
);
this._loadCards();
@@ -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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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 =>
!isUnavailableState(stateObj.state);
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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 =>
!isUnavailableState(stateObj.state);
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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 =>
!isUnavailableState(stateObj.state);
stateObj.state !== UNAVAILABLE && stateObj.state !== UNKNOWN;
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 { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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=${isUnavailableState(stateObj.state)
.value=${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
? 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 { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant, ValueChangedEvent } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -46,9 +46,10 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
const unavailable = stateObj.state === UNAVAILABLE;
const dateObj = isUnavailableState(stateObj.state)
? undefined
: new Date(stateObj.state);
const dateObj =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
? 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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import type { EntitiesCardEntityConfig } from "../cards/types";
@@ -51,6 +51,9 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
`;
}
const noValue =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
return html`
<hui-generic-entity-row
.hass=${this.hass}
@@ -65,7 +68,7 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
})}
>
<div class="when">
${isUnavailableState(stateObj.state)
${noValue
? this.hass.formatEntityState(stateObj)
: html`<hui-timestamp-display
.hass=${this.hass}
@@ -75,7 +78,7 @@ class HuiEventEntityRow extends LitElement implements LovelaceRow {
></hui-timestamp-display>`}
</div>
<div class="what">
${isUnavailableState(stateObj.state)
${noValue
? 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 { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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 && isUnavailableState(newValue)) {
if (newValue && (newValue === UNAVAILABLE || newValue === UNKNOWN)) {
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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } 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=${isUnavailableState(stateObj.state)}
.disabled=${stateObj.state === UNAVAILABLE}
class="text-content"
>
${stateObj.state === "locked"
@@ -22,7 +22,7 @@ import { supportsFeature } from "../../../common/entity/supports-feature";
import { debounce } from "../../../common/util/debounce";
import "../../../components/ha-icon-button";
import "../../../components/ha-slider";
import { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } from "../../../data/entity/entity";
import type {
ControlButton,
MediaPlayerEntity,
@@ -195,7 +195,7 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow {
<div class="controls">
${supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_ON) &&
(!stateActive(stateObj) || assumedState) &&
!isUnavailableState(entityState)
entityState !== UNAVAILABLE
? html`
<ha-icon-button
.path=${assumedState ? mdiPowerOn : mdiPower}
@@ -209,7 +209,7 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow {
(stateActive(stateObj) ||
assumedState ||
!supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_ON) ||
isUnavailableState(entityState))
entityState === UNAVAILABLE)
? buttons
: ""}
${supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_OFF) &&
@@ -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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE } 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,8 +68,7 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
appearance="plain"
size="small"
@click=${this._runScript}
.disabled=${isUnavailableState(stateObj.state) ||
!canRun(stateObj)}
.disabled=${stateObj.state === UNAVAILABLE || !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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import {
SENSOR_DEVICE_CLASS_UPTIME,
SENSOR_TIMESTAMP_DEVICE_CLASSES,
@@ -55,7 +55,9 @@ 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
) && !isUnavailableState(stateObj.state)
) &&
stateObj.state !== UNAVAILABLE &&
stateObj.state !== UNKNOWN
? 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 { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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 && isUnavailableState(newValue)) {
if (newValue && (newValue === UNAVAILABLE || newValue === UNKNOWN)) {
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 { isUnavailableState, UNAVAILABLE } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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=${isUnavailableState(stateObj.state)
.value=${stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
? 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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -44,7 +44,8 @@ class HuiToggleEntityRow extends LitElement implements LovelaceRow {
const showToggle =
stateObj.state === "on" ||
stateObj.state === "off" ||
isUnavailableState(stateObj.state);
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN;
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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
@@ -44,7 +44,8 @@ class HuiValveEntityRow extends LitElement implements LovelaceRow {
const showToggle =
stateObj.state === "open" ||
stateObj.state === "closed" ||
isUnavailableState(stateObj.state);
stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN;
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 { isUnavailableState } from "../../../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { ForecastEvent, WeatherEntity } from "../../../data/weather";
import {
@@ -193,7 +193,8 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
})}
>
<div>
${isUnavailableState(stateObj.state) ||
${stateObj.state === UNAVAILABLE ||
stateObj.state === UNKNOWN ||
stateObj.attributes.temperature === undefined ||
stateObj.attributes.temperature === null
? this.hass.formatEntityState(stateObj)
+5 -3
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 { isUnavailableState } from "../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import {
SENSOR_TIMESTAMP_DEVICE_CLASSES,
SENSOR_DEVICE_CLASS_UPTIME,
@@ -89,7 +89,9 @@ class StateDisplay extends LitElement {
const domain = computeStateDomain(stateObj);
if (content === "state") {
if (this.dashUnavailable && isUnavailableState(stateObj.state)) {
const noValue =
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN;
if (this.dashUnavailable && noValue) {
return "—";
}
if (
@@ -97,7 +99,7 @@ class StateDisplay extends LitElement {
this.stateObj.attributes.device_class
) ||
TIMESTAMP_STATE_DOMAINS.includes(domain)) &&
!isUnavailableState(stateObj.state)
!noValue
) {
return html`
<hui-timestamp-display
+3 -2
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 { isUnavailableState } from "../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } from "../data/entity/entity";
import {
SENSOR_TIMESTAMP_DEVICE_CLASSES,
SENSOR_DEVICE_CLASS_UPTIME,
@@ -44,7 +44,8 @@ class StateCardDisplay extends LitElement {
SENSOR_TIMESTAMP_DEVICE_CLASSES.includes(
this.stateObj.attributes.device_class
) &&
!isUnavailableState(this.stateObj.state)
this.stateObj.state !== UNAVAILABLE &&
this.stateObj.state !== UNKNOWN
? html`<hui-timestamp-display
.hass=${this.hass}
.ts=${new Date(this.stateObj.state)}
+2 -3
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 { isUnavailableState } from "../data/entity/entity";
import { UNAVAILABLE } 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,8 +48,7 @@ class StateCardScript extends LitElement {
appearance="plain"
size="small"
@click=${this._runScript}
.disabled=${isUnavailableState(stateObj.state) ||
!canRun(stateObj)}
.disabled=${stateObj.state === UNAVAILABLE || !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 { isUnavailableState, UNAVAILABLE } from "../data/entity/entity";
import { UNAVAILABLE, UNKNOWN } 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 && isUnavailableState(value)) {
if (value && (value === UNAVAILABLE || value === UNKNOWN)) {
(ev.target as HaInput).value = this.stateObj.state;
return;
}
-5
View File
@@ -5043,11 +5043,6 @@
"placeholder": "Optional description",
"add": "Add description"
},
"comment": {
"label": "Comment",
"edit": "Edit comment",
"add": "Add comment"
},
"leave": {
"unsaved_new_title": "Save new automation?",
"unsaved_new_text": "You can save your changes, or delete this automation. You can't undo this action.",