CheckpointTimeline
Checkpoint history with snapshot indicators and restore actions.
CheckpointTimeline is the workspace’s undo history: every agent checkpoint on a hairline rail, newest first, with square markers in the status vocabulary — the latest holds primary, the past stays muted. Each row carries the label, a relative timestamp, and mono metadata chips: the git sha, a snapshot indicator when a database snapshot rides along, and the tenant project id. Restore pins the acting row under a shimmering label and locks the rest until the flight lands. Before the first checkpoint exists, EmptyState holds the space.
Install
npx shadcn@latest add https://ui.neon.com/r/checkpoint-timeline.json
Usage
import { CheckpointTimeline } from "@/components/neon-ui/checkpoint-timeline";
<CheckpointTimeline
checkpoints={checkpoints}
restoringId={restoringId}
onRestore={(id) => restoreCheckpoint(id)}
/>;
Wiring to Neon
A server component lists the project’s snapshots and wires restore as a server action:
import { createNeonClient } from "@/lib/neon-client";
const neon = createNeonClient(process.env.NEON_API_KEY);
const { data } = await neon.snapshots.list(projectId);
const checkpoints = (data ?? []).map((snapshot) => ({
id: snapshot.id,
label: snapshot.name,
createdAt: snapshot.created_at,
snapshot: snapshot.id,
projectId,
}));
const restore = async (snapshotId: string) => {
"use server";
await neon.snapshots.restore(projectId, snapshotId);
};
Snapshots come back oldest first, so reverse them: the timeline expects newest first. restore creates a new branch rather than overwriting one. Pass targetBranchId to restore onto an existing branch instead, or a preview callback to check the restored data and commit or abort. Set waitForReadiness on the client and the call returns only once the restore has settled, so restoringId can clear on the await.
States
- Entrance — rows rise 8px one at a time, 60ms apart, newest first.
- Restoring — the acting row’s action swaps to a shimmering “Restoring…” and every other action dims until
restoringIdclears. - Empty — the built-in EmptyState explains what checkpoints are; replace it with the
emptyslot.
Props
checkpointsCheckpoint[]
Newest first: id, label, createdAt, plus optional sha, snapshot, projectId.
Checkpoint[]onRestore?(id: string) => void
Renders the restore action on every row.
(id: string) => voidrestoringId?string | null
The checkpoint currently restoring; locks every other action.
string | nullnullempty?ReactNode
Override the built-in empty state.
ReactNodeAccessibility
- The history is an ordered list — position in time is structural, not visual.
- Restore buttons are real buttons with busy state communicated through the label swap; locked actions are
disabled. - Markers and the rail are decorative (
aria-hidden); the timestamp text carries recency. - Entrance stagger and shimmer are static under
prefers-reduced-motion.