From b3b4f7468dd2c236f008e412664f22b66711f856 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 5 Jun 2018 10:50:16 -0400 Subject: [PATCH] Further cleanup frontend (#14805) * Remove registering panels * Remove unused image * Lint --- homeassistant/components/frontend/__init__.py | 196 ++++-------------- .../www_static/images/logo_tellduslive.png | Bin 7796 -> 0 bytes tests/components/test_frontend.py | 11 +- 3 files changed, 39 insertions(+), 168 deletions(-) delete mode 100644 homeassistant/components/frontend/www_static/images/logo_tellduslive.png diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 5dad77f64ce..3f2f9ded22a 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -5,7 +5,6 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/frontend/ """ import asyncio -import hashlib import json import logging import os @@ -30,8 +29,6 @@ REQUIREMENTS = ['home-assistant-frontend==20180603.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log'] -URL_PANEL_COMPONENT_FP = '/frontend/panels/{}-{}.html' - CONF_THEMES = 'themes' CONF_EXTRA_HTML_URL = 'extra_html_url' CONF_EXTRA_HTML_URL_ES5 = 'extra_html_url_es5' @@ -101,7 +98,7 @@ SCHEMA_GET_PANELS = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({ }) -class AbstractPanel: +class Panel: """Abstract class for panels.""" # Name of the webcomponent @@ -113,44 +110,12 @@ class AbstractPanel: # Title to show in the sidebar (optional) sidebar_title = None - # Url to the webcomponent (depending on JS version) - webcomponent_url_es5 = None - webcomponent_url_latest = None - # Url to show the panel in the frontend frontend_url_path = None # Config to pass to the webcomponent config = None - @asyncio.coroutine - def async_register(self, hass): - """Register panel with HASS.""" - panels = hass.data.get(DATA_PANELS) - if panels is None: - panels = hass.data[DATA_PANELS] = {} - - if self.frontend_url_path in panels: - _LOGGER.warning("Overwriting component %s", self.frontend_url_path) - - if DATA_FINALIZE_PANEL in hass.data: - yield from hass.data[DATA_FINALIZE_PANEL](self) - - panels[self.frontend_url_path] = self - - @callback - def async_register_index_routes(self, router, index_view): - """Register routes for panel to be served by index view.""" - router.add_route( - 'get', '/{}'.format(self.frontend_url_path), index_view.get) - router.add_route( - 'get', '/{}/{{extra:.+}}'.format(self.frontend_url_path), - index_view.get) - - -class BuiltInPanel(AbstractPanel): - """Panel that is part of hass_frontend.""" - def __init__(self, component_name, sidebar_title, sidebar_icon, frontend_url_path, config): """Initialize a built-in panel.""" @@ -160,6 +125,16 @@ class BuiltInPanel(AbstractPanel): self.frontend_url_path = frontend_url_path or component_name self.config = config + @callback + def async_register_index_routes(self, router, index_view): + """Register routes for panel to be served by index view.""" + router.add_route( + 'get', '/{}'.format(self.frontend_url_path), index_view.get) + router.add_route( + 'get', '/{}/{{extra:.+}}'.format(self.frontend_url_path), + index_view.get) + + @callback def to_response(self, hass, request): """Panel as dictionary.""" return { @@ -171,95 +146,25 @@ class BuiltInPanel(AbstractPanel): } -class ExternalPanel(AbstractPanel): - """Panel that is added by a custom component.""" - - REGISTERED_COMPONENTS = set() - - def __init__(self, component_name, path, md5, sidebar_title, sidebar_icon, - frontend_url_path, config): - """Initialize an external panel.""" - self.component_name = component_name - self.path = path - self.md5 = md5 - self.sidebar_title = sidebar_title - self.sidebar_icon = sidebar_icon - self.frontend_url_path = frontend_url_path or component_name - self.config = config - - @asyncio.coroutine - def async_finalize(self, hass, frontend_repository_path): - """Finalize this panel for usage. - - frontend_repository_path is set, will be prepended to path of built-in - components. - """ - try: - if self.md5 is None: - self.md5 = yield from hass.async_add_job( - _fingerprint, self.path) - except OSError: - _LOGGER.error('Cannot find or access %s at %s', - self.component_name, self.path) - hass.data[DATA_PANELS].pop(self.frontend_url_path) - return - - self.webcomponent_url_es5 = self.webcomponent_url_latest = \ - URL_PANEL_COMPONENT_FP.format(self.component_name, self.md5) - - if self.component_name not in self.REGISTERED_COMPONENTS: - hass.http.register_static_path( - self.webcomponent_url_latest, self.path, - # if path is None, we're in prod mode, so cache static assets - frontend_repository_path is None) - self.REGISTERED_COMPONENTS.add(self.component_name) - - def to_response(self, hass, request): - """Panel as dictionary.""" - result = { - 'component_name': self.component_name, - 'icon': self.sidebar_icon, - 'title': self.sidebar_title, - 'url_path': self.frontend_url_path, - 'config': self.config, - } - if _is_latest(hass.data[DATA_JS_VERSION], request): - result['url'] = self.webcomponent_url_latest - else: - result['url'] = self.webcomponent_url_es5 - return result - - @bind_hass -@asyncio.coroutine -def async_register_built_in_panel(hass, component_name, sidebar_title=None, - sidebar_icon=None, frontend_url_path=None, - config=None): +async def async_register_built_in_panel(hass, component_name, + sidebar_title=None, sidebar_icon=None, + frontend_url_path=None, config=None): """Register a built-in panel.""" - panel = BuiltInPanel(component_name, sidebar_title, sidebar_icon, - frontend_url_path, config) - yield from panel.async_register(hass) + panel = Panel(component_name, sidebar_title, sidebar_icon, + frontend_url_path, config) + panels = hass.data.get(DATA_PANELS) + if panels is None: + panels = hass.data[DATA_PANELS] = {} -@bind_hass -@asyncio.coroutine -def async_register_panel(hass, component_name, path, md5=None, - sidebar_title=None, sidebar_icon=None, - frontend_url_path=None, config=None): - """Register a panel for the frontend. + if panel.frontend_url_path in panels: + _LOGGER.warning("Overwriting component %s", panel.frontend_url_path) - component_name: name of the web component - path: path to the HTML of the web component - (required unless url is provided) - md5: the md5 hash of the web component (for versioning in URL, optional) - sidebar_title: title to show in the sidebar (optional) - sidebar_icon: icon to show next to title in sidebar (optional) - url_path: name to use in the URL (defaults to component_name) - config: config to be passed into the web component - """ - panel = ExternalPanel(component_name, path, md5, sidebar_title, - sidebar_icon, frontend_url_path, config) - yield from panel.async_register(hass) + if DATA_FINALIZE_PANEL in hass.data: + hass.data[DATA_FINALIZE_PANEL](panel) + + panels[panel.frontend_url_path] = panel @bind_hass @@ -278,11 +183,10 @@ def add_manifest_json_key(key, val): MANIFEST_JSON[key] = val -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Set up the serving of the frontend.""" if list(hass.auth.async_auth_providers): - client = yield from hass.auth.async_create_client( + client = await hass.auth.async_create_client( 'Home Assistant Frontend', redirect_uris=['/'], no_secret=True, @@ -331,24 +235,22 @@ def async_setup(hass, config): index_view = IndexView(repo_path, js_version, client) hass.http.register_view(index_view) - async def finalize_panel(panel): + @callback + def async_finalize_panel(panel): """Finalize setup of a panel.""" - if hasattr(panel, 'async_finalize'): - await panel.async_finalize(hass, repo_path) panel.async_register_index_routes(hass.http.app.router, index_view) - yield from asyncio.wait([ + await asyncio.wait([ async_register_built_in_panel(hass, panel) for panel in ('dev-event', 'dev-info', 'dev-service', 'dev-state', 'dev-template', 'dev-mqtt', 'kiosk')], loop=hass.loop) - hass.data[DATA_FINALIZE_PANEL] = finalize_panel + hass.data[DATA_FINALIZE_PANEL] = async_finalize_panel # Finalize registration of panels that registered before frontend was setup # This includes the built-in panels from line above. - yield from asyncio.wait( - [finalize_panel(panel) for panel in hass.data[DATA_PANELS].values()], - loop=hass.loop) + for panel in hass.data[DATA_PANELS].values(): + async_finalize_panel(panel) if DATA_EXTRA_HTML_URL not in hass.data: hass.data[DATA_EXTRA_HTML_URL] = set() @@ -456,38 +358,23 @@ class IndexView(HomeAssistantView): return tpl - @asyncio.coroutine - def get(self, request, extra=None): + async def get(self, request, extra=None): """Serve the index view.""" hass = request.app['hass'] latest = self.repo_path is not None or \ _is_latest(self.js_option, request) - if request.path == '/': - panel = 'states' - else: - panel = request.path.split('/')[1] - - if panel == 'states': - panel_url = '' - elif latest: - panel_url = hass.data[DATA_PANELS][panel].webcomponent_url_latest - else: - panel_url = hass.data[DATA_PANELS][panel].webcomponent_url_es5 - no_auth = '1' if hass.config.api.api_password and not request[KEY_AUTHENTICATED]: # do not try to auto connect on load no_auth = '0' - template = yield from hass.async_add_job(self.get_template, latest) + template = await hass.async_add_job(self.get_template, latest) extra_key = DATA_EXTRA_HTML_URL if latest else DATA_EXTRA_HTML_URL_ES5 template_params = dict( no_auth=no_auth, - panel_url=panel_url, - panels=hass.data[DATA_PANELS], theme_color=MANIFEST_JSON['theme_color'], extra_urls=hass.data[extra_key], ) @@ -506,7 +393,7 @@ class ManifestJSONView(HomeAssistantView): url = '/manifest.json' name = 'manifestjson' - @asyncio.coroutine + @callback def get(self, request): # pylint: disable=no-self-use """Return the manifest.json.""" msg = json.dumps(MANIFEST_JSON, sort_keys=True) @@ -537,23 +424,16 @@ class TranslationsView(HomeAssistantView): url = '/api/translations/{language}' name = 'api:translations' - @asyncio.coroutine - def get(self, request, language): + async def get(self, request, language): """Return translations.""" hass = request.app['hass'] - resources = yield from async_get_translations(hass, language) + resources = await async_get_translations(hass, language) return self.json({ 'resources': resources, }) -def _fingerprint(path): - """Fingerprint a file.""" - with open(path) as fil: - return hashlib.md5(fil.read().encode('utf-8')).hexdigest() - - def _is_latest(js_option, request): """ Return whether we should serve latest untranspiled code. diff --git a/homeassistant/components/frontend/www_static/images/logo_tellduslive.png b/homeassistant/components/frontend/www_static/images/logo_tellduslive.png deleted file mode 100644 index 7ea78f8ef3aad4d3cd982835c797693a68264c00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7796 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 diff --git a/tests/components/test_frontend.py b/tests/components/test_frontend.py index 657497b868b..2f83d923e2b 100644 --- a/tests/components/test_frontend.py +++ b/tests/components/test_frontend.py @@ -8,7 +8,7 @@ import pytest from homeassistant.setup import async_setup_component from homeassistant.components.frontend import ( DOMAIN, CONF_JS_VERSION, CONF_THEMES, CONF_EXTRA_HTML_URL, - CONF_EXTRA_HTML_URL_ES5, DATA_PANELS) + CONF_EXTRA_HTML_URL_ES5) from homeassistant.components import websocket_api as wapi @@ -183,15 +183,6 @@ def test_extra_urls_es5(mock_http_client_with_urls): assert text.find('href="https://domain.com/my_extra_url_es5.html"') >= 0 -@asyncio.coroutine -def test_panel_without_path(hass): - """Test panel registration without file path.""" - yield from hass.components.frontend.async_register_panel( - 'test_component', 'nonexistant_file') - yield from async_setup_component(hass, 'frontend', {}) - assert 'test_component' not in hass.data[DATA_PANELS] - - async def test_get_panels(hass, hass_ws_client): """Test get_panels command.""" await async_setup_component(hass, 'frontend')