mirror of
https://github.com/home-assistant/frontend.git
synced 2026-10-29 09:04:22 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d43e1ef4cc | ||
|
|
f699019994 |
No files matched your search
@@ -245,15 +245,15 @@ export class HaAreasFloorsDisplayEditor extends LitElement {
|
||||
const newOrder: string[] = [];
|
||||
|
||||
for (const floorId of floorIds) {
|
||||
const isOnFloor = (areaId: string) =>
|
||||
(this._areas[areaId]?.floor_id ?? UNASSIGNED_FLOOR) === floorId;
|
||||
if ((currentFloorId ?? UNASSIGNED_FLOOR) === floorId) {
|
||||
newHidden.push(...(value.hidden ?? []));
|
||||
// Reordering returns the hidden areas of every floor, not just this one
|
||||
newHidden.push(...(value.hidden ?? []).filter(isOnFloor));
|
||||
newOrder.push(...(value.order ?? []));
|
||||
continue;
|
||||
}
|
||||
const hidden = oldHidden.filter((areaId) => {
|
||||
const id = this._areas[areaId]?.floor_id ?? UNASSIGNED_FLOOR;
|
||||
return id === floorId;
|
||||
});
|
||||
const hidden = oldHidden.filter(isOnFloor);
|
||||
if (hidden?.length) {
|
||||
newHidden.push(...hidden);
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ export class LovelacePanel extends LitElement {
|
||||
// Refreshing a YAML config can trigger an update event. We will ignore
|
||||
// all update events while fetching the config and for 2 seconds after the config is back.
|
||||
// We ignore because we already have the latest config.
|
||||
if (this.lovelace && this.lovelace.mode === "yaml") {
|
||||
if (confMode === "yaml") {
|
||||
this._ignoreNextUpdateEvent = true;
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ export class LovelacePanel extends LitElement {
|
||||
} finally {
|
||||
this._loading = false;
|
||||
// Ignore updates for another 2 seconds.
|
||||
if (this.lovelace && this.lovelace.mode === "yaml") {
|
||||
if (confMode === "yaml") {
|
||||
setTimeout(() => {
|
||||
this._ignoreNextUpdateEvent = false;
|
||||
}, 2000);
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
import { ContextProvider } from "@lit/context";
|
||||
import {
|
||||
afterEach,
|
||||
beforeAll,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
vi,
|
||||
} from "vitest";
|
||||
import "../../src/components/ha-areas-floors-display-editor";
|
||||
import type {
|
||||
AreasFloorsDisplayValue,
|
||||
HaAreasFloorsDisplayEditor,
|
||||
} from "../../src/components/ha-areas-floors-display-editor";
|
||||
import type { HaItemDisplayEditor } from "../../src/components/ha-items-display-editor";
|
||||
import {
|
||||
areasContext,
|
||||
floorsContext,
|
||||
internationalizationContext,
|
||||
} from "../../src/data/context";
|
||||
import type {
|
||||
HomeAssistant,
|
||||
HomeAssistantInternationalization,
|
||||
} from "../../src/types";
|
||||
|
||||
beforeAll(() => {
|
||||
// jsdom's ElementInternals lacks the validity API used by the webawesome
|
||||
// buttons that render inside the items editor.
|
||||
const internalsProto = window.ElementInternals.prototype as any;
|
||||
internalsProto.setValidity = vi.fn();
|
||||
internalsProto.setFormValue = vi.fn();
|
||||
Object.defineProperty(internalsProto, "validity", {
|
||||
get: () => ({ valid: true }),
|
||||
configurable: true,
|
||||
});
|
||||
});
|
||||
|
||||
class MockResizeObserver {
|
||||
observe = vi.fn();
|
||||
|
||||
unobserve = vi.fn();
|
||||
|
||||
disconnect = vi.fn();
|
||||
}
|
||||
|
||||
const UNASSIGNED_FLOOR = "__unassigned__";
|
||||
|
||||
const FLOORS = {
|
||||
floor_a: { floor_id: "floor_a", name: "A", level: 0 },
|
||||
floor_b: { floor_id: "floor_b", name: "B", level: 1 },
|
||||
} as unknown as HomeAssistant["floors"];
|
||||
|
||||
const area = (areaId: string, floorId: string | null) => ({
|
||||
area_id: areaId,
|
||||
name: areaId,
|
||||
floor_id: floorId,
|
||||
icon: null,
|
||||
});
|
||||
|
||||
const AREAS = Object.fromEntries(
|
||||
[
|
||||
area("a1", "floor_a"),
|
||||
area("a2", "floor_a"),
|
||||
area("a3", "floor_a"),
|
||||
area("b1", "floor_b"),
|
||||
area("b2", "floor_b"),
|
||||
area("b3", "floor_b"),
|
||||
area("u1", null),
|
||||
area("u2", null),
|
||||
].map((entry) => [entry.area_id, entry])
|
||||
) as unknown as HomeAssistant["areas"];
|
||||
|
||||
describe("ha-areas-floors-display-editor", () => {
|
||||
let host: HTMLDivElement | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal("ResizeObserver", MockResizeObserver);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
host?.remove();
|
||||
host = undefined;
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
const mount = async (
|
||||
value: AreasFloorsDisplayValue
|
||||
): Promise<HaAreasFloorsDisplayEditor> => {
|
||||
host = document.createElement("div");
|
||||
document.body.appendChild(host);
|
||||
new ContextProvider(host, {
|
||||
context: internationalizationContext,
|
||||
initialValue: {
|
||||
localize: (key: string) => key,
|
||||
} as unknown as HomeAssistantInternationalization,
|
||||
});
|
||||
new ContextProvider(host, { context: areasContext, initialValue: AREAS });
|
||||
new ContextProvider(host, { context: floorsContext, initialValue: FLOORS });
|
||||
const el = document.createElement(
|
||||
"ha-areas-floors-display-editor"
|
||||
) as HaAreasFloorsDisplayEditor;
|
||||
el.value = value;
|
||||
host.appendChild(el);
|
||||
await el.updateComplete;
|
||||
return el;
|
||||
};
|
||||
|
||||
// Drags the first visible area of a floor below the second one and returns
|
||||
// the configuration the editor emits.
|
||||
const reorderFirstTwo = async (
|
||||
el: HaAreasFloorsDisplayEditor,
|
||||
floorId: string
|
||||
): Promise<AreasFloorsDisplayValue> => {
|
||||
const editor = Array.from(
|
||||
el.shadowRoot!.querySelectorAll("ha-items-display-editor")
|
||||
).find(
|
||||
(child) =>
|
||||
(child as HaItemDisplayEditor & { floorId: string }).floorId === floorId
|
||||
)!;
|
||||
await editor.updateComplete;
|
||||
const emitted: AreasFloorsDisplayValue[] = [];
|
||||
el.addEventListener(
|
||||
"value-changed",
|
||||
(ev) => emitted.push((ev as CustomEvent).detail.value),
|
||||
{ once: true }
|
||||
);
|
||||
editor.shadowRoot!.querySelector("ha-sortable")!.dispatchEvent(
|
||||
new CustomEvent("item-moved", {
|
||||
detail: { oldIndex: 0, newIndex: 1 },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
})
|
||||
);
|
||||
expect(emitted).toHaveLength(1);
|
||||
return emitted[0];
|
||||
};
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "hidden area on another floor",
|
||||
floorId: "floor_a",
|
||||
value: {
|
||||
areas_display: { hidden: ["b1"], order: ["b3", "b2"] },
|
||||
},
|
||||
expected: {
|
||||
hidden: ["b1"],
|
||||
order: ["a2", "a1", "a3", "b3", "b2"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "hidden areas on the reordered and another floor",
|
||||
floorId: "floor_a",
|
||||
value: { areas_display: { hidden: ["a3", "b1"] } },
|
||||
expected: { hidden: ["a3", "b1"], order: ["a2", "a1"] },
|
||||
},
|
||||
{
|
||||
name: "reordering areas without a floor",
|
||||
floorId: UNASSIGNED_FLOOR,
|
||||
value: { areas_display: { hidden: ["b1"] } },
|
||||
expected: { hidden: ["b1"], order: ["u2", "u1"] },
|
||||
},
|
||||
{
|
||||
name: "no hidden areas",
|
||||
floorId: "floor_b",
|
||||
value: {},
|
||||
expected: { order: ["b2", "b1", "b3"] },
|
||||
},
|
||||
])(
|
||||
"keeps hidden areas unchanged when reordering: $name",
|
||||
async ({ floorId, value, expected }) => {
|
||||
const el = await mount(value);
|
||||
|
||||
const first = await reorderFirstTwo(el, floorId);
|
||||
expect(first.areas_display).toEqual(expected);
|
||||
|
||||
// Saving and reordering again must not grow the hidden list
|
||||
el.value = first;
|
||||
await el.updateComplete;
|
||||
const second = await reorderFirstTwo(el, floorId);
|
||||
expect(second.areas_display?.hidden).toEqual(expected.hidden);
|
||||
}
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user