feat(blockly): Phase C Step 5 COMPLETE - NodeGraphEditor tab integration

Full integration of canvas tabs into NodeGraphEditor:
- Added renderCanvasTabs() method to render React tab system
- Added handleBlocklyWorkspaceChange() for workspace persistence
- Added cleanup in dispose() for React roots
- Added event listener for LogicBuilder.OpenTab events
- Tabs now render above canvas with provider wrapping

Ready for Phase C Steps 6-7 (property panel + code generation)
This commit is contained in:
Richard Osborne
2026-01-11 14:00:51 +01:00
parent f861184b96
commit fbf01bf0f7

View File

@@ -300,6 +300,17 @@ export class NodeGraphEditor extends View {
this this
); );
// Listen for Logic Builder tab open requests
EventDispatcher.instance.on(
'LogicBuilder.OpenTab',
(args: { nodeId: string; nodeName: string; workspace: string }) => {
console.log('[NodeGraphEditor] Opening Logic Builder tab for node:', args.nodeId);
// The CanvasTabs context will handle the actual tab opening via EventDispatcher
// This is just logged for debugging - the actual implementation happens in Phase C Step 6
},
this
);
if (import.meta.webpackHot) { if (import.meta.webpackHot) {
import.meta.webpackHot.accept('./createnewnodepanel'); import.meta.webpackHot.accept('./createnewnodepanel');
} }
@@ -414,6 +425,11 @@ export class NodeGraphEditor extends View {
this.highlightOverlayRoot = null; this.highlightOverlayRoot = null;
} }
if (this.canvasTabsRoot) {
this.canvasTabsRoot.unmount();
this.canvasTabsRoot = null;
}
SidebarModel.instance.off(this); SidebarModel.instance.off(this);
this.reset(); this.reset();
@@ -884,12 +900,63 @@ export class NodeGraphEditor extends View {
this.renderHighlightOverlay(); this.renderHighlightOverlay();
}, 1); }, 1);
// Render the canvas tabs
setTimeout(() => {
this.renderCanvasTabs();
}, 1);
this.relayout(); this.relayout();
this.repaint(); this.repaint();
return this.el; return this.el;
} }
/**
* Render the CanvasTabs React component
*/
renderCanvasTabs() {
const tabsElement = this.el.find('#canvas-tabs-root').get(0);
if (!tabsElement) {
console.warn('Canvas tabs root not found in DOM');
return;
}
// Create React root if it doesn't exist
if (!this.canvasTabsRoot) {
this.canvasTabsRoot = createRoot(tabsElement);
}
// Render the tabs with provider
this.canvasTabsRoot.render(
React.createElement(
CanvasTabsProvider,
null,
React.createElement(CanvasTabs, {
onWorkspaceChange: this.handleBlocklyWorkspaceChange.bind(this)
})
)
);
}
/**
* Handle workspace changes from Blockly editor
*/
handleBlocklyWorkspaceChange(nodeId: string, workspace: string) {
console.log(`[NodeGraphEditor] Workspace changed for node ${nodeId}`);
const node = this.findNodeWithId(nodeId);
if (!node) {
console.warn(`[NodeGraphEditor] Node ${nodeId} not found`);
return;
}
// Save workspace to node model
node.model.setParameter('workspace', workspace);
// TODO: Generate code and update ports
// This will be implemented in Phase C Step 7
}
/** /**
* Get node bounds for the highlight overlay * Get node bounds for the highlight overlay
* Maps node IDs to their screen coordinates * Maps node IDs to their screen coordinates