dashboard: rebuild the page on Bootstrap 5 + jQuery + Chart.js + Font Awesome
One card per timeframe (M5/M15/H1/H4) in a Bootstrap column grid, above a direction board that charts every timeframe's score as a diverging bar. Each card carries its own indicator-vote chart, and the newswire gets a headline-tone bar. Bootstrap Icons and the hand-rolled CSS gauges are gone; dashboard.css is now the token set plus the app-specific pieces only. Chart marks use a diverging pair validated on this surface (#0d9f7a / #e8503a: lightness band, chroma floor, colour-vision separation, contrast). Lighter steps of the same two hues carry the colour where it has to work as text, and direction never travels as colour alone -- an arrow icon and the word ride with it. Behaviour is unchanged: same snapshot.json / news.json contract, the same coordinated refresh loop (boundary poll, 60 s fallback, 15 s retry, in-flight guard, stale-snapshot guard), per-timeframe change detection, modal state preservation, HTML escaping, the news_summary.php contract and the warming / scan-failed / weekend states. Nothing on the signal path is touched, so no book moves. Verified headlessly against a fixture replayed through the real signal code (wide / laptop / tablet / mobile, both dialogs, every degraded state): no console errors, html-validate clean. Suite 553 -- the old static-UI test splits into one that pins the CDN stack and one that pins a card and a chart per timeframe against dashboard_publisher.DASHBOARD_TFS. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+31
-4
@@ -5496,18 +5496,45 @@ def _():
|
||||
["dashboard.css", "dashboard.html", "dashboard.js", "news_summary.php"] # all installed, no .tmp
|
||||
|
||||
|
||||
@test("dashboard: static UI uses CSS gauges and a coordinated refresh loop")
|
||||
@test("dashboard: static UI is Bootstrap + jQuery + Chart.js on a CDN")
|
||||
def _():
|
||||
# The page is served as-is (no build step), so its four libraries are
|
||||
# pinned <script>/<link> tags. Only jsdelivr and cdnjs are allowed.
|
||||
import re
|
||||
static_dir = os.path.join(os.path.dirname(__file__), "static")
|
||||
with open(os.path.join(static_dir, "dashboard.html"), encoding="utf-8") as fh:
|
||||
html = fh.read()
|
||||
for needle in ("bootstrap@5.3", "bootstrap.bundle.min.js", "jquery@3.7",
|
||||
"chart.js@4.4", "font-awesome/6."):
|
||||
assert needle in html, needle
|
||||
assert "gauge.js" not in html # no local charting script survives
|
||||
from urllib.parse import urlsplit
|
||||
for url in re.findall(r'(?:src|href)="(https?://[^"]+)"', html):
|
||||
assert urlsplit(url).netloc in {
|
||||
"cdn.jsdelivr.net", "cdnjs.cloudflare.com",
|
||||
"fonts.googleapis.com", "fonts.gstatic.com"}, url
|
||||
|
||||
|
||||
@test("dashboard: one card and one chart per timeframe, coordinated refresh")
|
||||
def _():
|
||||
import re
|
||||
static_dir = os.path.join(os.path.dirname(__file__), "static")
|
||||
with open(os.path.join(static_dir, "dashboard.html"), encoding="utf-8") as fh:
|
||||
html = fh.read()
|
||||
with open(os.path.join(static_dir, "dashboard.js"), encoding="utf-8") as fh:
|
||||
js = fh.read()
|
||||
assert "chart.js" not in html.lower()
|
||||
assert "gauge.js" not in html
|
||||
# The four dashboard timeframes render as Bootstrap columns inside one
|
||||
# row, each card carrying its own indicator canvas.
|
||||
assert 'id="tf-grid"' in html and "row-cols-" in html
|
||||
assert 'id="chart-direction"' in html and 'id="chart-tone"' in html
|
||||
assert 'id="ind-${tf}"' in js and "cardShell" in js
|
||||
assert [tf.value for tf in dpub.DASHBOARD_TFS] == \
|
||||
re.search(r'const TF_ORDER = \[([^\]]+)\]', js).group(1) \
|
||||
.replace('"', "").replace(" ", "").split(",")
|
||||
# One coordinated refresh loop, never a polling interval.
|
||||
assert "setInterval(poll" not in js
|
||||
assert "FALLBACK_POLL_MS" in js and "pollInFlight" in js
|
||||
assert "data-select-tf" in js and "localStorage" in js
|
||||
assert "scheduleBoundaryRefresh" in js and "localStorage" in js
|
||||
|
||||
|
||||
@test("dashboard: publish is atomic and leaves no temp file")
|
||||
|
||||
Reference in New Issue
Block a user