Show entities on area page (#8980)

Co-authored-by: Philip Allgaier <mail@spacegaier.de>
This commit is contained in:
Paulus Schoutsen 2021-04-28 08:01:43 -07:00 committed by GitHub
parent 9690434cac
commit 7962130a0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 137 additions and 14 deletions

View File

@ -22,12 +22,16 @@ import {
import { import {
computeDeviceName, computeDeviceName,
DeviceRegistryEntry, DeviceRegistryEntry,
devicesInArea,
} from "../../../data/device_registry"; } from "../../../data/device_registry";
import {
computeEntityRegistryName,
EntityRegistryEntry,
} from "../../../data/entity_registry";
import { findRelated, RelatedResult } from "../../../data/search"; import { findRelated, RelatedResult } from "../../../data/search";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles"; import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types"; import { HomeAssistant, Route } from "../../../types";
import { showEntityEditorDialog } from "../entities/show-dialog-entity-editor";
import { configSections } from "../ha-panel-config"; import { configSections } from "../ha-panel-config";
import { import {
loadAreaRegistryDetailDialog, loadAreaRegistryDetailDialog,
@ -44,6 +48,8 @@ class HaConfigAreaPage extends LitElement {
@property() public devices!: DeviceRegistryEntry[]; @property() public devices!: DeviceRegistryEntry[];
@property() public entities!: EntityRegistryEntry[];
@property({ type: Boolean, reflect: true }) public narrow!: boolean; @property({ type: Boolean, reflect: true }) public narrow!: boolean;
@property() public isWide!: boolean; @property() public isWide!: boolean;
@ -58,9 +64,39 @@ class HaConfigAreaPage extends LitElement {
| AreaRegistryEntry | AreaRegistryEntry
| undefined => areas.find((area) => area.area_id === areaId)); | undefined => areas.find((area) => area.area_id === areaId));
private _devices = memoizeOne( private _memberships = memoizeOne(
(areaId: string, devices: DeviceRegistryEntry[]): DeviceRegistryEntry[] => (
devicesInArea(devices, areaId) areaId: string,
registryDevices: DeviceRegistryEntry[],
registryEntities: EntityRegistryEntry[]
) => {
const devices = new Map();
for (const device of registryDevices) {
if (device.area_id === areaId) {
devices.set(device.id, device);
}
}
const entities: EntityRegistryEntry[] = [];
const indirectEntities: EntityRegistryEntry[] = [];
for (const entity of registryEntities) {
if (entity.area_id) {
if (entity.area_id === areaId) {
entities.push(entity);
}
} else if (devices.has(entity.device_id)) {
indirectEntities.push(entity);
}
}
return {
devices: Array.from(devices.values()),
entities,
indirectEntities,
};
}
); );
protected firstUpdated(changedProps) { protected firstUpdated(changedProps) {
@ -87,7 +123,11 @@ class HaConfigAreaPage extends LitElement {
`; `;
} }
const devices = this._devices(this.areaId, this.devices); const { devices, entities } = this._memberships(
this.areaId,
this.devices,
this.entities
);
return html` return html`
<hass-tabs-subpage <hass-tabs-subpage
@ -144,6 +184,33 @@ class HaConfigAreaPage extends LitElement {
> >
`} `}
</ha-card> </ha-card>
<ha-card
.header=${this.hass.localize(
"ui.panel.config.areas.editor.linked_entities_caption"
)}
>${entities.length
? entities.map(
(entity) =>
html`
<paper-item
@click=${this._openEntity}
.entity=${entity}
>
<paper-item-body>
${computeEntityRegistryName(this.hass, entity)}
</paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
`
)
: html`
<paper-item class="no-link"
>${this.hass.localize(
"ui.panel.config.areas.editor.no_linked_entities"
)}</paper-item
>
`}
</ha-card>
</div> </div>
<div class="column"> <div class="column">
${isComponentLoaded(this.hass, "automation") ${isComponentLoaded(this.hass, "automation")
@ -299,6 +366,14 @@ class HaConfigAreaPage extends LitElement {
this._openDialog(entry); this._openDialog(entry);
} }
private _openEntity(ev) {
const entry: EntityRegistryEntry = (ev.currentTarget as any).entity;
showEntityEditorDialog(this, {
entity_id: entry.entity_id,
entry,
});
}
private _openDialog(entry?: AreaRegistryEntry) { private _openDialog(entry?: AreaRegistryEntry) {
showAreaRegistryDetailDialog(this, { showAreaRegistryDetailDialog(this, {
entry, entry,

View File

@ -24,10 +24,8 @@ import {
AreaRegistryEntry, AreaRegistryEntry,
createAreaRegistryEntry, createAreaRegistryEntry,
} from "../../../data/area_registry"; } from "../../../data/area_registry";
import { import type { DeviceRegistryEntry } from "../../../data/device_registry";
DeviceRegistryEntry, import type { EntityRegistryEntry } from "../../../data/entity_registry";
devicesInArea,
} from "../../../data/device_registry";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box"; import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-loading-screen"; import "../../../layouts/hass-loading-screen";
import "../../../layouts/hass-tabs-subpage-data-table"; import "../../../layouts/hass-tabs-subpage-data-table";
@ -53,12 +51,39 @@ export class HaConfigAreasDashboard extends LitElement {
@property() public devices!: DeviceRegistryEntry[]; @property() public devices!: DeviceRegistryEntry[];
@property() public entities!: EntityRegistryEntry[];
private _areas = memoizeOne( private _areas = memoizeOne(
(areas: AreaRegistryEntry[], devices: DeviceRegistryEntry[]) => { (
areas: AreaRegistryEntry[],
devices: DeviceRegistryEntry[],
entities: EntityRegistryEntry[]
) => {
return areas.map((area) => { return areas.map((area) => {
const devicesInArea = new Set();
for (const device of devices) {
if (device.area_id === area.area_id) {
devicesInArea.add(device.id);
}
}
let entitiesInArea = 0;
for (const entity of entities) {
if (
entity.area_id
? entity.area_id === area.area_id
: devicesInArea.has(entity.device_id)
) {
entitiesInArea++;
}
}
return { return {
...area, ...area,
devices: devicesInArea(devices, area.area_id).length, devices: devicesInArea.size,
entities: entitiesInArea,
}; };
}); });
} }
@ -97,6 +122,15 @@ export class HaConfigAreasDashboard extends LitElement {
width: "20%", width: "20%",
direction: "asc", direction: "asc",
}, },
entities: {
title: this.hass.localize(
"ui.panel.config.areas.data_table.entities"
),
sortable: true,
type: "numeric",
width: "20%",
direction: "asc",
},
} }
); );
@ -110,7 +144,7 @@ export class HaConfigAreasDashboard extends LitElement {
.tabs=${configSections.integrations} .tabs=${configSections.integrations}
.route=${this.route} .route=${this.route}
.columns=${this._columns(this.narrow)} .columns=${this._columns(this.narrow)}
.data=${this._areas(this.areas, this.devices)} .data=${this._areas(this.areas, this.devices, this.entities)}
@row-click=${this._handleRowClicked} @row-click=${this._handleRowClicked}
.noDataText=${this.hass.localize( .noDataText=${this.hass.localize(
"ui.panel.config.areas.picker.no_areas" "ui.panel.config.areas.picker.no_areas"

View File

@ -15,6 +15,10 @@ import {
DeviceRegistryEntry, DeviceRegistryEntry,
subscribeDeviceRegistry, subscribeDeviceRegistry,
} from "../../../data/device_registry"; } from "../../../data/device_registry";
import {
EntityRegistryEntry,
subscribeEntityRegistry,
} from "../../../data/entity_registry";
import { import {
HassRouterPage, HassRouterPage,
RouterOptions, RouterOptions,
@ -51,6 +55,9 @@ class HaConfigAreas extends HassRouterPage {
@internalProperty() @internalProperty()
private _deviceRegistryEntries: DeviceRegistryEntry[] = []; private _deviceRegistryEntries: DeviceRegistryEntry[] = [];
@internalProperty()
private _entityRegistryEntries: EntityRegistryEntry[] = [];
@internalProperty() private _areas: AreaRegistryEntry[] = []; @internalProperty() private _areas: AreaRegistryEntry[] = [];
private _unsubs?: UnsubscribeFunc[]; private _unsubs?: UnsubscribeFunc[];
@ -90,6 +97,7 @@ class HaConfigAreas extends HassRouterPage {
pageEl.entries = this._configEntries; pageEl.entries = this._configEntries;
pageEl.devices = this._deviceRegistryEntries; pageEl.devices = this._deviceRegistryEntries;
pageEl.entities = this._entityRegistryEntries;
pageEl.areas = this._areas; pageEl.areas = this._areas;
pageEl.narrow = this.narrow; pageEl.narrow = this.narrow;
pageEl.isWide = this.isWide; pageEl.isWide = this.isWide;
@ -113,6 +121,9 @@ class HaConfigAreas extends HassRouterPage {
subscribeDeviceRegistry(this.hass.connection, (entries) => { subscribeDeviceRegistry(this.hass.connection, (entries) => {
this._deviceRegistryEntries = entries; this._deviceRegistryEntries = entries;
}), }),
subscribeEntityRegistry(this.hass.connection, (entries) => {
this._entityRegistryEntries = entries;
}),
]; ];
} }
} }

View File

@ -905,7 +905,8 @@
"description": "Group devices and entities into areas", "description": "Group devices and entities into areas",
"data_table": { "data_table": {
"area": "Area", "area": "Area",
"devices": "Devices" "devices": "Devices",
"entities": "Entities"
}, },
"picker": { "picker": {
"header": "Areas", "header": "Areas",
@ -923,7 +924,9 @@
"name": "Name", "name": "Name",
"name_required": "Name is required", "name_required": "Name is required",
"area_id": "Area ID", "area_id": "Area ID",
"unknown_error": "Unknown error" "unknown_error": "Unknown error",
"linked_entities_caption": "Entities",
"no_linked_entities": "There are no entities linked to this area."
}, },
"delete": { "delete": {
"confirmation_title": "Are you sure you want to delete this area?", "confirmation_title": "Are you sure you want to delete this area?",