Remove create_list from StorageCollectionWebsocket.async_setup (#119508)

This commit is contained in:
Erik Montnemery 2024-06-17 12:16:36 +02:00 committed by GitHub
parent 0ae4903686
commit e0378f79a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 142 additions and 69 deletions

View file

@ -1609,11 +1609,10 @@ class PipelineStorageCollectionWebsocket(
self,
hass: HomeAssistant,
*,
create_list: bool = True,
create_create: bool = True,
) -> None:
"""Set up the websocket commands."""
super().async_setup(hass, create_list=create_list, create_create=create_create)
super().async_setup(hass, create_create=create_create)
websocket_api.async_register_command(
hass,

View file

@ -115,6 +115,17 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
reload_resources_service_handler,
schema=RESOURCE_RELOAD_SERVICE_SCHEMA,
)
# Register lovelace/resources for backwards compatibility, remove in
# Home Assistant Core 2025.1
for command in ("lovelace/resources", "lovelace/resources/list"):
websocket_api.async_register_command(
hass,
command,
websocket.websocket_lovelace_resources,
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
{"type": command},
),
)
else:
default_config = dashboard.LovelaceStorage(hass, None)
@ -127,22 +138,19 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
resource_collection = resources.ResourceStorageCollection(hass, default_config)
collection.DictStorageCollectionWebsocket(
resources.ResourceStorageCollectionWebsocket(
resource_collection,
"lovelace/resources",
"resource",
RESOURCE_CREATE_FIELDS,
RESOURCE_UPDATE_FIELDS,
).async_setup(hass, create_list=False)
).async_setup(hass)
websocket_api.async_register_command(hass, websocket.websocket_lovelace_config)
websocket_api.async_register_command(hass, websocket.websocket_lovelace_save_config)
websocket_api.async_register_command(
hass, websocket.websocket_lovelace_delete_config
)
websocket_api.async_register_command(hass, websocket.websocket_lovelace_resources)
websocket_api.async_register_command(hass, websocket.websocket_lovelace_dashboards)
hass.data[DOMAIN] = {
# We store a dictionary mapping url_path: config. None is the default.
@ -209,13 +217,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
dashboards_collection.async_add_listener(storage_dashboard_changed)
await dashboards_collection.async_load()
collection.DictStorageCollectionWebsocket(
dashboard.DashboardsCollectionWebSocket(
dashboards_collection,
"lovelace/dashboards",
"dashboard",
STORAGE_DASHBOARD_CREATE_FIELDS,
STORAGE_DASHBOARD_UPDATE_FIELDS,
).async_setup(hass, create_list=False)
).async_setup(hass)
def create_map_dashboard():
hass.async_create_task(_create_map_dashboard(hass))

View file

@ -11,6 +11,7 @@ from typing import Any
import voluptuous as vol
from homeassistant.components import websocket_api
from homeassistant.components.frontend import DATA_PANELS
from homeassistant.const import CONF_FILENAME
from homeassistant.core import HomeAssistant, callback
@ -297,3 +298,24 @@ class DashboardsCollection(collection.DictStorageCollection):
updated.pop(CONF_ICON)
return updated
class DashboardsCollectionWebSocket(collection.DictStorageCollectionWebsocket):
"""Class to expose storage collection management over websocket."""
@callback
def ws_list_item(
self,
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Send Lovelace UI resources over WebSocket connection."""
connection.send_result(
msg["id"],
[
dashboard.config
for dashboard in hass.data[DOMAIN]["dashboards"].values()
if dashboard.config
],
)

View file

@ -8,6 +8,7 @@ import uuid
import voluptuous as vol
from homeassistant.components import websocket_api
from homeassistant.const import CONF_ID, CONF_RESOURCES, CONF_TYPE
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
@ -21,6 +22,7 @@ from .const import (
RESOURCE_UPDATE_FIELDS,
)
from .dashboard import LovelaceConfig
from .websocket import websocket_lovelace_resources_impl
RESOURCE_STORAGE_KEY = f"{DOMAIN}_resources"
RESOURCES_STORAGE_VERSION = 1
@ -125,3 +127,38 @@ class ResourceStorageCollection(collection.DictStorageCollection):
update_data[CONF_TYPE] = update_data.pop(CONF_RESOURCE_TYPE_WS)
return {**item, **update_data}
class ResourceStorageCollectionWebsocket(collection.DictStorageCollectionWebsocket):
"""Class to expose storage collection management over websocket."""
@callback
def async_setup(
self,
hass: HomeAssistant,
*,
create_create: bool = True,
) -> None:
"""Set up the websocket commands."""
super().async_setup(hass, create_create=create_create)
# Register lovelace/resources for backwards compatibility, remove in
# Home Assistant Core 2025.1
websocket_api.async_register_command(
hass,
self.api_prefix,
self.ws_list_item,
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
{vol.Required("type"): f"{self.api_prefix}"}
),
)
@staticmethod
@websocket_api.async_response
async def ws_list_item(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Send Lovelace UI resources over WebSocket connection."""
await websocket_lovelace_resources_impl(hass, connection, msg)

View file

@ -8,7 +8,7 @@ from typing import Any
import voluptuous as vol
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant, callback
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.json import json_fragment
@ -52,14 +52,28 @@ def _handle_errors(func):
return send_with_error_handling
@websocket_api.websocket_command({"type": "lovelace/resources"})
@websocket_api.async_response
async def websocket_lovelace_resources(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Send Lovelace UI resources over WebSocket configuration."""
"""Send Lovelace UI resources over WebSocket connection.
This function is used in YAML mode.
"""
await websocket_lovelace_resources_impl(hass, connection, msg)
async def websocket_lovelace_resources_impl(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Help send Lovelace UI resources over WebSocket connection.
This function is called by both Storage and YAML mode WS handlers.
"""
resources = hass.data[DOMAIN]["resources"]
if hass.config.safe_mode:
@ -129,21 +143,3 @@ async def websocket_lovelace_delete_config(
) -> None:
"""Delete Lovelace UI configuration."""
await config.async_delete()
@websocket_api.websocket_command({"type": "lovelace/dashboards/list"})
@callback
def websocket_lovelace_dashboards(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Send Lovelace dashboard configuration."""
connection.send_result(
msg["id"],
[
dashboard.config
for dashboard in hass.data[DOMAIN]["dashboards"].values()
if dashboard.config
],
)

View file

@ -24,7 +24,6 @@ from homeassistant.const import (
ATTR_NAME,
CONF_ID,
CONF_NAME,
CONF_TYPE,
EVENT_HOMEASSISTANT_START,
SERVICE_RELOAD,
STATE_HOME,
@ -307,6 +306,23 @@ class PersonStorageCollection(collection.DictStorageCollection):
raise ValueError("User already taken")
class PersonStorageCollectionWebsocket(collection.DictStorageCollectionWebsocket):
"""Class to expose storage collection management over websocket."""
def ws_list_item(
self,
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""List persons."""
yaml, storage, _ = hass.data[DOMAIN]
connection.send_result(
msg[ATTR_ID],
{"storage": storage.async_items(), "config": yaml.async_items()},
)
async def filter_yaml_data(hass: HomeAssistant, persons: list[dict]) -> list[dict]:
"""Validate YAML data that we can't validate via schema."""
filtered = []
@ -370,11 +386,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
hass.data[DOMAIN] = (yaml_collection, storage_collection, entity_component)
collection.DictStorageCollectionWebsocket(
PersonStorageCollectionWebsocket(
storage_collection, DOMAIN, DOMAIN, CREATE_FIELDS, UPDATE_FIELDS
).async_setup(hass, create_list=False)
websocket_api.async_register_command(hass, ws_list_person)
).async_setup(hass)
async def _handle_user_removed(event: Event) -> None:
"""Handle a user being removed."""
@ -570,19 +584,6 @@ class Person(
self._attr_extra_state_attributes = data
@websocket_api.websocket_command({vol.Required(CONF_TYPE): "person/list"})
def ws_list_person(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""List persons."""
yaml, storage, _ = hass.data[DOMAIN]
connection.send_result(
msg[ATTR_ID], {"storage": storage.async_items(), "config": yaml.async_items()}
)
def _get_latest(prev: State | None, curr: State) -> State:
"""Get latest state."""
if prev is None or curr.last_updated > prev.last_updated:

View file

@ -537,19 +537,17 @@ class StorageCollectionWebsocket[_StorageCollectionT: StorageCollection]:
self,
hass: HomeAssistant,
*,
create_list: bool = True,
create_create: bool = True,
) -> None:
"""Set up the websocket commands."""
if create_list:
websocket_api.async_register_command(
hass,
f"{self.api_prefix}/list",
self.ws_list_item,
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
{vol.Required("type"): f"{self.api_prefix}/list"}
),
)
websocket_api.async_register_command(
hass,
f"{self.api_prefix}/list",
self.ws_list_item,
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
{vol.Required("type"): f"{self.api_prefix}/list"}
),
)
if create_create:
websocket_api.async_register_command(

View file

@ -5,6 +5,8 @@ from typing import Any
from unittest.mock import patch
import uuid
import pytest
from homeassistant.components.lovelace import dashboard, resources
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
@ -17,8 +19,9 @@ RESOURCE_EXAMPLES = [
]
@pytest.mark.parametrize("list_cmd", ["lovelace/resources", "lovelace/resources/list"])
async def test_yaml_resources(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
hass: HomeAssistant, hass_ws_client: WebSocketGenerator, list_cmd: str
) -> None:
"""Test defining resources in configuration.yaml."""
assert await async_setup_component(
@ -28,14 +31,15 @@ async def test_yaml_resources(
client = await hass_ws_client(hass)
# Fetch data
await client.send_json({"id": 5, "type": "lovelace/resources"})
await client.send_json({"id": 5, "type": list_cmd})
response = await client.receive_json()
assert response["success"]
assert response["result"] == RESOURCE_EXAMPLES
@pytest.mark.parametrize("list_cmd", ["lovelace/resources", "lovelace/resources/list"])
async def test_yaml_resources_backwards(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
hass: HomeAssistant, hass_ws_client: WebSocketGenerator, list_cmd: str
) -> None:
"""Test defining resources in YAML ll config (legacy)."""
with patch(
@ -49,16 +53,18 @@ async def test_yaml_resources_backwards(
client = await hass_ws_client(hass)
# Fetch data
await client.send_json({"id": 5, "type": "lovelace/resources"})
await client.send_json({"id": 5, "type": list_cmd})
response = await client.receive_json()
assert response["success"]
assert response["result"] == RESOURCE_EXAMPLES
@pytest.mark.parametrize("list_cmd", ["lovelace/resources", "lovelace/resources/list"])
async def test_storage_resources(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
hass_storage: dict[str, Any],
list_cmd: str,
) -> None:
"""Test defining resources in storage config."""
resource_config = [{**item, "id": uuid.uuid4().hex} for item in RESOURCE_EXAMPLES]
@ -72,16 +78,18 @@ async def test_storage_resources(
client = await hass_ws_client(hass)
# Fetch data
await client.send_json({"id": 5, "type": "lovelace/resources"})
await client.send_json({"id": 5, "type": list_cmd})
response = await client.receive_json()
assert response["success"]
assert response["result"] == resource_config
@pytest.mark.parametrize("list_cmd", ["lovelace/resources", "lovelace/resources/list"])
async def test_storage_resources_import(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
hass_storage: dict[str, Any],
list_cmd: str,
) -> None:
"""Test importing resources from storage config."""
assert await async_setup_component(hass, "lovelace", {})
@ -94,7 +102,7 @@ async def test_storage_resources_import(
client = await hass_ws_client(hass)
# Fetch data
await client.send_json({"id": 5, "type": "lovelace/resources"})
await client.send_json({"id": 5, "type": list_cmd})
response = await client.receive_json()
assert response["success"]
assert (
@ -118,7 +126,7 @@ async def test_storage_resources_import(
response = await client.receive_json()
assert response["success"]
await client.send_json({"id": 7, "type": "lovelace/resources"})
await client.send_json({"id": 7, "type": list_cmd})
response = await client.receive_json()
assert response["success"]
@ -141,7 +149,7 @@ async def test_storage_resources_import(
response = await client.receive_json()
assert response["success"]
await client.send_json({"id": 9, "type": "lovelace/resources"})
await client.send_json({"id": 9, "type": list_cmd})
response = await client.receive_json()
assert response["success"]
@ -160,7 +168,7 @@ async def test_storage_resources_import(
response = await client.receive_json()
assert response["success"]
await client.send_json({"id": 11, "type": "lovelace/resources"})
await client.send_json({"id": 11, "type": list_cmd})
response = await client.receive_json()
assert response["success"]
@ -168,10 +176,12 @@ async def test_storage_resources_import(
assert first_item["id"] not in (item["id"] for item in response["result"])
@pytest.mark.parametrize("list_cmd", ["lovelace/resources", "lovelace/resources/list"])
async def test_storage_resources_import_invalid(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
hass_storage: dict[str, Any],
list_cmd: str,
) -> None:
"""Test importing resources from storage config."""
assert await async_setup_component(hass, "lovelace", {})
@ -184,7 +194,7 @@ async def test_storage_resources_import_invalid(
client = await hass_ws_client(hass)
# Fetch data
await client.send_json({"id": 5, "type": "lovelace/resources"})
await client.send_json({"id": 5, "type": list_cmd})
response = await client.receive_json()
assert response["success"]
assert response["result"] == []
@ -194,10 +204,12 @@ async def test_storage_resources_import_invalid(
)
@pytest.mark.parametrize("list_cmd", ["lovelace/resources", "lovelace/resources/list"])
async def test_storage_resources_safe_mode(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
hass_storage: dict[str, Any],
list_cmd: str,
) -> None:
"""Test defining resources in storage config."""
@ -213,7 +225,7 @@ async def test_storage_resources_safe_mode(
hass.config.safe_mode = True
# Fetch data
await client.send_json({"id": 5, "type": "lovelace/resources"})
await client.send_json({"id": 5, "type": list_cmd})
response = await client.receive_json()
assert response["success"]
assert response["result"] == []