diff --git a/homeassistant/components/panel_custom.py b/homeassistant/components/panel_custom.py index 473d44f3b55..4659578ae27 100644 --- a/homeassistant/components/panel_custom.py +++ b/homeassistant/components/panel_custom.py @@ -4,7 +4,6 @@ Register a custom front end panel. For more details about this component, please refer to the documentation at https://home-assistant.io/components/panel_custom/ """ -import asyncio import logging import os @@ -21,27 +20,33 @@ CONF_SIDEBAR_ICON = 'sidebar_icon' CONF_URL_PATH = 'url_path' CONF_CONFIG = 'config' CONF_WEBCOMPONENT_PATH = 'webcomponent_path' +CONF_JS_URL = 'js_url' +CONF_EMBED_IFRAME = 'embed_iframe' +CONF_TRUST_EXTERNAL_SCRIPT = 'trust_external_script' DEFAULT_ICON = 'mdi:bookmark' +LEGACY_URL = '/api/panel_custom/{}' PANEL_DIR = 'panels' CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.All(cv.ensure_list, [{ - vol.Required(CONF_COMPONENT_NAME): cv.slug, + DOMAIN: vol.All(cv.ensure_list, [vol.Schema({ + vol.Required(CONF_COMPONENT_NAME): cv.string, vol.Optional(CONF_SIDEBAR_TITLE): cv.string, vol.Optional(CONF_SIDEBAR_ICON, default=DEFAULT_ICON): cv.icon, vol.Optional(CONF_URL_PATH): cv.string, - vol.Optional(CONF_CONFIG): cv.match_all, + vol.Optional(CONF_CONFIG): dict, vol.Optional(CONF_WEBCOMPONENT_PATH): cv.isfile, - }]) + vol.Optional(CONF_JS_URL): cv.string, + vol.Optional(CONF_EMBED_IFRAME, default=False): cv.boolean, + vol.Optional(CONF_TRUST_EXTERNAL_SCRIPT, default=False): cv.boolean, + })]) }, extra=vol.ALLOW_EXTRA) _LOGGER = logging.getLogger(__name__) -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Initialize custom panel.""" success = False @@ -52,17 +57,39 @@ def async_setup(hass, config): if panel_path is None: panel_path = hass.config.path(PANEL_DIR, '{}.html'.format(name)) - if not os.path.isfile(panel_path): + custom_panel_config = { + 'name': name, + 'embed_iframe': panel[CONF_EMBED_IFRAME], + 'trust_external': panel[CONF_TRUST_EXTERNAL_SCRIPT], + } + + if CONF_JS_URL in panel: + custom_panel_config['js_url'] = panel[CONF_JS_URL] + + elif not await hass.async_add_job(os.path.isfile, panel_path): _LOGGER.error('Unable to find webcomponent for %s: %s', name, panel_path) continue - yield from hass.components.frontend.async_register_panel( - name, panel_path, + else: + url = LEGACY_URL.format(name) + hass.http.register_static_path(url, panel_path) + custom_panel_config['html_url'] = LEGACY_URL.format(name) + + if CONF_CONFIG in panel: + # Make copy because we're mutating it + config = dict(panel[CONF_CONFIG]) + else: + config = {} + + config['_panel_custom'] = custom_panel_config + + await hass.components.frontend.async_register_built_in_panel( + component_name='custom', sidebar_title=panel.get(CONF_SIDEBAR_TITLE), sidebar_icon=panel.get(CONF_SIDEBAR_ICON), frontend_url_path=panel.get(CONF_URL_PATH), - config=panel.get(CONF_CONFIG), + config=config ) success = True diff --git a/tests/components/test_panel_custom.py b/tests/components/test_panel_custom.py index d33221da2a7..596aa1b3c0b 100644 --- a/tests/components/test_panel_custom.py +++ b/tests/components/test_panel_custom.py @@ -1,23 +1,11 @@ """The tests for the panel_custom component.""" -import asyncio from unittest.mock import Mock, patch -import pytest - from homeassistant import setup from homeassistant.components import frontend -from tests.common import mock_component - -@pytest.fixture(autouse=True) -def mock_frontend_loaded(hass): - """Mock frontend is loaded.""" - mock_component(hass, 'frontend') - - -@asyncio.coroutine -def test_webcomponent_custom_path_not_found(hass): +async def test_webcomponent_custom_path_not_found(hass): """Test if a web component is found in config panels dir.""" filename = 'mock.file' @@ -33,45 +21,96 @@ def test_webcomponent_custom_path_not_found(hass): } with patch('os.path.isfile', Mock(return_value=False)): - result = yield from setup.async_setup_component( + result = await setup.async_setup_component( hass, 'panel_custom', config ) assert not result assert len(hass.data.get(frontend.DATA_PANELS, {})) == 0 -@asyncio.coroutine -def test_webcomponent_custom_path(hass): +async def test_webcomponent_custom_path(hass): """Test if a web component is found in config panels dir.""" filename = 'mock.file' config = { 'panel_custom': { - 'name': 'todomvc', + 'name': 'todo-mvc', 'webcomponent_path': filename, 'sidebar_title': 'Sidebar Title', 'sidebar_icon': 'mdi:iconicon', 'url_path': 'nice_url', - 'config': 5, + 'config': { + 'hello': 'world', + } } } with patch('os.path.isfile', Mock(return_value=True)): with patch('os.access', Mock(return_value=True)): - result = yield from setup.async_setup_component( + result = await setup.async_setup_component( hass, 'panel_custom', config ) assert result panels = hass.data.get(frontend.DATA_PANELS, []) - assert len(panels) == 1 + assert panels assert 'nice_url' in panels panel = panels['nice_url'] - assert panel.config == 5 + assert panel.config == { + 'hello': 'world', + '_panel_custom': { + 'html_url': '/api/panel_custom/todo-mvc', + 'name': 'todo-mvc', + 'embed_iframe': False, + 'trust_external': False, + }, + } assert panel.frontend_url_path == 'nice_url' assert panel.sidebar_icon == 'mdi:iconicon' assert panel.sidebar_title == 'Sidebar Title' - assert panel.path == filename + + +async def test_js_webcomponent(hass): + """Test if a web component is found in config panels dir.""" + config = { + 'panel_custom': { + 'name': 'todo-mvc', + 'js_url': '/local/bla.js', + 'sidebar_title': 'Sidebar Title', + 'sidebar_icon': 'mdi:iconicon', + 'url_path': 'nice_url', + 'config': { + 'hello': 'world', + }, + 'embed_iframe': True, + 'trust_external_script': True, + } + } + + result = await setup.async_setup_component( + hass, 'panel_custom', config + ) + assert result + + panels = hass.data.get(frontend.DATA_PANELS, []) + + assert panels + assert 'nice_url' in panels + + panel = panels['nice_url'] + + assert panel.config == { + 'hello': 'world', + '_panel_custom': { + 'js_url': '/local/bla.js', + 'name': 'todo-mvc', + 'embed_iframe': True, + 'trust_external': True, + } + } + assert panel.frontend_url_path == 'nice_url' + assert panel.sidebar_icon == 'mdi:iconicon' + assert panel.sidebar_title == 'Sidebar Title'