Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tile card feature for input_select domain #16650

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import "../tile-features/hui-alarm-modes-tile-feature";
import "../tile-features/hui-cover-open-close-tile-feature";
import "../tile-features/hui-cover-tilt-tile-feature";
import "../tile-features/hui-fan-speed-tile-feature";
import "../tile-features/hui-input_select-options-tile-feature";
import "../tile-features/hui-light-brightness-tile-feature";
import "../tile-features/hui-vacuum-commands-tile-feature";
import { LovelaceTileFeatureConfig } from "../tile-features/types";
Expand All @@ -17,6 +18,7 @@ const TYPES: Set<LovelaceTileFeatureConfig["type"]> = new Set([
"vacuum-commands",
"fan-speed",
"alarm-modes",
"input_select-options",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename it to select-options and add support for select entity too?

]);

export const createTileFeatureElement = (config: LovelaceTileFeatureConfig) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { HassEntity } from "home-assistant-js-websocket";
import { html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../common/dom/fire_event";
import type { LocalizeFunc } from "../../../../common/translations/localize";
import type { SchemaUnion } from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types";
import {
LovelaceTileFeatureContext,
InputSelectOptionsFeatureConfig,
} from "../../tile-features/types";
import type { LovelaceTileFeatureEditor } from "../../types";

@customElement("hui-input_select-options-tile-feature-editor")
export class HuiInputSelectOptionsTileFeatureEditor
extends LitElement
implements LovelaceTileFeatureEditor
{
@property({ attribute: false }) public hass?: HomeAssistant;

@property({ attribute: false }) public context?: LovelaceTileFeatureContext;

@state() private _config?: InputSelectOptionsFeatureConfig;

public setConfig(config: InputSelectOptionsFeatureConfig): void {
this._config = config;
}

private _schema = memoizeOne(
(localize: LocalizeFunc, stateObj?: HassEntity) =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(localize: LocalizeFunc, stateObj?: HassEntity) =>
(stateObj?: HassEntity) =>

[
{
name: "options",
selector: {
select: {
multiple: true,
mode: "list",
options: stateObj!.attributes.options.map((option) => ({
value: option,
label: option,
})),
},
},
},
] as const
);

protected render() {
if (!this.hass || !this._config) {
return nothing;
}

const stateObj = this.context?.entity_id
? this.hass.states[this.context?.entity_id]
: undefined;

const schema = this._schema(this.hass.localize, stateObj);

return html`
<ha-form
.hass=${this.hass}
.data=${this._config}
.schema=${schema}
.computeLabel=${this._computeLabelCallback}
@value-changed=${this._valueChanged}
></ha-form>
`;
}

private _valueChanged(ev: CustomEvent): void {
fireEvent(this, "config-changed", { config: ev.detail.value });
}

private _computeLabelCallback = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "options":
return this.hass!.localize(
`ui.panel.lovelace.editor.card.tile.features.types.alarm-modes.${schema.name}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`ui.panel.lovelace.editor.card.tile.features.types.alarm-modes.${schema.name}`
`ui.panel.lovelace.editor.card.tile.features.types.select-options.${schema.name}`

);
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
);
}
};
}

declare global {
interface HTMLElementTagNameMap {
"hui-input_select-options-tile-feature-editor": HuiInputSelectOptionsTileFeatureEditor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { getTileFeatureElementClass } from "../../create-element/create-tile-fea
import { supportsAlarmModesTileFeature } from "../../tile-features/hui-alarm-modes-tile-feature";
import { supportsCoverOpenCloseTileFeature } from "../../tile-features/hui-cover-open-close-tile-feature";
import { supportsCoverTiltTileFeature } from "../../tile-features/hui-cover-tilt-tile-feature";
import { supportsInputSelectOptionsTileFeature } from "../../tile-features/hui-input_select-options-tile-feature";
import { supportsFanSpeedTileFeature } from "../../tile-features/hui-fan-speed-tile-feature";
import { supportsLightBrightnessTileFeature } from "../../tile-features/hui-light-brightness-tile-feature";
import { supportsVacuumCommandTileFeature } from "../../tile-features/hui-vacuum-commands-tile-feature";
Expand All @@ -43,11 +44,13 @@ const FEATURE_TYPES: FeatureType[] = [
"vacuum-commands",
"fan-speed",
"alarm-modes",
"input_select-options",
];

const EDITABLES_FEATURE_TYPES = new Set<FeatureType>([
"vacuum-commands",
"alarm-modes",
"input_select-options",
]);

const SUPPORTS_FEATURE_TYPES: Record<FeatureType, SupportsFeature | undefined> =
Expand All @@ -58,6 +61,7 @@ const SUPPORTS_FEATURE_TYPES: Record<FeatureType, SupportsFeature | undefined> =
"vacuum-commands": supportsVacuumCommandTileFeature,
"fan-speed": supportsFanSpeedTileFeature,
"alarm-modes": supportsAlarmModesTileFeature,
"input_select-options": supportsInputSelectOptionsTileFeature,
};

const CUSTOM_FEATURE_ENTRIES: Record<
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { HassEntity } from "home-assistant-js-websocket";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { computeDomain } from "../../../common/entity/compute_domain";
import { InputSelectEntity } from "../../../data/input_select";
import { ControlSelectOption } from "../../../components/ha-control-select";
import { HomeAssistant } from "../../../types";
import { LovelaceTileFeature, LovelaceTileFeatureEditor } from "../types";
import { InputSelectOptionsFeatureConfig } from "./types";

export const supportsInputSelectOptionsTileFeature = (stateObj: HassEntity) => {
const domain = computeDomain(stateObj.entity_id);
return domain === "input_select";
};
Comment on lines +11 to +14
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should support select entities too.


@customElement("hui-input_select-options-tile-feature")
class HuiInputSelectOptionsTileFeature
extends LitElement
implements LovelaceTileFeature
{
@property({ attribute: false }) public hass?: HomeAssistant;

@property({ attribute: false }) public stateObj?: InputSelectEntity;

@state() private _config?: InputSelectOptionsFeatureConfig;

static getStubConfig(
_,
stateObj?: HassEntity
): InputSelectOptionsFeatureConfig {
return {
type: "input_select-options",
options: stateObj ? stateObj.attributes.options : [],
};
}

public static async getConfigElement(): Promise<LovelaceTileFeatureEditor> {
await import(
"../editor/config-elements/hui-input_select-options-tile-feature-editor"
);
return document.createElement(
"hui-input_select-options-tile-feature-editor"
);
}

public setConfig(config: InputSelectOptionsFeatureConfig): void {
if (!config) {
throw new Error("Invalid configuration");
}
this._config = config;
}

protected render() {
if (
!this._config ||
!this.hass ||
!this.stateObj ||
!supportsInputSelectOptionsTileFeature(this.stateObj)
) {
return nothing;
}

const options = this.stateObj.attributes.options
.filter(
(option) =>
this._config?.options?.includes(option) ||
this._config?.options === undefined ||
this._config?.options?.length === 0
)
Comment on lines +65 to +69
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(option) =>
this._config?.options?.includes(option) ||
this._config?.options === undefined ||
this._config?.options?.length === 0
)
(option) =>
this._config?.options?.includes(option) ||
this._config?.options === undefined
)

If options is empty we must display nothing.

.map<ControlSelectOption>((key) => ({
value: key,
label: key,
}));
const value = this.stateObj.state;

return html`
<div class="container">
<ha-control-select
.options=${options}
.value=${value}
@value-changed=${this._valueChanged}
.ariaLabel=${options}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must be a label, not options

></ha-control-select>
</div>
`;
}

private async _valueChanged(ev: CustomEvent) {
const value = (ev.detail as any).value as string;

this.hass!.callService("input_select", "select_option", {
entity_id: this.stateObj!.entity_id,
option: value,
});
}

static get styles() {
return css`
ha-control-select {
--control-select-color: var(--tile-color);
--control-select-padding: 0;
--control-select-thickness: 40px;
--control-select-border-radius: 10px;
--control-select-button-border-radius: 10px;
}
.container {
padding: 0 12px 12px 12px;
width: auto;
}
`;
}
}

declare global {
interface HTMLElementTagNameMap {
"hui-input_select-tile-feature": HuiInputSelectOptionsTileFeature;
}
}
6 changes: 6 additions & 0 deletions src/panels/lovelace/tile-features/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export interface AlarmModesFileFeatureConfig {
modes?: AlarmMode[];
}

export interface InputSelectOptionsFeatureConfig {
type: "input_select-options";
options?: string[];
}

export const VACUUM_COMMANDS = [
"start_pause",
"stop",
Expand All @@ -42,6 +47,7 @@ export type LovelaceTileFeatureConfig =
| LightBrightnessTileFeatureConfig
| VacuumCommandsTileFeatureConfig
| FanSpeedTileFeatureConfig
| InputSelectOptionsFeatureConfig
| AlarmModesFileFeatureConfig;

export type LovelaceTileFeatureContext = {
Expand Down
3 changes: 3 additions & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -4670,6 +4670,9 @@
"disarmed": "[%key:ui::dialogs::more_info_control::alarm_control_panel::modes::disarmed%]"
}
},
"input_select-options": {
"label": "Input Select options"
},
"light-brightness": {
"label": "Light brightness"
},
Expand Down