Further cleanup frontend (#14805)

* Remove registering panels

* Remove unused image

* Lint
This commit is contained in:
Paulus Schoutsen 2018-06-05 10:50:16 -04:00 committed by GitHub
parent ad9621ebe5
commit b3b4f7468d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 168 deletions

View File

@ -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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -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')