Add 'Not' to lovelace visibility conditions (#26408)

:Add 'Not' to lovelace visibility conditions
This commit is contained in:
Luke Mondy 2025-08-07 23:40:27 +10:00 committed by GitHub
parent 39d14c943c
commit 0b3e4eab23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 89 additions and 1 deletions

View File

@ -2,6 +2,7 @@ import {
mdiAccount,
mdiAmpersand,
mdiGateOr,
mdiNotEqualVariant,
mdiNumeric,
mdiResponsive,
mdiStateMachine,
@ -14,5 +15,6 @@ export const ICON_CONDITION: Record<Condition["condition"], string> = {
screen: mdiResponsive,
user: mdiAccount,
and: mdiAmpersand,
not: mdiNotEqualVariant,
or: mdiGateOr,
};

View File

@ -11,7 +11,8 @@ export type Condition =
| ScreenCondition
| UserCondition
| OrCondition
| AndCondition;
| AndCondition
| NotCondition;
// Legacy conditional card condition
export interface LegacyCondition {
@ -58,6 +59,11 @@ export interface AndCondition extends BaseCondition {
conditions?: Condition[];
}
export interface NotCondition extends BaseCondition {
condition: "not";
conditions?: Condition[];
}
function getValueFromEntityId(
hass: HomeAssistant,
value: string
@ -149,6 +155,11 @@ function checkAndCondition(condition: AndCondition, hass: HomeAssistant) {
return checkConditionsMet(condition.conditions, hass);
}
function checkNotCondition(condition: NotCondition, hass: HomeAssistant) {
if (!condition.conditions) return true;
return !checkConditionsMet(condition.conditions, hass);
}
function checkOrCondition(condition: OrCondition, hass: HomeAssistant) {
if (!condition.conditions) return true;
return condition.conditions.some((c) => checkConditionsMet([c], hass));
@ -175,6 +186,8 @@ export function checkConditionsMet(
return checkStateNumericCondition(c, hass);
case "and":
return checkAndCondition(c, hass);
case "not":
return checkNotCondition(c, hass);
case "or":
return checkOrCondition(c, hass);
default:
@ -247,6 +260,10 @@ function validateAndCondition(condition: AndCondition) {
return condition.conditions != null;
}
function validateNotCondition(condition: NotCondition) {
return condition.conditions != null;
}
function validateOrCondition(condition: OrCondition) {
return condition.conditions != null;
}
@ -276,6 +293,8 @@ export function validateConditionalConfig(
return validateNumericStateCondition(c);
case "and":
return validateAndCondition(c);
case "not":
return validateNotCondition(c);
case "or":
return validateOrCondition(c);
default:

View File

@ -18,6 +18,7 @@ import "./ha-card-condition-editor";
import type { HaCardConditionEditor } from "./ha-card-condition-editor";
import type { LovelaceConditionEditorConstructor } from "./types";
import "./types/ha-card-condition-and";
import "./types/ha-card-condition-not";
import "./types/ha-card-condition-numeric_state";
import "./types/ha-card-condition-or";
import "./types/ha-card-condition-screen";
@ -30,6 +31,7 @@ const UI_CONDITION = [
"screen",
"user",
"and",
"not",
"or",
] as const satisfies readonly Condition["condition"][];

View File

@ -0,0 +1,62 @@
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { any, array, assert, literal, object, optional } from "superstruct";
import { fireEvent } from "../../../../../common/dom/fire_event";
import "../../../../../components/ha-form/ha-form";
import type { HomeAssistant } from "../../../../../types";
import type {
NotCondition,
Condition,
StateCondition,
} from "../../../common/validate-condition";
import "../ha-card-conditions-editor";
const notConditionStruct = object({
condition: literal("not"),
conditions: optional(array(any())),
});
@customElement("ha-card-condition-not")
export class HaCardConditionNot extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public condition!: NotCondition;
@property({ type: Boolean }) public disabled = false;
public static get defaultConfig(): NotCondition {
return { condition: "not", conditions: [] };
}
protected static validateUIConfig(condition: StateCondition) {
return assert(condition, notConditionStruct);
}
protected render() {
return html`
<ha-card-conditions-editor
nested
.hass=${this.hass}
.conditions=${this.condition.conditions}
@value-changed=${this._valueChanged}
>
</ha-card-conditions-editor>
`;
}
private _valueChanged(ev: CustomEvent): void {
ev.stopPropagation();
const conditions = ev.detail.value as Condition[];
const condition = {
...this.condition,
conditions,
};
fireEvent(this, "value-changed", { value: condition });
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-card-condition-not": HaCardConditionNot;
}
}

View File

@ -7283,6 +7283,9 @@
"or": {
"label": "Or"
},
"not": {
"label": "Not"
},
"and": {
"label": "And"
}