mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 15:27:33 +00:00
[web_server] Show the offline hint on a timer so a stalled download is covered too
This commit is contained in:
@@ -362,7 +362,16 @@ async def add_entity_config(entity, config):
|
||||
|
||||
|
||||
def build_index_html(config: ConfigType, offline_hint: bool = True) -> str:
|
||||
js_url = config[CONF_JS_URL]
|
||||
# The interface is downloaded from the internet. Without internet access, which is
|
||||
# common for browsers on the WiFi AP, that download fails or simply stalls and the
|
||||
# page stays blank. Show a hint after a few seconds unless www.js has registered the
|
||||
# esp-app element; CSS hides the hint again if the interface does arrive later.
|
||||
# Kept short: it lives in flash on every build without captive_portal.
|
||||
offline_hint = offline_hint and bool(js_url)
|
||||
html = "<!DOCTYPE html><html><head><meta charset=UTF-8><link rel=icon href=data:>"
|
||||
if offline_hint:
|
||||
html += "<style>esp-app:defined+p{display:none}</style>"
|
||||
css_include = config.get(CONF_CSS_INCLUDE)
|
||||
js_include = config.get(CONF_JS_INCLUDE)
|
||||
if css_include:
|
||||
@@ -373,18 +382,15 @@ def build_index_html(config: ConfigType, offline_hint: bool = True) -> str:
|
||||
if js_include:
|
||||
html += "<script type=module src=/0.js></script>"
|
||||
html += "<esp-app></esp-app>"
|
||||
if js_url := config[CONF_JS_URL]:
|
||||
onerror = ""
|
||||
if offline_hint:
|
||||
# The interface is downloaded from the internet. Show a hint instead of a
|
||||
# blank page when the browser cannot reach it, which is common in WiFi AP
|
||||
# mode. Kept short: it lives in flash on every build without captive_portal.
|
||||
onerror = (
|
||||
" onerror=\"document.body.innerText='Could not download the web interface. "
|
||||
"This browser needs internet access, or set local: true under web_server: "
|
||||
"in the YAML.'\""
|
||||
)
|
||||
html += f'<script src="{js_url}"{onerror}></script>'
|
||||
if offline_hint:
|
||||
html += (
|
||||
"<p hidden>The web interface is not loading. This browser needs internet "
|
||||
"access to download it, or set local: true under web_server: in the YAML.</p>"
|
||||
"<script>setTimeout(function(){document.querySelector('p').hidden=0},5e3)"
|
||||
"</script>"
|
||||
)
|
||||
if js_url:
|
||||
html += f'<script src="{js_url}"></script>'
|
||||
html += "</body></html>"
|
||||
return html
|
||||
|
||||
|
||||
@@ -23,24 +23,29 @@ JS_URL = "https://oi.esphome.io/v2/www.js"
|
||||
|
||||
|
||||
def test_build_index_html_has_offline_hint() -> None:
|
||||
"""The hosted script tag shows a hint when the browser cannot download it."""
|
||||
"""A hidden hint is shown after a timeout unless www.js registered esp-app."""
|
||||
html = build_index_html({CONF_JS_URL: JS_URL, CONF_CSS_URL: ""})
|
||||
assert f'<script src="{JS_URL}" onerror="' in html
|
||||
assert "document.body.innerText='Could not download the web interface." in html
|
||||
assert "<style>esp-app:defined+p{display:none}</style>" in html
|
||||
assert "<esp-app></esp-app><p hidden>The web interface is not loading." in html
|
||||
assert "local: true" in html
|
||||
assert "<script>setTimeout(function(){document.querySelector('p').hidden=0}" in html
|
||||
# The hint script must come before the hosted script, which may never finish loading
|
||||
assert html.index("setTimeout") < html.index(f'<script src="{JS_URL}">')
|
||||
|
||||
|
||||
def test_build_index_html_hint_disabled() -> None:
|
||||
"""The plain script tag is kept when the hint is not wanted (captive_portal)."""
|
||||
"""Plain page when the hint is not wanted (captive_portal)."""
|
||||
html = build_index_html({CONF_JS_URL: JS_URL, CONF_CSS_URL: ""}, offline_hint=False)
|
||||
assert f'<script src="{JS_URL}"></script>' in html
|
||||
assert "onerror" not in html
|
||||
assert f'<esp-app></esp-app><script src="{JS_URL}"></script>' in html
|
||||
assert "<p" not in html
|
||||
assert "<style>" not in html
|
||||
|
||||
|
||||
def test_build_index_html_without_js_url() -> None:
|
||||
"""No hosted script and no hint when js_url is empty."""
|
||||
html = build_index_html({CONF_JS_URL: "", CONF_CSS_URL: ""})
|
||||
assert "<script" not in html
|
||||
assert "<p" not in html
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
||||
Reference in New Issue
Block a user