Add configurable actions to Gauge Card (#20833)

* Add actions to gauge card

* struct support

* tap_action in UI

* Apply suggestions from code review

Co-authored-by: Paul Bottein <paul.bottein@gmail.com>

* typo

---------

Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
This commit is contained in:
karwosts 2024-05-22 05:10:22 -07:00 committed by GitHub
parent 2113cf5280
commit 9fe8f507ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 59 additions and 5 deletions

View File

@ -8,17 +8,22 @@ import {
nothing,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
import { getNumberFormatOptions } from "../../../common/number/format_number";
import "../../../components/ha-card";
import "../../../components/ha-gauge";
import { UNAVAILABLE } from "../../../data/entity";
import { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { findEntities } from "../common/find-entities";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceCard, LovelaceCardEditor } from "../types";
@ -123,10 +128,26 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
const name = this._config.name ?? computeStateName(stateObj);
const hasAnyAction =
!this._config.tap_action ||
hasAction(this._config.tap_action) ||
hasAction(this._config.hold_action) ||
hasAction(this._config.double_tap_action);
// Use `stateObj.state` as value to keep formatting (e.g trailing zeros)
// for consistent value display across gauge, entity, entity-row, etc.
return html`
<ha-card @click=${this._handleClick} tabindex="0">
<ha-card
class=${classMap({ action: hasAnyAction })}
@action=${this._handleAction}
.actionHandler=${actionHandler({
hasHold: hasAction(this._config.hold_action),
hasDoubleClick: hasAction(this._config.double_tap_action),
})}
tabindex=${ifDefined(
hasAction(this._config.tap_action) ? "0" : undefined
)}
>
<ha-gauge
.min=${this._config.min!}
.max=${this._config.max!}
@ -256,14 +277,13 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
}));
}
private _handleClick(): void {
fireEvent(this, "hass-more-info", { entityId: this._config!.entity });
private _handleAction(ev: ActionHandlerEvent) {
handleAction(this, this.hass!, this._config!, ev.detail.action!);
}
static get styles(): CSSResultGroup {
return css`
ha-card {
cursor: pointer;
height: 100%;
overflow: hidden;
padding: 16px;
@ -274,6 +294,10 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
box-sizing: border-box;
}
ha-card.action {
cursor: pointer;
}
ha-card:focus {
outline: none;
}

View File

@ -235,6 +235,9 @@ export interface GaugeCardConfig extends LovelaceCardConfig {
theme?: string;
needle?: boolean;
segments?: GaugeSegment[];
tap_action?: ActionConfig;
hold_action?: ActionConfig;
double_tap_action?: ActionConfig;
}
export interface ConfigEntity extends EntityConfig {

View File

@ -9,6 +9,7 @@ import {
number,
object,
optional,
refine,
string,
} from "superstruct";
import { fireEvent } from "../../../../common/dom/fire_event";
@ -17,8 +18,12 @@ import type { SchemaUnion } from "../../../../components/ha-form/types";
import type { HomeAssistant } from "../../../../types";
import type { GaugeCardConfig } from "../../cards/types";
import type { LovelaceCardEditor } from "../../types";
import { actionConfigStruct } from "../structs/action-struct";
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
import { DEFAULT_MIN, DEFAULT_MAX } from "../../cards/hui-gauge-card";
import { UiAction } from "../../components/hui-action-editor";
const TAP_ACTIONS: UiAction[] = ["navigate", "url", "call-service", "none"];
const gaugeSegmentStruct = object({
from: number(),
@ -38,6 +43,13 @@ const cardConfigStruct = assign(
theme: optional(string()),
needle: optional(boolean()),
segments: optional(array(gaugeSegmentStruct)),
tap_action: optional(
refine(actionConfigStruct, TAP_ACTIONS.toString(), (value) =>
TAP_ACTIONS.includes(value.action)
)
),
hold_action: optional(actionConfigStruct),
double_tap_action: optional(actionConfigStruct),
})
);
@ -121,6 +133,15 @@ export class HuiGaugeCardEditor
},
] as const)
: []),
{
name: "tap_action",
selector: {
ui_action: {
actions: TAP_ACTIONS,
default_action: "more-info",
},
},
},
] as const
);
@ -210,6 +231,12 @@ export class HuiGaugeCardEditor
return this.hass!.localize(
"ui.panel.lovelace.editor.card.generic.unit"
);
case "tap_action":
return `${this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional"
)})`;
default:
// "green" | "yellow" | "red"
return this.hass!.localize(