Skip to content

Commit cf35543

Browse files
committed
Refine entity details context section
1 parent 24f522b commit cf35543

2 files changed

Lines changed: 130 additions & 50 deletions

File tree

src/dialogs/more-info/ha-more-info-details.ts

Lines changed: 130 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { mdiContentCopy, mdiDevices, mdiTextureBox } from "@mdi/js";
12
import { consume } from "@lit/context";
23
import type { HassEntity } from "home-assistant-js-websocket";
3-
import type { CSSResultGroup, PropertyValues } from "lit";
4+
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
45
import { css, html, LitElement, nothing } from "lit";
56
import { customElement, property, state } from "lit/decorators";
67
import memoizeOne from "memoize-one";
@@ -11,8 +12,14 @@ import { getEntityContext } from "../../common/entity/context/get_entity_context
1112
import checkValidDate from "../../common/datetime/check_valid_date";
1213
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
1314
import "../../components/ha-attribute-value";
15+
import "../../components/ha-floor-icon";
16+
import "../../components/ha-icon";
17+
import "../../components/ha-icon-next";
18+
import "../../components/ha-svg-icon";
19+
import "../../components/item/ha-list-item-button";
1420
import "../../components/item/ha-list-item-value";
1521
import "../../components/list/ha-grouped-list";
22+
import { copyToClipboard } from "../../common/util/copy-clipboard";
1623
import type { LocalizeKeys } from "../../common/translations/localize";
1724
import { labelsContext } from "../../data/context";
1825
import type { ExtEntityRegistryEntry } from "../../data/entity/entity_registry";
@@ -25,6 +32,8 @@ import { getFeatures } from "../../common/entity/get_domain_features";
2532
import { supportsFeature } from "../../common/entity/supports-feature";
2633
import { titleCase } from "../../common/string/title-case";
2734
import { stringCompare } from "../../common/string/compare";
35+
import { brandsUrl } from "../../util/brands-url";
36+
import { showToast } from "../../util/toast";
2837

2938
interface DetailsViewParams {
3039
entityId: string;
@@ -34,6 +43,8 @@ interface DetailEntry {
3443
translationKey: LocalizeKeys;
3544
value: string;
3645
href?: string;
46+
icon?: TemplateResult;
47+
copyable?: boolean;
3748
}
3849

3950
@customElement("ha-more-info-details")
@@ -106,20 +117,25 @@ class HaMoreInfoDetails extends LitElement {
106117
translationKey: "ui.dialogs.more_info_control.floor",
107118
value: floorName,
108119
href: "/config/areas/dashboard",
120+
icon: html`<ha-floor-icon slot="end" .floor=${floor}></ha-floor-icon>`,
109121
});
110122
}
111123
if (area && areaName) {
112124
contextEntries.push({
113125
translationKey: "ui.components.related-items.area",
114126
value: areaName,
115127
href: `/config/areas/area/${area.area_id}`,
128+
icon: area.icon
129+
? html`<ha-icon slot="end" .icon=${area.icon}></ha-icon>`
130+
: html`<ha-svg-icon slot="end" .path=${mdiTextureBox}></ha-svg-icon>`,
116131
});
117132
}
118133
if (device && deviceName) {
119134
contextEntries.push({
120135
translationKey: "ui.components.related-items.device",
121136
value: deviceName,
122137
href: `/config/devices/device/${device.id}`,
138+
icon: html`<ha-svg-icon slot="end" .path=${mdiDevices}></ha-svg-icon>`,
123139
});
124140
}
125141
if (this.entry?.platform && integrationName) {
@@ -129,31 +145,40 @@ class HaMoreInfoDetails extends LitElement {
129145
href: this.entry.config_entry_id
130146
? `/config/integrations/integration/${this.entry.platform}#config_entry=${this.entry.config_entry_id}`
131147
: undefined,
148+
icon: html`<img
149+
slot="end"
150+
alt=""
151+
crossorigin="anonymous"
152+
referrerpolicy="no-referrer"
153+
src=${brandsUrl(
154+
{
155+
domain: this.entry.platform,
156+
type: "icon",
157+
darkOptimized: this.hass.themes?.darkMode,
158+
},
159+
this.hass.auth.data.hassUrl
160+
)}
161+
/>`,
132162
});
133163
}
134164

135-
const entityEntries: DetailEntry[] = [
165+
contextEntries.push(
136166
{
137167
translationKey: "ui.dialogs.more_info_control.entity_id",
138168
value: this.params.entityId,
169+
copyable: true,
139170
},
140171
{
141172
translationKey: "ui.dialogs.more_info_control.labels",
142173
value: labelNames.join(", ") || this.hass.localize("ui.common.none"),
143-
},
144-
];
174+
}
175+
);
145176
const yamlData = {
146-
...(contextEntries.length
147-
? {
148-
context: {
149-
...(floorName ? { floor: floorName } : {}),
150-
...(areaName ? { area: areaName } : {}),
151-
...(deviceName ? { device: deviceName } : {}),
152-
...(integrationName ? { integration: integrationName } : {}),
153-
},
154-
}
155-
: {}),
156-
entity: {
177+
context: {
178+
...(floorName ? { floor: floorName } : {}),
179+
...(areaName ? { area: areaName } : {}),
180+
...(deviceName ? { device: deviceName } : {}),
181+
...(integrationName ? { integration: integrationName } : {}),
157182
entity_id: this.params.entityId,
158183
labels: labelNames,
159184
},
@@ -171,17 +196,9 @@ class HaMoreInfoDetails extends LitElement {
171196
in-dialog
172197
></ha-yaml-editor>`
173198
: html`
174-
${
175-
contextEntries.length
176-
? html`<ha-grouped-list
177-
.header=${this.hass.localize(
178-
"ui.dialogs.more_info_control.context"
179-
)}
180-
>
181-
${this._renderEntries(contextEntries)}
182-
</ha-grouped-list>`
183-
: nothing
184-
}
199+
<ha-grouped-list>
200+
${this._renderEntries(contextEntries)}
201+
</ha-grouped-list>
185202
186203
<ha-grouped-list
187204
.header=${this.hass.localize(
@@ -191,14 +208,6 @@ class HaMoreInfoDetails extends LitElement {
191208
${this._renderEntries(stateEntries)}
192209
</ha-grouped-list>
193210
194-
<ha-grouped-list
195-
.header=${this.hass.localize(
196-
"ui.dialogs.more_info_control.entity"
197-
)}
198-
>
199-
${this._renderEntries(entityEntries)}
200-
</ha-grouped-list>
201-
202211
<ha-grouped-list
203212
.header=${this.hass.localize(
204213
"ui.dialogs.more_info_control.attributes"
@@ -284,17 +293,54 @@ class HaMoreInfoDetails extends LitElement {
284293
}
285294

286295
private _renderEntries(entries: DetailEntry[]) {
287-
return entries.map(
288-
(entry) => html`
289-
<ha-list-item-value .label=${this.hass.localize(entry.translationKey)}>
290-
${
291-
entry.href
292-
? html`<a href=${entry.href}>${entry.value}</a>`
293-
: entry.value
294-
}
295-
</ha-list-item-value>
296-
`
297-
);
296+
return entries.map((entry) => {
297+
const label = this.hass.localize(entry.translationKey);
298+
299+
if (!entry.href && !entry.copyable) {
300+
return html`
301+
<ha-list-item-value .label=${label}
302+
>${entry.value}</ha-list-item-value
303+
>
304+
`;
305+
}
306+
307+
if (entry.copyable) {
308+
return html`
309+
<ha-list-item-button
310+
data-value=${entry.value}
311+
@click=${this._copyValue}
312+
>
313+
<div class="link-row" slot="content">
314+
<div class="label">${label}</div>
315+
<div class="value">${entry.value}</div>
316+
</div>
317+
<ha-svg-icon slot="end" .path=${mdiContentCopy}></ha-svg-icon>
318+
</ha-list-item-button>
319+
`;
320+
}
321+
322+
return html`
323+
<ha-list-item-button .href=${entry.href}>
324+
<div class="link-row" slot="content">
325+
<div class="label">${label}</div>
326+
<div class="value">${entry.value}</div>
327+
</div>
328+
${entry.icon ?? nothing}
329+
<ha-icon-next slot="end"></ha-icon-next>
330+
</ha-list-item-button>
331+
`;
332+
});
333+
}
334+
335+
private async _copyValue(ev: Event) {
336+
const value = (ev.currentTarget as HTMLElement).dataset.value;
337+
if (value === undefined) {
338+
return;
339+
}
340+
await copyToClipboard(value);
341+
showToast(this, {
342+
message: this.hass.localize("ui.common.copied_clipboard"),
343+
});
298344
}
299345

300346
private _renderAttributes(attributes: { name: string; label: string }[]) {
@@ -358,11 +404,47 @@ class HaMoreInfoDetails extends LitElement {
358404
}
359405
360406
ha-grouped-list + ha-grouped-list {
361-
margin-top: var(--ha-space-4);
407+
margin-top: var(--ha-space-6);
408+
}
409+
410+
ha-list-item-button {
411+
--ha-row-item-padding-block: var(--ha-space-2);
412+
--ha-row-item-min-height: 40px;
413+
--ha-row-item-gap: var(--ha-space-3);
414+
--mdc-icon-size: 20px;
415+
}
416+
417+
ha-list-item-button::part(end) {
418+
gap: var(--ha-space-2);
419+
}
420+
421+
ha-list-item-button img {
422+
width: 20px;
423+
height: 20px;
424+
object-fit: contain;
362425
}
363426
364-
a {
365-
color: var(--primary-color);
427+
.link-row {
428+
display: flex;
429+
flex-direction: row;
430+
align-items: center;
431+
gap: var(--ha-space-3);
432+
}
433+
434+
.link-row .label {
435+
flex: 1;
436+
color: var(--secondary-text-color);
437+
}
438+
439+
.link-row .value {
440+
max-width: 60%;
441+
min-width: 0;
442+
text-align: end;
443+
overflow-wrap: anywhere;
444+
}
445+
446+
ha-icon-next {
447+
color: var(--secondary-text-color);
366448
}
367449
368450
.empty {

src/translations/en.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,8 +1674,6 @@
16741674
"person": "Edit person"
16751675
},
16761676
"details": "Details",
1677-
"context": "Context",
1678-
"entity": "Entity",
16791677
"floor": "Floor",
16801678
"entity_id": "Entity ID",
16811679
"labels": "Labels",

0 commit comments

Comments
 (0)