diff --git a/src/panels/lovelace/card-features/common/filter-modes.ts b/src/panels/lovelace/card-features/common/filter-modes.ts index e3d1d50acd35..d1e81385df16 100644 --- a/src/panels/lovelace/card-features/common/filter-modes.ts +++ b/src/panels/lovelace/card-features/common/filter-modes.ts @@ -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 || []; diff --git a/src/panels/lovelace/card-features/hui-climate-fan-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-climate-fan-modes-card-feature.ts index 70c81e98ae9b..3cfa5624b54c 100644 --- a/src/panels/lovelace/card-features/hui-climate-fan-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-climate-fan-modes-card-feature.ts @@ -45,7 +45,6 @@ class HuiClimateFanModesCardFeature return { type: "climate-fan-modes", style: "dropdown", - fan_modes: [], }; } diff --git a/src/panels/lovelace/card-features/hui-climate-hvac-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-climate-hvac-modes-card-feature.ts index 949bf3b0c5a9..3eab79b85ea3 100644 --- a/src/panels/lovelace/card-features/hui-climate-hvac-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-climate-hvac-modes-card-feature.ts @@ -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((mode) => ({ value: mode, diff --git a/src/panels/lovelace/card-features/hui-climate-preset-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-climate-preset-modes-card-feature.ts index 84e3d61acf85..5cd1e233e53c 100644 --- a/src/panels/lovelace/card-features/hui-climate-preset-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-climate-preset-modes-card-feature.ts @@ -45,7 +45,6 @@ class HuiClimatePresetModesCardFeature return { type: "climate-preset-modes", style: "dropdown", - preset_modes: [], }; } diff --git a/src/panels/lovelace/card-features/hui-climate-swing-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-climate-swing-modes-card-feature.ts index 6d5399f3e260..adc88c1948d0 100644 --- a/src/panels/lovelace/card-features/hui-climate-swing-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-climate-swing-modes-card-feature.ts @@ -45,7 +45,6 @@ class HuiClimateSwingModesCardFeature return { type: "climate-swing-modes", style: "dropdown", - swing_modes: [], }; } diff --git a/src/panels/lovelace/card-features/hui-fan-preset-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-fan-preset-modes-card-feature.ts index 42066f146b23..d1cfb0fcc296 100644 --- a/src/panels/lovelace/card-features/hui-fan-preset-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-fan-preset-modes-card-feature.ts @@ -44,7 +44,6 @@ class HuiFanPresetModesCardFeature return { type: "fan-preset-modes", style: "dropdown", - preset_modes: [], }; } diff --git a/src/panels/lovelace/card-features/hui-humidifier-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-humidifier-modes-card-feature.ts index 1f9c970194fd..ee5176f9adba 100644 --- a/src/panels/lovelace/card-features/hui-humidifier-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-humidifier-modes-card-feature.ts @@ -48,7 +48,6 @@ class HuiHumidifierModesCardFeature return { type: "humidifier-modes", style: "dropdown", - modes: [], }; } diff --git a/src/panels/lovelace/card-features/hui-water-heater-operation-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-water-heater-operation-modes-card-feature.ts index 3dbb61162208..f676b16ca699 100644 --- a/src/panels/lovelace/card-features/hui-water-heater-operation-modes-card-feature.ts +++ b/src/panels/lovelace/card-features/hui-water-heater-operation-modes-card-feature.ts @@ -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((mode) => ({ value: mode, diff --git a/src/panels/lovelace/editor/config-elements/hui-climate-fan-modes-card-feature-editor.ts b/src/panels/lovelace/editor/config-elements/hui-climate-fan-modes-card-feature-editor.ts index dafd27ec1289..85c505913525 100644 --- a/src/panels/lovelace/editor/config-elements/hui-climate-fan-modes-card-feature-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-climate-fan-modes-card-feature-editor.ts @@ -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}` ); diff --git a/src/panels/lovelace/editor/config-elements/hui-climate-hvac-modes-card-feature-editor.ts b/src/panels/lovelace/editor/config-elements/hui-climate-hvac-modes-card-feature-editor.ts index 1d6aa6774f81..87663228aabb 100644 --- a/src/panels/lovelace/editor/config-elements/hui-climate-hvac-modes-card-feature-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-climate-hvac-modes-card-feature-editor.ts @@ -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}` ); diff --git a/src/panels/lovelace/editor/config-elements/hui-climate-preset-modes-card-feature-editor.ts b/src/panels/lovelace/editor/config-elements/hui-climate-preset-modes-card-feature-editor.ts index db33052af105..344fc4da8491 100644 --- a/src/panels/lovelace/editor/config-elements/hui-climate-preset-modes-card-feature-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-climate-preset-modes-card-feature-editor.ts @@ -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}` ); diff --git a/src/panels/lovelace/editor/config-elements/hui-climate-swing-modes-card-feature-editor.ts b/src/panels/lovelace/editor/config-elements/hui-climate-swing-modes-card-feature-editor.ts index a490a86fc5f1..a8c4f4c09c3c 100644 --- a/src/panels/lovelace/editor/config-elements/hui-climate-swing-modes-card-feature-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-climate-swing-modes-card-feature-editor.ts @@ -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}` ); diff --git a/src/panels/lovelace/editor/config-elements/hui-fan-preset-modes-card-feature-editor.ts b/src/panels/lovelace/editor/config-elements/hui-fan-preset-modes-card-feature-editor.ts index 5c4d688f672e..acc3cc18319d 100644 --- a/src/panels/lovelace/editor/config-elements/hui-fan-preset-modes-card-feature-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-fan-preset-modes-card-feature-editor.ts @@ -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}` ); diff --git a/src/panels/lovelace/editor/config-elements/hui-humidifier-modes-card-feature-editor.ts b/src/panels/lovelace/editor/config-elements/hui-humidifier-modes-card-feature-editor.ts index 33df27d2dc5e..92e6f778bb50 100644 --- a/src/panels/lovelace/editor/config-elements/hui-humidifier-modes-card-feature-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-humidifier-modes-card-feature-editor.ts @@ -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}` ); diff --git a/src/panels/lovelace/editor/config-elements/hui-water-heater-operation-modes-card-feature-editor.ts b/src/panels/lovelace/editor/config-elements/hui-water-heater-operation-modes-card-feature-editor.ts index a5763b3401cd..aad60f9034c6 100644 --- a/src/panels/lovelace/editor/config-elements/hui-water-heater-operation-modes-card-feature-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-water-heater-operation-modes-card-feature-editor.ts @@ -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` { 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 ""; } }; } diff --git a/src/translations/en.json b/src/translations/en.json index e6c7dadff19d..a92e37fc5a18 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -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",