Boring cloud consoles are the point
what I learned building infrastructure UIs under time pressure: tables, consequences, and color that means something.
Most of my console work (Huddle Cloud and similar) was for people shipping or debugging under time pressure. Flashy UI did not help them. Clear state did.
"Boring" here means the screen answers three questions fast: what is true, what am I changing, what happens if I confirm.
Three layers
World state: nodes, regions, jobs. Say when the UI is behind reality.
Intent: the form or action. Prefer reversible until commit.
Consequences: blast radius in plain language, not footer fine print.
function DestroyClusterDialog({ cluster }: { cluster: Cluster }) {
return (
<Dialog severity="destructive">
<DialogTitle>Destroy {cluster.name}?</DialogTitle>
<DialogBody>
<p>
This deletes {cluster.nodeCount} nodes in {cluster.region}.
</p>
<ConsequenceList
items={[
"Active connections drop now",
"Backups stay 7 days, then go",
"Cannot undo",
]}
/>
<ConfirmInput label={`Type ${cluster.name} to confirm`} />
</DialogBody>
</Dialog>
);
}If production destroy does not ask you to type the name, someone will click the wrong row eventually.
Tables do most of the work
Operators think in inventories. A usable table usually needs:
- Sticky headers
- Saved column prefs
- Actions that are obvious without hunting a
⋯ - Empty states that say why it is empty
- Filters in the URL so you can paste a view to someone
| Column | Job | Common mistake |
|---|---|---|
| Name | link to detail | cut off with no tooltip |
| Status | health at a glance | color only, no text |
| Region | where it lives | gone on small screens with no replacement |
| Updated | freshness | relative time with no absolute |
| Actions | safe verbs | icon-only menu |
Bad table UX costs more hours than a slightly awkward API.

Save color for state
One accent for primary actions. Semantic colors for success / warn / danger, used rarely. Charts get their own palette with a non-color backup (pattern or label).
Using brand red for buttons and errors trains people to ignore red.
Dark mode is not invert-and-ship. Check contrast again for long sessions.
Error copy is the product
Weak: Error: operation failed (code: 409)
Better: Deploy blocked: v2.14 is already rolling in us-east-1. Wait it out or cancel that rollout.
Say what failed, what to do next, and keep a small copyable code for support.
{
"error": {
"code": "rollout_in_progress",
"message": "Deploy blocked: active rollout in us-east-1",
"docs": "https://docs.example.com/errors/rollout_in_progress"
}
}Link the docs from the error. Searching Slack for the code is a tax you invent for yourself.
Show freshness
Polling without a timestamp makes people refresh forever. We refreshed VM detail pages a painful number of times when status felt live but was not.
export function usePolling<T>(
fetcher: () => Promise<T>,
intervalMs = 30_000,
) {
const [data, setData] = useState<T | null>(null);
const [updatedAt, setUpdatedAt] = useState<Date | null>(null);
useEffect(() => {
let active = true;
async function tick() {
const next = await fetcher();
if (!active) return;
setData(next);
setUpdatedAt(new Date());
}
tick();
const id = setInterval(tick, intervalMs);
return () => {
active = false;
clearInterval(id);
};
}, [fetcher, intervalMs]);
return { data, updatedAt };
}Stale with a clock is fine. Stale wearing a "live" badge is not.
Keyboard paths matter
Dense tables and modals get used repeatedly. Tab order, escape from dialogs, and a table fall-back for charts are not polish. They are how people work when they are tired.
How you know it is working
- New eng can do a core flow without a walkthrough
- Tickets skew toward real system failures, not "what does this mean"
- One primary button style, not seven
- Incidents show up where people already look
Opposite smell: charts nobody acts on, empty states that blame the user, settings buried three levels deep, motion that delays the click.
Consoles are workplaces. Labels should face the person using them. Alarms should mean one thing. Nothing should glow for decoration.