Skip to content

Commit 5a5593e

Browse files
timmo001MindFreeze
andauthored
Add labels to device info card on device/service/hub page (#28082)
* Fix typo * Add labels to device info card * Lock * Use token * Add same class * Apply suggestions from code review Co-authored-by: Petar Petrov <[email protected]> * Match codebase style --------- Co-authored-by: Petar Petrov <[email protected]>
1 parent 2d39afd commit 5a5593e

File tree

1 file changed

+99
-6
lines changed

1 file changed

+99
-6
lines changed

src/panels/config/devices/device-detail/ha-device-info-card.ts

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,71 @@
11
import 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";
45
import { computeDeviceNameDisplay } from "../../../../common/entity/compute_device_name";
6+
import { stringCompare } from "../../../../common/string/compare";
57
import { titleCase } from "../../../../common/string/title-case";
68
import "../../../../components/ha-card";
79
import type { DeviceRegistryEntry } from "../../../../data/device_registry";
810
import { haStyle } from "../../../../resources/styles";
911
import type { HomeAssistant } from "../../../../types";
1012
import { createSearchParam } from "../../../../common/url/search-params";
1113
import { 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: 8px;
259+
margin-top: var(--ha-space-2);
167260
word-wrap: break-word;
168261
}
169262
.manuf,

0 commit comments

Comments
 (0)