Date: 2026-03-28
Branch:feature/flow-backend-integration
Status: Ready to implement
Two P0 bugs block the Flow Builder UI. Both are frontend-only — backend APIs are working.
Three interrelated data/type issues:
ActionOption.categoryinmodal.types.tsonly allows'transform' | 'control' | 'utility' | 'integration'— missing'agent'and'tool'.actions.tssets both "Run Agent" and "Call Tool" tocategory: 'transform'(the only valid option) instead of'agent'and'tool'.NodeSelectionModal.tsxfilters forcategory === 'agent'andcategory === 'tool'— these buckets are always empty, so "AI & Agents" and "Tools" sections never render.
Important
Previous fix attempts all focused on icons (imports, iconMap, null checks). The real issue is the data model mismatch between types, data, and filter logic.
Circular state update between FlowCanvas and FlowContext:
activeFlow changes
→ FlowCanvas useEffect sets local nodes/edges
→ React Flow fires onNodesChange (dimension recalc)
→ onNodesChange calls updateNodesAndEdges
→ flowService.updateNodesAndEdges updates cache + notifies listeners
→ FlowContext subscriber calls setActiveFlowState(cached)
→ activeFlow changes → LOOP
FlowContext.saveFlow passes activeFlowId (string) to flowService.saveFlow(), but the service method expects a Flow object. This would crash on any save attempt.
[MODIFY] modal.types.ts
- category: 'transform' | 'control' | 'utility' | 'integration';
+ category: 'agent' | 'tool' | 'transform' | 'control' | 'utility' | 'integration';[MODIFY] actions.ts
{
id: 'agent-run',
name: 'Run Agent',
icon: 'Bot',
- category: 'transform'
+ category: 'agent'
},
{
id: 'tool-call',
name: 'Call Tool',
icon: 'Wrench',
- category: 'transform'
+ category: 'tool'
},Add missing actions for remaining categories (transform, utility, integration).
[MODIFY] FlowCanvas.tsx
Add a isSyncingRef guard to prevent writing back to context when local state change originated from context sync (not user interaction).
+ const isSyncingRef = useRef(false);
useEffect(() => {
if (activeFlow) {
+ isSyncingRef.current = true;
setNodes(activeFlow.nodes);
setEdges(activeFlow.edges);
+ requestAnimationFrame(() => { isSyncingRef.current = false; });
}
}, [activeFlow]);
const onNodesChange = useCallback((changes) => {
setNodes((nds) => {
const updatedNodes = applyNodeChanges(changes, nds);
- if (activeFlow) {
+ if (activeFlow && !isSyncingRef.current) {
updateNodesAndEdges(updatedNodes, edges);
}
return updatedNodes;
});
}, ...);Same guard applied to onEdgesChange and onConnect.
[MODIFY] FlowContext.tsx
const saveFlow = useCallback(async () => {
- if (!activeFlowId || !hasUnsavedChanges) return;
+ if (!activeFlowId || !activeFlow || !hasUnsavedChanges) return;
setSaveState('saving');
try {
- await flowService.saveFlow(activeFlowId);
+ await flowService.saveFlow(activeFlow);- Login as
Administrator/admin - Navigate to Flows page
- BUG-002: Confirm no React #185 errors, page loads cleanly
- Open/create a flow, click "+" on a node
- BUG-001: Click "Actions" tab — verify all categories render without crash
- Click actions, verify they dispatch correctly
cd frontend && yarn typecheck| File | Change |
|---|---|
modal.types.ts |
Add 'agent' + 'tool' to category union |
actions.ts |
Fix categories, add missing actions |
FlowCanvas.tsx |
Add syncing guard ref |
FlowContext.tsx |
Fix saveFlow signature |
- FLOW_NODE_MODAL_TRACKER.md — Modal bug details
- FLOW_UI_FEATURE_TRACKER.md — Overall UI status
- INDEX.md — Master index
Update this document after each fix is verified.