Add panel custom to load any webcomponent (#2747)

pull/2759/head
Paulus Schoutsen 2016-08-08 17:35:46 -07:00 committed by GitHub
parent 9a575eb6d6
commit 8081fe794e
5 changed files with 161 additions and 31 deletions

4
.gitignore vendored
View File

@ -7,7 +7,9 @@ config/custom_components/*
!config/custom_components/example.py
!config/custom_components/hello_world.py
!config/custom_components/mqtt_example.py
!config/custom_components/react_panel
!config/panels
config/panels/*
!config/panels/react.html
tests/testing_config/deps
tests/testing_config/home-assistant.log

View File

@ -1,30 +0,0 @@
"""
Custom panel example showing TodoMVC using React.
Will add a panel to control lights and switches using React. Allows configuring
the title via configuration.yaml:
react_panel:
title: 'home'
"""
import os
from homeassistant.components.frontend import register_panel
DOMAIN = 'react_panel'
DEPENDENCIES = ['frontend']
PANEL_PATH = os.path.join(os.path.dirname(__file__), 'panel.html')
def setup(hass, config):
"""Initialize custom panel."""
title = config.get(DOMAIN, {}).get('title')
config = None if title is None else {'title': title}
register_panel(hass, 'react', PANEL_PATH,
title='TodoMVC', icon='mdi:checkbox-marked-outline',
config=config)
return True

View File

@ -1,3 +1,20 @@
<!--
Custom Home Assistant panel example.
Currently only works in Firefox and Chrome because it uses ES6.
Make sure this file is in <config>/panels/react.html
Add to your configuration.yaml:
panel_custom:
- name: react
sidebar_title: TodoMVC
sidebar_icon: mdi:checkbox-marked-outline
config:
title: Wow hello!
-->
<script src="https://fb.me/react-15.2.1.min.js"></script>
<script src="https://fb.me/react-dom-15.2.1.min.js"></script>

View File

@ -0,0 +1,64 @@
"""Register a custom front end panel."""
import logging
import os
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.frontend import register_panel
DOMAIN = 'panel_custom'
DEPENDENCIES = ['frontend']
CONF_COMPONENT_NAME = 'name'
CONF_SIDEBAR_TITLE = 'sidebar_title'
CONF_SIDEBAR_ICON = 'sidebar_icon'
CONF_URL_PATH = 'url_path'
CONF_CONFIG = 'config'
CONF_WEBCOMPONENT_PATH = 'webcomponent_path'
DEFAULT_ICON = 'mdi:bookmark'
PANEL_DIR = 'panels'
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.All(cv.ensure_list, [{
vol.Required(CONF_COMPONENT_NAME): cv.slug,
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_WEBCOMPONENT_PATH): cv.isfile,
}])
}, extra=vol.ALLOW_EXTRA)
_LOGGER = logging.getLogger(__name__)
def setup(hass, config):
"""Initialize custom panel."""
success = False
for panel in config.get(DOMAIN):
name = panel.get(CONF_COMPONENT_NAME)
panel_path = panel.get(CONF_WEBCOMPONENT_PATH)
if panel_path is None:
panel_path = hass.config.path(PANEL_DIR, '{}.html'.format(name))
if not os.path.isfile(panel_path):
_LOGGER.error('Unable to find webcomponent for %s: %s',
name, panel_path)
continue
register_panel(
hass, name, panel_path,
sidebar_title=panel.get(CONF_SIDEBAR_TITLE),
sidebar_icon=panel.get(CONF_SIDEBAR_ICON),
url_path=panel.get(CONF_URL_PATH),
config=panel.get(CONF_CONFIG),
)
success = True
return success

View File

@ -0,0 +1,77 @@
"""The tests for the panel_custom component."""
import os
import shutil
from tempfile import NamedTemporaryFile
import unittest
from unittest.mock import patch
from homeassistant import bootstrap
from homeassistant.components import panel_custom
from tests.common import get_test_home_assistant
@patch('homeassistant.components.frontend.setup', return_value=True)
class TestPanelCustom(unittest.TestCase):
"""Test the panel_custom component."""
def setup_method(self, method):
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
def teardown_method(self, method):
"""Stop everything that was started."""
self.hass.stop()
shutil.rmtree(self.hass.config.path(panel_custom.PANEL_DIR),
ignore_errors=True)
@patch('homeassistant.components.panel_custom.register_panel')
def test_webcomponent_in_panels_dir(self, mock_register, _mock_setup):
"""Test if a web component is found in config panels dir."""
config = {
'panel_custom': {
'name': 'todomvc',
}
}
assert not bootstrap.setup_component(self.hass, 'panel_custom', config)
assert not mock_register.called
path = self.hass.config.path(panel_custom.PANEL_DIR)
os.mkdir(path)
with open(os.path.join(path, 'todomvc.html'), 'a'):
assert bootstrap.setup_component(self.hass, 'panel_custom', config)
assert mock_register.called
@patch('homeassistant.components.panel_custom.register_panel')
def test_webcomponent_custom_path(self, mock_register, _mock_setup):
"""Test if a web component is found in config panels dir."""
with NamedTemporaryFile() as fp:
config = {
'panel_custom': {
'name': 'todomvc',
'webcomponent_path': fp.name,
'sidebar_title': 'Sidebar Title',
'sidebar_icon': 'mdi:iconicon',
'url_path': 'nice_url',
'config': 5,
}
}
with patch('os.path.isfile', return_value=False):
assert not bootstrap.setup_component(self.hass, 'panel_custom',
config)
assert not mock_register.called
assert bootstrap.setup_component(self.hass, 'panel_custom', config)
assert mock_register.called
args = mock_register.mock_calls[0][1]
kwargs = mock_register.mock_calls[0][2]
assert args == (self.hass, 'todomvc', fp.name)
assert kwargs == {
'config': 5,
'url_path': 'nice_url',
'sidebar_icon': 'mdi:iconicon',
'sidebar_title': 'Sidebar Title'
}