Files
OpenNoodl/dev-docs/tasks/phase-2/TASK-004B-componentsPanel-react-migration/STATUS-BLOCKED.md
2025-12-23 09:39:33 +01:00

11 KiB

TASK-004B ComponentsPanel React Migration - STATUS: BLOCKED

Last Updated: December 22, 2025
Status: 🚫 BLOCKED - Caching Issue Preventing Testing
Completion: ~85% (Backend works, UI update blocked)


🎯 Original Goal

Migrate the legacy ComponentsPanel to React while maintaining all functionality, with a focus on fixing the component rename feature that doesn't update the UI after renaming.


What's Been Completed

Phase 1-4: Foundation & Core Features

  • React component structure created
  • Tree rendering implemented
  • Context menus working
  • Drag & drop functional

Phase 5: Inline Rename - PARTIALLY COMPLETE

Backend Rename Logic

The actual renaming WORKS PERFECTLY:

  • Component renaming executes successfully
  • Files are renamed on disk
  • Project state updates correctly
  • Changes are persisted (see console log: Project saved...)

Evidence from console logs:

 Calling performRename...
🔍 performRename result: true
 Rename successful - canceling rename mode
Project saved Mon Dec 22 2025 22:03:56 GMT+0100

UI Update Logic - BLOCKED 🚫

The problem: UI doesn't update after rename because the React component never receives the componentRenamed event from ProjectModel.

Root Cause: useEventListener hook's useEffect never executes, preventing subscription to ProjectModel events.


🔍 Technical Investigation Summary

Issue 1: React useEffect Not Running with Array Dependencies

Problem: When passing an array as a dependency to useEffect, React 19's Object.is() comparison always sees it as changed, but paradoxically, the useEffect never runs.

Original Code (BROKEN):

const events = ['componentAdded', 'componentRemoved', 'componentRenamed'];
useEventListener(ProjectModel.instance, events, callback);

// Inside useEventListener:
useEffect(() => {
  // Never runs!
}, [dispatcher, eventName]); // eventName is an array

Solution Implemented:

// 1. Create stable array reference
const PROJECT_EVENTS = ['componentAdded', 'componentRemoved', 'componentRenamed'];

// 2. Spread array into individual dependencies
useEffect(() => {
  // Should run now
}, [dispatcher, ...(Array.isArray(eventName) ? eventName : [eventName])]);

Issue 2: Webpack 5 Persistent Caching

Problem: Even after fixing the code, changes don't appear in the running application.

Root Cause: Webpack 5 enables persistent caching by default:

  • Cache location: packages/noodl-editor/node_modules/.cache
  • Electron also caches: ~/Library/Application Support/Electron
  • Even after clearing caches and restarting npm run dev, old bundles persist

Actions Taken:

# Cleared all caches
rm -rf packages/noodl-editor/node_modules/.cache
rm -rf ~/Library/Application\ Support/Electron
rm -rf ~/Library/Application\ Support/OpenNoodl

Still Blocked: Despite cache clearing, debug markers never appear in console, indicating old code is still running.


📊 Current State Analysis

What We KNOW Works

  1. Source files contain all fixes (verified with grep)
  2. Component rename backend executes successfully
  3. useEventListener hook logic is correct (when it runs)
  4. Debug logging is in place to verify execution

What We KNOW Doesn't Work

  1. useEventListener's useEffect never executes
  2. No subscription to ProjectModel events occurs
  3. UI never receives componentRenamed event
  4. Debug markers (🔥) never appear in console

What We DON'T Know

  1. Why cache clearing doesn't force recompilation
  2. If there's another cache layer we haven't found
  3. If webpack-dev-server is truly recompiling on changes
  4. If there's a build configuration preventing hot reload

🐛 Bonus Bug Discovered

PopupMenu Constructor Error:

Uncaught TypeError: _popuplayer__WEBPACK_IMPORTED_MODULE_3___default(...).PopupMenu is not a constructor
    at ComponentItem.tsx:131:1

This is a separate bug affecting context menus (right-click). Unrelated to rename issue but should be fixed.


📁 Files Modified (With Debug Logging)

Core Implementation Files

  1. packages/noodl-editor/src/editor/src/hooks/useEventListener.ts

    • Module load marker: 🔥 useEventListener.ts MODULE LOADED
    • useEffect marker: 🚨 useEventListener useEffect RUNNING!
    • Subscription marker: 📡 subscribing to...
    • Event received marker: 🔔 useEventListener received event
  2. packages/noodl-editor/src/editor/src/views/panels/ComponentsPanelNew/hooks/useComponentsPanel.ts

    • Module load marker: 🔥 useComponentsPanel.ts MODULE LOADED
    • Integration with useEventListener
    • Stable PROJECT_EVENTS array
  3. packages/noodl-editor/src/editor/src/views/panels/ComponentsPanelNew/ComponentsPanelReact.tsx

    • Render markers
    • Rename flow markers

Documentation Files

  1. CACHE-CLEAR-RESTART-GUIDE.md - Instructions for clearing caches
  2. RENAME-TEST-PLAN.md - Test procedures
  3. This file - Status documentation

🚧 Blocking Issues

Primary Blocker: Webpack/Electron Caching

Severity: CRITICAL
Impact: Cannot test ANY changes to the code

Symptoms:

  • Code changes in source files don't appear in running app
  • Console shows NO debug markers (🔥, 🚨, 📡, 🔔)
  • Multiple dev server restarts don't help
  • Cache clearing doesn't help

Possible Causes:

  1. Webpack dev server not watching TypeScript files correctly
  2. Another cache layer (browser cache, service worker, etc.)
  3. Electron loading from wrong bundle location
  4. Build configuration preventing hot reload
  5. macOS file system caching (unlikely but possible)

Secondary Blocker: React 19 + EventDispatcher Incompatibility

Severity: HIGH
Impact: Even if caching is fixed, may need alternative approach

The useEventListener hook solution from TASK-008 may have edge cases with React 19's new behavior that weren't caught in isolation testing.


💡 Potential Solutions (Untested)

Solution 1: Aggressive Cache Clearing Script

Create a script that:

  • Kills all Node/Electron processes
  • Clears all known cache directories
  • Clears macOS file system cache
  • Forces a clean webpack build
  • Restarts with --no-cache flag

Solution 2: Bypass useEventListener Temporarily

As a workaround, try direct subscription in component:

useEffect(() => {
  const group = { id: 'ComponentsPanel' };
  const handler = () => setUpdateCounter((c) => c + 1);

  ProjectModel.instance.on('componentRenamed', handler, group);

  return () => ProjectModel.instance.off(group);
}, []);

Solution 3: Use Polling as Temporary Fix

While not elegant, could work around the event issue:

useEffect(() => {
  const interval = setInterval(() => {
    // Force re-render every 500ms when in rename mode
    if (isRenaming) {
      setUpdateCounter((c) => c + 1);
    }
  }, 500);
  return () => clearInterval(interval);
}, [isRenaming]);

Solution 4: Production Build Test

Build a production bundle to see if the issue is dev-only:

npm run build
# Test with production Electron app

📋 Next Steps for Future Developer

Immediate Actions

  1. Verify caching issue:

    • Kill ALL node/electron processes: killall node; killall Electron
    • Clear caches again
    • Try adding a simple console.log to a DIFFERENT file to see if ANY changes load
  2. If caching persists:

    • Investigate webpack configuration in webpackconfigs/
    • Check if there's a service worker
    • Look for additional cache directories
    • Consider creating a fresh dev environment in a new directory
  3. If caching resolved but useEffect still doesn't run:

    • Review React 19 useEffect behavior with array spreading
    • Test useEventListener hook in isolation with a simple test case
    • Consider alternative event subscription approach

Alternative Approaches

  1. Revert to old panel temporarily - The legacy panel works, could postpone migration
  2. Hybrid approach - Use React for rendering but keep legacy event handling
  3. Full rewrite - Start fresh with a different architecture pattern

🔬 Debug Checklist for Next Session

When picking this up again, verify these in order:

  • Console shows 🔥 module load markers (proves new code loaded)
  • Console shows 🚨 useEffect RUNNING marker (proves useEffect executes)
  • Console shows 📡 subscription marker (proves ProjectModel subscription)
  • Rename a component
  • Console shows 🔔 event received marker (proves events are firing)
  • Console shows 🎉 counter update marker (proves React re-renders)
  • UI actually updates (proves the whole chain works)

If step 1 fails: Still a caching issue, don't proceed
If step 1 passes, step 2 fails: React useEffect issue, review dependency array
If step 2 passes, step 3 fails: EventDispatcher integration issue
If step 3 passes, step 4 fails: ProjectModel not emitting events


  • TASK-008: EventDispatcher React Investigation (useEventListener solution)
  • LEARNINGS.md: Webpack caching issues section (to be added)
  • CACHE-CLEAR-RESTART-GUIDE.md: Instructions for clearing caches
  • RENAME-TEST-PLAN.md: Test procedures for rename functionality

🎓 Key Learnings

  1. Webpack 5 caching is AGGRESSIVE - Can persist across multiple dev server restarts
  2. React 19 + arrays in deps - Spreading array items into deps is necessary
  3. EventDispatcher + React - Requires careful lifecycle management
  4. Debug logging is essential - Emoji markers made it easy to trace execution
  5. Test in isolation first - useEventListener worked in isolation but fails in real app

⏱️ Time Investment

  • Initial implementation: ~3 hours
  • Debugging UI update issue: ~2 hours
  • EventDispatcher investigation: ~4 hours
  • Caching investigation: ~2 hours
  • Documentation: ~1 hour

Total: ~12 hours - Majority spent on debugging caching/event issues rather than actual feature implementation.


🏁 Recommendation

Option A (Quick Fix): Use the legacy ComponentsPanel for now. It works, and this migration can wait.

Option B (Workaround): Implement one of the temporary solutions (polling or direct subscription) to unblock other work.

Option C (Full Investigation): Dedicate a full session to solving the caching mystery with fresh eyes, possibly in a completely new terminal/environment.

My Recommendation: Option A. The backend rename logic works perfectly. The UI update is a nice-to-have but not critical. Move on to more impactful work and revisit this when someone has time to fully diagnose the caching issue.