# TASK-010: Code Editor Undo/Versioning System **Status:** 📝 Planned **Priority:** Medium **Estimated Effort:** 2-3 days **Dependencies:** TASK-009 (Monaco Replacement) --- ## Problem Statement When editing code in Expression/Function/Script nodes, users cannot: - Undo changes after saving and closing the editor - Roll back to previous working versions when code breaks - See a history of code changes - Compare versions This leads to frustration when: - A working expression gets accidentally modified - Code is saved with a typo that breaks functionality - Users want to experiment but fear losing working code --- ## Proposed Solution ### Auto-Snapshot System Implement automatic code snapshots that are: 1. **Saved on every successful save** (not on every keystroke) 2. **Stored per-node** (each node has its own history) 3. **Time-stamped** (know when each version was created) 4. **Limited** (keep last N versions to avoid bloat) ### User Interface **Option A: Simple History Dropdown** ``` Code Editor Toolbar: ┌─────────────────────────────────────┐ │ Expression ✓ Valid [History ▼] │ │ [Format] [Save]│ └─────────────────────────────────────┘ History dropdown: ┌─────────────────────────────────┐ │ ✓ Current (just now) │ │ • 5 minutes ago │ │ • 1 hour ago │ │ • Yesterday at 3:15 PM │ │ • 2 days ago │ └─────────────────────────────────┘ ``` **Option B: Side Panel** ``` ┌────────────────┬──────────────────┐ │ History │ Code │ │ │ │ │ ✓ Current │ const x = 1; │ │ │ return x + 2; │ │ • 5 min ago │ │ │ • 1 hour ago │ │ │ • Yesterday │ │ │ │ │ │ [Compare] │ [Format] [Save] │ └────────────────┴──────────────────┘ ``` --- ## Technical Architecture ### Data Storage **Storage Location:** Project file (under each node) ```json { "nodes": [ { "id": "node-123", "type": "Expression", "parameters": { "code": "a + b", // Current code "codeHistory": [ // NEW: History array { "code": "a + b", "timestamp": "2024-12-31T22:00:00Z", "hash": "abc123" // For deduplication }, { "code": "a + b + c", "timestamp": "2024-12-31T21:00:00Z", "hash": "def456" } ] } } ] } ``` ### Snapshot Logic ```typescript class CodeHistoryManager { /** * Take a snapshot of current code */ saveSnapshot(nodeId: string, code: string): void { const hash = this.hashCode(code); const lastSnapshot = this.getLastSnapshot(nodeId); // Only save if code actually changed if (lastSnapshot?.hash === hash) { return; } const snapshot = { code, timestamp: new Date().toISOString(), hash }; this.addSnapshot(nodeId, snapshot); this.pruneOldSnapshots(nodeId); // Keep only last N } /** * Restore from a snapshot */ restoreSnapshot(nodeId: string, timestamp: string): string { const snapshot = this.getSnapshot(nodeId, timestamp); return snapshot.code; } /** * Keep only last N snapshots */ private pruneOldSnapshots(nodeId: string, maxSnapshots = 20): void { // Keep most recent 20 snapshots // Older ones are deleted to avoid project file bloat } } ``` ### Integration Points **1. Save Hook** ```typescript // In CodeEditorType.ts → save() function save() { let source = _this.model.getValue(); if (source === '') source = undefined; // NEW: Save snapshot before updating CodeHistoryManager.instance.saveSnapshot(nodeId, source); _this.value = source; _this.parent.setParameter(scope.name, source !== _this.default ? source : undefined); _this.isDefault = source === undefined; } ``` **2. UI Component** ```tsx // New component: CodeHistoryButton function CodeHistoryButton({ nodeId, onRestore }) { const history = CodeHistoryManager.instance.getHistory(nodeId); const [isOpen, setIsOpen] = useState(false); return (