Add customize mode option to card features with modes (#20670)

* Add customize mode options to card features with modes

* Better type

* Fix water heater and humidifier

* Clean schema
This commit is contained in:
Paul Bottein 2024-04-30 18:38:51 +02:00 committed by GitHub
parent 334c245b65
commit 7120ad99b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 403 additions and 154 deletions

View File

@ -2,6 +2,6 @@ export const filterModes = (
supportedModes: string[] | undefined,
selectedModes: string[] | undefined
): string[] =>
(selectedModes || []).length
? selectedModes!.filter((mode) => (supportedModes || []).includes(mode))
selectedModes
? selectedModes.filter((mode) => (supportedModes || []).includes(mode))
: supportedModes || [];

View File

@ -45,7 +45,6 @@ class HuiClimateFanModesCardFeature
return {
type: "climate-fan-modes",
style: "dropdown",
fan_modes: [],
};
}

View File

@ -19,8 +19,8 @@ import {
import { UNAVAILABLE } from "../../../data/entity";
import { HomeAssistant } from "../../../types";
import { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
import { ClimateHvacModesCardFeatureConfig } from "./types";
import { filterModes } from "./common/filter-modes";
import { ClimateHvacModesCardFeatureConfig } from "./types";
export const supportsClimateHvacModesCardFeature = (stateObj: HassEntity) => {
const domain = computeDomain(stateObj.entity_id);
@ -46,7 +46,6 @@ class HuiClimateHvacModesCardFeature
static getStubConfig(): ClimateHvacModesCardFeatureConfig {
return {
type: "climate-hvac-modes",
hvac_modes: [],
};
}
@ -120,10 +119,12 @@ class HuiClimateHvacModesCardFeature
const color = stateColorCss(this.stateObj);
const ordererHvacModes = (this.stateObj.attributes.hvac_modes || [])
.concat()
.sort(compareClimateHvacModes);
const options = filterModes(
[...(this.stateObj?.attributes.hvac_modes || [])].sort(
compareClimateHvacModes
),
ordererHvacModes,
this._config.hvac_modes
).map<ControlSelectOption>((mode) => ({
value: mode,

View File

@ -45,7 +45,6 @@ class HuiClimatePresetModesCardFeature
return {
type: "climate-preset-modes",
style: "dropdown",
preset_modes: [],
};
}

View File

@ -45,7 +45,6 @@ class HuiClimateSwingModesCardFeature
return {
type: "climate-swing-modes",
style: "dropdown",
swing_modes: [],
};
}

View File

@ -44,7 +44,6 @@ class HuiFanPresetModesCardFeature
return {
type: "fan-preset-modes",
style: "dropdown",
preset_modes: [],
};
}

View File

@ -48,7 +48,6 @@ class HuiHumidifierModesCardFeature
return {
type: "humidifier-modes",
style: "dropdown",
modes: [],
};
}

View File

@ -44,7 +44,6 @@ class HuiWaterHeaterOperationModeCardFeature
static getStubConfig(): WaterHeaterOperationModesCardFeatureConfig {
return {
type: "water-heater-operation-modes",
operation_modes: [],
};
}
@ -105,10 +104,12 @@ class HuiWaterHeaterOperationModeCardFeature
const color = stateColorCss(this.stateObj);
const orderedModes = (this.stateObj.attributes.operation_list || [])
.concat()
.sort(compareWaterHeaterOperationMode);
const options = filterModes(
[...(this.stateObj?.attributes.operation_list || [])].sort(
compareWaterHeaterOperationMode
),
orderedModes,
this._config.operation_modes
).map<ControlSelectOption>((mode) => ({
value: mode,

View File

@ -17,6 +17,10 @@ import {
} from "../../card-features/types";
import type { LovelaceCardFeatureEditor } from "../../types";
type ClimateFanModesCardFeatureData = ClimateFanModesCardFeatureConfig & {
customize_modes: boolean;
};
@customElement("hui-climate-fan-modes-card-feature-editor")
export class HuiClimateFanModesCardFeatureEditor
extends LitElement
@ -36,7 +40,8 @@ export class HuiClimateFanModesCardFeatureEditor
(
localize: LocalizeFunc,
formatEntityAttributeValue: FormatEntityAttributeValueFunc,
stateObj?: HassEntity
stateObj: HassEntity | undefined,
customizeModes: boolean
) =>
[
{
@ -55,20 +60,33 @@ export class HuiClimateFanModesCardFeatureEditor
},
},
{
name: "fan_modes",
name: "customize_modes",
selector: {
select: {
multiple: true,
reorder: true,
mode: "list",
options:
stateObj?.attributes.fan_modes?.map((mode) => ({
value: mode,
label: formatEntityAttributeValue(stateObj, "fan_mode", mode),
})) || [],
},
boolean: {},
},
},
...(customizeModes
? ([
{
name: "fan_modes",
selector: {
select: {
multiple: true,
reorder: true,
options:
stateObj?.attributes.fan_modes?.map((mode) => ({
value: mode,
label: formatEntityAttributeValue(
stateObj,
"fan_mode",
mode
),
})) || [],
},
},
},
] as const satisfies readonly HaFormSchema[])
: []),
] as const satisfies readonly HaFormSchema[]
);
@ -81,16 +99,17 @@ export class HuiClimateFanModesCardFeatureEditor
? this.hass.states[this.context?.entity_id]
: undefined;
const data: ClimateFanModesCardFeatureConfig = {
const data: ClimateFanModesCardFeatureData = {
style: "dropdown",
fan_modes: [],
...this._config,
customize_modes: this._config.fan_modes !== undefined,
};
const schema = this._schema(
this.hass.localize,
this.hass.formatEntityAttributeValue,
stateObj
stateObj,
data.customize_modes
);
return html`
@ -105,7 +124,21 @@ export class HuiClimateFanModesCardFeatureEditor
}
private _valueChanged(ev: CustomEvent): void {
fireEvent(this, "config-changed", { config: ev.detail.value });
const { customize_modes, ...config } = ev.detail
.value as ClimateFanModesCardFeatureData;
const stateObj = this.context?.entity_id
? this.hass!.states[this.context?.entity_id]
: undefined;
if (customize_modes && !config.fan_modes) {
config.fan_modes = stateObj?.attributes.fan_modes || [];
}
if (!customize_modes && config.fan_modes) {
delete config.fan_modes;
}
fireEvent(this, "config-changed", { config: config });
}
private _computeLabelCallback = (
@ -114,6 +147,7 @@ export class HuiClimateFanModesCardFeatureEditor
switch (schema.name) {
case "style":
case "fan_modes":
case "customize_modes":
return this.hass!.localize(
`ui.panel.lovelace.editor.features.types.climate-fan-modes.${schema.name}`
);

View File

@ -6,8 +6,11 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import type { FormatEntityStateFunc } from "../../../../common/translations/entity-state";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import "../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../components/ha-form/types";
import { HVAC_MODES } from "../../../../data/climate";
import type {
HaFormSchema,
SchemaUnion,
} from "../../../../components/ha-form/types";
import { compareClimateHvacModes } from "../../../../data/climate";
import type { HomeAssistant } from "../../../../types";
import {
ClimateHvacModesCardFeatureConfig,
@ -15,6 +18,10 @@ import {
} from "../../card-features/types";
import type { LovelaceCardFeatureEditor } from "../../types";
type ClimateHvacModesCardFeatureData = ClimateHvacModesCardFeatureConfig & {
customize_modes: boolean;
};
@customElement("hui-climate-hvac-modes-card-feature-editor")
export class HuiClimateHvacModesCardFeatureEditor
extends LitElement
@ -34,7 +41,8 @@ export class HuiClimateHvacModesCardFeatureEditor
(
localize: LocalizeFunc,
formatEntityState: FormatEntityStateFunc,
stateObj?: HassEntity
stateObj: HassEntity | undefined,
customizeModes: boolean
) =>
[
{
@ -53,22 +61,34 @@ export class HuiClimateHvacModesCardFeatureEditor
},
},
{
name: "hvac_modes",
name: "customize_modes",
selector: {
select: {
multiple: true,
reorder: true,
mode: "list",
options: HVAC_MODES.filter((mode) =>
stateObj?.attributes.hvac_modes?.includes(mode)
).map((mode) => ({
value: mode,
label: stateObj ? formatEntityState(stateObj, mode) : mode,
})),
},
boolean: {},
},
},
] as const
...(customizeModes
? ([
{
name: "hvac_modes",
selector: {
select: {
reorder: true,
multiple: true,
options: (stateObj?.attributes.hvac_modes || [])
.concat()
.sort(compareClimateHvacModes)
.map((mode) => ({
value: mode,
label: stateObj
? formatEntityState(stateObj, mode)
: mode,
})),
},
},
},
] as const satisfies readonly HaFormSchema[])
: []),
] as const satisfies readonly HaFormSchema[]
);
protected render() {
@ -80,16 +100,17 @@ export class HuiClimateHvacModesCardFeatureEditor
? this.hass.states[this.context?.entity_id]
: undefined;
const data: ClimateHvacModesCardFeatureConfig = {
const data: ClimateHvacModesCardFeatureData = {
style: "icons",
hvac_modes: [],
...this._config,
customize_modes: this._config.hvac_modes !== undefined,
};
const schema = this._schema(
this.hass.localize,
this.hass.formatEntityState,
stateObj
stateObj,
data.customize_modes
);
return html`
@ -104,7 +125,24 @@ export class HuiClimateHvacModesCardFeatureEditor
}
private _valueChanged(ev: CustomEvent): void {
fireEvent(this, "config-changed", { config: ev.detail.value });
const { customize_modes, ...config } = ev.detail
.value as ClimateHvacModesCardFeatureData;
const stateObj = this.context?.entity_id
? this.hass!.states[this.context?.entity_id]
: undefined;
if (customize_modes && !config.hvac_modes) {
const ordererHvacModes = (stateObj?.attributes.hvac_modes || [])
.concat()
.sort(compareClimateHvacModes);
config.hvac_modes = ordererHvacModes;
}
if (!customize_modes && config.hvac_modes) {
delete config.hvac_modes;
}
fireEvent(this, "config-changed", { config: config });
}
private _computeLabelCallback = (
@ -113,6 +151,7 @@ export class HuiClimateHvacModesCardFeatureEditor
switch (schema.name) {
case "hvac_modes":
case "style":
case "customize_modes":
return this.hass!.localize(
`ui.panel.lovelace.editor.features.types.climate-hvac-modes.${schema.name}`
);

View File

@ -17,6 +17,10 @@ import {
} from "../../card-features/types";
import type { LovelaceCardFeatureEditor } from "../../types";
type ClimatePresetModesCardFeatureData = ClimatePresetModesCardFeatureConfig & {
customize_modes: boolean;
};
@customElement("hui-climate-preset-modes-card-feature-editor")
export class HuiClimatePresetModesCardFeatureEditor
extends LitElement
@ -36,7 +40,8 @@ export class HuiClimatePresetModesCardFeatureEditor
(
localize: LocalizeFunc,
formatEntityAttributeValue: FormatEntityAttributeValueFunc,
stateObj?: HassEntity
stateObj: HassEntity | undefined,
customizeModes: boolean
) =>
[
{
@ -55,24 +60,33 @@ export class HuiClimatePresetModesCardFeatureEditor
},
},
{
name: "preset_modes",
name: "customize_modes",
selector: {
select: {
multiple: true,
reorder: true,
mode: "list",
options:
stateObj?.attributes.preset_modes?.map((mode) => ({
value: mode,
label: formatEntityAttributeValue(
stateObj,
"preset_mode",
mode
),
})) || [],
},
boolean: {},
},
},
...(customizeModes
? ([
{
name: "preset_modes",
selector: {
select: {
reorder: true,
multiple: true,
options:
stateObj?.attributes.preset_modes?.map((mode) => ({
value: mode,
label: formatEntityAttributeValue(
stateObj,
"preset_mode",
mode
),
})) || [],
},
},
},
] as const satisfies readonly HaFormSchema[])
: []),
] as const satisfies readonly HaFormSchema[]
);
@ -85,16 +99,17 @@ export class HuiClimatePresetModesCardFeatureEditor
? this.hass.states[this.context?.entity_id]
: undefined;
const data: ClimatePresetModesCardFeatureConfig = {
const data: ClimatePresetModesCardFeatureData = {
style: "dropdown",
preset_modes: [],
...this._config,
customize_modes: this._config.preset_modes !== undefined,
};
const schema = this._schema(
this.hass.localize,
this.hass.formatEntityAttributeValue,
stateObj
stateObj,
data.customize_modes
);
return html`
@ -109,7 +124,21 @@ export class HuiClimatePresetModesCardFeatureEditor
}
private _valueChanged(ev: CustomEvent): void {
fireEvent(this, "config-changed", { config: ev.detail.value });
const { customize_modes, ...config } = ev.detail
.value as ClimatePresetModesCardFeatureData;
const stateObj = this.context?.entity_id
? this.hass!.states[this.context?.entity_id]
: undefined;
if (customize_modes && !config.preset_modes) {
config.preset_modes = stateObj?.attributes.preset_modes || [];
}
if (!customize_modes && config.preset_modes) {
delete config.preset_modes;
}
fireEvent(this, "config-changed", { config: config });
}
private _computeLabelCallback = (
@ -118,6 +147,7 @@ export class HuiClimatePresetModesCardFeatureEditor
switch (schema.name) {
case "style":
case "preset_modes":
case "customize_modes":
return this.hass!.localize(
`ui.panel.lovelace.editor.features.types.climate-preset-modes.${schema.name}`
);

View File

@ -17,6 +17,10 @@ import {
} from "../../card-features/types";
import type { LovelaceCardFeatureEditor } from "../../types";
type ClimateSwingModesCardFeatureData = ClimateSwingModesCardFeatureConfig & {
customize_modes: boolean;
};
@customElement("hui-climate-swing-modes-card-feature-editor")
export class HuiClimateSwingModesCardFeatureEditor
extends LitElement
@ -36,7 +40,8 @@ export class HuiClimateSwingModesCardFeatureEditor
(
localize: LocalizeFunc,
formatEntityAttributeValue: FormatEntityAttributeValueFunc,
stateObj?: HassEntity
stateObj: HassEntity | undefined,
customizeModes: boolean
) =>
[
{
@ -55,24 +60,33 @@ export class HuiClimateSwingModesCardFeatureEditor
},
},
{
name: "swing_modes",
name: "customize_modes",
selector: {
select: {
multiple: true,
reorder: true,
mode: "list",
options:
stateObj?.attributes.swing_modes?.map((mode) => ({
value: mode,
label: formatEntityAttributeValue(
stateObj,
"swing_mode",
mode
),
})) || [],
},
boolean: {},
},
},
...(customizeModes
? ([
{
name: "swing_modes",
selector: {
select: {
reorder: true,
multiple: true,
options:
stateObj?.attributes.swing_modes?.map((mode) => ({
value: mode,
label: formatEntityAttributeValue(
stateObj,
"swing_mode",
mode
),
})) || [],
},
},
},
] as const satisfies readonly HaFormSchema[])
: []),
] as const satisfies readonly HaFormSchema[]
);
@ -85,16 +99,17 @@ export class HuiClimateSwingModesCardFeatureEditor
? this.hass.states[this.context?.entity_id]
: undefined;
const data: ClimateSwingModesCardFeatureConfig = {
const data: ClimateSwingModesCardFeatureData = {
style: "dropdown",
swing_modes: [],
...this._config,
customize_modes: this._config.swing_modes !== undefined,
};
const schema = this._schema(
this.hass.localize,
this.hass.formatEntityAttributeValue,
stateObj
stateObj,
data.customize_modes
);
return html`
@ -109,7 +124,21 @@ export class HuiClimateSwingModesCardFeatureEditor
}
private _valueChanged(ev: CustomEvent): void {
fireEvent(this, "config-changed", { config: ev.detail.value });
const { customize_modes, ...config } = ev.detail
.value as ClimateSwingModesCardFeatureData;
const stateObj = this.context?.entity_id
? this.hass!.states[this.context?.entity_id]
: undefined;
if (customize_modes && !config.swing_modes) {
config.swing_modes = stateObj?.attributes.swing_modes || [];
}
if (!customize_modes && config.swing_modes) {
delete config.swing_modes;
}
fireEvent(this, "config-changed", { config: config });
}
private _computeLabelCallback = (
@ -118,6 +147,7 @@ export class HuiClimateSwingModesCardFeatureEditor
switch (schema.name) {
case "style":
case "swing_modes":
case "customize_modes":
return this.hass!.localize(
`ui.panel.lovelace.editor.features.types.climate-swing-modes.${schema.name}`
);

View File

@ -17,6 +17,10 @@ import {
} from "../../card-features/types";
import type { LovelaceCardFeatureEditor } from "../../types";
type FanPresetModesCardFeatureData = FanPresetModesCardFeatureConfig & {
customize_modes: boolean;
};
@customElement("hui-fan-preset-modes-card-feature-editor")
export class HuiFanPresetModesCardFeatureEditor
extends LitElement
@ -36,7 +40,8 @@ export class HuiFanPresetModesCardFeatureEditor
(
localize: LocalizeFunc,
formatEntityAttributeValue: FormatEntityAttributeValueFunc,
stateObj?: HassEntity
stateObj: HassEntity | undefined,
customizeModes: boolean
) =>
[
{
@ -55,24 +60,33 @@ export class HuiFanPresetModesCardFeatureEditor
},
},
{
name: "preset_modes",
name: "customize_modes",
selector: {
select: {
multiple: true,
reorder: true,
mode: "list",
options:
stateObj?.attributes.preset_modes?.map((mode) => ({
value: mode,
label: formatEntityAttributeValue(
stateObj,
"preset_mode",
mode
),
})) || [],
},
boolean: {},
},
},
...(customizeModes
? ([
{
name: "preset_modes",
selector: {
select: {
reorder: true,
multiple: true,
options:
stateObj?.attributes.preset_modes?.map((mode) => ({
value: mode,
label: formatEntityAttributeValue(
stateObj,
"preset_mode",
mode
),
})) || [],
},
},
},
] as const satisfies readonly HaFormSchema[])
: []),
] as const satisfies readonly HaFormSchema[]
);
@ -85,16 +99,17 @@ export class HuiFanPresetModesCardFeatureEditor
? this.hass.states[this.context?.entity_id]
: undefined;
const data: FanPresetModesCardFeatureConfig = {
const data: FanPresetModesCardFeatureData = {
style: "dropdown",
preset_modes: [],
...this._config,
customize_modes: this._config.preset_modes !== undefined,
};
const schema = this._schema(
this.hass.localize,
this.hass.formatEntityAttributeValue,
stateObj
stateObj,
data.customize_modes
);
return html`
@ -109,7 +124,21 @@ export class HuiFanPresetModesCardFeatureEditor
}
private _valueChanged(ev: CustomEvent): void {
fireEvent(this, "config-changed", { config: ev.detail.value });
const { customize_modes, ...config } = ev.detail
.value as FanPresetModesCardFeatureData;
const stateObj = this.context?.entity_id
? this.hass!.states[this.context?.entity_id]
: undefined;
if (customize_modes && !config.preset_modes) {
config.preset_modes = stateObj?.attributes.preset_modes || [];
}
if (!customize_modes && config.preset_modes) {
delete config.preset_modes;
}
fireEvent(this, "config-changed", { config: config });
}
private _computeLabelCallback = (
@ -118,6 +147,7 @@ export class HuiFanPresetModesCardFeatureEditor
switch (schema.name) {
case "style":
case "preset_modes":
case "customize_modes":
return this.hass!.localize(
`ui.panel.lovelace.editor.features.types.fan-preset-modes.${schema.name}`
);

View File

@ -17,6 +17,10 @@ import {
} from "../../card-features/types";
import type { LovelaceCardFeatureEditor } from "../../types";
type HumidifierModesCardFeatureData = HumidifierModesCardFeatureConfig & {
customize_modes: boolean;
};
@customElement("hui-humidifier-modes-card-feature-editor")
export class HuiHumidifierModesCardFeatureEditor
extends LitElement
@ -36,7 +40,8 @@ export class HuiHumidifierModesCardFeatureEditor
(
localize: LocalizeFunc,
formatEntityAttributeValue: FormatEntityAttributeValueFunc,
stateObj?: HassEntity
stateObj: HassEntity | undefined,
customizeModes: boolean
) =>
[
{
@ -55,20 +60,33 @@ export class HuiHumidifierModesCardFeatureEditor
},
},
{
name: "modes",
name: "customize_modes",
selector: {
select: {
multiple: true,
reorder: true,
mode: "list",
options:
stateObj?.attributes.available_modes?.map((mode) => ({
value: mode,
label: formatEntityAttributeValue(stateObj, "mode", mode),
})) || [],
},
boolean: {},
},
},
...(customizeModes
? ([
{
name: "modes",
selector: {
select: {
reorder: true,
multiple: true,
options:
stateObj?.attributes.available_modes?.map((mode) => ({
value: mode,
label: formatEntityAttributeValue(
stateObj,
"mode",
mode
),
})) || [],
},
},
},
] as const satisfies readonly HaFormSchema[])
: []),
] as const satisfies readonly HaFormSchema[]
);
@ -81,16 +99,17 @@ export class HuiHumidifierModesCardFeatureEditor
? this.hass.states[this.context?.entity_id]
: undefined;
const data: HumidifierModesCardFeatureConfig = {
const data: HumidifierModesCardFeatureData = {
style: "dropdown",
modes: [],
...this._config,
customize_modes: this._config.modes !== undefined,
};
const schema = this._schema(
this.hass.localize,
this.hass.formatEntityAttributeValue,
stateObj
stateObj,
data.customize_modes
);
return html`
@ -105,7 +124,21 @@ export class HuiHumidifierModesCardFeatureEditor
}
private _valueChanged(ev: CustomEvent): void {
fireEvent(this, "config-changed", { config: ev.detail.value });
const { customize_modes, ...config } = ev.detail
.value as HumidifierModesCardFeatureData;
const stateObj = this.context?.entity_id
? this.hass!.states[this.context?.entity_id]
: undefined;
if (customize_modes && !config.modes) {
config.modes = stateObj?.attributes.available_modes || [];
}
if (!customize_modes && config.modes) {
delete config.modes;
}
fireEvent(this, "config-changed", { config: config });
}
private _computeLabelCallback = (
@ -114,6 +147,7 @@ export class HuiHumidifierModesCardFeatureEditor
switch (schema.name) {
case "style":
case "modes":
case "customize_modes":
return this.hass!.localize(
`ui.panel.lovelace.editor.features.types.humidifier-modes.${schema.name}`
);

View File

@ -5,14 +5,22 @@ import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../common/dom/fire_event";
import type { FormatEntityStateFunc } from "../../../../common/translations/entity-state";
import "../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../components/ha-form/types";
import type {
HaFormSchema,
SchemaUnion,
} from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types";
import {
WaterHeaterOperationModesCardFeatureConfig,
LovelaceCardFeatureContext,
} from "../../card-features/types";
import type { LovelaceCardFeatureEditor } from "../../types";
import { OPERATION_MODES } from "../../../../data/water_heater";
import { compareWaterHeaterOperationMode } from "../../../../data/water_heater";
type WaterHeaterOperationModesCardFeatureData =
WaterHeaterOperationModesCardFeatureConfig & {
customize_modes: boolean;
};
@customElement("hui-water-heater-operation-modes-card-feature-editor")
export class HuiWaterHeaterOperationModesCardFeatureEditor
@ -30,25 +38,41 @@ export class HuiWaterHeaterOperationModesCardFeatureEditor
}
private _schema = memoizeOne(
(formatEntityState: FormatEntityStateFunc, stateObj?: HassEntity) =>
(
formatEntityState: FormatEntityStateFunc,
stateObj: HassEntity | undefined,
customizeModes: boolean
) =>
[
{
name: "operation_modes",
name: "customize_modes",
selector: {
select: {
multiple: true,
reorder: true,
mode: "list",
options: OPERATION_MODES.filter((mode) =>
stateObj?.attributes.operation_list?.includes(mode)
).map((mode) => ({
value: mode,
label: stateObj ? formatEntityState(stateObj, mode) : mode,
})),
},
boolean: {},
},
},
] as const
...(customizeModes
? ([
{
name: "operation_modes",
selector: {
select: {
reorder: true,
multiple: true,
options: (stateObj?.attributes.operation_list || [])
.concat()
.sort(compareWaterHeaterOperationMode)
.map((mode) => ({
value: mode,
label: stateObj
? formatEntityState(stateObj, mode)
: mode,
})),
},
},
},
] as const satisfies readonly HaFormSchema[])
: []),
] as const satisfies readonly HaFormSchema[]
);
protected render() {
@ -60,12 +84,21 @@ export class HuiWaterHeaterOperationModesCardFeatureEditor
? this.hass.states[this.context?.entity_id]
: undefined;
const schema = this._schema(this.hass.formatEntityState, stateObj);
const data: WaterHeaterOperationModesCardFeatureData = {
...this._config,
customize_modes: this._config.operation_modes !== undefined,
};
const schema = this._schema(
this.hass.formatEntityState,
stateObj,
data.customize_modes
);
return html`
<ha-form
.hass=${this.hass}
.data=${this._config}
.data=${data}
.schema=${schema}
.computeLabel=${this._computeLabelCallback}
@value-changed=${this._valueChanged}
@ -74,7 +107,23 @@ export class HuiWaterHeaterOperationModesCardFeatureEditor
}
private _valueChanged(ev: CustomEvent): void {
fireEvent(this, "config-changed", { config: ev.detail.value });
const { customize_modes, ...config } = ev.detail
.value as WaterHeaterOperationModesCardFeatureData;
const stateObj = this.context?.entity_id
? this.hass!.states[this.context?.entity_id]
: undefined;
if (customize_modes && !config.operation_modes) {
config.operation_modes = (stateObj?.attributes.operation_list || [])
.concat()
.sort(compareWaterHeaterOperationMode);
}
if (!customize_modes && config.operation_modes) {
delete config.operation_modes;
}
fireEvent(this, "config-changed", { config: config });
}
private _computeLabelCallback = (
@ -82,13 +131,12 @@ export class HuiWaterHeaterOperationModesCardFeatureEditor
) => {
switch (schema.name) {
case "operation_modes":
case "customize_modes":
return this.hass!.localize(
`ui.panel.lovelace.editor.features.types.water-heater-modes.${schema.name}`
`ui.panel.lovelace.editor.features.types.water-heater-operation-modes.${schema.name}`
);
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
);
return "";
}
};
}

View File

@ -5996,16 +5996,18 @@
"dropdown": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style_list::dropdown%]",
"icons": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style_list::icons%]"
},
"customize_modes": "Customize fan modes",
"fan_modes": "Fan modes"
},
"climate-swing-modes": {
"label": "Climate swing modes",
"swing_modes": "Swing modes",
"style": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style%]",
"style_list": {
"dropdown": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style_list::dropdown%]",
"icons": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style_list::icons%]"
},
"swing_modes": "Swing modes"
"customize_modes": "Customize swing modes"
},
"climate-hvac-modes": {
"label": "Climate HVAC modes",
@ -6014,7 +6016,8 @@
"style_list": {
"dropdown": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style_list::dropdown%]",
"icons": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style_list::icons%]"
}
},
"customize_modes": "Customize HVAC modes"
},
"climate-preset-modes": {
"label": "Climate preset modes",
@ -6023,6 +6026,7 @@
"dropdown": "Dropdown",
"icons": "Icons"
},
"customize_modes": "Customize preset modes",
"preset_modes": "Preset modes"
},
"fan-preset-modes": {
@ -6032,6 +6036,7 @@
"dropdown": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style_list::dropdown%]",
"icons": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style_list::icons%]"
},
"customize_modes": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::customize_modes%]",
"preset_modes": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::preset_modes%]"
},
"humidifier-toggle": {
@ -6044,6 +6049,7 @@
"dropdown": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style_list::dropdown%]",
"icons": "[%key:ui::panel::lovelace::editor::features::types::climate-preset-modes::style_list::icons%]"
},
"customize_modes": "Customize modes",
"modes": "Modes"
},
"select-options": {
@ -6065,7 +6071,8 @@
},
"water-heater-operation-modes": {
"label": "Water heater operation modes",
"operation_modes": "Operation modes"
"operation_modes": "Operation modes",
"customize_modes": "Customize operation modes"
},
"lawn-mower-commands": {
"label": "Lawn mower commands",