mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-18 23:06:40 +00:00
Use areas when generating Lovelace config (#3175)
* Use areas when generating Lovelace config * Add missing return type
This commit is contained in:
parent
89a35a0062
commit
32e68c1a4b
@ -75,7 +75,7 @@
|
||||
"es6-object-assign": "^1.1.0",
|
||||
"fecha": "^3.0.2",
|
||||
"hls.js": "^0.12.4",
|
||||
"home-assistant-js-websocket": "^4.1.1",
|
||||
"home-assistant-js-websocket": "^4.1.2",
|
||||
"intl-messageformat": "^2.2.0",
|
||||
"jquery": "^3.3.1",
|
||||
"js-yaml": "^3.13.0",
|
||||
|
16
src/common/util/subscribe-one.ts
Normal file
16
src/common/util/subscribe-one.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
|
||||
export const subscribeOne = async <T>(
|
||||
hass: HomeAssistant,
|
||||
subscribe: (
|
||||
hass: HomeAssistant,
|
||||
onChange: (items: T) => void
|
||||
) => UnsubscribeFunc
|
||||
) =>
|
||||
new Promise<T>((resolve) => {
|
||||
const unsub = subscribe(hass, (items) => {
|
||||
unsub();
|
||||
resolve(items);
|
||||
});
|
||||
});
|
@ -17,6 +17,19 @@ import computeDomain from "../../../common/entity/compute_domain";
|
||||
import { EntityRowConfig, WeblinkConfig } from "../entity-rows/types";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import { EntitiesCardConfig } from "../cards/types";
|
||||
import {
|
||||
subscribeAreaRegistry,
|
||||
AreaRegistryEntry,
|
||||
} from "../../../data/area_registry";
|
||||
import { subscribeOne } from "../../../common/util/subscribe-one";
|
||||
import {
|
||||
subscribeDeviceRegistry,
|
||||
DeviceRegistryEntry,
|
||||
} from "../../../data/device_registry";
|
||||
import {
|
||||
subscribeEntityRegistry,
|
||||
EntityRegistryEntry,
|
||||
} from "../../../data/entity_registry";
|
||||
|
||||
const DEFAULT_VIEW_ENTITY_ID = "group.default_view";
|
||||
const DOMAINS_BADGES = [
|
||||
@ -34,6 +47,55 @@ const HIDE_DOMAIN = new Set([
|
||||
"geo_location",
|
||||
]);
|
||||
|
||||
interface Registries {
|
||||
areas: AreaRegistryEntry[];
|
||||
devices: DeviceRegistryEntry[];
|
||||
entities: EntityRegistryEntry[];
|
||||
}
|
||||
|
||||
let subscribedRegistries = false;
|
||||
|
||||
interface SplittedByAreas {
|
||||
areasWithEntities: Array<[AreaRegistryEntry, HassEntity[]]>;
|
||||
otherEntities: HassEntities;
|
||||
}
|
||||
|
||||
const splitByAreas = (
|
||||
registries: Registries,
|
||||
entities: HassEntities
|
||||
): SplittedByAreas => {
|
||||
const allEntities = { ...entities };
|
||||
const areasWithEntities: SplittedByAreas["areasWithEntities"] = [];
|
||||
|
||||
for (const area of registries.areas) {
|
||||
const areaEntities: HassEntity[] = [];
|
||||
const areaDevices = new Set(
|
||||
registries.devices
|
||||
.filter((device) => device.area_id === area.area_id)
|
||||
.map((device) => device.id)
|
||||
);
|
||||
for (const entity of registries.entities) {
|
||||
if (
|
||||
areaDevices.has(
|
||||
// @ts-ignore
|
||||
entity.device_id
|
||||
) &&
|
||||
entity.entity_id in allEntities
|
||||
) {
|
||||
areaEntities.push(allEntities[entity.entity_id]);
|
||||
delete allEntities[entity.entity_id];
|
||||
}
|
||||
}
|
||||
if (areaEntities.length > 0) {
|
||||
areasWithEntities.push([area, areaEntities]);
|
||||
}
|
||||
}
|
||||
return {
|
||||
areasWithEntities,
|
||||
otherEntities: allEntities,
|
||||
};
|
||||
};
|
||||
|
||||
const computeCards = (
|
||||
states: Array<[string, HassEntity]>,
|
||||
entityCardOptions: Partial<EntitiesCardConfig>
|
||||
@ -124,6 +186,51 @@ const computeDefaultViewStates = (hass: HomeAssistant): HassEntities => {
|
||||
return states;
|
||||
};
|
||||
|
||||
const generateDefaultViewConfig = (
|
||||
hass: HomeAssistant,
|
||||
registries: Registries
|
||||
): LovelaceViewConfig => {
|
||||
const states = computeDefaultViewStates(hass);
|
||||
const path = "default_view";
|
||||
const title = "Home";
|
||||
const icon = undefined;
|
||||
|
||||
// In the case of a default view, we want to use the group order attribute
|
||||
const groupOrders = {};
|
||||
Object.keys(states).forEach((entityId) => {
|
||||
const stateObj = states[entityId];
|
||||
if (stateObj.attributes.order) {
|
||||
groupOrders[entityId] = stateObj.attributes.order;
|
||||
}
|
||||
});
|
||||
|
||||
const splittedByAreas = splitByAreas(registries, states);
|
||||
|
||||
const config = generateViewConfig(
|
||||
hass.localize,
|
||||
path,
|
||||
title,
|
||||
icon,
|
||||
splittedByAreas.otherEntities,
|
||||
groupOrders
|
||||
);
|
||||
|
||||
const areaCards: LovelaceCardConfig[] = [];
|
||||
|
||||
splittedByAreas.areasWithEntities.forEach(([area, entities]) => {
|
||||
areaCards.push(
|
||||
...computeCards(entities.map((entity) => [entity.entity_id, entity]), {
|
||||
title: area.name,
|
||||
show_header_toggle: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
config.cards!.unshift(...areaCards);
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
const generateViewConfig = (
|
||||
localize: LocalizeFunc,
|
||||
path: string,
|
||||
@ -208,10 +315,10 @@ const generateViewConfig = (
|
||||
return view;
|
||||
};
|
||||
|
||||
export const generateLovelaceConfig = (
|
||||
export const generateLovelaceConfig = async (
|
||||
hass: HomeAssistant,
|
||||
localize: LocalizeFunc
|
||||
): LovelaceConfig => {
|
||||
): Promise<LovelaceConfig> => {
|
||||
const viewEntities = extractViews(hass.states);
|
||||
|
||||
const views = viewEntities.map((viewEntity: GroupEntity) => {
|
||||
@ -241,27 +348,23 @@ export const generateLovelaceConfig = (
|
||||
viewEntities.length === 0 ||
|
||||
viewEntities[0].entity_id !== DEFAULT_VIEW_ENTITY_ID
|
||||
) {
|
||||
const states = computeDefaultViewStates(hass);
|
||||
|
||||
// In the case of a default view, we want to use the group order attribute
|
||||
const groupOrders = {};
|
||||
Object.keys(states).forEach((entityId) => {
|
||||
const stateObj = states[entityId];
|
||||
if (stateObj.attributes.order) {
|
||||
groupOrders[entityId] = stateObj.attributes.order;
|
||||
// We want to keep the registry subscriptions alive after generating the UI
|
||||
// so that we don't serve up stale data after changing areas.
|
||||
if (!subscribedRegistries) {
|
||||
subscribedRegistries = true;
|
||||
subscribeAreaRegistry(hass, () => undefined);
|
||||
subscribeDeviceRegistry(hass, () => undefined);
|
||||
subscribeEntityRegistry(hass, () => undefined);
|
||||
}
|
||||
});
|
||||
|
||||
views.unshift(
|
||||
generateViewConfig(
|
||||
localize,
|
||||
"default_view",
|
||||
"Home",
|
||||
undefined,
|
||||
states,
|
||||
groupOrders
|
||||
)
|
||||
);
|
||||
const [areas, devices, entities] = await Promise.all([
|
||||
subscribeOne(hass, subscribeAreaRegistry),
|
||||
subscribeOne(hass, subscribeDeviceRegistry),
|
||||
subscribeOne(hass, subscribeEntityRegistry),
|
||||
]);
|
||||
const registries = { areas, devices, entities };
|
||||
|
||||
views.unshift(generateDefaultViewConfig(hass, registries));
|
||||
|
||||
// Add map of geo locations to default view if loaded
|
||||
if (hass.config.components.includes("geo_location")) {
|
||||
|
@ -171,7 +171,7 @@ class LovelacePanel extends LitElement {
|
||||
this._errorMsg = err.message;
|
||||
return;
|
||||
}
|
||||
conf = generateLovelaceConfig(this.hass!, this.hass!.localize);
|
||||
conf = await generateLovelaceConfig(this.hass!, this.hass!.localize);
|
||||
confMode = "generated";
|
||||
}
|
||||
|
||||
|
@ -7237,10 +7237,10 @@ hoek@6.x.x:
|
||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-6.1.3.tgz#73b7d33952e01fe27a38b0457294b79dd8da242c"
|
||||
integrity sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==
|
||||
|
||||
home-assistant-js-websocket@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/home-assistant-js-websocket/-/home-assistant-js-websocket-4.1.1.tgz#b85152c223a20bfe8827b817b927fd97cc021157"
|
||||
integrity sha512-hNk8bj9JObd3NpgQ1+KtQCbSoz/TWockC8T/L8KvsPrDtkl1oQddajirumaMDgrJg/su4QsxFNUcDPGJyJ05UA==
|
||||
home-assistant-js-websocket@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/home-assistant-js-websocket/-/home-assistant-js-websocket-4.1.2.tgz#dbcdb4b67df8d189d29bbf5603771d5bc80ef031"
|
||||
integrity sha512-/I0m6FTDEq3LkzFc4tmgHJHTj9gWA6Wn/fgaa1ghIJJY0Yqb3x6whovN5pRNFsl6bnKzOCR+nmJ2ruVTBa5mVQ==
|
||||
|
||||
homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
|
||||
version "1.0.3"
|
||||
|
Loading…
x
Reference in New Issue
Block a user