Time Travel

The Time Travel plugin provides full state history management for your grid. It captures snapshots on every state change, supports unlimited undo/redo, named checkpoints for marking important states, state diffing to visualize what changed between two points, and branches for exploring what-if scenarios without losing your current state.

Installation

npm install @gridstorm/plugin-time-travel

Setup

import { createGrid } from '@gridstorm/core';
import { TimeTravelPlugin } from '@gridstorm/plugin-time-travel';

const grid = createGrid({
  columns: [
    { colId: 'name', field: 'name', headerName: 'Name' },
    { colId: 'value', field: 'value', headerName: 'Value' },
    { colId: 'status', field: 'status', headerName: 'Status' },
  ],
  rowData: [],
  plugins: [
    TimeTravelPlugin({
      maxSnapshots: 200,
      autoCapture: true,
      maxBranches: 10,
    }),
  ],
});

:::example{title="Live Time Travel Demo" href="/cookbook/#time-travel-basic"} Edit grid data, then use undo/redo and branch to explore alternative states. View diffs between any two checkpoints. :::

Plugin Options

Name Type Default Description
maxSnapshots number 100 Maximum number of snapshots retained in history. Oldest snapshots are pruned when the limit is exceeded.
autoCapture boolean true Automatically capture a snapshot after every state-changing command. When false, snapshots must be created manually.
maxBranches number 5 Maximum number of concurrent branches. Creating a new branch when at the limit removes the oldest branch.

Commands

Name Payload Description
timeTravel:snapshot { label?: string } Capture the current grid state as a named checkpoint.
timeTravel:restore { snapshotId: string } Restore the grid to a previously captured snapshot.
timeTravel:undo {} Revert to the previous state in history.
timeTravel:redo {} Advance to the next state in history after an undo.
timeTravel:diff { from: string; to: string } Compute the differences between two snapshots, returning added, removed, and modified rows.
timeTravel:branch { name: string; from?: string } Create a new branch from the current state or a specific snapshot for what-if analysis.

Events

Name Payload Description
timeTravel:snapshotCaptured { snapshot: StateSnapshot } Emitted when a new snapshot is captured (auto, manual, or checkpoint).
timeTravel:restored { snapshotId: string } Emitted after the grid state is restored from a snapshot.
timeTravel:undone { snapshotIndex: number } Emitted after an undo moves the cursor to an earlier snapshot.
timeTravel:redone { snapshotIndex: number } Emitted after a redo moves the cursor to a later snapshot.
timeTravel:diffResult { fromId: string; toId: string; diff: DiffResult } Emitted with the computed diff between two snapshots.
timeTravel:branchCreated { branchId: string; name: string } Emitted when a new branch is created and switched to.
timeTravel:branchSwitched { branchId: string } Emitted after switching to a different branch.
timeTravel:history { branchId: string; snapshots: […]; currentIndex: number } Emitted in response to timeTravel:getHistory.
timeTravel:error { message: string } Emitted when a time-travel operation fails (e.g. branch cap reached).

Note: restore/undo/redo/branch-switch also emit a standard rowData:changed ({ rowData }) so renderers and framework adapters re-render. The events above carry time-travel-specific detail and never reuse rowData:changed for notifications.

Usage Examples

Undo and Redo

Standard undo/redo navigation through state history.

// Make some edits...
grid.commandBus.dispatch('edit:commit', {
  rowId: 'row-1', colId: 'value', value: 42,
});

// Undo the last change
grid.commandBus.dispatch('timeTravel:undo', {});

// Redo it
grid.commandBus.dispatch('timeTravel:redo', {});

Named Checkpoints

Save important states with descriptive labels for easy recall.

// Mark the current state before a bulk operation
grid.commandBus.dispatch('timeTravel:snapshot', {
  label: 'Before Q4 import',
});

// ... perform bulk data import ...

// Something went wrong — restore the checkpoint
grid.commandBus.dispatch('timeTravel:restore', {
  snapshotId: 'before-q4-import',
});

Branches and Diffing

Create branches to explore alternative scenarios, then compare the results.

// Create a what-if branch
grid.commandBus.dispatch('timeTravel:branch', {
  name: 'optimistic-forecast',
});

// Make speculative edits on the branch...

// Compare the branch state against the main timeline
grid.commandBus.dispatch('timeTravel:diff', {
  from: 'main',
  to: 'optimistic-forecast',
});

// Listen for diff results
grid.eventBus.on('timeTravel:diff:computed', (event) => {
  console.log(`${event.added} added, ${event.removed} removed, ${event.modified} modified`);
});

Next Steps