Portal look: aligned header and footer, 7-day chart, today's reasons, pass rate

Header, breadcrumb, page and footer share one 1180px column; the header
marks the current page; a footer sits at the bottom of every page.
Dashboard: pass rate on Checked today, a Last 7 days Pass / Fail / Review
chart, today's Fail and Review reasons grouped with counts, and three
equal cards (Claim status, Runs, Find a claim). Motion is movement only
and off under prefers-reduced-motion. Context.md brought up to date.

Snapshot of local 9d5ac63 (tree scanned: no real claim ids, no patient
data).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ManikandanandClaude Opus 5.5 committed 2026-10-26 13:06:52 +05:30
1 parent ba15a574ab
commit 120fd6808a
5 files changed
+295 -39

No files matched your search

+20 -2
View File
@@ -31,7 +31,8 @@ import sys
import html
import json
import pathlib
from datetime import date, datetime
from collections import Counter
from datetime import date, datetime, timedelta
ROOT = pathlib.Path(__file__).resolve().parent.parent
if str(ROOT / "src") not in sys.path:
@@ -248,6 +249,17 @@ def _counts(rows) -> dict:
return out
def _reasons(rows, top=6) -> list:
"""A day's Fail and Review comments, grouped: `[{category, comment,
count}]`, most frequent first, Fail before Review on a tie."""
counted = Counter((r.get("category"), (r.get("comments") or "").strip())
for r in rows if r.get("category") in ("Fail", "Review"))
ordered = sorted(counted.items(),
key=lambda kv: (-kv[1], kv[0][0] != "Fail", kv[0][1]))
return [{"category": cat, "comment": text or "(no comment)", "count": n}
for (cat, text), n in ordered[:top]]
def create_app(repo, allowed_hosts=ALLOWED_HOSTS, runner=None,
allowed_origins=ALLOWED_ORIGINS, logs_dir=None,
screenshots_root=None, users_store=None,
@@ -385,9 +397,15 @@ def create_app(repo, allowed_hosts=ALLOWED_HOSTS, runner=None,
today = date.today()
counts = next((d for d in days if d["day"] == today),
{"day": today, "runs": 0, **_counts([])})
week = sorted((d for d in days
if today - timedelta(days=6) <= d["day"] <= today),
key=lambda d: d["day"])
# Only a day with claims costs the second query.
reasons = (_reasons(_db(repo.day_results, today))
if counts["claims"] else [])
return _page(request, "dashboard.html", [["Dashboard", None]],
today=counts, has_runs=bool(days),
alert=_last_run_alert())
alert=_last_run_alert(), week=week, reasons=reasons)
@app.get("/days", response_class=HTMLResponse)
def days_page(request: Request):