Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
"punycode": "2.3.1",
"qr-scanner": "1.4.2",
"qrcode": "1.5.4",
"remove-markdown": "0.6.2",
"roboto-fontface": "0.10.0",
"rrule": "2.8.1",
"sortablejs": "patch:sortablejs@npm%3A1.15.6#~/.yarn/patches/sortablejs-npm-1.15.6-3235a8f83b.patch",
Expand Down
8 changes: 2 additions & 6 deletions src/components/data-table/ha-data-table-labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class HaDataTableLabels extends LitElement {
@click=${clickAction ? this._labelClicked : undefined}
@keydown=${clickAction ? this._labelClicked : undefined}
style=${color ? `--color: ${color}` : ""}
.description=${label.description}
.description=${label.description ?? undefined}
>
${label?.icon
? html`<ha-icon slot="icon" .icon=${label.icon}></ha-icon>`
Expand Down Expand Up @@ -94,14 +94,10 @@ class HaDataTableLabels extends LitElement {
static styles = css`
:host {
display: block;
flex-grow: 1;
flex-shrink: 0;
margin-top: 4px;
height: 22px;
}
ha-chip-set {
position: fixed;
flex-wrap: nowrap;
}
ha-label {
--ha-label-background-color: var(--color, var(--grey-color));
--ha-label-background-opacity: 0.5;
Expand Down
12 changes: 12 additions & 0 deletions src/components/data-table/ha-data-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1400,12 +1400,24 @@ export class HaDataTable extends LitElement {
.center {
text-align: center;
}

.secondary {
color: var(--secondary-text-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.labels-with-text:has(ha-data-table-labels):has(.secondary) {
/* used to display labels with a description */
display: flex;
align-items: center;
}
.labels-with-text:has(ha-data-table-labels) > .secondary {
margin-left: var(--ha-space-2);
margin-inline-start: var(--ha-space-2);
margin-inline-end: initial;
}

.scroller {
height: calc(100% - 57px);
overflow: overlay !important;
Expand Down
49 changes: 49 additions & 0 deletions src/data/entity/entity_description.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { HomeAssistant } from "../../types";

export interface EntityDescription {
entity_id: string;
description: string | undefined;
}

export const getEntityDescription = (
entity_id: string,
descriptions: EntityDescription[]
): string | undefined => {
let description;
if (descriptions.length > 0) {
const entry = descriptions.find((_entry) => _entry.entity_id === entity_id);
if (entry) description = entry.description;
}
return description;
};

interface GetEntityConfigFuncResult {
config: { description: string | undefined };
}

type GetEntityConfigFunc = (
hass: HomeAssistant,
entity_id: string
) => Promise<GetEntityConfigFuncResult | any>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any shouldn't be needed here


export const setEntityDescription = (
hass: HomeAssistant,
entity_id: string,
descriptions: EntityDescription[],
getEntityConfigFunc: GetEntityConfigFunc
) => {
getEntityConfigFunc(hass, entity_id).then((result) => {
let entry;
if (descriptions.length > 0) {
entry = descriptions.find((_entry) => _entry.entity_id === entity_id);
}
if (entry) {
entry.description = result.config.description ?? undefined;
} else {
descriptions.push({
entity_id: entity_id,
description: result.config.description ?? undefined,
});
}
});
};
Comment on lines +29 to +49
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an extremely weird pattern. It should be an async function that returns data instead of modifying descriptions directly. The descriptions.push also won't trigger a render.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was to prepare a list of descriptions and then use it. I believed that acquiring a description takes some time - so wanted to get all descriptions right after a view is created - to have them ready by a moment of 1st render() call.
In reality, these descriptions are not ready yet by the 1st render() call - but they are ready by the 2nd call (do not recall exactly a difference between these two calls). So, I accepted the fact that anyway descriptions are acquired.
But I understand that I have not provided 100% guarantee that all descriptions will be ready by that 2nd render() call moment.
Also, these descriptions are acquired only once. To update them, you need to update a page (F5). Also, descriptions are updated for a NEW added entry (automation or script). Compare to memoize(): if anything is changed in states object or in registry, the memoized property is updated - and causes a new render() call. But descriptions are not a part of a states object or registry. So, I could not to monitor these descriptions asynchronously and then render() when needed. Finally, I decided that this is a rare case and it is not critical to track descriptions.

Sorry for probably being dumb, have a very little experience with async stuff in JS.

43 changes: 40 additions & 3 deletions src/panels/config/automation/ha-automation-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import removeMd from "remove-markdown";
import memoizeOne from "memoize-one";
import { computeCssColor } from "../../../common/color/compute-color";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
Expand Down Expand Up @@ -93,6 +94,11 @@ import type {
UpdateEntityRegistryEntryResult,
} from "../../../data/entity/entity_registry";
import { updateEntityRegistryEntry } from "../../../data/entity/entity_registry";
import type { EntityDescription } from "../../../data/entity/entity_description";
import {
getEntityDescription,
setEntityDescription,
} from "../../../data/entity/entity_description";
import type { LabelRegistryEntry } from "../../../data/label/label_registry";
import {
createLabelRegistryEntry,
Expand Down Expand Up @@ -212,6 +218,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
callback: (entries) => entries[0]?.contentRect.width,
});

private _fetchedDescriptions: EntityDescription[] = [];

private _automations = memoizeOne(
(
automations: AutomationEntity[],
Expand Down Expand Up @@ -293,13 +301,25 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
filterable: true,
direction: "asc",
flex: 2,
extraTemplate: (automation) =>
automation.labels.length
extraTemplate: (automation) => {
const labels = automation.labels.length
? html`<ha-data-table-labels
@label-clicked=${narrow ? undefined : this._labelClicked}
.labels=${automation.labels}
></ha-data-table-labels>`
: nothing,
: nothing;
const description = html`<div class="secondary">
${removeMd(
getEntityDescription(
automation.entity_id,
this._fetchedDescriptions
) ?? ""
)}
</div>`;
return html`<div class="labels-with-text">
${labels}${description}
</div>`;
},
},
area: {
title: localize("ui.panel.config.automation.picker.headers.area"),
Expand Down Expand Up @@ -436,6 +456,11 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
];
}

public connectedCallback() {
super.connectedCallback();
this._fetchDescriptions();
}

protected render(): TemplateResult {
const categoryItems = html`${this._categories?.map(
(category) =>
Expand Down Expand Up @@ -550,6 +575,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
this._labels,
this._filteredAutomations
);

return html`
<hass-tabs-subpage-data-table
.hass=${this.hass}
Expand Down Expand Up @@ -1240,6 +1266,17 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
}
};

private _fetchDescriptions() {
this.automations.forEach((automation) =>
setEntityDescription(
this.hass,
automation.entity_id,
this._fetchedDescriptions,
getAutomationStateConfig
)
);
Comment on lines +1270 to +1277
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would fire a websocket request for each automation. Don't know if core supports it but we should batch this or just add the data in the original fetch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a list of possible requests somewhere?

}

private _showHelp() {
showAlertDialog(this, {
title: this.hass.localize("ui.panel.config.automation.caption"),
Expand Down
43 changes: 40 additions & 3 deletions src/panels/config/script/ha-script-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import removeMd from "remove-markdown";
import memoizeOne from "memoize-one";
import { computeCssColor } from "../../../common/color/compute-color";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
Expand Down Expand Up @@ -79,6 +80,11 @@ import type {
UpdateEntityRegistryEntryResult,
} from "../../../data/entity/entity_registry";
import { updateEntityRegistryEntry } from "../../../data/entity/entity_registry";
import type { EntityDescription } from "../../../data/entity/entity_description";
import {
getEntityDescription,
setEntityDescription,
} from "../../../data/entity/entity_description";
import type { LabelRegistryEntry } from "../../../data/label/label_registry";
import {
createLabelRegistryEntry,
Expand Down Expand Up @@ -206,6 +212,8 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
callback: (entries) => entries[0]?.contentRect.width,
});

private _fetchedDescriptions: EntityDescription[] = [];

private _scripts = memoizeOne(
(
scripts: ScriptEntity[],
Expand Down Expand Up @@ -275,13 +283,25 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
filterable: true,
direction: "asc",
flex: 2,
extraTemplate: (script) =>
script.labels.length
extraTemplate: (script) => {
const labels = script.labels.length
? html`<ha-data-table-labels
@label-clicked=${this._labelClicked}
.labels=${script.labels}
></ha-data-table-labels>`
: nothing,
: nothing;
const description = html`<div class="secondary">
${removeMd(
getEntityDescription(
script.entity_id,
this._fetchedDescriptions
) ?? ""
)}
</div>`;
return html`<div class="labels-with-text">
${labels}${description}
</div>`;
},
},
area: {
title: localize("ui.panel.config.script.picker.headers.area"),
Expand Down Expand Up @@ -445,6 +465,11 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
];
}

public connectedCallback() {
super.connectedCallback();
this._fetchDescriptions();
}

protected render(): TemplateResult {
const categoryItems = html`${this._categories?.map(
(category) =>
Expand Down Expand Up @@ -558,6 +583,7 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
this._labels,
this._filteredScripts
);

return html`
<hass-tabs-subpage-data-table
.hass=${this.hass}
Expand Down Expand Up @@ -1237,6 +1263,17 @@ ${rejected
}
}

private _fetchDescriptions() {
this.scripts.forEach((script) =>
setEntityDescription(
this.hass,
script.entity_id,
this._fetchedDescriptions,
getScriptStateConfig
)
);
}

private _bulkCreateCategory = () => {
showCategoryRegistryDetailDialog(this, {
scope: "script",
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9160,6 +9160,7 @@ __metadata:
punycode: "npm:2.3.1"
qr-scanner: "npm:1.4.2"
qrcode: "npm:1.5.4"
remove-markdown: "npm:0.6.2"
roboto-fontface: "npm:0.10.0"
rrule: "npm:2.8.1"
rspack-manifest-plugin: "npm:5.2.0"
Expand Down Expand Up @@ -12246,6 +12247,13 @@ __metadata:
languageName: node
linkType: hard

"remove-markdown@npm:0.6.2":
version: 0.6.2
resolution: "remove-markdown@npm:0.6.2"
checksum: 10/4ee134dacb69ee768198e81130f7bfce0c8415eb7a97206b6ce67aa16c86c57b704356a8fa57cf45e384d1dbe7bee4d9d7bce3be4318904dd230b80553691c9b
languageName: node
linkType: hard

"remove-trailing-separator@npm:^1.0.1, remove-trailing-separator@npm:^1.1.0":
version: 1.1.0
resolution: "remove-trailing-separator@npm:1.1.0"
Expand Down
Loading