1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-14 12:31:04 +01:00

Load lovelace resource collection eagerly during setup (#165773)

This commit is contained in:
Renaud Allard
2026-04-10 10:38:17 +02:00
committed by GitHub
parent 14f24226ae
commit 4c8ea3669c
2 changed files with 56 additions and 6 deletions
+20 -6
View File
@@ -62,14 +62,32 @@ class ResourceStorageCollection(collection.DictStorageCollection):
)
self.ll_config = ll_config
async def async_get_info(self) -> dict[str, int]:
"""Return the resources info for YAML mode."""
async def _async_ensure_loaded(self) -> None:
"""Ensure the collection has been loaded from storage."""
if not self.loaded:
await self.async_load()
self.loaded = True
async def async_get_info(self) -> dict[str, int]:
"""Return the resources info for YAML mode."""
await self._async_ensure_loaded()
return {"resources": len(self.async_items() or [])}
async def async_create_item(self, data: dict) -> dict:
"""Create a new item."""
await self._async_ensure_loaded()
return await super().async_create_item(data)
async def async_update_item(self, item_id: str, updates: dict) -> dict:
"""Update item."""
await self._async_ensure_loaded()
return await super().async_update_item(item_id, updates)
async def async_delete_item(self, item_id: str) -> None:
"""Delete item."""
await self._async_ensure_loaded()
await super().async_delete_item(item_id)
async def _async_load_data(self) -> collection.SerializedStorageCollection | None:
"""Load the data."""
if (store_data := await self.store.async_load()) is not None:
@@ -118,10 +136,6 @@ class ResourceStorageCollection(collection.DictStorageCollection):
async def _update_data(self, item: dict, update_data: dict) -> dict:
"""Return a new updated data object."""
if not self.loaded:
await self.async_load()
self.loaded = True
update_data = self.UPDATE_SCHEMA(update_data)
if CONF_RESOURCE_TYPE_WS in update_data:
update_data[CONF_TYPE] = update_data.pop(CONF_RESOURCE_TYPE_WS)
@@ -8,6 +8,7 @@ import uuid
import pytest
from homeassistant.components.lovelace import dashboard, resources
from homeassistant.components.lovelace.const import LOVELACE_DATA
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
@@ -278,6 +279,41 @@ async def test_storage_resources_import_invalid(
)
async def test_storage_resources_create_preserves_existing(
hass: HomeAssistant,
hass_storage: dict[str, Any],
) -> None:
"""Test async_create_item lazy-loads before writing.
Custom integrations may call async_create_item() during startup before the
frontend triggers a resource listing. Without a lazy-load guard, the
collection is empty and async_create_item() overwrites all existing
resources on disk.
"""
resource_config = [{**item, "id": uuid.uuid4().hex} for item in RESOURCE_EXAMPLES]
hass_storage[resources.RESOURCE_STORAGE_KEY] = {
"key": resources.RESOURCE_STORAGE_KEY,
"version": 1,
"data": {"items": resource_config},
}
assert await async_setup_component(hass, "lovelace", {})
resource_collection = hass.data[LOVELACE_DATA].resources
# Directly call async_create_item before any websocket listing
await resource_collection.async_create_item(
{"res_type": "module", "url": "/local/new.js"}
)
# Existing resources must still be present
items = resource_collection.async_items()
assert len(items) == len(resource_config) + 1
urls = [item["url"] for item in items]
for original in resource_config:
assert original["url"] in urls
assert "/local/new.js" in urls
@pytest.mark.parametrize("list_cmd", ["lovelace/resources", "lovelace/resources/list"])
async def test_storage_resources_safe_mode(
hass: HomeAssistant,