Compare commits

...
6 changed files with 189 additions and 93 deletions
@@ -8,8 +8,8 @@ import { truncateWithEllipsis } from "../../common/string/truncate-with-ellipsis
import type { Condition } from "../../data/automation";
import type { ConditionDescription } from "../../data/condition";
import { internationalizationContext } from "../../data/context";
import "../../panels/config/automation/ha-automation-row-behavior";
import "../../panels/config/automation/ha-automation-row-options";
import "../../panels/config/automation/ha-automation-row-threshold";
import { getDeviceTarget } from "../../panels/config/automation/target/get_device_target";
import { getEntityTarget } from "../../panels/config/automation/target/get_entity_target";
import "../../panels/config/automation/target/ha-automation-row-targets";
@@ -63,10 +63,13 @@ export class HaAutomationConditionSummary extends LitElement {
${this.label}
${
this.description && this.condition
? html`<ha-automation-row-behavior
mode="condition"
.config=${this.condition}
></ha-automation-row-behavior>`
? html`<ha-automation-row-threshold
.config=${this.condition}
.description=${this.description}
></ha-automation-row-threshold>
<ha-automation-row-options
.config=${this.condition}
></ha-automation-row-options> `
: nothing
}
${
@@ -83,13 +86,6 @@ export class HaAutomationConditionSummary extends LitElement {
></ha-automation-row-targets>`
: nothing
}
${
this.description && this.condition
? html`<ha-automation-row-options
.config=${this.condition}
></ha-automation-row-options>`
: nothing
}
<slot name="references"></slot>
${
note
@@ -1,8 +1,8 @@
import memoizeOne from "memoize-one";
import { mdiChartBellCurveCumulative } from "@mdi/js";
import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { mdiChartBellCurveCumulative } from "@mdi/js";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../common/dom/fire_event";
import type {
NumericThresholdSelector,
@@ -28,14 +28,14 @@ const iconThresholdOutside =
type ThresholdType = "above" | "below" | "between" | "outside" | "any";
interface ThresholdValueEntry {
export interface ThresholdValueEntry {
active_choice?: string;
number?: number;
entity?: string;
unit_of_measurement?: string;
}
interface NumericThresholdValue {
export interface NumericThresholdValue {
type: ThresholdType;
value?: ThresholdValueEntry;
value_min?: ThresholdValueEntry;
@@ -1,66 +0,0 @@
import { consume, type ContextType } from "@lit/context";
import { html, LitElement, nothing, type PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import { internationalizationContext } from "../../../data/context";
import type {
AutomationBehaviorConditionMode,
AutomationBehaviorTriggerMode,
} from "../../../data/selector";
import { rowSummaryStyles } from "./styles";
interface HaAutomationRowBehaviorConfig {
options?: {
behavior?: AutomationBehaviorTriggerMode | AutomationBehaviorConditionMode;
};
}
@customElement("ha-automation-row-behavior")
export class HaAutomationRowBehavior extends LitElement {
@property({ attribute: false }) public config!: HaAutomationRowBehaviorConfig;
@property() public mode: "trigger" | "condition" = "trigger";
@state()
@consume({ context: internationalizationContext, subscribe: true })
private _i18n!: ContextType<typeof internationalizationContext>;
private get _label(): string | undefined {
const behavior = this.config?.options?.behavior;
if (!behavior) {
return undefined;
}
return (
(this.mode === "condition"
? this._i18n?.localize(
`ui.components.selectors.automation_behavior.condition.options.${behavior as AutomationBehaviorConditionMode}.row_label`
)
: this._i18n?.localize(
`ui.components.selectors.automation_behavior.trigger.options.${behavior as AutomationBehaviorTriggerMode}.row_label`
)) || undefined
);
}
protected render() {
const label = this._label;
if (!label) {
return nothing;
}
return html`<span class="dot-separator"></span>${label}`;
}
protected updated(changedProperties: PropertyValues): void {
super.updated(changedProperties);
// Collapse the host when empty so the parent flex gap is not reserved.
this.toggleAttribute("hidden", !this._label);
}
static styles = rowSummaryStyles;
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-row-behavior": HaAutomationRowBehavior;
}
}
@@ -0,0 +1,159 @@
import { consume, type ContextType } from "@lit/context";
import { html, LitElement, nothing, type PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { formatNumber } from "../../../common/number/format_number";
import { blankBeforeUnit } from "../../../common/translations/blank_before_unit";
import type {
NumericThresholdValue,
ThresholdValueEntry,
} from "../../../components/ha-selector/ha-selector-numeric-threshold";
import type {
PlatformCondition,
PlatformTrigger,
} from "../../../data/automation";
import type { ConditionDescription } from "../../../data/condition";
import { internationalizationContext } from "../../../data/context";
import type { NumericThresholdSelector } from "../../../data/selector";
import type { TriggerDescription } from "../../../data/trigger";
import { rowSummaryStyles } from "./styles";
@customElement("ha-automation-row-threshold")
export class HaAutomationRowThreshold extends LitElement {
@property({ attribute: false })
public config!: PlatformTrigger | PlatformCondition;
@property({ attribute: false })
public description?: TriggerDescription | ConditionDescription;
@state()
@consume({ context: internationalizationContext, subscribe: true })
private _i18n!: ContextType<typeof internationalizationContext>;
protected updated(changedProperties: PropertyValues): void {
super.updated(changedProperties);
// Collapse the host when empty so the parent flex gap is not reserved.
this.toggleAttribute(
"hidden",
!this._getLabel(
this._getThreshold(this.config, this.description),
this._i18n
)
);
}
protected render() {
const label = this._getLabel(
this._getThreshold(this.config, this.description),
this._i18n
);
if (!label) {
return nothing;
}
return html`<span class="dot-separator"></span>${label}`;
}
private _getThreshold = memoizeOne(
(
config: PlatformTrigger | PlatformCondition,
description: TriggerDescription | ConditionDescription | undefined
) => {
const fields = description?.fields;
if (!fields || !config.options) {
return undefined;
}
const entry = Object.entries(fields).find(
([, field]) => field.selector && "numeric_threshold" in field.selector
);
if (!entry) {
return undefined;
}
const value = config.options[entry[0]] as
NumericThresholdValue | undefined;
if (!value?.type) {
return undefined;
}
const threshold = (entry[1].selector as NumericThresholdSelector)
.numeric_threshold;
const fallbackUnit =
threshold?.unit_of_measurement?.[0] ??
threshold?.number?.unit_of_measurement;
const withUnit = (bound?: ThresholdValueEntry) =>
bound
? {
...bound,
unit_of_measurement: bound.unit_of_measurement ?? fallbackUnit,
}
: bound;
return {
...value,
value: withUnit(value.value),
value_min: withUnit(value.value_min),
value_max: withUnit(value.value_max),
};
}
);
private _getLabel = memoizeOne(
(threshold: NumericThresholdValue | undefined, i18n: typeof this._i18n) => {
if (
!threshold ||
!threshold?.type ||
threshold.type === "any" ||
threshold.value?.active_choice === "entity" ||
threshold.value_min?.active_choice === "entity" ||
threshold.value_max?.active_choice === "entity"
) {
return undefined;
}
if (threshold.type === "between" || threshold.type === "outside") {
const min = threshold.value_min?.number;
const max = threshold.value_max?.number;
if (min === undefined || max === undefined) {
return undefined;
}
const separateUnits =
threshold.value_min?.unit_of_measurement !==
threshold.value_max?.unit_of_measurement;
const range = `${formatNumber(min, this._i18n.locale)}${separateUnits ? this._unit(threshold.value_min?.unit_of_measurement) : ""} ${formatNumber(max, this._i18n.locale)}${this._unit(threshold.value_max?.unit_of_measurement)}`;
return i18n.localize(
`ui.components.selectors.numeric_threshold.row_label.${threshold.type}`,
{ value: range }
);
}
if (isNaN(Number(threshold.value?.number))) {
return undefined;
}
return i18n.localize(
`ui.components.selectors.numeric_threshold.row_label.${threshold.type}`,
{
value: `${formatNumber(threshold.value!.number!, this._i18n.locale)}${this._unit(threshold.value!.unit_of_measurement ?? "")}`,
}
);
}
);
private _unit(unit?: string): string {
if (!unit) {
return "";
}
return `${blankBeforeUnit(unit, this._i18n.locale)}${unit}`;
}
static styles = rowSummaryStyles;
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-row-threshold": HaAutomationRowThreshold;
}
}
@@ -73,8 +73,8 @@ import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import { showEditorToast } from "../editor-toast";
import "../ha-automation-editor-warning";
import "../ha-automation-row-behavior";
import "../ha-automation-row-options";
import "../ha-automation-row-threshold";
import { overflowStyles, rowStyles } from "../styles";
import { getDeviceTarget } from "../target/get_device_target";
import { getEntityTarget } from "../target/get_entity_target";
@@ -303,9 +303,17 @@ export default class HaAutomationTriggerRow extends LitElement {
)}
${
type === "platform"
? html`<ha-automation-row-behavior
.config=${this.trigger}
></ha-automation-row-behavior>`
? html`<ha-automation-row-threshold
.config=${this.trigger}
.description=${
this.triggerDescriptions[
(this.trigger as PlatformTrigger).trigger
]
}
></ha-automation-row-threshold>
<ha-automation-row-options
.config=${this.trigger}
></ha-automation-row-options>`
: nothing
}
${
@@ -318,13 +326,6 @@ export default class HaAutomationTriggerRow extends LitElement {
)
: nothing
}
${
type === "platform"
? html`<ha-automation-row-options
.config=${this.trigger}
></ha-automation-row-options>`
: nothing
}
${
type !== "list" &&
(this.trigger as Exclude<Trigger, TriggerList>).note?.trim()
+6
View File
@@ -642,6 +642,12 @@
"entity": "Entity",
"from": "From",
"to": "To",
"row_label": {
"above": "above {value}",
"below": "below {value}",
"between": "in range {value}",
"outside": "outside {value}"
},
"crossed": {
"type": "Fire when the value goes",
"above": "Above",