Allow integrations to register custom config panels (#96245)
parent
a69b5a8d3b
commit
1a9e27cdaf
|
@ -222,6 +222,9 @@ class Panel:
|
|||
# If the panel should only be visible to admins
|
||||
require_admin = False
|
||||
|
||||
# If the panel is a configuration panel for a integration
|
||||
config_panel_domain: str | None = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
component_name: str,
|
||||
|
@ -230,6 +233,7 @@ class Panel:
|
|||
frontend_url_path: str | None,
|
||||
config: dict[str, Any] | None,
|
||||
require_admin: bool,
|
||||
config_panel_domain: str | None,
|
||||
) -> None:
|
||||
"""Initialize a built-in panel."""
|
||||
self.component_name = component_name
|
||||
|
@ -238,6 +242,7 @@ class Panel:
|
|||
self.frontend_url_path = frontend_url_path or component_name
|
||||
self.config = config
|
||||
self.require_admin = require_admin
|
||||
self.config_panel_domain = config_panel_domain
|
||||
|
||||
@callback
|
||||
def to_response(self) -> PanelRespons:
|
||||
|
@ -249,6 +254,7 @@ class Panel:
|
|||
"config": self.config,
|
||||
"url_path": self.frontend_url_path,
|
||||
"require_admin": self.require_admin,
|
||||
"config_panel_domain": self.config_panel_domain,
|
||||
}
|
||||
|
||||
|
||||
|
@ -264,6 +270,7 @@ def async_register_built_in_panel(
|
|||
require_admin: bool = False,
|
||||
*,
|
||||
update: bool = False,
|
||||
config_panel_domain: str | None = None,
|
||||
) -> None:
|
||||
"""Register a built-in panel."""
|
||||
panel = Panel(
|
||||
|
@ -273,6 +280,7 @@ def async_register_built_in_panel(
|
|||
frontend_url_path,
|
||||
config,
|
||||
require_admin,
|
||||
config_panel_domain,
|
||||
)
|
||||
|
||||
panels = hass.data.setdefault(DATA_PANELS, {})
|
||||
|
@ -720,3 +728,4 @@ class PanelRespons(TypedDict):
|
|||
config: dict[str, Any] | None
|
||||
url_path: str | None
|
||||
require_admin: bool
|
||||
config_panel_domain: str | None
|
||||
|
|
|
@ -92,6 +92,8 @@ async def async_register_panel(
|
|||
config: ConfigType | None = None,
|
||||
# If your panel should only be shown to admin users
|
||||
require_admin: bool = False,
|
||||
# If your panel is used to configure an integration, needs the domain of the integration
|
||||
config_panel_domain: str | None = None,
|
||||
) -> None:
|
||||
"""Register a new custom panel."""
|
||||
if js_url is None and module_url is None:
|
||||
|
@ -127,6 +129,7 @@ async def async_register_panel(
|
|||
frontend_url_path=frontend_url_path,
|
||||
config=config,
|
||||
require_admin=require_admin,
|
||||
config_panel_domain=config_panel_domain,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -265,6 +265,7 @@ async def test_setup_api_panel(
|
|||
"title": None,
|
||||
"url_path": "hassio",
|
||||
"require_admin": True,
|
||||
"config_panel_domain": None,
|
||||
"config": {
|
||||
"_panel_custom": {
|
||||
"embed_iframe": True,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from unittest.mock import Mock, patch
|
||||
|
||||
from homeassistant import setup
|
||||
from homeassistant.components import frontend
|
||||
from homeassistant.components import frontend, panel_custom
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
|
||||
|
@ -155,3 +155,37 @@ async def test_url_path_conflict(hass: HomeAssistant) -> None:
|
|||
]
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
async def test_register_config_panel(hass: HomeAssistant) -> None:
|
||||
"""Test setting up a custom config panel for an integration."""
|
||||
result = await setup.async_setup_component(hass, "panel_custom", {})
|
||||
assert result
|
||||
|
||||
# Register a custom panel
|
||||
await panel_custom.async_register_panel(
|
||||
hass=hass,
|
||||
frontend_url_path="config_panel",
|
||||
webcomponent_name="custom-frontend",
|
||||
module_url="custom-frontend",
|
||||
embed_iframe=True,
|
||||
require_admin=True,
|
||||
config_panel_domain="test",
|
||||
)
|
||||
|
||||
panels = hass.data.get(frontend.DATA_PANELS, [])
|
||||
assert panels
|
||||
assert "config_panel" in panels
|
||||
|
||||
panel = panels["config_panel"]
|
||||
|
||||
assert panel.config == {
|
||||
"_panel_custom": {
|
||||
"module_url": "custom-frontend",
|
||||
"name": "custom-frontend",
|
||||
"embed_iframe": True,
|
||||
"trust_external": False,
|
||||
},
|
||||
}
|
||||
assert panel.frontend_url_path == "config_panel"
|
||||
assert panel.config_panel_domain == "test"
|
||||
|
|
|
@ -54,6 +54,7 @@ async def test_correct_config(hass: HomeAssistant) -> None:
|
|||
assert panels.get("router").to_response() == {
|
||||
"component_name": "iframe",
|
||||
"config": {"url": "http://192.168.1.1"},
|
||||
"config_panel_domain": None,
|
||||
"icon": "mdi:network-wireless",
|
||||
"title": "Router",
|
||||
"url_path": "router",
|
||||
|
@ -63,6 +64,7 @@ async def test_correct_config(hass: HomeAssistant) -> None:
|
|||
assert panels.get("weather").to_response() == {
|
||||
"component_name": "iframe",
|
||||
"config": {"url": "https://www.wunderground.com/us/ca/san-diego"},
|
||||
"config_panel_domain": None,
|
||||
"icon": "mdi:weather",
|
||||
"title": "Weather",
|
||||
"url_path": "weather",
|
||||
|
@ -72,6 +74,7 @@ async def test_correct_config(hass: HomeAssistant) -> None:
|
|||
assert panels.get("api").to_response() == {
|
||||
"component_name": "iframe",
|
||||
"config": {"url": "/api"},
|
||||
"config_panel_domain": None,
|
||||
"icon": "mdi:weather",
|
||||
"title": "Api",
|
||||
"url_path": "api",
|
||||
|
@ -81,6 +84,7 @@ async def test_correct_config(hass: HomeAssistant) -> None:
|
|||
assert panels.get("ftp").to_response() == {
|
||||
"component_name": "iframe",
|
||||
"config": {"url": "ftp://some/ftp"},
|
||||
"config_panel_domain": None,
|
||||
"icon": "mdi:weather",
|
||||
"title": "FTP",
|
||||
"url_path": "ftp",
|
||||
|
|
Loading…
Reference in New Issue