Dashboard Overview
The screen an app opens on: shell, header, KPI row, chart and activity feed — numbers first, shape second, changes last.
Thresholds with how often each has actually fired, what that produced, where it went — and the digest settings that exist because of the answer.
app/alerting-page.tsxnpx hoverlab add alerting-page
Or over MCP, from your editor's agent — no account needed.
Free to read, copy and install, for personal and non-commercial projects. Shipping it in client work or a paid product needs Pro ($79 once). The source lands in your repo and stops being ours — no attribution, nothing to upgrade.
The rules, how often they have fired, where that went — and the batching that exists because of the answer.
4 of 5 active · 1 delivering nowhere
Alert when API error rate stays above 2% for 5 minutes.
Alert when p95 latency stays above 800ms for 15 minutes.
This rule is on, but #platform-alerts is muted — nothing has been delivered since it was muted.
Alert when Signups per hour stays below 4 for 1 hour.
Firing 142 times a month is usually a threshold problem rather than an incident. Consider raising it before muting the channel.
Alert when Job queue depth stays above 5,000 for 10 minutes.
Alert when Storage used stays above 85% for 1 day.
An alert that has never fired looks identical to an alert that is broken. Showing the current distance to the threshold is what tells the two apart at a glance.
The all-or-nothing toggle is why people mute products. Routing by event lets the two that matter stay loud while the rest go somewhere quiet.
The alternative is fourteen separate emails, which is how a notification system trains people to filter it into a folder they never open.
The alternative offered by most products is on or off, so everyone picks off. A time and a floor turns the same stream into one predictable message.
The real page, rendered in your current theme — every section below is a live block, not a screenshot.
Only want one section? Open it and copy that block instead — browse Dashboards.
/**
* Alerting, as the loop it actually is: a rule fires, something happens to
* a person, and someone eventually decides it was firing too often.
*
* Most alert settings screens are a list of thresholds and a list of email
* addresses, on separate tabs, with nothing joining them. The join is the
* whole subject. A threshold nobody has tuned and a channel nobody reads
* produce the same outcome — an incident nobody saw — and you cannot tell
* which one you have unless the two are on the same screen.
*
* rules thresholds, with how often each has fired. That number is
* the one most rule lists omit and the only one that says
* whether the rule is any good
* fired what those rules produced
* channels where it went
* digest what got batched instead of sent immediately
* schedule and when the batch goes out
*
* The digest pair is at the end because batching is the answer to the
* problem the first three sections describe, and an answer read before the
* problem is just another setting. Someone arriving here because they are
* being paged too much should scroll through the evidence for that on the
* way to the control that fixes it.
*/
import * as React from 'react'
import { DashboardAlertRules } from '@/components/dashboard-alert-rules'
import { MetricAlertList } from '@/components/metric-alert-list'
import { NotificationChannelList } from '@/components/notification-channel-list'
import { NotificationDigestList } from '@/components/notification-digest-list'
import { DigestScheduleForm } from '@/components/digest-schedule-form'
export default function AlertingPage() {
return (
<main className="min-h-screen bg-background text-foreground">
<section className="mx-auto w-full max-w-5xl px-6 pb-2 pt-12">
<h1 className="text-2xl font-bold tracking-tight">Alerting</h1>
<p className="mt-1 text-sm text-muted-foreground">
The rules, how often they have fired, where that went — and the
batching that exists because of the answer.
</p>
</section>
<DashboardAlertRules />
<MetricAlertList />
<NotificationChannelList />
{/* The fix for everything above it, so it comes after. */}
<NotificationDigestList />
<DigestScheduleForm />
</main>
)
}
components/ — each block page has its own copy button.app/alerting-page.tsx. The imports already point at @/components/…, so they resolve with no edits.The component, its props, the design tokens it expects and the command that installs it — as one prompt. Paste it into Claude, Cursor, v0 or ChatGPT and what they build around it will match the rest of the catalog instead of inventing its own system.
The screen an app opens on: shell, header, KPI row, chart and activity feed — numbers first, shape second, changes last.
An agent working inside a real app: a transcript down the middle — reasoning, answer, then the one card that can act — with what it may read and what it noticed demoted to a rail.
A kanban board inside the app shell, with tabs that admit the board is one view among several and a header whose primary action is creating work.
The canonical CRUD list — header, toolbar, sortable table and pagination framed as one panel instead of three stacked cards.
A wizard for the session someone finishes and a checklist for the one they do not, with the only genuinely blocking step in front of both.
Built around the state a search page is in most of the time — empty — so recent queries lead and the facets sit in a sidebar that survives growing to twelve.
One run opened up in the order you would debug it — intent, actions, the retries that are invisible in both, then cost.
The queue, the same queue sorted by how long things have waited, and the policy that decided both — with the policy last so it is not scrolled past forever.
The blank thread answered with real starter prompts, the model picker with the three numbers the choice turns on, and the four surfaces a session grows into — attachments, branches, canvas, threads.
The three states an agent screen usually omits: the wait before the first token, the trace after something broke with retries costed in the open, and the diff it wants a person to accept.
Why the answer said what it said: what is connected, how stale it is, what the query was allowed to see, what fitted in the window and what fell out — plus the failed-search state a debugging tool is most needed in.
Five ways to reach a model without the cursor leaving the sentence — slash menu, inline completion, selection toolbar, action menu, property inspector — and the two surfaces that say where the answer came from.
A table after real people have used it — columns reordered from the keyboard, a selection bar that asks page-or-all, subtotals that survive collapsing, cells edited in place, and the empty state its own filters produced.
The saved view and the comparison window first, because every figure below depends on both — then six charts, none of which load a charting library.
The flow between an empty product and a useful one, in the order it goes wrong: sample data offered with equal weight, a file, a URL, the column mapping everything stalls on, and an upload that survives the connection dropping.
A profile form where the role options state what they actually change, the avatar crop works from the keyboard, and a navigation guard names the fields it is about to throw away.
The furniture that is on every screen and belongs to none — navbar, mobile drawer, command palette, shortcut sheet, header search, scope switcher, and the two shapes a detail view takes without losing the list.
Backwards from now and forwards from it on one screen — a day-grouped timeline, a month grid where a busy Tuesday never changes the row height, and the state both are in on day one.
What the product looks like while onboarding happens: a tour step anchored to the control it explains, the skeletons of the slowest load it will ever do, and the checklist that outlives both.