Skip to content
Merged
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
85 changes: 80 additions & 5 deletions src/panels/config/areas/ha-config-area-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@ import {
import {
computeDeviceName,
DeviceRegistryEntry,
devicesInArea,
} from "../../../data/device_registry";
import {
computeEntityRegistryName,
EntityRegistryEntry,
} from "../../../data/entity_registry";
import { findRelated, RelatedResult } from "../../../data/search";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types";
import { showEntityEditorDialog } from "../entities/show-dialog-entity-editor";
import { configSections } from "../ha-panel-config";
import {
loadAreaRegistryDetailDialog,
Expand All @@ -44,6 +48,8 @@ class HaConfigAreaPage extends LitElement {

@property() public devices!: DeviceRegistryEntry[];

@property() public entities!: EntityRegistryEntry[];

@property({ type: Boolean, reflect: true }) public narrow!: boolean;

@property() public isWide!: boolean;
Expand All @@ -58,9 +64,39 @@ class HaConfigAreaPage extends LitElement {
| AreaRegistryEntry
| undefined => areas.find((area) => area.area_id === areaId));

private _devices = memoizeOne(
(areaId: string, devices: DeviceRegistryEntry[]): DeviceRegistryEntry[] =>
devicesInArea(devices, areaId)
private _memberships = memoizeOne(
(
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,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We don't do anything with these?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm still thinking about what to do with them 🤷 maybe a toggle to include them ? A new card ?

};
}
);

protected firstUpdated(changedProps) {
Expand All @@ -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`
<hass-tabs-subpage
Expand Down Expand Up @@ -144,6 +184,33 @@ class HaConfigAreaPage extends LitElement {
>
`}
</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 class="column">
${isComponentLoaded(this.hass, "automation")
Expand Down Expand Up @@ -299,6 +366,14 @@ class HaConfigAreaPage extends LitElement {
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) {
showAreaRegistryDetailDialog(this, {
entry,
Expand Down
48 changes: 41 additions & 7 deletions src/panels/config/areas/ha-config-areas-dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,8 @@ import {
AreaRegistryEntry,
createAreaRegistryEntry,
} from "../../../data/area_registry";
import {
DeviceRegistryEntry,
devicesInArea,
} from "../../../data/device_registry";
import type { DeviceRegistryEntry } from "../../../data/device_registry";
import type { EntityRegistryEntry } from "../../../data/entity_registry";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-loading-screen";
import "../../../layouts/hass-tabs-subpage-data-table";
Expand All @@ -53,12 +51,39 @@ export class HaConfigAreasDashboard extends LitElement {

@property() public devices!: DeviceRegistryEntry[];

@property() public entities!: EntityRegistryEntry[];

private _areas = memoizeOne(
(areas: AreaRegistryEntry[], devices: DeviceRegistryEntry[]) => {
(
areas: AreaRegistryEntry[],
devices: DeviceRegistryEntry[],
entities: EntityRegistryEntry[]
) => {
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 {
...area,
devices: devicesInArea(devices, area.area_id).length,
devices: devicesInArea.size,
entities: entitiesInArea,
};
});
}
Expand Down Expand Up @@ -97,6 +122,15 @@ export class HaConfigAreasDashboard extends LitElement {
width: "20%",
direction: "asc",
},
entities: {
title: this.hass.localize(
"ui.panel.config.areas.data_table.entities"
),
sortable: true,
type: "numeric",
width: "20%",
direction: "asc",
},
}
);

Expand All @@ -110,7 +144,7 @@ export class HaConfigAreasDashboard extends LitElement {
.tabs=${configSections.integrations}
.route=${this.route}
.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}
.noDataText=${this.hass.localize(
"ui.panel.config.areas.picker.no_areas"
Expand Down
11 changes: 11 additions & 0 deletions src/panels/config/areas/ha-config-areas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import {
DeviceRegistryEntry,
subscribeDeviceRegistry,
} from "../../../data/device_registry";
import {
EntityRegistryEntry,
subscribeEntityRegistry,
} from "../../../data/entity_registry";
import {
HassRouterPage,
RouterOptions,
Expand Down Expand Up @@ -51,6 +55,9 @@ class HaConfigAreas extends HassRouterPage {
@internalProperty()
private _deviceRegistryEntries: DeviceRegistryEntry[] = [];

@internalProperty()
private _entityRegistryEntries: EntityRegistryEntry[] = [];

@internalProperty() private _areas: AreaRegistryEntry[] = [];

private _unsubs?: UnsubscribeFunc[];
Expand Down Expand Up @@ -90,6 +97,7 @@ class HaConfigAreas extends HassRouterPage {

pageEl.entries = this._configEntries;
pageEl.devices = this._deviceRegistryEntries;
pageEl.entities = this._entityRegistryEntries;
pageEl.areas = this._areas;
pageEl.narrow = this.narrow;
pageEl.isWide = this.isWide;
Expand All @@ -113,6 +121,9 @@ class HaConfigAreas extends HassRouterPage {
subscribeDeviceRegistry(this.hass.connection, (entries) => {
this._deviceRegistryEntries = entries;
}),
subscribeEntityRegistry(this.hass.connection, (entries) => {
this._entityRegistryEntries = entries;
}),
];
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,8 @@
"description": "Group devices and entities into areas",
"data_table": {
"area": "Area",
"devices": "Devices"
"devices": "Devices",
"entities": "Entities"
},
"picker": {
"header": "Areas",
Expand All @@ -904,7 +905,9 @@
"name": "Name",
"name_required": "Name is required",
"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": {
"confirmation_title": "Are you sure you want to delete this area?",
Expand Down