Sort all elements on the area page (#11338)

This commit is contained in:
Philip Allgaier 2022-01-26 18:06:12 +01:00 committed by GitHub
parent 7d335d7d85
commit a4ae1bee79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 162 additions and 89 deletions

View File

@ -1,5 +1,6 @@
import { Connection, createCollection } from "home-assistant-js-websocket";
import { computeStateName } from "../common/entity/compute_state_name";
import { caseInsensitiveStringCompare } from "../common/string/compare";
import { debounce } from "../common/util/debounce";
import { HomeAssistant } from "../types";
import { EntityRegistryEntry } from "./entity_registry";
@ -99,3 +100,8 @@ export const subscribeDeviceRegistry = (
conn,
onChange
);
export const sortDeviceRegistryByName = (entries: DeviceRegistryEntry[]) =>
entries.sort((entry1, entry2) =>
caseInsensitiveStringCompare(entry1.name || "", entry2.name || "")
);

View File

@ -1,6 +1,7 @@
import { Connection, createCollection } from "home-assistant-js-websocket";
import { Store } from "home-assistant-js-websocket/dist/store";
import { computeStateName } from "../common/entity/compute_state_name";
import { caseInsensitiveStringCompare } from "../common/string/compare";
import { debounce } from "../common/util/debounce";
import { HomeAssistant } from "../types";
@ -133,3 +134,8 @@ export const subscribeEntityRegistry = (
conn,
onChange
);
export const sortEntityRegistryByName = (entries: EntityRegistryEntry[]) =>
entries.sort((entry1, entry2) =>
caseInsensitiveStringCompare(entry1.name || "", entry2.name || "")
);

View File

@ -1,13 +1,17 @@
import "@material/mwc-button";
import { mdiImagePlus, mdiPencil } from "@mdi/js";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";
import { mdiImagePlus, mdiPencil } from "@mdi/js";
import { HassEntity } from "home-assistant-js-websocket/dist/types";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
import { groupBy } from "../../../common/util/group-by";
import { afterNextRender } from "../../../common/util/render-status";
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
@ -17,14 +21,19 @@ import {
deleteAreaRegistryEntry,
updateAreaRegistryEntry,
} from "../../../data/area_registry";
import { AutomationEntity } from "../../../data/automation";
import {
computeDeviceName,
DeviceRegistryEntry,
sortDeviceRegistryByName,
} from "../../../data/device_registry";
import {
computeEntityRegistryName,
EntityRegistryEntry,
sortEntityRegistryByName,
} from "../../../data/entity_registry";
import { SceneEntity } from "../../../data/scene";
import { ScriptEntity } from "../../../data/script";
import { findRelated, RelatedResult } from "../../../data/search";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles";
@ -35,11 +44,11 @@ import {
loadAreaRegistryDetailDialog,
showAreaRegistryDetailDialog,
} from "./show-dialog-area-registry-detail";
import { computeDomain } from "../../../common/entity/compute_domain";
import { SceneEntity } from "../../../data/scene";
import { ScriptEntity } from "../../../data/script";
import { AutomationEntity } from "../../../data/automation";
import { groupBy } from "../../../common/util/group-by";
declare type NameAndEntity<EntityType extends HassEntity> = {
name: string;
entity: EntityType;
};
@customElement("ha-config-area-page")
class HaConfigAreaPage extends LitElement {
@ -136,10 +145,59 @@ class HaConfigAreaPage extends LitElement {
this.entities
);
const grouped = groupBy(entities, (entity) =>
// Pre-compute the entity and device names, so we can sort by them
if (devices) {
devices.forEach((entry) => {
entry.name = computeDeviceName(entry, this.hass);
});
sortDeviceRegistryByName(devices);
}
if (entities) {
entities.forEach((entry) => {
entry.name = computeEntityRegistryName(this.hass, entry);
});
sortEntityRegistryByName(entities);
}
// Group entities by domain
const groupedEntities = groupBy(entities, (entity) =>
computeDomain(entity.entity_id)
);
// Pre-compute the name also for the grouped and related entities so we can sort by them
let groupedAutomations: NameAndEntity<AutomationEntity>[] = [];
let groupedScenes: NameAndEntity<SceneEntity>[] = [];
let groupedScripts: NameAndEntity<ScriptEntity>[] = [];
let relatedAutomations: NameAndEntity<AutomationEntity>[] = [];
let relatedScenes: NameAndEntity<SceneEntity>[] = [];
let relatedScripts: NameAndEntity<ScriptEntity>[] = [];
if (isComponentLoaded(this.hass, "automation")) {
({
groupedEntities: groupedAutomations,
relatedEntities: relatedAutomations,
} = this._prepareEntities<AutomationEntity>(
groupedEntities.automation,
this._related?.automation
));
}
if (isComponentLoaded(this.hass, "scene")) {
({ groupedEntities: groupedScenes, relatedEntities: relatedScenes } =
this._prepareEntities<SceneEntity>(
groupedEntities.scene,
this._related?.scene
));
}
if (isComponentLoaded(this.hass, "script")) {
({ groupedEntities: groupedScripts, relatedEntities: relatedScripts } =
this._prepareEntities<ScriptEntity>(
groupedEntities.script,
this._related?.script
));
}
return html`
<hass-tabs-subpage
.hass=${this.hass}
@ -208,9 +266,7 @@ class HaConfigAreaPage extends LitElement {
html`
<a href="/config/devices/device/${device.id}">
<paper-item>
<paper-item-body>
${computeDeviceName(device, this.hass)}
</paper-item-body>
<paper-item-body> ${device.name} </paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
@ -240,9 +296,7 @@ class HaConfigAreaPage extends LitElement {
@click=${this._openEntity}
.entity=${entity}
>
<paper-item-body>
${computeEntityRegistryName(this.hass, entity)}
</paper-item-body>
<paper-item-body> ${entity.name} </paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
`
@ -264,43 +318,33 @@ class HaConfigAreaPage extends LitElement {
"ui.panel.config.devices.automation.automations"
)}
>
${grouped.automation?.length
${groupedAutomations?.length
? html`<h3>
${this.hass.localize(
"ui.panel.config.areas.assigned_to_area"
)}:
</h3>
${grouped.automation.map((entity) => {
const entityState = this.hass.states[
entity.entity_id
] as AutomationEntity | undefined;
return entityState
? this._renderAutomation(entityState)
: "";
})}`
${groupedAutomations.map((automation) =>
this._renderAutomation(
automation.name,
automation.entity
)
)}`
: ""}
${this._related?.automation?.filter(
(entityId) =>
!grouped.automation?.find(
(entity) => entity.entity_id === entityId
)
).length
${relatedAutomations?.length
? html`<h3>
${this.hass.localize(
"ui.panel.config.areas.targeting_area"
)}:
</h3>
${this._related.automation.map((scene) => {
const entityState = this.hass.states[scene] as
| AutomationEntity
| undefined;
return entityState
? this._renderAutomation(entityState)
: "";
})}`
${relatedAutomations.map((automation) =>
this._renderAutomation(
automation.name,
automation.entity
)
)}`
: ""}
${!grouped.automation?.length &&
!this._related?.automation?.length
${!groupedAutomations?.length && !relatedAutomations?.length
? html`
<paper-item class="no-link"
>${this.hass.localize(
@ -321,39 +365,27 @@ class HaConfigAreaPage extends LitElement {
"ui.panel.config.devices.scene.scenes"
)}
>
${grouped.scene?.length
${groupedScenes?.length
? html`<h3>
${this.hass.localize(
"ui.panel.config.areas.assigned_to_area"
)}:
</h3>
${grouped.scene.map((entity) => {
const entityState =
this.hass.states[entity.entity_id];
return entityState
? this._renderScene(entityState)
: "";
})}`
${groupedScenes.map((scene) =>
this._renderScene(scene.name, scene.entity)
)}`
: ""}
${this._related?.scene?.filter(
(entityId) =>
!grouped.scene?.find(
(entity) => entity.entity_id === entityId
)
).length
${relatedScenes?.length
? html`<h3>
${this.hass.localize(
"ui.panel.config.areas.targeting_area"
)}:
</h3>
${this._related.scene.map((scene) => {
const entityState = this.hass.states[scene];
return entityState
? this._renderScene(entityState)
: "";
})}`
${relatedScenes.map((scene) =>
this._renderScene(scene.name, scene.entity)
)}`
: ""}
${!grouped.scene?.length && !this._related?.scene?.length
${!groupedScenes?.length && !relatedScenes?.length
? html`
<paper-item class="no-link"
>${this.hass.localize(
@ -372,42 +404,27 @@ class HaConfigAreaPage extends LitElement {
"ui.panel.config.devices.script.scripts"
)}
>
${grouped.script?.length
${groupedScripts?.length
? html`<h3>
${this.hass.localize(
"ui.panel.config.areas.assigned_to_area"
)}:
</h3>
${grouped.script.map((entity) => {
const entityState = this.hass.states[
entity.entity_id
] as ScriptEntity | undefined;
return entityState
? this._renderScript(entityState)
: "";
})}`
${groupedScripts.map((script) =>
this._renderScript(script.name, script.entity)
)}`
: ""}
${this._related?.script?.filter(
(entityId) =>
!grouped.script?.find(
(entity) => entity.entity_id === entityId
)
).length
${relatedScripts?.length
? html`<h3>
${this.hass.localize(
"ui.panel.config.areas.targeting_area"
)}:
</h3>
${this._related.script.map((scene) => {
const entityState = this.hass.states[scene] as
| ScriptEntity
| undefined;
return entityState
? this._renderScript(entityState)
: "";
})}`
${relatedScripts.map((script) =>
this._renderScript(script.name, script.entity)
)}`
: ""}
${!grouped.script?.length && !this._related?.script?.length
${!groupedScripts?.length && !relatedScripts?.length
? html`
<paper-item class="no-link"
>${this.hass.localize(
@ -425,7 +442,51 @@ class HaConfigAreaPage extends LitElement {
`;
}
private _renderScene(entityState: SceneEntity) {
private _prepareEntities<EntityType extends HassEntity>(
entries?: EntityRegistryEntry[],
relatedEntityIds?: string[]
): {
groupedEntities: NameAndEntity<EntityType>[];
relatedEntities: NameAndEntity<EntityType>[];
} {
const groupedEntities: NameAndEntity<EntityType>[] = [];
const relatedEntities: NameAndEntity<EntityType>[] = [];
if (entries?.length) {
entries.forEach((entity) => {
const entityState = this.hass.states[
entity.entity_id
] as unknown as EntityType;
if (entityState) {
groupedEntities.push({
name: computeStateName(entityState),
entity: entityState,
});
}
});
groupedEntities.sort((entry1, entry2) =>
caseInsensitiveStringCompare(entry1.name!, entry2.name!)
);
}
if (relatedEntityIds?.length) {
relatedEntityIds.forEach((entity) => {
const entityState = this.hass.states[entity] as EntityType;
if (entityState) {
relatedEntities.push({
name: entityState ? computeStateName(entityState) : "",
entity: entityState,
});
}
});
relatedEntities.sort((entry1, entry2) =>
caseInsensitiveStringCompare(entry1.name!, entry2.name!)
);
}
return { groupedEntities, relatedEntities };
}
private _renderScene(name: string, entityState: SceneEntity) {
return html`<div>
<a
href=${ifDefined(
@ -435,7 +496,7 @@ class HaConfigAreaPage extends LitElement {
)}
>
<paper-item .disabled=${!entityState.attributes.id}>
<paper-item-body> ${computeStateName(entityState)} </paper-item-body>
<paper-item-body> ${name} </paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
@ -449,7 +510,7 @@ class HaConfigAreaPage extends LitElement {
</div>`;
}
private _renderAutomation(entityState: AutomationEntity) {
private _renderAutomation(name: string, entityState: AutomationEntity) {
return html`<div>
<a
href=${ifDefined(
@ -459,7 +520,7 @@ class HaConfigAreaPage extends LitElement {
)}
>
<paper-item .disabled=${!entityState.attributes.id}>
<paper-item-body> ${computeStateName(entityState)} </paper-item-body>
<paper-item-body> ${name} </paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
@ -473,10 +534,10 @@ class HaConfigAreaPage extends LitElement {
</div>`;
}
private _renderScript(entityState: ScriptEntity) {
private _renderScript(name: string, entityState: ScriptEntity) {
return html`<a href=${`/config/script/edit/${entityState.entity_id}`}>
<paper-item>
<paper-item-body> ${computeStateName(entityState)} </paper-item-body>
<paper-item-body> ${name} </paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>`;