Skip to content

Commit

Permalink
Add customize mode option to card features with modes (#20670)
Browse files Browse the repository at this point in the history
* Add customize mode options to card features with modes

* Better type

* Fix water heater and humidifier

* Clean schema
  • Loading branch information
piitaya authored Apr 30, 2024
1 parent 334c245 commit 7120ad9
Show file tree
Hide file tree
Showing 16 changed files with 403 additions and 154 deletions.
4 changes: 2 additions & 2 deletions src/panels/lovelace/card-features/common/filter-modes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 || [];
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class HuiClimateFanModesCardFeature
return {
type: "climate-fan-modes",
style: "dropdown",
fan_modes: [],
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -46,7 +46,6 @@ class HuiClimateHvacModesCardFeature
static getStubConfig(): ClimateHvacModesCardFeatureConfig {
return {
type: "climate-hvac-modes",
hvac_modes: [],
};
}

Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class HuiClimatePresetModesCardFeature
return {
type: "climate-preset-modes",
style: "dropdown",
preset_modes: [],
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class HuiClimateSwingModesCardFeature
return {
type: "climate-swing-modes",
style: "dropdown",
swing_modes: [],
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ class HuiFanPresetModesCardFeature
return {
type: "fan-preset-modes",
style: "dropdown",
preset_modes: [],
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ class HuiHumidifierModesCardFeature
return {
type: "humidifier-modes",
style: "dropdown",
modes: [],
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ class HuiWaterHeaterOperationModeCardFeature
static getStubConfig(): WaterHeaterOperationModesCardFeatureConfig {
return {
type: "water-heater-operation-modes",
operation_modes: [],
};
}

Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -36,7 +40,8 @@ export class HuiClimateFanModesCardFeatureEditor
(
localize: LocalizeFunc,
formatEntityAttributeValue: FormatEntityAttributeValueFunc,
stateObj?: HassEntity
stateObj: HassEntity | undefined,
customizeModes: boolean
) =>
[
{
Expand All @@ -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[]
);

Expand All @@ -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`
Expand All @@ -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 = (
Expand All @@ -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}`
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,22 @@ 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,
LovelaceCardFeatureContext,
} 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
Expand All @@ -34,7 +41,8 @@ export class HuiClimateHvacModesCardFeatureEditor
(
localize: LocalizeFunc,
formatEntityState: FormatEntityStateFunc,
stateObj?: HassEntity
stateObj: HassEntity | undefined,
customizeModes: boolean
) =>
[
{
Expand All @@ -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() {
Expand All @@ -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`
Expand All @@ -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 = (
Expand All @@ -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}`
);
Expand Down
Loading

0 comments on commit 7120ad9

Please sign in to comment.