Skip to content
D
Documentation

Command history and edits

concept
2 min readUpdated

An undoable Command packages a diagram edit so the engine can execute it, undo it, and put it on the shared history stack.

The DiagramInstance exposes the mounted diagram's model and its engine. The DiagramModel owns the diagram data; the DiagramEngine owns behavior, including command history. A user gesture goes through the command manager, while initial setup and loading can write to the model directly:

mermaid
flowchart LR
  G["User gesture or user-directed edit"] --> C["CommandManager.execute(command)"]
  C --> H["Undo history"]
  H --> U["Undo / redo"]
  S["Setup or load"] --> M["DiagramModel operations"]
  M --> V["Diagram data, not an undo step"]

Choose by intent

Use model operations to build or load the diagram: adding nodes directly to the model does not create a history entry. Use a command when your feature edits on the user's behalf, such as applying a toolbar action or suggestion; executing it records an undoable change.

This helper expects the instance from an already mounted diagram. It adds a starting node as setup, then adds a suggested node through the shipped AddNodeCommand. After it completes, the mounted diagram contains both boxes; the setup node is not an undo step, while the suggestion is.

ts
import { AddNodeCommand, NodeModel } from '@grafloria/engine';
import type { DiagramInstance } from '@grafloria/renderer';

export async function prepareAndSuggest(instance: DiagramInstance): Promise<void> {
  const diagram = instance.getModel();
  const start = new NodeModel({
    id: 'start',
    type: 'basic',
    position: { x: 80, y: 80 },
    size: { width: 160, height: 80 },
  });
  diagram.addNode(start);

  const suggestion = new NodeModel({
    id: 'suggestion',
    type: 'basic',
    position: { x: 300, y: 80 },
    size: { width: 160, height: 80 },
  });
  await instance.getEngine().commandManager.execute(new AddNodeCommand(suggestion));
}

The command manager's execute() returns a promise, so await it before checking the diagram or updating controls. To undo that edit later, call undo() on instance.getEngine(); DiagramInstance itself has no undo() method. The starting node remains because diagram.addNode() did not enter history. To combine several related edits into one undo step, use the shipped BatchCommand.

Gestures use the same history

Dragging, connecting, deleting, pasting, and grouping are user edits, so their completed actions are represented as commands on the same history stack as a programmatic feature edit. A completed drag is one history step rather than one step per pointer-position update. Undo and redo apply those commands to the model, so the rendered diagram reflects the reverted or replayed state.

Try the live interaction demo: drag an item, then use the platform's undo shortcut to see the gesture revert.

Was this page helpful?

Command history and edits — Grafloria · GPT-6 Luna