Record time machine
A React component in Beamline's Data & tables category.
The record itself, rewound in place: a slim track of every change (a tick per change in its person's colour, hollow for automation, named moments as flags, removed history hatched) and a head you drag or step with [ and ]. As it passes changes the fields morph to their earlier values; fields that differ from now wear the accent's edge and say what they are now and who changed them; long text shows its word differences; a field's own story filters the track to its changes. In the past, tick fields to restore just those, previewed now → then with what the restore sets off, written as a new event.
Use it for
- Any record more than one person (or automation) edits: a deal, a product, a contract, a patient's medication list, a shift, a page.
- The host keeps the change events ([before, after] per field) and writes a restore as a new event; the part derives every past state from them.
Not for
- A feed of activity across many records → activity-feed or timeline.
- Comparing two documents line by line → file-diff or diff-table.
Anatomy
- header: the record's name, what you are viewing (Now · N changes, or Viewing <when> · N changes since), Back to now
- track (when there is history): named moments as flags above it, a hatched start for removed history, a tick per change in its actor's colour (hollow for automation), the head (a slider), the two ends
- fields: label and value (short values morph letter by letter; long text shows word differences against now); in the past a field that differs wears the accent's edge, a chip (now <value> · changed by <who>, <date>) and a checkbox when restoring is allowed; each field's change count opens its story (each value with who and when; a row jumps the head there)
- restore bar (in the past, when the host allows): the ticked fields as now → then, what the restore sets off, a change made since you started, and Restore N fields from <date>
States
- now
- no history
- viewing the past
- one field's story (the track filtered)
- restore preview
- restoring
- restored (the head back at now)
- conflict (changed since you started)
- removed history (cutoff)
- read-only past
- hidden field
Keyboard
- The head is a slider: ← → (or [ and ]) step one change, Home goes before the first kept change, End to now; its value text is the date and the change ("1 Oct, 14:20, Ana Ruiz changed Amount and Products")
- Tab reaches the moments, the fields' checkboxes and change counts, the story's rows and the restore button; focusing a field filters the track to its changes
- The header's line is polite live: it says what is shown as you step
Motion
The head rides a lane as wide as the track (one transform) and settles on its change over the standard duration; while dragged it follows the hand exactly. Values morph letter by letter as the head passes their changes; ticks not about the pointed field fade. Reduced motion places everything.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label (required) | string | — | The record's name: "Northwind renewal". |
fields (required) | RecordField[] | — | |
values (required) | Record<string, RecordValue> | — | The values now, by field id. |
events (required) | RecordEvent[] | — | Every change, oldest first. The part derives any past state by undoing them from now; it never edits them. |
moments | RecordMoment[] | — | |
cutoff | Date | — | History before this was removed (a retention policy): the track starts hatched. |
now | Date | — | "Now" for the track's right end; default the time of drawing. |
currency | string | — | ISO code for "money" fields. Default USD. |
format | ((value: RecordValue, field: RecordField) => string) | — | A value as words, for a field the default reading doesn't fit. |
position | number | — | How many events are applied: `events.length` is now, 0 the oldest kept state. Controlled with onPositionChange; after a restore the part asks for now again (onPositionChange with the new events' length). |
defaultPosition | number | — | |
onPositionChange | ((position: number) => void) | — | |
onRestore | ((fieldIds: string[], at: Date) => void | Promise<void>) | — | Restore the ticked fields to their values at `at`: the time of the change at the head (the moment viewed). The host writes it as a new event; the part then returns to now. A promise shows Restoring until it settles; a rejected one leaves the past shown with the fields still ticked, to try again (say why in the app). Omit to make the past read-only. |
consequences | ((fieldIds: string[]) => string[]) | — | What a restore of these fields sets off (the host's rules): "Probability recalculates from the stage". |
className | string | — | Classes on the documented visual root; no override by default. |
classNames | Partial<Record<"root" | "header" | "head" | "track" | "tick" | "bar" | "field" | "chip"… | — | Classes for the named visual parts; no overrides by default. |
style | CSSProperties | — | Inline styles on the documented visual root; no overrides by default. |
ref | Ref<HTMLDivElement> | — | Receives the documented native target or imperative handle; omitted by default. |
Built from
Dependencies
lucide-react
Import
import { RecordTimeMachine } from "@beamline/record-time-machine";
Get it
Record time machine is part of Beamline UI. Install the parts you need in your React app as compiled packages or editable source. Get Beamline · Connect your agent
More in Data & tables
- Living table: A table that shows as much as fits on both axes: width decides which columns show (the rest ride in the name line, moving there rather than vanishing)…
- Availability layers: A week of bookable start times whose closed times explain themselves: every availability rule (hours, time off, bookings, buffers, rooms, lead time…
- Capacity terrain: A schedule that stands on a terrain of capacity: under each station's lane of jobs, every day's load rises to its capacity line and an overload is a…
- Domino move: A room board where one move shows its chain: drag a booking (or pick it and aim it with the keys) onto a taken room and the bookings it would push appear…
- Match board: Month-end matching as one picture: bank lines and books entries side by side with threads between them — solid for matched, dashed with the host's reason…
- Split anything: One splitter for money, quantities and time: a bar of the whole shows every target's part and what is not split yet; items are dragged onto targets…
- Approval route: A policy you can read by trying it: an amount on a log scale with the thresholds as marks (the arrows stop just under, at and just over each), the…
- Proposal twin: A proposal edited beside the client's exact page, the two linked both ways: a field in focus lights its twin on the page, scrolls it into view and joins…
- Quantity river: The life of one order line's quantity: at rest a bar of its real split ("5 delivered · 1 back in stock · 1 damaged · 5 cancelled"), unfolding into a…
- Stock horizon: Projected stock per item over the coming weeks: a strip of weeks with the safety line, weeks under safety in warn and short in danger, every dip said in…
- Ageing queue: Tickets that visibly age: each ticket's ring fills toward its own service target and steps from on time to late to very late, the words say when it is…
- Import lens: A messy import made fixable by kind: rows stream through the checks once with live counts; problems gather into groups that say what is wrong in words…
- Duplicate guard: A new record that watches for the one that already exists: as you type, the likely duplicates slide in beside the form with the fields that match lit and…
- Scan flow: A pick list that takes scans: each scan flies from the scan field into its row and fills that row's quantity ring, and the prompt moves to the next bin…
- Pack planner: The packing bench: the order's items sit in box outlines drawn to scale, each box filling to its padding line, weighing against its limit and naming the…
- Provenance lens: Hold Alt (or press Lens) over any number on the page and see what makes it: hairline threads draw from the number to the rows, cards and documents on…
- Tension timeline: A plan where slack is something you see: every dependency is a string from one task's end to the next one's start, sagging with the days it has to spare…
- Replay bar: Rewind for anything live: pause a stream, scrub back to the moment you missed (markers for the ones that matter), step one update at a time, replay at a…
- Event calendar: A schedule of events by day, week or month: events that overlap sit side by side, drag one to another time or day or pull its bottom edge to change its…
- Kanban board: Work as cards in columns by stage: drag a card (or lift it with Space and walk it with the arrows) to another column or place, the cards around it make…
- Data grid: Virtualised local or server-driven grid: stable row IDs, manual sort and filters, pages or infinite loading, retry without losing rows, inline editing…
- Pivot table: Records summed up by the fields people choose: rows grouped by one or more fields that fold open level by level, columns split by another, one or more…
- Query builder: Conditions people build by hand to pick out records: each rule is a field, an operator that fits the field (contains, between, in the last N days, is any…
- Sort order: Several sort keys in order. Each key says its rank in words ("Sort by Plan, A to Z", "then by Size, largest first") with its order named for the field's…
- Metric rules: Ordered rules that colour a dashboard number. Each rule has a name for what its colour means ("At risk", not just red) and a tone (good, watch, act…
- Log viewer: Log lines as they stream: it follows the newest line until you scroll up, then counts what arrived and brings you back in one click; filter by level with…
- JSON viewer: A JSON value as a tree you can read and walk: branches open and close (one level, or all at once), closed ones preview what they hold, every value reads…
- JSON diff viewer: Two versions of a JSON value compared as one tree: added keys marked +, removed ones struck through with −, changed values read old → new, unchanged keys…
- Import mapping: Map the columns of a file to the fields of one record type, see what every value becomes, then run the import and get an outcome for each row…
- Diff table: Proposed edits to a table before they happen: new rows green, removals struck through, changed cells old → new; each change can be left out and Apply…
- Filter toolbar: The filters on a list kept in view: chips that remove themselves, Add filter with fields and their values, Clear all, and room for search or view controls.
- Table: A native HTML table for small datasets, composed with children or driven by records; shared server paging, sorting, filters, search, stable-ID selection…