Skip to content
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

Sort related automations, scripts and scenes on device info page #23740

Draft
wants to merge 2 commits into
base: dev
Choose a base branch
from
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
43 changes: 7 additions & 36 deletions src/components/ha-related-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import { caseInsensitiveStringCompare } from "../common/string/compare";
import type { Blueprints } from "../data/blueprint";
import { fetchBlueprints } from "../data/blueprint";
import type { ConfigEntry } from "../data/config_entries";
Expand Down Expand Up @@ -74,38 +73,10 @@ export class HaRelatedItems extends LitElement {
}
}

private _relatedEntities = memoizeOne((entityIds: string[]) =>
this._toEntities(entityIds)
private _toEntities = memoizeOne((entityIds: string[]) =>
entityIds.map((entityId) => this.hass.states[entityId])
);
Comment on lines +76 to 78
Copy link
Contributor

Choose a reason for hiding this comment

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

This change will defeat the purpose of MemoizeOne here. You can read about MemoizeOne here: https://www.npmjs.com/package/memoize-one#usage

Previously, we had individual MemoizeOne on entities, groups, automations, scripts, ...
So, if the related scripts don't change, memoize will return the cache result fast upon each rendering.

With these changes, only one MemoizeOne remains and since we fetch related entities, groups, automations, scripts and so on in sequence, it will never be able to return the cache.

Copy link
Member

Choose a reason for hiding this comment

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

I would make this 1 memoized function, that returns all the sorted and filtered entities:

private _getRelated_ = memoizeOne((this._related) => {entity: [], automation: [], ... });


private _relatedAutomations = memoizeOne((automationEntityIds: string[]) =>
this._toEntities(automationEntityIds)
);

private _relatedScripts = memoizeOne((scriptEntityIds: string[]) =>
this._toEntities(scriptEntityIds)
);

private _relatedGroups = memoizeOne((groupEntityIds: string[]) =>
this._toEntities(groupEntityIds)
);

private _relatedScenes = memoizeOne((sceneEntityIds: string[]) =>
this._toEntities(sceneEntityIds)
);

private _toEntities = (entityIds: string[]) =>
entityIds
.map((entityId) => this.hass.states[entityId])
.filter((entity) => entity)
.sort((a, b) =>
caseInsensitiveStringCompare(
a.attributes.friendly_name ?? a.entity_id,
b.attributes.friendly_name ?? b.entity_id,
this.hass.language
)
);

private _getConfigEntries = memoizeOne(
(
relatedConfigEntries: string[] | undefined,
Expand Down Expand Up @@ -275,7 +246,7 @@ export class HaRelatedItems extends LitElement {
? html`
<h3>${this.hass.localize("ui.components.related-items.entity")}</h3>
<mwc-list>
${this._relatedEntities(this._related.entity).map(
${this._toEntities(this._related.entity).map(
(entity) => html`
<ha-list-item
@click=${this._openMoreInfo}
Expand All @@ -300,7 +271,7 @@ export class HaRelatedItems extends LitElement {
? html`
<h3>${this.hass.localize("ui.components.related-items.group")}</h3>
<mwc-list>
${this._relatedGroups(this._related.group).map(
${this._toEntities(this._related.group).map(
(group) => html`
<ha-list-item
@click=${this._openMoreInfo}
Expand All @@ -325,7 +296,7 @@ export class HaRelatedItems extends LitElement {
? html`
<h3>${this.hass.localize("ui.components.related-items.scene")}</h3>
<mwc-list>
${this._relatedScenes(this._related.scene).map(
${this._toEntities(this._related.scene).map(
(scene) => html`
<ha-list-item
@click=${this._openMoreInfo}
Expand Down Expand Up @@ -378,7 +349,7 @@ export class HaRelatedItems extends LitElement {
${this.hass.localize("ui.components.related-items.automation")}
</h3>
<mwc-list>
${this._relatedAutomations(this._related.automation).map(
${this._toEntities(this._related.automation).map(
(automation) => html`
<ha-list-item
@click=${this._openMoreInfo}
Expand Down Expand Up @@ -430,7 +401,7 @@ export class HaRelatedItems extends LitElement {
? html`
<h3>${this.hass.localize("ui.components.related-items.script")}</h3>
<mwc-list>
${this._relatedScripts(this._related.script).map(
${this._toEntities(this._related.script).map(
(script) => html`
<ha-list-item
@click=${this._openMoreInfo}
Expand Down
25 changes: 22 additions & 3 deletions src/data/search.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { HassEntity } from "home-assistant-js-websocket";
import type { HomeAssistant } from "../types";
import { caseInsensitiveStringCompare } from "../common/string/compare";

export interface RelatedResult {
area?: string[];
Expand Down Expand Up @@ -35,13 +37,30 @@ export type ItemType =
| "automation_blueprint"
| "script_blueprint";

export const findRelated = (
export const findRelated = async (
hass: HomeAssistant,
itemType: ItemType,
itemId: string
): Promise<RelatedResult> =>
hass.callWS({
): Promise<RelatedResult> => {
const related = await hass.callWS<RelatedResult>({
type: "search/related",
item_type: itemType,
item_id: itemId,
});

Object.keys(related).forEach((key) => {
related[key] = related[key]
.map((id: string) => hass.states[id])
Copy link
Member

Choose a reason for hiding this comment

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

Not all related items are entities, so this does not makes sense. Only for scenes, scripts, automations and entity it makes sense.

.filter(Boolean)
.sort((a: HassEntity, b: HassEntity) =>
Copy link
Member

Choose a reason for hiding this comment

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

If an entity name is changed after we fetched related, it will not update the sorting, that is kinda weird.

caseInsensitiveStringCompare(
a.attributes.friendly_name ?? a.entity_id,
b.attributes.friendly_name ?? b.entity_id,
hass.language
)
)
.map((entity: HassEntity) => entity.entity_id);
});

return related;
};
Loading