# Incident Timeline

> Status-page incident report with a Resolved badge, duration and affected services in the header, then four updates newest first, from Resolved back to Investigating, each with a time and note.

A shadcn/ui block from the [@01orbital](https://01orbital.dev/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/01orbital/incident-timeline).

- Page, with a live preview: https://shadcn.exchange/r/01orbital/incident-timeline
- Screenshot: https://shadcn.exchange/shot/01orbital/incident-timeline/light.png
- Registry item: https://01orbital.dev/r/incident-timeline.json
- Categories: timeline
- Listed: 2026-11-01, source last changed 2026-11-01

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/01orbital/incident-timeline.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `@01orbital/badge`, `@01orbital/timeline`

## Files

### `blocks/timeline/incident-timeline/index.tsx`

```tsx
import {
  Timeline,
  TimelineContent,
  TimelineDescription,
  TimelineIndicator,
  TimelineItem,
  TimelineLabel,
  TimelineTitle,
} from "@/components/editorial/timeline"
import { Badge } from "@/components/ui/badge"

// The copy: change text here, not in the markup.
const COPY = {
  eyebrow: "Incident",
  title: "Elevated error rates on the registry API",
  resolved: "Resolved",
  duration: "Duration 1h 48m",
  affected: "Affected: registry downloads, MCP search",
} as const

const UPDATES = [
  {
    status: "Resolved",
    time: "16:03 UTC",
    body: "Error rates have been normal for 30 minutes. The faulty node is out of rotation and will be rebuilt.",
  },
  {
    status: "Monitoring",
    time: "15:33 UTC",
    body: "A fix is deployed. We are watching error rates before closing.",
  },
  {
    status: "Identified",
    time: "14:51 UTC",
    body: "One cache node is returning stale certificates. Traffic is being drained from it.",
  },
  {
    status: "Investigating",
    time: "14:15 UTC",
    body: "We are looking into a rise in 5xx responses from the registry API in eu-west.",
  },
] as const

// The newest update leads and carries the ring; older ones are plain dots.
export default function IncidentTimeline() {
  return (
    <article className="mx-auto w-full max-w-xl">
      <header className="mb-8 border-b border-border pb-6">
        <p className="text-xs font-medium tracking-wide text-muted-foreground uppercase">
          {COPY.eyebrow}
        </p>
        <h2 className="mt-2 text-xl font-semibold tracking-tight">
          {COPY.title}
        </h2>
        <div className="mt-3 flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
          <Badge>{COPY.resolved}</Badge>
          <span>{COPY.duration}</span>
          <span aria-hidden>·</span>
          <span>{COPY.affected}</span>
        </div>
      </header>
      <Timeline className="[--timeline-lh:1.25rem]">
        {UPDATES.map((u, i) => (
          <TimelineItem key={u.time}>
            <TimelineIndicator
              className={
                i > 0
                  ? "border-0 [&_[data-slot=timeline-dot]]:bg-muted-foreground/60"
                  : undefined
              }
            />
            <TimelineContent>
              <div className="flex flex-wrap items-baseline gap-x-3">
                <TimelineTitle className="text-sm/5">{u.status}</TimelineTitle>
                <TimelineLabel className="text-sm/5 tabular-nums">
                  {u.time}
                </TimelineLabel>
              </div>
              <TimelineDescription className="max-w-prose">
                {u.body}
              </TimelineDescription>
            </TimelineContent>
          </TimelineItem>
        ))}
      </Timeline>
    </article>
  )
}
```
