Refactor and clean up of device pages (#18796)

This commit is contained in:
Bram Kragten 2023-11-29 09:01:11 +01:00 committed by GitHub
parent 081bd98e98
commit d8d4ecf79f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 187 deletions

View File

@ -1,15 +1,13 @@
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { titleCase } from "../../../../common/string/title-case";
import "../../../../components/ha-card"; import "../../../../components/ha-card";
import { AreaRegistryEntry } from "../../../../data/area_registry";
import { import {
computeDeviceName, computeDeviceName,
DeviceRegistryEntry, DeviceRegistryEntry,
} from "../../../../data/device_registry"; } from "../../../../data/device_registry";
import { haStyle } from "../../../../resources/styles"; import { haStyle } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types"; import { HomeAssistant } from "../../../../types";
import { loadDeviceRegistryDetailDialog } from "../device-registry-detail/show-dialog-device-registry-detail";
import { titleCase } from "../../../../common/string/title-case";
@customElement("ha-device-info-card") @customElement("ha-device-info-card")
export class HaDeviceCard extends LitElement { export class HaDeviceCard extends LitElement {
@ -17,10 +15,6 @@ export class HaDeviceCard extends LitElement {
@property() public device!: DeviceRegistryEntry; @property() public device!: DeviceRegistryEntry;
@property() public devices!: DeviceRegistryEntry[];
@property() public areas!: AreaRegistryEntry[];
@property() public narrow!: boolean; @property() public narrow!: boolean;
protected render(): TemplateResult { protected render(): TemplateResult {
@ -37,7 +31,7 @@ export class HaDeviceCard extends LitElement {
> >
<div class="card-content"> <div class="card-content">
${this.device.model ${this.device.model
? html` <div class="model">${this.device.model}</div> ` ? html`<div class="model">${this.device.model}</div>`
: ""} : ""}
${this.device.manufacturer ${this.device.manufacturer
? html` ? html`
@ -58,10 +52,7 @@ export class HaDeviceCard extends LitElement {
<span class="hub" <span class="hub"
><a ><a
href="/config/devices/device/${this.device.via_device_id}" href="/config/devices/device/${this.device.via_device_id}"
>${this._computeDeviceName( >${this._computeDeviceName(this.device.via_device_id)}</a
this.devices,
this.device.via_device_id
)}</a
></span ></span
> >
</div> </div>
@ -123,13 +114,8 @@ export class HaDeviceCard extends LitElement {
); );
} }
protected firstUpdated(changedProps) { private _computeDeviceName(deviceId) {
super.firstUpdated(changedProps); const device = this.hass.devices[deviceId];
loadDeviceRegistryDetailDialog();
}
private _computeDeviceName(devices, deviceId) {
const device = devices.find((dev) => dev.id === deviceId);
return device return device
? computeDeviceName(device, this.hass) ? computeDeviceName(device, this.hass)
: `<${this.hass.localize( : `<${this.hass.localize(
@ -151,9 +137,6 @@ export class HaDeviceCard extends LitElement {
.device { .device {
width: 30%; width: 30%;
} }
.area {
color: var(--primary-text-color);
}
.extra-info { .extra-info {
margin-top: 8px; margin-top: 8px;
word-wrap: break-word; word-wrap: break-word;

View File

@ -35,7 +35,6 @@ import "../../../components/ha-button-menu";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
import "../../../components/ha-icon-next"; import "../../../components/ha-icon-next";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
import { AreaRegistryEntry } from "../../../data/area_registry";
import { getSignedPath } from "../../../data/auth"; import { getSignedPath } from "../../../data/auth";
import { import {
ConfigEntry, ConfigEntry,
@ -109,14 +108,8 @@ export interface DeviceAlert {
export class HaConfigDevicePage extends LitElement { export class HaConfigDevicePage extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public devices!: DeviceRegistryEntry[];
@property({ attribute: false }) public entries!: ConfigEntry[]; @property({ attribute: false }) public entries!: ConfigEntry[];
@property({ attribute: false }) public entities!: EntityRegistryEntry[];
@property({ attribute: false }) public areas!: AreaRegistryEntry[];
@property({ attribute: false }) public manifests!: IntegrationManifest[]; @property({ attribute: false }) public manifests!: IntegrationManifest[];
@property() public deviceId!: string; @property() public deviceId!: string;
@ -144,14 +137,6 @@ export class HaConfigDevicePage extends LitElement {
private _logbookTime = { recent: 86400 }; private _logbookTime = { recent: 86400 };
private _device = memoizeOne(
(
deviceId: string,
devices: DeviceRegistryEntry[]
): DeviceRegistryEntry | undefined =>
devices ? devices.find((device) => device.id === deviceId) : undefined
);
private _integrations = memoizeOne( private _integrations = memoizeOne(
( (
device: DeviceRegistryEntry, device: DeviceRegistryEntry,
@ -234,15 +219,6 @@ export class HaConfigDevicePage extends LitElement {
} }
); );
private _computeArea = memoizeOne(
(areas, device): AreaRegistryEntry | undefined => {
if (!areas || !device || !device.area_id) {
return undefined;
}
return areas.find((area) => area.area_id === device.area_id);
}
);
private _batteryEntity = memoizeOne( private _batteryEntity = memoizeOne(
(entities: EntityRegistryEntry[]): EntityRegistryEntry | undefined => (entities: EntityRegistryEntry[]): EntityRegistryEntry | undefined =>
findBatteryEntity(this.hass, entities) findBatteryEntity(this.hass, entities)
@ -272,7 +248,6 @@ export class HaConfigDevicePage extends LitElement {
this._deleteButtons && this._deleteButtons &&
this._deviceActions && this._deviceActions &&
this._deviceAlerts) || this._deviceAlerts) ||
!this.devices ||
!this.deviceId || !this.deviceId ||
!this.entries !this.entries
) { ) {
@ -302,10 +277,10 @@ export class HaConfigDevicePage extends LitElement {
} }
protected render() { protected render() {
if (!this.devices || !this.deviceId) { if (!this.hass || !this.deviceId) {
return nothing; return nothing;
} }
const device = this._device(this.deviceId, this.devices); const device = this.hass.devices[this.deviceId];
if (!device) { if (!device) {
return html` return html`
@ -324,7 +299,7 @@ export class HaConfigDevicePage extends LitElement {
this.entries, this.entries,
this.manifests this.manifests
); );
const entities = this._entities(this.deviceId, this.entities); const entities = this._entities(this.deviceId, this._entityReg);
const entitiesByCategory = this._entitiesByCategory(entities); const entitiesByCategory = this._entitiesByCategory(entities);
const batteryEntity = this._batteryEntity(entities); const batteryEntity = this._batteryEntity(entities);
const batteryChargingEntity = this._batteryChargingEntity(entities); const batteryChargingEntity = this._batteryChargingEntity(entities);
@ -336,7 +311,7 @@ export class HaConfigDevicePage extends LitElement {
const batteryChargingState = batteryChargingEntity const batteryChargingState = batteryChargingEntity
? this.hass.states[batteryChargingEntity.entity_id] ? this.hass.states[batteryChargingEntity.entity_id]
: undefined; : undefined;
const area = this._computeArea(this.areas, device); const area = device.area_id ? this.hass.areas[device.area_id] : undefined;
const deviceInfo: TemplateResult[] = integrations.map( const deviceInfo: TemplateResult[] = integrations.map(
(integration) => (integration) =>
@ -636,7 +611,7 @@ export class HaConfigDevicePage extends LitElement {
<div class="items"> <div class="items">
${this._related.script.map((script) => { ${this._related.script.map((script) => {
const entityState = this.hass.states[script]; const entityState = this.hass.states[script];
const entry = this.entities.find( const entry = this._entityReg.find(
(e) => e.entity_id === script (e) => e.entity_id === script
); );
let url = `/config/script/show/${entityState.entity_id}`; let url = `/config/script/show/${entityState.entity_id}`;
@ -766,8 +741,6 @@ export class HaConfigDevicePage extends LitElement {
} }
<ha-device-info-card <ha-device-info-card
.hass=${this.hass} .hass=${this.hass}
.areas=${this.areas}
.devices=${this.devices}
.device=${device} .device=${device}
> >
${deviceInfo} ${deviceInfo}
@ -940,7 +913,7 @@ export class HaConfigDevicePage extends LitElement {
return; return;
} }
const device = this._device(this.deviceId, this.devices); const device = this.hass.devices[this.deviceId];
if (!device) { if (!device) {
return; return;
@ -1003,7 +976,7 @@ export class HaConfigDevicePage extends LitElement {
} }
private _getDeleteActions() { private _getDeleteActions() {
const device = this._device(this.deviceId, this.devices); const device = this.hass.devices[this.deviceId];
if (!device) { if (!device) {
return; return;
@ -1066,7 +1039,7 @@ export class HaConfigDevicePage extends LitElement {
} }
private async _getDeviceActions() { private async _getDeviceActions() {
const device = this._device(this.deviceId, this.devices); const device = this.hass.devices[this.deviceId];
if (!device) { if (!device) {
return; return;
@ -1129,7 +1102,7 @@ export class HaConfigDevicePage extends LitElement {
} }
private async _getDeviceAlerts() { private async _getDeviceAlerts() {
const device = this._device(this.deviceId, this.devices); const device = this.hass.devices[this.deviceId];
if (!device) { if (!device) {
return; return;
@ -1179,7 +1152,7 @@ export class HaConfigDevicePage extends LitElement {
private _createScene() { private _createScene() {
const entities: SceneEntities = {}; const entities: SceneEntities = {};
this._entities(this.deviceId, this.entities).forEach((entity) => { this._entities(this.deviceId, this._entityReg).forEach((entity) => {
entities[entity.entity_id] = ""; entities[entity.entity_id] = "";
}); });
showSceneEditor({ showSceneEditor({
@ -1189,7 +1162,7 @@ export class HaConfigDevicePage extends LitElement {
private _showScriptDialog() { private _showScriptDialog() {
showDeviceAutomationDialog(this, { showDeviceAutomationDialog(this, {
device: this._device(this.deviceId, this.devices)!, device: this.hass.devices[this.deviceId],
entityReg: this._entityReg, entityReg: this._entityReg,
script: true, script: true,
}); });
@ -1197,7 +1170,7 @@ export class HaConfigDevicePage extends LitElement {
private _showAutomationDialog() { private _showAutomationDialog() {
showDeviceAutomationDialog(this, { showDeviceAutomationDialog(this, {
device: this._device(this.deviceId, this.devices)!, device: this.hass.devices[this.deviceId],
entityReg: this._entityReg, entityReg: this._entityReg,
script: false, script: false,
}); });
@ -1232,7 +1205,7 @@ export class HaConfigDevicePage extends LitElement {
} }
private async _showSettings() { private async _showSettings() {
const device = this._device(this.deviceId, this.devices)!; const device = this.hass.devices[this.deviceId];
showDeviceRegistryDetailDialog(this, { showDeviceRegistryDetailDialog(this, {
device, device,
updateEntry: async (updates) => { updateEntry: async (updates) => {
@ -1244,7 +1217,7 @@ export class HaConfigDevicePage extends LitElement {
if (disabled) { if (disabled) {
for (const cnfg_entry of device.config_entries) { for (const cnfg_entry of device.config_entries) {
if ( if (
!this.devices.some( !Object.values(this.hass.devices).some(
(dvc) => (dvc) =>
dvc.id !== device.id && dvc.id !== device.id &&
dvc.config_entries.includes(cnfg_entry) dvc.config_entries.includes(cnfg_entry)
@ -1315,7 +1288,7 @@ export class HaConfigDevicePage extends LitElement {
) { ) {
return; return;
} }
const entities = this._entities(this.deviceId, this.entities); const entities = this._entities(this.deviceId, this._entityReg);
const renameEntityid = const renameEntityid =
this.showAdvanced && this.showAdvanced &&

View File

@ -1,3 +1,4 @@
import { consume } from "@lit-labs/context";
import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item"; import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
import { mdiCancel, mdiFilterVariant, mdiPlus } from "@mdi/js"; import { mdiCancel, mdiFilterVariant, mdiPlus } from "@mdi/js";
@ -29,8 +30,8 @@ import "../../../components/ha-button-menu";
import "../../../components/ha-check-list-item"; import "../../../components/ha-check-list-item";
import "../../../components/ha-fab"; import "../../../components/ha-fab";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
import { AreaRegistryEntry } from "../../../data/area_registry";
import { ConfigEntry, sortConfigEntries } from "../../../data/config_entries"; import { ConfigEntry, sortConfigEntries } from "../../../data/config_entries";
import { fullEntitiesContext } from "../../../data/context";
import { import {
DeviceEntityLookup, DeviceEntityLookup,
DeviceRegistryEntry, DeviceRegistryEntry,
@ -65,13 +66,11 @@ export class HaConfigDeviceDashboard extends LitElement {
@property() public isWide = false; @property() public isWide = false;
@property() public devices!: DeviceRegistryEntry[];
@property() public entries!: ConfigEntry[]; @property() public entries!: ConfigEntry[];
@property() public entities!: EntityRegistryEntry[]; @state()
@consume({ context: fullEntitiesContext, subscribe: true })
@property() public areas!: AreaRegistryEntry[]; entities!: EntityRegistryEntry[];
@property() public manifests!: IntegrationManifest[]; @property() public manifests!: IntegrationManifest[];
@ -87,28 +86,34 @@ export class HaConfigDeviceDashboard extends LitElement {
private _ignoreLocationChange = false; private _ignoreLocationChange = false;
public constructor() { public connectedCallback() {
super(); super.connectedCallback();
window.addEventListener("location-changed", () => { window.addEventListener("location-changed", this._locationChanged);
if (this._ignoreLocationChange) { window.addEventListener("popstate", this._popState);
this._ignoreLocationChange = false;
return;
}
if (
window.location.search.substring(1) !== this._searchParms.toString()
) {
this._searchParms = new URLSearchParams(window.location.search);
}
});
window.addEventListener("popstate", () => {
if (
window.location.search.substring(1) !== this._searchParms.toString()
) {
this._searchParms = new URLSearchParams(window.location.search);
}
});
} }
disconnectedCallback(): void {
super.disconnectedCallback();
window.removeEventListener("location-changed", this._locationChanged);
window.removeEventListener("popstate", this._popState);
}
private _locationChanged = () => {
if (this._ignoreLocationChange) {
this._ignoreLocationChange = false;
return;
}
if (window.location.search.substring(1) !== this._searchParms.toString()) {
this._searchParms = new URLSearchParams(window.location.search);
}
};
private _popState = () => {
if (window.location.search.substring(1) !== this._searchParms.toString()) {
this._searchParms = new URLSearchParams(window.location.search);
}
};
private _activeFilters = memoizeOne( private _activeFilters = memoizeOne(
( (
entries: ConfigEntry[], entries: ConfigEntry[],
@ -152,10 +157,10 @@ export class HaConfigDeviceDashboard extends LitElement {
private _devicesAndFilterDomains = memoizeOne( private _devicesAndFilterDomains = memoizeOne(
( (
devices: DeviceRegistryEntry[], devices: HomeAssistant["devices"],
entries: ConfigEntry[], entries: ConfigEntry[],
entities: EntityRegistryEntry[], entities: EntityRegistryEntry[],
areas: AreaRegistryEntry[], areas: HomeAssistant["areas"],
manifests: IntegrationManifest[], manifests: IntegrationManifest[],
filters: URLSearchParams, filters: URLSearchParams,
showDisabled: boolean, showDisabled: boolean,
@ -163,12 +168,7 @@ export class HaConfigDeviceDashboard extends LitElement {
) => { ) => {
// Some older installations might have devices pointing at invalid entryIDs // Some older installations might have devices pointing at invalid entryIDs
// So we guard for that. // So we guard for that.
let outputDevices: DeviceRowData[] = devices; let outputDevices: DeviceRowData[] = Object.values(devices);
const deviceLookup: { [deviceId: string]: DeviceRegistryEntry } = {};
for (const device of devices) {
deviceLookup[device.id] = device;
}
// If nothing gets filtered, this is our correct count of devices // If nothing gets filtered, this is our correct count of devices
let startLength = outputDevices.length; let startLength = outputDevices.length;
@ -189,11 +189,6 @@ export class HaConfigDeviceDashboard extends LitElement {
entryLookup[entry.entry_id] = entry; entryLookup[entry.entry_id] = entry;
} }
const areaLookup: { [areaId: string]: AreaRegistryEntry } = {};
for (const area of areas) {
areaLookup[area.area_id] = area;
}
const manifestLookup: { [domain: string]: IntegrationManifest } = {}; const manifestLookup: { [domain: string]: IntegrationManifest } = {};
for (const manifest of manifests) { for (const manifest of manifests) {
manifestLookup[manifest.domain] = manifest; manifestLookup[manifest.domain] = manifest;
@ -251,8 +246,8 @@ export class HaConfigDeviceDashboard extends LitElement {
device.manufacturer || device.manufacturer ||
`<${localize("ui.panel.config.devices.data_table.unknown")}>`, `<${localize("ui.panel.config.devices.data_table.unknown")}>`,
area: area:
device.area_id && areaLookup[device.area_id] device.area_id && areas[device.area_id]
? areaLookup[device.area_id].name ? areas[device.area_id].name
: "—", : "—",
integration: deviceEntries.length integration: deviceEntries.length
? deviceEntries ? deviceEntries
@ -438,10 +433,10 @@ export class HaConfigDeviceDashboard extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
const { devicesOutput } = this._devicesAndFilterDomains( const { devicesOutput } = this._devicesAndFilterDomains(
this.devices, this.hass.devices,
this.entries, this.entries,
this.entities, this.entities,
this.areas, this.hass.areas,
this.manifests, this.manifests,
this._searchParms, this._searchParms,
this._showDisabled, this._showDisabled,
@ -580,10 +575,10 @@ export class HaConfigDeviceDashboard extends LitElement {
private _addDevice() { private _addDevice() {
const { filteredConfigEntry, filteredDomains } = const { filteredConfigEntry, filteredDomains } =
this._devicesAndFilterDomains( this._devicesAndFilterDomains(
this.devices, this.hass.devices,
this.entries, this.entries,
this.entities, this.entities,
this.areas, this.hass.areas,
this.manifests, this.manifests,
this._searchParms, this._searchParms,
this._showDisabled, this._showDisabled,

View File

@ -1,19 +1,5 @@
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import {
AreaRegistryEntry,
subscribeAreaRegistry,
} from "../../../data/area_registry";
import { ConfigEntry, getConfigEntries } from "../../../data/config_entries"; import { ConfigEntry, getConfigEntries } from "../../../data/config_entries";
import {
DeviceRegistryEntry,
subscribeDeviceRegistry,
} from "../../../data/device_registry";
import {
EntityRegistryEntry,
subscribeEntityRegistry,
} from "../../../data/entity_registry";
import { import {
IntegrationManifest, IntegrationManifest,
fetchIntegrationManifests, fetchIntegrationManifests,
@ -53,47 +39,9 @@ class HaConfigDevices extends HassRouterPage {
@state() private _manifests: IntegrationManifest[] = []; @state() private _manifests: IntegrationManifest[] = [];
@state()
private _entityRegistryEntries: EntityRegistryEntry[] = [];
@state()
private _deviceRegistryEntries: DeviceRegistryEntry[] = [];
@state() private _areas: AreaRegistryEntry[] = [];
private _unsubs?: UnsubscribeFunc[];
public connectedCallback() {
super.connectedCallback();
if (!this.hass) {
return;
}
this._loadData();
}
public disconnectedCallback() {
super.disconnectedCallback();
if (this._unsubs) {
while (this._unsubs.length) {
this._unsubs.pop()!();
}
this._unsubs = undefined;
}
}
protected firstUpdated(changedProps) { protected firstUpdated(changedProps) {
super.firstUpdated(changedProps); super.firstUpdated(changedProps);
this.addEventListener("hass-reload-entries", () => { this._loadData();
this._loadData();
});
}
protected updated(changedProps: PropertyValues) {
super.updated(changedProps);
if (!this._unsubs && changedProps.has("hass")) {
this._loadData();
}
} }
protected updatePageEl(pageEl) { protected updatePageEl(pageEl) {
@ -103,39 +51,17 @@ class HaConfigDevices extends HassRouterPage {
pageEl.deviceId = this.routeTail.path.substr(1); pageEl.deviceId = this.routeTail.path.substr(1);
} }
pageEl.entities = this._entityRegistryEntries;
pageEl.entries = this._configEntries; pageEl.entries = this._configEntries;
pageEl.manifests = this._manifests; pageEl.manifests = this._manifests;
pageEl.devices = this._deviceRegistryEntries;
pageEl.areas = this._areas;
pageEl.narrow = this.narrow; pageEl.narrow = this.narrow;
pageEl.isWide = this.isWide; pageEl.isWide = this.isWide;
pageEl.showAdvanced = this.showAdvanced; pageEl.showAdvanced = this.showAdvanced;
pageEl.route = this.routeTail; pageEl.route = this.routeTail;
} }
private _loadData() { private async _loadData() {
getConfigEntries(this.hass).then((configEntries) => { this._configEntries = await getConfigEntries(this.hass);
this._configEntries = configEntries; this._manifests = await fetchIntegrationManifests(this.hass);
});
fetchIntegrationManifests(this.hass).then((manifests) => {
this._manifests = manifests;
});
if (this._unsubs) {
return;
}
this._unsubs = [
subscribeAreaRegistry(this.hass.connection, (areas) => {
this._areas = areas;
}),
subscribeEntityRegistry(this.hass.connection, (entries) => {
this._entityRegistryEntries = entries;
}),
subscribeDeviceRegistry(this.hass.connection, (entries) => {
this._deviceRegistryEntries = entries;
}),
];
} }
} }