11import type { CSSResultGroup , TemplateResult } from "lit" ;
2- import { css , html , LitElement } from "lit" ;
3- import { customElement , property } from "lit/decorators" ;
2+ import { css , html , LitElement , nothing } from "lit" ;
3+ import { customElement , property , state } from "lit/decorators" ;
4+ import memoizeOne from "memoize-one" ;
45import { computeDeviceNameDisplay } from "../../../../common/entity/compute_device_name" ;
6+ import { stringCompare } from "../../../../common/string/compare" ;
57import { titleCase } from "../../../../common/string/title-case" ;
68import "../../../../components/ha-card" ;
79import type { DeviceRegistryEntry } from "../../../../data/device_registry" ;
810import { haStyle } from "../../../../resources/styles" ;
911import type { HomeAssistant } from "../../../../types" ;
1012import { createSearchParam } from "../../../../common/url/search-params" ;
1113import { isComponentLoaded } from "../../../../common/config/is_component_loaded" ;
14+ import "../../../../components/ha-icon" ;
15+ import "../../../../components/ha-label" ;
16+ import type { LabelRegistryEntry } from "../../../../data/label_registry" ;
17+ import { subscribeLabelRegistry } from "../../../../data/label_registry" ;
18+ import { computeCssColor } from "../../../../common/color/compute-color" ;
19+ import { SubscribeMixin } from "../../../../mixins/subscribe-mixin" ;
1220
1321@customElement ( "ha-device-info-card" )
14- export class HaDeviceCard extends LitElement {
22+ export class HaDeviceCard extends SubscribeMixin ( LitElement ) {
1523 @property ( { attribute : false } ) public hass ! : HomeAssistant ;
1624
1725 @property ( { attribute : false } ) public device ! : DeviceRegistryEntry ;
1826
1927 @property ( { type : Boolean } ) public narrow = false ;
2028
29+ @state ( ) private _labelRegistry ?: LabelRegistryEntry [ ] ;
30+
31+ private _labelsData = memoizeOne (
32+ (
33+ labels : LabelRegistryEntry [ ] | undefined ,
34+ labelIds : string [ ] ,
35+ language : string
36+ ) : {
37+ map : Map < string , LabelRegistryEntry > ;
38+ ids : string [ ] ;
39+ } => {
40+ const map = labels
41+ ? new Map ( labels . map ( ( label ) => [ label . label_id , label ] ) )
42+ : new Map < string , LabelRegistryEntry > ( ) ;
43+ const ids = [ ...labelIds ] . sort ( ( labelA , labelB ) =>
44+ stringCompare (
45+ map . get ( labelA ) ?. name || labelA ,
46+ map . get ( labelB ) ?. name || labelB ,
47+ language
48+ )
49+ ) ;
50+ return { map, ids } ;
51+ }
52+ ) ;
53+
54+ public hassSubscribe ( ) {
55+ return [
56+ subscribeLabelRegistry ( this . hass . connection , ( labels ) => {
57+ this . _labelRegistry = labels ;
58+ } ) ,
59+ ] ;
60+ }
61+
2162 protected render ( ) : TemplateResult {
63+ const { map : labelMap , ids : labels } = this . _labelsData (
64+ this . _labelRegistry ,
65+ this . device . labels ,
66+ this . hass . locale . language
67+ ) ;
68+
2269 return html `
2370 <ha- card
2471 outlined
@@ -58,7 +105,7 @@ export class HaDeviceCard extends LitElement {
58105 <span class= "hub"
59106 > <a
60107 href= "/config/devices/device/${ this . device . via_device_id } "
61- > ${ this . _computeDeviceNameDislay (
108+ > ${ this . _computeDeviceNameDisplay (
62109 this . device . via_device_id
63110 ) } </ a
64111 > </ span
@@ -126,6 +173,34 @@ export class HaDeviceCard extends LitElement {
126173 </ div>
127174 `
128175 ) }
176+ ${ labels . length > 0
177+ ? html `
178+ <div class= "extra-info labels" >
179+ ${ labels . map ( ( labelId ) => {
180+ const label = labelMap . get ( labelId ) ;
181+ const color =
182+ label ?. color && typeof label . color === "string"
183+ ? computeCssColor ( label . color )
184+ : undefined ;
185+ return html `
186+ <ha- label
187+ style= ${ color ? `--color: ${ color } ` : "" }
188+ .description = ${ label ?. description }
189+ >
190+ ${ label ?. icon
191+ ? html `<ha- icon
192+ slot= "icon"
193+ .icon = ${ label . icon }
194+ > </ ha- icon> `
195+ : nothing }
196+ ${ label ?. name || labelId }
197+ </ ha- label>
198+ ` ;
199+ } ) }
200+ </ div>
201+ `
202+ : nothing }
203+
129204 <slot> </ slot>
130205 </ div>
131206 <slot name= "actions" > </ slot>
@@ -139,7 +214,7 @@ export class HaDeviceCard extends LitElement {
139214 ) ;
140215 }
141216
142- private _computeDeviceNameDislay ( deviceId ) {
217+ private _computeDeviceNameDisplay ( deviceId : string ) {
143218 const device = this . hass . devices [ deviceId ] ;
144219 return device
145220 ? computeDeviceNameDisplay ( device , this . hass )
@@ -162,8 +237,26 @@ export class HaDeviceCard extends LitElement {
162237 .device {
163238 width : 30% ;
164239 }
240+ .labels {
241+ display : flex;
242+ flex-wrap : wrap;
243+ gap : var (--ha-space-1 );
244+ width : 100% ;
245+ max-width : 100% ;
246+ }
247+ .labels ha-label {
248+ min-width : 0 ;
249+ max-width : 100% ;
250+ flex : 0 1 auto;
251+ }
252+ ha-label {
253+ --ha-label-background-color : var (--color , var (--grey-color ));
254+ --ha-label-background-opacity : 0.5 ;
255+ --ha-label-text-color : var (--primary-text-color );
256+ --ha-label-icon-color : var (--primary-text-color );
257+ }
165258 .extra-info {
166- margin-top : 8 px ;
259+ margin-top : var ( --ha-space-2 ) ;
167260 word-wrap : break-word;
168261 }
169262 .manuf ,
0 commit comments