Fixes to device page (#3756)
* Fixes to device page * Cache page with data page
This commit is contained in:
parent
b6fbf4da3a
commit
c898db5010
@ -35,6 +35,8 @@ import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||
import { ConfigEntry } from "../../../data/config_entries";
|
||||
import { AreaRegistryEntry } from "../../../data/area_registry";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
|
||||
interface DeviceRowData extends DeviceRegistryEntry {
|
||||
device?: DeviceRowData;
|
||||
@ -43,6 +45,10 @@ interface DeviceRowData extends DeviceRegistryEntry {
|
||||
battery_entity?: string;
|
||||
}
|
||||
|
||||
interface DeviceEntityLookup {
|
||||
[deviceId: string]: EntityRegistryEntry[];
|
||||
}
|
||||
|
||||
@customElement("ha-config-devices-dashboard")
|
||||
export class HaConfigDeviceDashboard extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@ -59,37 +65,73 @@ export class HaConfigDeviceDashboard extends LitElement {
|
||||
entries: ConfigEntry[],
|
||||
entities: EntityRegistryEntry[],
|
||||
areas: AreaRegistryEntry[],
|
||||
domain: string
|
||||
domain: string,
|
||||
localize: LocalizeFunc
|
||||
) => {
|
||||
// Some older installations might have devices pointing at invalid entryIDs
|
||||
// So we guard for that.
|
||||
|
||||
let outputDevices: DeviceRowData[] = devices;
|
||||
|
||||
const deviceLookup: { [deviceId: string]: DeviceRegistryEntry } = {};
|
||||
for (const device of devices) {
|
||||
deviceLookup[device.id] = device;
|
||||
}
|
||||
|
||||
const deviceEntityLookup: DeviceEntityLookup = {};
|
||||
for (const entity of entities) {
|
||||
if (!entity.device_id) {
|
||||
continue;
|
||||
}
|
||||
if (!(entity.device_id in deviceEntityLookup)) {
|
||||
deviceEntityLookup[entity.device_id] = [];
|
||||
}
|
||||
deviceEntityLookup[entity.device_id].push(entity);
|
||||
}
|
||||
|
||||
const entryLookup: { [entryId: string]: ConfigEntry } = {};
|
||||
for (const entry of entries) {
|
||||
entryLookup[entry.entry_id] = entry;
|
||||
}
|
||||
|
||||
const areaLookup: { [areaId: string]: AreaRegistryEntry } = {};
|
||||
for (const area of areas) {
|
||||
areaLookup[area.area_id] = area;
|
||||
}
|
||||
|
||||
if (domain) {
|
||||
outputDevices = outputDevices.filter(
|
||||
(device) =>
|
||||
entries.find((entry) =>
|
||||
device.config_entries.includes(entry.entry_id)
|
||||
)!.domain === domain
|
||||
outputDevices = outputDevices.filter((device) =>
|
||||
device.config_entries.find(
|
||||
(entryId) =>
|
||||
entryId in entryLookup && entryLookup[entryId].domain === domain
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
outputDevices = outputDevices.map((device) => {
|
||||
const output = { ...device };
|
||||
output.name = device.name_by_user || device.name || "No name";
|
||||
|
||||
output.area =
|
||||
!areas || !device || !device.area_id
|
||||
? "No area"
|
||||
: areas.find((area) => area.area_id === device.area_id)!.name;
|
||||
|
||||
output.integration =
|
||||
!entries || !device || !device.config_entries
|
||||
? "No integration"
|
||||
: entries.find((entry) =>
|
||||
device.config_entries.includes(entry.entry_id)
|
||||
)!.domain;
|
||||
|
||||
output.battery_entity = this._batteryEntity(device, entities);
|
||||
|
||||
return output;
|
||||
return {
|
||||
...device,
|
||||
name:
|
||||
device.name_by_user ||
|
||||
device.name ||
|
||||
this._fallbackDeviceName(device.id, deviceEntityLookup) ||
|
||||
"No name",
|
||||
model: device.model || "<unknown>",
|
||||
manufacturer: device.manufacturer || "<unknown>",
|
||||
area: device.area_id ? areaLookup[device.area_id].name : "No area",
|
||||
integration: device.config_entries.length
|
||||
? device.config_entries
|
||||
.filter((entId) => entId in entryLookup)
|
||||
.map(
|
||||
(entId) =>
|
||||
localize(
|
||||
`component.${entryLookup[entId].domain}.config.title`
|
||||
) || entryLookup[entId].domain
|
||||
)
|
||||
.join(", ")
|
||||
: "No integration",
|
||||
battery_entity: this._batteryEntity(device.id, deviceEntityLookup),
|
||||
};
|
||||
});
|
||||
|
||||
return outputDevices;
|
||||
@ -171,7 +213,7 @@ export class HaConfigDeviceDashboard extends LitElement {
|
||||
></ha-state-icon>
|
||||
`
|
||||
: html`
|
||||
n/a
|
||||
-
|
||||
`;
|
||||
},
|
||||
},
|
||||
@ -190,7 +232,8 @@ export class HaConfigDeviceDashboard extends LitElement {
|
||||
this.entries,
|
||||
this.entities,
|
||||
this.areas,
|
||||
this.domain
|
||||
this.domain,
|
||||
this.hass.localize
|
||||
).map((device: DeviceRowData) => {
|
||||
// We don't need a lot of this data for mobile view, but kept it for filtering...
|
||||
const data: DataTabelRowData = {
|
||||
@ -214,10 +257,12 @@ export class HaConfigDeviceDashboard extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _batteryEntity(device, entities): string | undefined {
|
||||
const batteryEntity = entities.find(
|
||||
private _batteryEntity(
|
||||
deviceId: string,
|
||||
deviceEntityLookup: DeviceEntityLookup
|
||||
): string | undefined {
|
||||
const batteryEntity = (deviceEntityLookup[deviceId] || []).find(
|
||||
(entity) =>
|
||||
entity.device_id === device.id &&
|
||||
this.hass.states[entity.entity_id] &&
|
||||
this.hass.states[entity.entity_id].attributes.device_class === "battery"
|
||||
);
|
||||
@ -225,6 +270,20 @@ export class HaConfigDeviceDashboard extends LitElement {
|
||||
return batteryEntity ? batteryEntity.entity_id : undefined;
|
||||
}
|
||||
|
||||
private _fallbackDeviceName(
|
||||
deviceId: string,
|
||||
deviceEntityLookup: DeviceEntityLookup
|
||||
): string | undefined {
|
||||
for (const entity of deviceEntityLookup[deviceId] || []) {
|
||||
const stateObj = this.hass.states[entity.entity_id];
|
||||
if (stateObj) {
|
||||
return computeStateName(stateObj);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _handleRowClicked(ev: CustomEvent) {
|
||||
const deviceId = (ev.detail as RowClickedEvent).id;
|
||||
navigate(this, `/config/devices/device/${deviceId}`);
|
||||
|
||||
@ -34,6 +34,7 @@ class HaConfigDevices extends HassRouterPage {
|
||||
routes: {
|
||||
dashboard: {
|
||||
tag: "ha-config-devices-dashboard",
|
||||
cache: true,
|
||||
},
|
||||
device: {
|
||||
tag: "ha-config-device-page",
|
||||
@ -41,10 +42,10 @@ class HaConfigDevices extends HassRouterPage {
|
||||
},
|
||||
};
|
||||
|
||||
@property() private _configEntries?: ConfigEntry[];
|
||||
@property() private _entityRegistryEntries?: EntityRegistryEntry[];
|
||||
@property() private _deviceRegistryEntries?: DeviceRegistryEntry[];
|
||||
@property() private _areas?: AreaRegistryEntry[];
|
||||
@property() private _configEntries: ConfigEntry[] = [];
|
||||
@property() private _entityRegistryEntries: EntityRegistryEntry[] = [];
|
||||
@property() private _deviceRegistryEntries: DeviceRegistryEntry[] = [];
|
||||
@property() private _areas: AreaRegistryEntry[] = [];
|
||||
|
||||
private _unsubs?: UnsubscribeFunc[];
|
||||
|
||||
|
||||
@ -37,25 +37,24 @@ import { HomeAssistant } from "../../../types";
|
||||
import { ConfigEntry } from "../../../data/config_entries";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||
import { DataEntryFlowProgress } from "../../../data/data_entry_flow";
|
||||
|
||||
@customElement("ha-config-entries-dashboard")
|
||||
export class HaConfigManagerDashboard extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property() public isWide = false;
|
||||
|
||||
@property() private entries = [];
|
||||
@property() private configEntries!: ConfigEntry[];
|
||||
|
||||
/**
|
||||
* Entity Registry entries.
|
||||
*/
|
||||
@property() private entities: EntityRegistryEntry[] = [];
|
||||
@property() private entityRegistryEntries!: EntityRegistryEntry[];
|
||||
|
||||
/**
|
||||
* Current flows that are in progress and have not been started by a user.
|
||||
* For example, can be discovered devices that require more config.
|
||||
*/
|
||||
@property() private progress = [];
|
||||
@property() private configEntriesInProgress!: DataEntryFlowProgress[];
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
@ -67,7 +66,7 @@ export class HaConfigManagerDashboard extends LitElement {
|
||||
<hass-subpage
|
||||
header=${this.hass.localize("ui.panel.config.integrations.caption")}
|
||||
>
|
||||
${this.progress.length
|
||||
${this.configEntriesInProgress.length
|
||||
? html`
|
||||
<ha-config-section>
|
||||
<span slot="header"
|
||||
@ -76,7 +75,7 @@ export class HaConfigManagerDashboard extends LitElement {
|
||||
)}</span
|
||||
>
|
||||
<ha-card>
|
||||
${this.progress.map(
|
||||
${this.configEntriesInProgress.map(
|
||||
(flow) => html`
|
||||
<div class="config-entry-row">
|
||||
<paper-item-body>
|
||||
@ -102,8 +101,8 @@ export class HaConfigManagerDashboard extends LitElement {
|
||||
)}</span
|
||||
>
|
||||
<ha-card>
|
||||
${this.entities.length
|
||||
? this.entries.map(
|
||||
${this.entityRegistryEntries.length
|
||||
? this.configEntries.map(
|
||||
(item: any, idx) => html`
|
||||
<a
|
||||
href="/config/integrations/config_entry/${item.entry_id}"
|
||||
@ -155,7 +154,6 @@ export class HaConfigManagerDashboard extends LitElement {
|
||||
title=${this.hass.localize("ui.panel.config.integrations.new")}
|
||||
@click=${this._createFlow}
|
||||
?rtl=${computeRTL(this.hass!)}
|
||||
?isWide=${this.isWide}
|
||||
></ha-fab>
|
||||
</hass-subpage>
|
||||
`;
|
||||
@ -175,11 +173,11 @@ export class HaConfigManagerDashboard extends LitElement {
|
||||
}
|
||||
|
||||
private _getEntities(configEntry: ConfigEntry): HassEntity[] {
|
||||
if (!this.entities) {
|
||||
if (!this.entityRegistryEntries) {
|
||||
return [];
|
||||
}
|
||||
const states: HassEntity[] = [];
|
||||
this.entities.forEach((entity) => {
|
||||
this.entityRegistryEntries.forEach((entity) => {
|
||||
if (
|
||||
entity.config_entry_id === configEntry.entry_id &&
|
||||
entity.entity_id in this.hass.states
|
||||
@ -217,21 +215,10 @@ export class HaConfigManagerDashboard extends LitElement {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
ha-fab[is-wide] {
|
||||
bottom: 24px;
|
||||
right: 24px;
|
||||
}
|
||||
|
||||
ha-fab[rtl] {
|
||||
right: auto;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
ha-fab[rtl][is-wide] {
|
||||
bottom: 24px;
|
||||
right: auto;
|
||||
left: 24px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import "@polymer/app-route/app-route";
|
||||
import { property, customElement, PropertyValues } from "lit-element";
|
||||
|
||||
import "./ha-config-entries-dashboard";
|
||||
import "./config-entry/ha-config-entry-page";
|
||||
@ -11,7 +12,6 @@ import {
|
||||
HassRouterPage,
|
||||
RouterOptions,
|
||||
} from "../../../layouts/hass-router-page";
|
||||
import { property, customElement, PropertyValues } from "lit-element";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ConfigEntry, getConfigEntries } from "../../../data/config_entries";
|
||||
import {
|
||||
@ -42,7 +42,6 @@ class HaConfigIntegrations extends HassRouterPage {
|
||||
|
||||
protected routerOptions: RouterOptions = {
|
||||
defaultPage: "dashboard",
|
||||
preloadAll: true,
|
||||
routes: {
|
||||
dashboard: {
|
||||
tag: "ha-config-entries-dashboard",
|
||||
@ -53,11 +52,11 @@ class HaConfigIntegrations extends HassRouterPage {
|
||||
},
|
||||
};
|
||||
|
||||
@property() private _configEntries?: ConfigEntry[];
|
||||
@property() private _configEntriesInProgress?: DataEntryFlowProgress[];
|
||||
@property() private _entityRegistryEntries?: EntityRegistryEntry[];
|
||||
@property() private _deviceRegistryEntries?: DeviceRegistryEntry[];
|
||||
@property() private _areas?: AreaRegistryEntry[];
|
||||
@property() private _configEntries: ConfigEntry[] = [];
|
||||
@property() private _configEntriesInProgress: DataEntryFlowProgress[] = [];
|
||||
@property() private _entityRegistryEntries: EntityRegistryEntry[] = [];
|
||||
@property() private _deviceRegistryEntries: DeviceRegistryEntry[] = [];
|
||||
@property() private _areas: AreaRegistryEntry[] = [];
|
||||
|
||||
private _unsubs?: UnsubscribeFunc[];
|
||||
|
||||
@ -98,15 +97,14 @@ class HaConfigIntegrations extends HassRouterPage {
|
||||
protected updatePageEl(pageEl) {
|
||||
pageEl.hass = this.hass;
|
||||
|
||||
pageEl.entityRegistryEntries = this._entityRegistryEntries;
|
||||
pageEl.configEntries = this._configEntries;
|
||||
|
||||
if (this._currentPage === "dashboard") {
|
||||
pageEl.entities = this._entityRegistryEntries;
|
||||
pageEl.entries = this._configEntries;
|
||||
pageEl.progress = this._configEntriesInProgress;
|
||||
pageEl.configEntriesInProgress = this._configEntriesInProgress;
|
||||
return;
|
||||
}
|
||||
|
||||
pageEl.entityRegistryEntries = this._entityRegistryEntries;
|
||||
pageEl.configEntries = this._configEntries;
|
||||
pageEl.configEntryId = this.routeTail.path.substr(1);
|
||||
pageEl.deviceRegistryEntries = this._deviceRegistryEntries;
|
||||
pageEl.areas = this._areas;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user