Files
OpenNoodl/dev-docs/tasks/phase-3-editor-ux-overhaul/TASK-012-blockly-integration/DRAG-DROP-FIX-ATTEMPT.md
2026-01-12 13:23:12 +01:00

161 lines
5.8 KiB
Markdown

# Blockly Drag-and-Drop Fix Attempt
**Date:** 2026-01-11
**Status:** Fix Implemented - Testing Required
**Severity:** High (Core functionality)
## Problem Summary
Two critical issues with Blockly integration:
1. **Drag Timeout:** Blocks could only be dragged for ~1000ms before gesture terminated
2. **Connection Errors:** Console flooded with errors when trying to connect blocks
## Root Cause Analysis
The original implementation used **blanket debouncing** on ALL Blockly change events:
```typescript
// ❌ OLD APPROACH - Debounced ALL events
const changeListener = () => {
if (changeTimeoutRef.current) clearTimeout(changeTimeoutRef.current);
changeTimeoutRef.current = setTimeout(() => {
const json = JSON.stringify(Blockly.serialization.workspaces.save(workspace));
const code = javascriptGenerator.workspaceToCode(workspace);
onChange(workspace, json, code);
}, 150);
};
```
### Why This Caused Problems
1. **During drag operations:** Blockly fires MANY events (BLOCK_DRAG, BLOCK_MOVE, etc.)
2. **Each event triggered:** A new debounce timeout
3. **React state updates:** Potentially caused re-renders during gesture
4. **Blockly's internal state:** Expected immediate consistency, but our debounce + React async updates created race conditions
5. **Insertion markers:** When trying to show connection previews, Blockly tried to update blocks that were in an inconsistent state
## The Solution
**Event Filtering** - Only respond to events that actually change workspace structure:
```typescript
// ✅ NEW APPROACH - Filter events intelligently
const changeListener = (event: Blockly.Events.Abstract) => {
if (!onChange || !workspace) return;
// Ignore UI events that don't change workspace structure
if (event.type === Blockly.Events.BLOCK_DRAG) return;
if (event.type === Blockly.Events.BLOCK_MOVE && !event.isUiEvent) return;
if (event.type === Blockly.Events.SELECTED) return;
if (event.type === Blockly.Events.CLICK) return;
if (event.type === Blockly.Events.VIEWPORT_CHANGE) return;
if (event.type === Blockly.Events.TOOLBOX_ITEM_SELECT) return;
if (event.type === Blockly.Events.THEME_CHANGE) return;
if (event.type === Blockly.Events.TRASHCAN_OPEN) return;
// For UI events that DO change workspace, debounce them
const isUiEvent = event.isUiEvent;
if (isUiEvent) {
// Debounce user-initiated changes (300ms)
changeTimeoutRef.current = setTimeout(() => {
const json = JSON.stringify(Blockly.serialization.workspaces.save(workspace));
const code = javascriptGenerator.workspaceToCode(workspace);
onChange(workspace, json, code);
}, 300);
} else {
// Programmatic changes fire immediately (undo/redo, loading)
const json = JSON.stringify(Blockly.serialization.workspaces.save(workspace));
const code = javascriptGenerator.workspaceToCode(workspace);
onChange(workspace, json, code);
}
};
```
### Key Changes
1. **Event type checking:** Ignore events that are purely UI feedback
2. **UI vs Programmatic:** Different handling based on event source
3. **No interference with gestures:** BLOCK_DRAG events are completely ignored
4. **Longer debounce:** Increased from 150ms to 300ms for stability
5. **Immediate programmatic updates:** Undo/redo and loading don't debounce
## Expected Results
### Before Fix
- ❌ Drag stops after ~1000ms
- ❌ Console errors during connection attempts
- ❌ Insertion markers cause state corruption
- ✅ But: no event spam (previous fix still working)
### After Fix
- ✅ Drag continuously for 10+ seconds
- ✅ No console errors during connections
- ✅ Clean insertion marker operations
- ✅ No event spam (maintained)
## Testing Checklist
### Drag Performance
- [ ] Drag block from toolbox → workspace (slow drag, 5+ seconds)
- [ ] Drag block around workspace (slow drag, 10+ seconds)
- [ ] Drag block quickly across workspace
- [ ] Drag multiple blocks in succession
### Connection Operations
- [ ] Drag block to connect to another block
- [ ] Check console for errors during connection
- [ ] Verify insertion marker appears/disappears smoothly
- [ ] Verify blocks actually connect properly
### Workspace Persistence
- [ ] Add blocks, close tab, reopen → blocks should persist
- [ ] Edit workspace, switch to canvas, back to Logic Builder → no loss
- [ ] Save project, reload → workspace loads correctly
### Performance
- [ ] No lag during dragging
- [ ] Console shows reasonable event frequency
- [ ] Project saves at reasonable intervals (not spamming)
## Files Modified
- `packages/noodl-editor/src/editor/src/views/BlocklyEditor/BlocklyWorkspace.tsx`
- Replaced blanket debouncing with event filtering
- Added event type checks for UI-only events
- Separated UI vs programmatic event handling
- Increased debounce timeout to 300ms
## Rollback Plan
If this fix doesn't work, we can:
1. Revert to previous debounced approach
2. Try alternative: disable onChange during gestures using Blockly gesture events
3. Try alternative: use MutationObserver instead of change events
## Learning
> **Blockly Event System:** Blockly fires many event types. Not all need persistence. UI feedback events (drag, select, viewport) should be ignored. Only respond to structural changes (CREATE, DELETE, CHANGE, MOVE completed). The `isUiEvent` property distinguishes user actions from programmatic changes.
## Next Steps
1. **Test the fix** - Run through testing checklist above
2. **If successful** - Update DRAG-DROP-ISSUE.md with "RESOLVED" status
3. **If unsuccessful** - Document what still fails and try alternative approaches
4. **Record in CHANGELOG.md** - Document the fix for future reference
5. **Record in LEARNINGS.md** - Add to institutional knowledge
---
**Testing Required By:** Richard (manual testing in running app)
**Expected Outcome:** Smooth, continuous dragging with no console errors