use-agent-history-manager.ts
Overview
The use-agent-history-manager.ts file provides an undo/redo history management system tailored for managing graph data consisting of nodes and edges. It encapsulates the history logic within a HistoryManager class and exposes a custom React hook useAgentHistoryManager which integrates the history manager with a React application's state management (using a Zustand store here).
This file's primary purpose is to track changes to the graph's state, allowing users to revert (undo) or reapply (redo) changes efficiently. It also supports keyboard shortcuts (Ctrl/Cmd + Z for undo, Ctrl/Cmd + Shift + Z for redo) to provide a smooth user experience.
Detailed Explanation
Class: HistoryManager
Manages the history stack of graph states and provides methods to manipulate and navigate the history.
Properties
Name | Type | Description |
|---|---|---|
| Array storing snapshots of graph states. | |
|
| Index of the current state in the history array. |
|
| Maximum number of history states to retain (default 50). |
|
| Callback to update the nodes state in the app. |
|
| Callback to update the edges state in the app. |
|
| JSON string of the last saved state for quick comparison. |
Constructor
constructor(setNodes: (nodes: any[]) => void, setEdges: (edges: any[]) => void)
Parameters:
setNodes: Function to update the nodes in the application state.setEdges: Function to update the edges in the application state.
Description:
Initializes the manager with setter functions to update the application's graph state.
Methods
private statesEqual(state1, state2): boolean
Parameters:
state1:{ nodes: any[]; edges: any[] }– First graph state.state2:{ nodes: any[]; edges: any[] }– Second graph state.
Returns:
boolean– Whether the two states are deeply equal.Description:
Compares two graph states by serializing them to JSON strings and checking equality.
push(nodes, edges): void
Parameters:
nodes:any[]– Current nodes array.edges:any[]– Current edges array.
Description:
Adds a new state snapshot to the history if it differs from the current state. If the history has undone states ahead of the current index, those are discarded. The history size is capped atmaxSize(50), dropping the oldest state if exceeded.Usage Example:
historyManager.push(currentNodes, currentEdges);
undo(): boolean
Returns:
boolean–trueif undo was successful;falseotherwise.Description:
Moves back one step in history if possible and updates the nodes and edges using the saved setter functions.Usage Example:
if (historyManager.canUndo()) {
historyManager.undo();
}
redo(): boolean
Returns:
boolean–trueif redo was successful;falseotherwise.Description:
Moves forward one step in history if possible and updates the nodes and edges accordingly.Usage Example:
if (historyManager.canRedo()) {
historyManager.redo();
}
canUndo(): boolean
Returns:
boolean– Whether an undo operation is possible (i.e.,currentIndex > 0).
canRedo(): boolean
Returns:
boolean– Whether a redo operation is possible (i.e.,currentIndex < history.length - 1).
reset(): void
Description:
Clears the entire history and resets the current index and last saved state.
Hook: useAgentHistoryManager
A React hook that integrates the HistoryManager with the React component lifecycle and the Zustand store.
Internal Behavior
Retrieves current graph state (
nodes,edges) and setters (setNodes,setEdges) from the Zustand graph store.Initializes a
HistoryManagerinstance stored in auseRefto persist across renders.Uses
useEffectto push new states into the history whenevernodesoredgeschange.Adds a
keydownevent listener for keyboard shortcuts:Undo: Ctrl/Cmd + Z (without Shift)
Redo: Ctrl/Cmd + Shift + Z
Prevents triggering shortcuts when an input, textarea, or contenteditable element is focused.
Usage Example
import React from 'react';
import { useAgentHistoryManager } from './use-agent-history-manager';
const GraphEditor = () => {
useAgentHistoryManager();
// Graph rendering and editing logic here
return <div>/* Graph UI */</div>;
};
Implementation Details & Algorithms
State Comparison: Uses JSON serialization to compare deep equality of node and edge arrays. This is simple but may be inefficient for very large graphs. However, it ensures accurate detection of state changes.
History Management: Implements a classic undo/redo stack with linear history. When a new state is pushed after undoing some states, the "future" states are discarded.
State Cloning: Deep clones nodes and edges using
JSON.parse(JSON.stringify(...))to prevent mutation side-effects.Keyboard Shortcut Handling: Listens globally on
documentfor keydown events and conditionally processes undo/redo commands, ignoring events when user is typing.
Interactions with Other Parts of the System
Zustand Store (
useGraphStore): The file relies on a Zustand store module (./store) that provides the current graph state (nodes,edges) and setter functions (setNodes,setEdges).Graph UI Components: The hook is intended to be used in React components that render and modify the graph. It automatically tracks changes to the graph state for undo/redo functionality.
Global Keyboard Handling: Integrates with the global DOM event system to handle keyboard shortcuts without requiring additional wiring in UI components.
Mermaid Class Diagram
classDiagram
class HistoryManager {
-history: array
-currentIndex: number
-maxSize: number
-setNodes(nodes: any[]): void
-setEdges(edges: any[]): void
-lastSavedState: string
-statesEqual(state1, state2): boolean
+constructor(setNodes, setEdges)
+push(nodes, edges): void
+undo(): boolean
+redo(): boolean
+canUndo(): boolean
+canRedo(): boolean
+reset(): void
}
HistoryManager o-- "2" Function : setNodes,setEdges
class useAgentHistoryManager {
<<hook>>
+() : void
}
Summary
The use-agent-history-manager.ts file encapsulates history tracking for graph data structures in React applications. It provides both a class (HistoryManager) to handle undo/redo state management and a custom hook (useAgentHistoryManager) that connects it seamlessly with React state and keyboard events. This design enables intuitive and efficient graph editing experiences with robust undo/redo capabilities.