From f5df91d4c7967396e1f6f395f36c6b7eb3f01af3 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Thu, 26 Jun 2025 12:18:34 +0200 Subject: [PATCH] Better handle case when no floors in areas dashboard (#25933) --- .../ha-areas-floors-display-editor.ts | 55 +++++++++++-------- .../areas/areas-overview-view-strategy.ts | 29 ++++++---- src/translations/en.json | 3 +- 3 files changed, 51 insertions(+), 36 deletions(-) diff --git a/src/components/ha-areas-floors-display-editor.ts b/src/components/ha-areas-floors-display-editor.ts index 414e2550c7..03ecec9ac2 100644 --- a/src/components/ha-areas-floors-display-editor.ts +++ b/src/components/ha-areas-floors-display-editor.ts @@ -1,6 +1,6 @@ import { mdiTextureBox } from "@mdi/js"; import type { TemplateResult } from "lit"; -import { LitElement, css, html } from "lit"; +import { LitElement, css, html, nothing } from "lit"; import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; @@ -64,26 +64,30 @@ export class HaAreasFloorsDisplayEditor extends LitElement { .expanded=${this.expanded} > - ${filteredFloors.map( - (floor) => html` + ${filteredFloors.map((floor, _, array) => { + const noFloors = + array.length === 1 && floor.floor_id === UNASSIGNED_FLOOR; + return html`
-
- -

${computeFloorName(floor)}

-
+ ${noFloors + ? nothing + : html`
+ +

${computeFloorName(floor)}

+
`}
- ` - )} + `; + })} `; } @@ -134,10 +138,10 @@ export class HaAreasFloorsDisplayEditor extends LitElement { floors.push({ floor_id: UNASSIGNED_FLOOR, name: this.hass.localize( - "ui.panel.lovelace.strategy.areas.unassigned_areas" + "ui.panel.lovelace.strategy.areas.others_areas" ), icon: null, - level: 999999, + level: null, aliases: [], created_at: 0, modified_at: 0, @@ -155,25 +159,30 @@ export class HaAreasFloorsDisplayEditor extends LitElement { (floor) => floor.floor_id ); + const oldHidden = this.value?.hidden ?? []; + const oldOrder = this.value?.order ?? []; + const newHidden: string[] = []; const newOrder: string[] = []; for (const floorId of floorIds) { - if (currentFloorId === floorId) { + if ((currentFloorId ?? UNASSIGNED_FLOOR) === floorId) { newHidden.push(...(value.hidden ?? [])); newOrder.push(...(value.order ?? [])); continue; } - const hidden = this.value?.hidden?.filter( - (areaId) => this.hass.areas[areaId]?.floor_id === floorId - ); - if (hidden) { + const hidden = oldHidden.filter((areaId) => { + const id = this.hass.areas[areaId]?.floor_id ?? UNASSIGNED_FLOOR; + return id === floorId; + }); + if (hidden?.length) { newHidden.push(...hidden); } - const order = this.value?.order?.filter( - (areaId) => this.hass.areas[areaId]?.floor_id === floorId - ); - if (order) { + const order = oldOrder.filter((areaId) => { + const id = this.hass.areas[areaId]?.floor_id ?? UNASSIGNED_FLOOR; + return id === floorId; + }); + if (order?.length) { newOrder.push(...order); } } @@ -188,7 +197,7 @@ export class HaAreasFloorsDisplayEditor extends LitElement { if (newValue.order?.length === 0) { delete newValue.order; } - + this.value = newValue; fireEvent(this, "value-changed", { value: newValue }); } @@ -199,7 +208,7 @@ export class HaAreasFloorsDisplayEditor extends LitElement { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; - flex: 1: + flex: 1; } .floor .header { margin: 16px 0 8px 0; diff --git a/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts b/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts index 99feb34b5a..0d0e43e8c9 100644 --- a/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts +++ b/src/panels/lovelace/strategies/areas/areas-overview-view-strategy.ts @@ -32,7 +32,7 @@ export class AreasOverviewViewStrategy extends ReactiveElement { config: AreasViewStrategyConfig, hass: HomeAssistant ): Promise { - const areas = getAreas( + const displayedAreas = getAreas( hass.areas, config.areas_display?.hidden, config.areas_display?.order @@ -50,25 +50,23 @@ export class AreasOverviewViewStrategy extends ReactiveElement { ...floors, { floor_id: UNASSIGNED_FLOOR, - name: hass.localize( - "ui.panel.lovelace.strategy.areas.unassigned_areas" - ), + name: hass.localize("ui.panel.lovelace.strategy.areas.others_areas"), level: null, icon: null, }, ] - .map((floor) => { - const areasInFloors = areas.filter( + .map((floor) => { + const areasInFloors = displayedAreas.filter( (area) => area.floor_id === floor.floor_id || (!area.floor_id && floor.floor_id === UNASSIGNED_FLOOR) ); - if (areasInFloors.length === 0) { - return undefined; - } - - const areasCards = areasInFloors.map((area) => { + return [floor, areasInFloors] as const; + }) + .filter(([_, areas]) => areas.length) + .map(([floor, areas], _, array) => { + const areasCards = areas.map((area) => { const path = computeAreaPath(area.area_id); const areaOptions = config.areas_options?.[area.area_id] || {}; @@ -123,10 +121,17 @@ export class AreasOverviewViewStrategy extends ReactiveElement { }; }); + const noFloors = + array.length === 1 && floor.floor_id === UNASSIGNED_FLOOR; + + const headingTitle = noFloors + ? hass.localize("ui.panel.lovelace.strategy.areas.areas") + : floor.name; + const headingCard: HeadingCardConfig = { type: "heading", heading_style: "title", - heading: floor.name, + heading: headingTitle, icon: floor.icon || floorDefaultIcon(floor), }; diff --git a/src/translations/en.json b/src/translations/en.json index ef0fe838d7..8b28a90f5a 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -6685,7 +6685,8 @@ "actions": "Actions", "others": "Others" }, - "unassigned_areas": "[%key:ui::panel::config::areas::picker::unassigned_areas%]" + "others_areas": "Other areas", + "areas": "Areas" } }, "cards": {