Custom dashboards: a widget builder over every watcher
Building a custom dashboard feature for Lookout — a widget/query builder that composes 18 watcher sources into stats, time series, and breakdowns, with portable SQL and pure-CSS charts.
The capstone stretch begins. First of the final features: custom dashboards — the thing that ties every watcher together.
After a sprint of building watchers — requests, queries, jobs, errors, mail, cache, Redis, storage, views, logs, gates, auth, and more — each lived on its own page. Useful, but siloed. A dashboard is where you compose them: request volume next to p95 latency next to top error types, your view, your project.
The query layer is the hard part
The watchers store data in very different shapes. Making them all chartable through one builder meant a uniform query layer. Two seams do the work:
DashboardMetricRegistry— a declarative catalogue of 18 sources, each with its metrics (count, p95, average, rate) and group-by dimensions. Adding a new chartable thing is a data edit, not new code.WidgetDataResolver— turns a widget into a result: a single stat, a time series, or a top-N breakdown.
Two details I'm proud of
- Portable time-bucketing. Charting a time series across both SQLite and MySQL without database-specific date functions meant epoch-bucketing — integer-dividing a unix timestamp by the bucket width and grouping on that. One expression, both engines.
- No chart library. The whole app renders visualizations with pure CSS bars and inline SVG — no JS charting dependency. The dashboards stay on that diet: CSS bars for series and breakdowns. Lighter, and it matches everything else.
A sensible default
A blank dashboard is a bad first impression, so new projects get an auto-seeded Overview — requests over time, p95, error rate, top routes, errors by type. Useful on first load; fully editable after.
It's the natural capstone: it only works because the watchers underneath it are rich. Next: making minified JavaScript errors readable with source maps.