mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Change entity badge display type to 3 booleans : name, state and icon (#21798)
* Change display type to 3 boolean : name, state and icon for entity badge * Fix image url * Fix not found entity * Update state-label badge migration
This commit is contained in:
parent
e9cbd54979
commit
7c5f947865
@ -13,7 +13,7 @@ export const ensureBadgeConfig = (
|
||||
return {
|
||||
type: "entity",
|
||||
entity: config,
|
||||
display_type: "complete",
|
||||
show_name: true,
|
||||
};
|
||||
}
|
||||
if ("type" in config && config.type) {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { mdiAlertCircle } from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
@ -5,15 +6,16 @@ import { classMap } from "lit/directives/class-map";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { mdiAlertCircle } from "@mdi/js";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { hsv2rgb, rgb2hex, rgb2hsv } from "../../../common/color/convert-color";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import "../../../components/ha-ripple";
|
||||
import "../../../components/ha-state-icon";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { cameraUrlWithWidthHeight } from "../../../data/camera";
|
||||
import { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
@ -22,15 +24,38 @@ import { handleAction } from "../common/handle-action";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import { LovelaceBadge, LovelaceBadgeEditor } from "../types";
|
||||
import { EntityBadgeConfig } from "./types";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
import { cameraUrlWithWidthHeight } from "../../../data/camera";
|
||||
|
||||
export const DISPLAY_TYPES = ["minimal", "standard", "complete"] as const;
|
||||
|
||||
export type DisplayType = (typeof DISPLAY_TYPES)[number];
|
||||
|
||||
export const DEFAULT_DISPLAY_TYPE: DisplayType = "standard";
|
||||
|
||||
export const DEFAULT_CONFIG: EntityBadgeConfig = {
|
||||
type: "entity",
|
||||
show_name: false,
|
||||
show_state: true,
|
||||
show_icon: true,
|
||||
};
|
||||
|
||||
export const migrateLegacyEntityBadgeConfig = (
|
||||
config: EntityBadgeConfig
|
||||
): EntityBadgeConfig => {
|
||||
const newConfig = { ...config };
|
||||
if (config.display_type) {
|
||||
if (config.show_name === undefined) {
|
||||
if (config.display_type === "complete") {
|
||||
newConfig.show_name = true;
|
||||
}
|
||||
}
|
||||
if (config.show_state === undefined) {
|
||||
if (config.display_type === "minimal") {
|
||||
newConfig.show_state = false;
|
||||
}
|
||||
}
|
||||
delete newConfig.display_type;
|
||||
}
|
||||
return newConfig;
|
||||
};
|
||||
|
||||
@customElement("hui-entity-badge")
|
||||
export class HuiEntityBadge extends LitElement implements LovelaceBadge {
|
||||
public static async getConfigElement(): Promise<LovelaceBadgeEditor> {
|
||||
@ -64,7 +89,10 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {
|
||||
@state() protected _config?: EntityBadgeConfig;
|
||||
|
||||
public setConfig(config: EntityBadgeConfig): void {
|
||||
this._config = config;
|
||||
this._config = {
|
||||
...DEFAULT_CONFIG,
|
||||
...migrateLegacyEntityBadgeConfig(config),
|
||||
};
|
||||
}
|
||||
|
||||
get hasAction() {
|
||||
@ -134,9 +162,9 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {
|
||||
return html`
|
||||
<div class="badge error">
|
||||
<ha-svg-icon .hass=${this.hass} .path=${mdiAlertCircle}></ha-svg-icon>
|
||||
<span class="content">
|
||||
<span class="name">${entityId}</span>
|
||||
<span class="state">
|
||||
<span class="info">
|
||||
<span class="label">${entityId}</span>
|
||||
<span class="content">
|
||||
${this.hass.localize("ui.badge.entity.not_found")}
|
||||
</span>
|
||||
</span>
|
||||
@ -163,18 +191,25 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {
|
||||
|
||||
const name = this._config.name || stateObj.attributes.friendly_name;
|
||||
|
||||
const displayType = this._config.display_type || DEFAULT_DISPLAY_TYPE;
|
||||
const showState = this._config.show_state;
|
||||
const showName = this._config.show_name;
|
||||
const showIcon = this._config.show_icon;
|
||||
const showEntityPicture = this._config.show_entity_picture;
|
||||
|
||||
const imageUrl = this._config.show_entity_picture
|
||||
const imageUrl = showEntityPicture
|
||||
? this._getImageUrl(stateObj)
|
||||
: undefined;
|
||||
|
||||
const label = showState && showName ? name : undefined;
|
||||
const content = showState ? stateDisplay : showName ? name : undefined;
|
||||
|
||||
return html`
|
||||
<div
|
||||
style=${styleMap(style)}
|
||||
class="badge ${classMap({
|
||||
active,
|
||||
[displayType]: true,
|
||||
"no-info": !showState && !showName,
|
||||
"no-icon": !showIcon,
|
||||
})}"
|
||||
@action=${this._handleAction}
|
||||
.actionHandler=${actionHandler({
|
||||
@ -185,22 +220,22 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {
|
||||
tabindex=${ifDefined(this.hasAction ? "0" : undefined)}
|
||||
>
|
||||
<ha-ripple .disabled=${!this.hasAction}></ha-ripple>
|
||||
${imageUrl
|
||||
? html`<img src=${imageUrl} aria-hidden />`
|
||||
: html`
|
||||
<ha-state-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
.icon=${this._config.icon}
|
||||
></ha-state-icon>
|
||||
`}
|
||||
${displayType !== "minimal"
|
||||
${showIcon
|
||||
? imageUrl
|
||||
? html`<img src=${imageUrl} aria-hidden />`
|
||||
: html`
|
||||
<ha-state-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
.icon=${this._config.icon}
|
||||
></ha-state-icon>
|
||||
`
|
||||
: nothing}
|
||||
${content
|
||||
? html`
|
||||
<span class="content">
|
||||
${displayType === "complete"
|
||||
? html`<span class="name">${name}</span>`
|
||||
: nothing}
|
||||
<span class="state">${stateDisplay}</span>
|
||||
<span class="info">
|
||||
${label ? html`<span class="label">${name}</span>` : nothing}
|
||||
<span class="content">${content}</span>
|
||||
</span>
|
||||
`
|
||||
: nothing}
|
||||
@ -277,7 +312,7 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {
|
||||
.badge.active {
|
||||
--badge-color: var(--primary-color);
|
||||
}
|
||||
.content {
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
@ -285,7 +320,7 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {
|
||||
padding-inline-end: 4px;
|
||||
padding-inline-start: initial;
|
||||
}
|
||||
.name {
|
||||
.label {
|
||||
font-size: 10px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
@ -293,7 +328,7 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {
|
||||
letter-spacing: 0.1px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.state {
|
||||
.content {
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
@ -313,14 +348,20 @@ export class HuiEntityBadge extends LitElement implements LovelaceBadge {
|
||||
object-fit: cover;
|
||||
overflow: hidden;
|
||||
}
|
||||
.badge.minimal {
|
||||
.badge.no-info {
|
||||
padding: 0;
|
||||
}
|
||||
.badge:not(.minimal) img {
|
||||
.badge:not(.no-icon) img {
|
||||
margin-left: -6px;
|
||||
margin-inline-start: -6px;
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
.badge.no-icon .info {
|
||||
padding-right: 4px;
|
||||
padding-left: 4px;
|
||||
padding-inline-end: 4px;
|
||||
padding-inline-start: 4px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,10 @@ export class HuiStateLabelBadge extends HuiEntityBadge {
|
||||
const entityBadgeConfig: EntityBadgeConfig = {
|
||||
type: "entity",
|
||||
entity: config.entity,
|
||||
display_type: config.show_name === false ? "standard" : "complete",
|
||||
show_name: config.show_name ?? true,
|
||||
};
|
||||
|
||||
this._config = entityBadgeConfig;
|
||||
super.setConfig(entityBadgeConfig);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import type { LovelaceBadgeConfig } from "../../../data/lovelace/config/badge";
|
||||
import type { LegacyStateFilter } from "../common/evaluate-filter";
|
||||
import type { Condition } from "../common/validate-condition";
|
||||
import type { EntityFilterEntityConfig } from "../entity-rows/types";
|
||||
import type { DisplayType } from "./hui-entity-badge";
|
||||
|
||||
export interface EntityFilterBadgeConfig extends LovelaceBadgeConfig {
|
||||
type: "entity-filter";
|
||||
@ -33,10 +34,16 @@ export interface EntityBadgeConfig extends LovelaceBadgeConfig {
|
||||
name?: string;
|
||||
icon?: string;
|
||||
color?: string;
|
||||
show_name?: boolean;
|
||||
show_state?: boolean;
|
||||
show_icon?: boolean;
|
||||
show_entity_picture?: boolean;
|
||||
display_type?: "minimal" | "standard" | "complete";
|
||||
state_content?: string | string[];
|
||||
tap_action?: ActionConfig;
|
||||
hold_action?: ActionConfig;
|
||||
double_tap_action?: ActionConfig;
|
||||
/**
|
||||
* @deprecated use `show_state`, `show_name`, `icon_type`
|
||||
*/
|
||||
display_type?: DisplayType;
|
||||
}
|
||||
|
@ -22,8 +22,9 @@ import type {
|
||||
} from "../../../../components/ha-form/types";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import {
|
||||
DEFAULT_DISPLAY_TYPE,
|
||||
DEFAULT_CONFIG,
|
||||
DISPLAY_TYPES,
|
||||
migrateLegacyEntityBadgeConfig,
|
||||
} from "../../badges/hui-entity-badge";
|
||||
import { EntityBadgeConfig } from "../../badges/types";
|
||||
import type { LovelaceBadgeEditor } from "../../types";
|
||||
@ -42,10 +43,12 @@ const badgeConfigStruct = assign(
|
||||
icon: optional(string()),
|
||||
state_content: optional(union([string(), array(string())])),
|
||||
color: optional(string()),
|
||||
show_name: optional(boolean()),
|
||||
show_state: optional(boolean()),
|
||||
show_icon: optional(boolean()),
|
||||
show_entity_picture: optional(boolean()),
|
||||
tap_action: optional(actionConfigStruct),
|
||||
show_name: optional(boolean()),
|
||||
image: optional(string()),
|
||||
image: optional(string()), // For old badge config support
|
||||
})
|
||||
);
|
||||
|
||||
@ -60,7 +63,10 @@ export class HuiEntityBadgeEditor
|
||||
|
||||
public setConfig(config: EntityBadgeConfig): void {
|
||||
assert(config, badgeConfigStruct);
|
||||
this._config = config;
|
||||
this._config = {
|
||||
...DEFAULT_CONFIG,
|
||||
...migrateLegacyEntityBadgeConfig(config),
|
||||
};
|
||||
}
|
||||
|
||||
private _schema = memoizeOne(
|
||||
@ -73,20 +79,6 @@ export class HuiEntityBadgeEditor
|
||||
iconPath: mdiPalette,
|
||||
title: localize(`ui.panel.lovelace.editor.badge.entity.appearance`),
|
||||
schema: [
|
||||
{
|
||||
name: "display_type",
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: DISPLAY_TYPES.map((type) => ({
|
||||
value: type,
|
||||
label: localize(
|
||||
`ui.panel.lovelace.editor.badge.entity.display_type_options.${type}`
|
||||
),
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "",
|
||||
type: "grid",
|
||||
@ -97,6 +89,12 @@ export class HuiEntityBadgeEditor
|
||||
text: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "color",
|
||||
selector: {
|
||||
ui_color: { default_color: true },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "icon",
|
||||
selector: {
|
||||
@ -104,12 +102,6 @@ export class HuiEntityBadgeEditor
|
||||
},
|
||||
context: { icon_entity: "entity" },
|
||||
},
|
||||
{
|
||||
name: "color",
|
||||
selector: {
|
||||
ui_color: { default_color: true },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "show_entity_picture",
|
||||
selector: {
|
||||
@ -118,7 +110,35 @@ export class HuiEntityBadgeEditor
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
name: "displayed_elements",
|
||||
selector: {
|
||||
select: {
|
||||
mode: "list",
|
||||
multiple: true,
|
||||
options: [
|
||||
{
|
||||
value: "name",
|
||||
label: localize(
|
||||
`ui.panel.lovelace.editor.badge.entity.displayed_elements_options.name`
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "state",
|
||||
label: localize(
|
||||
`ui.panel.lovelace.editor.badge.entity.displayed_elements_options.state`
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "icon",
|
||||
label: localize(
|
||||
`ui.panel.lovelace.editor.badge.entity.displayed_elements_options.icon`
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "state_content",
|
||||
selector: {
|
||||
@ -151,6 +171,20 @@ export class HuiEntityBadgeEditor
|
||||
] as const satisfies readonly HaFormSchema[]
|
||||
);
|
||||
|
||||
_displayedElements = memoizeOne((config: EntityBadgeConfig) => {
|
||||
const elements: string[] = [];
|
||||
if (config.show_name) {
|
||||
elements.push("name");
|
||||
}
|
||||
if (config.show_state) {
|
||||
elements.push("state");
|
||||
}
|
||||
if (config.show_icon) {
|
||||
elements.push("icon");
|
||||
}
|
||||
return elements;
|
||||
});
|
||||
|
||||
protected render() {
|
||||
if (!this.hass || !this._config) {
|
||||
return nothing;
|
||||
@ -158,11 +192,10 @@ export class HuiEntityBadgeEditor
|
||||
|
||||
const schema = this._schema(this.hass!.localize);
|
||||
|
||||
const data = { ...this._config };
|
||||
|
||||
if (!data.display_type) {
|
||||
data.display_type = DEFAULT_DISPLAY_TYPE;
|
||||
}
|
||||
const data = {
|
||||
...this._config,
|
||||
displayed_elements: this._displayedElements(this._config),
|
||||
};
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
@ -181,18 +214,17 @@ export class HuiEntityBadgeEditor
|
||||
return;
|
||||
}
|
||||
|
||||
const newConfig = ev.detail.value as EntityBadgeConfig;
|
||||
|
||||
const config: EntityBadgeConfig = {
|
||||
...newConfig,
|
||||
};
|
||||
const config = { ...ev.detail.value } as EntityBadgeConfig;
|
||||
|
||||
if (!config.state_content) {
|
||||
delete config.state_content;
|
||||
}
|
||||
|
||||
if (config.display_type === "standard") {
|
||||
delete config.display_type;
|
||||
if (config.displayed_elements) {
|
||||
config.show_name = config.displayed_elements.includes("name");
|
||||
config.show_state = config.displayed_elements.includes("state");
|
||||
config.show_icon = config.displayed_elements.includes("icon");
|
||||
delete config.displayed_elements;
|
||||
}
|
||||
|
||||
fireEvent(this, "config-changed", { config });
|
||||
@ -204,8 +236,8 @@ export class HuiEntityBadgeEditor
|
||||
switch (schema.name) {
|
||||
case "color":
|
||||
case "state_content":
|
||||
case "display_type":
|
||||
case "show_entity_picture":
|
||||
case "displayed_elements":
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.badge.entity.${schema.name}`
|
||||
);
|
||||
|
@ -30,11 +30,11 @@ export class HuiStateLabelBadgeEditor extends HuiEntityBadgeEditor {
|
||||
const entityBadgeConfig: EntityBadgeConfig = {
|
||||
type: "entity",
|
||||
entity: config.entity,
|
||||
display_type: config.show_name === false ? "standard" : "complete",
|
||||
show_name: config.show_name ?? true,
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
this._config = entityBadgeConfig;
|
||||
super.setConfig(entityBadgeConfig);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5959,9 +5959,9 @@
|
||||
"paste": "Paste from clipboard",
|
||||
"paste_description": "Paste a {type} card from the clipboard",
|
||||
"refresh_interval": "Refresh interval",
|
||||
"show_icon": "Show icon?",
|
||||
"show_name": "Show name?",
|
||||
"show_state": "Show state?",
|
||||
"show_icon": "Show icon",
|
||||
"show_name": "Show name",
|
||||
"show_state": "Show state",
|
||||
"tap_action": "Tap behavior",
|
||||
"title": "Title",
|
||||
"theme": "Theme",
|
||||
@ -6101,11 +6101,11 @@
|
||||
"appearance": "Appearance",
|
||||
"show_entity_picture": "Show entity picture",
|
||||
"state_content": "State content",
|
||||
"display_type": "Display type",
|
||||
"display_type_options": {
|
||||
"minimal": "Minimal (icon only)",
|
||||
"standard": "Standard (icon and state)",
|
||||
"complete": "Complete (icon, name and state)"
|
||||
"displayed_elements": "Displayed elements",
|
||||
"displayed_elements_options": {
|
||||
"icon": "Icon",
|
||||
"name": "Name",
|
||||
"state": "State"
|
||||
}
|
||||
},
|
||||
"generic": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user