* Grow the viewport so Grafana full-dashboard captures render every panel
Grafana only runs a panel's queries once the panel enters the viewport,
so the full-page screenshot taken at a fixed 1720x1200 viewport captured
everything below the fold as an empty placeholder — the tables in the
bottom two-thirds of the DMARC dashboard came out blank. Scroll-through
approaches are unreliable in headless Chromium (Grafana's custom scroll
container ignores synthetic wheel events), so instead measure the
dashboard's full scroll height and grow the viewport to cover it before
capturing, then restore the normal viewport for the per-panel viewPanel
captures (which fill the viewport and would otherwise be distorted).
Verified against the live dashboard-dev stack: all panels, including the
bottom alignment-detail tables, now render in the capture.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Pin ruff exactly, matching the existing pyright pin rationale
CI installs the [build] extra fresh on every run, and ruff was the one
lint tool left unpinned. ruff 0.16.0 (released this week) began
flagging this codebase's str.format() house style, so every PR started
failing lint on lines it never touched. Pin to 0.15.21 — the version
the codebase is clean under — with the same bump-deliberately comment
pyright carries. Upgrading to 0.16 and converting to f-strings can be
its own PR.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Capture the grown viewport, not the full page (Copilot finding)
full_page=True screenshots the entire scrollable page, so a dashboard
taller than the 12000px viewport cap would still include unrendered
blank panels below the cap. Capture the viewport exactly instead — a
taller-than-cap dashboard now yields a truncated-but-fully-rendered
image, with a printed note about the truncation instead of silence.
Verified against the live dashboard-dev stack: capture is 1720x6241,
matching the measured dashboard height plus buffer, all panels
rendered.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Add dashboard screenshot harness to the dev tooling
dashboard-dev-screenshots.py drives headless Chromium (Playwright)
against the dashboard dev stack and captures how Kibana, OpenSearch
Dashboards, Grafana, and Splunk actually render the current sample
data — for end-to-end verification of dashboard changes and PR
evidence. It encodes the platform quirks that otherwise cost time to
rediscover: fixed render waits instead of networkidle (Kibana/OSD
dashboards poll forever), pinning OSD to the global tenant (a stale
private-tenant copy silently screenshots old dashboards), and driving
the Grafana and Splunk login forms rather than HTTP basic auth. The
output directory is gitignored; usage is documented in
dashboards/README.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Address Copilot review findings on the screenshot harness
- Only require OPENSEARCH_INITIAL_ADMIN_PASSWORD / SPLUNK_PASSWORD when
the osd / splunk targets are selected, and fail fast before launching
Playwright with a clear message naming the missing variable(s).
- Honor GRAFANA_USER (defaulting to admin) to match the dev bootstrap
script instead of hard-coding the Grafana username.
- Print a full traceback to stderr when a target fails, instead of just
the exception message, while still continuing to the next target.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Always close the browser when a screenshot target fails
Copilot round 2: each target only closed its Chromium instance on the
happy path, so a mid-run Playwright failure leaked a headless browser
while the script continued to the next target. Wrap each target body in
try/finally; closing the browser also closes its contexts and pages, so
the single b.close() covers the OSD context too.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Exit with an install hint when playwright is missing
Copilot round 3: playwright is deliberately not a project dependency, so
a bare import failure produced a raw ModuleNotFoundError traceback.
Catch ImportError and exit with the same one-time install command the
module docstring documents.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>