Skip to content

Commit 6177417

Browse files
jdrumgooleclaude
andcommitted
Vendor HTMX/Pico/Chart.js so HTMX buttons work in pywebview
HTMX, Pico CSS, Chart.js and chartjs-adapter-date-fns all loaded from cdn.jsdelivr.net with an SRI hash on the HTMX script. Inside pywebview (WKWebView on macOS) the HTMX request was failing — offline-tolerant caching, an SRI mismatch on a re-built CDN file, or strict content-policy — and dropping silently. Without HTMX every HTMX button (Test MongoDB connection, Test SolisCloud, Poll SolisCloud now) clicked to nothing with no console error, which presented as "I can't click on anything in the app". Everything is now served from `src/solisdash/static/vendor/`: - pico.min.css (Pico 2) - htmx.min.js (HTMX 2.0.4) - chart.umd.min.js (Chart.js 4.4.7) - chartjs-adapter-date-fns.bundle.min.js base.html and history.html load them via `url_for('static', path='vendor/…')`. No network roundtrip on first render, no CDN dependency at runtime. Also adds `tests/test_clickability.py`: - For every authed page, extract every `<a href>`, `<form action>` and `[hx-{get,post,put,delete}]` URL pointing back at our app, then assert the endpoint doesn't 5xx (catches "I shipped a button whose handler doesn't exist" and "the handler 500s on empty input"). - Refuse any future `cdn.jsdelivr.net` / `unpkg.com` / `cdnjs.cloudflare.com` reference in a template. - Confirm all four vendored asset files are present on disk. - Refuse `pointer-events` declarations in style.css without an explicit `/* allow-pointer-events: … */` justification. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2de5fb9 commit 6177417

12 files changed

Lines changed: 297 additions & 22 deletions

‎CHANGELOG.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,27 @@ All notable changes to **Solisdash** are documented here. Version numbers
44
follow [Semantic Versioning](https://semver.org/). The package is published
55
to PyPI on every `vX.Y.Z` tag push.
66

7+
## 0.8.1 — 2026-05-16
8+
9+
### Fixed
10+
- **HTMX buttons (Test MongoDB connection, Test SolisCloud, Poll
11+
SolisCloud now) silently did nothing inside pywebview.** HTMX was
12+
loaded from a CDN with SRI; pywebview's WKWebView dropped the script
13+
in some environments (offline, strict caching, SRI mismatches) and
14+
the buttons stopped working with no visible error. Solisdash now
15+
vendors HTMX, Pico CSS, Chart.js, and the Chart.js date-fns adapter
16+
under `static/vendor/`, so the entire UI works without network access
17+
to a CDN.
18+
19+
### Added
20+
- `tests/test_clickability.py` regression suite. For every authed
21+
page (`/`, `/history`, `/alarms`, `/settings`) we extract every
22+
`<a href>`, `<form action>`, `[hx-{get,post,put,delete}]` URL
23+
pointing at our own app and assert each endpoint doesn't 5xx. The
24+
same file also asserts (a) no template references a CDN at runtime,
25+
(b) all four vendored assets are present on disk, and (c) `style.css`
26+
doesn't sneak in a `pointer-events: none` overlay.
27+
728
## 0.8.0 — 2026-05-16
829

930
### Added

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "solisdash"
3-
version = "0.8.0"
3+
version = "0.8.1"
44
description = "Self-hosted dashboard for the SolisCloud (Ginlong Solis) platform"
55
readme = "README.md"
66
requires-python = ">=3.10"

‎src/solisdash/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.8.0"
1+
__version__ = "0.8.1"

‎src/solisdash/static/vendor/chart.umd.min.js‎

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/solisdash/static/vendor/chartjs-adapter-date-fns.bundle.min.js‎

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/solisdash/static/vendor/htmx.min.js‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/solisdash/static/vendor/pico.min.css‎

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/solisdash/templates/base.html‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
<meta charset="utf-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1" />
66
<title>{% block title %}Solisdash{% endblock %}</title>
7-
<link
8-
rel="stylesheet"
9-
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
10-
/>
7+
<link rel="stylesheet" href="{{ url_for('static', path='vendor/pico.min.css') }}" />
118
<link rel="stylesheet" href="{{ url_for('static', path='style.css') }}" />
129
<script>
1310
// Apply persisted theme as early as possible to avoid a flash on load.
@@ -20,12 +17,7 @@
2017
}
2118
})();
2219
</script>
23-
<script
24-
src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.4/dist/htmx.min.js"
25-
integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+"
26-
crossorigin="anonymous"
27-
defer
28-
></script>
20+
<script src="{{ url_for('static', path='vendor/htmx.min.js') }}" defer></script>
2921
</head>
3022
<body>
3123
<header class="container">

‎src/solisdash/templates/history.html‎

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,7 @@ <h2>History</h2>
8989
</article>
9090
{% endif %}
9191

92-
<script
93-
src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"
94-
defer
95-
></script>
96-
<script
97-
src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3/dist/chartjs-adapter-date-fns.bundle.min.js"
98-
defer
99-
></script>
92+
<script src="{{ url_for('static', path='vendor/chart.umd.min.js') }}" defer></script>
93+
<script src="{{ url_for('static', path='vendor/chartjs-adapter-date-fns.bundle.min.js') }}" defer></script>
10094
<script src="{{ url_for('static', path='history.js') }}" defer></script>
10195
{% endblock %}

‎tests/test_app_history.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ async def test_history_page_renders_station_picker_and_chart_canvas(
7575
assert 'id="station-select"' in body
7676
assert "Roof" in body
7777
assert 'id="history-chart"' in body
78-
assert "chart.js" in body
78+
assert "chart.umd.min.js" in body
7979
assert "chartjs-adapter-date-fns" in body
80+
# Must be vendored under /static/vendor/ (see test_clickability.py).
81+
assert "cdn.jsdelivr.net" not in body
8082

8183

8284
async def test_history_page_renders_metric_tabs(

0 commit comments

Comments
 (0)