-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Automations & Scripts tables: show descriptions #28592
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from 14 commits
d5d40de
b9ac14b
396e026
6ac4aaa
7d999fb
bc94925
82aeedb
7858a57
f98d84a
1643b79
c3e24d8
2da8149
2ab0f2c
48feafe
807073e
500fb1a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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>; | ||
|
|
||
| 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
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. Sorry for probably being dumb, have a very little experience with async stuff in JS. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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"; | ||
|
|
@@ -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, | ||
|
|
@@ -210,6 +216,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) { | |
| callback: (entries) => entries[0]?.contentRect.width, | ||
| }); | ||
|
|
||
| private _fetchedDescriptions: EntityDescription[] = []; | ||
|
|
||
| private _automations = memoizeOne( | ||
| ( | ||
| automations: AutomationEntity[], | ||
|
|
@@ -291,13 +299,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"), | ||
|
|
@@ -409,6 +429,11 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) { | |
| ]; | ||
| } | ||
|
|
||
| public connectedCallback() { | ||
| super.connectedCallback(); | ||
| this._fetchDescriptions(); | ||
| } | ||
|
|
||
| protected render(): TemplateResult { | ||
| const categoryItems = html`${this._categories?.map( | ||
| (category) => | ||
|
|
@@ -523,6 +548,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) { | |
| this._labels, | ||
| this._filteredAutomations | ||
| ); | ||
|
|
||
| return html` | ||
| <hass-tabs-subpage-data-table | ||
| .hass=${this.hass} | ||
|
|
@@ -1213,6 +1239,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
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
anyshouldn't be needed here