Diagram - History
Keep one edit per Undo unit, replay under current permissions and separate model history from navigation.
#Usage
import { Diagram } from '@primeui/vue-diagram';<Diagram.Root :store="store" page-id="page">
<Diagram.CommandButton command-id="undo" v-slot="{ getButtonProps }">
<button v-bind="getButtonProps({ type: 'button' })">Undo</button>
</Diagram.CommandButton>
<Diagram.CommandButton command-id="redo" v-slot="{ getButtonProps }">
<button v-bind="getButtonProps({ type: 'button' })">Redo</button>
</Diagram.CommandButton>
<Diagram.Viewport label="Workflow editor" style="height: 24rem" />
</Diagram.Root>History belongs to the store; session commands also restore supported interaction state and enforce current policy.
This skeleton assumes an initialized store with page page. Use First Diagram for model creation, style imports and store disposal.
Diagram history belongs to the store. It records committed model edits, while selection, focus, pan, zoom and active tools belong to the session. Use the editor's Undo/Redo commands for user-facing replay so current permissions apply.
#UI Composition
Import copied DiagramCommandGroupUI from your application's UI directory and
mount it under the root with :command-ids="['undo', 'redo']". The complete demo
uses historyLimit: 3 to make eviction visible. Command availability includes
current editor policy; the store's canUndo/canRedo alone does not.
#Make one gesture one Undo
Drag a card through several positions and release it. Undo once: the whole drag is reversed. Pointer previews are transient, so each pointer movement does not become another history entry. Cancelling a drag creates no committed edit.
Use Atomic two-command edit, then Undo. The example moves Review and changes
Approve's title in one store transaction; both changes reverse together. The
batch validates together before committing. This abbreviated host transaction
assumes an existing store:
store.transact({
id: 'application-batch-1',
origin: { kind: 'api' },
baseRevision: store.revision,
commands: [
{ kind: 'update', collection: 'nodes', id: 'review', changes: { rotation: 15 } },
{ kind: 'update', collection: 'nodes', id: 'approve', changes: { rotation: 15 } }
]
});A batch is appropriate when several changes form one application operation. Separate transactions create separate history entries. Do not reproduce a drag engine with host transactions merely to group pointer movements.
#Understand the history limit and no-ops
| Member | Contract |
|---|---|
Store option historyLimit | Nonnegative safe integer; default 100. Zero retains no Undo entries. Oldest entries are discarded at the limit. |
historySize | Current number of Undo entries, not a revision number or total edits ever made. |
canUndo, canRedo | Store availability; false for an unavailable store, pending proposal or empty direction. Editor policy can further restrict replay. |
inspectHistory('undo' | 'redo') | Readonly prospective patches for application inspection; does not execute replay. |
session.undo(), session.redo() | Current editor permission checks, then store replay; return the operation result. |
store.undo(id, origin?), store.redo(id, origin?) | Direct application authority. Defaults origins to undo / redo; require a unique transaction ID. |
A no-change transaction returns noop, does not advance revision or add an entry,
and preserves Redo. In the example, Undo a batch and submit a no-op; Redo is still
ready. Commit a different edit after Undo and the Redo stack clears. Rejected,
stale, cancelled, duplicate and unresolved pending transactions do not add
committed history. Accepting a controlled proposal applies its history effect;
rejecting it does not.
The history limit is a store creation option. Keep that store stable while refreshing source data. Replacing the store starts a new history lifetime; native serialization saves model content, not the Undo/Redo stack.
#Replay with current permissions
Toggle read-only and compare the copied Undo/Redo controls. A session rechecks permissions against the records and operations affected by replay, including current record constraints, ancestors, layers and installed notation rules. An edit that was allowed earlier can be rejected now. A rejected replay leaves both model and history in place; change the applicable policy before retrying.
The example's host batch still uses direct store authority. A root's read-only setting controls editor actions; it does not veto every host method. For a host approval workflow, see Controlled State. Newer host synchronization clears both history stacks and invalidates pending work. Single-user history does not implement collaborative Undo.
#Restore selection and keep navigation outside history
Select and focus Review, delete it, then Undo. The session can restore its previous selection and focus when those deleted records are reintroduced and remain eligible in the current session. Ordinary commits reconcile selection against surviving visible records; Undo does not restore an old viewport. Import or remote commits clear the session's removal-restoration records, and a new session has no previous removal-restoration state.
Pan, Fit, zoom, selection changes, focus changes and active tool changes do not add model history. Use Pan view between edits and compare the entry count. The copied command group provides the same editor policy as keyboard Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z or Y when the canvas owns input. Native text fields and composing input retain their own editing and history keys.
Receipt retention is independent of history. The default receiptLimit: 4096
expires the oldest finalized transaction IDs; historyLimit: 0 does not disable
that window. See Controlled State
for retry semantics and the explicit lifetime option.
Saving acknowledges a checkpoint independently of history. Undo can return the model to saved content, but a revision alone does not describe whether the current content is dirty. See Save and Load.
Unsubscribe application observers and dispose an owned store on destruction. Diagram roots own and dispose their sessions; history refreshes do not require recreating either owner.
Restart example explicitly starts a new model/session and disposes the previous owned controllers and subscriptions. Use it to repeat a failure or deleted-content scenario. Ordinary refresh, save, load and paste keep the current store/session. Restart does not reset an external service; these providers are local demonstration fixtures.
Commands ยท Selection ยท Permissions ยท Events and commands