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

Display default action label in action selector #18398

Merged
merged 3 commits into from
Nov 2, 2023
Merged
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
1 change: 1 addition & 0 deletions src/components/ha-selector/ha-selector-ui-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class HaSelectorUiAction extends LitElement {
.hass=${this.hass}
.config=${this.value}
.actions=${this.selector.ui_action?.actions}
.defaultAction=${this.selector.ui_action?.default_action}
.tooltipText=${this.helper}
@value-changed=${this._valueChanged}
></hui-action-editor>
Expand Down
1 change: 1 addition & 0 deletions src/data/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ export interface TTSVoiceSelector {
export interface UiActionSelector {
ui_action: {
actions?: UiAction[];
default_action?: UiAction;
} | null;
}

Expand Down
10 changes: 6 additions & 4 deletions src/panels/lovelace/cards/hui-button-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ import { createEntityNotFoundWarning } from "../components/hui-warning";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { ButtonCardConfig } from "./types";

export const getEntityDefaultButtonAction = (entityId?: string) =>
entityId && DOMAINS_TOGGLE.has(computeDomain(entityId))
? "toggle"
: "more-info";

@customElement("hui-button-card")
export class HuiButtonCard extends LitElement implements LovelaceCard {
public static async getConfigElement(): Promise<LovelaceCardEditor> {
Expand Down Expand Up @@ -149,10 +154,7 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {

this._config = {
tap_action: {
action:
config.entity && DOMAINS_TOGGLE.has(computeDomain(config.entity))
? "toggle"
: "more-info",
action: getEntityDefaultButtonAction(config.entity),
},
hold_action: { action: "more-info" },
show_icon: true,
Expand Down
16 changes: 10 additions & 6 deletions src/panels/lovelace/cards/hui-tile-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ import type { ThermostatCardConfig, TileCardConfig } from "./types";

const TIMESTAMP_STATE_DOMAINS = ["button", "input_button", "scene"];

export const getEntityDefaultTileIconAction = (entityId: string) => {
const domain = computeDomain(entityId);
const supportsIconAction =
DOMAINS_TOGGLE.has(domain) ||
["button", "input_button", "scene"].includes(domain);

return supportsIconAction ? "toggle" : "more-info";
};

@customElement("hui-tile-card")
export class HuiTileCard extends LitElement implements LovelaceCard {
public static async getConfigElement(): Promise<LovelaceCardEditor> {
Expand Down Expand Up @@ -87,17 +96,12 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
throw new Error("Specify an entity");
}

const domain = computeDomain(config.entity);
const supportsIconAction =
DOMAINS_TOGGLE.has(domain) ||
["button", "input_button", "scene"].includes(domain);

this._config = {
tap_action: {
action: "more-info",
},
icon_tap_action: {
action: supportsIconAction ? "toggle" : "more-info",
action: getEntityDefaultTileIconAction(config.entity),
},
...config,
};
Expand Down
30 changes: 28 additions & 2 deletions src/panels/lovelace/components/hui-action-editor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import {
css,
CSSResultGroup,
html,
LitElement,
nothing,
PropertyValues,
} from "lit";
import { customElement, property, query } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import { stopPropagation } from "../../../common/dom/stop_propagation";
Expand All @@ -17,6 +24,7 @@ import {
import { ServiceAction } from "../../../data/script";
import { HomeAssistant } from "../../../types";
import { EditorTarget } from "../editor/types";
import { HaSelect } from "../../../components/ha-select";

export type UiAction = Exclude<ActionConfig["action"], "fire-dom-event">;

Expand Down Expand Up @@ -70,10 +78,14 @@ export class HuiActionEditor extends LitElement {

@property() public actions?: UiAction[];

@property() public defaultAction?: UiAction;

@property() public tooltipText?: string;

@property() protected hass?: HomeAssistant;

@query("ha-select") private _select!: HaSelect;

get _navigation_path(): string {
const config = this.config as NavigateActionConfig | undefined;
return config?.navigation_path || "";
Expand All @@ -99,6 +111,15 @@ export class HuiActionEditor extends LitElement {
})
);

protected updated(changedProperties: PropertyValues<typeof this>) {
super.updated(changedProperties);
if (changedProperties.has("defaultAction")) {
if (changedProperties.get("defaultAction") !== this.defaultAction) {
this._select.layoutOptions();
}
}
}

protected render() {
if (!this.hass) {
return nothing;
Expand All @@ -121,6 +142,11 @@ export class HuiActionEditor extends LitElement {
${this.hass!.localize(
"ui.panel.lovelace.editor.action-editor.actions.default_action"
)}
${this.defaultAction
? ` (${this.hass!.localize(
`ui.panel.lovelace.editor.action-editor.actions.${this.defaultAction}`
).toLowerCase()})`
: nothing}
Copy link
Member

Choose a reason for hiding this comment

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

Should we lowercase this? Shouldn't the translation handle that?

Copy link
Member Author

Choose a reason for hiding this comment

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

We can lowercase the translation but we will have to capitalize the first letter when using as a select option 😅

</mwc-list-item>
${actions.map(
(action) => html`
Expand Down
122 changes: 72 additions & 50 deletions src/panels/lovelace/editor/config-elements/hui-button-card-editor.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { assert, assign, boolean, object, optional, string } from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
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 { getEntityDefaultButtonAction } from "../../cards/hui-button-card";
import type { ButtonCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { actionConfigStruct } from "../structs/action-struct";
Expand All @@ -27,52 +32,6 @@ const cardConfigStruct = assign(
})
);

const SCHEMA = [
{ name: "entity", selector: { entity: {} } },
{
name: "",
type: "grid",
schema: [
{ name: "name", selector: { text: {} } },
{
name: "icon",
selector: {
icon: {},
},
context: {
icon_entity: "entity",
},
},
],
},
{
name: "",
type: "grid",
column_min_width: "100px",
schema: [
{ name: "show_name", selector: { boolean: {} } },
{ name: "show_state", selector: { boolean: {} } },
{ name: "show_icon", selector: { boolean: {} } },
],
},
{
name: "",
type: "grid",
schema: [
{ name: "icon_height", selector: { text: { suffix: "px" } } },
{ name: "theme", selector: { theme: {} } },
],
},
{
name: "tap_action",
selector: { ui_action: {} },
},
{
name: "hold_action",
selector: { ui_action: {} },
},
] as const;

@customElement("hui-button-card-editor")
export class HuiButtonCardEditor
extends LitElement
Expand All @@ -87,6 +46,63 @@ export class HuiButtonCardEditor
this._config = config;
}

private _schema = memoizeOne(
(entityId: string | undefined) =>
[
{ name: "entity", selector: { entity: {} } },
{
name: "",
type: "grid",
schema: [
{ name: "name", selector: { text: {} } },
{
name: "icon",
selector: {
icon: {},
},
context: {
icon_entity: "entity",
},
},
],
},
{
name: "",
type: "grid",
column_min_width: "100px",
schema: [
{ name: "show_name", selector: { boolean: {} } },
{ name: "show_state", selector: { boolean: {} } },
{ name: "show_icon", selector: { boolean: {} } },
],
},
{
name: "",
type: "grid",
schema: [
{ name: "icon_height", selector: { text: { suffix: "px" } } },
{ name: "theme", selector: { theme: {} } },
],
},
{
name: "tap_action",
selector: {
ui_action: {
default_action: getEntityDefaultButtonAction(entityId),
},
},
},
{
name: "hold_action",
selector: {
ui_action: {
default_action: "more-info",
},
},
},
] as const satisfies readonly HaFormSchema[]
);

protected render() {
if (!this.hass || !this._config) {
return nothing;
Expand All @@ -102,11 +118,13 @@ export class HuiButtonCardEditor
data.icon_height = String(parseFloat(data.icon_height));
}

const schema = this._schema(this._config.entity);

return html`
<ha-form
.hass=${this.hass}
.data=${data}
.schema=${SCHEMA}
.schema=${schema}
.computeLabel=${this._computeLabelCallback}
.computeHelper=${this._computeHelperCallback}
@value-changed=${this._valueChanged}
Expand All @@ -124,7 +142,9 @@ export class HuiButtonCardEditor
fireEvent(this, "config-changed", { config });
}

private _computeHelperCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
private _computeHelperCallback = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "tap_action":
case "hold_action":
Expand All @@ -136,7 +156,9 @@ export class HuiButtonCardEditor
}
};

private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
private _computeLabelCallback = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
) => {
switch (schema.name) {
case "theme":
case "tap_action":
Expand Down
19 changes: 14 additions & 5 deletions src/panels/lovelace/editor/config-elements/hui-tile-card-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { EditSubElementEvent, SubElementEditorConfig } from "../types";
import { configElementStyle } from "./config-elements-style";
import "./hui-tile-card-features-editor";
import { getEntityDefaultTileIconAction } from "../../cards/hui-tile-card";

const HIDDEN_ATTRIBUTES = [
"access_token",
Expand Down Expand Up @@ -125,6 +126,7 @@ export class HuiTileCardEditor
(
localize: LocalizeFunc,
formatEntityAttributeName: formatEntityAttributeNameFunc,
entityId: string | undefined,
stateObj: HassEntity | undefined,
hideState: boolean
) =>
Expand Down Expand Up @@ -219,13 +221,19 @@ export class HuiTileCardEditor
{
name: "tap_action",
selector: {
ui_action: {},
ui_action: {
default_action: "more-info",
},
},
},
{
name: "icon_tap_action",
selector: {
ui_action: {},
ui_action: {
default_action: entityId
? getEntityDefaultTileIconAction(entityId)
: "more-info",
},
},
},
],
Expand All @@ -242,13 +250,14 @@ export class HuiTileCardEditor
return nothing;
}

const stateObj = this.hass.states[this._config.entity ?? ""] as
| HassEntity
| undefined;
const stateObj = this._config.entity
? this.hass.states[this._config.entity]
: undefined;

const schema = this._schema(
this.hass!.localize,
this.hass.formatEntityAttributeName,
this._config.entity,
stateObj,
this._config.hide_state ?? false
);
Expand Down
Loading