From 19545f29dcaacc9c47a863988ed7ea1720f00bfc Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Wed, 25 Feb 2026 16:37:15 +0100 Subject: [PATCH] Use show in sidebar property instead of removing panel title and icon (#164025) --- homeassistant/components/frontend/__init__.py | 31 ++++++++++++------- homeassistant/components/lovelace/__init__.py | 7 ++--- tests/components/frontend/test_init.py | 23 ++++++++------ tests/components/hassio/test_init.py | 2 ++ 4 files changed, 37 insertions(+), 26 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index e8ab7acae4a2..6531f80ddaf4 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -297,6 +297,9 @@ class Panel: # If the panel should only be visible to admins require_admin = False + # If the panel should be shown in the sidebar + show_in_sidebar = True + # If the panel is a configuration panel for a integration config_panel_domain: str | None = None @@ -310,6 +313,7 @@ class Panel: config: dict[str, Any] | None, require_admin: bool, config_panel_domain: str | None, + show_in_sidebar: bool, ) -> None: """Initialize a built-in panel.""" self.component_name = component_name @@ -319,6 +323,7 @@ class Panel: self.config = config self.require_admin = require_admin self.config_panel_domain = config_panel_domain + self.show_in_sidebar = show_in_sidebar self.sidebar_default_visible = sidebar_default_visible @callback @@ -335,18 +340,17 @@ class Panel: "url_path": self.frontend_url_path, "require_admin": self.require_admin, "config_panel_domain": self.config_panel_domain, + "show_in_sidebar": self.show_in_sidebar, } if config_override: if "require_admin" in config_override: response["require_admin"] = config_override["require_admin"] - if config_override.get("show_in_sidebar") is False: - response["title"] = None - response["icon"] = None - else: - if "icon" in config_override: - response["icon"] = config_override["icon"] - if "title" in config_override: - response["title"] = config_override["title"] + if "show_in_sidebar" in config_override: + response["show_in_sidebar"] = config_override["show_in_sidebar"] + if "icon" in config_override: + response["icon"] = config_override["icon"] + if "title" in config_override: + response["title"] = config_override["title"] return response @@ -364,6 +368,7 @@ def async_register_built_in_panel( *, update: bool = False, config_panel_domain: str | None = None, + show_in_sidebar: bool = True, ) -> None: """Register a built-in panel.""" panel = Panel( @@ -375,6 +380,7 @@ def async_register_built_in_panel( config, require_admin, config_panel_domain, + show_in_sidebar, ) panels = hass.data.setdefault(DATA_PANELS, {}) @@ -570,28 +576,28 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: "light", sidebar_icon="mdi:lamps", sidebar_title="light", - sidebar_default_visible=False, + show_in_sidebar=False, ) async_register_built_in_panel( hass, "security", sidebar_icon="mdi:security", sidebar_title="security", - sidebar_default_visible=False, + show_in_sidebar=False, ) async_register_built_in_panel( hass, "climate", sidebar_icon="mdi:home-thermometer", sidebar_title="climate", - sidebar_default_visible=False, + show_in_sidebar=False, ) async_register_built_in_panel( hass, "home", sidebar_icon="mdi:home", sidebar_title="home", - sidebar_default_visible=False, + show_in_sidebar=False, ) async_register_built_in_panel(hass, "profile") @@ -1085,3 +1091,4 @@ class PanelResponse(TypedDict): url_path: str require_admin: bool config_panel_domain: str | None + show_in_sidebar: bool diff --git a/homeassistant/components/lovelace/__init__.py b/homeassistant/components/lovelace/__init__.py index 295042405ee7..1513d1a68699 100644 --- a/homeassistant/components/lovelace/__init__.py +++ b/homeassistant/components/lovelace/__init__.py @@ -353,14 +353,13 @@ def _register_panel( kwargs = { "frontend_url_path": url_path, "require_admin": config[CONF_REQUIRE_ADMIN], + "show_in_sidebar": config[CONF_SHOW_IN_SIDEBAR], + "sidebar_title": config[CONF_TITLE], + "sidebar_icon": config.get(CONF_ICON, DEFAULT_ICON), "config": {"mode": mode}, "update": update, } - if config[CONF_SHOW_IN_SIDEBAR]: - kwargs["sidebar_title"] = config[CONF_TITLE] - kwargs["sidebar_icon"] = config.get(CONF_ICON, DEFAULT_ICON) - frontend.async_register_built_in_panel(hass, DOMAIN, **kwargs) diff --git a/tests/components/frontend/test_init.py b/tests/components/frontend/test_init.py index dc5a8cbabd08..d861721d28c1 100644 --- a/tests/components/frontend/test_init.py +++ b/tests/components/frontend/test_init.py @@ -1268,7 +1268,7 @@ async def test_update_panel_partial( assert msg["result"]["climate"]["title"] == "HVAC" assert msg["result"]["climate"]["icon"] == "mdi:home-thermometer" assert msg["result"]["climate"]["require_admin"] is False - assert msg["result"]["climate"]["default_visible"] is False + assert msg["result"]["climate"]["default_visible"] is True async def test_update_panel_not_found(ws_client: MockHAClientWebSocket) -> None: @@ -1376,35 +1376,37 @@ async def test_update_panel_reset_param( assert msg["result"]["security"]["icon"] == "mdi:security" -async def test_update_panel_hide_sidebar( +async def test_update_panel_toggle_show_in_sidebar( hass: HomeAssistant, ws_client: MockHAClientWebSocket ) -> None: - """Test that show_in_sidebar=false clears title and icon like lovelace.""" + """Test that show_in_sidebar is returned without altering title and icon.""" # Verify initial state has title and icon await ws_client.send_json({"id": 1, "type": "get_panels"}) msg = await ws_client.receive_json() assert msg["result"]["light"]["title"] == "light" assert msg["result"]["light"]["icon"] == "mdi:lamps" + assert msg["result"]["light"]["show_in_sidebar"] is False - # Hide from sidebar + # Show in sidebar await ws_client.send_json( { "id": 2, "type": "frontend/update_panel", "url_path": "light", - "show_in_sidebar": False, + "show_in_sidebar": True, } ) msg = await ws_client.receive_json() assert msg["success"] - # Title and icon should be None + # Title and icon should remain unchanged and show_in_sidebar should be True await ws_client.send_json({"id": 3, "type": "get_panels"}) msg = await ws_client.receive_json() - assert msg["result"]["light"]["title"] is None - assert msg["result"]["light"]["icon"] is None + assert msg["result"]["light"]["title"] == "light" + assert msg["result"]["light"]["icon"] == "mdi:lamps" + assert msg["result"]["light"]["show_in_sidebar"] is True - # Show in sidebar again by resetting show_in_sidebar + # Reset show_in_sidebar to panel default await ws_client.send_json( { "id": 4, @@ -1416,11 +1418,12 @@ async def test_update_panel_hide_sidebar( msg = await ws_client.receive_json() assert msg["success"] - # Title and icon should be restored + # show_in_sidebar should be restored to built-in default await ws_client.send_json({"id": 5, "type": "get_panels"}) msg = await ws_client.receive_json() assert msg["result"]["light"]["title"] == "light" assert msg["result"]["light"]["icon"] == "mdi:lamps" + assert msg["result"]["light"]["show_in_sidebar"] is False async def test_panels_config_invalid_storage( diff --git a/tests/components/hassio/test_init.py b/tests/components/hassio/test_init.py index d9ff4362609c..b6295feda10d 100644 --- a/tests/components/hassio/test_init.py +++ b/tests/components/hassio/test_init.py @@ -260,6 +260,7 @@ async def test_setup_api_panel( }, "url_path": "hassio", "require_admin": True, + "show_in_sidebar": True, "config_panel_domain": None, } @@ -281,6 +282,7 @@ async def test_setup_app_panel(hass: HomeAssistant) -> None: "config": None, "url_path": "app", "require_admin": False, + "show_in_sidebar": True, "config_panel_domain": None, }