Better handle case when no floors in areas dashboard (#25933)

This commit is contained in:
Paul Bottein 2025-06-26 12:18:34 +02:00 committed by GitHub
parent d8ab9b73ba
commit f5df91d4c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 51 additions and 36 deletions

View File

@ -1,6 +1,6 @@
import { mdiTextureBox } from "@mdi/js"; import { mdiTextureBox } from "@mdi/js";
import type { TemplateResult } from "lit"; 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 { customElement, property } from "lit/decorators";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event"; import { fireEvent } from "../common/dom/fire_event";
@ -64,26 +64,30 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
.expanded=${this.expanded} .expanded=${this.expanded}
> >
<ha-svg-icon slot="leading-icon" .path=${mdiTextureBox}></ha-svg-icon> <ha-svg-icon slot="leading-icon" .path=${mdiTextureBox}></ha-svg-icon>
${filteredFloors.map( ${filteredFloors.map((floor, _, array) => {
(floor) => html` const noFloors =
array.length === 1 && floor.floor_id === UNASSIGNED_FLOOR;
return html`
<div class="floor"> <div class="floor">
<div class="header"> ${noFloors
<ha-floor-icon .floor=${floor}></ha-floor-icon> ? nothing
<p>${computeFloorName(floor)}</p> : html`<div class="header">
</div> <ha-floor-icon .floor=${floor}></ha-floor-icon>
<p>${computeFloorName(floor)}</p>
</div>`}
<div class="areas"> <div class="areas">
<ha-items-display-editor <ha-items-display-editor
.hass=${this.hass} .hass=${this.hass}
.items=${groupedItems[floor.floor_id] || []} .items=${groupedItems[floor.floor_id] || []}
.value=${value} .value=${value}
.floorId=${floor.floor_id} .floorId=${floor.floor_id ?? UNASSIGNED_FLOOR}
@value-changed=${this._areaDisplayChanged} @value-changed=${this._areaDisplayChanged}
.showNavigationButton=${this.showNavigationButton} .showNavigationButton=${this.showNavigationButton}
></ha-items-display-editor> ></ha-items-display-editor>
</div> </div>
</div> </div>
` `;
)} })}
</ha-expansion-panel> </ha-expansion-panel>
`; `;
} }
@ -134,10 +138,10 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
floors.push({ floors.push({
floor_id: UNASSIGNED_FLOOR, floor_id: UNASSIGNED_FLOOR,
name: this.hass.localize( name: this.hass.localize(
"ui.panel.lovelace.strategy.areas.unassigned_areas" "ui.panel.lovelace.strategy.areas.others_areas"
), ),
icon: null, icon: null,
level: 999999, level: null,
aliases: [], aliases: [],
created_at: 0, created_at: 0,
modified_at: 0, modified_at: 0,
@ -155,25 +159,30 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
(floor) => floor.floor_id (floor) => floor.floor_id
); );
const oldHidden = this.value?.hidden ?? [];
const oldOrder = this.value?.order ?? [];
const newHidden: string[] = []; const newHidden: string[] = [];
const newOrder: string[] = []; const newOrder: string[] = [];
for (const floorId of floorIds) { for (const floorId of floorIds) {
if (currentFloorId === floorId) { if ((currentFloorId ?? UNASSIGNED_FLOOR) === floorId) {
newHidden.push(...(value.hidden ?? [])); newHidden.push(...(value.hidden ?? []));
newOrder.push(...(value.order ?? [])); newOrder.push(...(value.order ?? []));
continue; continue;
} }
const hidden = this.value?.hidden?.filter( const hidden = oldHidden.filter((areaId) => {
(areaId) => this.hass.areas[areaId]?.floor_id === floorId const id = this.hass.areas[areaId]?.floor_id ?? UNASSIGNED_FLOOR;
); return id === floorId;
if (hidden) { });
if (hidden?.length) {
newHidden.push(...hidden); newHidden.push(...hidden);
} }
const order = this.value?.order?.filter( const order = oldOrder.filter((areaId) => {
(areaId) => this.hass.areas[areaId]?.floor_id === floorId const id = this.hass.areas[areaId]?.floor_id ?? UNASSIGNED_FLOOR;
); return id === floorId;
if (order) { });
if (order?.length) {
newOrder.push(...order); newOrder.push(...order);
} }
} }
@ -188,7 +197,7 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
if (newValue.order?.length === 0) { if (newValue.order?.length === 0) {
delete newValue.order; delete newValue.order;
} }
this.value = newValue;
fireEvent(this, "value-changed", { value: newValue }); fireEvent(this, "value-changed", { value: newValue });
} }
@ -199,7 +208,7 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
flex: 1: flex: 1;
} }
.floor .header { .floor .header {
margin: 16px 0 8px 0; margin: 16px 0 8px 0;

View File

@ -32,7 +32,7 @@ export class AreasOverviewViewStrategy extends ReactiveElement {
config: AreasViewStrategyConfig, config: AreasViewStrategyConfig,
hass: HomeAssistant hass: HomeAssistant
): Promise<LovelaceViewConfig> { ): Promise<LovelaceViewConfig> {
const areas = getAreas( const displayedAreas = getAreas(
hass.areas, hass.areas,
config.areas_display?.hidden, config.areas_display?.hidden,
config.areas_display?.order config.areas_display?.order
@ -50,25 +50,23 @@ export class AreasOverviewViewStrategy extends ReactiveElement {
...floors, ...floors,
{ {
floor_id: UNASSIGNED_FLOOR, floor_id: UNASSIGNED_FLOOR,
name: hass.localize( name: hass.localize("ui.panel.lovelace.strategy.areas.others_areas"),
"ui.panel.lovelace.strategy.areas.unassigned_areas"
),
level: null, level: null,
icon: null, icon: null,
}, },
] ]
.map<LovelaceSectionConfig | undefined>((floor) => { .map((floor) => {
const areasInFloors = areas.filter( const areasInFloors = displayedAreas.filter(
(area) => (area) =>
area.floor_id === floor.floor_id || area.floor_id === floor.floor_id ||
(!area.floor_id && floor.floor_id === UNASSIGNED_FLOOR) (!area.floor_id && floor.floor_id === UNASSIGNED_FLOOR)
); );
if (areasInFloors.length === 0) { return [floor, areasInFloors] as const;
return undefined; })
} .filter(([_, areas]) => areas.length)
.map<LovelaceSectionConfig | undefined>(([floor, areas], _, array) => {
const areasCards = areasInFloors.map<AreaCardConfig>((area) => { const areasCards = areas.map<AreaCardConfig>((area) => {
const path = computeAreaPath(area.area_id); const path = computeAreaPath(area.area_id);
const areaOptions = config.areas_options?.[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 = { const headingCard: HeadingCardConfig = {
type: "heading", type: "heading",
heading_style: "title", heading_style: "title",
heading: floor.name, heading: headingTitle,
icon: floor.icon || floorDefaultIcon(floor), icon: floor.icon || floorDefaultIcon(floor),
}; };

View File

@ -6685,7 +6685,8 @@
"actions": "Actions", "actions": "Actions",
"others": "Others" "others": "Others"
}, },
"unassigned_areas": "[%key:ui::panel::config::areas::picker::unassigned_areas%]" "others_areas": "Other areas",
"areas": "Areas"
} }
}, },
"cards": { "cards": {