mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-01 13:37:47 +00:00
Lovelace tweaks (#3439)
This commit is contained in:
parent
4edcd5f2ef
commit
b158f15d93
@ -29,7 +29,9 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard {
|
||||
@property() private _config?: MarkdownCardConfig;
|
||||
|
||||
public getCardSize(): number {
|
||||
return this._config!.content.split("\n").length;
|
||||
return (
|
||||
this._config!.content.split("\n").length + (this._config!.title ? 1 : 0)
|
||||
);
|
||||
}
|
||||
|
||||
public setConfig(config: MarkdownCardConfig): void {
|
||||
|
@ -4,7 +4,11 @@ import {
|
||||
LovelaceCardConfig,
|
||||
LovelaceViewConfig,
|
||||
} from "../../../data/lovelace";
|
||||
import { HassEntity, HassEntities } from "home-assistant-js-websocket";
|
||||
import {
|
||||
HassEntity,
|
||||
HassEntities,
|
||||
HassConfig,
|
||||
} from "home-assistant-js-websocket";
|
||||
|
||||
import extractViews from "../../../common/entity/extract_views";
|
||||
import getViewEntities from "../../../common/entity/get_view_entities";
|
||||
@ -47,12 +51,6 @@ const HIDE_DOMAIN = new Set([
|
||||
"geo_location",
|
||||
]);
|
||||
|
||||
interface Registries {
|
||||
areas: AreaRegistryEntry[];
|
||||
devices: DeviceRegistryEntry[];
|
||||
entities: EntityRegistryEntry[];
|
||||
}
|
||||
|
||||
let subscribedRegistries = false;
|
||||
|
||||
interface SplittedByAreas {
|
||||
@ -61,20 +59,22 @@ interface SplittedByAreas {
|
||||
}
|
||||
|
||||
const splitByAreas = (
|
||||
registries: Registries,
|
||||
areaEntries: AreaRegistryEntry[],
|
||||
deviceEntries: DeviceRegistryEntry[],
|
||||
entityEntries: EntityRegistryEntry[],
|
||||
entities: HassEntities
|
||||
): SplittedByAreas => {
|
||||
const allEntities = { ...entities };
|
||||
const areasWithEntities: SplittedByAreas["areasWithEntities"] = [];
|
||||
|
||||
for (const area of registries.areas) {
|
||||
for (const area of areaEntries) {
|
||||
const areaEntities: HassEntity[] = [];
|
||||
const areaDevices = new Set(
|
||||
registries.devices
|
||||
deviceEntries
|
||||
.filter((device) => device.area_id === area.area_id)
|
||||
.map((device) => device.id)
|
||||
);
|
||||
for (const entity of registries.entities) {
|
||||
for (const entity of entityEntries) {
|
||||
if (
|
||||
areaDevices.has(
|
||||
// @ts-ignore
|
||||
@ -172,25 +172,28 @@ const computeCards = (
|
||||
return cards;
|
||||
};
|
||||
|
||||
const computeDefaultViewStates = (hass: HomeAssistant): HassEntities => {
|
||||
const computeDefaultViewStates = (entities: HassEntities): HassEntities => {
|
||||
const states = {};
|
||||
Object.keys(hass.states).forEach((entityId) => {
|
||||
const stateObj = hass.states[entityId];
|
||||
Object.keys(entities).forEach((entityId) => {
|
||||
const stateObj = entities[entityId];
|
||||
if (
|
||||
!stateObj.attributes.hidden &&
|
||||
!HIDE_DOMAIN.has(computeStateDomain(stateObj))
|
||||
) {
|
||||
states[entityId] = hass.states[entityId];
|
||||
states[entityId] = entities[entityId];
|
||||
}
|
||||
});
|
||||
return states;
|
||||
};
|
||||
|
||||
const generateDefaultViewConfig = (
|
||||
hass: HomeAssistant,
|
||||
registries: Registries
|
||||
export const generateDefaultViewConfig = (
|
||||
areaEntries: AreaRegistryEntry[],
|
||||
deviceEntries: DeviceRegistryEntry[],
|
||||
entityEntries: EntityRegistryEntry[],
|
||||
entities: HassEntities,
|
||||
localize: LocalizeFunc
|
||||
): LovelaceViewConfig => {
|
||||
const states = computeDefaultViewStates(hass);
|
||||
const states = computeDefaultViewStates(entities);
|
||||
const path = "default_view";
|
||||
const title = "Home";
|
||||
const icon = undefined;
|
||||
@ -204,10 +207,15 @@ const generateDefaultViewConfig = (
|
||||
}
|
||||
});
|
||||
|
||||
const splittedByAreas = splitByAreas(registries, states);
|
||||
const splittedByAreas = splitByAreas(
|
||||
areaEntries,
|
||||
deviceEntries,
|
||||
entityEntries,
|
||||
states
|
||||
);
|
||||
|
||||
const config = generateViewConfig(
|
||||
hass.localize,
|
||||
localize,
|
||||
path,
|
||||
title,
|
||||
icon,
|
||||
@ -217,12 +225,15 @@ const generateDefaultViewConfig = (
|
||||
|
||||
const areaCards: LovelaceCardConfig[] = [];
|
||||
|
||||
splittedByAreas.areasWithEntities.forEach(([area, entities]) => {
|
||||
splittedByAreas.areasWithEntities.forEach(([area, areaEntities]) => {
|
||||
areaCards.push(
|
||||
...computeCards(entities.map((entity) => [entity.entity_id, entity]), {
|
||||
title: area.name,
|
||||
show_header_toggle: true,
|
||||
})
|
||||
...computeCards(
|
||||
areaEntities.map((entity) => [entity.entity_id, entity]),
|
||||
{
|
||||
title: area.name,
|
||||
show_header_toggle: true,
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
@ -315,14 +326,44 @@ const generateViewConfig = (
|
||||
return view;
|
||||
};
|
||||
|
||||
export const generateLovelaceConfig = async (
|
||||
hass: HomeAssistant,
|
||||
export const generateLovelaceConfigFromHass = async (hass: HomeAssistant) => {
|
||||
// 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.connection, () => undefined);
|
||||
subscribeDeviceRegistry(hass.connection, () => undefined);
|
||||
subscribeEntityRegistry(hass.connection, () => undefined);
|
||||
}
|
||||
|
||||
const [areaEntries, deviceEntries, entityEntries] = await Promise.all([
|
||||
subscribeOne(hass.connection, subscribeAreaRegistry),
|
||||
subscribeOne(hass.connection, subscribeDeviceRegistry),
|
||||
subscribeOne(hass.connection, subscribeEntityRegistry),
|
||||
]);
|
||||
|
||||
return generateLovelaceConfigFromData(
|
||||
hass.config,
|
||||
areaEntries,
|
||||
deviceEntries,
|
||||
entityEntries,
|
||||
hass.states,
|
||||
hass.localize
|
||||
);
|
||||
};
|
||||
|
||||
export const generateLovelaceConfigFromData = async (
|
||||
config: HassConfig,
|
||||
areaEntries: AreaRegistryEntry[],
|
||||
deviceEntries: DeviceRegistryEntry[],
|
||||
entityEntries: EntityRegistryEntry[],
|
||||
entities: HassEntities,
|
||||
localize: LocalizeFunc
|
||||
): Promise<LovelaceConfig> => {
|
||||
const viewEntities = extractViews(hass.states);
|
||||
const viewEntities = extractViews(entities);
|
||||
|
||||
const views = viewEntities.map((viewEntity: GroupEntity) => {
|
||||
const states = getViewEntities(hass.states, viewEntity);
|
||||
const states = getViewEntities(entities, viewEntity);
|
||||
|
||||
// In the case of a normal view, we use group order as specified in view
|
||||
const groupOrders = {};
|
||||
@ -340,7 +381,7 @@ export const generateLovelaceConfig = async (
|
||||
);
|
||||
});
|
||||
|
||||
let title = hass.config.location_name;
|
||||
let title = config.location_name;
|
||||
|
||||
// User can override default view. If they didn't, we will add one
|
||||
// that contains all entities.
|
||||
@ -348,26 +389,18 @@ export const generateLovelaceConfig = async (
|
||||
viewEntities.length === 0 ||
|
||||
viewEntities[0].entity_id !== DEFAULT_VIEW_ENTITY_ID
|
||||
) {
|
||||
// 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.connection, () => undefined);
|
||||
subscribeDeviceRegistry(hass.connection, () => undefined);
|
||||
subscribeEntityRegistry(hass.connection, () => undefined);
|
||||
}
|
||||
|
||||
const [areas, devices, entities] = await Promise.all([
|
||||
subscribeOne(hass.connection, subscribeAreaRegistry),
|
||||
subscribeOne(hass.connection, subscribeDeviceRegistry),
|
||||
subscribeOne(hass.connection, subscribeEntityRegistry),
|
||||
]);
|
||||
const registries = { areas, devices, entities };
|
||||
|
||||
views.unshift(generateDefaultViewConfig(hass, registries));
|
||||
views.unshift(
|
||||
generateDefaultViewConfig(
|
||||
areaEntries,
|
||||
deviceEntries,
|
||||
entityEntries,
|
||||
entities,
|
||||
localize
|
||||
)
|
||||
);
|
||||
|
||||
// Add map of geo locations to default view if loaded
|
||||
if (hass.config.components.includes("geo_location")) {
|
||||
if (config.components.includes("geo_location")) {
|
||||
if (views[0] && views[0].cards) {
|
||||
views[0].cards.push({
|
||||
type: "map",
|
||||
@ -382,12 +415,6 @@ export const generateLovelaceConfig = async (
|
||||
}
|
||||
}
|
||||
|
||||
if (__DEMO__) {
|
||||
views[0].cards!.unshift({
|
||||
type: "custom:ha-demo-card",
|
||||
});
|
||||
}
|
||||
|
||||
// User has no entities
|
||||
if (views.length === 1 && views[0].cards!.length === 0) {
|
||||
import(/* webpackChunkName: "hui-empty-state-card" */ "../cards/hui-empty-state-card");
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
property,
|
||||
} from "lit-element";
|
||||
import { showSaveDialog } from "./editor/show-save-config-dialog";
|
||||
import { generateLovelaceConfig } from "./common/generate-lovelace-config";
|
||||
import { generateLovelaceConfigFromHass } from "./common/generate-lovelace-config";
|
||||
import { showToast } from "../../util/toast";
|
||||
|
||||
interface LovelacePanelConfig {
|
||||
@ -162,7 +162,7 @@ class LovelacePanel extends LitElement {
|
||||
}
|
||||
|
||||
private async _regenerateConfig() {
|
||||
const conf = await generateLovelaceConfig(this.hass!, this.hass!.localize);
|
||||
const conf = await generateLovelaceConfigFromHass(this.hass!);
|
||||
this._setLovelaceConfig(conf, "generated");
|
||||
this._state = "loaded";
|
||||
}
|
||||
@ -241,7 +241,7 @@ class LovelacePanel extends LitElement {
|
||||
this._errorMsg = err.message;
|
||||
return;
|
||||
}
|
||||
conf = await generateLovelaceConfig(this.hass!, this.hass!.localize);
|
||||
conf = await generateLovelaceConfigFromHass(this.hass!);
|
||||
confMode = "generated";
|
||||
}
|
||||
|
||||
|
@ -352,6 +352,7 @@ class HUIRoot extends LitElement {
|
||||
}
|
||||
#view > * {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
paper-item {
|
||||
cursor: pointer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user